#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 <cassert>
#include <memory>
#include <unordered_map>
#include <atomic>
static constexpr unsigned int gPluginNodeId = 0x00080033;
static constexpr const char gPluginNodeName[] = "footPrint_GeometryOverride";
static constexpr const char gPluginDrawDbClassification[] = "drawdb/geometry/footPrint_GeometryOverride";
static constexpr const char gPluginDrawRegistrantId[] = "footPrintNode_GeometryOverridePlugin";
static constexpr const char gPluginSelectionMask[] = "footPrintSelection";
static constexpr const char gPluginNodeMessagePrefix[] = "FootPrintGeometryOverride: ";
{
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::geometryChanging = {};
const MTypeId FootPrintNode::id = gPluginNodeId;
const MString FootPrintNode::drawDbClassification = gPluginDrawDbClassification;
const MString FootPrintNode::drawRegistrantId = gPluginDrawRegistrantId;
FootPrintNode::FootPrintNode() {}
FootPrintNode::~FootPrintNode() {}
{
{
sizeHandle.
copy(inputSizeHandle);
}
{
}
else
{
return MS::kUnknownParameter;
}
}
{
{
{
MPlug osPlug(thisNode, outputSize);
MPlug scPlug(thisNode, geometryChanging);
}
}
}
{
if (evalType == PostEvaluationEnum::kEvaluatedDirectly &&
{
}
}
{
}
{
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;
}
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 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:
~FootPrintGeometryOverride() 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:
FootPrintGeometryOverride(
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;
};
FootPrintGeometryOverride::FootPrintGeometryOverride(
const MObject& obj)
, mFootPrintNode(nullptr)
{
MPxNode* footPrintNode = dependNode.userNode(&returnStatus);
mFootPrintNode = dynamic_cast<FootPrintNode*>(footPrintNode);
}
FootPrintGeometryOverride::~FootPrintGeometryOverride()
{}
void FootPrintGeometryOverride::updateDG()
{
mFootPrintNode->updateRenderAttributes();
}
bool FootPrintGeometryOverride::requiresUpdateRenderItems(
const MDagPath & path)
const
{
return false;
}
{
MColor color = MGeometryUtilities::wireframeColor(path);
int index = list.
indexOf(WireframeItemName);
if (index < 0)
{
wireframeItem = MRenderItem::Create(
WireframeItemName,
MRenderItem::DecorationItem,
MGeometry::kLines);
wireframeItem->
depthPriority(MRenderItem::sDormantWireDepthPriority);
} 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);
} else{
shadedItem = list.
itemAt(index);
}
if (shadedItem)
{
}
}
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 FootPrintGeometryOverride::requiresGeometryUpdate() const
{
return mFootPrintNode->isGeometryChanging();
}
namespace
{
static constexpr int soleCount = 21;
static constexpr int heelCount = 17;
}
void FootPrintGeometryOverride::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 FootPrintGeometryOverride::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 FootPrintGeometryOverride::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 FootPrintGeometryOverride::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 FootPrintGeometryOverride::traceCallSequence() const
{
return false;
}
inline void FootPrintGeometryOverride::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;
}
attributeAffects(inputSize, outputSize);
attributeAffects(inputSize, geometryChanging);
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,
FootPrintGeometryOverride::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);
}