#include <maya/MIOStream.h>
#include <apiMeshShapeUI.h>
#include <maya/MMaterial.h>
#include <maya/MColor.h>
#include <maya/MDrawData.h>
#include <maya/MMatrix.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MObjectArray.h>
#include <maya/MDagPath.h>
#include <maya/MGlobal.h>
#include <maya/MTextureEditorDrawInfo.h>
#define LEAD_COLOR 18 // green
#define ACTIVE_COLOR 15 // white
#define ACTIVE_AFFECTED_COLOR 8 // purple
#define DORMANT_COLOR 4 // blue
#define HILITE_COLOR 17 // pale blue
#define DORMANT_VERTEX_COLOR 8 // purple
#define ACTIVE_VERTEX_COLOR 16 // yellow
#define POINT_SIZE 2.0
#define UV_POINT_SIZE 4.0
apiMeshUI::apiMeshUI() {}
apiMeshUI::~apiMeshUI() {}
void* apiMeshUI::creator()
{
return new apiMeshUI();
}
void apiMeshUI::getDrawRequests( const MDrawInfo & info,
bool objectAndActiveOnly,
MDrawRequestQueue & queue )
{
MDrawData data;
apiMesh* meshNode = (apiMesh*)surfaceShape();
apiMeshGeom * geom = meshNode->meshGeom();
if ( (NULL == geom) || (0 == geom->faceCount) ) {
cerr << "NO DrawRequest for apiMesh\n";
return;
}
MDrawRequest request = info.getPrototype( *this );
getDrawData( geom, data );
request.setDrawData( data );
M3dView::DisplayStyle appearance = info.displayStyle();
M3dView::DisplayStatus displayStatus = info.displayStatus();
if ( ! info.objectDisplayStatus( M3dView::kDisplayMeshes ) )
return;
if ( info.inUserInteraction() || info.userChangingViewContext() ) {
request.setToken( kDrawRedPointAtCenter );
queue.add( request );
return;
}
switch ( appearance )
{
case M3dView::kWireFrame :
{
request.setToken( kDrawWireframe );
M3dView::ColorTable activeColorTable = M3dView::kActiveColors;
M3dView::ColorTable dormantColorTable = M3dView::kDormantColors;
switch ( displayStatus )
{
case M3dView::kLead :
request.setColor( LEAD_COLOR, activeColorTable );
break;
case M3dView::kActive :
request.setColor( ACTIVE_COLOR, activeColorTable );
break;
case M3dView::kActiveAffected :
request.setColor( ACTIVE_AFFECTED_COLOR, activeColorTable );
break;
case M3dView::kDormant :
request.setColor( DORMANT_COLOR, dormantColorTable );
break;
case M3dView::kHilite :
request.setColor( HILITE_COLOR, activeColorTable );
break;
default:
break;
}
queue.add( request );
break;
}
case M3dView::kGouraudShaded :
{
request.setToken( kDrawSmoothShaded );
MDagPath path = info.multiPath();
M3dView view = info.view();;
MMaterial material = MPxSurfaceShapeUI::material( path );
if ( ! material.evaluateMaterial( view, path ) ) {
cerr << "Couldnt evaluate\n";
}
bool drawTexture = true;
if ( drawTexture && material.materialIsTextured() ) {
material.evaluateTexture( data );
}
request.setMaterial( material );
bool materialTransparent = false;
material.getHasTransparency( materialTransparent );
if ( materialTransparent ) {
request.setIsTransparent( true );
}
queue.add( request );
if ( (displayStatus == M3dView::kActive) ||
(displayStatus == M3dView::kLead) ||
(displayStatus == M3dView::kHilite) )
{
MDrawRequest wireRequest = info.getPrototype( *this );
wireRequest.setDrawData( data );
wireRequest.setToken( kDrawWireframeOnShaded );
wireRequest.setDisplayStyle( M3dView::kWireFrame );
M3dView::ColorTable activeColorTable = M3dView::kActiveColors;
switch ( displayStatus )
{
case M3dView::kLead :
wireRequest.setColor( LEAD_COLOR, activeColorTable );
break;
case M3dView::kActive :
wireRequest.setColor( ACTIVE_COLOR, activeColorTable );
break;
case M3dView::kHilite :
wireRequest.setColor( HILITE_COLOR, activeColorTable );
break;
default:
break;
}
queue.add( wireRequest );
}
break;
}
case M3dView::kFlatShaded :
request.setToken( kDrawFlatShaded );
queue.add( request );
break;
case M3dView::kBoundingBox :
request.setToken( kDrawBoundingBox );
queue.add( request );
break;
default:
break;
}
if ( !objectAndActiveOnly ) {
if ( (appearance == M3dView::kPoints) ||
(displayStatus == M3dView::kHilite) )
{
MDrawRequest vertexRequest = info.getPrototype( *this );
vertexRequest.setDrawData( data );
vertexRequest.setToken( kDrawVertices );
vertexRequest.setColor( DORMANT_VERTEX_COLOR,
M3dView::kActiveColors );
queue.add( vertexRequest );
}
if ( surfaceShape()->hasActiveComponents() ) {
MDrawRequest activeVertexRequest = info.getPrototype( *this );
activeVertexRequest.setDrawData( data );
activeVertexRequest.setToken( kDrawVertices );
activeVertexRequest.setColor( ACTIVE_VERTEX_COLOR,
M3dView::kActiveColors );
MObjectArray clist = surfaceShape()->activeComponents();
MObject vertexComponent = clist[0];
activeVertexRequest.setComponent( vertexComponent );
queue.add( activeVertexRequest );
}
}
}
void apiMeshUI::draw( const MDrawRequest & request, M3dView & view ) const
{
int token = request.token();
switch( token )
{
case kDrawWireframe :
case kDrawWireframeOnShaded :
drawWireframe( request, view );
break;
case kDrawSmoothShaded :
drawShaded( request, view );
break;
case kDrawFlatShaded :
break;
case kDrawVertices :
drawVertices( request, view );
break;
case kDrawBoundingBox:
drawBoundingBox( request, view );
break;
case kDrawRedPointAtCenter:
drawRedPointAtCenter( request, view );
break;
}
}
bool apiMeshUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList,
MPointArray &worldSpaceSelectPts ) const
{
bool selected = false;
bool componentSelected = false;
bool hilited = false;
hilited = (selectInfo.displayStatus() == M3dView::kHilite);
if ( hilited ) {
componentSelected = selectVertices( selectInfo, selectionList,
worldSpaceSelectPts );
selected = selected || componentSelected;
}
if ( !selected ) {
apiMesh* meshNode = (apiMesh*)surfaceShape();
selected = true;
MSelectionMask priorityMask( MSelectionMask::kSelectNurbsSurfaces );
MSelectionList item;
item.add( selectInfo.selectPath() );
MPoint xformedPt;
if ( selectInfo.singleSelection() ) {
MPoint center = meshNode->boundingBox().center();
xformedPt = center;
xformedPt *= selectInfo.selectPath().inclusiveMatrix();
}
selectInfo.addSelection( item, xformedPt, selectionList,
worldSpaceSelectPts, priorityMask, false );
}
return selected;
}
void apiMeshUI::drawWireframe( const MDrawRequest & request,
M3dView & view ) const
{
MDrawData data = request.drawData();
apiMeshGeom * geom = (apiMeshGeom*)data.geometry();
int token = request.token();
bool wireFrameOnShaded = false;
if ( kDrawWireframeOnShaded == token ) {
wireFrameOnShaded = true;
}
view.beginGL();
bool lightingWasOn = glIsEnabled( GL_LIGHTING ) ? true : false;
if ( lightingWasOn ) {
glDisable( GL_LIGHTING );
}
if ( wireFrameOnShaded ) {
glDepthMask( false );
}
int vid = 0;
for ( int i=0; i<geom->faceCount; i++ )
{
glBegin( GL_LINE_LOOP );
for ( int v=0; v<geom->face_counts[i]; v++ )
{
MPoint vertex = geom->vertices[ geom->face_connects[vid++] ];
glVertex3f( (float)vertex[0], (float)vertex[1], (float)vertex[2] );
}
glEnd();
}
if ( lightingWasOn ) {
glEnable( GL_LIGHTING );
}
if ( wireFrameOnShaded ) {
glDepthMask( true );
}
view.endGL();
}
void apiMeshUI::drawShaded( const MDrawRequest & request,
M3dView & view ) const
{
MDrawData data = request.drawData();
apiMeshGeom * geom = (apiMeshGeom*)data.geometry();
view.beginGL();
#if defined(SGI) || defined(MESA)
glEnable( GL_POLYGON_OFFSET_EXT );
#else
glEnable( GL_POLYGON_OFFSET_FILL );
#endif
MMaterial material = request.material();
material.setMaterial( request.multiPath(), request.isTransparent() );
bool drawTexture = material.materialIsTextured();
if ( drawTexture ) glEnable(GL_TEXTURE_2D);
if ( drawTexture ) {
material.applyTexture( view, data );
}
int vid = 0;
int uv_len = geom->uvcoords.uvcount();
for ( int i=0; i<geom->faceCount; i++ )
{
glBegin( GL_POLYGON );
for ( int v=0; v<geom->face_counts[i]; v++ )
{
MPoint vertex = geom->vertices[ geom->face_connects[vid] ];
MVector normal = geom->normals[ geom->face_connects[vid] ];
if ( drawTexture ) {
float u, v;
int uvId1 = geom->uvcoords.uvId(vid);
if ( uvId1 < uv_len ) {
geom->uvcoords.getUV( uvId1, u, v );
glTexCoord2f( (GLfloat)u, (GLfloat)v );
}
}
glNormal3f( (float)normal[0], (float)normal[1], (float)normal[2] );
glVertex3f( (float)vertex[0], (float)vertex[1], (float)vertex[2] );
vid++;
}
glEnd();
}
if ( drawTexture ) glDisable(GL_TEXTURE_2D);
view.endGL();
}
void apiMeshUI::drawVertices( const MDrawRequest & request,
M3dView & view ) const
{
MDrawData data = request.drawData();
apiMeshGeom * geom = (apiMeshGeom*)data.geometry();
view.beginGL();
bool lightingWasOn = glIsEnabled( GL_LIGHTING ) ? true : false;
if ( lightingWasOn ) {
glDisable( GL_LIGHTING );
}
float lastPointSize;
glGetFloatv( GL_POINT_SIZE, &lastPointSize );
glPointSize( POINT_SIZE );
MObject comp = request.component();
if ( ! comp.isNull() ) {
MFnSingleIndexedComponent fnComponent( comp );
for ( int i=0; i<fnComponent.elementCount(); i++ )
{
int index = fnComponent.element( i );
glBegin( GL_POINTS );
MPoint vertex = geom->vertices[ index ];
glVertex3f( (float)vertex[0],
(float)vertex[1],
(float)vertex[2] );
glEnd();
char annotation[32];
sprintf( annotation, "%d", index );
view.drawText( annotation, vertex );
}
}
else {
int vid = 0;
for ( int i=0; i<geom->faceCount; i++ )
{
glBegin( GL_POINTS );
for ( int v=0; v<geom->face_counts[i]; v++ )
{
MPoint vertex =
geom->vertices[ geom->face_connects[vid++] ];
glVertex3f( (float)vertex[0],
(float)vertex[1],
(float)vertex[2] );
}
glEnd();
}
}
if ( lightingWasOn ) {
glEnable( GL_LIGHTING );
}
glPointSize( lastPointSize );
view.endGL();
}
void apiMeshUI::drawBoundingBox( const MDrawRequest & request,
M3dView & view ) const
{
MPxSurfaceShape *shape = surfaceShape();
if ( !shape )
return;
MBoundingBox box = shape->boundingBox();
float w = (float) box.width();
float h = (float) box.height();
float d = (float) box.depth();
view.beginGL();
MPoint minVertex = box.min();
glBegin( GL_LINE_LOOP );
MPoint vertex = minVertex;
glVertex3f( (float)vertex[0], (float)vertex[1], (float)vertex[2] );
glVertex3f( (float)vertex[0]+w, (float)vertex[1], (float)vertex[2] );
glVertex3f( (float)vertex[0]+w, (float)vertex[1]+h, (float)vertex[2] );
glVertex3f( (float)vertex[0], (float)vertex[1]+h, (float)vertex[2] );
glVertex3f( (float)vertex[0], (float)vertex[1], (float)vertex[2] );
glEnd();
MPoint sideFactor(0,0,d);
MPoint vertex2 = minVertex + sideFactor;
glBegin( GL_LINE_LOOP );
glVertex3f( (float)vertex2[0], (float)vertex2[1], (float)vertex2[2] );
glVertex3f( (float)vertex2[0]+w, (float)vertex2[1], (float)vertex2[2] );
glVertex3f( (float)vertex2[0]+w, (float)vertex2[1]+h, (float)vertex2[2] );
glVertex3f( (float)vertex2[0], (float)vertex2[1]+h, (float)vertex2[2] );
glVertex3f( (float)vertex2[0], (float)vertex2[1], (float)vertex2[2] );
glEnd();
glBegin( GL_LINES );
glVertex3f( (float)vertex2[0], (float)vertex2[1], (float)vertex2[2] );
glVertex3f( (float)vertex[0], (float)vertex[1], (float)vertex[2] );
glVertex3f( (float)vertex2[0]+w, (float)vertex2[1], (float)vertex2[2] );
glVertex3f( (float)vertex[0]+w, (float)vertex[1], (float)vertex[2] );
glVertex3f( (float)vertex2[0]+w, (float)vertex2[1]+h, (float)vertex2[2] );
glVertex3f( (float)vertex[0]+w, (float)vertex[1]+h, (float)vertex[2] );
glVertex3f( (float)vertex2[0], (float)vertex2[1]+h, (float)vertex2[2] );
glVertex3f( (float)vertex[0], (float)vertex[1]+h, (float)vertex[2] );
glEnd();
view.endGL();
}
void apiMeshUI::drawRedPointAtCenter( const MDrawRequest & request,
M3dView & view ) const
{
view.beginGL();
glPushAttrib( GL_CURRENT_BIT | GL_POINT_BIT );
glPointSize( 20.0f );
glBegin( GL_POINTS );
glColor3f( 1.0f, 0.0f, 0.0f );
glVertex3f(0.0f, 0.0f, 0.0f );
glEnd();
glPopAttrib();
view.endGL();
}
bool apiMeshUI::selectVertices( MSelectInfo &selectInfo,
MSelectionList &selectionList,
MPointArray &worldSpaceSelectPts ) const
{
bool selected = false;
M3dView view = selectInfo.view();
MPoint xformedPoint;
MPoint selectionPoint;
double z,previousZ = 0.0;
int closestPointVertexIndex = -1;
const MDagPath & path = selectInfo.multiPath();
MFnSingleIndexedComponent fnComponent;
MObject surfaceComponent = fnComponent.create( MFn::kMeshVertComponent );
int vertexIndex;
MMatrix alignmentMatrix;
MPoint singlePoint;
bool singleSelection = selectInfo.singleSelection();
if( singleSelection ) {
alignmentMatrix = selectInfo.getAlignmentMatrix();
}
apiMesh* meshNode = (apiMesh*)surfaceShape();
apiMeshGeom * geom = meshNode->meshGeom();
int numVertices = geom->vertices.length();
for ( vertexIndex=0; vertexIndex<numVertices; vertexIndex++ )
{
MPoint currentPoint = geom->vertices[ vertexIndex ];
view.beginSelect();
glBegin( GL_POINTS );
glVertex3f( (float)currentPoint[0],
(float)currentPoint[1],
(float)currentPoint[2] );
glEnd();
if ( view.endSelect() > 0 )
{
selected = true;
if ( singleSelection ) {
xformedPoint = currentPoint;
xformedPoint.homogenize();
xformedPoint*= alignmentMatrix;
z = xformedPoint.z;
if ( closestPointVertexIndex < 0 || z > previousZ ) {
closestPointVertexIndex = vertexIndex;
singlePoint = currentPoint;
previousZ = z;
}
} else {
fnComponent.addElement( vertexIndex );
}
}
}
if ( selected && selectInfo.singleSelection() ) {
fnComponent.addElement(closestPointVertexIndex);
selectionPoint = singlePoint;
selectionPoint *= path.inclusiveMatrix();
}
if ( selected ) {
MSelectionList selectionItem;
selectionItem.add( path, surfaceComponent );
MSelectionMask mask( MSelectionMask::kSelectComponentsMask );
selectInfo.addSelection(
selectionItem, selectionPoint,
selectionList, worldSpaceSelectPts,
mask, true );
}
return selected;
}
bool apiMeshUI::canDrawUV() const
{
apiMesh* meshNode = (apiMesh*)surfaceShape();
apiMeshGeom * geom = meshNode->meshGeom();
return geom->uvcoords.uvcount() > 0;
}
void apiMeshUI::drawUVWireframe(
apiMeshGeom *geom,
M3dView &view,
const MTextureEditorDrawInfo &info
) const
{
view.beginGL();
int vid = 0;
int vid_start = vid;
for ( int i=0; i<geom->faceCount; i++ )
{
glBegin( GL_LINES );
int v;
vid_start = vid;
for ( v=0; v<geom->face_counts[i]-1; v++ )
{
float du1, dv1, du2, dv2;
int uvId1 = geom->uvcoords.uvId(vid);
int uvId2 = geom->uvcoords.uvId(vid+1);
geom->uvcoords.getUV( uvId1, du1, dv1 );
geom->uvcoords.getUV( uvId2, du2, dv2 );
glVertex3f( (GLfloat)du1, (GLfloat)dv1, 0.0f );
glVertex3f( (GLfloat)du2, (GLfloat)dv2, 0.0f );
vid++;
}
float du1, dv1, du2, dv2;
int uvId1 = geom->uvcoords.uvId(vid);
int uvId2 = geom->uvcoords.uvId(vid_start);
geom->uvcoords.getUV( uvId1, du1, dv1 );
geom->uvcoords.getUV( uvId2, du2, dv2 );
glVertex3f( (GLfloat)du1, (GLfloat)dv1, 0.0f );
glVertex3f( (GLfloat)du2, (GLfloat)dv2, 0.0f );
vid ++ ;
glEnd();
}
}
void apiMeshUI::drawUVMapCoord(
M3dView &view,
int uv,
float u, float v,
bool drawNum
) const
{
if ( drawNum ) {
char s[32];
sprintf( s, "%d", uv );
view.drawText( s, MPoint( u, v, 0 ), M3dView::kCenter );
}
glVertex3f( (GLfloat)u, (GLfloat)v, 0.0f );
}
void apiMeshUI::drawUVMapCoordNum(
apiMeshGeom *geom,
M3dView &view,
const MTextureEditorDrawInfo &info,
bool drawNumbers
) const
{
view.beginGL();
GLfloat ptSize;
glGetFloatv( GL_POINT_SIZE, &ptSize );
glPointSize( UV_POINT_SIZE );
int uv;
int uv_len = geom->uvcoords.uvcount();
for ( uv = 0; uv < uv_len; uv ++ ) {
float du, dv;
geom->uvcoords.getUV( uv, du, dv );
drawUVMapCoord( view, uv, du, dv, drawNumbers );
}
glPointSize( ptSize );
view.endGL();
}
void apiMeshUI::drawUV( M3dView &view, const MTextureEditorDrawInfo &info ) const
{
apiMesh* meshNode = (apiMesh*)surfaceShape();
apiMeshGeom * geom = meshNode->meshGeom();
view.setDrawColor( MColor( 1.0f, 0.0f, 0.0f ) );
switch( info.drawingFunction() ) {
case MTextureEditorDrawInfo::kDrawWireframe:
drawUVWireframe( geom, view, info );
break;
case MTextureEditorDrawInfo::kDrawEverything:
case MTextureEditorDrawInfo::kDrawUVForSelect:
drawUVWireframe( geom, view, info );
drawUVMapCoordNum( geom, view, info, false );
break;
case MTextureEditorDrawInfo::kDrawVertexForSelect:
case MTextureEditorDrawInfo::kDrawEdgeForSelect:
case MTextureEditorDrawInfo::kDrawFacetForSelect:
default:
drawUVWireframe( geom, view, info );
};
}