#include <maya/MFnMesh.h>
#include <maya/MFloatPoint.h>
#include <maya/MFloatPointArray.h>
#include <maya/MIntArray.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MPxNode.h>
#include <maya/MObject.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MFnMeshData.h>
#include <maya/MIOStream.h>
#include <maya/MItMeshVertex.h>
#include "blindDataMesh.h"
MStatus returnStatus;
#define McheckErr(stat,msg) \
if ( MS::kSuccess != stat ) { \
cerr << msg; \
return MS::kFailure; \
}
MObject blindDataMesh::seed;
MObject blindDataMesh::outputMesh;
MTypeId blindDataMesh::id( 0x60EA );
void* blindDataMesh::creator()
{
return new blindDataMesh;
}
MStatus blindDataMesh::initialize()
{
MFnTypedAttribute typedAttr;
MStatus returnStatus;
blindDataMesh::outputMesh = typedAttr.create( "outputMesh", "out",
MFnData::kMesh, &returnStatus );
McheckErr(returnStatus, "ERROR creating blindDataMesh output attribute\n");
typedAttr.setStorable(false);
returnStatus = addAttribute(blindDataMesh::outputMesh);
McheckErr(returnStatus, "ERROR adding outputMesh attribute\n");
MFnNumericAttribute numAttr;
blindDataMesh::seed = numAttr.create( "randomSeed", "seed",
MFnNumericData::kLong, 0, &returnStatus );
McheckErr(returnStatus, "ERROR creating blindDataMesh input attribute\n");
returnStatus = addAttribute(blindDataMesh::seed);
McheckErr(returnStatus, "ERROR adding input attribute\n");
returnStatus = attributeAffects(blindDataMesh::seed,
blindDataMesh::outputMesh);
McheckErr(returnStatus, "ERROR in attributeAffects\n");
return MS::kSuccess;
}
MObject blindDataMesh::createMesh(long seed, MObject& outData, MStatus& stat)
{
MFloatPointArray vertices;
MIntArray faceDegrees;
MIntArray faceVertices;
int i, j;
srand(seed);
float planeSize = 20.0f;
float planeOffset = planeSize / 2.0f;
float planeDim = 0.5f;
int numDivisions = (int) (planeSize / planeDim);
int numFaces = numDivisions * numDivisions;
for (i = 0; i < (numDivisions + 1); ++i)
{
for (j = 0; j < (numDivisions + 1); ++j)
{
float height;
if (i == 0 && j == 0)
{
height = ((rand() % 101) / 100.0f - 0.5f);
}
else if (i == 0)
{
float previousHeight = vertices[j - 1][1];
height = previousHeight + ((rand() % 101) / 100.0f - 0.5f);
}
else if (j == 0)
{
float previousHeight = vertices[(i-1)*(numDivisions + 1)][1];
height = previousHeight + ((rand() % 101) / 100.0f - 0.5f);
}
else
{
float previousHeight
= vertices[(i-1)*(numDivisions + 1) + j][1];
float previousHeight2
= vertices[i*(numDivisions + 1) + j - 1][1];
height = (previousHeight + previousHeight2)
/ 2.0f + ((rand() % 101) / 100.0f - 0.5f);
}
MFloatPoint vtx( i * planeDim - planeOffset, height,
j * planeDim - planeOffset );
vertices.append(vtx);
}
}
for (i = 0; i < numFaces; ++i)
{
faceDegrees.append(4);
}
for (i = 0; i < numDivisions; ++i)
{
for (j = 0; j < numDivisions; ++j)
{
faceVertices.append(i*(numDivisions+1) + j);
faceVertices.append(i*(numDivisions+1) + j + 1);
faceVertices.append((i+1)*(numDivisions+1) + j + 1);
faceVertices.append((i+1)*(numDivisions+1) + j);
}
}
MFnMesh meshFn;
MObject newMesh = meshFn.create(vertices.length(), numFaces, vertices,
faceDegrees, faceVertices, outData, &stat);
return newMesh;
}
MStatus blindDataMesh::compute(const MPlug& plug, MDataBlock& data)
{
MStatus returnStatus;
if (plug == outputMesh) {
MDataHandle seedHandle = data.inputValue(seed, &returnStatus);
McheckErr(returnStatus,"ERROR getting random number generator seed\n");
long seed = seedHandle.asLong();
MFnMeshData dataCreator;
MDataHandle outputHandle = data.outputValue(outputMesh, &returnStatus);
McheckErr(returnStatus, "ERROR getting polygon data handle\n");
MObject newOutputData = dataCreator.create(&returnStatus);
McheckErr(returnStatus, "ERROR creating outputData");
createMesh(seed, newOutputData, returnStatus);
McheckErr(returnStatus, "ERROR creating new plane");
returnStatus = setMeshBlindData(newOutputData);
McheckErr(returnStatus, "ERROR setting the blind Data on the plane");
outputHandle.set(newOutputData);
data.setClean( plug );
} else
return MS::kUnknownParameter;
return MS::kSuccess;
}
MStatus blindDataMesh::setMeshBlindData(MObject& mesh)
{
MStatus stat = MS::kSuccess;
MFnMesh meshFn(mesh);
int blindDataID = 60;
if (!meshFn.isBlindDataTypeUsed(blindDataID, &stat))
{
MStringArray longNames, shortNames, formatNames;
longNames.append("red_color");
shortNames.append("red");
formatNames.append("double");
longNames.append("green");
shortNames.append("grn");
formatNames.append("double");
longNames.append("blue_color");
shortNames.append("blue");
formatNames.append("double");
stat = meshFn.createBlindDataType(
blindDataID, longNames, shortNames, formatNames );
if (!stat) return stat;
}
else if (!stat) return stat;
MItMeshVertex itVertex(mesh);
double lowest = 1e10, highest = -1e10;
for ( ; !itVertex.isDone(); itVertex.next() )
{
MPoint vertexPosition = itVertex.position();
double height = vertexPosition[1];
if (height < lowest) lowest = height;
if (height > highest) highest = height;
}
double range = highest - lowest;
for ( itVertex.reset(mesh); !itVertex.isDone(); itVertex.next() )
{
MPoint vertexPosition = itVertex.position();
double height = vertexPosition[1] - lowest;
double red, green, blue;
red = 2.0 * ( height / range ) - 1.0;
if (height > range/2.0) {
if (red < 0.7) green = 0.7;
else green = red;
}
else green = 0.7 * (1.0 - (((range/2.0) - height) / (range/2.0))
* (((range/2.0) - height) / (range/2.0)));
if (height > range/2.0) blue = red;
else blue = 1.0 - (green*green);
if (red < 0.0) red = 0.0;
stat = meshFn.setDoubleBlindData(itVertex.index(),
MFn::kMeshVertComponent, blindDataID, "red", red);
if (!stat) return stat;
stat = meshFn.setDoubleBlindData(itVertex.index(),
MFn::kMeshVertComponent, blindDataID, "green", green);
if (!stat) return stat;
stat = meshFn.setDoubleBlindData(itVertex.index(),
MFn::kMeshVertComponent, blindDataID, "blue", blue);
if (!stat) return stat;
}
return stat;
}