349 lines
11 KiB
C++
349 lines
11 KiB
C++
//#include <maya/MIOStream.h>
|
|
//#include <stdio.h>
|
|
//#include <stdlib.h>
|
|
//
|
|
//#include <maya/MFn.h>
|
|
//#include <maya/MPxNode.h>
|
|
//#include <maya/MPxManipContainer.h>
|
|
//#include <maya/MPxSelectionContext.h>
|
|
//#include <maya/MPxContextCommand.h>
|
|
//#include <maya/MModelMessage.h>
|
|
//#include <maya/MFnPlugin.h>
|
|
#include <maya/MGlobal.h>
|
|
//#include <maya/MItSelectionList.h>
|
|
//#include <maya/MPoint.h>
|
|
#include <maya/MVector.h>
|
|
//#include <maya/MDagPath.h>
|
|
#include <maya/MManipData.h>
|
|
//#include <maya/MSelectionList.h>
|
|
#include <maya/MItMeshVertex.h>
|
|
#include <maya/MFnComponent.h>
|
|
//#include <maya/MStatus.h>
|
|
//#include <maya/MObject.h>
|
|
#include <maya/MPlug.h>
|
|
#include <maya/MFnMesh.h>
|
|
#include <maya/MFnNumericAttribute.h>
|
|
|
|
//
|
|
//Manipulators
|
|
#include <maya/MFnScaleManip.h>
|
|
#include <maya/MFnRotateManip.h>
|
|
//
|
|
//#include "rageHairContext.h"
|
|
#include "rageHairManip.h"
|
|
//#include "rageHairScaleCmd.h"
|
|
// #include "rageHairManip.h"
|
|
#define POINT_SIZE 20.0
|
|
#define BLIND_DATA_ID 60
|
|
|
|
|
|
void OutputError(const MString& obStrErrorMessage)
|
|
{
|
|
cout<<obStrErrorMessage<<endl;
|
|
MGlobal::displayError(obStrErrorMessage);
|
|
}
|
|
|
|
|
|
MStatus addArrayAttribute(MString strAttributeName, MObject obNode)
|
|
{
|
|
MFnDependencyNode obFnNode(obNode);
|
|
|
|
// Add an array atrribute to store all the hair vectors in
|
|
MStatus obStatus;
|
|
MPlug obPlug = obFnNode.findPlug(strAttributeName, &obStatus);
|
|
if (obPlug.isNull())
|
|
{
|
|
// Attribute does not exist, so create it
|
|
MFnNumericAttribute attributeFn;
|
|
MObject attr = attributeFn.create(strAttributeName, strAttributeName, MFnNumericData::k3Double);
|
|
attributeFn.setArray(true);
|
|
obFnNode.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr);
|
|
MPlug obPlug = obFnNode.findPlug(strAttributeName, &obStatus);
|
|
if (obPlug.isNull())
|
|
{
|
|
OutputError("Could not add "+ strAttributeName +" attribute.");
|
|
return MS::kFailure;
|
|
}
|
|
}
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
rageHairManip::rageHairManip() :
|
|
m_aobInitialHairVectors(NULL),
|
|
m_abVertexIsSelected(NULL)
|
|
{
|
|
// The constructor must not call createChildren for user-defined
|
|
// manipulators.
|
|
m_astrBindDataLongNames.clear();
|
|
m_astrBindDataLongNames.append("rageHairBlindDataX");
|
|
m_astrBindDataLongNames.append("rageHairBlindDataY");
|
|
m_astrBindDataLongNames.append("rageHairBlindDataZ");
|
|
}
|
|
|
|
|
|
rageHairManip::~rageHairManip()
|
|
{
|
|
// m_aobInitialHairVectors should always be either NULL or an allocated array
|
|
// of MPoint.
|
|
//
|
|
delete [] m_aobInitialHairVectors;
|
|
delete [] m_abVertexIsSelected;
|
|
}
|
|
|
|
MStatus rageHairManip::initialize()
|
|
{
|
|
MStatus obStatus;
|
|
obStatus = MPxManipContainer::initialize();
|
|
return obStatus;
|
|
}
|
|
|
|
MStatus rageHairManip::connectToDependNode(const MObject &obMeshNode)
|
|
{
|
|
MStatus obStatus;
|
|
|
|
// Set up some stuff
|
|
delete [] m_aobInitialHairVectors;
|
|
delete [] m_abVertexIsSelected;
|
|
int iTotalNoOfVertsInMesh = MFnMesh(obMeshNode).numVertices();
|
|
|
|
// Fill in vector array
|
|
m_aobInitialHairVectors = new MVector[iTotalNoOfVertsInMesh];
|
|
for(int i=0; i<iTotalNoOfVertsInMesh; i++) m_aobInitialHairVectors[i] = MVector(1.0f, 2.0f, 3.0f);
|
|
|
|
// Fill in the bool array
|
|
m_abVertexIsSelected = new bool[iTotalNoOfVertsInMesh];
|
|
for(int i=0; i<iTotalNoOfVertsInMesh; i++) m_abVertexIsSelected[i] = false;
|
|
|
|
// I need to create a MFnMesh node, but if you create one from a MObject the blind data functions do not work
|
|
// So do some evil hacks to get a MDagPath to create it out of instead
|
|
MDagPath obDagPathMeshNode;
|
|
MDagPath::getAPathTo(obMeshNode, obDagPathMeshNode);
|
|
MFnMesh obFnMeshNode(obDagPathMeshNode);
|
|
|
|
|
|
// Throw on a dummy attribute, just so the manipulator has something to hang off
|
|
MPlug obDummyPlug = obFnMeshNode.findPlug( DUMMY_ATTRIBUTE_NAME, &obStatus );
|
|
if((!obStatus) || (obDummyPlug.isNull()))
|
|
{
|
|
// Unable to find dummy plug, so add it
|
|
MFnNumericAttribute obFnNumericAttribute;
|
|
MObject obAttr = obFnNumericAttribute.create(DUMMY_ATTRIBUTE_NAME, "rhd", MFnNumericData::kFloat , 0, &obStatus);
|
|
if(!obStatus)
|
|
{
|
|
OutputError(MString("Unable to create dummy attribute ")+ DUMMY_ATTRIBUTE_NAME);
|
|
return MS::kFailure;
|
|
}
|
|
obFnNumericAttribute.setHidden(true);
|
|
|
|
obStatus = obFnMeshNode.addAttribute(obAttr, MFnDependencyNode::kLocalDynamicAttr);
|
|
if(!obStatus)
|
|
{
|
|
OutputError(MString("Unable to add dummy attribute ")+ DUMMY_ATTRIBUTE_NAME +" to "+ obFnMeshNode.fullPathName());
|
|
return MS::kFailure;
|
|
}
|
|
}
|
|
|
|
|
|
// If mesh currently does not have blinddata, add it
|
|
// Create blind data type
|
|
MStringArray astrBindDataShortNames;
|
|
astrBindDataShortNames.append("rhx");
|
|
astrBindDataShortNames.append("rhy");
|
|
astrBindDataShortNames.append("rhz");
|
|
MStringArray formatNames;
|
|
formatNames.append("float");
|
|
formatNames.append("float");
|
|
formatNames.append("float");
|
|
|
|
// See if blinddata id already used in scene
|
|
if(!obFnMeshNode.isBlindDataTypeUsed(BLIND_DATA_ID,&obStatus))
|
|
{
|
|
// cout<<"Creating blind data"<<endl;
|
|
// Not already used so create
|
|
obStatus = obFnMeshNode.createBlindDataType(BLIND_DATA_ID, m_astrBindDataLongNames, astrBindDataShortNames, formatNames);
|
|
if(!obStatus)
|
|
{
|
|
OutputError("Error creating blind data");
|
|
return MS::kFailure;
|
|
}
|
|
}
|
|
|
|
// Iterate through the components, storing initial positions and find the
|
|
// m_obCentroidOfAllSelectedComponents. Add manipToPlug callbacks for each component.
|
|
//
|
|
m_obAISelectedComponentIndexes.clear();
|
|
MItMeshVertex iter(m_obMeshDagPath, GetSelectedComponents());
|
|
for (; !iter.isDone(); iter.next())
|
|
{
|
|
MString obStrVertNoAsString;
|
|
obStrVertNoAsString += iter.index();
|
|
m_obAISelectedComponentIndexes.append(iter.index());
|
|
m_abVertexIsSelected[iter.index()] = true;
|
|
m_obCentroidOfAllSelectedComponents += iter.position(MSpace::kWorld);
|
|
|
|
if(!obFnMeshNode.hasBlindData(iter.index(), MFn::kMeshVertComponent, BLIND_DATA_ID))
|
|
{
|
|
// I don't have a hair vector, so create one
|
|
MVector obVertexNormal;
|
|
iter.getNormal(obVertexNormal, MSpace::kWorld);
|
|
|
|
for(int iAxis=0; iAxis<3; iAxis++)
|
|
{
|
|
// Set value for the blind data
|
|
// polyBlindData -id 60 -associationType "vertex" -longDataName "bdFloat" -doubleData 234 pPlane1.vtx[0]
|
|
float fDataIn = 0.5f * (float)obVertexNormal[iAxis];
|
|
// cout<<"fDataIn = "<<fDataIn<<"\tobVertexNormal["<<iAxis<<"] = "<<obVertexNormal[iAxis]<<endl;
|
|
obStatus = obFnMeshNode.setFloatBlindData(iter.index(), MFn::kMeshVertComponent, BLIND_DATA_ID, m_astrBindDataLongNames[iAxis], fDataIn);
|
|
if (!obStatus)
|
|
{
|
|
OutputError("Could not set blind data "+ m_astrBindDataLongNames[iAxis] +" X for vert "+ obStrVertNoAsString +" on "+ obFnMeshNode.fullPathName());
|
|
return MS::kFailure;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Store for future reference
|
|
double3 adHairVector;
|
|
for(int iAxis = 0; iAxis<3; iAxis++)
|
|
{
|
|
float fDataOut;
|
|
obStatus = obFnMeshNode.getFloatBlindData(iter.index(), MFn::kMeshVertComponent, BLIND_DATA_ID, m_astrBindDataLongNames[iAxis], fDataOut);
|
|
if (!obStatus)
|
|
{
|
|
OutputError("Could not get "+ m_astrBindDataLongNames[iAxis] +" for vert "+ obStrVertNoAsString +" on "+ obFnMeshNode.fullPathName());
|
|
return MS::kFailure;
|
|
}
|
|
adHairVector[iAxis] = fDataOut;
|
|
}
|
|
m_aobInitialHairVectors[iter.index()] = MVector( adHairVector[0], adHairVector[1], adHairVector[2] );
|
|
}
|
|
m_obCentroidOfAllSelectedComponents = m_obCentroidOfAllSelectedComponents * (1.0f/(float)iter.count());
|
|
|
|
MPxManipContainer::connectToDependNode(obMeshNode);
|
|
|
|
return obStatus;
|
|
}
|
|
|
|
|
|
void rageHairManip::draw(M3dView & view,
|
|
const MDagPath & path,
|
|
M3dView::DisplayStyle style,
|
|
M3dView::DisplayStatus obStatus)
|
|
{
|
|
MPxManipContainer::draw(view, path, style, obStatus);
|
|
|
|
// Draw the normals
|
|
view.beginGL();
|
|
|
|
// Query current obStatuse so it can be restored
|
|
//
|
|
bool lightingWasOn = glIsEnabled( GL_LIGHTING ) ? true : false;
|
|
if ( lightingWasOn )
|
|
{
|
|
glDisable( GL_LIGHTING );
|
|
}
|
|
|
|
float lastPointSize;
|
|
glGetFloatv( GL_POINT_SIZE, &lastPointSize );
|
|
|
|
// Set the point size of the vertices
|
|
glPointSize( POINT_SIZE );
|
|
|
|
// Get verts
|
|
// First the unselected one
|
|
glColor4f( 0.0f, 1.0f, 0.0f, 1.0f );
|
|
MFnMesh obFnMeshNode(m_obMeshDagPath.node());
|
|
for(MItMeshVertex iter(m_obMeshDagPath); !iter.isDone(); iter.next())
|
|
{
|
|
if(!m_abVertexIsSelected[iter.index()])
|
|
{
|
|
// Go through verts, drawing as I go
|
|
MPoint vertex = iter.position(MSpace::kWorld);
|
|
MVector obHair;
|
|
if(obFnMeshNode.hasBlindData(iter.index(), MFn::kMeshVertComponent, BLIND_DATA_ID))
|
|
{
|
|
for(int iAxis = 0; iAxis<3; iAxis++)
|
|
{
|
|
float fDataOut;
|
|
obFnMeshNode.getFloatBlindData(iter.index(), MFn::kMeshVertComponent, BLIND_DATA_ID, m_astrBindDataLongNames[iAxis], fDataOut);
|
|
obHair[iAxis] = fDataOut;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iter.getNormal(obHair, MSpace::kWorld);
|
|
obHair = obHair * 0.5f;
|
|
}
|
|
// obHair = obHair * 20.0f;
|
|
|
|
glBegin( GL_LINES );
|
|
glVertex3f( (float)vertex[0], (float)vertex[1], (float)vertex[2] );
|
|
glVertex3f( (float)obHair.x + (float)vertex[0], (float)obHair.y + (float)vertex[1], (float)obHair.z + (float)vertex[2] );
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
// Then the selected one
|
|
glColor4f( 1.0f, 0.0f, 0.0f, 1.0f );
|
|
for(MItMeshVertex iter(m_obMeshDagPath); !iter.isDone(); iter.next())
|
|
{
|
|
if(m_abVertexIsSelected[iter.index()])
|
|
{
|
|
// Go through verts, drawing as I go
|
|
MPoint vertex = iter.position(MSpace::kWorld);
|
|
double3 adHairVector;
|
|
for(int iAxis = 0; iAxis<3; iAxis++)
|
|
{
|
|
float fDataOut;
|
|
obFnMeshNode.getFloatBlindData (iter.index(), MFn::kMeshVertComponent, BLIND_DATA_ID, m_astrBindDataLongNames[iAxis], fDataOut);
|
|
adHairVector[iAxis] = fDataOut;
|
|
}
|
|
|
|
// Draw it
|
|
glBegin( GL_LINES );
|
|
glVertex3f( (float)vertex[0], (float)vertex[1], (float)vertex[2] );
|
|
glVertex3f( (float)adHairVector[0] + (float)vertex[0], (float)adHairVector[1] + (float)vertex[1], (float)adHairVector[2] + (float)vertex[2] );
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
// Restore the obStatuse
|
|
if ( lightingWasOn )
|
|
{
|
|
glEnable( GL_LIGHTING );
|
|
}
|
|
glPointSize( lastPointSize );
|
|
|
|
view.endGL();
|
|
}
|
|
|
|
MManipData rageHairManip::centerChangedCallback(unsigned index)
|
|
{
|
|
MObject obj = MObject::kNullObj;
|
|
|
|
// If we entered the callback with an invalid index, print an error and
|
|
// return. Since we registered the callback only for one index, all
|
|
// invocations of the callback should be for that index.
|
|
//
|
|
//MFnScaleManip scaleManip(m_obManipDagPath);
|
|
//if (index != scaleManip.scaleCenterIndex())
|
|
//{
|
|
// OutputError("Invalid index in center changed callback!");
|
|
|
|
// // For invalid indices, return vector of 0's
|
|
// MFnNumericData numericData;
|
|
// obj = numericData.create( MFnNumericData::k3Double );
|
|
// numericData.setData(0.0,0.0,0.0);
|
|
|
|
// return obj;
|
|
//}
|
|
|
|
// Set the center point for scaling to the m_obCentroidOfAllSelectedComponents of the CV's.
|
|
//
|
|
MFnNumericData numericData;
|
|
obj = numericData.create( MFnNumericData::k3Double );
|
|
numericData.setData(m_obCentroidOfAllSelectedComponents.x,m_obCentroidOfAllSelectedComponents.y,m_obCentroidOfAllSelectedComponents.z);
|
|
|
|
return MManipData(obj);
|
|
}
|