1 | /* |
2 | --------------------------------------------------------------------------- |
3 | Open Asset Import Library (assimp) |
4 | --------------------------------------------------------------------------- |
5 | |
6 | Copyright (c) 2006-2017, assimp team |
7 | |
8 | |
9 | All rights reserved. |
10 | |
11 | Redistribution and use of this software in source and binary forms, |
12 | with or without modification, are permitted provided that the following |
13 | conditions are met: |
14 | |
15 | * Redistributions of source code must retain the above |
16 | copyright notice, this list of conditions and the |
17 | following disclaimer. |
18 | |
19 | * Redistributions in binary form must reproduce the above |
20 | copyright notice, this list of conditions and the |
21 | following disclaimer in the documentation and/or other |
22 | materials provided with the distribution. |
23 | |
24 | * Neither the name of the assimp team, nor the names of its |
25 | contributors may be used to endorse or promote products |
26 | derived from this software without specific prior |
27 | written permission of the assimp team. |
28 | |
29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
30 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
33 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
34 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
35 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
36 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
37 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
39 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
40 | --------------------------------------------------------------------------- |
41 | */ |
42 | /** @file Implementation of the post processing step to remove |
43 | * any parts of the mesh structure from the imported data. |
44 | */ |
45 | |
46 | |
47 | #include "RemoveVCProcess.h" |
48 | #include <assimp/postprocess.h> |
49 | #include <assimp/DefaultLogger.hpp> |
50 | #include <assimp/scene.h> |
51 | |
52 | using namespace Assimp; |
53 | |
54 | // ------------------------------------------------------------------------------------------------ |
55 | // Constructor to be privately used by Importer |
56 | RemoveVCProcess::RemoveVCProcess() : |
57 | configDeleteFlags() |
58 | , mScene() |
59 | {} |
60 | |
61 | // ------------------------------------------------------------------------------------------------ |
62 | // Destructor, private as well |
63 | RemoveVCProcess::~RemoveVCProcess() |
64 | {} |
65 | |
66 | // ------------------------------------------------------------------------------------------------ |
67 | // Returns whether the processing step is present in the given flag field. |
68 | bool RemoveVCProcess::IsActive( unsigned int pFlags) const |
69 | { |
70 | return (pFlags & aiProcess_RemoveComponent) != 0; |
71 | } |
72 | |
73 | // ------------------------------------------------------------------------------------------------ |
74 | // Small helper function to delete all elements in a T** aray using delete |
75 | template <typename T> |
76 | inline void ArrayDelete(T**& in, unsigned int& num) |
77 | { |
78 | for (unsigned int i = 0; i < num; ++i) |
79 | delete in[i]; |
80 | |
81 | delete[] in; |
82 | in = NULL; |
83 | num = 0; |
84 | } |
85 | |
86 | #if 0 |
87 | // ------------------------------------------------------------------------------------------------ |
88 | // Updates the node graph - removes all nodes which have the "remove" flag set and the |
89 | // "don't remove" flag not set. Nodes with meshes are never deleted. |
90 | bool UpdateNodeGraph(aiNode* node,std::list<aiNode*>& childsOfParent,bool root) |
91 | { |
92 | bool b = false; |
93 | |
94 | std::list<aiNode*> mine; |
95 | for (unsigned int i = 0; i < node->mNumChildren;++i) |
96 | { |
97 | if(UpdateNodeGraph(node->mChildren[i],mine,false)) |
98 | b = true; |
99 | } |
100 | |
101 | // somewhat tricky ... mNumMeshes must be originally 0 and MSB2 may not be set, |
102 | // so we can do a simple comparison against MSB here |
103 | if (!root && AI_RC_UINT_MSB == node->mNumMeshes ) |
104 | { |
105 | // this node needs to be removed |
106 | if(node->mNumChildren) |
107 | { |
108 | childsOfParent.insert(childsOfParent.end(),mine.begin(),mine.end()); |
109 | |
110 | // set all children to NULL to make sure they are not deleted when we delete ourself |
111 | for (unsigned int i = 0; i < node->mNumChildren;++i) |
112 | node->mChildren[i] = NULL; |
113 | } |
114 | b = true; |
115 | delete node; |
116 | } |
117 | else |
118 | { |
119 | AI_RC_UNMASK(node->mNumMeshes); |
120 | childsOfParent.push_back(node); |
121 | |
122 | if (b) |
123 | { |
124 | // reallocate the array of our children here |
125 | node->mNumChildren = (unsigned int)mine.size(); |
126 | aiNode** const children = new aiNode*[mine.size()]; |
127 | aiNode** ptr = children; |
128 | |
129 | for (std::list<aiNode*>::iterator it = mine.begin(), end = mine.end(); |
130 | it != end; ++it) |
131 | { |
132 | *ptr++ = *it; |
133 | } |
134 | delete[] node->mChildren; |
135 | node->mChildren = children; |
136 | return false; |
137 | } |
138 | } |
139 | return b; |
140 | } |
141 | #endif |
142 | |
143 | // ------------------------------------------------------------------------------------------------ |
144 | // Executes the post processing step on the given imported data. |
145 | void RemoveVCProcess::Execute( aiScene* pScene) |
146 | { |
147 | DefaultLogger::get()->debug("RemoveVCProcess begin" ); |
148 | bool bHas = false; //,bMasked = false; |
149 | |
150 | mScene = pScene; |
151 | |
152 | // handle animations |
153 | if ( configDeleteFlags & aiComponent_ANIMATIONS) |
154 | { |
155 | |
156 | bHas = true; |
157 | ArrayDelete(pScene->mAnimations,pScene->mNumAnimations); |
158 | } |
159 | |
160 | // handle textures |
161 | if ( configDeleteFlags & aiComponent_TEXTURES) |
162 | { |
163 | bHas = true; |
164 | ArrayDelete(pScene->mTextures,pScene->mNumTextures); |
165 | } |
166 | |
167 | // handle materials |
168 | if ( configDeleteFlags & aiComponent_MATERIALS && pScene->mNumMaterials) |
169 | { |
170 | bHas = true; |
171 | for (unsigned int i = 1;i < pScene->mNumMaterials;++i) |
172 | delete pScene->mMaterials[i]; |
173 | |
174 | pScene->mNumMaterials = 1; |
175 | aiMaterial* helper = (aiMaterial*) pScene->mMaterials[0]; |
176 | ai_assert(NULL != helper); |
177 | helper->Clear(); |
178 | |
179 | // gray |
180 | aiColor3D clr(0.6f,0.6f,0.6f); |
181 | helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); |
182 | |
183 | // add a small ambient color value |
184 | clr = aiColor3D(0.05f,0.05f,0.05f); |
185 | helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT); |
186 | |
187 | aiString s; |
188 | s.Set("Dummy_MaterialsRemoved" ); |
189 | helper->AddProperty(&s,AI_MATKEY_NAME); |
190 | } |
191 | |
192 | // handle light sources |
193 | if ( configDeleteFlags & aiComponent_LIGHTS) |
194 | { |
195 | bHas = true; |
196 | ArrayDelete(pScene->mLights,pScene->mNumLights); |
197 | } |
198 | |
199 | // handle camneras |
200 | if ( configDeleteFlags & aiComponent_CAMERAS) |
201 | { |
202 | bHas = true; |
203 | ArrayDelete(pScene->mCameras,pScene->mNumCameras); |
204 | } |
205 | |
206 | // handle meshes |
207 | if (configDeleteFlags & aiComponent_MESHES) |
208 | { |
209 | bHas = true; |
210 | ArrayDelete(pScene->mMeshes,pScene->mNumMeshes); |
211 | } |
212 | else |
213 | { |
214 | for( unsigned int a = 0; a < pScene->mNumMeshes; a++) |
215 | { |
216 | if( ProcessMesh( pScene->mMeshes[a])) |
217 | bHas = true; |
218 | } |
219 | } |
220 | |
221 | |
222 | // now check whether the result is still a full scene |
223 | if (!pScene->mNumMeshes || !pScene->mNumMaterials) |
224 | { |
225 | pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; |
226 | DefaultLogger::get()->debug("Setting AI_SCENE_FLAGS_INCOMPLETE flag" ); |
227 | |
228 | // If we have no meshes anymore we should also clear another flag ... |
229 | if (!pScene->mNumMeshes) |
230 | pScene->mFlags &= ~AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; |
231 | } |
232 | |
233 | if (bHas)DefaultLogger::get()->info("RemoveVCProcess finished. Data structure cleanup has been done." ); |
234 | else DefaultLogger::get()->debug("RemoveVCProcess finished. Nothing to be done ..." ); |
235 | } |
236 | |
237 | // ------------------------------------------------------------------------------------------------ |
238 | // Setup configuration properties for the step |
239 | void RemoveVCProcess::SetupProperties(const Importer* pImp) |
240 | { |
241 | configDeleteFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,0x0); |
242 | if (!configDeleteFlags) |
243 | { |
244 | DefaultLogger::get()->warn("RemoveVCProcess: AI_CONFIG_PP_RVC_FLAGS is zero." ); |
245 | } |
246 | } |
247 | |
248 | // ------------------------------------------------------------------------------------------------ |
249 | // Executes the post processing step on the given imported data. |
250 | bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh) |
251 | { |
252 | bool ret = false; |
253 | |
254 | // if all materials have been deleted let the material |
255 | // index of the mesh point to the created default material |
256 | if ( configDeleteFlags & aiComponent_MATERIALS) |
257 | pMesh->mMaterialIndex = 0; |
258 | |
259 | // handle normals |
260 | if (configDeleteFlags & aiComponent_NORMALS && pMesh->mNormals) |
261 | { |
262 | delete[] pMesh->mNormals; |
263 | pMesh->mNormals = NULL; |
264 | ret = true; |
265 | } |
266 | |
267 | // handle tangents and bitangents |
268 | if (configDeleteFlags & aiComponent_TANGENTS_AND_BITANGENTS && pMesh->mTangents) |
269 | { |
270 | delete[] pMesh->mTangents; |
271 | pMesh->mTangents = NULL; |
272 | |
273 | delete[] pMesh->mBitangents; |
274 | pMesh->mBitangents = NULL; |
275 | ret = true; |
276 | } |
277 | |
278 | // handle texture coordinates |
279 | bool b = (0 != (configDeleteFlags & aiComponent_TEXCOORDS)); |
280 | for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++real) |
281 | { |
282 | if (!pMesh->mTextureCoords[i])break; |
283 | if (configDeleteFlags & aiComponent_TEXCOORDSn(real) || b) |
284 | { |
285 | delete [] pMesh->mTextureCoords[i]; |
286 | pMesh->mTextureCoords[i] = NULL; |
287 | ret = true; |
288 | |
289 | if (!b) |
290 | { |
291 | // collapse the rest of the array |
292 | for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) |
293 | pMesh->mTextureCoords[a-1] = pMesh->mTextureCoords[a]; |
294 | |
295 | pMesh->mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS-1] = NULL; |
296 | continue; |
297 | } |
298 | } |
299 | ++i; |
300 | } |
301 | |
302 | // handle vertex colors |
303 | b = (0 != (configDeleteFlags & aiComponent_COLORS)); |
304 | for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_COLOR_SETS; ++real) |
305 | { |
306 | if (!pMesh->mColors[i])break; |
307 | if (configDeleteFlags & aiComponent_COLORSn(i) || b) |
308 | { |
309 | delete [] pMesh->mColors[i]; |
310 | pMesh->mColors[i] = NULL; |
311 | ret = true; |
312 | |
313 | if (!b) |
314 | { |
315 | // collapse the rest of the array |
316 | for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) |
317 | pMesh->mColors[a-1] = pMesh->mColors[a]; |
318 | |
319 | pMesh->mColors[AI_MAX_NUMBER_OF_COLOR_SETS-1] = NULL; |
320 | continue; |
321 | } |
322 | } |
323 | ++i; |
324 | } |
325 | |
326 | // handle bones |
327 | if (configDeleteFlags & aiComponent_BONEWEIGHTS && pMesh->mBones) |
328 | { |
329 | ArrayDelete(pMesh->mBones,pMesh->mNumBones); |
330 | ret = true; |
331 | } |
332 | return ret; |
333 | } |
334 | |