/src/assimp/code/PostProcessing/MakeVerboseFormat.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | --------------------------------------------------------------------------- |
3 | | Open Asset Import Library (assimp) |
4 | | --------------------------------------------------------------------------- |
5 | | |
6 | | Copyright (c) 2006-2025, assimp team |
7 | | |
8 | | |
9 | | |
10 | | All rights reserved. |
11 | | |
12 | | Redistribution and use of this software in source and binary forms, |
13 | | with or without modification, are permitted provided that the following |
14 | | conditions are met: |
15 | | |
16 | | * Redistributions of source code must retain the above |
17 | | copyright notice, this list of conditions and the |
18 | | following disclaimer. |
19 | | |
20 | | * Redistributions in binary form must reproduce the above |
21 | | copyright notice, this list of conditions and the |
22 | | following disclaimer in the documentation and/or other |
23 | | materials provided with the distribution. |
24 | | |
25 | | * Neither the name of the assimp team, nor the names of its |
26 | | contributors may be used to endorse or promote products |
27 | | derived from this software without specific prior |
28 | | written permission of the assimp team. |
29 | | |
30 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
31 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
32 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
33 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
34 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
35 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
36 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
37 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
38 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
39 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
40 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
41 | | --------------------------------------------------------------------------- |
42 | | */ |
43 | | /** @file Implementation of the post processing step "MakeVerboseFormat" |
44 | | */ |
45 | | |
46 | | #include "MakeVerboseFormat.h" |
47 | | #include <assimp/scene.h> |
48 | | #include <assimp/DefaultLogger.hpp> |
49 | | |
50 | | using namespace Assimp; |
51 | | |
52 | | // ------------------------------------------------------------------------------------------------ |
53 | | // Executes the post processing step on the given imported data. |
54 | 0 | void MakeVerboseFormatProcess::Execute(aiScene *pScene) { |
55 | 0 | ai_assert(nullptr != pScene); |
56 | 0 | ASSIMP_LOG_DEBUG("MakeVerboseFormatProcess begin"); |
57 | |
|
58 | 0 | bool bHas = false; |
59 | 0 | for (unsigned int a = 0; a < pScene->mNumMeshes; a++) { |
60 | 0 | if (MakeVerboseFormat(pScene->mMeshes[a])) |
61 | 0 | bHas = true; |
62 | 0 | } |
63 | 0 | if (bHas) { |
64 | 0 | ASSIMP_LOG_INFO("MakeVerboseFormatProcess finished. There was much work to do ..."); |
65 | 0 | } else { |
66 | 0 | ASSIMP_LOG_DEBUG("MakeVerboseFormatProcess. There was nothing to do."); |
67 | 0 | } |
68 | |
|
69 | 0 | pScene->mFlags &= ~AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; |
70 | 0 | } |
71 | | |
72 | | // ------------------------------------------------------------------------------------------------ |
73 | | // Executes the post processing step on the given imported data. |
74 | 0 | bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh *pcMesh) { |
75 | 0 | ai_assert(nullptr != pcMesh); |
76 | |
|
77 | 0 | unsigned int iOldNumVertices = pcMesh->mNumVertices; |
78 | 0 | const unsigned int iNumVerts = pcMesh->mNumFaces * 3; |
79 | |
|
80 | 0 | aiVector3D *pvPositions = new aiVector3D[iNumVerts]; |
81 | |
|
82 | 0 | aiVector3D *pvNormals = nullptr; |
83 | 0 | if (pcMesh->HasNormals()) { |
84 | 0 | pvNormals = new aiVector3D[iNumVerts]; |
85 | 0 | } |
86 | 0 | aiVector3D *pvTangents = nullptr, *pvBitangents = nullptr; |
87 | 0 | if (pcMesh->HasTangentsAndBitangents()) { |
88 | 0 | pvTangents = new aiVector3D[iNumVerts]; |
89 | 0 | pvBitangents = new aiVector3D[iNumVerts]; |
90 | 0 | } |
91 | |
|
92 | 0 | aiVector3D *apvTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS] = { nullptr }; |
93 | 0 | aiColor4D *apvColorSets[AI_MAX_NUMBER_OF_COLOR_SETS] = { nullptr }; |
94 | |
|
95 | 0 | unsigned int p = 0; |
96 | 0 | while (pcMesh->HasTextureCoords(p)) |
97 | 0 | apvTextureCoords[p++] = new aiVector3D[iNumVerts]; |
98 | |
|
99 | 0 | p = 0; |
100 | 0 | while (pcMesh->HasVertexColors(p)) |
101 | 0 | apvColorSets[p++] = new aiColor4D[iNumVerts]; |
102 | | |
103 | | // allocate enough memory to hold output bones and vertex weights ... |
104 | 0 | std::vector<aiVertexWeight> *newWeights = new std::vector<aiVertexWeight>[pcMesh->mNumBones]; |
105 | 0 | for (unsigned int i = 0; i < pcMesh->mNumBones; ++i) { |
106 | 0 | newWeights[i].reserve(pcMesh->mBones[i]->mNumWeights * 3); |
107 | 0 | } |
108 | | |
109 | | // iterate through all faces and build a clean list |
110 | 0 | unsigned int iIndex = 0; |
111 | 0 | for (unsigned int a = 0; a < pcMesh->mNumFaces; ++a) { |
112 | 0 | aiFace *pcFace = &pcMesh->mFaces[a]; |
113 | 0 | for (unsigned int q = 0; q < pcFace->mNumIndices; ++q, ++iIndex) { |
114 | | // need to build a clean list of bones, too |
115 | 0 | for (unsigned int i = 0; i < pcMesh->mNumBones; ++i) { |
116 | 0 | for (unsigned int boneIdx = 0; boneIdx < pcMesh->mBones[i]->mNumWeights; ++boneIdx) { |
117 | 0 | const aiVertexWeight &w = pcMesh->mBones[i]->mWeights[boneIdx]; |
118 | 0 | if (pcFace->mIndices[q] == w.mVertexId) { |
119 | 0 | aiVertexWeight wNew; |
120 | 0 | wNew.mVertexId = iIndex; |
121 | 0 | wNew.mWeight = w.mWeight; |
122 | 0 | newWeights[i].push_back(wNew); |
123 | 0 | } |
124 | 0 | } |
125 | 0 | } |
126 | |
|
127 | 0 | pvPositions[iIndex] = pcMesh->mVertices[pcFace->mIndices[q]]; |
128 | |
|
129 | 0 | if (pcMesh->HasNormals()) { |
130 | 0 | pvNormals[iIndex] = pcMesh->mNormals[pcFace->mIndices[q]]; |
131 | 0 | } |
132 | 0 | if (pcMesh->HasTangentsAndBitangents()) { |
133 | 0 | pvTangents[iIndex] = pcMesh->mTangents[pcFace->mIndices[q]]; |
134 | 0 | pvBitangents[iIndex] = pcMesh->mBitangents[pcFace->mIndices[q]]; |
135 | 0 | } |
136 | |
|
137 | 0 | unsigned int pp = 0; |
138 | 0 | while (pcMesh->HasTextureCoords(pp)) { |
139 | 0 | apvTextureCoords[pp][iIndex] = pcMesh->mTextureCoords[pp][pcFace->mIndices[q]]; |
140 | 0 | ++pp; |
141 | 0 | } |
142 | 0 | pp = 0; |
143 | 0 | while (pcMesh->HasVertexColors(pp)) { |
144 | 0 | apvColorSets[pp][iIndex] = pcMesh->mColors[pp][pcFace->mIndices[q]]; |
145 | 0 | ++pp; |
146 | 0 | } |
147 | 0 | pcFace->mIndices[q] = iIndex; |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | | // build output vertex weights |
152 | 0 | for (unsigned int i = 0; i < pcMesh->mNumBones; ++i) { |
153 | 0 | delete[] pcMesh->mBones[i]->mWeights; |
154 | 0 | if (!newWeights[i].empty()) { |
155 | 0 | pcMesh->mBones[i]->mWeights = new aiVertexWeight[newWeights[i].size()]; |
156 | 0 | pcMesh->mBones[i]->mNumWeights = static_cast<unsigned int>(newWeights[i].size()); |
157 | 0 | aiVertexWeight *weightToCopy = &(newWeights[i][0]); |
158 | 0 | memcpy(pcMesh->mBones[i]->mWeights, weightToCopy, |
159 | 0 | sizeof(aiVertexWeight) * newWeights[i].size()); |
160 | 0 | } else { |
161 | 0 | pcMesh->mBones[i]->mWeights = nullptr; |
162 | 0 | } |
163 | 0 | } |
164 | 0 | delete[] newWeights; |
165 | | |
166 | | // delete the old members |
167 | 0 | delete[] pcMesh->mVertices; |
168 | 0 | pcMesh->mVertices = pvPositions; |
169 | |
|
170 | 0 | p = 0; |
171 | 0 | while (pcMesh->HasTextureCoords(p)) { |
172 | 0 | delete[] pcMesh->mTextureCoords[p]; |
173 | 0 | pcMesh->mTextureCoords[p] = apvTextureCoords[p]; |
174 | 0 | ++p; |
175 | 0 | } |
176 | 0 | p = 0; |
177 | 0 | while (pcMesh->HasVertexColors(p)) { |
178 | 0 | delete[] pcMesh->mColors[p]; |
179 | 0 | pcMesh->mColors[p] = apvColorSets[p]; |
180 | 0 | ++p; |
181 | 0 | } |
182 | 0 | pcMesh->mNumVertices = iNumVerts; |
183 | |
|
184 | 0 | if (pcMesh->HasNormals()) { |
185 | 0 | delete[] pcMesh->mNormals; |
186 | 0 | pcMesh->mNormals = pvNormals; |
187 | 0 | } |
188 | 0 | if (pcMesh->HasTangentsAndBitangents()) { |
189 | 0 | delete[] pcMesh->mTangents; |
190 | 0 | pcMesh->mTangents = pvTangents; |
191 | 0 | delete[] pcMesh->mBitangents; |
192 | 0 | pcMesh->mBitangents = pvBitangents; |
193 | 0 | } |
194 | 0 | return (pcMesh->mNumVertices != iOldNumVertices); |
195 | 0 | } |
196 | | |
197 | | // ------------------------------------------------------------------------------------------------ |
198 | 749 | bool IsMeshInVerboseFormat(const aiMesh *mesh) { |
199 | | // avoid slow vector<bool> specialization |
200 | 749 | std::vector<unsigned int> seen(mesh->mNumVertices, 0); |
201 | 1.51k | for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { |
202 | 932 | const aiFace &f = mesh->mFaces[i]; |
203 | 2.72k | for (unsigned int j = 0; j < f.mNumIndices; ++j) { |
204 | 1.96k | if (++seen[f.mIndices[j]] == 2) { |
205 | | // found a duplicate index |
206 | 164 | return false; |
207 | 164 | } |
208 | 1.96k | } |
209 | 932 | } |
210 | | |
211 | 585 | return true; |
212 | 749 | } |
213 | | |
214 | | // ------------------------------------------------------------------------------------------------ |
215 | 271 | bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene *pScene) { |
216 | 856 | for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { |
217 | 749 | if (!IsMeshInVerboseFormat(pScene->mMeshes[i])) { |
218 | 164 | return false; |
219 | 164 | } |
220 | 749 | } |
221 | | |
222 | 107 | return true; |
223 | 271 | } |