vrshoot

view libs/assimp/OptimizeGraph.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
42 /** @file OptimizeGraph.cpp
43 * @brief Implementation of the aiProcess_OptimizGraph step
44 */
46 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
49 using namespace Assimp;
50 #include "OptimizeGraph.h"
51 #include "ProcessHelper.h"
52 #include "SceneCombiner.h"
54 #define AI_RESERVED_NODE_NAME "$Reserved_And_Evil"
56 /* AI_OG_USE_HASHING enables the use of hashing to speed-up std::set lookups.
57 * The unhashed variant should be faster, except for *very* large data sets
58 */
59 #ifdef AI_OG_USE_HASHING
60 // Use our standard hashing function to compute the hash
61 # define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length)
62 #else
63 // Otherwise hope that std::string will utilize a static buffer
64 // for shorter node names. This would avoid endless heap copying.
65 # define AI_OG_GETKEY(str) std::string(str.data)
66 #endif
68 // ------------------------------------------------------------------------------------------------
69 // Constructor to be privately used by Importer
70 OptimizeGraphProcess::OptimizeGraphProcess()
71 {}
73 // ------------------------------------------------------------------------------------------------
74 // Destructor, private as well
75 OptimizeGraphProcess::~OptimizeGraphProcess()
76 {}
78 // ------------------------------------------------------------------------------------------------
79 // Returns whether the processing step is present in the given flag field.
80 bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const
81 {
82 return (0 != (pFlags & aiProcess_OptimizeGraph));
83 }
85 // ------------------------------------------------------------------------------------------------
86 // Setup properties for the postprocessing step
87 void OptimizeGraphProcess::SetupProperties(const Importer* pImp)
88 {
89 // Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST
90 std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,"");
91 AddLockedNodeList(tmp);
92 }
94 // ------------------------------------------------------------------------------------------------
95 // Collect new children
96 void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes)
97 {
98 nodes_in += nd->mNumChildren;
100 // Process children
101 std::list<aiNode*> child_nodes;
102 for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
104 CollectNewChildren(nd->mChildren[i],child_nodes);
105 nd->mChildren[i] = NULL;
106 }
108 // Check whether we need this node; if not we can replace it by our own children (warn, danger of incest).
109 if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end() ) {
110 for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
112 if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) {
113 (*it)->mTransformation = nd->mTransformation * (*it)->mTransformation;
114 nodes.push_back(*it);
116 it = child_nodes.erase(it);
117 continue;
118 }
119 ++it;
120 }
122 if (nd->mNumMeshes || child_nodes.size()) {
123 nodes.push_back(nd);
124 }
125 else {
126 delete nd; /* bye, node */
127 return;
128 }
129 }
130 else {
132 // Retain our current position in the hierarchy
133 nodes.push_back(nd);
135 // Now check for possible optimizations in our list of child nodes. join as many as possible
136 aiNode* join_master = NULL;
137 aiMatrix4x4 inv;
139 const LockedSetType::const_iterator end = locked.end();
141 std::list<aiNode*> join;
142 for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
143 aiNode* child = *it;
144 if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) {
146 // There may be no instanced meshes
147 unsigned int n = 0;
148 for (; n < child->mNumMeshes;++n) {
149 if (meshes[child->mMeshes[n]] > 1) {
150 break;
151 }
152 }
153 if (n == child->mNumMeshes) {
155 if (!join_master) {
156 join_master = child;
157 inv = join_master->mTransformation;
158 inv.Inverse();
159 }
160 else {
162 child->mTransformation = inv * child->mTransformation ;
164 join.push_back(child);
165 it = child_nodes.erase(it);
166 continue;
167 }
168 }
169 }
170 ++it;
171 }
172 if (join_master && join.size()) {
173 join_master->mName.length = sprintf(join_master->mName.data,"$MergedNode_%i",count_merged++);
175 unsigned int out_meshes = 0;
176 for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
177 out_meshes += (*it)->mNumMeshes;
178 }
180 // copy all mesh references in one array
181 if (out_meshes) {
182 unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes;
183 for (unsigned int n = 0; n < join_master->mNumMeshes;++n) {
184 *tmp++ = join_master->mMeshes[n];
185 }
187 for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
188 for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) {
190 *tmp = (*it)->mMeshes[n];
191 aiMesh* mesh = mScene->mMeshes[*tmp++];
193 // manually move the mesh into the right coordinate system
194 const aiMatrix3x3 IT = aiMatrix3x3( (*it)->mTransformation ).Inverse().Transpose();
195 for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
197 mesh->mVertices[a] *= (*it)->mTransformation;
199 if (mesh->HasNormals())
200 mesh->mNormals[a] *= IT;
202 if (mesh->HasTangentsAndBitangents()) {
203 mesh->mTangents[a] *= IT;
204 mesh->mBitangents[a] *= IT;
205 }
206 }
207 }
208 delete *it; // bye, node
209 }
210 delete[] join_master->mMeshes;
211 join_master->mMeshes = meshes;
212 join_master->mNumMeshes += out_meshes;
213 }
214 }
215 }
216 // reassign children if something changed
217 if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) {
219 delete[] nd->mChildren;
221 if (child_nodes.size())
222 nd->mChildren = new aiNode*[child_nodes.size()];
223 else nd->mChildren = NULL;
224 }
226 nd->mNumChildren = child_nodes.size();
228 aiNode** tmp = nd->mChildren;
229 for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
230 aiNode* node = *tmp++ = *it;
231 node->mParent = nd;
232 }
234 nodes_out += child_nodes.size();
235 }
237 // ------------------------------------------------------------------------------------------------
238 // Execute the postprocessing step on the given scene
239 void OptimizeGraphProcess::Execute( aiScene* pScene)
240 {
241 DefaultLogger::get()->debug("OptimizeGraphProcess begin");
242 nodes_in = nodes_out = count_merged = 0;
243 mScene = pScene;
245 meshes.resize(pScene->mNumMeshes,0);
246 FindInstancedMeshes(pScene->mRootNode);
248 // build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it
249 locked.clear();
250 for (std::list<std::string>::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) {
251 #ifdef AI_OG_USE_HASHING
252 locked.insert(SuperFastHash((*it).c_str()));
253 #else
254 locked.insert(*it);
255 #endif
256 }
258 for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {
259 for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) {
261 aiNodeAnim* anim = pScene->mAnimations[i]->mChannels[a];
262 locked.insert(AI_OG_GETKEY(anim->mNodeName));
263 }
264 }
266 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
267 for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) {
269 aiBone* bone = pScene->mMeshes[i]->mBones[a];
270 locked.insert(AI_OG_GETKEY(bone->mName));
272 // HACK: Meshes referencing bones may not be transformed; we need to look them.
273 // The easiest way to do this is to increase their reference counters ...
274 meshes[i] += 2;
275 }
276 }
278 for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {
279 aiCamera* cam = pScene->mCameras[i];
280 locked.insert(AI_OG_GETKEY(cam->mName));
281 }
283 for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
284 aiLight* lgh = pScene->mLights[i];
285 locked.insert(AI_OG_GETKEY(lgh->mName));
286 }
288 // Insert a dummy master node and make it read-only
289 aiNode* dummy_root = new aiNode(AI_RESERVED_NODE_NAME);
290 locked.insert(AI_OG_GETKEY(dummy_root->mName));
292 const aiString prev = pScene->mRootNode->mName;
293 pScene->mRootNode->mParent = dummy_root;
295 dummy_root->mChildren = new aiNode*[dummy_root->mNumChildren = 1];
296 dummy_root->mChildren[0] = pScene->mRootNode;
298 // Do our recursive processing of scenegraph nodes. For each node collect
299 // a fully new list of children and allow their children to place themselves
300 // on the same hierarchy layer as their parents.
301 std::list<aiNode*> nodes;
302 CollectNewChildren (dummy_root,nodes);
304 ai_assert(nodes.size() == 1);
306 if (dummy_root->mNumChildren == 0) {
307 pScene->mRootNode = NULL;
308 throw DeadlyImportError("After optimizing the scene graph, no data remains");
309 }
311 if (dummy_root->mNumChildren > 1) {
312 pScene->mRootNode = dummy_root;
314 // Keep the dummy node but assign the name of the old root node to it
315 pScene->mRootNode->mName = prev;
316 }
317 else {
319 // Remove the dummy root node again.
320 pScene->mRootNode = dummy_root->mChildren[0];
322 dummy_root->mChildren[0] = NULL;
323 delete dummy_root;
324 }
326 pScene->mRootNode->mParent = NULL;
327 if (!DefaultLogger::isNullLogger()) {
328 if ( nodes_in != nodes_out) {
330 char buf[512];
331 sprintf(buf,"OptimizeGraphProcess finished; Input nodes: %i, Output nodes: %i",nodes_in,nodes_out);
332 DefaultLogger::get()->info(buf);
333 }
334 else DefaultLogger::get()->debug("OptimizeGraphProcess finished");
335 }
336 meshes.clear();
337 locked.clear();
338 }
340 // ------------------------------------------------------------------------------------------------
341 // Buidl a LUT of all instanced meshes
342 void OptimizeGraphProcess::FindInstancedMeshes (aiNode* pNode)
343 {
344 for (unsigned int i = 0; i < pNode->mNumMeshes;++i) {
345 ++meshes[pNode->mMeshes[i]];
346 }
348 for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
349 FindInstancedMeshes(pNode->mChildren[i]);
350 }
352 #endif // !! ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS