#include <maya/MString.h>
#include <maya/MTypeId.h>
#include <maya/MPlug.h>
#include <maya/MPlugArray.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MColor.h>
#include <maya/MFnPlugin.h>
#include <maya/MDistance.h>
#include <maya/MFnUnitAttribute.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MPxLocatorNode.h>
#include <maya/MGlobal.h>
#include <maya/MDagMessage.h>
#include <maya/MEvaluationManager.h>
#include <maya/MEvaluationNode.h>
#include <maya/MDrawRegistry.h>
#include <maya/MPxGeometryOverride.h>
#include <maya/MShaderManager.h>
#include <maya/MHWGeometry.h>
#include <maya/MHWGeometryUtilities.h>
#include <maya/MUserData.h>
#include <cassert>
#include <memory>
#include <unordered_map>
#include <atomic>
static constexpr unsigned int gPluginNodeId = 0x00080039;
static constexpr const char gPluginNodeName[] = "footPrint_GeometryOverride_AnimatedMaterial";
static constexpr const char gPluginDrawDbClassification[] = "drawdb/geometry/footPrint_GeometryOverride_AnimatedMaterial";
static constexpr const char gPluginDrawRegistrantId[] = "footPrintNode_GeometryOverride_AnimatedMaterialPlugin";
static constexpr const char gPluginSelectionMask[] = "footPrintSelection";
static constexpr const char gPluginNodeMessagePrefix[] = "FootPrintGeometryOverrideAnimatedMaterial: ";
{
public:
public:
FootPrintNode();
~FootPrintNode() override;
bool isBounded()
const override {
return true; }
static void * creator() { return new FootPrintNode(); }
public:
struct GeometryParameters
{
double Size;
};
bool isGeometryChanging() const;
void updateRenderAttributes();
GeometryParameters updatingGeometry();
public:
static const MString drawDbClassification;
static const MString drawRegistrantId;
static const MString drawDbLightClassification;
};
MObject FootPrintNode::outputSize = {};
MObject FootPrintNode::inputSize = {};
MObject FootPrintNode::inputColor = {};
MObject FootPrintNode::outputColor = {};
MObject FootPrintNode::geometryChanging = {};
const MTypeId FootPrintNode::id = gPluginNodeId;
const MString FootPrintNode::drawDbClassification = gPluginDrawDbClassification;
const MString FootPrintNode::drawRegistrantId = gPluginDrawRegistrantId;
FootPrintNode::FootPrintNode() {}
FootPrintNode::~FootPrintNode() {}
{
{
sizeHandle.
copy(inputSizeHandle);
}
{
colorHandle.
copy(inputColorHandle);
}
{
}
else
{
return MS::kUnknownParameter;
}
}
{
{
{
MPlug osPlug(thisNode, outputSize);
MPlug scPlug(thisNode, geometryChanging);
}
{
MPlug ocPlug(thisNode, outputColor);
}
}
}
{
if (evalType == PostEvaluationEnum::kEvaluatedDirectly &&
{
}
return status;
}
{
}
{
MPlug plug( thisNode, outputSize );
MPoint corner1( -0.17, 0.0, -0.7 );
MPoint corner2( 0.17, 0.0, 0.3 );
corner1 = corner1 * multiplier;
corner2 = corner2 * multiplier;
}
MColor FootPrintNode::renderColor()
const
{
MDataBlock block =
const_cast<FootPrintNode*
>(
this)->forceCache();
return MColor(color[0], color[1], color[2]);
}
bool FootPrintNode::isGeometryChanging() const
{
MDataBlock block =
const_cast<FootPrintNode*
>(
this)->forceCache();
}
void FootPrintNode::updateRenderAttributes()
{
datablock.
inputValue(FootPrintNode::geometryChanging);
}
FootPrintNode::GeometryParameters FootPrintNode::updatingGeometry()
{
MDataBlock block =
const_cast<FootPrintNode*
>(
this)->forceCache();
GeometryParameters param;
return param;
}
struct ShaderDeleter {
auto* mgr = rednerer ? rednerer->getShaderManager() : nullptr;
if (mgr)
mgr->releaseShader(shader);
}
};
class AnimatedColorShader {
public:
void reset() { mAnimateColorShader.reset(); }
private:
std::unique_ptr<MShaderInstance, ShaderDeleter> mAnimateColorShader;
};
class FootprintNodeRenderItemData :
public MUserData
{
public:
FootprintNodeRenderItemData(FootPrintNode* node) : Node(node),
MUserData(false) {}
FootPrintNode* Node;
};
class SolidColorShaderStore {
public:
void clear() { mShaders.clear(); }
private:
static std::uint32_t encode(
MColor color);
std::unordered_map<std::uint32_t, std::unique_ptr<MShaderInstance, ShaderDeleter>> mShaders;
};
struct GlobalVariables {
SolidColorShaderStore solidColorShaderStore;
};
static GlobalVariables* Globals = nullptr;
static const MString ColorParameterName =
"solidColor";
static const MString WireframeItemName =
"footPrintLocatorWires";
static const MString ShadedItemName =
"footPrintLocatorTriangles";
static const MColor ErrorColor = { 1.0F, 0.0F,0.0F,1.0F };
{
public:
~FootPrintGeometryOverrideAnimatedMaterial() override;
DrawAPI supportedDrawAPIs()
const override {
return (DrawAPI::kOpenGL | DrawAPI::kDirectX11 | DrawAPI::kOpenGLCoreProfile); }
bool hasUIDrawables() const override { return false; }
bool supportsEvaluationManagerParallelUpdate() const override { return true; }
bool supportsVP2CustomCaching() const override { return true; }
void updateDG() override;
void cleanUp() override {};
bool requiresUpdateRenderItems(
const MDagPath& path)
const override;
bool requiresGeometryUpdate() const override;
bool isIndexingDirty(
const MRenderItem &item)
override {
return false; }
bool traceCallSequence() const override;
void handleTraceMessage(
const MString &message)
const override;
private:
FootPrintGeometryOverrideAnimatedMaterial(
const MObject& obj);
protected:
void fillFootprintSolidIndices(int numIndex, unsigned int * indices);
void fillFootprintWireframeIndices(int numIndex, unsigned int * indices);
void fillFootPrintVertices(float * vertices, float outputSize);
private:
FootPrintNode* mFootPrintNode;
AnimatedColorShader mAnimateColorShader;
};
FootPrintGeometryOverrideAnimatedMaterial::FootPrintGeometryOverrideAnimatedMaterial(
const MObject& obj)
, mFootPrintNode(nullptr)
{
MPxNode* footPrintNode = dependNode.userNode(&returnStatus);
mFootPrintNode = dynamic_cast<FootPrintNode*>(footPrintNode);
}
FootPrintGeometryOverrideAnimatedMaterial::~FootPrintGeometryOverrideAnimatedMaterial()
{}
{
MStatus status = schema.
add(FootPrintNode::outputColor);
assert(status);
}
}
void FootPrintGeometryOverrideAnimatedMaterial::updateDG()
{
mFootPrintNode->updateRenderAttributes();
}
bool FootPrintGeometryOverrideAnimatedMaterial::requiresUpdateRenderItems(
const MDagPath & path)
const
{
return false;
}
{
DisplayStatus displayStatus = MGeometryUtilities::displayStatus(path);
bool active = displayStatus == DisplayStatus::kLead ||
displayStatus == DisplayStatus::kActive ||
displayStatus == DisplayStatus::kHilite ||
displayStatus == DisplayStatus::kActiveComponent;
if (active)
{
MColor color = MGeometryUtilities::wireframeColor(path);
shader = Globals->solidColorShaderStore.get(color);
} else {
shader = mAnimateColorShader.get();
}
int index = list.
indexOf(WireframeItemName);
if (index < 0)
{
wireframeItem = MRenderItem::Create(
WireframeItemName,
MRenderItem::DecorationItem,
MGeometry::kLines);
wireframeItem->
depthPriority(MRenderItem::sDormantWireDepthPriority);
wireframeItem->
setCustomData(
new FootprintNodeRenderItemData(mFootPrintNode));
} else {
wireframeItem = list.
itemAt(index);
}
if (wireframeItem)
{
}
index = list.
indexOf(ShadedItemName);
if (index < 0)
{
shadedItem = MRenderItem::Create(
ShadedItemName,
MRenderItem::DecorationItem,
MGeometry::kTriangles);
shadedItem->
depthPriority(MRenderItem::sDormantFilledDepthPriority);
shadedItem->
setCustomData(
new FootprintNodeRenderItemData(mFootPrintNode));
} else{
shadedItem = list.
itemAt(index);
}
if (shadedItem)
{
}
}
{
if (renderItemList.
length() > 0)
{
auto customData =
static_cast<FootprintNodeRenderItemData*
>(renderItem->
customData());
auto footprint = customData ? customData->Node : nullptr;
color = footprint ? footprint->renderColor() : ErrorColor;
}
}
if (mAnimateColorShader)
return mAnimateColorShader.get();
MRenderer* renderer = MRenderer::theRenderer();
if (renderer)
{
if (shaderMgr)
{
MShaderManager::k3dSolidShader,
&AnimatedColorShader::ShaderPreDrawCallback);
mAnimateColorShader.reset(shader);
}
}
return shader;
}
std::uint32_t SolidColorShaderStore::encode(
MColor color)
{
constexpr int bitsPerChannel = 8;
constexpr std::uint32_t mask = (1 << bitsPerChannel) - 1;
return
(static_cast<std::uint32_t>(color.
r * mask) << (bitsPerChannel * 0)) |
(
static_cast<std::uint32_t
>(color.
g * mask) << (bitsPerChannel * 1)) |
(static_cast<std::uint32_t>(color.
b * mask) << (bitsPerChannel * 2)) |
(
static_cast<std::uint32_t
>(color.
a * mask) << (bitsPerChannel * 3));
}
auto& stored = mShaders[encode(color)];
if (!stored)
{
MRenderer* renderer = MRenderer::theRenderer();
if (renderer)
{
if (shaderMgr)
{
stored.reset(shader);
}
}
}
return stored.get();
}
bool FootPrintGeometryOverrideAnimatedMaterial::requiresGeometryUpdate() const
{
return mFootPrintNode->isGeometryChanging();
}
namespace
{
static constexpr int soleCount = 21;
static constexpr int heelCount = 17;
}
void FootPrintGeometryOverrideAnimatedMaterial::populateGeometry(
{
FootPrintNode::GeometryParameters footprintParam = mFootPrintNode->updatingGeometry();
float* vertices = nullptr;
const int numberOfVertexRequirments = vertexBufferDescriptorList.
length();
for (int requirmentNumber = 0; requirmentNumber < numberOfVertexRequirments; ++requirmentNumber)
{
if (!vertexBufferDescriptorList.
getDescriptor(requirmentNumber, vertexBufferDescriptor))
{
continue;
}
switch (vertexBufferDescriptor.
semantic())
{
case MGeometry::kPosition:
{
if (!verticesBuffer)
{
if (verticesBuffer)
{
vertices = (
float*)verticesBuffer->
acquire(soleCount+heelCount,
false);
}
}
}
break;
default:
break;
}
}
fillFootPrintVertices(vertices, footprintParam.Size);
if(verticesBuffer && vertices)
{
verticesBuffer->
commit(vertices);
}
for (
int i=0; i < renderItems.
length(); ++i)
{
if (!item)
{
continue;
}
if (item->
name() == WireframeItemName )
{
int numPrimitive = heelCount + soleCount - 2;
int numIndex = numPrimitive * 2;
unsigned int* indices = (
unsigned int*)indexBuffer->
acquire(numIndex,
false);
fillFootprintWireframeIndices(numIndex, indices);
}
else if (item->
name() == ShadedItemName )
{
int numPrimitive = heelCount + soleCount - 4;
int numIndex = numPrimitive * 3;
unsigned int* indices = (
unsigned int*)indexBuffer->
acquire(numIndex,
false);
fillFootprintSolidIndices(numIndex, indices);
}
}
}
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 } };
}
void FootPrintGeometryOverrideAnimatedMaterial::fillFootprintSolidIndices(int numIndex, unsigned int * indices)
{
int primitiveIndex = 0;
int startIndex = 0;
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;
}
}
void FootPrintGeometryOverrideAnimatedMaterial::fillFootprintWireframeIndices(int numIndex, unsigned int * indices)
{
int primitiveIndex = 0;
int startIndex = 0;
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;
}
}
void FootPrintGeometryOverrideAnimatedMaterial::fillFootPrintVertices(float * vertices, float outputSize)
{
int verticesPointerOffset = 0;
for (int currentVertex = 0; currentVertex < soleCount + heelCount; ++currentVertex)
{
if (vertices)
{
if (currentVertex < heelCount)
{
int heelVtx = currentVertex;
vertices[verticesPointerOffset++] = heel[heelVtx][0] * outputSize;
vertices[verticesPointerOffset++] = heel[heelVtx][1] * outputSize;
vertices[verticesPointerOffset++] = heel[heelVtx][2] * outputSize;
}
else
{
int soleVtx = currentVertex - heelCount;
vertices[verticesPointerOffset++] = sole[soleVtx][0] * outputSize;
vertices[verticesPointerOffset++] = sole[soleVtx][1] * outputSize;
vertices[verticesPointerOffset++] = sole[soleVtx][2] * outputSize;
}
}
}
}
bool FootPrintGeometryOverrideAnimatedMaterial::traceCallSequence() const
{
return false;
}
inline void FootPrintGeometryOverrideAnimatedMaterial::handleTraceMessage(
const MString & message)
const
{
fputs(gPluginNodeMessagePrefix, stderr);
fputs(message.
asChar(), stderr);
fputs("\n", stderr);
}
MStatus FootPrintNode::initialize()
{
stat = addAttribute(outputSize);
if (!stat) {
return stat;
}
stat = addAttribute(inputSize);
if (!stat) {
return stat;
}
stat = addAttribute(geometryChanging);
if (!stat) {
return stat;
}
stat = addAttribute(inputColor);
if (!stat) {
return stat;
}
outputColor = nAttr.
createColor(
"outputColor",
"ocl", &stat);
if (!stat) {
return stat;
}
stat = addAttribute(outputColor);
if (!stat) {
return stat;
}
attributeAffects(inputSize, outputSize);
attributeAffects(inputSize, geometryChanging);
attributeAffects(inputColor, outputColor);
return MS::kSuccess;
}
{
MFnPlugin plugin(obj, PLUGIN_COMPANY,
"3.0",
"Any");
Globals = new GlobalVariables();
status = plugin.registerNode(
gPluginNodeName,
FootPrintNode::id,
&FootPrintNode::creator,
&FootPrintNode::initialize,
&FootPrintNode::drawDbClassification);
if (!status) {
status.
perror(
"registerNode");
return status;
}
status = MDrawRegistry::registerGeometryOverrideCreator(
FootPrintNode::drawDbClassification,
FootPrintNode::drawRegistrantId,
FootPrintGeometryOverrideAnimatedMaterial::Creator);
if (!status) {
status.
perror(
"registerDrawOverrideCreator");
return status;
}
char cmd[256];
snprintf(cmd, sizeof(cmd), "selectType -byName \"%s\" 1", gPluginSelectionMask);
return status;
}
{
delete Globals;
MDrawRegistry::deregisterGeometryOverrideCreator(
FootPrintNode::drawDbClassification,
FootPrintNode::drawRegistrantId);
plugin.deregisterNode(FootPrintNode::id);
}