SO3Engine
ALScene.cpp
Go to the documentation of this file.
3
4#include <vector>
5#include <sstream>
6#include <queue>
7#include <utility>
8
11
12namespace SO3
13{
15 {
16 mScene = 0;
17 scolScene = 0;
18 parentNode = 0;
19 isConverted = false;
20 resGroup = "";
21 resPath = "";
22 }
23
24 ALScene::ALScene(ALSceneLoader* alSceneLoader, SScene* scene, std::string ressourceGroup, const aiScene* loadedScene, SNode* parent, const std::string &sceneName, bool isLoaderMode)
25 {
26 mSceneLoader = alSceneLoader;
27 mScene = loadedScene;
28 scolScene = scene;
29 isConverted = false;
30 mIsLoaderMode = isLoaderMode;
31 resGroup = ressourceGroup;
32 mSceneName = sceneName;
33
34 // the ressource path is the directory where the original file is contained, so we get
35 // the path up to the last slash.
36 resPath = mSceneLoader->getFilePath().remove_filename().generic_string();
37
38 parentNode = parent;
39 }
40
42 {
43 }
44
46 {
47 return (mScene) ? true : false;
48 }
49
50 const std::vector<std::string> ALScene::getMaterialNames()
51 {
52 return mMaterialNames;
53 }
54
56 {
57 return mIsLoaderMode;
58 }
59
60 aiMatrix4x4 ALScene::getFullTransform(aiNode* toThis)
61 {
62 aiMatrix4x4 fullTrans = toThis->mTransformation;
63 aiNode* parent = toThis->mParent;
64 while(parent && parent != mScene->mRootNode)
65 {
66 fullTrans = parent->mTransformation * fullTrans;
67 parent = parent->mParent;
68 }
69
70 return fullTrans;
71 }
72
73 bool ALScene::load(std::vector<SNode*> &scolNodes, std::vector<SMaterial*> &scolMats)
74 {
75 // If the mScene has not been set ( first constructor, we return nothing ).
76 if(mScene != 0)
77 {
78 if(!isConverted)
79 {
80 // run through the entire list of object and create the hierarchy.
81 // We need assimp to have at least one node, wich should always be the case ( assimp always create at least one root node ).
82 if(mScene->mRootNode != 0)
83 {
84 // get vertex color list
85 std::vector<bool> vertexColorList;
86 vertexColorList.resize(mScene->mNumMaterials, false);
87 for (unsigned int n = 0; n<mScene->mNumMeshes; ++n)
88 {
89 if (mScene->mMeshes[n]->GetNumColorChannels() > 0)
90 vertexColorList[mScene->mMeshes[n]->mMaterialIndex] = true;
91 }
92
93 // Loading all the materials.
94 loadMaterials(vertexColorList, scolMats);
95
96 for (unsigned int i=0; i < scolMats.size(); ++i)
97 {
98 mMaterialNames.push_back(scolMats[i]->GetName());
99 }
100
101 // To avoid ending up with names like mesh3215654 we reset the uid each time finished with one type of data.
103
104 // Loading all the bones names.
105 for(unsigned int n=0; n<mScene->mNumMeshes; ++n)
106 {
107 for(unsigned int i=0; i<mScene->mMeshes[n]->mNumBones; ++i)
108 {
109 aiNode* bnode = mScene->mRootNode->FindNode(mScene->mMeshes[n]->mBones[i]->mName);
110 setBones(bnode);
111 }
112 }
113
114 // Loading all the cameras and light.
115 std::vector<aiCamera*> cams;
116 for(unsigned int n=0; n<mScene->mNumCameras; ++n)
117 cams.push_back(mScene->mCameras[n]);
118
119 std::vector<aiLight*> light;
120 for(unsigned int n=0; n<mScene->mNumLights; ++n)
121 light.push_back(mScene->mLights[n]);
122
123 // Create nodes, meshes, cameras and lights.
124 aiNode* asRootNode = mScene->mRootNode;
125 if (!loadNodes(asRootNode, cams, light, scolNodes))
126 {
127 // error on loading, remove all created nodes
128 for (unsigned int i = 0; i < scolNodes.size(); ++i)
129 {
130 scolScene->DeleteNode(scolNodes[i]);
131 }
132 scolNodes.clear();
133 }
134
136 }
137 }
138
139 return true;
140 }
141 else
142 {
143 return false;
144 }
145 }
146
147 void ALScene::setBones(aiNode* bone)
148 {
149 //add all the parent nodes as bones
150 aiNode* newBone = 0;
151 aiNode* curBone = bone;
152 while(curBone && (curBone->mNumMeshes == 0) && (curBone != mScene->mRootNode))
153 {
154 newBone = curBone;
155 curBone = curBone->mParent;
156 }
157
158 if (newBone)
159 {
160 //add current
161 mBonesNames.insert(std::string(newBone->mName.C_Str()));
162
163 // add all sons
164 std::queue<aiNode*> nodes;
165 nodes.push(newBone);
166 while(!nodes.empty())
167 {
168 newBone = nodes.front();
169 nodes.pop();
170
171 // Get the number of son.
172 unsigned int nbSons = newBone->mNumChildren;
173
174 // while there is still sons, we go through each of them add
175 // add them to the queue.
176 if(nbSons>0)
177 {
178 aiNode** sons = newBone->mChildren;
179
180 for(unsigned int n=0; n<nbSons; ++n)
181 {
182 // We get the son 1 by 1.
183 aiNode* son = sons[n];
184 if (son && (son->mNumMeshes == 0) && (son != mScene->mRootNode))
185 {
186 mBonesNames.insert(std::string(son->mName.C_Str()));
187 nodes.push(son);
188 }
189 }
190 }
191 }
192 }
193 }
194
195 void ALScene::convert(boost::filesystem::path expFolder)
196 {
197 // If the mScene has not been set ( first constructor, we return nothing ).
198 if(mScene != 0)
199 {
200 if(!isConverted)
201 {
202 boost::filesystem::path expFile = expFolder;
203 expFile /= mSceneName + ".scene";
204
205 // run through the entire list of object and create the hierarchy.
206 // We need assimp to have at least one node, wich should always be the case ( assimp always create at least one root node ).
207 if(mScene->mRootNode != 0)
208 {
209 // Create the Dot Scene file for Ogre.
210 std::string sceneFileName = expFile.generic_string();
211 tinyxml2::XMLDocument dotScene;
212 //dotScene.LoadFile(exportFile.c_str());
213
214 // Initializing the scene :
215 tinyxml2::XMLElement* mainElem = dotScene.NewElement("scene");
216 mainElem->SetAttribute("upAxis", "y");
217 mainElem->SetAttribute("unitType", "meters");
218 mainElem->SetAttribute("formatVersion", "1.0");
219 mainElem->SetAttribute("minOgreVersion", "1.8");
220 mainElem->SetAttribute("author", "Scol_Assimp_Exporter");
221 dotScene.InsertEndChild(mainElem);
222
223 // Set environnement
224 tinyxml2::XMLElement* env = dotScene.NewElement("environnement");
225 tinyxml2::XMLElement* colAmbient = dotScene.NewElement("ColourAmbient");
226 tinyxml2::XMLElement* colBack = dotScene.NewElement("ColourBackground");
227 colAmbient->SetAttribute("r", 0.25f);
228 colAmbient->SetAttribute("g", 0.25f);
229 colAmbient->SetAttribute("b", 0.25f);
230 colBack->SetAttribute("r", 0);
231 colBack->SetAttribute("g", 0);
232 colBack->SetAttribute("b", 0);
233
234 env->InsertEndChild(colAmbient);
235 env->InsertEndChild(colBack);
236 mainElem->InsertEndChild(env);
237
238 // get vertex color list
239 std::vector<bool> vertexColorList;
240 vertexColorList.resize(mScene->mNumMaterials, false);
241 for (unsigned int n = 0; n<mScene->mNumMeshes; ++n)
242 {
243 if (mScene->mMeshes[n]->GetNumColorChannels() > 0)
244 vertexColorList[mScene->mMeshes[n]->mMaterialIndex] = true;
245 }
246
247 // convert embedded texture
248 if (mScene->HasTextures())
249 {
250 for (unsigned int i = 0; i < mScene->mNumTextures; i++)
251 {
252 aiTexture* tex = mScene->mTextures[i];
253 bool compressed = (tex->mHeight == 0);
254 //TODO build png texture from data
255 /*
256 if (compressed)
257 {
258 for (unsigned int n = 0; n < tex->mWidth;++n)
259 {
260 fprintf(out,"\t\t\t%2x",reinterpret_cast<uint8_t*>(tex->pcData)[n]);
261 if (n && !(n % 50))
262 fprintf(out,"\n");
263 }
264 }
265 else
266 for (unsigned int y = 0; y < tex->mHeight;++y)
267 {
268 for (unsigned int x = 0; x < tex->mWidth;++x)
269 {
270 aiTexel* tx = tex->pcData + y*tex->mWidth+x;
271 unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a;
272 fprintf(out,"\t\t\t%2x %2x %2x %2x",r,g,b,a);
273
274 // group by four for readibility
275 if (0 == (x+y*tex->mWidth) % 4)
276 fprintf(out,"\n");
277 }
278 }
279 */
280 }
281 }
282
283 // Loading all the materials.
284 convertMaterials(expFolder, vertexColorList, mMaterialNames);
285
286 // To avoid ending up with names like mesh3215654 we reset the uid each time finished with one type of data.
288
289 // Loading all the cameras and light.
290 std::vector<aiCamera*> cams;
291 for(unsigned int n=0; n<mScene->mNumCameras; ++n)
292 cams.push_back(mScene->mCameras[n]);
293
294 std::vector<aiLight*> light;
295 for(unsigned int n=0; n<mScene->mNumLights; ++n)
296 light.push_back(mScene->mLights[n]);
297
298 // Loading all the bones names.
299 for(unsigned int n=0; n<mScene->mNumMeshes; ++n)
300 {
301 for(unsigned int i=0; i<mScene->mMeshes[n]->mNumBones; ++i)
302 {
303 aiNode* bnode = mScene->mRootNode->FindNode(mScene->mMeshes[n]->mBones[i]->mName);
304 setBones(bnode);
305 }
306 }
307
308 // Create nodes, meshes, cameras and lights.
309 tinyxml2::XMLElement* xmlnodes = dotScene.NewElement("nodes");
310 aiNode* asRootNode = mScene->mRootNode;
311 convertNodes(asRootNode, cams, light, expFolder, xmlnodes);
313
314 mainElem->InsertEndChild(xmlnodes);
315
316 dotScene.SaveFile(sceneFileName.c_str());
317 }
318 }
319 }
320 }
321
322 void ALScene::loadMaterials(std::vector<bool> &vertexColorList, std::vector<SMaterial*> &matsList)
323 {
324 unsigned int nbMat = mScene->mNumMaterials;
325 aiMaterial** materials = mScene->mMaterials;
326
327 for(unsigned int n=0; n<nbMat; ++n)
328 {
329 ALMaterial matConv(this, materials[n], vertexColorList[n]);
330 SMaterial* nmat = matConv.load();
331
332 if (nmat)
333 matsList.push_back(nmat);
334 }
335 }
336
337 void ALScene::convertMaterials(boost::filesystem::path expPath, std::vector<bool> &vertexColorList, std::vector<std::string> &matNames)
338 {
339 unsigned int nbMat = mScene->mNumMaterials;
340 aiMaterial** materials = mScene->mMaterials;
341
342 bool Clear = true;
343 for(unsigned int n=0; n<nbMat; ++n)
344 {
345 ALMaterial matConv(this, materials[n], vertexColorList[n]);
346 matNames.push_back(matConv.convert(expPath, Clear));
347 Clear = false;
348 }
349 }
350
351 bool ALScene::loadNodes(aiNode* rootNode, std::vector<aiCamera*> cameras, std::vector<aiLight*> lights, std::vector<SNode*>& outNodes)
352 {
353 ALNode nconv(rootNode, (parentNode == 0) ? scolScene->GetRootNode() : parentNode, this, cameras, lights);
354 SNode* rootScolNode = nconv.load();
355
356 std::pair<aiNode*,SNode*> currentRoot(rootNode, (parentNode == 0) ? scolScene->GetRootNode() : parentNode);
357 std::queue< std::pair<aiNode*,SNode*> > file;
358 file.push(currentRoot);
359
360 // do not add the root node
361 outNodes.push_back(rootScolNode);
362
363 // If the queue is not empty that mean that we have not gone through all the nodes
364 // So, we continue until the queue is empty.
365 while(!file.empty())
366 {
367 // Since we are searching for the children of the first Node in the queue,
368 // it become the current root node for this iteration.
369 currentRoot = file.front();
370 file.pop();
371
372 // Get the number of son.
373 unsigned int nbSons = currentRoot.first->mNumChildren;
374
375 // while there is still sons, we go through each of them add
376 // add them to the queue.
377 if(nbSons>0)
378 {
379 aiNode** sons = currentRoot.first->mChildren;
380
381 for(unsigned int n=0; n<nbSons; ++n)
382 {
383 // We get the son 1 by 1.
384 aiNode* son = sons[n];
385
386 // Convert the current Node, attach it to his parent and compute the transformation.
387 ALNode nconv(son, currentRoot.second, this, cameras, lights);
388 SNode* scolSon = nconv.load();
389
390 // error on loading
391 if (scolSon)
392 {
393 // Add the son to the queue
394 std::pair<aiNode*, SNode*> sonNodes(son, scolSon);
395 file.push(sonNodes);
396
397 // Now we just put the SNode in our list.
398 outNodes.push_back(scolSon);
399 }
400 }
401 }
402 }
403
404 return true;
405 }
406
407 void ALScene::convertNodes(aiNode* rootNode, std::vector<aiCamera*> cameras, std::vector<aiLight*> lights, boost::filesystem::path expPath, tinyxml2::XMLElement* xmlParent)
408 {
409 SNode* rootScolNode = parentNode;
410 ALNode nodeConverter(rootNode, rootScolNode, this, cameras, lights, xmlParent);
411
412 // We begin the algorithm with the root node of the scene.
413 // We use a pair because we need to know the SNode parent of the node we are dealing with.
414 // This is the simpliest way I found to keep track of the Node in both system ( assimp and scol )
415 // since we need both of them at any point.
416 tinyxml2::XMLElement* xmlRootNode = nodeConverter.convert(expPath);
417
418 aiNode* currentRoot(rootNode);
419 std::pair<aiNode*,tinyxml2::XMLElement*> rootinfo(currentRoot, xmlRootNode);
420 std::queue<std::pair<aiNode*,tinyxml2::XMLElement*>> file;
421 file.push(rootinfo);
422
423 // If the queue is not empty that mean that we have not gone through all the nodes
424 // So, we continue until the queue is empty.
425 while(!file.empty())
426 {
427 // Since we are searching for the children of the first Node in the queue,
428 // it become the current root node for this iteration.
429 rootinfo = file.front();
430 currentRoot = rootinfo.first;
431 file.pop();
432
433 //ignore bones but keep nodes with meshes
434 if (!isSceneDependent(currentRoot))
435 continue;
436
437 // Get the number of son.
438 unsigned int nbSons = currentRoot->mNumChildren;
439
440 // while there is still sons, we go through each of them add
441 // add them to the queue.
442 if(nbSons>0)
443 {
444 aiNode** sons = currentRoot->mChildren;
445
446 for(unsigned int n=0; n<nbSons; ++n)
447 {
448 // We get the son 1 by 1.
449 aiNode* son = sons[n];
450
451 //ignore bones
452 if (!isSceneDependent(son))
453 continue;
454
455 // Convert the current Node, attach it to his parent and compute the transformation.
456 ALNode nconv(son, 0, this, cameras, lights, rootinfo.second);
457 tinyxml2::XMLElement* xnode = nconv.convert(expPath);
458
459 // Add the son to the queue
460 std::pair<aiNode*,tinyxml2::XMLElement*> sonInfo(son, xnode);
461
462 file.push(sonInfo);
463 }
464 }
465 }
466 }
467
468 bool ALScene::addTextureRef(std::string name, std::string path)
469 {
470 AlTexturesMap::iterator iTextureSearched = mTextureMap.find(path);
471 if(iTextureSearched != mTextureMap.end())
472 return false;
473
474 mTextureMap.insert(AlTexturesMap::value_type(path, name));
475 return true;
476 }
477
478 std::string ALScene::getTextureRef(std::string path)
479 {
480 AlTexturesMap::iterator iTextureSearched = mTextureMap.find(path);
481 if(iTextureSearched == mTextureMap.end())
482 return "";
483
484 return iTextureSearched->second;
485 }
486
488 {
489 return scolScene;
490 }
491
492 const aiScene* ALScene::getAiScene()
493 {
494 return mScene;
495 }
496
498 {
499 return resGroup;
500 }
501
503 {
504 return resPath;
505 }
506
508 {
509 return mSceneName;
510 }
511
512 std::set<std::string> ALScene::getBonesNames()
513 {
514 return mBonesNames;
515 }
516
517 bool ALScene::isBone(aiNode* node)
518 {
519 if(mBonesNames.find(std::string(node->mName.C_Str())) != mBonesNames.end())
520 return true;
521 else
522 return false;
523 }
524
526 {
527 bool haveMesh = node->mNumMeshes > 0;
528 unsigned int nbSons = node->mNumChildren;
529
530 if (nbSons > 0)
531 {
532 aiNode** sons = node->mChildren;
533
534 for (unsigned int n = 0; n < nbSons && !haveMesh; ++n)
535 {
536 aiNode* son = sons[n];
537 haveMesh = son->mNumMeshes > 0;
538 if (!haveMesh)
539 haveMesh = haveMeshInHierarchy(son);
540 }
541 }
542 return haveMesh;
543 }
544
545 bool ALScene::isSceneDependent(aiNode* node)
546 {
547 if (!isBone(node) || haveMeshInHierarchy(node))
548 return true;
549 else
550 return false;
551 }
552}
static void resetUID()
reset the uid to 0.
std::string getRessourceGroup()
Definition ALScene.cpp:497
bool load(std::vector< SNode * > &scolNodes, std::vector< SMaterial * > &scolMats)
Definition ALScene.cpp:73
const std::vector< std::string > getMaterialNames()
Definition ALScene.cpp:50
aiMatrix4x4 getFullTransform(aiNode *toThis)
Definition ALScene.cpp:60
bool haveMeshInHierarchy(aiNode *node)
Definition ALScene.cpp:525
SScene * getSScene()
Definition ALScene.cpp:487
ALScene()
Empty constructor. Can be used when you can't directly use the full constructor.
Definition ALScene.cpp:14
bool isEmpty()
Definition ALScene.cpp:45
bool isSceneDependent(aiNode *node)
Definition ALScene.cpp:545
const aiScene * getAiScene()
Definition ALScene.cpp:492
bool addTextureRef(std::string name, std::string path)
Definition ALScene.cpp:468
void convert(boost::filesystem::path exportFolder)
Definition ALScene.cpp:195
std::string getSceneName()
Definition ALScene.cpp:507
std::string getTextureRef(std::string path)
Definition ALScene.cpp:478
std::set< std::string > getBonesNames()
Definition ALScene.cpp:512
bool isBone(aiNode *node)
Check if a node is a bone.
Definition ALScene.cpp:517
bool IsLoaderModeEnable()
Definition ALScene.cpp:55
~ALScene()
Destructor.
Definition ALScene.cpp:41
std::string getRessourcePath()
Definition ALScene.cpp:502
boost::filesystem::path getFilePath()
SNode * GetRootNode()
Definition SO3Scene.cpp:454
void DeleteNode(SNode *existingNode)
Definition SO3Scene.cpp:630
XMLElement * NewElement(const char *name)
XMLError SaveFile(const char *filename, bool compact=false)
void SetAttribute(const char *name, const char *value)
Sets the named attribute to value.
Definition tinyxml2.h:1303
XMLNode * InsertEndChild(XMLNode *addThis)