#include <maya/MPxLocatorNode.h>
#include <maya/MString.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MColor.h>
#include <maya/M3dView.h>
#include <maya/MFnPlugin.h>
#include <maya/MDistance.h>
#include <maya/MFnUnitAttribute.h>
#include <maya/MGlobal.h>
#include <maya/MFnDagNode.h>
#include <maya/MSelectionContext.h>
#include <maya/MDagMessage.h>
#include <maya/MDrawRegistry.h>
#include <maya/MPxSubSceneOverride.h>
#include <maya/MShaderManager.h>
#include <maya/MHWGeometry.h>
#include <maya/MHWGeometryUtilities.h>
#include <unordered_map>
namespace
{
float sole[][3] = { { 0.00f, 0.0f, -0.70f },
{ 0.04f, 0.0f, -0.69f },
{ 0.09f, 0.0f, -0.65f },
{ 0.13f, 0.0f, -0.61f },
{ 0.16f, 0.0f, -0.54f },
{ 0.17f, 0.0f, -0.46f },
{ 0.17f, 0.0f, -0.35f },
{ 0.16f, 0.0f, -0.25f },
{ 0.15f, 0.0f, -0.14f },
{ 0.13f, 0.0f, 0.00f },
{ 0.00f, 0.0f, 0.00f },
{ -0.13f, 0.0f, 0.00f },
{ -0.15f, 0.0f, -0.14f },
{ -0.16f, 0.0f, -0.25f },
{ -0.17f, 0.0f, -0.35f },
{ -0.17f, 0.0f, -0.46f },
{ -0.16f, 0.0f, -0.54f },
{ -0.13f, 0.0f, -0.61f },
{ -0.09f, 0.0f, -0.65f },
{ -0.04f, 0.0f, -0.69f },
{ -0.00f, 0.0f, -0.70f } };
float heel[][3] = { { 0.00f, 0.0f, 0.06f },
{ 0.13f, 0.0f, 0.06f },
{ 0.14f, 0.0f, 0.15f },
{ 0.14f, 0.0f, 0.21f },
{ 0.13f, 0.0f, 0.25f },
{ 0.11f, 0.0f, 0.28f },
{ 0.09f, 0.0f, 0.29f },
{ 0.04f, 0.0f, 0.30f },
{ 0.00f, 0.0f, 0.30f },
{ -0.04f, 0.0f, 0.30f },
{ -0.09f, 0.0f, 0.29f },
{ -0.11f, 0.0f, 0.28f },
{ -0.13f, 0.0f, 0.25f },
{ -0.14f, 0.0f, 0.21f },
{ -0.14f, 0.0f, 0.15f },
{ -0.13f, 0.0f, 0.06f },
{ -0.00f, 0.0f, 0.06f } };
int soleCount = 21;
int heelCount = 17;
const MString colorParameterName_ =
"solidColor";
const MString wireframeItemName_ =
"footPrintLocatorWires";
const MString shadedItemName_ =
"footPrintLocatorTriangles";
struct MColorHash
{
std::size_t operator()(
const MColor& color)
const
{
std::size_t seed = 0;
CombineHashCode(seed, color.
r);
CombineHashCode(seed, color.
g);
CombineHashCode(seed, color.
b);
CombineHashCode(seed, color.
a);
return seed;
}
void CombineHashCode(std::size_t& seed, float v) const
{
std::hash<float> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
};
std::unordered_map<MColor, MHWRender::MShaderInstance*, MColorHash> the3dSolidShaders;
{
auto it = the3dSolidShaders.find(color);
if (it != the3dSolidShaders.end())
{
return it->second;
}
if (renderer)
{
if (shaderMgr)
{
}
}
if (shader)
{
float solidColor[] = { color.
r, color.
g, color.
b, 1.0f };
the3dSolidShaders[color] = shader;
}
return shader;
}
{
if (renderer)
{
if (shaderMgr)
{
for (auto it = the3dSolidShaders.begin(); it != the3dSolidShaders.end(); it++)
{
}
the3dSolidShaders.clear();
return MS::kSuccess;
}
}
return MS::kFailure;
}
}
{
public:
footPrint();
~footPrint() override;
static void * creator();
public:
static MString drawDbClassification;
};
MTypeId footPrint::id( 0x00080037 );
MString footPrint::drawDbClassification(
"drawdb/subscene/footPrint_SubSceneOverride");
MString footPrint::drawRegistrantId(
"FootprintNode_SubSceneOverridePlugin");
footPrint::footPrint() {}
footPrint::~footPrint() {}
{
return MS::kUnknownParameter;
}
bool footPrint::isBounded() const
{
return true;
}
{
MPlug plug( thisNode, size );
plug.getValue( sizeVal );
MPoint corner1( -0.17, 0.0, -0.7 );
MPoint corner2( 0.17, 0.0, 0.3 );
corner1 = corner1 * multiplier;
corner2 = corner2 * multiplier;
}
{
}
void* footPrint::creator()
{
return new footPrint();
}
{
stat = addAttribute( size );
if (!stat) {
return stat;
}
return MS::kSuccess;
}
{
public:
{
return new FootPrintSubSceneOverride(obj);
}
~FootPrintSubSceneOverride() override;
{
return MHWRender::kAllDevices;
}
{
return true;
}
{
return true;
}
{
return fAreUIDrawablesDirty;
}
private:
FootPrintSubSceneOverride(
const MObject& obj);
void rebuildGeometryBuffers();
void deleteGeometryBuffers();
float fMultiplier;
bool fIsInstanceMode;
bool fAreUIDrawablesDirty;
struct InstanceInfo
{
InstanceInfo() {}
InstanceInfo(
const MMatrix& m,
const MColor& c) : fMatrix(m), fColor(c) {}
};
typedef std::map<unsigned int, InstanceInfo> InstanceInfoMap;
InstanceInfoMap fInstanceInfoCache;
static void InstanceChangedCallback(
MDagPath &child,
MDagPath &parent,
void *clientData);
MCallbackId fInstanceAddedCbId;
MCallbackId fInstanceRemovedCbId;
};
FootPrintSubSceneOverride::FootPrintSubSceneOverride(
const MObject& obj)
, fLocatorNode(obj)
, fMultiplier(0.0f)
, fIsInstanceMode(false)
, fAreUIDrawablesDirty(true)
, fPositionBuffer(NULL)
, fWireIndexBuffer(NULL)
, fShadedIndexBuffer(NULL)
, fInstanceAddedCbId(0)
, fInstanceRemovedCbId(0)
{
{
dagPath, InstanceChangedCallback, this);
dagPath, InstanceChangedCallback, this);
}
}
FootPrintSubSceneOverride::~FootPrintSubSceneOverride()
{
deleteGeometryBuffers();
if (fInstanceAddedCbId != 0)
{
fInstanceAddedCbId = 0;
}
if (fInstanceRemovedCbId != 0)
{
fInstanceRemovedCbId = 0;
}
}
void FootPrintSubSceneOverride::InstanceChangedCallback(
void* clientData)
{
FootPrintSubSceneOverride* ovr = static_cast<FootPrintSubSceneOverride*>(clientData);
if (ovr)
{
ovr->fInstanceDagPaths.clear();
}
}
void FootPrintSubSceneOverride::update(
{
unsigned int numInstances = fInstanceDagPaths.length();
if (numInstances == 0)
{
{
fprintf(stderr, "FootPrintSubSceneOverride: Failed to get all DAG paths.\n");
return;
}
numInstances = fInstanceDagPaths.length();
}
if (numInstances == 0) return;
if (!shader)
{
fprintf(stderr, "FootPrintSubSceneOverride: Failed to get a 3d solid shader.\n");
return;
}
MPlug plug(fLocatorNode, footPrint::size);
float newMultiplier = 1.0f;
if (!plug.isNull())
{
if (plug.getValue(sizeVal))
{
}
}
bool updateGeometry = (container.
count() == 0);
if (fMultiplier != newMultiplier)
{
fMultiplier = newMultiplier;
updateGeometry = true;
}
if (updateGeometry)
{
rebuildGeometryBuffers();
}
bool anyInstanceChanged = false;
unsigned int numVisibleInstances = 0;
const unsigned int componentsPerColor = 4;
MFloatArray instanceColorArray(numInstances * componentsPerColor);
for (unsigned int i=0; i<numInstances; i++)
{
const MDagPath& instance = fInstanceDagPaths[i];
{
InstanceInfoMap::iterator iter = fInstanceInfoCache.find(i);
if (iter == fInstanceInfoCache.end() ||
iter->second.fColor != instanceInfo.fColor ||
!iter->second.fMatrix.isEquivalent(instanceInfo.fMatrix))
{
if (!fAreUIDrawablesDirty &&
(iter == fInstanceInfoCache.end() ||
!iter->second.fMatrix.isEquivalent(instanceInfo.fMatrix)))
{
fAreUIDrawablesDirty = true;
}
anyInstanceChanged = true;
fInstanceInfoCache[i] = instanceInfo;
}
instanceMatrixArray[numVisibleInstances] = instanceInfo.fMatrix;
instanceColorArray[numVisibleInstances*componentsPerColor] = instanceInfo.fColor.r;
instanceColorArray[numVisibleInstances*componentsPerColor+1] = instanceInfo.fColor.g;
instanceColorArray[numVisibleInstances*componentsPerColor+2] = instanceInfo.fColor.b;
instanceColorArray[numVisibleInstances*componentsPerColor+3] = instanceInfo.fColor.a;
numVisibleInstances++;
}
else
{
InstanceInfoMap::iterator iter = fInstanceInfoCache.find(i);
if (iter != fInstanceInfoCache.end())
{
fInstanceInfoCache.erase(i);
anyInstanceChanged = true;
fAreUIDrawablesDirty = true;
}
}
}
instanceMatrixArray.setLength(numVisibleInstances);
instanceColorArray.setLength(numVisibleInstances*componentsPerColor);
unsigned int numInstanceInfo = fInstanceInfoCache.size();
if (numInstanceInfo != numVisibleInstances)
{
for (unsigned int i=numVisibleInstances; i<numInstanceInfo; i++)
{
fInstanceInfoCache.erase(i);
}
anyInstanceChanged = true;
fAreUIDrawablesDirty = true;
}
bool itemsChanged = false;
if (!wireItem)
{
itemsChanged = true;
}
if (!shadedItem)
{
container.
add(shadedItem);
itemsChanged = true;
}
if (itemsChanged || anyInstanceChanged)
{
}
if (itemsChanged || updateGeometry)
{
footPrint* fp = status ? dynamic_cast<footPrint*>(node.userNode()) : NULL;
vertexBuffers.
addBuffer(
"positions", fPositionBuffer);
setGeometryForRenderItem(*wireItem, vertexBuffers, *fWireIndexBuffer, bounds);
setGeometryForRenderItem(*shadedItem, vertexBuffers, *fShadedIndexBuffer, bounds);
if (bounds) delete bounds;
}
if (itemsChanged || anyInstanceChanged)
{
if (!fIsInstanceMode && numInstances == 1)
{
MMatrix& objToWorld = instanceMatrixArray[0];
}
else
{
setInstanceTransformArray(*wireItem, instanceMatrixArray);
setInstanceTransformArray(*shadedItem, instanceMatrixArray);
setExtraInstanceData(*wireItem, colorParameterName_, instanceColorArray);
setExtraInstanceData(*shadedItem, colorParameterName_, instanceColorArray);
fIsInstanceMode = true;
}
}
}
void FootPrintSubSceneOverride::addUIDrawables(
{
MColor textColor( 0.1f, 0.8f, 0.8f, 1.0f );
for (auto it = fInstanceInfoCache.begin(); it != fInstanceInfoCache.end(); it++)
{
drawManager.
text((pos * it->second.fMatrix) * worldInverse0,
}
fAreUIDrawablesDirty = false;
}
bool FootPrintSubSceneOverride::getInstancedSelectionPath(
{
unsigned int numInstances = fInstanceDagPaths.length();
if (numInstances == 0) return false;
if (instanceId > (int)numInstances) return false;
if (numInstances == 1 || instanceId == -1)
{
instanceId = 1;
}
}
void FootPrintSubSceneOverride::rebuildGeometryBuffers()
{
deleteGeometryBuffers();
if (fPositionBuffer)
{
float* positions = (float*)fPositionBuffer->acquire(soleCount+heelCount, true);
if (positions)
{
int verticesPointerOffset = 0;
for (int currentVertex = 0 ; currentVertex < soleCount+heelCount; ++currentVertex)
{
if (currentVertex < heelCount)
{
int heelVtx = currentVertex;
positions[verticesPointerOffset++] = heel[heelVtx][0] * fMultiplier;
positions[verticesPointerOffset++] = heel[heelVtx][1] * fMultiplier;
positions[verticesPointerOffset++] = heel[heelVtx][2] * fMultiplier;
}
else
{
int soleVtx = currentVertex - heelCount;
positions[verticesPointerOffset++] = sole[soleVtx][0] * fMultiplier;
positions[verticesPointerOffset++] = sole[soleVtx][1] * fMultiplier;
positions[verticesPointerOffset++] = sole[soleVtx][2] * fMultiplier;
}
}
fPositionBuffer->commit(positions);
}
}
if (fWireIndexBuffer)
{
int primitiveIndex = 0;
int startIndex = 0;
int numPrimitive = heelCount + soleCount - 2;
int numIndex = numPrimitive * 2;
unsigned int* indices = (unsigned int*)fWireIndexBuffer->acquire(numIndex, true);
if (indices)
{
for (int i = 0; i < numIndex; )
{
if (i < (heelCount - 1) * 2)
{
startIndex = 0;
primitiveIndex = i / 2;
}
else
{
startIndex = heelCount;
primitiveIndex = i / 2 - heelCount + 1;
}
indices[i++] = startIndex + primitiveIndex;
indices[i++] = startIndex + primitiveIndex + 1;
}
fWireIndexBuffer->commit(indices);
}
}
if (fShadedIndexBuffer)
{
int primitiveIndex = 0;
int startIndex = 0;
int numPrimitive = heelCount + soleCount - 4;
int numIndex = numPrimitive * 3;
unsigned int* indices = (unsigned int*)fShadedIndexBuffer->acquire(numIndex, true);
if (indices)
{
for (int i = 0; i < numIndex; )
{
if (i < (heelCount - 2) * 3)
{
startIndex = 0;
primitiveIndex = i / 3;
}
else
{
startIndex = heelCount;
primitiveIndex = i / 3 - heelCount + 2;
}
indices[i++] = startIndex;
indices[i++] = startIndex + primitiveIndex + 1;
indices[i++] = startIndex + primitiveIndex + 2;
}
fShadedIndexBuffer->commit(indices);
}
}
}
void FootPrintSubSceneOverride::deleteGeometryBuffers()
{
if (fPositionBuffer)
{
delete fPositionBuffer;
fPositionBuffer = NULL;
}
if (fWireIndexBuffer)
{
delete fWireIndexBuffer;
fWireIndexBuffer = NULL;
}
if (fShadedIndexBuffer)
{
delete fShadedIndexBuffer;
fShadedIndexBuffer = NULL;
}
}
{
MFnPlugin plugin(obj, PLUGIN_COMPANY,
"1.0",
"Any");
status = plugin.registerNode(
"footPrint_SubSceneOverride",
footPrint::id,
&footPrint::creator,
&footPrint::initialize,
&footPrint::drawDbClassification);
if (!status)
{
status.
perror(
"registerNode");
return status;
}
footPrint::drawDbClassification,
footPrint::drawRegistrantId,
FootPrintSubSceneOverride::Creator);
if (!status)
{
status.
perror(
"registerSubSceneOverrideCreator");
return status;
}
return status;
}
{
footPrint::drawDbClassification,
footPrint::drawRegistrantId);
if (!status)
{
status.
perror(
"deregisterSubSceneOverrideCreator");
return status;
}
status = releaseShaders();
if (!status)
{
status.
perror(
"releaseShaders");
return status;
}
status = plugin.deregisterNode( footPrint::id );
if (!status)
{
status.
perror(
"deregisterNode");
return status;
}
return status;
}