diff options
Diffstat (limited to 'thirdparty/thekla_atlas/nvmesh/MeshBuilder.cpp')
-rw-r--r-- | thirdparty/thekla_atlas/nvmesh/MeshBuilder.cpp | 1000 |
1 files changed, 1000 insertions, 0 deletions
diff --git a/thirdparty/thekla_atlas/nvmesh/MeshBuilder.cpp b/thirdparty/thekla_atlas/nvmesh/MeshBuilder.cpp new file mode 100644 index 0000000000..24d8ddff89 --- /dev/null +++ b/thirdparty/thekla_atlas/nvmesh/MeshBuilder.cpp @@ -0,0 +1,1000 @@ +// This code is in the public domain -- castanyo@yahoo.es + +#include "nvmesh.h" // pch + +#include "MeshBuilder.h" +#include "TriMesh.h" +#include "QuadTriMesh.h" +#include "halfedge/Mesh.h" +#include "halfedge/Vertex.h" +#include "halfedge/Face.h" + +#include "weld/Weld.h" + +#include "nvmath/Box.h" +#include "nvmath/Vector.inl" + +#include "nvcore/StrLib.h" +#include "nvcore/RadixSort.h" +#include "nvcore/Ptr.h" +#include "nvcore/Array.inl" +#include "nvcore/HashMap.inl" + + +using namespace nv; + +/* +By default the mesh builder creates 3 streams (position, normal, texcoord), I'm planning to add support for extra streams as follows: + +enum StreamType { StreamType_Float, StreamType_Vector2, StreamType_Vector3, StreamType_Vector4 }; + +uint addStream(const char *, uint idx, StreamType); + +uint addAttribute(float) +uint addAttribute(Vector2) +uint addAttribute(Vector3) +uint addAttribute(Vector4) + +struct Vertex +{ + uint pos; + uint nor; + uint tex; + uint * attribs; // NULL or NIL terminated array? +}; + +All streams must be added before hand, so that you know the size of the attribs array. + +The vertex hash function could be kept as is, but the == operator should be extended to test +the extra atributes when available. + +That might require a custom hash implementation, or an extension of the current one. How to +handle the variable number of attributes in the attribs array? + +bool operator()(const Vertex & a, const Vertex & b) const +{ + if (a.pos != b.pos || a.nor != b.nor || a.tex != b.tex) return false; + if (a.attribs == NULL && b.attribs == NULL) return true; + return 0 == memcmp(a.attribs, b.attribs, ???); +} + +We could use a NIL terminated array, or provide custom user data to the equals functor. + +vertexMap.setUserData((void *)vertexAttribCount); + +bool operator()(const Vertex & a, const Vertex & b, void * userData) const { ... } + +*/ + + + +namespace +{ + struct Material + { + Material() : faceCount(0) {} + Material(const String & str) : name(str), faceCount(0) {} + + String name; + uint faceCount; + }; + + struct Vertex + { + //Vertex() {} + //Vertex(uint p, uint n, uint t0, uint t1, uint c) : pos(p), nor(n), tex0(t0), tex1(t1), col(c) {} + + friend bool operator==(const Vertex & a, const Vertex & b) + { + return a.pos == b.pos && a.nor == b.nor && a.tex[0] == b.tex[0] && a.tex[1] == b.tex[1] && a.col[0] == b.col[0] && a.col[1] == b.col[1] && a.col[2] == b.col[2]; + } + + uint pos; + uint nor; + uint tex[2]; + uint col[3]; + }; + + struct Face + { + uint id; + uint firstIndex; + uint indexCount; + uint material; + uint group; + }; + +} // namespace + + +namespace nv +{ + // This is a much better hash than the default and greatly improves performance! + template <> struct Hash<Vertex> + { + uint operator()(const Vertex & v) const { return v.pos + v.nor + v.tex[0]/* + v.col*/; } + }; +} + +struct MeshBuilder::PrivateData +{ + PrivateData() : currentGroup(NIL), currentMaterial(NIL), maxFaceIndexCount(0) {} + + uint pushVertex(uint p, uint n, uint t0, uint t1, uint c0, uint c1, uint c2); + uint pushVertex(const Vertex & v); + + Array<Vector3> posArray; + Array<Vector3> norArray; + Array<Vector2> texArray[2]; + Array<Vector4> colArray[3]; + + Array<Vertex> vertexArray; + HashMap<Vertex, uint> vertexMap; + + HashMap<String, uint> materialMap; + Array<Material> materialArray; + + uint currentGroup; + uint currentMaterial; + + Array<uint> indexArray; + Array<Face> faceArray; + + uint maxFaceIndexCount; +}; + + +uint MeshBuilder::PrivateData::pushVertex(uint p, uint n, uint t0, uint t1, uint c0, uint c1, uint c2) +{ + Vertex v; + v.pos = p; + v.nor = n; + v.tex[0] = t0; + v.tex[1] = t1; + v.col[0] = c0; + v.col[1] = c1; + v.col[2] = c2; + return pushVertex(v); +} + +uint MeshBuilder::PrivateData::pushVertex(const Vertex & v) +{ + // Lookup vertex v in map. + uint idx; + if (vertexMap.get(v, &idx)) + { + return idx; + } + + idx = vertexArray.count(); + vertexArray.pushBack(v); + vertexMap.add(v, idx); + + return idx; +} + + +MeshBuilder::MeshBuilder() : d(new PrivateData()) +{ +} + +MeshBuilder::~MeshBuilder() +{ + nvDebugCheck(d != NULL); + delete d; +} + + +// Builder methods. +uint MeshBuilder::addPosition(const Vector3 & v) +{ + d->posArray.pushBack(validate(v)); + return d->posArray.count() - 1; +} + +uint MeshBuilder::addNormal(const Vector3 & v) +{ + d->norArray.pushBack(validate(v)); + return d->norArray.count() - 1; +} + +uint MeshBuilder::addTexCoord(const Vector2 & v, uint set/*=0*/) +{ + d->texArray[set].pushBack(validate(v)); + return d->texArray[set].count() - 1; +} + +uint MeshBuilder::addColor(const Vector4 & v, uint set/*=0*/) +{ + d->colArray[set].pushBack(validate(v)); + return d->colArray[set].count() - 1; +} + +void MeshBuilder::beginGroup(uint id) +{ + d->currentGroup = id; +} + +void MeshBuilder::endGroup() +{ + d->currentGroup = NIL; +} + +// Add named material, check for uniquenes. +uint MeshBuilder::addMaterial(const char * name) +{ + uint index; + if (d->materialMap.get(name, &index)) { + nvDebugCheck(d->materialArray[index].name == name); + } + else { + index = d->materialArray.count(); + d->materialMap.add(name, index); + + Material material(name); + d->materialArray.append(material); + } + return index; +} + +void MeshBuilder::beginMaterial(uint id) +{ + d->currentMaterial = id; +} + +void MeshBuilder::endMaterial() +{ + d->currentMaterial = NIL; +} + +void MeshBuilder::beginPolygon(uint id/*=0*/) +{ + Face face; + face.id = id; + face.firstIndex = d->indexArray.count(); + face.indexCount = 0; + face.material = d->currentMaterial; + face.group = d->currentGroup; + + d->faceArray.pushBack(face); +} + +uint MeshBuilder::addVertex(uint p, uint n/*= NIL*/, uint t0/*= NIL*/, uint t1/*= NIL*/, uint c0/*= NIL*/, uint c1/*= NIL*/, uint c2/*= NIL*/) +{ + // @@ In theory there's no need to add vertices before faces, but I'm adding this to debug problems in our maya exporter: + nvDebugCheck(p < d->posArray.count()); + nvDebugCheck(n == NIL || n < d->norArray.count()); + nvDebugCheck(t0 == NIL || t0 < d->texArray[0].count()); + nvDebugCheck(t1 == NIL || t1 < d->texArray[1].count()); + //nvDebugCheck(c0 == NIL || c0 < d->colArray[0].count()); + if (c0 > d->colArray[0].count()) c0 = NIL; // @@ This seems to be happening in loc_swamp_catwalk.mb! No idea why. + nvDebugCheck(c1 == NIL || c1 < d->colArray[1].count()); + nvDebugCheck(c2 == NIL || c2 < d->colArray[2].count()); + + uint idx = d->pushVertex(p, n, t0, t1, c0, c1, c2); + d->indexArray.pushBack(idx); + d->faceArray.back().indexCount++; + return idx; +} + +uint MeshBuilder::addVertex(const Vector3 & pos) +{ + uint p = addPosition(pos); + return addVertex(p); +} + +#if 0 +uint MeshBuilder::addVertex(const Vector3 & pos, const Vector3 & nor, const Vector2 & tex0, const Vector2 & tex1, const Vector4 & col0, const Vector4 & col1) +{ + uint p = addPosition(pos); + uint n = addNormal(nor); + uint t0 = addTexCoord(tex0, 0); + uint t1 = addTexCoord(tex1, 1); + uint c0 = addColor(col0); + uint c1 = addColor(col1); + return addVertex(p, n, t0, t1, c0, c1); +} +#endif + +// Return true if the face is valid and was added to the mesh. +bool MeshBuilder::endPolygon() +{ + const Face & face = d->faceArray.back(); + const uint count = face.indexCount; + + // Validate polygon here. + bool invalid = count <= 2; + + if (!invalid) { + // Skip zero area polygons. Or polygons with degenerate edges (which will result in zero-area triangles). + const uint first = face.firstIndex; + for (uint j = count - 1, i = 0; i < count; j = i, i++) { + uint v0 = d->indexArray[first + i]; + uint v1 = d->indexArray[first + j]; + + uint p0 = d->vertexArray[v0].pos; + uint p1 = d->vertexArray[v1].pos; + + if (p0 == p1) { + invalid = true; + break; + } + + if (equal(d->posArray[p0], d->posArray[p1], FLT_EPSILON)) { + invalid = true; + break; + } + } + + uint v0 = d->indexArray[first]; + uint p0 = d->vertexArray[v0].pos; + Vector3 x0 = d->posArray[p0]; + + float area = 0.0f; + for (uint j = 1, i = 2; i < count; j = i, i++) { + uint v1 = d->indexArray[first + i]; + uint v2 = d->indexArray[first + j]; + + uint p1 = d->vertexArray[v1].pos; + uint p2 = d->vertexArray[v2].pos; + + Vector3 x1 = d->posArray[p1]; + Vector3 x2 = d->posArray[p2]; + + area += length(cross(x1-x0, x2-x0)); + } + + if (0.5 * area < 1e-6) { // Reduce this threshold if artists have legitimate complains. + invalid = true; + } + + // @@ This is not complete. We may still get zero area triangles after triangulation. + // However, our plugin triangulates before building the mesh, so hopefully that's not a problem. + + } + + if (invalid) + { + d->indexArray.resize(d->indexArray.size() - count); + d->faceArray.popBack(); + return false; + } + else + { + if (d->currentMaterial != NIL) { + d->materialArray[d->currentMaterial].faceCount++; + } + + d->maxFaceIndexCount = max(d->maxFaceIndexCount, count); + return true; + } +} + + +uint MeshBuilder::weldPositions() +{ + Array<uint> xrefs; + Weld<Vector3> weldVector3; + + if (d->posArray.count()) { + // Weld vertex attributes. + weldVector3(d->posArray, xrefs); + + // Remap vertex indices. + const uint vertexCount = d->vertexArray.count(); + for (uint v = 0; v < vertexCount; v++) + { + Vertex & vertex = d->vertexArray[v]; + if (vertex.pos != NIL) vertex.pos = xrefs[vertex.pos]; + } + } + + return d->posArray.count(); +} + +uint MeshBuilder::weldNormals() +{ + Array<uint> xrefs; + Weld<Vector3> weldVector3; + + if (d->norArray.count()) { + // Weld vertex attributes. + weldVector3(d->norArray, xrefs); + + // Remap vertex indices. + const uint vertexCount = d->vertexArray.count(); + for (uint v = 0; v < vertexCount; v++) + { + Vertex & vertex = d->vertexArray[v]; + if (vertex.nor != NIL) vertex.nor = xrefs[vertex.nor]; + } + } + + return d->norArray.count(); +} + +uint MeshBuilder::weldTexCoords(uint set/*=0*/) +{ + Array<uint> xrefs; + Weld<Vector2> weldVector2; + + if (d->texArray[set].count()) { + // Weld vertex attributes. + weldVector2(d->texArray[set], xrefs); + + // Remap vertex indices. + const uint vertexCount = d->vertexArray.count(); + for (uint v = 0; v < vertexCount; v++) + { + Vertex & vertex = d->vertexArray[v]; + if (vertex.tex[set] != NIL) vertex.tex[set] = xrefs[vertex.tex[set]]; + } + } + + return d->texArray[set].count(); +} + +uint MeshBuilder::weldColors(uint set/*=0*/) +{ + Array<uint> xrefs; + Weld<Vector4> weldVector4; + + if (d->colArray[set].count()) { + // Weld vertex attributes. + weldVector4(d->colArray[set], xrefs); + + // Remap vertex indices. + const uint vertexCount = d->vertexArray.count(); + for (uint v = 0; v < vertexCount; v++) + { + Vertex & vertex = d->vertexArray[v]; + if (vertex.col[set] != NIL) vertex.col[set] = xrefs[vertex.col[set]]; + } + } + + return d->colArray[set].count(); +} + +void MeshBuilder::weldVertices() { + + if (d->vertexArray.count() == 0) { + // Nothing to do. + return; + } + + Array<uint> xrefs; + Weld<Vertex> weldVertex; + + // Weld vertices. + weldVertex(d->vertexArray, xrefs); + + // Remap face indices. + const uint indexCount = d->indexArray.count(); + for (uint i = 0; i < indexCount; i++) + { + d->indexArray[i] = xrefs[d->indexArray[i]]; + } + + // Remap vertex map. + foreach(i, d->vertexMap) + { + d->vertexMap[i].value = xrefs[d->vertexMap[i].value]; + } +} + + +void MeshBuilder::optimize() +{ + if (d->vertexArray.count() == 0) + { + return; + } + + weldPositions(); + weldNormals(); + weldTexCoords(0); + weldTexCoords(1); + weldColors(); + + weldVertices(); +} + + + + + + +void MeshBuilder::removeUnusedMaterials(Array<uint> & newMaterialId) +{ + uint materialCount = d->materialArray.count(); + + // Reset face counts. + for (uint i = 0; i < materialCount; i++) { + d->materialArray[i].faceCount = 0; + } + + // Count faces. + foreach(i, d->faceArray) { + Face & face = d->faceArray[i]; + + if (face.material != NIL) { + nvDebugCheck(face.material < materialCount); + + d->materialArray[face.material].faceCount++; + } + } + + // Remove unused materials. + newMaterialId.resize(materialCount); + + for (uint i = 0, m = 0; i < materialCount; i++) + { + if (d->materialArray[m].faceCount > 0) + { + newMaterialId[i] = m++; + } + else + { + newMaterialId[i] = NIL; + d->materialArray.removeAt(m); + } + } + + materialCount = d->materialArray.count(); + + // Update face material ids. + foreach(i, d->faceArray) { + Face & face = d->faceArray[i]; + + if (face.material != NIL) { + uint id = newMaterialId[face.material]; + nvDebugCheck(id != NIL && id < materialCount); + + face.material = id; + } + } +} + +void MeshBuilder::sortFacesByGroup() +{ + const uint faceCount = d->faceArray.count(); + + Array<uint> faceGroupArray; + faceGroupArray.resize(faceCount); + + for (uint i = 0; i < faceCount; i++) { + faceGroupArray[i] = d->faceArray[i].group; + } + + RadixSort radix; + radix.sort(faceGroupArray); + + Array<Face> newFaceArray; + newFaceArray.resize(faceCount); + + for (uint i = 0; i < faceCount; i++) { + newFaceArray[i] = d->faceArray[radix.rank(i)]; + } + + swap(newFaceArray, d->faceArray); +} + +void MeshBuilder::sortFacesByMaterial() +{ + const uint faceCount = d->faceArray.count(); + + Array<uint> faceMaterialArray; + faceMaterialArray.resize(faceCount); + + for (uint i = 0; i < faceCount; i++) { + faceMaterialArray[i] = d->faceArray[i].material; + } + + RadixSort radix; + radix.sort(faceMaterialArray); + + Array<Face> newFaceArray; + newFaceArray.resize(faceCount); + + for (uint i = 0; i < faceCount; i++) { + newFaceArray[i] = d->faceArray[radix.rank(i)]; + } + + swap(newFaceArray, d->faceArray); +} + + +void MeshBuilder::reset() +{ + nvDebugCheck(d != NULL); + delete d; + d = new PrivateData(); +} + +void MeshBuilder::done() +{ + if (d->currentGroup != NIL) { + endGroup(); + } + + if (d->currentMaterial != NIL) { + endMaterial(); + } +} + +// Hints. +void MeshBuilder::hintTriangleCount(uint count) +{ + d->indexArray.reserve(d->indexArray.count() + count * 4); +} + +void MeshBuilder::hintVertexCount(uint count) +{ + d->vertexArray.reserve(d->vertexArray.count() + count); + d->vertexMap.resize(d->vertexMap.count() + count); +} + +void MeshBuilder::hintPositionCount(uint count) +{ + d->posArray.reserve(d->posArray.count() + count); +} + +void MeshBuilder::hintNormalCount(uint count) +{ + d->norArray.reserve(d->norArray.count() + count); +} + +void MeshBuilder::hintTexCoordCount(uint count, uint set/*=0*/) +{ + d->texArray[set].reserve(d->texArray[set].count() + count); +} + +void MeshBuilder::hintColorCount(uint count, uint set/*=0*/) +{ + d->colArray[set].reserve(d->colArray[set].count() + count); +} + + +// Helpers. +void MeshBuilder::addTriangle(uint v0, uint v1, uint v2) +{ + beginPolygon(); + addVertex(v0); + addVertex(v1); + addVertex(v2); + endPolygon(); +} + +void MeshBuilder::addQuad(uint v0, uint v1, uint v2, uint v3) +{ + beginPolygon(); + addVertex(v0); + addVertex(v1); + addVertex(v2); + addVertex(v3); + endPolygon(); +} + + +// Get tri mesh. +TriMesh * MeshBuilder::buildTriMesh() const +{ + const uint faceCount = d->faceArray.count(); + uint triangleCount = 0; + for (uint f = 0; f < faceCount; f++) { + triangleCount += d->faceArray[f].indexCount - 2; + } + + const uint vertexCount = d->vertexArray.count(); + TriMesh * mesh = new TriMesh(triangleCount, vertexCount); + + // Build faces. + Array<TriMesh::Face> & faces = mesh->faces(); + + for(uint f = 0; f < faceCount; f++) + { + int firstIndex = d->faceArray[f].firstIndex; + int indexCount = d->faceArray[f].indexCount; + + int v0 = d->indexArray[firstIndex + 0]; + int v1 = d->indexArray[firstIndex + 1]; + + for(int t = 0; t < indexCount - 2; t++) { + int v2 = d->indexArray[firstIndex + t + 2]; + + TriMesh::Face face; + face.id = faces.count(); + face.v[0] = v0; + face.v[1] = v1; + face.v[2] = v2; + faces.append(face); + + v1 = v2; + } + } + + // Build vertices. + Array<BaseMesh::Vertex> & vertices = mesh->vertices(); + + for(uint i = 0; i < vertexCount; i++) + { + BaseMesh::Vertex vertex; + vertex.id = i; + if (d->vertexArray[i].pos != NIL) vertex.pos = d->posArray[d->vertexArray[i].pos]; + if (d->vertexArray[i].nor != NIL) vertex.nor = d->norArray[d->vertexArray[i].nor]; + if (d->vertexArray[i].tex[0] != NIL) vertex.tex = d->texArray[0][d->vertexArray[i].tex[0]]; + + vertices.append(vertex); + } + + return mesh; +} + +// Get quad/tri mesh. +QuadTriMesh * MeshBuilder::buildQuadTriMesh() const +{ + const uint faceCount = d->faceArray.count(); + const uint vertexCount = d->vertexArray.count(); + QuadTriMesh * mesh = new QuadTriMesh(faceCount, vertexCount); + + // Build faces. + Array<QuadTriMesh::Face> & faces = mesh->faces(); + + for (uint f = 0; f < faceCount; f++) + { + int firstIndex = d->faceArray[f].firstIndex; + int indexCount = d->faceArray[f].indexCount; + + QuadTriMesh::Face face; + face.id = f; + + face.v[0] = d->indexArray[firstIndex + 0]; + face.v[1] = d->indexArray[firstIndex + 1]; + face.v[2] = d->indexArray[firstIndex + 2]; + + // Only adds triangles and quads. Ignores polygons. + if (indexCount == 3) { + face.v[3] = NIL; + faces.append(face); + } + else if (indexCount == 4) { + face.v[3] = d->indexArray[firstIndex + 3]; + faces.append(face); + } + } + + // Build vertices. + Array<BaseMesh::Vertex> & vertices = mesh->vertices(); + + for(uint i = 0; i < vertexCount; i++) + { + BaseMesh::Vertex vertex; + vertex.id = i; + if (d->vertexArray[i].pos != NIL) vertex.pos = d->posArray[d->vertexArray[i].pos]; + if (d->vertexArray[i].nor != NIL) vertex.nor = d->norArray[d->vertexArray[i].nor]; + if (d->vertexArray[i].tex[0] != NIL) vertex.tex = d->texArray[0][d->vertexArray[i].tex[0]]; + + vertices.append(vertex); + } + + return mesh; +} + +// Get half edge mesh. +HalfEdge::Mesh * MeshBuilder::buildHalfEdgeMesh(bool weldPositions, Error * error/*=NULL*/, Array<uint> * badFaces/*=NULL*/) const +{ + if (error != NULL) *error = Error_None; + + const uint vertexCount = d->vertexArray.count(); + AutoPtr<HalfEdge::Mesh> mesh(new HalfEdge::Mesh()); + + for(uint v = 0; v < vertexCount; v++) + { + HalfEdge::Vertex * vertex = mesh->addVertex(d->posArray[d->vertexArray[v].pos]); + if (d->vertexArray[v].nor != NIL) vertex->nor = d->norArray[d->vertexArray[v].nor]; + if (d->vertexArray[v].tex[0] != NIL) vertex->tex = Vector2(d->texArray[0][d->vertexArray[v].tex[0]]); + if (d->vertexArray[v].col[0] != NIL) vertex->col = d->colArray[0][d->vertexArray[v].col[0]]; + } + + if (weldPositions) { + mesh->linkColocals(); + } + else { + // Build canonical map from position indices. + Array<uint> canonicalMap(vertexCount); + + foreach (i, d->vertexArray) { + canonicalMap.append(d->vertexArray[i].pos); + } + + mesh->linkColocalsWithCanonicalMap(canonicalMap); + } + + const uint faceCount = d->faceArray.count(); + for (uint f = 0; f < faceCount; f++) + { + const uint firstIndex = d->faceArray[f].firstIndex; + const uint indexCount = d->faceArray[f].indexCount; + + HalfEdge::Face * face = mesh->addFace(d->indexArray, firstIndex, indexCount); + + // @@ This is too late, removing the face here will leave the mesh improperly connected. + /*if (face->area() <= FLT_EPSILON) { + mesh->remove(face); + face = NULL; + }*/ + + if (face == NULL) { + // Non manifold mesh. + if (error != NULL) *error = Error_NonManifoldEdge; + if (badFaces != NULL) { + badFaces->append(d->faceArray[f].id); + } + //return NULL; // IC: Ignore error and continue building the mesh. + } + + if (face != NULL) { + face->group = d->faceArray[f].group; + face->material = d->faceArray[f].material; + } + } + + mesh->linkBoundary(); + + // We cannot fix functions here, because this would introduce new vertices and these vertices won't have the corresponding builder data. + + // Maybe the builder should perform the search for T-junctions and update the vertex data directly. + + // For now, we don't fix T-junctions at export time, but only during parameterization. + + //mesh->fixBoundaryJunctions(); + + //mesh->sewBoundary(); + + return mesh.release(); +} + + +bool MeshBuilder::buildPositions(Array<Vector3> & positionArray) +{ + const uint vertexCount = d->vertexArray.count(); + positionArray.resize(vertexCount); + + for (uint v = 0; v < vertexCount; v++) + { + nvDebugCheck(d->vertexArray[v].pos != NIL); + positionArray[v] = d->posArray[d->vertexArray[v].pos]; + } + + return true; +} + +bool MeshBuilder::buildNormals(Array<Vector3> & normalArray) +{ + bool anyNormal = false; + + const uint vertexCount = d->vertexArray.count(); + normalArray.resize(vertexCount); + + for (uint v = 0; v < vertexCount; v++) + { + if (d->vertexArray[v].nor == NIL) { + normalArray[v] = Vector3(0, 0, 1); + } + else { + anyNormal = true; + normalArray[v] = d->norArray[d->vertexArray[v].nor]; + } + } + + return anyNormal; +} + +bool MeshBuilder::buildTexCoords(Array<Vector2> & texCoordArray, uint set/*=0*/) +{ + bool anyTexCoord = false; + + const uint vertexCount = d->vertexArray.count(); + texCoordArray.resize(vertexCount); + + for (uint v = 0; v < vertexCount; v++) + { + if (d->vertexArray[v].tex[set] == NIL) { + texCoordArray[v] = Vector2(0, 0); + } + else { + anyTexCoord = true; + texCoordArray[v] = d->texArray[set][d->vertexArray[v].tex[set]]; + } + } + + return anyTexCoord; +} + +bool MeshBuilder::buildColors(Array<Vector4> & colorArray, uint set/*=0*/) +{ + bool anyColor = false; + + const uint vertexCount = d->vertexArray.count(); + colorArray.resize(vertexCount); + + for (uint v = 0; v < vertexCount; v++) + { + if (d->vertexArray[v].col[set] == NIL) { + colorArray[v] = Vector4(0, 0, 0, 1); + } + else { + anyColor = true; + colorArray[v] = d->colArray[set][d->vertexArray[v].col[set]]; + } + } + + return anyColor; +} + +void MeshBuilder::buildVertexToPositionMap(Array<int> &map) +{ + const uint vertexCount = d->vertexArray.count(); + map.resize(vertexCount); + + foreach (i, d->vertexArray) { + map[i] = d->vertexArray[i].pos; + } +} + + + +uint MeshBuilder::vertexCount() const +{ + return d->vertexArray.count(); +} + + +uint MeshBuilder::positionCount() const +{ + return d->posArray.count(); +} + +uint MeshBuilder::normalCount() const +{ + return d->norArray.count(); +} + +uint MeshBuilder::texCoordCount(uint set/*=0*/) const +{ + return d->texArray[set].count(); +} + +uint MeshBuilder::colorCount(uint set/*=0*/) const +{ + return d->colArray[set].count(); +} + + +uint MeshBuilder::materialCount() const +{ + return d->materialArray.count(); +} + +const char * MeshBuilder::material(uint i) const +{ + return d->materialArray[i].name; +} + + +uint MeshBuilder::positionIndex(uint vertex) const +{ + return d->vertexArray[vertex].pos; +} +uint MeshBuilder::normalIndex(uint vertex) const +{ + return d->vertexArray[vertex].nor; +} +uint MeshBuilder::texCoordIndex(uint vertex, uint set/*=0*/) const +{ + return d->vertexArray[vertex].tex[set]; +} +uint MeshBuilder::colorIndex(uint vertex, uint set/*=0*/) const +{ + return d->vertexArray[vertex].col[set]; +} |