#ifndef _gpuCacheUtil_h_
#define _gpuCacheUtil_h_
#include <cassert>
#include <maya/MPlugArray.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnMesh.h>
#include <maya/MPlug.h>
#include <maya/MFloatArray.h>
#include <maya/MFloatVector.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MFloatPoint.h>
#include <maya/MFloatPointArray.h>
#include <maya/MGlobal.h>
#include <maya/MStringResource.h>
#include <boost/shared_array.hpp>
#include <unordered_set>
#include <unordered_map>
#include <boost/functional/hash.hpp>
#include <boost/noncopyable.hpp>
#include <map>
#include "gpuCacheSample.h"
#include "gpuCacheGeometry.h"
#include "gpuCacheMaterialNodes.h"
#ifdef _DEBUG
#define MStatAssert(status) assert(status)
#else
#define MStatAssert(status) ((void)status)
#endif
namespace GPUCache {
class ShapeVisibilityChecker
{
public:
ShapeVisibilityChecker(
const MObject& shapeNode)
: fShape(shapeNode)
{}
bool isVisible()
{
MPlug visibilityPlug = fShape.findPlug(
"visibility");
assert(!visibilityPlug.
isNull());
if (!visibilityPlug.
asBool()) {
return false;
}
MPlug drawOverridePlug = fShape.findPlug(
"drawOverride");
assert(!drawOverridePlug.
isNull());
drawOverridePlug.
connectedTo(displayLayers,
true,
false);
for (unsigned int i = 0; i < displayLayers.length(); i++) {
MObject displayLayerNode = displayLayers[i].node();
visibilityPlug = displayLayer.
findPlug(
"visibility");
assert(!visibilityPlug.
isNull());
if (!visibilityPlug.
asBool()) {
return false;
}
}
}
return true;
}
private:
ShapeVisibilityChecker(const ShapeVisibilityChecker&);
const ShapeVisibilityChecker& operator=(const ShapeVisibilityChecker&);
};
template<class INDEX_TYPE>
class WireIndicesGenerator
{
public:
typedef INDEX_TYPE index_type;
WireIndicesGenerator(size_t numFaceCounts, const unsigned int* faceCounts,
size_t numFaceIndices, const index_type* faceIndices,
const index_type* mappedFaceIndices)
: fNumFaceCounts(numFaceCounts), fFaceCounts(faceCounts),
fNumFaceIndices(numFaceIndices), fFaceIndices(faceIndices),
fMappedFaceIndices(mappedFaceIndices),
fNumWires(0)
{}
void compute()
{
if (fNumFaceCounts == 0 || fNumFaceIndices == 0) {
return;
}
size_t maxNumWires = fNumFaceIndices;
std::unordered_set<WirePair, typename WirePair::Hash, typename WirePair::EqualTo>
wireSet(size_t(maxNumWires / 0.75f));
size_t polyIndex = 0;
size_t endOfPoly = fFaceCounts[polyIndex];
for (size_t i = 0; i < fNumFaceIndices; i++) {
index_type v1, v2, mappedV1, mappedV2;
v1 = fFaceIndices[i];
mappedV1 = fMappedFaceIndices[i];
size_t v2Index;
if (i + 1 == endOfPoly) {
v2Index = i + 1 - fFaceCounts[polyIndex];
if (++polyIndex < fNumFaceCounts) {
endOfPoly += fFaceCounts[polyIndex];
}
}
else {
v2Index = i + 1;
}
v2 = fFaceIndices[v2Index];
mappedV2 = fMappedFaceIndices[v2Index];
wireSet.insert(WirePair(v1, v2, mappedV1, mappedV2));
}
size_t numWires = wireSet.size();
boost::shared_array<index_type> wireIndices(new index_type[numWires * 2]);
size_t wireCount = 0;
for(const WirePair& pair : wireSet) {
wireIndices[wireCount * 2 + 0] = pair.fMappedV1;
wireIndices[wireCount * 2 + 1] = pair.fMappedV2;
wireCount++;
}
fNumWires = numWires;
fWireIndices = wireIndices;
}
size_t numWires() { return fNumWires; }
boost::shared_array<index_type>& wireIndices() { return fWireIndices; }
private:
WireIndicesGenerator(const WireIndicesGenerator&);
const WireIndicesGenerator& operator= (const WireIndicesGenerator&);
struct WirePair
{
WirePair(index_type v1, index_type v2,
index_type mappedV1, index_type mappedV2)
: fV1(v1), fV2(v2), fMappedV1(mappedV1), fMappedV2(mappedV2)
{}
struct Hash : std::unary_function<WirePair, std::size_t>
{
std::size_t operator()(const WirePair& pair) const
{
std::size_t seed = 0;
if (pair.fV1 < pair.fV2) {
boost::hash_combine(seed, pair.fV1);
boost::hash_combine(seed, pair.fV2);
}
else {
boost::hash_combine(seed, pair.fV2);
boost::hash_combine(seed, pair.fV1);
}
return seed;
}
};
struct EqualTo : std::binary_function<WirePair, WirePair, bool>
{
bool operator()(const WirePair& x, const WirePair& y) const
{
if (x.fV1 < x.fV2) {
if (y.fV1 < y.fV2) {
return (x.fV1 == y.fV1 && x.fV2 == y.fV2);
}
else {
return (x.fV1 == y.fV2 && x.fV2 == y.fV1);
}
}
else {
if (y.fV1 < y.fV2) {
return (x.fV2 == y.fV1 && x.fV1 == y.fV2);
}
else {
return (x.fV2 == y.fV2 && x.fV1 == y.fV1);
}
}
}
};
index_type fV1, fV2;
index_type fMappedV1, fMappedV2;
};
size_t fNumFaceCounts;
const unsigned int* fFaceCounts;
size_t fNumFaceIndices;
const index_type* fFaceIndices;
const index_type* fMappedFaceIndices;
size_t fNumWires;
boost::shared_array<index_type> fWireIndices;
};
template<class INDEX_TYPE, size_t MAX_NUM_STREAMS = 16>
class MultiIndexedStreamsConverter
{
public:
typedef INDEX_TYPE index_type;
MultiIndexedStreamsConverter(size_t numFaceIndices, const index_type* faceIndices)
: fNumFaceIndices(numFaceIndices), fFaceIndices(faceIndices), fNumStreams(0),
fNumVertices(0)
{
addMultiIndexedStream(faceIndices);
}
void addMultiIndexedStream(const index_type* indices)
{
fStreams[fNumStreams++] = indices;
assert(fNumStreams <= MAX_NUM_STREAMS);
}
void compute()
{
boost::shared_array<index_type> indicesRegion(
new index_type[fNumStreams * fNumFaceIndices]);
typedef std::unordered_map<IndexTuple,size_t,typename IndexTuple::Hash,typename IndexTuple::EqualTo> IndicesMap;
IndicesMap indicesMap(size_t(fNumFaceIndices / 0.75f));
size_t vertexAttribIndex = 0;
boost::shared_array<index_type> mappedFaceIndices(new index_type[fNumFaceIndices]);
for (size_t i = 0; i < fNumFaceIndices; i++) {
index_type* indices = &indicesRegion[i * fNumStreams];
for (unsigned int j = 0; j < fNumStreams; j++) {
indices[j] = fStreams[j] ? fStreams[j][i] : (index_type)i;
}
IndexTuple tuple(indices, fNumStreams, (unsigned int)i);
std::pair<typename IndicesMap::iterator,bool> ret = indicesMap.insert(std::make_pair(tuple, 0));
if (ret.second) {
ret.first->second = vertexAttribIndex++;
}
mappedFaceIndices[i] = (index_type)ret.first->second;
}
size_t numVertex = vertexAttribIndex;
assert(vertexAttribIndex == indicesMap.size());
boost::shared_array<unsigned int> vertAttribsIndices(new unsigned int[numVertex]);
for(const typename IndicesMap::value_type& pair : indicesMap) {
vertAttribsIndices[pair.second] = pair.first.faceIndex();
}
fMappedFaceIndices = mappedFaceIndices;
fVertAttribsIndices = vertAttribsIndices;
fNumVertices = numVertex;
}
unsigned int numStreams() { return fNumStreams; }
size_t numVertices() { return fNumVertices; }
boost::shared_array<unsigned int>& vertAttribsIndices() { return fVertAttribsIndices; }
boost::shared_array<index_type>& mappedFaceIndices() { return fMappedFaceIndices; }
private:
MultiIndexedStreamsConverter(const MultiIndexedStreamsConverter&);
const MultiIndexedStreamsConverter& operator= (const MultiIndexedStreamsConverter&);
class IndexTuple
{
public:
IndexTuple(index_type* indices, unsigned int size, unsigned int faceIndex)
: fIndices(indices), fSize(size), fFaceIndex(faceIndex)
{}
const index_type& operator[](unsigned int index) const
{
assert(index < fSize);
return fIndices[index];
}
unsigned int faceIndex() const
{
return fFaceIndex;
}
struct Hash : std::unary_function<IndexTuple, std::size_t>
{
std::size_t operator()(const IndexTuple& tuple) const
{
std::size_t seed = 0;
for (unsigned int i = 0; i < tuple.fSize; i++) {
boost::hash_combine(seed, tuple.fIndices[i]);
}
return seed;
}
};
struct EqualTo : std::binary_function<IndexTuple, IndexTuple, bool>
{
bool operator()(const IndexTuple& x, const IndexTuple& y) const
{
if (x.fSize == y.fSize) {
return memcmp(x.fIndices, y.fIndices, sizeof(index_type) * x.fSize) == 0;
}
return false;
}
};
private:
index_type* fIndices;
unsigned int fFaceIndex;
unsigned int fSize;
};
size_t fNumFaceIndices;
const index_type* fFaceIndices;
const index_type* fStreams[MAX_NUM_STREAMS];
unsigned int fNumStreams;
size_t fNumVertices;
boost::shared_array<unsigned int> fVertAttribsIndices;
boost::shared_array<index_type> fMappedFaceIndices;
};
template<class INDEX_TYPE, size_t SIZE>
class IndicesDropper
{
public:
typedef INDEX_TYPE index_type;
IndicesDropper(const float* attribArray, const index_type* indexArray, size_t numVerts)
{
boost::shared_array<float> mappedAttribs(new float[numVerts * SIZE]);
for (size_t i = 0; i < numVerts; i++) {
for (size_t j = 0; j < SIZE; j++) {
mappedAttribs[i * SIZE + j] = attribArray[indexArray[i] * SIZE + j];
}
}
fMappedAttribs = mappedAttribs;
}
boost::shared_array<float>& mappedAttribs() { return fMappedAttribs; }
private:
IndicesDropper(const IndicesDropper&);
const IndicesDropper& operator= (const IndicesDropper&);
boost::shared_array<float> fMappedAttribs;
};
template<class INDEX_TYPE, size_t MAX_NUM_STREAMS = 16>
class MultiIndexedStreamsRemapper
{
public:
typedef INDEX_TYPE index_type;
MultiIndexedStreamsRemapper(const index_type* faceIndices,
size_t numNewVertices, const unsigned int* vertAttribsIndices)
: fFaceIndices(faceIndices), fNumNewVertices(numNewVertices),
fVertAttribsIndices(vertAttribsIndices), fNumStreams(0)
{}
void addMultiIndexedStream(const float* attribs, const index_type* indices, bool faceVarying, int stride)
{
fAttribs[fNumStreams] = attribs;
fIndices[fNumStreams] = indices;
fFaceVarying[fNumStreams] = faceVarying;
fStride[fNumStreams] = stride;
fNumStreams++;
}
void compute()
{
for (unsigned int i = 0; i < fNumStreams; i++) {
const float* attribs = fAttribs[i];
const index_type* indices = fIndices[i];
bool faceVarying = fFaceVarying[i];
int stride = fStride[i];
boost::shared_array<float> mappedVertAttrib(
new float[fNumNewVertices * stride]);
for (size_t j = 0; j < fNumNewVertices; j++) {
unsigned int polyVertIndex = fVertAttribsIndices[j];
index_type pointOrPolyVertIndex = faceVarying ?
polyVertIndex : fFaceIndices[polyVertIndex];
index_type attribIndex = indices ?
indices[pointOrPolyVertIndex] : pointOrPolyVertIndex;
if (stride == 3) {
mappedVertAttrib[j * 3 + 0] = attribs[attribIndex * 3 + 0];
mappedVertAttrib[j * 3 + 1] = attribs[attribIndex * 3 + 1];
mappedVertAttrib[j * 3 + 2] = attribs[attribIndex * 3 + 2];
}
else if (stride == 2) {
mappedVertAttrib[j * 2 + 0] = attribs[attribIndex * 2 + 0];
mappedVertAttrib[j * 2 + 1] = attribs[attribIndex * 2 + 1];
}
else {
assert(0);
}
}
fMappedVertAttribs[i] = mappedVertAttrib;
}
}
boost::shared_array<float>& mappedVertAttribs(unsigned int index)
{
assert(index < fNumStreams);
return fMappedVertAttribs[index];
}
private:
MultiIndexedStreamsRemapper(const MultiIndexedStreamsRemapper&);
const MultiIndexedStreamsRemapper& operator= (const MultiIndexedStreamsRemapper&);
const index_type* fFaceIndices;
size_t fNumNewVertices;
const unsigned int* fVertAttribsIndices;
const float* fAttribs[MAX_NUM_STREAMS];
const index_type* fIndices[MAX_NUM_STREAMS];
bool fFaceVarying[MAX_NUM_STREAMS];
int fStride[MAX_NUM_STREAMS];
unsigned int fNumStreams;
boost::shared_array<float> fMappedVertAttribs[MAX_NUM_STREAMS];
};
template<class INDEX_TYPE>
class PolyTriangulator
{
public:
typedef INDEX_TYPE index_type;
PolyTriangulator(size_t numFaceCounts, const unsigned int* faceCounts,
const index_type* faceIndices, bool faceIndicesCW,
const float* positions, const float* normals)
: fNumFaceCounts(numFaceCounts), fFaceCounts(faceCounts),
fFaceIndices(faceIndices), fFaceIndicesCW(faceIndicesCW),
fPositions(positions), fNormals(normals),
fNumTriangles(0)
{}
void compute()
{
if (fNumFaceCounts == 0) {
return;
}
size_t maxPoints = 0;
size_t totalTriangles = 0;
for (size_t i = 0; i < fNumFaceCounts; i++) {
size_t numPoints = fFaceCounts[i];
if (numPoints < 3) {
continue;
}
maxPoints = std::max(numPoints, maxPoints);
size_t numTriangles = numPoints - 2;
totalTriangles += numTriangles;
}
size_t maxTriangles = maxPoints - 2;
boost::shared_array<index_type> indices(new index_type[maxPoints]);
boost::shared_array<unsigned short> triangles(new unsigned short[maxTriangles * 3]);
boost::shared_array<float> aPosition(new float[maxPoints * 2]);
boost::shared_array<float> aNormal;
if (fNormals) {
aNormal.reset(new float[maxPoints * 3]);
}
boost::shared_array<index_type> triangleIndices(new index_type[totalTriangles * 3]);
size_t triangleCount = 0;
for (size_t i = 0, polyVertOffset = 0; i < fNumFaceCounts; polyVertOffset += fFaceCounts[i], i++) {
size_t numPoints = fFaceCounts[i];
if (numPoints < 3) {
continue;
}
if (numPoints == 3) {
if (fFaceIndicesCW) {
triangleIndices[triangleCount * 3 + 0] = fFaceIndices[polyVertOffset + 2];
triangleIndices[triangleCount * 3 + 1] = fFaceIndices[polyVertOffset + 1];
triangleIndices[triangleCount * 3 + 2] = fFaceIndices[polyVertOffset + 0];
}
else {
triangleIndices[triangleCount * 3 + 0] = fFaceIndices[polyVertOffset + 0];
triangleIndices[triangleCount * 3 + 1] = fFaceIndices[polyVertOffset + 1];
triangleIndices[triangleCount * 3 + 2] = fFaceIndices[polyVertOffset + 2];
}
triangleCount++;
continue;
}
if (fFaceIndicesCW)
{
for (size_t j = 0; j < numPoints; j++) {
size_t jCCW = numPoints - j - 1;
indices[j] = fFaceIndices[polyVertOffset + jCCW];
}
}
else {
for (size_t j = 0; j < numPoints; j++) {
indices[j] = fFaceIndices[polyVertOffset + j];
}
}
for (size_t j = 0; j < numPoints; j++) {
const float* thisPoint = &fPositions[indices[j] * 3];
const float* nextPoint = &fPositions[indices[(j + numPoints - 1) % numPoints] * 3];
faceNormal.
x += (thisPoint[1] - nextPoint[1]) * (thisPoint[2] + nextPoint[2]);
faceNormal.
y += (thisPoint[2] - nextPoint[2]) * (thisPoint[0] + nextPoint[0]);
faceNormal.
z += (thisPoint[0] - nextPoint[0]) * (thisPoint[1] + nextPoint[1]);
}
float cosa, sina, cosb, sinb, cacb, sacb;
sinb = -sqrtf(faceNormal[0] * faceNormal[0] + faceNormal[1] * faceNormal[1]);
if (sinb < -1e-5) {
cosb = faceNormal[2];
sina = faceNormal[1] / sinb;
cosa = -faceNormal[0] / sinb;
cacb = cosa * cosb;
sacb = sina * cosb;
}
else {
cacb = 1.0f;
sacb = 0.0f;
sinb = 0.0f;
sina = 0.0f;
if (faceNormal[2] > 0.0f) {
cosa = 1.0f;
cosb = 1.0f;
}
else {
cosa = -1.0f;
cosb = -1.0f;
}
}
for (size_t j = 0; j < numPoints; j++) {
const float* point = &fPositions[indices[j] * 3];
aPosition[j * 2 + 0] = cacb * point[0] - sacb * point[1] + sinb * point[2];
aPosition[j * 2 + 1] = sina * point[0] + cosa * point[1];
}
if (fNormals) {
for (size_t j = 0; j < numPoints; j++) {
aNormal[j * 3 + 0] = fNormals[indices[j] * 3 + 0];
aNormal[j * 3 + 1] = fNormals[indices[j] * 3 + 1];
aNormal[j * 3 + 2] = fNormals[indices[j] * 3 + 2];
}
}
int numResultTriangles = 0;
aPosition.get(),
(unsigned int)numPoints,
(unsigned int)numPoints,
0,
fNormals != NULL,
aNormal.get(),
triangles.get(),
numResultTriangles);
if (numResultTriangles == int(numPoints - 2)) {
for (size_t j = 0; j < size_t(numResultTriangles); j++) {
triangleIndices[triangleCount * 3 + 0] = indices[triangles[j * 3 + 0]];
triangleIndices[triangleCount * 3 + 1] = indices[triangles[j * 3 + 1]];
triangleIndices[triangleCount * 3 + 2] = indices[triangles[j * 3 + 2]];
triangleCount++;
}
}
else {
for (size_t j = 1; j < numPoints - 1; j++) {
triangleIndices[triangleCount * 3 + 0] = indices[0];
triangleIndices[triangleCount * 3 + 1] = indices[j];
triangleIndices[triangleCount * 3 + 2] = indices[j + 1];
triangleCount++;
}
}
}
fNumTriangles = totalTriangles;
fTriangleIndices = triangleIndices;
}
size_t numTriangles() { return fNumTriangles; }
boost::shared_array<index_type>& triangleIndices() { return fTriangleIndices; }
private:
PolyTriangulator(const PolyTriangulator&);
const PolyTriangulator& operator= (const PolyTriangulator&);
size_t fNumFaceCounts;
const unsigned int* fFaceCounts;
const index_type* fFaceIndices;
bool fFaceIndicesCW;
const float* fPositions;
const float* fNormals;
size_t fNumTriangles;
boost::shared_array<index_type> fTriangleIndices;
};
template<class INDEX_TYPE>
class MayaMeshExtractor
{
public:
typedef INDEX_TYPE index_type;
MayaMeshExtractor(
const MObject& meshObj)
: fPolyMesh(meshObj), fWantUVs(true)
{}
void setWantUVs(bool wantUVs) { fWantUVs = wantUVs; }
void compute()
{
bool needTriangulate = false;
size_t numFaceCounts;
boost::shared_array<unsigned int> faceCounts;
size_t numFaceIndices;
boost::shared_array<index_type> faceIndices;
{
status = fPolyMesh.getVertices(mayaVertexCount, mayaVertexList);
assert(status == MS::kSuccess);
numFaceCounts = mayaVertexCount.
length();
const int* srcVertexCount = &mayaVertexCount[0];
faceCounts.reset(new unsigned int[numFaceCounts]);
for (size_t i = 0; i < numFaceCounts; i++) {
faceCounts[i] = srcVertexCount[i];
if (faceCounts[i] != 3) needTriangulate = true;
}
numFaceIndices = mayaVertexList.
length();
const int* srcVertexList = &mayaVertexList[0];
faceIndices.reset(new index_type[numFaceIndices]);
for (size_t i = 0; i < numFaceIndices; i++) {
faceIndices[i] = srcVertexList[i];
}
}
boost::shared_array<float> positions;
{
status = fPolyMesh.getPoints(mayaPositions);
assert(status == MS::kSuccess);
unsigned int numPositions = mayaPositions.
length();
positions.reset(new float[numPositions * 3]);
for (unsigned int i = 0; i < numPositions; i++) {
positions[i * 3 + 0] = point.
x;
positions[i * 3 + 1] = point.
y;
positions[i * 3 + 2] = point.
z;
}
}
boost::shared_array<float> normals;
boost::shared_array<index_type> normalIndices;
{
status = fPolyMesh.getNormals(mayaNormals);
assert(status == MS::kSuccess);
status = fPolyMesh.getNormalIds(mayaNormalIdCounts, mayaNormalIds);
assert(status == MS::kSuccess);
unsigned int numNormals = mayaNormals.
length();
unsigned int numNormalIds = mayaNormalIds.
length();
normals.reset(new float[numNormals * 3]);
normalIndices.reset(new index_type[numNormalIds]);
for (unsigned int i = 0; i < numNormals; i++) {
normals[i * 3 + 0] = normal.
x;
normals[i * 3 + 1] = normal.
y;
normals[i * 3 + 2] = normal.
z;
}
for (unsigned int i = 0; i < numNormalIds; i++) {
normalIndices[i] = mayaNormalIds[i];
}
}
boost::shared_array<float> UVs;
boost::shared_array<index_type> uvIndices;
if (fWantUVs) {
status = fPolyMesh.getUVs(mayaUArray, mayaVArray);
assert(status == MS::kSuccess);
status = fPolyMesh.getAssignedUVs(mayaUVCounts, mayaUVIds);
assert(status == MS::kSuccess);
unsigned int numUVs = mayaUArray.
length();
unsigned int numUVIds = mayaUVIds.
length();
if (numUVs > 0 && numUVIds > 0) {
UVs.reset(new float[numUVs * 2]);
uvIndices.reset(new index_type[numUVIds]);
for (unsigned int i = 0; i < numUVs; i++) {
UVs[i * 2 + 0] = mayaUArray[i];
UVs[i * 2 + 1] = mayaVArray[i];
}
for (unsigned int i = 0; i < numUVIds; i++) {
uvIndices[i] = mayaUVIds[i];
}
}
}
size_t numVertices = 0;
boost::shared_array<index_type> mappedFaceIndices;
boost::shared_array<unsigned int> vertAttribsIndices;
{
MultiIndexedStreamsConverter<index_type>
converter(numFaceIndices, faceIndices.get());
converter.addMultiIndexedStream(normalIndices.get());
if (fWantUVs && uvIndices) {
converter.addMultiIndexedStream(uvIndices.get());
}
converter.compute();
numVertices = converter.numVertices();
mappedFaceIndices = converter.mappedFaceIndices();
vertAttribsIndices = converter.vertAttribsIndices();
}
boost::shared_array<float> mappedPositions;
boost::shared_array<float> mappedNormals;
boost::shared_array<float> mappedUVs;
{
MultiIndexedStreamsRemapper<index_type>
remapper(faceIndices.get(), numVertices, vertAttribsIndices.get());
remapper.addMultiIndexedStream(positions.get(), NULL, false, 3);
remapper.addMultiIndexedStream(normals.get(), normalIndices.get(), true, 3);
if (fWantUVs && UVs && uvIndices) {
remapper.addMultiIndexedStream(UVs.get(), uvIndices.get(), true, 2);
}
remapper.compute();
mappedPositions = remapper.mappedVertAttribs(0);
mappedNormals = remapper.mappedVertAttribs(1);
if (fWantUVs && UVs && uvIndices) {
mappedUVs = remapper.mappedVertAttribs(2);
}
}
size_t numWires = 0;
boost::shared_array<index_type> wireIndices;
{
WireIndicesGenerator<index_type> wireIndicesGenerator(
numFaceCounts, faceCounts.get(),
numFaceIndices, faceIndices.get(),
mappedFaceIndices.get());
wireIndicesGenerator.compute();
numWires = wireIndicesGenerator.numWires();
wireIndices = wireIndicesGenerator.wireIndices();
}
size_t numTriangles = 0;
boost::shared_array<index_type> triangleIndices;
if (needTriangulate) {
PolyTriangulator<index_type> polyTriangulator(
numFaceCounts, faceCounts.get(),
mappedFaceIndices.get(), false,
mappedPositions.get(), mappedNormals.get());
polyTriangulator.compute();
numTriangles = polyTriangulator.numTriangles();
triangleIndices = polyTriangulator.triangleIndices();
}
else {
assert(numFaceIndices % 3 == 0);
numTriangles = numFaceIndices / 3;
triangleIndices = mappedFaceIndices;
}
fWireIndices = SharedArray<index_type>::create(
wireIndices, numWires * 2);
fTriangleIndices = SharedArray<index_type>::create(
triangleIndices, numTriangles * 3);
fPositions = SharedArray<float>::create(
mappedPositions, numVertices * 3);
fNormals = SharedArray<float>::create(
mappedNormals, numVertices * 3);
if (fWantUVs && mappedUVs) {
fUVs = SharedArray<float>::create(
mappedUVs, numVertices * 2);
}
}
std::shared_ptr<ReadableArray<index_type> >& triangleIndices()
{ return fTriangleIndices; }
std::shared_ptr<ReadableArray<index_type> >& wireIndices()
{ return fWireIndices; }
std::shared_ptr<ReadableArray<float> >& positions()
{ return fPositions; }
std::shared_ptr<ReadableArray<float> >& normals()
{ return fNormals; }
std::shared_ptr<ReadableArray<float> >& uvs()
{ return fUVs; }
private:
MayaMeshExtractor(const MayaMeshExtractor&);
const MayaMeshExtractor& operator= (const MayaMeshExtractor&);
bool fWantUVs;
std::shared_ptr<ReadableArray<index_type> > fTriangleIndices;
std::shared_ptr<ReadableArray<index_type> > fWireIndices;
std::shared_ptr<ReadableArray<float> > fPositions;
std::shared_ptr<ReadableArray<float> > fNormals;
std::shared_ptr<ReadableArray<float> > fUVs;
};
class SubNodeTransparentTypeVisitor : public SubNodeVisitor
{
public:
SubNodeTransparentTypeVisitor() {}
~SubNodeTransparentTypeVisitor() override {}
void visit(const XformData& xform,
const SubNode& subNode) override
{
fTransparentTypes.push_back(SubNode::kUnknown);
for(const SubNode::Ptr& child : subNode.getChildren()) {
child->accept(*this);
}
const_cast<SubNode&>(subNode).setTransparentType(fTransparentTypes.back());
fTransparentTypes.pop_back();
}
void visit(const ShapeData& shape,
const SubNode& subNode) override
{
for (size_t i = 0; i < fTransparentTypes.size(); i++) {
if (fTransparentTypes[i] == SubNode::kUnknown) {
fTransparentTypes[i] = subNode.transparentType();
}
else {
if (fTransparentTypes[i] != subNode.transparentType()) {
fTransparentTypes[i] = SubNode::kOpaqueAndTransparent;
}
}
}
}
private:
std::vector<SubNode::TransparentType> fTransparentTypes;
};
class BoundingBoxVisitor : public SubNodeVisitor
{
public:
BoundingBoxVisitor(double timeInSeconds)
: fTimeInSeconds(timeInSeconds)
{}
~BoundingBoxVisitor() override {}
{ return fBoundingBox; }
void visit(const XformData& xform,
const SubNode& subNode) override
{
const std::shared_ptr<const XformSample>& sample =
xform.getSample(fTimeInSeconds);
if (sample) {
fBoundingBox = sample->boundingBox();
}
}
void visit(const ShapeData& shape,
const SubNode& subNode) override
{
const std::shared_ptr<const ShapeSample>& sample =
shape.getSample(fTimeInSeconds);
if (sample) {
fBoundingBox = sample->boundingBox();
}
}
static MBoundingBox boundingBox(
const SubNode::Ptr& subNode,
const double timeInSeconds)
{
if (subNode) {
BoundingBoxVisitor visitor(timeInSeconds);
subNode->accept(visitor);
return visitor.boundingBox();
}
}
private:
const double fTimeInSeconds;
};
class ShapePathVisitor : public SubNodeVisitor
{
public:
typedef std::pair<MString,const SubNode*> ShapePathAndSubNode;
typedef std::vector<ShapePathAndSubNode> ShapePathAndSubNodeList;
ShapePathVisitor(ShapePathAndSubNodeList& shapePaths)
: fShapePaths(shapePaths)
{}
~ShapePathVisitor() override
{}
void visit(const XformData& xform,
const SubNode& subNode) override
{
bool isTop = subNode.getName() == "|";
if (!isTop) fCurrentPath.push_back(subNode.getName());
for(const SubNode::Ptr& child : subNode.getChildren()) {
child->accept(*this);
}
if (!isTop) fCurrentPath.pop_back();
}
void visit(const ShapeData& shape,
const SubNode& subNode) override
{
for (size_t i = 0; i < fCurrentPath.size(); i++) {
path += "|";
path += fCurrentPath[i];
}
path += "|";
path += subNode.getName();
fShapePaths.push_back(
std::make_pair(path, &subNode));
}
private:
ShapePathAndSubNodeList& fShapePaths;
std::vector<MString> fCurrentPath;
};
inline bool ReplaceSubNodeData(
const SubNode::Ptr& top,
const SubNode::Ptr& node,
const MString& path)
{
if (steps.
length() == 0)
return false;
SubNode::Ptr firstNode;
if (top->getName() == "|") {
for(const SubNode::Ptr& child : top->getChildren()) {
if (child->getName() == steps[0]) {
firstNode = child;
break;
}
}
}
else {
if (top->getName() == steps[0]) {
firstNode = top;
}
}
if (!firstNode) return false;
SubNode::Ptr current = firstNode;
for (
unsigned int i = 1; i < steps.
length(); i++) {
bool found = false;
for(const SubNode::Ptr& child : current->getChildren()) {
if (child->getName() == steps[i]) {
current = child;
found = true;
break;
}
}
if (!found) return false;
}
assert(current);
assert(node);
SubNode::MPtr mCurrent = std::const_pointer_cast<SubNode>(current);
SubNode::MPtr mNode = std::const_pointer_cast<SubNode>(node);
SubNode::swapNodeData(mCurrent, mNode);
return true;
}
inline bool ValidateGeomPath(
const SubNode::Ptr& top,
const MString& geomPath,
MString& validatedGeomPath)
{
if( !top )
{
return false;
}
geomPath.
split(
'|', pathArray);
bool valid = true;
const bool isTop = top->getParents().empty() && top->getName() == "|";
if (!isTop && pathArray.
length() > 0)
{
if (top->getName() == pathArray[0])
{
validatedGeomPath =
MString(
"|") + pathArray[0];
}
else
{
return false;
}
}
SubNode::Ptr current = top;
for(
unsigned int i = 0; i < pathArray.
length(); i++ )
{
bool foundChild = false;
const std::vector<SubNode::Ptr>& children = current->getChildren();
for( unsigned int j = 0; j < children.size(); j++ )
{
if( children[j]->getName() == step )
{
current = children[j];
foundChild = true;
}
}
if( !foundChild )
{
valid = false;
break;
}
validatedGeomPath += step;
}
if (validatedGeomPath.
length() == 0) {
}
return valid;
}
inline bool CreateSubNodeHierarchy(
const SubNode::Ptr& top,
const MString& geomPath,
MString& validatedGeomPath, SubNode::Ptr& out)
{
if( !top )
{
return false;
}
ValidateGeomPath( top, geomPath, validatedGeomPath );
validatedGeomPath.
split(
'|', pathArray);
const bool isTop = top->getParents().empty() && top->getName() == "|";
if (!isTop && pathArray.
length() > 0)
{
}
{
out = top;
}
else
{
SubNode::MPtr copyTop = SubNode::create( top->getName(), top->getData() );
copyTop->setTransparentType( top->transparentType() );
SubNode::MPtr copyCurrent = copyTop;
SubNode::Ptr current = top;
for(
unsigned int i = 0; i < pathArray.
length(); i++ )
{
const std::vector<SubNode::Ptr>& children = current->getChildren();
bool foundChild = false;
for( unsigned int j = 0; j < children.size(); j++ )
{
if( children[j]->getName() == step )
{
current = children[j];
foundChild = true;
break;
}
}
assert(foundChild);
SubNode::MPtr copyChild;
if( i+1 < pathArray.
length() )
{
copyChild = SubNode::create( current->getName(), current->getData() );
copyChild->setTransparentType( current->transparentType() );
}
else
{
copyChild = std::const_pointer_cast<SubNode>(current);
}
SubNode::connect(copyCurrent, copyChild);
copyCurrent = copyChild;
}
out = copyTop;
}
return true;
}
class InstanceMaterialLookup : boost::noncopyable
{
public:
InstanceMaterialLookup(
const MDagPath& dagPath);
~InstanceMaterialLookup();
bool hasWholeObjectMaterial();
MObject findWholeObjectShadingGroup();
MObject findWholeObjectSurfaceMaterial();
bool hasComponentMaterials();
bool findShadingGroups(std::vector<MObject>& shadingGroups);
bool findSurfaceMaterials(std::vector<MObject>& surfaceMaterials);
private:
static MObject findShadingGroupByPlug(
const MPlug& srcPlug);
static MObject findSurfaceMaterialByShadingGroup(
const MObject& shadingGroup);
static void findObjectGroupsPlug(
const MPlug& iogPlug, std::vector<MPlug>& ogPlugs);
const MPlug fInstObjGroupsPlug;
};
class ShadedModeColor : boost::noncopyable
{
public:
static bool evaluateBool(const MaterialProperty::Ptr& prop,
double timeInSeconds);
static float evaluateFloat(const MaterialProperty::Ptr& prop,
double timeInSeconds);
static MColor evaluateDefaultColor(
const MaterialProperty::Ptr& prop,
double timeInSeconds);
static MColor evaluateColor(
const MaterialProperty::Ptr& prop,
double timeInSeconds);
};
{
const wchar_t* buffer = msg.
asWChar();
std::wstringstream stream;
for (unsigned int i = 0; i < length; i++) {
wchar_t ch = buffer[i];
switch (ch) {
case '\n': stream << L"\\n"; continue;
case '\t': stream << L"\\t"; continue;
case '\b': stream << L"\\b"; continue;
case '\r': stream << L"\\r"; continue;
case '\f': stream << L"\\f"; continue;
case '\v': stream << L"\\v"; continue;
case '\a': stream << L"\\a"; continue;
case '\\': stream << L"\\\\"; continue;
case '\"': stream << L"\\\""; continue;
case '\'': stream << L"\\\'"; continue;
}
stream << ch;
}
std::wstring str = stream.str();
}
inline void DisplayError(
const MString& msg)
{
}
{
DisplayError(msg);
}
{
msg.
format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
DisplayError(msg);
}
inline void DisplayWarning(
const MString& msg)
{
}
{
DisplayWarning(msg);
}
{
msg.
format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
DisplayWarning(msg);
}
}
#endif