| 1 | // tMesh.h  |
| 2 | //  |
| 3 | // This file implements a mesh. A tMesh is not a tObject, but rather a member of a tPolyModel.  |
| 4 | //  |
| 5 | // Copyright (c) 2006, 2017, 2023, 2024 Tristan Grimmer.  |
| 6 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
| 7 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
| 8 | //  |
| 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
| 10 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
| 11 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
| 12 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
| 13 | // PERFORMANCE OF THIS SOFTWARE.  |
| 14 |   |
| 15 | #pragma once  |
| 16 | #include <Foundation/tStandard.h>  |
| 17 | #include <System/tChunk.h>  |
| 18 | namespace tScene  |
| 19 | {  |
| 20 |   |
| 21 |   |
| 22 | struct tVertWeight  |
| 23 | {  |
| 24 | bool operator==(const tVertWeight& w) const { return ((SkeletonID == w.SkeletonID) && (JointID == w.JointID) && (Weight == w.Weight)) ? true : false; }  |
| 25 | bool operator!=(const tVertWeight& w) const { return !(*this == w); }  |
| 26 |   |
| 27 | uint32 SkeletonID;  |
| 28 | uint32 JointID;  |
| 29 | float Weight;  |
| 30 | };  |
| 31 |   |
| 32 |   |
| 33 | struct tWeightSet  |
| 34 | {  |
| 35 | tWeightSet() { tStd::tMemset(dest: this, val: 0, numBytes: sizeof(tWeightSet)); }  |
| 36 | bool operator==(const tWeightSet& s) const { if (NumWeights != s.NumWeights) return false; for (int i = 0; i < NumWeights; i++) if (Weights[i] != s.Weights[i]) return false; return true; }  |
| 37 | bool operator!=(const tWeightSet& s) const { return !(*this == s); }  |
| 38 |   |
| 39 | // The number of weights that are non-zero in the weight table.  |
| 40 | int NumWeights;  |
| 41 |   |
| 42 | // Max number of joints that can affect a single vertex. If you change this, you'll need to re-export everything.  |
| 43 | static const int MaxJointInfluences = 8;  |
| 44 | tVertWeight Weights[MaxJointInfluences];  |
| 45 | };  |
| 46 |   |
| 47 |   |
| 48 | class tMesh  |
| 49 | {  |
| 50 | public:  |
| 51 | tMesh() { }  |
| 52 | tMesh(const tChunk& chunk) { Load(chunk); }  |
| 53 | tMesh(const tMesh& src) { *this = src; }  |
| 54 | virtual ~tMesh() { }  |
| 55 |   |
| 56 | void Save(tChunkWriter&) const;  |
| 57 | void Load(const tChunk&);  |
| 58 | void Clear();  |
| 59 | void Scale(float);  |
| 60 |   |
| 61 | // Reverses the winding order of all face index tables. That is, those tables that are arrays of tTriFaces.  |
| 62 | void ReverseWinding();  |
| 63 | tMesh& operator=(const tMesh&);  |
| 64 |   |
| 65 | // Faces. Note that some tables may be nullptr. If a particular table does exist it will have NumFaces elements.  |
| 66 | // The Create table functions assume that the number of faces has been previously set. The created table is  |
| 67 | // uninitialized -- you must populate it. If num faces is 0 calling create will destroy the table. Setting the  |
| 68 | // number of faces does _not_ modify or delete the associated tables.  |
| 69 | void SetNumFaces(int numFaces) { NumFaces = numFaces; }  |
| 70 | int GetNumFaces() const { return NumFaces; }  |
| 71 | void CreateFaceTableVertPositionIndices() { DestroyFaceTableVertPositionIndices(); if (NumFaces) FaceTableVertPositionIndices = new tMath::tTriFace[NumFaces]; }  |
| 72 | void DestroyFaceTableVertPositionIndices() { delete[] FaceTableVertPositionIndices; FaceTableVertPositionIndices = nullptr; }  |
| 73 | void CreateFaceTableVertWeightSetIndices() { DestroyFaceTableVertWeightSetIndices(); if (NumFaces) FaceTableVertWeightSetIndices = new tMath::tTriFace[NumFaces]; }  |
| 74 | void DestroyFaceTableVertWeightSetIndices() { delete[] FaceTableVertWeightSetIndices; FaceTableVertWeightSetIndices = nullptr; }  |
| 75 | void CreateFaceTableVertNormalIndices() { DestroyFaceTableVertNormalIndices(); if (NumFaces) FaceTableVertNormalIndices = new tMath::tTriFace[NumFaces]; }  |
| 76 | void DestroyFaceTableVertNormalIndices() { delete[] FaceTableVertNormalIndices; FaceTableVertNormalIndices = nullptr; }  |
| 77 | void CreateFaceTableFaceNormals() { DestroyFaceTableFaceNormals(); if (NumFaces) FaceTableFaceNormals = new tMath::tVector3[NumFaces]; }  |
| 78 | void DestroyFaceTableFaceNormals() { delete[] FaceTableFaceNormals; FaceTableFaceNormals = nullptr; }  |
| 79 | void CreateFaceTableUVIndices() { DestroyFaceTableUVIndices(); if (NumFaces) FaceTableUVIndices = new tMath::tTriFace[NumFaces]; }  |
| 80 | void DestroyFaceTableUVIndices() { delete[] FaceTableUVIndices; FaceTableUVIndices = nullptr; }  |
| 81 | void CreateFaceTableNormalMapUVIndices() { DestroyFaceTableNormalMapUVIndices(); if (NumFaces) FaceTableNormalMapUVIndices = new tMath::tTriFace[NumFaces]; }  |
| 82 | void DestroyFaceTableNormalMapUVIndices() { delete[] FaceTableNormalMapUVIndices; FaceTableNormalMapUVIndices = nullptr; }  |
| 83 | void CreateFaceTableColourIndices() { DestroyFaceTableColourIndices(); if (NumFaces) FaceTableColourIndices = new tMath::tTriFace[NumFaces]; }  |
| 84 | void DestroyFaceTableColourIndices() { delete[] FaceTableColourIndices; FaceTableColourIndices = nullptr; }  |
| 85 | void CreateFaceTableMaterialIDs() { DestroyFaceTableMaterialIDs(); if (NumFaces) FaceTableMaterialIDs = new uint32[NumFaces]; }  |
| 86 | void DestroyFaceTableMaterialIDs() { delete[] FaceTableMaterialIDs; FaceTableMaterialIDs = nullptr; }  |
| 87 | void CreateFaceTableTangentIndices() { DestroyFaceTableTangentIndices(); if (NumFaces) FaceTableTangentIndices = new tMath::tTriFace[NumFaces]; }  |
| 88 | void DestroyFaceTableTangentIndices() { delete[] FaceTableTangentIndices; FaceTableTangentIndices = nullptr; }  |
| 89 |   |
| 90 | int NumFaces;  |
| 91 | tMath::tTriFace* FaceTableVertPositionIndices = nullptr; // Contains indices into the vert position table.  |
| 92 | tMath::tTriFace* FaceTableVertWeightSetIndices = nullptr; // Contains indices into the vert weight table.  |
| 93 | tMath::tTriFace* FaceTableVertNormalIndices = nullptr; // Contains indices into the vertex normal table.  |
| 94 | tMath::tVector3* FaceTableFaceNormals = nullptr; // Contains unit length face normals.  |
| 95 | tMath::tTriFace* FaceTableUVIndices = nullptr; // Contains indices into the UV table.  |
| 96 | tMath::tTriFace* FaceTableNormalMapUVIndices = nullptr; // Contains indices into the normal/bump map UV table.  |
| 97 | tMath::tTriFace* FaceTableColourIndices = nullptr; // Contains indices into the colour table.  |
| 98 | uint32* FaceTableMaterialIDs = nullptr; // Contains material ids.  |
| 99 | tMath::tTriFace* FaceTableTangentIndices = nullptr; // Contains indices into the table of tangents.  |
| 100 |   |
| 101 | // Edges.  |
| 102 | void SetNumEdges(int numEdges) { NumEdges = numEdges; }  |
| 103 | int GetNumEdges() const { return NumEdges; }  |
| 104 | int FindEdgeIndex(const tMath::tEdge& edge) const { for (int e = 0; e < NumEdges; e++) if (EdgeTableVertPositionIndices[e] == edge) return e; return -1; }  |
| 105 | void CreateEdgeTableVertPositionIndices() { DestroyEdgeTableVertPositionIndices(); if (NumEdges) EdgeTableVertPositionIndices = new tMath::tEdge[NumEdges]; }  |
| 106 | void DestroyEdgeTableVertPositionIndices() { delete[] EdgeTableVertPositionIndices; EdgeTableVertPositionIndices = nullptr; }  |
| 107 | int NumEdges;  |
| 108 | tMath::tEdge* EdgeTableVertPositionIndices = nullptr; // Contains indices into the vert pos table, 2 per edge.  |
| 109 |   |
| 110 | // Vertices.  |
| 111 | void SetNumVertPositions(int numVertPositions) { NumVertPositions = numVertPositions; }  |
| 112 | int GetNumVertPositions() const { return NumVertPositions; }  |
| 113 | int FindVertPositionIndex(const tMath::tVector3& pos) const { for (int p = 0; p < NumVertPositions; p++) if (VertTablePositions[p] == pos) return p; return -1; }  |
| 114 | void CreateVertTablePositions() { DestroyVertTablePositions(); if (NumVertPositions) VertTablePositions = new tMath::tVector3[NumVertPositions]; }  |
| 115 | void DestroyVertTablePositions() { delete[] VertTablePositions; VertTablePositions = nullptr; }  |
| 116 | int NumVertPositions;  |
| 117 | tMath::tVector3* VertTablePositions = nullptr;  |
| 118 |   |
| 119 | void SetNumVertWeightSets(int numVertWeightSets) { NumVertWeightSets = numVertWeightSets; }  |
| 120 | int GetNumVertWeightSets() const { return NumVertWeightSets; }  |
| 121 | int FindWeightSetIndex(const tWeightSet& set) const { for (int s = 0; s < NumVertWeightSets; s++) if (VertTableWeightSets[s] == set) return s; return -1; }  |
| 122 | void CreateVertTableWeightSets() { DestroyVertTableWeightSets(); if (NumVertWeightSets) VertTableWeightSets = new tWeightSet[NumVertWeightSets]; }  |
| 123 | void DestroyVertTableWeightSets() { delete[] VertTableWeightSets; VertTableWeightSets = nullptr; }  |
| 124 | int NumVertWeightSets;  |
| 125 | tWeightSet* VertTableWeightSets = nullptr;  |
| 126 |   |
| 127 | void SetNumVertNormals(int numVertNormals) { NumVertNormals = numVertNormals; }  |
| 128 | int GetNumVertNormals() const { return NumVertNormals; }  |
| 129 | int FindVertNormalIndex(const tMath::tVector3& normal) const { for (int n = 0; n < NumVertNormals; n++) if (VertTableNormals[n] == normal) return n; return -1; }  |
| 130 | void CreateVertTableNormals() { DestroyVertTableNormals(); if (NumVertNormals) VertTableNormals = new tMath::tVector3[NumVertNormals]; }  |
| 131 | void DestroyVertTableNormals() { delete[] VertTableNormals; VertTableNormals = nullptr; }  |
| 132 | int NumVertNormals;  |
| 133 | tMath::tVector3* VertTableNormals = nullptr;  |
| 134 |   |
| 135 | void SetNumVertUVs(int numVertUVs) { NumVertUVs = numVertUVs; }  |
| 136 | int GetNumVertUVs() const { return NumVertUVs; }  |
| 137 | int FindVertUVIndex(const tMath::tVector2& uv) const { for (int u = 0; u < NumVertUVs; u++) if (VertTableUVs[u] == uv) return u; return -1; }  |
| 138 | void CreateVertTableUVs() { DestroyVertTableUVs(); if (NumVertUVs) VertTableUVs = new tMath::tVector2[NumVertUVs]; }  |
| 139 | void DestroyVertTableUVs() { delete[] VertTableUVs; VertTableUVs = nullptr; }  |
| 140 | int NumVertUVs;  |
| 141 | tMath::tVector2* VertTableUVs = nullptr;  |
| 142 |   |
| 143 | void SetNumVertNormalMapUVs(int numVertNormalMapUVs) { NumVertNormalMapUVs = numVertNormalMapUVs; }  |
| 144 | int GetNumVertNormalMapUVs() const { return NumVertNormalMapUVs; }  |
| 145 | int FindNormalMapUVIndex(const tMath::tVector2& uv) const { for (int u = 0; u < NumVertNormalMapUVs; u++) if (VertTableNormalMapUVs[u] == uv) return u; return -1; }  |
| 146 | void CreateVertTableNormalMapUVs() { DestroyVertTableNormalMapUVs(); if (NumVertNormalMapUVs) VertTableNormalMapUVs = new tMath::tVector2[NumVertNormalMapUVs]; }  |
| 147 | void DestroyVertTableNormalMapUVs() { delete[] VertTableNormalMapUVs; VertTableNormalMapUVs = nullptr; }  |
| 148 | int NumVertNormalMapUVs;  |
| 149 | tMath::tVector2* VertTableNormalMapUVs = nullptr;  |
| 150 |   |
| 151 | void SetNumVertColours(int numVertColours) { NumVertColours = numVertColours; }  |
| 152 | int GetNumVertColours() const { return NumVertColours; }  |
| 153 | int FindVertColourIndex(const tColour4b& colour) const { for (int c = 0; c < NumVertColours; c++) if (VertTableColours[c] == colour) return c; return -1; }  |
| 154 | void CreateVertTableColours() { DestroyVertTableColours(); if (NumVertColours) VertTableColours = new tColour4b[NumVertColours]; }  |
| 155 | void DestroyVertTableColours() { delete[] VertTableColours; VertTableColours = nullptr; }  |
| 156 | int NumVertColours;  |
| 157 | tColour4b* VertTableColours = nullptr;  |
| 158 |   |
| 159 | void SetNumVertTangents(int numVertTangents) { NumVertTangents = numVertTangents; }  |
| 160 | int GetNumVertTangents() const { return NumVertTangents; }  |
| 161 | int FindVertTangentIndex(const tMath::tVector4& tangent) const { for (int t = 0; t < NumVertTangents; t++) if (VertTableTangents[t] == tangent) return t; return -1; }  |
| 162 | void CreateVertTableTangents() { DestroyVertTableTangents(); if (NumVertTangents) VertTableTangents = new tMath::tVector4[NumVertTangents]; }  |
| 163 | void DestroyVertTableTangents() { delete[] VertTableTangents; VertTableTangents = nullptr; }  |
| 164 | int NumVertTangents;  |
| 165 | tMath::tVector4* VertTableTangents = nullptr;  |
| 166 | };  |
| 167 |   |
| 168 |   |
| 169 | }  |
| 170 | |