aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CColladaFileLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CColladaFileLoader.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CColladaFileLoader.cpp2957
1 files changed, 2957 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CColladaFileLoader.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CColladaFileLoader.cpp
new file mode 100644
index 0000000..6509812
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CColladaFileLoader.cpp
@@ -0,0 +1,2957 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "IrrCompileConfig.h"
6#ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_
7
8#include "CColladaFileLoader.h"
9#include "os.h"
10#include "IXMLReader.h"
11#include "IDummyTransformationSceneNode.h"
12#include "SAnimatedMesh.h"
13#include "fast_atof.h"
14#include "quaternion.h"
15#include "ILightSceneNode.h"
16#include "ICameraSceneNode.h"
17#include "IMeshManipulator.h"
18#include "IReadFile.h"
19#include "IAttributes.h"
20#include "IMeshCache.h"
21#include "IMeshSceneNode.h"
22#include "SMeshBufferLightMap.h"
23#include "irrMap.h"
24
25#ifdef _DEBUG
26#define COLLADA_READER_DEBUG
27#endif
28namespace irr
29{
30namespace scene
31{
32namespace
33{
34 // currently supported COLLADA tag names
35 const core::stringc colladaSectionName = "COLLADA";
36 const core::stringc librarySectionName = "library";
37 const core::stringc libraryNodesSectionName = "library_nodes";
38 const core::stringc libraryGeometriesSectionName = "library_geometries";
39 const core::stringc libraryMaterialsSectionName = "library_materials";
40 const core::stringc libraryImagesSectionName = "library_images";
41 const core::stringc libraryVisualScenesSectionName = "library_visual_scenes";
42 const core::stringc libraryCamerasSectionName = "library_cameras";
43 const core::stringc libraryLightsSectionName = "library_lights";
44 const core::stringc libraryEffectsSectionName = "library_effects";
45 const core::stringc assetSectionName = "asset";
46 const core::stringc sceneSectionName = "scene";
47 const core::stringc visualSceneSectionName = "visual_scene";
48
49 const core::stringc lightPrefabName = "light";
50 const core::stringc cameraPrefabName = "camera";
51 const core::stringc materialSectionName = "material";
52 const core::stringc geometrySectionName = "geometry";
53 const core::stringc imageSectionName = "image";
54 const core::stringc textureSectionName = "texture";
55 const core::stringc effectSectionName = "effect";
56
57 const core::stringc pointSectionName = "point";
58 const core::stringc directionalSectionName ="directional";
59 const core::stringc spotSectionName = "spot";
60 const core::stringc ambientSectionName = "ambient";
61 const core::stringc meshSectionName = "mesh";
62 const core::stringc sourceSectionName = "source";
63 const core::stringc arraySectionName = "array";
64 const core::stringc floatArraySectionName ="float_array";
65 const core::stringc intArraySectionName = "int_array";
66 const core::stringc techniqueCommonSectionName = "technique_common";
67 const core::stringc accessorSectionName = "accessor";
68 const core::stringc verticesSectionName = "vertices";
69 const core::stringc inputTagName = "input";
70 const core::stringc polylistSectionName = "polylist";
71 const core::stringc trianglesSectionName = "triangles";
72 const core::stringc polygonsSectionName = "polygons";
73 const core::stringc primitivesName = "p";
74 const core::stringc vcountName = "vcount";
75
76 const core::stringc upAxisNodeName = "up_axis";
77 const core::stringc nodeSectionName = "node";
78 const core::stringc lookatNodeName = "lookat";
79 const core::stringc matrixNodeName = "matrix";
80 const core::stringc perspectiveNodeName = "perspective";
81 const core::stringc rotateNodeName = "rotate";
82 const core::stringc scaleNodeName = "scale";
83 const core::stringc translateNodeName = "translate";
84 const core::stringc skewNodeName = "skew";
85 const core::stringc bboxNodeName = "boundingbox";
86 const core::stringc minNodeName = "min";
87 const core::stringc maxNodeName = "max";
88 const core::stringc instanceName = "instance";
89 const core::stringc instanceGeometryName = "instance_geometry";
90 const core::stringc instanceSceneName = "instance_visual_scene";
91 const core::stringc instanceEffectName = "instance_effect";
92 const core::stringc instanceMaterialName = "instance_material";
93 const core::stringc instanceLightName = "instance_light";
94 const core::stringc instanceNodeName = "instance_node";
95 const core::stringc bindMaterialName = "bind_material";
96 const core::stringc extraNodeName = "extra";
97 const core::stringc techniqueNodeName = "technique";
98 const core::stringc colorNodeName = "color";
99 const core::stringc floatNodeName = "float";
100 const core::stringc float2NodeName = "float2";
101 const core::stringc float3NodeName = "float3";
102
103 const core::stringc newParamName = "newparam";
104 const core::stringc paramTagName = "param";
105 const core::stringc initFromName = "init_from";
106 const core::stringc dataName = "data";
107 const core::stringc wrapsName = "wrap_s";
108 const core::stringc wraptName = "wrap_t";
109 const core::stringc minfilterName = "minfilter";
110 const core::stringc magfilterName = "magfilter";
111 const core::stringc mipfilterName = "mipfilter";
112
113 const core::stringc textureNodeName = "texture";
114 const core::stringc doubleSidedNodeName = "double_sided";
115 const core::stringc constantAttenuationNodeName = "constant_attenuation";
116 const core::stringc linearAttenuationNodeName = "linear_attenuation";
117 const core::stringc quadraticAttenuationNodeName = "quadratic_attenuation";
118 const core::stringc falloffAngleNodeName = "falloff_angle";
119 const core::stringc falloffExponentNodeName = "falloff_exponent";
120
121 const core::stringc profileCOMMONSectionName = "profile_COMMON";
122 const core::stringc profileCOMMONAttributeName = "COMMON";
123
124 const char* const inputSemanticNames[] = {"POSITION", "VERTEX", "NORMAL", "TEXCOORD",
125 "UV", "TANGENT", "IMAGE", "TEXTURE", 0};
126
127 // We have to read ambient lights like other light types here, so we need a type for it
128 const video::E_LIGHT_TYPE ELT_AMBIENT = video::E_LIGHT_TYPE(video::ELT_COUNT+1);
129}
130
131 //! following class is for holding and creating instances of library
132 //! objects, named prefabs in this loader.
133 class CPrefab : public IColladaPrefab
134 {
135 public:
136
137 CPrefab(const core::stringc& id) : Id(id)
138 {
139 }
140
141 //! creates an instance of this prefab
142 virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent,
143 scene::ISceneManager* mgr)
144 {
145 // empty implementation
146 return 0;
147 }
148
149 //! returns id of this prefab
150 virtual const core::stringc& getId()
151 {
152 return Id;
153 }
154
155 protected:
156
157 core::stringc Id;
158 };
159
160
161 //! prefab for a light scene node
162 class CLightPrefab : public CPrefab
163 {
164 public:
165
166 CLightPrefab(const core::stringc& id) : CPrefab(id)
167 {
168 #ifdef COLLADA_READER_DEBUG
169 os::Printer::log("COLLADA: loaded light prefab", Id.c_str(), ELL_DEBUG);
170 #endif
171 }
172
173 video::SLight LightData; // publically accessible
174
175 //! creates an instance of this prefab
176 virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent,
177 scene::ISceneManager* mgr)
178 {
179 #ifdef COLLADA_READER_DEBUG
180 os::Printer::log("COLLADA: Constructing light instance", Id.c_str(), ELL_DEBUG);
181 #endif
182
183 if ( LightData.Type == ELT_AMBIENT )
184 {
185 mgr->setAmbientLight( LightData.DiffuseColor );
186 return 0;
187 }
188
189 scene::ILightSceneNode* l = mgr->addLightSceneNode(parent);
190 if (l)
191 {
192 l->setLightData ( LightData );
193 l->setName(getId());
194 }
195 return l;
196 }
197 };
198
199
200 //! prefab for a mesh scene node
201 class CGeometryPrefab : public CPrefab
202 {
203 public:
204
205 CGeometryPrefab(const core::stringc& id) : CPrefab(id)
206 {
207 }
208
209 scene::IMesh* Mesh;
210
211 //! creates an instance of this prefab
212 virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent,
213 scene::ISceneManager* mgr)
214 {
215 #ifdef COLLADA_READER_DEBUG
216 os::Printer::log("COLLADA: Constructing mesh instance", Id.c_str(), ELL_DEBUG);
217 #endif
218
219 scene::ISceneNode* m = mgr->addMeshSceneNode(Mesh, parent);
220 if (m)
221 {
222 m->setName(getId());
223// m->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
224// m->setDebugDataVisible(scene::EDS_FULL);
225 }
226 return m;
227 }
228 };
229
230
231 //! prefab for a camera scene node
232 class CCameraPrefab : public CPrefab
233 {
234 public:
235
236 CCameraPrefab(const core::stringc& id)
237 : CPrefab(id), YFov(core::PI / 2.5f), ZNear(1.0f), ZFar(3000.0f)
238 {
239 #ifdef COLLADA_READER_DEBUG
240 os::Printer::log("COLLADA: loaded camera prefab", Id.c_str(), ELL_DEBUG);
241 #endif
242 }
243
244 // publicly accessible data
245 f32 YFov;
246 f32 ZNear;
247 f32 ZFar;
248
249 //! creates an instance of this prefab
250 virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent,
251 scene::ISceneManager* mgr)
252 {
253 #ifdef COLLADA_READER_DEBUG
254 os::Printer::log("COLLADA: Constructing camera instance", Id.c_str(), ELL_DEBUG);
255 #endif
256
257 scene::ICameraSceneNode* c = mgr->addCameraSceneNode(parent);
258 if (c)
259 {
260 c->setFOV(YFov);
261 c->setNearValue(ZNear);
262 c->setFarValue(ZFar);
263 c->setName(getId());
264 }
265 return c;
266 }
267 };
268
269
270 //! prefab for a container scene node
271 //! Collects other prefabs and instantiates them upon instantiation
272 //! Uses a dummy scene node to return the children as one scene node
273 class CScenePrefab : public CPrefab
274 {
275 public:
276 CScenePrefab(const core::stringc& id) : CPrefab(id)
277 {
278 #ifdef COLLADA_READER_DEBUG
279 os::Printer::log("COLLADA: loaded scene prefab", Id.c_str(), ELL_DEBUG);
280 #endif
281 }
282
283 //! creates an instance of this prefab
284 virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent,
285 scene::ISceneManager* mgr)
286 {
287 #ifdef COLLADA_READER_DEBUG
288 os::Printer::log("COLLADA: Constructing scene instance", Id.c_str(), ELL_DEBUG);
289 #endif
290
291 if (Children.size()==0)
292 return 0;
293
294 scene::IDummyTransformationSceneNode* s = mgr->addDummyTransformationSceneNode(parent);
295 if (s)
296 {
297 s->setName(getId());
298 s->getRelativeTransformationMatrix() = Transformation;
299 s->updateAbsolutePosition();
300 core::stringc t;
301 for (u32 i=0; i<16; ++i)
302 {
303 t+=core::stringc((double)Transformation[i]);
304 t+=" ";
305 }
306 #ifdef COLLADA_READER_DEBUG
307 os::Printer::log("COLLADA: Transformation", t.c_str(), ELL_DEBUG);
308 #endif
309
310 for (u32 i=0; i<Children.size(); ++i)
311 Children[i]->addInstance(s, mgr);
312 }
313
314 return s;
315 }
316
317 core::array<IColladaPrefab*> Children;
318 core::matrix4 Transformation;
319 };
320
321
322//! Constructor
323CColladaFileLoader::CColladaFileLoader(scene::ISceneManager* smgr,
324 io::IFileSystem* fs)
325: SceneManager(smgr), FileSystem(fs), DummyMesh(0),
326 FirstLoadedMesh(0), LoadedMeshCount(0), CreateInstances(false)
327{
328 #ifdef _DEBUG
329 setDebugName("CColladaFileLoader");
330 #endif
331}
332
333
334//! destructor
335CColladaFileLoader::~CColladaFileLoader()
336{
337 if (DummyMesh)
338 DummyMesh->drop();
339
340 if (FirstLoadedMesh)
341 FirstLoadedMesh->drop();
342}
343
344
345//! Returns true if the file maybe is able to be loaded by this class.
346/** This decision should be based only on the file extension (e.g. ".cob") */
347bool CColladaFileLoader::isALoadableFileExtension(const io::path& filename) const
348{
349 return core::hasFileExtension ( filename, "xml", "dae" );
350}
351
352
353//! creates/loads an animated mesh from the file.
354//! \return Pointer to the created mesh. Returns 0 if loading failed.
355//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
356//! See IReferenceCounted::drop() for more information.
357IAnimatedMesh* CColladaFileLoader::createMesh(io::IReadFile* file)
358{
359 io::IXMLReaderUTF8* reader = FileSystem->createXMLReaderUTF8(file);
360 if (!reader)
361 return 0;
362
363 CurrentlyLoadingMesh = file->getFileName();
364 CreateInstances = SceneManager->getParameters()->getAttributeAsBool(
365 scene::COLLADA_CREATE_SCENE_INSTANCES);
366 Version = 0;
367 FlipAxis = false;
368
369 // read until COLLADA section, skip other parts
370
371 while(reader->read())
372 {
373 if (reader->getNodeType() == io::EXN_ELEMENT)
374 {
375 if (colladaSectionName == reader->getNodeName())
376 readColladaSection(reader);
377 else
378 skipSection(reader, true); // unknown section
379 }
380 }
381
382 reader->drop();
383 if (!Version)
384 return 0;
385
386 // because this loader loads and creates a complete scene instead of
387 // a single mesh, return an empty dummy mesh to make the scene manager
388 // know that everything went well.
389 if (!DummyMesh)
390 DummyMesh = new SAnimatedMesh();
391 scene::IAnimatedMesh* returnMesh = DummyMesh;
392
393 if (Version < 10400)
394 instantiateNode(SceneManager->getRootSceneNode());
395
396 // add the first loaded mesh into the mesh cache too, if more than one
397 // meshes have been loaded from the file
398 if (LoadedMeshCount>1 && FirstLoadedMesh)
399 {
400 os::Printer::log("Added COLLADA mesh", FirstLoadedMeshName.c_str());
401 SceneManager->getMeshCache()->addMesh(FirstLoadedMeshName.c_str(), FirstLoadedMesh);
402 }
403
404 // clean up temporary loaded data
405 clearData();
406
407 returnMesh->grab(); // store until this loader is destroyed
408
409 DummyMesh->drop();
410 DummyMesh = 0;
411
412 if (FirstLoadedMesh)
413 FirstLoadedMesh->drop();
414 FirstLoadedMesh = 0;
415 LoadedMeshCount = 0;
416
417 return returnMesh;
418}
419
420
421//! skips an (unknown) section in the collada document
422void CColladaFileLoader::skipSection(io::IXMLReaderUTF8* reader, bool reportSkipping)
423{
424 #ifndef COLLADA_READER_DEBUG
425 if (reportSkipping) // always report in COLLADA_READER_DEBUG mode
426 #endif
427 os::Printer::log("COLLADA skipping section", core::stringc(reader->getNodeName()).c_str(), ELL_DEBUG);
428
429 // skip if this element is empty anyway.
430 if (reader->isEmptyElement())
431 return;
432
433 // read until we've reached the last element in this section
434 u32 tagCounter = 1;
435
436 while(tagCounter && reader->read())
437 {
438 if (reader->getNodeType() == io::EXN_ELEMENT &&
439 !reader->isEmptyElement())
440 {
441 #ifdef COLLADA_READER_DEBUG
442 if (reportSkipping)
443 os::Printer::log("Skipping COLLADA unknown element", core::stringc(reader->getNodeName()).c_str(), ELL_DEBUG);
444 #endif
445
446 ++tagCounter;
447 }
448 else
449 if (reader->getNodeType() == io::EXN_ELEMENT_END)
450 --tagCounter;
451 }
452}
453
454
455//! reads the <COLLADA> section and its content
456void CColladaFileLoader::readColladaSection(io::IXMLReaderUTF8* reader)
457{
458 if (reader->isEmptyElement())
459 return;
460
461 // todo: patch level needs to be handled
462 const f32 version = core::fast_atof(core::stringc(reader->getAttributeValue("version")).c_str());
463 Version = core::floor32(version)*10000+core::round32(core::fract(version)*1000.0f);
464 // Version 1.4 can be checked for by if (Version >= 10400)
465
466 while(reader->read())
467 if (reader->getNodeType() == io::EXN_ELEMENT)
468 {
469 if (assetSectionName == reader->getNodeName())
470 readAssetSection(reader);
471 else
472 if (librarySectionName == reader->getNodeName())
473 readLibrarySection(reader);
474 else
475 if (libraryNodesSectionName == reader->getNodeName())
476 readLibrarySection(reader);
477 else
478 if (libraryGeometriesSectionName == reader->getNodeName())
479 readLibrarySection(reader);
480 else
481 if (libraryMaterialsSectionName == reader->getNodeName())
482 readLibrarySection(reader);
483 else
484 if (libraryEffectsSectionName == reader->getNodeName())
485 readLibrarySection(reader);
486 else
487 if (libraryImagesSectionName == reader->getNodeName())
488 readLibrarySection(reader);
489 else
490 if (libraryCamerasSectionName == reader->getNodeName())
491 readLibrarySection(reader);
492 else
493 if (libraryLightsSectionName == reader->getNodeName())
494 readLibrarySection(reader);
495 else
496 if (libraryVisualScenesSectionName == reader->getNodeName())
497 readVisualScene(reader);
498 else
499 if (assetSectionName == reader->getNodeName())
500 readAssetSection(reader);
501 else
502 if (sceneSectionName == reader->getNodeName())
503 readSceneSection(reader);
504 else
505 {
506 os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING);
507 skipSection(reader, true); // unknown section
508 }
509 }
510}
511
512
513//! reads a <library> section and its content
514void CColladaFileLoader::readLibrarySection(io::IXMLReaderUTF8* reader)
515{
516 #ifdef COLLADA_READER_DEBUG
517 os::Printer::log("COLLADA reading library", ELL_DEBUG);
518 #endif
519
520 if (reader->isEmptyElement())
521 return;
522
523 while(reader->read())
524 {
525 if (reader->getNodeType() == io::EXN_ELEMENT)
526 {
527 // animation section tbd
528 if (cameraPrefabName == reader->getNodeName())
529 readCameraPrefab(reader);
530 else
531 // code section tbd
532 // controller section tbd
533 if (geometrySectionName == reader->getNodeName())
534 readGeometry(reader);
535 else
536 if (imageSectionName == reader->getNodeName())
537 readImage(reader);
538 else
539 if (lightPrefabName == reader->getNodeName())
540 readLightPrefab(reader);
541 else
542 if (materialSectionName == reader->getNodeName())
543 readMaterial(reader);
544 else
545 if (nodeSectionName == reader->getNodeName())
546 {
547 CScenePrefab p("");
548
549 readNodeSection(reader, SceneManager->getRootSceneNode(), &p);
550 }
551 else
552 if (effectSectionName == reader->getNodeName())
553 readEffect(reader);
554 else
555 // program section tbd
556 if (textureSectionName == reader->getNodeName())
557 readTexture(reader);
558 else
559 skipSection(reader, true); // unknown section, not all allowed supported yet
560 }
561 else
562 if (reader->getNodeType() == io::EXN_ELEMENT_END)
563 {
564 if (librarySectionName == reader->getNodeName())
565 break; // end reading.
566 if (libraryNodesSectionName == reader->getNodeName())
567 break; // end reading.
568 if (libraryGeometriesSectionName == reader->getNodeName())
569 break; // end reading.
570 if (libraryMaterialsSectionName == reader->getNodeName())
571 break; // end reading.
572 if (libraryEffectsSectionName == reader->getNodeName())
573 break; // end reading.
574 if (libraryImagesSectionName == reader->getNodeName())
575 break; // end reading.
576 if (libraryLightsSectionName == reader->getNodeName())
577 break; // end reading.
578 if (libraryCamerasSectionName == reader->getNodeName())
579 break; // end reading.
580 }
581 }
582}
583
584
585//! reads a <visual_scene> element and stores it as a prefab
586void CColladaFileLoader::readVisualScene(io::IXMLReaderUTF8* reader)
587{
588 CScenePrefab* p = 0;
589 while(reader->read())
590 {
591 if (reader->getNodeType() == io::EXN_ELEMENT)
592 {
593 if (visualSceneSectionName == reader->getNodeName())
594 p = new CScenePrefab(readId(reader));
595 else
596 if (p && nodeSectionName == reader->getNodeName()) // as a child of visual_scene
597 readNodeSection(reader, SceneManager->getRootSceneNode(), p);
598 else
599 if (assetSectionName == reader->getNodeName())
600 readAssetSection(reader);
601 else
602 if (extraNodeName == reader->getNodeName())
603 skipSection(reader, false); // ignore all other sections
604 else
605 {
606 os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING);
607 skipSection(reader, true); // ignore all other sections
608 }
609 }
610 else
611 if (reader->getNodeType() == io::EXN_ELEMENT_END)
612 {
613 if (libraryVisualScenesSectionName == reader->getNodeName())
614 return;
615 else
616 if ((visualSceneSectionName == reader->getNodeName()) && p)
617 {
618 Prefabs.push_back(p);
619 p = 0;
620 }
621 }
622 }
623}
624
625
626//! reads a <scene> section and its content
627void CColladaFileLoader::readSceneSection(io::IXMLReaderUTF8* reader)
628{
629 #ifdef COLLADA_READER_DEBUG
630 os::Printer::log("COLLADA reading scene", ELL_DEBUG);
631 #endif
632
633 if (reader->isEmptyElement())
634 return;
635
636 // read the scene
637
638 core::matrix4 transform; // transformation of this node
639 core::aabbox3df bbox;
640 scene::IDummyTransformationSceneNode* node = 0;
641
642 while(reader->read())
643 {
644 if (reader->getNodeType() == io::EXN_ELEMENT)
645 {
646 if (lookatNodeName == reader->getNodeName())
647 transform *= readLookAtNode(reader);
648 else
649 if (matrixNodeName == reader->getNodeName())
650 transform *= readMatrixNode(reader);
651 else
652 if (perspectiveNodeName == reader->getNodeName())
653 transform *= readPerspectiveNode(reader);
654 else
655 if (rotateNodeName == reader->getNodeName())
656 transform *= readRotateNode(reader);
657 else
658 if (scaleNodeName == reader->getNodeName())
659 transform *= readScaleNode(reader);
660 else
661 if (skewNodeName == reader->getNodeName())
662 transform *= readSkewNode(reader);
663 else
664 if (translateNodeName == reader->getNodeName())
665 transform *= readTranslateNode(reader);
666 else
667 if (bboxNodeName == reader->getNodeName())
668 readBboxNode(reader, bbox);
669 else
670 if (nodeSectionName == reader->getNodeName())
671 {
672 // create dummy node if there is none yet.
673 if (!node)
674 node = SceneManager->addDummyTransformationSceneNode(SceneManager->getRootSceneNode());
675
676 readNodeSection(reader, node);
677 }
678 else
679 if ((instanceSceneName == reader->getNodeName()))
680 readInstanceNode(reader, SceneManager->getRootSceneNode(), 0, 0,instanceSceneName);
681 else
682 if (extraNodeName == reader->getNodeName())
683 skipSection(reader, false);
684 else
685 {
686 os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING);
687 skipSection(reader, true); // ignore all other sections
688 }
689 }
690 else
691 if ((reader->getNodeType() == io::EXN_ELEMENT_END) &&
692 (sceneSectionName == reader->getNodeName()))
693 return;
694 }
695 if (node)
696 node->getRelativeTransformationMatrix() = transform;
697}
698
699
700//! reads a <asset> section and its content
701void CColladaFileLoader::readAssetSection(io::IXMLReaderUTF8* reader)
702{
703 #ifdef COLLADA_READER_DEBUG
704 os::Printer::log("COLLADA reading asset", ELL_DEBUG);
705 #endif
706
707 if (reader->isEmptyElement())
708 return;
709
710 while(reader->read())
711 {
712 if (reader->getNodeType() == io::EXN_ELEMENT)
713 {
714 if (upAxisNodeName == reader->getNodeName())
715 {
716 reader->read();
717 FlipAxis = (core::stringc("Z_UP") == reader->getNodeData());
718 }
719 }
720 else
721 if ((reader->getNodeType() == io::EXN_ELEMENT_END) &&
722 (assetSectionName == reader->getNodeName()))
723 return;
724 }
725}
726
727
728//! reads a <node> section and its content
729void CColladaFileLoader::readNodeSection(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, CScenePrefab* p)
730{
731 if (reader->isEmptyElement())
732 {
733 return;
734 #ifdef COLLADA_READER_DEBUG
735 os::Printer::log("COLLADA reading empty node", ELL_DEBUG);
736 #endif
737 }
738
739 core::stringc name = readId(reader);
740 #ifdef COLLADA_READER_DEBUG
741 os::Printer::log("COLLADA reading node", name, ELL_DEBUG);
742 #endif
743
744 core::matrix4 transform; // transformation of this node
745 core::aabbox3df bbox;
746 scene::ISceneNode* node = 0; // instance
747 CScenePrefab* nodeprefab = 0; // prefab for library_nodes usage
748
749 if (p)
750 {
751 nodeprefab = new CScenePrefab(readId(reader));
752 p->Children.push_back(nodeprefab);
753 Prefabs.push_back(nodeprefab); // in order to delete them later on
754 }
755
756 // read the node
757
758 while(reader->read())
759 {
760 if (reader->getNodeType() == io::EXN_ELEMENT)
761 {
762 if (assetSectionName == reader->getNodeName())
763 readAssetSection(reader);
764 else
765 if (lookatNodeName == reader->getNodeName())
766 transform *= readLookAtNode(reader);
767 else
768 if (matrixNodeName == reader->getNodeName())
769 transform *= readMatrixNode(reader);
770 else
771 if (perspectiveNodeName == reader->getNodeName())
772 transform *= readPerspectiveNode(reader);
773 else
774 if (rotateNodeName == reader->getNodeName())
775 transform *= readRotateNode(reader);
776 else
777 if (scaleNodeName == reader->getNodeName())
778 transform *= readScaleNode(reader);
779 else
780 if (skewNodeName == reader->getNodeName())
781 transform *= readSkewNode(reader);
782 else
783 if (translateNodeName == reader->getNodeName())
784 transform *= readTranslateNode(reader);
785 else
786 if (bboxNodeName == reader->getNodeName())
787 readBboxNode(reader, bbox);
788 else
789 if ((instanceName == reader->getNodeName()) ||
790 (instanceNodeName == reader->getNodeName()) ||
791 (instanceGeometryName == reader->getNodeName()) ||
792 (instanceLightName == reader->getNodeName()))
793 {
794 scene::ISceneNode* newnode = 0;
795 readInstanceNode(reader, parent, &newnode, nodeprefab, reader->getNodeName());
796
797 if (node && newnode)
798 {
799 // move children from dummy to new node
800 ISceneNodeList::ConstIterator it = node->getChildren().begin();
801 for (; it != node->getChildren().end(); it = node->getChildren().begin())
802 (*it)->setParent(newnode);
803
804 // remove previous dummy node
805 node->remove();
806 node = newnode;
807 }
808 }
809 else
810 if (nodeSectionName == reader->getNodeName())
811 {
812 // create dummy node if there is none yet.
813 if (CreateInstances && !node)
814 {
815 scene::IDummyTransformationSceneNode* dummy =
816 SceneManager->addDummyTransformationSceneNode(parent);
817 dummy->getRelativeTransformationMatrix() = transform;
818 node = dummy;
819 }
820 else
821 node = parent;
822
823 // read and add child
824 readNodeSection(reader, node, nodeprefab);
825 }
826 else
827 if (extraNodeName == reader->getNodeName())
828 skipSection(reader, false);
829 else
830 skipSection(reader, true); // ignore all other sections
831
832 } // end if node
833 else
834 if (reader->getNodeType() == io::EXN_ELEMENT_END)
835 {
836 if (nodeSectionName == reader->getNodeName())
837 break;
838 }
839 }
840
841 if (nodeprefab)
842 nodeprefab->Transformation = transform;
843 else
844 if (node)
845 {
846 // set transformation correctly into node.
847 node->setPosition(transform.getTranslation());
848 node->setRotation(transform.getRotationDegrees());
849 node->setScale(transform.getScale());
850 node->updateAbsolutePosition();
851
852 node->setName(name);
853 }
854}
855
856
857//! reads a <lookat> element and its content and creates a matrix from it
858core::matrix4 CColladaFileLoader::readLookAtNode(io::IXMLReaderUTF8* reader)
859{
860 core::matrix4 mat;
861 if (reader->isEmptyElement())
862 return mat;
863
864 #ifdef COLLADA_READER_DEBUG
865 os::Printer::log("COLLADA reading look at node", ELL_DEBUG);
866 #endif
867
868 f32 floats[9];
869 readFloatsInsideElement(reader, floats, 9);
870
871 mat.buildCameraLookAtMatrixLH(
872 core::vector3df(floats[0], floats[1], floats[2]),
873 core::vector3df(floats[3], floats[4], floats[5]),
874 core::vector3df(floats[6], floats[7], floats[8]));
875
876 return mat;
877}
878
879
880//! reads a <skew> element and its content and creates a matrix from it
881core::matrix4 CColladaFileLoader::readSkewNode(io::IXMLReaderUTF8* reader)
882{
883 #ifdef COLLADA_READER_DEBUG
884 os::Printer::log("COLLADA reading skew node", ELL_DEBUG);
885 #endif
886
887 core::matrix4 mat;
888 if (reader->isEmptyElement())
889 return mat;
890
891 f32 floats[7]; // angle rotation-axis translation-axis
892 readFloatsInsideElement(reader, floats, 7);
893
894 // build skew matrix from these 7 floats
895 core::quaternion q;
896 q.fromAngleAxis(floats[0]*core::DEGTORAD, core::vector3df(floats[1], floats[2], floats[3]));
897 mat = q.getMatrix();
898
899 if (floats[4]==1.f) // along x-axis
900 {
901 mat[4]=0.f;
902 mat[6]=0.f;
903 mat[8]=0.f;
904 mat[9]=0.f;
905 }
906 else
907 if (floats[5]==1.f) // along y-axis
908 {
909 mat[1]=0.f;
910 mat[2]=0.f;
911 mat[8]=0.f;
912 mat[9]=0.f;
913 }
914 else
915 if (floats[6]==1.f) // along z-axis
916 {
917 mat[1]=0.f;
918 mat[2]=0.f;
919 mat[4]=0.f;
920 mat[6]=0.f;
921 }
922
923 return mat;
924}
925
926
927//! reads a <boundingbox> element and its content and stores it in bbox
928void CColladaFileLoader::readBboxNode(io::IXMLReaderUTF8* reader,
929 core::aabbox3df& bbox)
930{
931 #ifdef COLLADA_READER_DEBUG
932 os::Printer::log("COLLADA reading boundingbox node", ELL_DEBUG);
933 #endif
934
935 bbox.reset(core::aabbox3df());
936
937 if (reader->isEmptyElement())
938 return;
939
940 f32 floats[3];
941
942 while(reader->read())
943 {
944 if (reader->getNodeType() == io::EXN_ELEMENT)
945 {
946 if (minNodeName == reader->getNodeName())
947 {
948 readFloatsInsideElement(reader, floats, 3);
949 bbox.MinEdge.set(floats[0], floats[1], floats[2]);
950 }
951 else
952 if (maxNodeName == reader->getNodeName())
953 {
954 readFloatsInsideElement(reader, floats, 3);
955 bbox.MaxEdge.set(floats[0], floats[1], floats[2]);
956 }
957 else
958 skipSection(reader, true); // ignore all other sections
959 }
960 else
961 if (reader->getNodeType() == io::EXN_ELEMENT_END)
962 {
963 if (bboxNodeName == reader->getNodeName())
964 break;
965 }
966 }
967}
968
969
970//! reads a <matrix> element and its content and creates a matrix from it
971core::matrix4 CColladaFileLoader::readMatrixNode(io::IXMLReaderUTF8* reader)
972{
973 #ifdef COLLADA_READER_DEBUG
974 os::Printer::log("COLLADA reading matrix node", ELL_DEBUG);
975 #endif
976
977 core::matrix4 mat;
978 if (reader->isEmptyElement())
979 return mat;
980
981 readFloatsInsideElement(reader, mat.pointer(), 16);
982 // put translation into the correct place
983 if (FlipAxis)
984 {
985 core::matrix4 mat2(mat, core::matrix4::EM4CONST_TRANSPOSED);
986 mat2[1]=mat[8];
987 mat2[2]=mat[4];
988 mat2[4]=mat[2];
989 mat2[5]=mat[10];
990 mat2[6]=mat[6];
991 mat2[8]=mat[1];
992 mat2[9]=mat[9];
993 mat2[10]=mat[5];
994 mat2[12]=mat[3];
995 mat2[13]=mat[11];
996 mat2[14]=mat[7];
997 return mat2;
998 }
999 else
1000 return core::matrix4(mat, core::matrix4::EM4CONST_TRANSPOSED);
1001}
1002
1003
1004//! reads a <perspective> element and its content and creates a matrix from it
1005core::matrix4 CColladaFileLoader::readPerspectiveNode(io::IXMLReaderUTF8* reader)
1006{
1007 #ifdef COLLADA_READER_DEBUG
1008 os::Printer::log("COLLADA reading perspective node", ELL_DEBUG);
1009 #endif
1010
1011 core::matrix4 mat;
1012 if (reader->isEmptyElement())
1013 return mat;
1014
1015 f32 floats[1];
1016 readFloatsInsideElement(reader, floats, 1);
1017
1018 // TODO: build perspecitve matrix from this float
1019
1020 os::Printer::log("COLLADA loader warning: <perspective> not implemented yet.", ELL_WARNING);
1021
1022 return mat;
1023}
1024
1025
1026//! reads a <rotate> element and its content and creates a matrix from it
1027core::matrix4 CColladaFileLoader::readRotateNode(io::IXMLReaderUTF8* reader)
1028{
1029 #ifdef COLLADA_READER_DEBUG
1030 os::Printer::log("COLLADA reading rotate node", ELL_DEBUG);
1031 #endif
1032
1033 core::matrix4 mat;
1034 if (reader->isEmptyElement())
1035 return mat;
1036
1037 f32 floats[4];
1038 readFloatsInsideElement(reader, floats, 4);
1039
1040 if (!core::iszero(floats[3]))
1041 {
1042 core::quaternion q;
1043 if (FlipAxis)
1044 q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[2], floats[1]));
1045 else
1046 q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[1], floats[2]));
1047 return q.getMatrix();
1048 }
1049 else
1050 return core::IdentityMatrix;
1051}
1052
1053
1054//! reads a <scale> element and its content and creates a matrix from it
1055core::matrix4 CColladaFileLoader::readScaleNode(io::IXMLReaderUTF8* reader)
1056{
1057 #ifdef COLLADA_READER_DEBUG
1058 os::Printer::log("COLLADA reading scale node", ELL_DEBUG);
1059 #endif
1060
1061 core::matrix4 mat;
1062 if (reader->isEmptyElement())
1063 return mat;
1064
1065 f32 floats[3];
1066 readFloatsInsideElement(reader, floats, 3);
1067
1068 if (FlipAxis)
1069 mat.setScale(core::vector3df(floats[0], floats[2], floats[1]));
1070 else
1071 mat.setScale(core::vector3df(floats[0], floats[1], floats[2]));
1072
1073 return mat;
1074}
1075
1076
1077//! reads a <translate> element and its content and creates a matrix from it
1078core::matrix4 CColladaFileLoader::readTranslateNode(io::IXMLReaderUTF8* reader)
1079{
1080 #ifdef COLLADA_READER_DEBUG
1081 os::Printer::log("COLLADA reading translate node", ELL_DEBUG);
1082 #endif
1083
1084 core::matrix4 mat;
1085 if (reader->isEmptyElement())
1086 return mat;
1087
1088 f32 floats[3];
1089 readFloatsInsideElement(reader, floats, 3);
1090
1091 if (FlipAxis)
1092 mat.setTranslation(core::vector3df(floats[0], floats[2], floats[1]));
1093 else
1094 mat.setTranslation(core::vector3df(floats[0], floats[1], floats[2]));
1095
1096 return mat;
1097}
1098
1099
1100//! reads any kind of <instance*> node
1101void CColladaFileLoader::readInstanceNode(io::IXMLReaderUTF8* reader,
1102 scene::ISceneNode* parent, scene::ISceneNode** outNode,
1103 CScenePrefab* p, const core::stringc& type)
1104{
1105 // find prefab of the specified id
1106 core::stringc url = reader->getAttributeValue("url");
1107 uriToId(url);
1108
1109 #ifdef COLLADA_READER_DEBUG
1110 os::Printer::log("COLLADA reading instance", url, ELL_DEBUG);
1111 #endif
1112
1113 if (!reader->isEmptyElement())
1114 {
1115 while(reader->read())
1116 {
1117 if (reader->getNodeType() == io::EXN_ELEMENT)
1118 {
1119 if (bindMaterialName == reader->getNodeName())
1120 readBindMaterialSection(reader,url);
1121 else
1122 if (extraNodeName == reader->getNodeName())
1123 skipSection(reader, false);
1124 }
1125 else
1126 if (reader->getNodeType() == io::EXN_ELEMENT_END)
1127 break;
1128 }
1129 }
1130 instantiateNode(parent, outNode, p, url, type);
1131}
1132
1133
1134void CColladaFileLoader::instantiateNode(scene::ISceneNode* parent,
1135 scene::ISceneNode** outNode, CScenePrefab* p, const core::stringc& url,
1136 const core::stringc& type)
1137{
1138 #ifdef COLLADA_READER_DEBUG
1139 os::Printer::log("COLLADA instantiate node", ELL_DEBUG);
1140 #endif
1141
1142 for (u32 i=0; i<Prefabs.size(); ++i)
1143 {
1144 if (url == "" || url == Prefabs[i]->getId())
1145 {
1146 if (p)
1147 p->Children.push_back(Prefabs[i]);
1148 else
1149 if (CreateInstances)
1150 {
1151 scene::ISceneNode * newNode
1152 = Prefabs[i]->addInstance(parent, SceneManager);
1153 if (outNode)
1154 {
1155 *outNode = newNode;
1156 if (*outNode)
1157 (*outNode)->setName(url);
1158 }
1159 }
1160 return;
1161 }
1162 }
1163 if (p)
1164 {
1165 if (instanceGeometryName==type)
1166 {
1167 Prefabs.push_back(new CGeometryPrefab(url));
1168 p->Children.push_back(Prefabs.getLast());
1169 }
1170 }
1171}
1172
1173
1174//! reads a <camera> element and stores it as prefab
1175void CColladaFileLoader::readCameraPrefab(io::IXMLReaderUTF8* reader)
1176{
1177 #ifdef COLLADA_READER_DEBUG
1178 os::Printer::log("COLLADA reading camera prefab", ELL_DEBUG);
1179 #endif
1180
1181 CCameraPrefab* prefab = new CCameraPrefab(readId(reader));
1182
1183 if (!reader->isEmptyElement())
1184 {
1185 // read techniques optics and imager (the latter is completely ignored, though)
1186 readColladaParameters(reader, cameraPrefabName);
1187
1188 SColladaParam* p;
1189
1190 // XFOV not yet supported
1191 p = getColladaParameter(ECPN_YFOV);
1192 if (p && p->Type == ECPT_FLOAT)
1193 prefab->YFov = p->Floats[0];
1194
1195 p = getColladaParameter(ECPN_ZNEAR);
1196 if (p && p->Type == ECPT_FLOAT)
1197 prefab->ZNear = p->Floats[0];
1198
1199 p = getColladaParameter(ECPN_ZFAR);
1200 if (p && p->Type == ECPT_FLOAT)
1201 prefab->ZFar = p->Floats[0];
1202 // orthographic camera uses LEFT, RIGHT, TOP, and BOTTOM
1203 }
1204
1205 Prefabs.push_back(prefab);
1206}
1207
1208
1209//! reads a <image> element and stores it in the image section
1210void CColladaFileLoader::readImage(io::IXMLReaderUTF8* reader)
1211{
1212 // add image to list of loaded images.
1213 Images.push_back(SColladaImage());
1214 SColladaImage& image=Images.getLast();
1215
1216 image.Id = readId(reader);
1217 #ifdef COLLADA_READER_DEBUG
1218 os::Printer::log("COLLADA reading image", core::stringc(image.Id), ELL_DEBUG);
1219 #endif
1220 image.Dimension.Height = (u32)reader->getAttributeValueAsInt("height");
1221 image.Dimension.Width = (u32)reader->getAttributeValueAsInt("width");
1222
1223 if (Version >= 10400) // start with 1.4
1224 {
1225 while(reader->read())
1226 {
1227 if (reader->getNodeType() == io::EXN_ELEMENT)
1228 {
1229 if (assetSectionName == reader->getNodeName())
1230 skipSection(reader, false);
1231 else
1232 if (initFromName == reader->getNodeName())
1233 {
1234 reader->read();
1235 image.Source = reader->getNodeData();
1236 image.Source.trim();
1237 image.SourceIsFilename=true;
1238 }
1239 else
1240 if (dataName == reader->getNodeName())
1241 {
1242 reader->read();
1243 image.Source = reader->getNodeData();
1244 image.Source.trim();
1245 image.SourceIsFilename=false;
1246 }
1247 else
1248 if (extraNodeName == reader->getNodeName())
1249 skipSection(reader, false);
1250 }
1251 else
1252 if (reader->getNodeType() == io::EXN_ELEMENT_END)
1253 {
1254 if (initFromName == reader->getNodeName())
1255 return;
1256 }
1257 }
1258 }
1259 else
1260 {
1261 image.Source = reader->getAttributeValue("source");
1262 image.Source.trim();
1263 image.SourceIsFilename=false;
1264 }
1265}
1266
1267
1268//! reads a <texture> element and stores it in the texture section
1269void CColladaFileLoader::readTexture(io::IXMLReaderUTF8* reader)
1270{
1271 // add texture to list of loaded textures.
1272 Textures.push_back(SColladaTexture());
1273 SColladaTexture& texture=Textures.getLast();
1274
1275 texture.Id = readId(reader);
1276 #ifdef COLLADA_READER_DEBUG
1277 os::Printer::log("COLLADA reading texture", core::stringc(texture.Id), ELL_DEBUG);
1278 #endif
1279
1280 if (!reader->isEmptyElement())
1281 {
1282 readColladaInputs(reader, textureSectionName);
1283 SColladaInput* input = getColladaInput(ECIS_IMAGE);
1284 if (input)
1285 {
1286 const core::stringc imageName = input->Source;
1287 texture.Texture = getTextureFromImage(imageName, NULL);
1288 }
1289 }
1290}
1291
1292
1293//! reads a <material> element and stores it in the material section
1294void CColladaFileLoader::readMaterial(io::IXMLReaderUTF8* reader)
1295{
1296 // add material to list of loaded materials.
1297 Materials.push_back(SColladaMaterial());
1298
1299 SColladaMaterial& material = Materials.getLast();
1300 material.Id = readId(reader);
1301 #ifdef COLLADA_READER_DEBUG
1302 os::Printer::log("COLLADA reading material", core::stringc(material.Id), ELL_DEBUG);
1303 #endif
1304
1305 if (Version >= 10400)
1306 {
1307 while(reader->read())
1308 {
1309 if (reader->getNodeType() == io::EXN_ELEMENT &&
1310 instanceEffectName == reader->getNodeName())
1311 {
1312 material.InstanceEffectId = reader->getAttributeValue("url");
1313 uriToId(material.InstanceEffectId);
1314 }
1315 else
1316 if (reader->getNodeType() == io::EXN_ELEMENT_END &&
1317 materialSectionName == reader->getNodeName())
1318 {
1319 break;
1320 }
1321 } // end while reader->read();
1322 }
1323 else
1324 {
1325 if (!reader->isEmptyElement())
1326 {
1327 readColladaInputs(reader, materialSectionName);
1328 SColladaInput* input = getColladaInput(ECIS_TEXTURE);
1329 if (input)
1330 {
1331 core::stringc textureName = input->Source;
1332 uriToId(textureName);
1333 for (u32 i=0; i<Textures.size(); ++i)
1334 if (textureName == Textures[i].Id)
1335 {
1336 material.Mat.setTexture(0, Textures[i].Texture);
1337 break;
1338 }
1339 }
1340
1341 //does not work because the wrong start node is chosen due to reading of inputs before
1342#if 0
1343 readColladaParameters(reader, materialSectionName);
1344
1345 SColladaParam* p;
1346
1347 p = getColladaParameter(ECPN_AMBIENT);
1348 if (p && p->Type == ECPT_FLOAT3)
1349 material.Mat.AmbientColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor();
1350 p = getColladaParameter(ECPN_DIFFUSE);
1351 if (p && p->Type == ECPT_FLOAT3)
1352 material.Mat.DiffuseColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor();
1353 p = getColladaParameter(ECPN_SPECULAR);
1354 if (p && p->Type == ECPT_FLOAT3)
1355 material.Mat.DiffuseColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor();
1356 p = getColladaParameter(ECPN_SHININESS);
1357 if (p && p->Type == ECPT_FLOAT)
1358 material.Mat.Shininess = p->Floats[0];
1359#endif
1360 }
1361 }
1362}
1363
1364void CColladaFileLoader::readEffect(io::IXMLReaderUTF8* reader, SColladaEffect * effect)
1365{
1366 static const core::stringc constantNode("constant");
1367 static const core::stringc lambertNode("lambert");
1368 static const core::stringc phongNode("phong");
1369 static const core::stringc blinnNode("blinn");
1370 static const core::stringc emissionNode("emission");
1371 static const core::stringc ambientNode("ambient");
1372 static const core::stringc diffuseNode("diffuse");
1373 static const core::stringc specularNode("specular");
1374 static const core::stringc shininessNode("shininess");
1375 static const core::stringc reflectiveNode("reflective");
1376 static const core::stringc reflectivityNode("reflectivity");
1377 static const core::stringc transparentNode("transparent");
1378 static const core::stringc transparencyNode("transparency");
1379 static const core::stringc indexOfRefractionNode("index_of_refraction");
1380
1381 if (!effect)
1382 {
1383 Effects.push_back(SColladaEffect());
1384 effect = &Effects.getLast();
1385 effect->Parameters = new io::CAttributes();
1386 effect->Id = readId(reader);
1387 effect->Transparency = 1.f;
1388 effect->Mat.Lighting=true;
1389 effect->Mat.NormalizeNormals=true;
1390 #ifdef COLLADA_READER_DEBUG
1391 os::Printer::log("COLLADA reading effect", core::stringc(effect->Id), ELL_DEBUG);
1392 #endif
1393 }
1394 while(reader->read())
1395 {
1396 if (reader->getNodeType() == io::EXN_ELEMENT)
1397 {
1398 // first come the tags we descend, but ignore the top-levels
1399 if (!reader->isEmptyElement() && ((profileCOMMONSectionName == reader->getNodeName()) ||
1400 (techniqueNodeName == reader->getNodeName())))
1401 readEffect(reader,effect);
1402 else
1403 if (newParamName == reader->getNodeName())
1404 readParameter(reader, effect->Parameters);
1405 else
1406 // these are the actual materials inside technique
1407 if (constantNode == reader->getNodeName() ||
1408 lambertNode == reader->getNodeName() ||
1409 phongNode == reader->getNodeName() ||
1410 blinnNode == reader->getNodeName())
1411 {
1412 #ifdef COLLADA_READER_DEBUG
1413 os::Printer::log("COLLADA reading effect part", reader->getNodeName(), ELL_DEBUG);
1414 #endif
1415 effect->Mat.setFlag(irr::video::EMF_GOURAUD_SHADING,
1416 phongNode == reader->getNodeName() ||
1417 blinnNode == reader->getNodeName());
1418 while(reader->read())
1419 {
1420 if (reader->getNodeType() == io::EXN_ELEMENT)
1421 {
1422 const core::stringc node = reader->getNodeName();
1423 if (emissionNode == node || ambientNode == node ||
1424 diffuseNode == node || specularNode == node ||
1425 reflectiveNode == node || transparentNode == node )
1426 {
1427 // color or texture types
1428 while(reader->read())
1429 {
1430 if (reader->getNodeType() == io::EXN_ELEMENT &&
1431 colorNodeName == reader->getNodeName())
1432 {
1433 const video::SColorf colorf = readColorNode(reader);
1434 const video::SColor color = colorf.toSColor();
1435 if (emissionNode == node)
1436 effect->Mat.EmissiveColor = color;
1437 else
1438 if (ambientNode == node)
1439 effect->Mat.AmbientColor = color;
1440 else
1441 if (diffuseNode == node)
1442 effect->Mat.DiffuseColor = color;
1443 else
1444 if (specularNode == node)
1445 effect->Mat.SpecularColor = color;
1446 else
1447 if (transparentNode == node)
1448 effect->Transparency = colorf.getAlpha();
1449 }
1450 else
1451 if (reader->getNodeType() == io::EXN_ELEMENT &&
1452 textureNodeName == reader->getNodeName())
1453 {
1454 effect->Textures.push_back(reader->getAttributeValue("texture"));
1455 break;
1456 }
1457 else
1458 if (reader->getNodeType() == io::EXN_ELEMENT)
1459 skipSection(reader, false);
1460 else
1461 if (reader->getNodeType() == io::EXN_ELEMENT_END &&
1462 node == reader->getNodeName())
1463 break;
1464 }
1465 }
1466 else
1467 if (shininessNode == node || reflectivityNode == node ||
1468 transparencyNode == node || indexOfRefractionNode == node )
1469 {
1470 // float or param types
1471 while(reader->read())
1472 {
1473 if (reader->getNodeType() == io::EXN_ELEMENT &&
1474 floatNodeName == reader->getNodeName())
1475 {
1476 f32 f = readFloatNode(reader);
1477 if (shininessNode == node)
1478 effect->Mat.Shininess = f;
1479 else
1480 if (transparencyNode == node)
1481 effect->Transparency *= f;
1482 }
1483 else
1484 if (reader->getNodeType() == io::EXN_ELEMENT)
1485 skipSection(reader, false);
1486 else
1487 if (reader->getNodeType() == io::EXN_ELEMENT_END &&
1488 node == reader->getNodeName())
1489 break;
1490 }
1491 }
1492 else
1493 skipSection(reader, true); // ignore all other nodes
1494 }
1495 else
1496 if (reader->getNodeType() == io::EXN_ELEMENT_END && (
1497 constantNode == reader->getNodeName() ||
1498 lambertNode == reader->getNodeName() ||
1499 phongNode == reader->getNodeName() ||
1500 blinnNode == reader->getNodeName()
1501 ))
1502 break;
1503 }
1504 }
1505 else
1506 if (!reader->isEmptyElement() && (extraNodeName == reader->getNodeName()))
1507 readEffect(reader,effect);
1508 else
1509 if (doubleSidedNodeName == reader->getNodeName())
1510 {
1511 // read the GoogleEarth extra flag for double sided polys
1512 s32 doubleSided = 0;
1513 readIntsInsideElement(reader,&doubleSided,1);
1514 if (doubleSided)
1515 {
1516 #ifdef COLLADA_READER_DEBUG
1517 os::Printer::log("Setting double sided flag for effect.", ELL_DEBUG);
1518 #endif
1519
1520 effect->Mat.setFlag(irr::video::EMF_BACK_FACE_CULLING,false);
1521 }
1522 }
1523 else
1524 skipSection(reader, true); // ignore all other sections
1525 }
1526 else
1527 if (reader->getNodeType() == io::EXN_ELEMENT_END)
1528 {
1529 if (effectSectionName == reader->getNodeName())
1530 break;
1531 else
1532 if (profileCOMMONSectionName == reader->getNodeName())
1533 break;
1534 else
1535 if (techniqueNodeName == reader->getNodeName())
1536 break;
1537 else
1538 if (extraNodeName == reader->getNodeName())
1539 break;
1540 }
1541 }
1542
1543 if (effect->Mat.AmbientColor == video::SColor(0) &&
1544 effect->Mat.DiffuseColor != video::SColor(0))
1545 effect->Mat.AmbientColor = effect->Mat.DiffuseColor;
1546 if (effect->Mat.DiffuseColor == video::SColor(0) &&
1547 effect->Mat.AmbientColor != video::SColor(0))
1548 effect->Mat.DiffuseColor = effect->Mat.AmbientColor;
1549 if ((effect->Transparency != 0.0f) && (effect->Transparency != 1.0f))
1550 {
1551 effect->Mat.MaterialType = irr::video::EMT_TRANSPARENT_VERTEX_ALPHA;
1552 effect->Mat.ZWriteEnable = false;
1553 }
1554
1555 video::E_TEXTURE_CLAMP twu = video::ETC_REPEAT;
1556 s32 idx = effect->Parameters->findAttribute(wrapsName.c_str());
1557 if ( idx >= 0 )
1558 twu = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx));
1559 video::E_TEXTURE_CLAMP twv = video::ETC_REPEAT;
1560 idx = effect->Parameters->findAttribute(wraptName.c_str());
1561 if ( idx >= 0 )
1562 twv = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx));
1563
1564 for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)
1565 {
1566 effect->Mat.TextureLayer[i].TextureWrapU = twu;
1567 effect->Mat.TextureLayer[i].TextureWrapV = twv;
1568 }
1569
1570 effect->Mat.setFlag(video::EMF_BILINEAR_FILTER, effect->Parameters->getAttributeAsBool("bilinear"));
1571 effect->Mat.setFlag(video::EMF_TRILINEAR_FILTER, effect->Parameters->getAttributeAsBool("trilinear"));
1572 effect->Mat.setFlag(video::EMF_ANISOTROPIC_FILTER, effect->Parameters->getAttributeAsBool("anisotropic"));
1573}
1574
1575
1576const SColladaMaterial* CColladaFileLoader::findMaterial(const core::stringc& materialName)
1577{
1578 #ifdef COLLADA_READER_DEBUG
1579 os::Printer::log("COLLADA find material", materialName, ELL_DEBUG);
1580 #endif
1581
1582 // do a quick lookup in the materials
1583 SColladaMaterial matToFind;
1584 matToFind.Id = materialName;
1585 s32 mat = Materials.binary_search(matToFind);
1586 if (mat == -1)
1587 return 0;
1588 // instantiate the material effect if needed
1589 if (Materials[mat].InstanceEffectId.size() != 0)
1590 {
1591 // do a quick lookup in the effects
1592 SColladaEffect effectToFind;
1593 effectToFind.Id = Materials[mat].InstanceEffectId;
1594 s32 effect = Effects.binary_search(effectToFind);
1595 if (effect != -1)
1596 {
1597 // found the effect, instantiate by copying into the material
1598 Materials[mat].Mat = Effects[effect].Mat;
1599 if (Effects[effect].Textures.size())
1600 Materials[mat].Mat.setTexture(0, getTextureFromImage(Effects[effect].Textures[0], &(Effects[effect])));
1601 Materials[mat].Transparency = Effects[effect].Transparency;
1602 // and indicate the material is instantiated by removing the effect ref
1603 Materials[mat].InstanceEffectId = "";
1604 }
1605 else
1606 return 0;
1607 }
1608 return &Materials[mat];
1609}
1610
1611
1612void CColladaFileLoader::readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id)
1613{
1614 #ifdef COLLADA_READER_DEBUG
1615 os::Printer::log("COLLADA reading bind material", ELL_DEBUG);
1616 #endif
1617
1618 while(reader->read())
1619 {
1620 if (reader->getNodeType() == io::EXN_ELEMENT)
1621 {
1622 if (instanceMaterialName == reader->getNodeName())
1623 {
1624 // the symbol to retarget, and the target material
1625 core::stringc meshbufferReference = reader->getAttributeValue("symbol");
1626 if (meshbufferReference.size()==0)
1627 continue;
1628 core::stringc target = reader->getAttributeValue("target");
1629 uriToId(target);
1630 if (target.size()==0)
1631 continue;
1632 const SColladaMaterial * material = findMaterial(target);
1633 if (!material)
1634 continue;
1635 // bind any pending materials for this node
1636 meshbufferReference = id+"/"+meshbufferReference;
1637#ifdef COLLADA_READER_DEBUG
1638 os::Printer::log((core::stringc("Material binding: ")+meshbufferReference+" "+target).c_str(), ELL_DEBUG);
1639#endif
1640 if (MaterialsToBind.find(meshbufferReference))
1641 {
1642 core::array<irr::scene::IMeshBuffer*> & toBind
1643 = MeshesToBind[MaterialsToBind[meshbufferReference]];
1644#ifdef COLLADA_READER_DEBUG
1645 os::Printer::log("Material binding now ",material->Id.c_str(), ELL_DEBUG);
1646 os::Printer::log("#meshbuffers",core::stringc(toBind.size()).c_str(), ELL_DEBUG);
1647#endif
1648 SMesh tmpmesh;
1649 for (u32 i = 0; i < toBind.size(); ++i)
1650 {
1651 toBind[i]->getMaterial() = material->Mat;
1652 tmpmesh.addMeshBuffer(toBind[i]);
1653
1654 if ((material->Transparency!=0.0f) && (material->Transparency!=1.0f))
1655 {
1656 toBind[i]->getMaterial().MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
1657 toBind[i]->getMaterial().ZWriteEnable = false;
1658 }
1659 }
1660 SceneManager->getMeshManipulator()->setVertexColors(&tmpmesh,material->Mat.DiffuseColor);
1661 if ((material->Transparency!=0.0f) && (material->Transparency!=1.0f))
1662 {
1663 #ifdef COLLADA_READER_DEBUG
1664 os::Printer::log("COLLADA found transparency material", core::stringc(material->Transparency).c_str(), ELL_DEBUG);
1665 #endif
1666 SceneManager->getMeshManipulator()->setVertexColorAlpha(&tmpmesh, core::floor32(material->Transparency*255.0f));
1667 }
1668 }
1669 }
1670 }
1671 else
1672 if (reader->getNodeType() == io::EXN_ELEMENT_END &&
1673 bindMaterialName == reader->getNodeName())
1674 break;
1675 }
1676}
1677
1678
1679//! reads a <geometry> element and stores it as mesh if possible
1680void CColladaFileLoader::readGeometry(io::IXMLReaderUTF8* reader)
1681{
1682 core::stringc id = readId(reader);
1683 #ifdef COLLADA_READER_DEBUG
1684 os::Printer::log("COLLADA reading geometry", id, ELL_DEBUG);
1685 #endif
1686
1687 SAnimatedMesh* amesh = new SAnimatedMesh();
1688 scene::SMesh* mesh = new SMesh();
1689 amesh->addMesh(mesh);
1690 core::array<SSource> sources;
1691 bool okToReadArray = false;
1692
1693 // handles geometry node and the mesh children in this loop
1694 // read sources with arrays and accessor for each mesh
1695 if (!reader->isEmptyElement())
1696 while(reader->read())
1697 {
1698 if (reader->getNodeType() == io::EXN_ELEMENT)
1699 {
1700 const char* nodeName = reader->getNodeName();
1701 if (meshSectionName == nodeName)
1702 {
1703 // inside a mesh section. Don't have to do anything here.
1704 }
1705 else
1706 if (sourceSectionName == nodeName)
1707 {
1708 // create a new source
1709 sources.push_back(SSource());
1710 sources.getLast().Id = readId(reader);
1711
1712 #ifdef COLLADA_READER_DEBUG
1713 os::Printer::log("Reading source", sources.getLast().Id.c_str(), ELL_DEBUG);
1714 #endif
1715 }
1716 else
1717 if (arraySectionName == nodeName || floatArraySectionName == nodeName || intArraySectionName == nodeName)
1718 {
1719 // create a new array and read it.
1720 if (!sources.empty())
1721 {
1722 sources.getLast().Array.Name = readId(reader);
1723
1724 int count = reader->getAttributeValueAsInt("count");
1725 sources.getLast().Array.Data.set_used(count); // pre allocate
1726
1727 // check if type of array is ok
1728 const char* type = reader->getAttributeValue("type");
1729 okToReadArray = (type && (!strcmp("float", type) || !strcmp("int", type))) || floatArraySectionName == nodeName || intArraySectionName == nodeName;
1730
1731 #ifdef COLLADA_READER_DEBUG
1732 os::Printer::log("Read array", sources.getLast().Array.Name.c_str(), ELL_DEBUG);
1733 #endif
1734 }
1735 #ifdef COLLADA_READER_DEBUG
1736 else
1737 os::Printer::log("Warning, array outside source found",
1738 readId(reader).c_str(), ELL_DEBUG);
1739 #endif
1740
1741 }
1742 else
1743 if (accessorSectionName == nodeName) // child of source (below a technique tag)
1744 {
1745 #ifdef COLLADA_READER_DEBUG
1746 os::Printer::log("Reading accessor", ELL_DEBUG);
1747 #endif
1748 SAccessor accessor;
1749 accessor.Count = reader->getAttributeValueAsInt("count");
1750 accessor.Offset = reader->getAttributeValueAsInt("offset");
1751 accessor.Stride = reader->getAttributeValueAsInt("stride");
1752 if (accessor.Stride == 0)
1753 accessor.Stride = 1;
1754
1755 // the accessor contains some information on how to access (boi!) the array,
1756 // the info is stored in collada style parameters, so just read them.
1757 readColladaParameters(reader, accessorSectionName);
1758 if (!sources.empty())
1759 {
1760 sources.getLast().Accessors.push_back(accessor);
1761 sources.getLast().Accessors.getLast().Parameters = ColladaParameters;
1762 }
1763 }
1764 else
1765 if (verticesSectionName == nodeName)
1766 {
1767 #ifdef COLLADA_READER_DEBUG
1768 os::Printer::log("Reading vertices", ELL_DEBUG);
1769 #endif
1770 // read vertex input position source
1771 readColladaInputs(reader, verticesSectionName);
1772 }
1773 else
1774 // lines and linestrips missing
1775 if (polygonsSectionName == nodeName ||
1776 polylistSectionName == nodeName ||
1777 trianglesSectionName == nodeName)
1778 {
1779 // read polygons section
1780 readPolygonSection(reader, sources, mesh, id);
1781 }
1782 else
1783 // trifans, and tristrips missing
1784 if (doubleSidedNodeName == reader->getNodeName())
1785 {
1786 // read the extra flag for double sided polys
1787 s32 doubleSided = 0;
1788 readIntsInsideElement(reader,&doubleSided,1);
1789 if (doubleSided)
1790 {
1791 #ifdef COLLADA_READER_DEBUG
1792 os::Printer::log("Setting double sided flag for mesh.", ELL_DEBUG);
1793 #endif
1794 amesh->setMaterialFlag(irr::video::EMF_BACK_FACE_CULLING,false);
1795 }
1796 }
1797 else
1798 // techniqueCommon or 'technique profile=common' must not be skipped
1799 if ((techniqueCommonSectionName != nodeName) // Collada 1.2/1.3
1800 && (techniqueNodeName != nodeName) // Collada 1.4+
1801 && (extraNodeName != nodeName))
1802 {
1803 os::Printer::log("COLLADA loader warning: Wrong tag usage found in geometry", reader->getNodeName(), ELL_WARNING);
1804 skipSection(reader, true); // ignore all other sections
1805 }
1806 } // end if node type is element
1807 else
1808 if (reader->getNodeType() == io::EXN_TEXT)
1809 {
1810 // read array data
1811 if (okToReadArray && !sources.empty())
1812 {
1813 core::array<f32>& a = sources.getLast().Array.Data;
1814 core::stringc data = reader->getNodeData();
1815 data.trim();
1816 const c8* p = &data[0];
1817
1818 for (u32 i=0; i<a.size(); ++i)
1819 {
1820 findNextNoneWhiteSpace(&p);
1821 if (*p)
1822 a[i] = readFloat(&p);
1823 else
1824 a[i] = 0.0f;
1825 }
1826 } // end reading array
1827
1828 okToReadArray = false;
1829
1830 } // end if node type is text
1831 else
1832 if (reader->getNodeType() == io::EXN_ELEMENT_END)
1833 {
1834 if (geometrySectionName == reader->getNodeName())
1835 {
1836 // end of geometry section reached, cancel out
1837 break;
1838 }
1839 }
1840 } // end while reader->read();
1841
1842 // add mesh as geometry
1843
1844 mesh->recalculateBoundingBox();
1845 amesh->recalculateBoundingBox();
1846
1847 // create virtual file name
1848 io::path filename = CurrentlyLoadingMesh;
1849 filename += '#';
1850 filename += id;
1851
1852 // add to scene manager
1853 if (LoadedMeshCount)
1854 {
1855 SceneManager->getMeshCache()->addMesh(filename.c_str(), amesh);
1856 os::Printer::log("Added COLLADA mesh", filename.c_str(), ELL_DEBUG);
1857 }
1858 else
1859 {
1860 FirstLoadedMeshName = filename;
1861 FirstLoadedMesh = amesh;
1862 FirstLoadedMesh->grab();
1863 }
1864
1865 ++LoadedMeshCount;
1866 mesh->drop();
1867 amesh->drop();
1868
1869 // create geometry prefab
1870 u32 i;
1871 for (i=0; i<Prefabs.size(); ++i)
1872 {
1873 if (Prefabs[i]->getId()==id)
1874 {
1875 ((CGeometryPrefab*)Prefabs[i])->Mesh=mesh;
1876 break;
1877 }
1878 }
1879 if (i==Prefabs.size())
1880 {
1881 CGeometryPrefab* prefab = new CGeometryPrefab(id);
1882 prefab->Mesh = mesh;
1883 Prefabs.push_back(prefab);
1884 }
1885
1886 // store as dummy mesh if no instances will be created
1887 if (!CreateInstances && !DummyMesh)
1888 {
1889 DummyMesh = amesh;
1890 DummyMesh->grab();
1891 }
1892}
1893
1894
1895struct SPolygon
1896{
1897 core::array<s32> Indices;
1898};
1899
1900//! reads a polygons section and creates a mesh from it
1901void CColladaFileLoader::readPolygonSection(io::IXMLReaderUTF8* reader,
1902 core::array<SSource>& sources, scene::SMesh* mesh,
1903 const core::stringc& geometryId)
1904{
1905 #ifdef COLLADA_READER_DEBUG
1906 os::Printer::log("COLLADA reading polygon section", ELL_DEBUG);
1907 #endif
1908
1909 core::stringc materialName = reader->getAttributeValue("material");
1910
1911 core::stringc polygonType = reader->getNodeName();
1912 const int polygonCount = reader->getAttributeValueAsInt("count"); // Not useful because it only determines the number of primitives, which have arbitrary vertices in case of polygon
1913 core::array<SPolygon> polygons;
1914 if (polygonType == polygonsSectionName)
1915 polygons.reallocate(polygonCount);
1916 core::array<int> vCounts;
1917 bool parsePolygonOK = false;
1918 bool parseVcountOK = false;
1919 u32 inputSemanticCount = 0;
1920 bool unresolvedInput=false;
1921 u32 maxOffset = 0;
1922 core::array<SColladaInput> localInputs;
1923
1924 // read all <input> and primitives
1925 if (!reader->isEmptyElement())
1926 while(reader->read())
1927 {
1928 const char* nodeName = reader->getNodeName();
1929
1930 if (reader->getNodeType() == io::EXN_ELEMENT)
1931 {
1932 // polygon node may contain params
1933 if (inputTagName == nodeName)
1934 {
1935 // read input tag
1936 readColladaInput(reader, localInputs);
1937
1938 // resolve input source
1939 SColladaInput& inp = localInputs.getLast();
1940
1941 // get input source array id, if it is a vertex input, take
1942 // the <vertex><input>-source attribute.
1943 if (inp.Semantic == ECIS_VERTEX)
1944 {
1945 inp.Source = Inputs[0].Source;
1946 for (u32 i=1; i<Inputs.size(); ++i)
1947 {
1948 localInputs.push_back(Inputs[i]);
1949 uriToId(localInputs.getLast().Source);
1950 maxOffset = core::max_(maxOffset,localInputs.getLast().Offset);
1951 ++inputSemanticCount;
1952 }
1953 }
1954 uriToId(inp.Source);
1955 maxOffset = core::max_(maxOffset,inp.Offset);
1956 ++inputSemanticCount;
1957 }
1958 else
1959 if (primitivesName == nodeName)
1960 {
1961 parsePolygonOK = true;
1962 polygons.push_back(SPolygon());
1963 }
1964 else
1965 if (vcountName == nodeName)
1966 {
1967 parseVcountOK = true;
1968 } // end is polygon node
1969 } // end is element node
1970 else
1971 if (reader->getNodeType() == io::EXN_ELEMENT_END)
1972 {
1973 if (primitivesName == nodeName)
1974 parsePolygonOK = false; // end parsing a polygon
1975 else
1976 if (vcountName == nodeName)
1977 parseVcountOK = false; // end parsing vcounts
1978 else
1979 if (polygonType == nodeName)
1980 break; // cancel out and create mesh
1981
1982 } // end is element end
1983 else
1984 if (reader->getNodeType() == io::EXN_TEXT)
1985 {
1986 if (parseVcountOK)
1987 {
1988 core::stringc data = reader->getNodeData();
1989 data.trim();
1990 const c8* p = &data[0];
1991 while(*p)
1992 {
1993 findNextNoneWhiteSpace(&p);
1994 if (*p)
1995 vCounts.push_back(readInt(&p));
1996 }
1997 parseVcountOK = false;
1998 }
1999 else
2000 if (parsePolygonOK && polygons.size())
2001 {
2002 core::stringc data = reader->getNodeData();
2003 data.trim();
2004 const c8* p = &data[0];
2005 SPolygon& poly = polygons.getLast();
2006 if (polygonType == polygonsSectionName)
2007 poly.Indices.reallocate((maxOffset+1)*3);
2008 else
2009 poly.Indices.reallocate(polygonCount*(maxOffset+1)*3);
2010
2011 if (vCounts.empty())
2012 {
2013 while(*p)
2014 {
2015 findNextNoneWhiteSpace(&p);
2016 poly.Indices.push_back(readInt(&p));
2017 }
2018 }
2019 else
2020 {
2021 for (u32 i = 0; i < vCounts.size(); i++)
2022 {
2023 const int polyVCount = vCounts[i];
2024 core::array<int> polyCorners;
2025
2026 for (u32 j = 0; j < polyVCount * inputSemanticCount; j++)
2027 {
2028 if (!*p)
2029 break;
2030 findNextNoneWhiteSpace(&p);
2031 polyCorners.push_back(readInt(&p));
2032 }
2033
2034 while (polyCorners.size() >= 3 * inputSemanticCount)
2035 {
2036 // add one triangle's worth of indices
2037 for (u32 k = 0; k < inputSemanticCount * 3; ++k)
2038 {
2039 poly.Indices.push_back(polyCorners[k]);
2040 }
2041
2042 // remove one corner from our poly
2043 polyCorners.erase(inputSemanticCount,inputSemanticCount);
2044 }
2045 polyCorners.clear();
2046 }
2047 vCounts.clear();
2048 }
2049 parsePolygonOK = false;
2050 }
2051 }
2052 } // end while reader->read()
2053
2054 // find source array (we'll ignore accessors for this implementation)
2055 for (u32 i=0; i<localInputs.size(); ++i)
2056 {
2057 SColladaInput& inp = localInputs[i];
2058 u32 s;
2059 for (s=0; s<sources.size(); ++s)
2060 {
2061 if (sources[s].Id == inp.Source)
2062 {
2063 // slot found
2064 inp.Data = sources[s].Array.Data.pointer();
2065 inp.Stride = sources[s].Accessors[0].Stride;
2066 break;
2067 }
2068 }
2069
2070 if (s == sources.size())
2071 {
2072 os::Printer::log("COLLADA Warning, polygon input source not found",
2073 inp.Source.c_str(), ELL_DEBUG);
2074 inp.Semantic=ECIS_COUNT; // for unknown
2075 unresolvedInput=true;
2076 }
2077 else
2078 {
2079 #ifdef COLLADA_READER_DEBUG
2080 // print slot
2081 core::stringc tmp = "Added slot ";
2082 tmp += inputSemanticNames[inp.Semantic];
2083 tmp += " sourceArray:";
2084 tmp += inp.Source;
2085 os::Printer::log(tmp.c_str(), ELL_DEBUG);
2086 #endif
2087 }
2088 }
2089
2090 if ((inputSemanticCount == 0) || !polygons.size())
2091 return; // cancel if there are no polygons anyway.
2092
2093 // analyze content of Inputs to create a fitting mesh buffer
2094
2095 u32 u;
2096 u32 textureCoordSetCount = 0;
2097 bool normalSlotCount = false;
2098 u32 secondTexCoordSetIndex = 0xFFFFFFFF;
2099
2100 for (u=0; u<Inputs.size(); ++u)
2101 {
2102 if (Inputs[u].Semantic == ECIS_TEXCOORD || Inputs[u].Semantic == ECIS_UV )
2103 {
2104 ++textureCoordSetCount;
2105
2106 if (textureCoordSetCount==2)
2107 secondTexCoordSetIndex = u;
2108 }
2109 else
2110 if (Inputs[u].Semantic == ECIS_NORMAL)
2111 normalSlotCount=true;
2112 }
2113
2114 // if there is more than one texture coordinate set, create a lightmap mesh buffer,
2115 // otherwise use a standard mesh buffer
2116
2117 scene::IMeshBuffer* buffer = 0;
2118 ++maxOffset; // +1 to jump to the next value
2119
2120 if ( textureCoordSetCount < 2 )
2121 {
2122 // standard mesh buffer
2123
2124 scene::SMeshBuffer* mbuffer = new SMeshBuffer();
2125 buffer = mbuffer;
2126
2127 core::map<video::S3DVertex, int> vertMap;
2128
2129 for (u32 i=0; i<polygons.size(); ++i)
2130 {
2131 core::array<u16> indices;
2132 const u32 vertexCount = polygons[i].Indices.size() / maxOffset;
2133 mbuffer->Vertices.reallocate(mbuffer->Vertices.size()+vertexCount);
2134
2135 // for all index/semantic groups
2136 for (u32 v=0; v<polygons[i].Indices.size(); v+=maxOffset)
2137 {
2138 video::S3DVertex vtx;
2139 vtx.Color.set(255,255,255,255);
2140
2141 // for all input semantics
2142 for (u32 k=0; k<localInputs.size(); ++k)
2143 {
2144 if (!localInputs[k].Data)
2145 continue;
2146 // build vertex from input semantics.
2147
2148 const u32 idx = localInputs[k].Stride*polygons[i].Indices[v+localInputs[k].Offset];
2149
2150 switch(localInputs[k].Semantic)
2151 {
2152 case ECIS_POSITION:
2153 case ECIS_VERTEX:
2154 vtx.Pos.X = localInputs[k].Data[idx+0];
2155 if (FlipAxis)
2156 {
2157 vtx.Pos.Z = localInputs[k].Data[idx+1];
2158 vtx.Pos.Y = localInputs[k].Data[idx+2];
2159 }
2160 else
2161 {
2162 vtx.Pos.Y = localInputs[k].Data[idx+1];
2163 vtx.Pos.Z = localInputs[k].Data[idx+2];
2164 }
2165 break;
2166 case ECIS_NORMAL:
2167 vtx.Normal.X = localInputs[k].Data[idx+0];
2168 if (FlipAxis)
2169 {
2170 vtx.Normal.Z = localInputs[k].Data[idx+1];
2171 vtx.Normal.Y = localInputs[k].Data[idx+2];
2172 }
2173 else
2174 {
2175 vtx.Normal.Y = localInputs[k].Data[idx+1];
2176 vtx.Normal.Z = localInputs[k].Data[idx+2];
2177 }
2178 break;
2179 case ECIS_TEXCOORD:
2180 case ECIS_UV:
2181 vtx.TCoords.X = localInputs[k].Data[idx+0];
2182 vtx.TCoords.Y = 1-localInputs[k].Data[idx+1];
2183 break;
2184 case ECIS_TANGENT:
2185 break;
2186 default:
2187 break;
2188 }
2189 }
2190
2191 //first, try to find this vertex in the mesh
2192 core::map<video::S3DVertex, int>::Node* n = vertMap.find(vtx);
2193 if (n)
2194 {
2195 indices.push_back(n->getValue());
2196 }
2197 else
2198 {
2199 indices.push_back(mbuffer->getVertexCount());
2200 mbuffer->Vertices.push_back(vtx);
2201 vertMap.insert(vtx, mbuffer->getVertexCount()-1);
2202 }
2203 } // end for all vertices
2204
2205 if (polygonsSectionName == polygonType &&
2206 indices.size() > 3)
2207 {
2208 // need to tesselate for polygons of 4 or more vertices
2209 // for now we naively turn interpret it as a triangle fan
2210 // as full tesselation is problematic
2211 if (FlipAxis)
2212 {
2213 for (u32 ind = indices.size()-3; ind>0 ; --ind)
2214 {
2215 mbuffer->Indices.push_back(indices[0]);
2216 mbuffer->Indices.push_back(indices[ind+2]);
2217 mbuffer->Indices.push_back(indices[ind+1]);
2218 }
2219 }
2220 else
2221 {
2222 for (u32 ind = 0; ind+2 < indices.size(); ++ind)
2223 {
2224 mbuffer->Indices.push_back(indices[0]);
2225 mbuffer->Indices.push_back(indices[ind+1]);
2226 mbuffer->Indices.push_back(indices[ind+2]);
2227 }
2228 }
2229 }
2230 else
2231 {
2232 // it's just triangles
2233 for (u32 ind = 0; ind < indices.size(); ind+=3)
2234 {
2235 if (FlipAxis)
2236 {
2237 mbuffer->Indices.push_back(indices[ind+2]);
2238 mbuffer->Indices.push_back(indices[ind+1]);
2239 mbuffer->Indices.push_back(indices[ind+0]);
2240 }
2241 else
2242 {
2243 mbuffer->Indices.push_back(indices[ind+0]);
2244 mbuffer->Indices.push_back(indices[ind+1]);
2245 mbuffer->Indices.push_back(indices[ind+2]);
2246 }
2247 }
2248 }
2249
2250 } // end for all polygons
2251 }
2252 else
2253 {
2254 // lightmap mesh buffer
2255
2256 scene::SMeshBufferLightMap* mbuffer = new SMeshBufferLightMap();
2257 buffer = mbuffer;
2258
2259 for (u32 i=0; i<polygons.size(); ++i)
2260 {
2261 const u32 vertexCount = polygons[i].Indices.size() / maxOffset;
2262 mbuffer->Vertices.reallocate(mbuffer->Vertices.size()+vertexCount);
2263 // for all vertices in array
2264 for (u32 v=0; v<polygons[i].Indices.size(); v+=maxOffset)
2265 {
2266 video::S3DVertex2TCoords vtx;
2267 vtx.Color.set(100,255,255,255);
2268
2269 // for all input semantics
2270 for (u32 k=0; k<Inputs.size(); ++k)
2271 {
2272 // build vertex from input semantics.
2273
2274 const u32 idx = localInputs[k].Stride*polygons[i].Indices[v+Inputs[k].Offset];
2275
2276 switch(localInputs[k].Semantic)
2277 {
2278 case ECIS_POSITION:
2279 case ECIS_VERTEX:
2280 vtx.Pos.X = localInputs[k].Data[idx+0];
2281 if (FlipAxis)
2282 {
2283 vtx.Pos.Z = localInputs[k].Data[idx+1];
2284 vtx.Pos.Y = localInputs[k].Data[idx+2];
2285 }
2286 else
2287 {
2288 vtx.Pos.Y = localInputs[k].Data[idx+1];
2289 vtx.Pos.Z = localInputs[k].Data[idx+2];
2290 }
2291 break;
2292 case ECIS_NORMAL:
2293 vtx.Normal.X = localInputs[k].Data[idx+0];
2294 if (FlipAxis)
2295 {
2296 vtx.Normal.Z = localInputs[k].Data[idx+1];
2297 vtx.Normal.Y = localInputs[k].Data[idx+2];
2298 }
2299 else
2300 {
2301 vtx.Normal.Y = localInputs[k].Data[idx+1];
2302 vtx.Normal.Z = localInputs[k].Data[idx+2];
2303 }
2304 break;
2305 case ECIS_TEXCOORD:
2306 case ECIS_UV:
2307 if (k==secondTexCoordSetIndex)
2308 {
2309 vtx.TCoords2.X = localInputs[k].Data[idx+0];
2310 vtx.TCoords2.Y = 1-localInputs[k].Data[idx+1];
2311 }
2312 else
2313 {
2314 vtx.TCoords.X = localInputs[k].Data[idx+0];
2315 vtx.TCoords.Y = 1-localInputs[k].Data[idx+1];
2316 }
2317 break;
2318 case ECIS_TANGENT:
2319 break;
2320 default:
2321 break;
2322 }
2323 }
2324
2325 mbuffer->Vertices.push_back(vtx);
2326
2327 } // end for all vertices
2328
2329 // add vertex indices
2330 const u32 oldVertexCount = mbuffer->Vertices.size() - vertexCount;
2331 for (u32 face=0; face<vertexCount-2; ++face)
2332 {
2333 mbuffer->Indices.push_back(oldVertexCount + 0);
2334 mbuffer->Indices.push_back(oldVertexCount + 1 + face);
2335 mbuffer->Indices.push_back(oldVertexCount + 2 + face);
2336 }
2337
2338 } // end for all polygons
2339 }
2340
2341 const SColladaMaterial* m = findMaterial(materialName);
2342 if (m)
2343 {
2344 buffer->getMaterial() = m->Mat;
2345 SMesh tmpmesh;
2346 tmpmesh.addMeshBuffer(buffer);
2347 SceneManager->getMeshManipulator()->setVertexColors(&tmpmesh,m->Mat.DiffuseColor);
2348 if (m->Transparency != 1.0f)
2349 SceneManager->getMeshManipulator()->setVertexColorAlpha(&tmpmesh,core::floor32(m->Transparency*255.0f));
2350 }
2351 // add future bind reference for the material
2352 core::stringc meshbufferReference = geometryId+"/"+materialName;
2353 if (!MaterialsToBind.find(meshbufferReference))
2354 {
2355 MaterialsToBind[meshbufferReference] = MeshesToBind.size();
2356 MeshesToBind.push_back(core::array<irr::scene::IMeshBuffer*>());
2357 }
2358 MeshesToBind[MaterialsToBind[meshbufferReference]].push_back(buffer);
2359
2360 // calculate normals if there is no slot for it
2361
2362 if (!normalSlotCount)
2363 SceneManager->getMeshManipulator()->recalculateNormals(buffer, true);
2364
2365 // recalculate bounding box
2366 buffer->recalculateBoundingBox();
2367
2368 // add mesh buffer
2369 mesh->addMeshBuffer(buffer);
2370 #ifdef COLLADA_READER_DEBUG
2371 os::Printer::log("COLLADA added meshbuffer", core::stringc(buffer->getVertexCount())+" vertices, "+core::stringc(buffer->getIndexCount())+" indices.", ELL_DEBUG);
2372 #endif
2373
2374 buffer->drop();
2375}
2376
2377
2378//! reads a <light> element and stores it as prefab
2379void CColladaFileLoader::readLightPrefab(io::IXMLReaderUTF8* reader)
2380{
2381 #ifdef COLLADA_READER_DEBUG
2382 os::Printer::log("COLLADA reading light prefab", ELL_DEBUG);
2383 #endif
2384
2385 CLightPrefab* prefab = new CLightPrefab(readId(reader));
2386
2387 if (!reader->isEmptyElement())
2388 {
2389 if (Version >= 10400) // start with 1.4
2390 {
2391 while(reader->read())
2392 {
2393 if (reader->getNodeType() == io::EXN_ELEMENT)
2394 {
2395 if (pointSectionName == reader->getNodeName())
2396 prefab->LightData.Type=video::ELT_POINT;
2397 else
2398 if (directionalSectionName == reader->getNodeName())
2399 prefab->LightData.Type=video::ELT_DIRECTIONAL;
2400 else
2401 if (spotSectionName == reader->getNodeName())
2402 prefab->LightData.Type=video::ELT_SPOT;
2403 else
2404 if (ambientSectionName == reader->getNodeName())
2405 prefab->LightData.Type=ELT_AMBIENT;
2406 else
2407 if (colorNodeName == reader->getNodeName())
2408 prefab->LightData.DiffuseColor=readColorNode(reader);
2409 else
2410 if (constantAttenuationNodeName == reader->getNodeName())
2411 readFloatsInsideElement(reader,&prefab->LightData.Attenuation.X,1);
2412 else
2413 if (linearAttenuationNodeName == reader->getNodeName())
2414 readFloatsInsideElement(reader,&prefab->LightData.Attenuation.Y,1);
2415 else
2416 if (quadraticAttenuationNodeName == reader->getNodeName())
2417 readFloatsInsideElement(reader,&prefab->LightData.Attenuation.Z,1);
2418 else
2419 if (falloffAngleNodeName == reader->getNodeName())
2420 {
2421 readFloatsInsideElement(reader,&prefab->LightData.OuterCone,1);
2422 prefab->LightData.OuterCone *= core::DEGTORAD;
2423 }
2424 else
2425 if (falloffExponentNodeName == reader->getNodeName())
2426 readFloatsInsideElement(reader,&prefab->LightData.Falloff,1);
2427 }
2428 else
2429 if (reader->getNodeType() == io::EXN_ELEMENT_END)
2430 {
2431 if ((pointSectionName == reader->getNodeName()) ||
2432 (directionalSectionName == reader->getNodeName()) ||
2433 (spotSectionName == reader->getNodeName()) ||
2434 (ambientSectionName == reader->getNodeName()))
2435 break;
2436 }
2437 }
2438 }
2439 else
2440 {
2441 readColladaParameters(reader, lightPrefabName);
2442
2443 SColladaParam* p = getColladaParameter(ECPN_COLOR);
2444 if (p && p->Type == ECPT_FLOAT3)
2445 prefab->LightData.DiffuseColor.set(p->Floats[0], p->Floats[1], p->Floats[2]);
2446 }
2447 }
2448
2449 Prefabs.push_back(prefab);
2450}
2451
2452
2453//! returns a collada parameter or none if not found
2454SColladaParam* CColladaFileLoader::getColladaParameter(ECOLLADA_PARAM_NAME name)
2455{
2456 for (u32 i=0; i<ColladaParameters.size(); ++i)
2457 if (ColladaParameters[i].Name == name)
2458 return &ColladaParameters[i];
2459
2460 return 0;
2461}
2462
2463//! returns a collada input or none if not found
2464SColladaInput* CColladaFileLoader::getColladaInput(ECOLLADA_INPUT_SEMANTIC input)
2465{
2466 for (u32 i=0; i<Inputs.size(); ++i)
2467 if (Inputs[i].Semantic == input)
2468 return &Inputs[i];
2469
2470 return 0;
2471}
2472
2473
2474//! reads a collada input tag and adds it to the input parameter
2475void CColladaFileLoader::readColladaInput(io::IXMLReaderUTF8* reader, core::array<SColladaInput>& inputs)
2476{
2477 // parse param
2478 SColladaInput p;
2479
2480 // get type
2481 core::stringc semanticName = reader->getAttributeValue("semantic");
2482 for (u32 i=0; inputSemanticNames[i]; ++i)
2483 {
2484 if (semanticName == inputSemanticNames[i])
2485 {
2486 p.Semantic = (ECOLLADA_INPUT_SEMANTIC)i;
2487 break;
2488 }
2489 }
2490
2491 // get source
2492 p.Source = reader->getAttributeValue("source");
2493 if (reader->getAttributeValue("offset")) // Collada 1.4+
2494 p.Offset = (u32)reader->getAttributeValueAsInt("offset");
2495 else // Collada 1.2/1.3
2496 p.Offset = (u32)reader->getAttributeValueAsInt("idx");
2497 p.Set = (u32)reader->getAttributeValueAsInt("set");
2498
2499 // add input
2500 inputs.push_back(p);
2501}
2502
2503//! parses all collada inputs inside an element and stores them in Inputs
2504void CColladaFileLoader::readColladaInputs(io::IXMLReaderUTF8* reader, const core::stringc& parentName)
2505{
2506 Inputs.clear();
2507
2508 while(reader->read())
2509 {
2510 if (reader->getNodeType() == io::EXN_ELEMENT &&
2511 inputTagName == reader->getNodeName())
2512 {
2513 readColladaInput(reader, Inputs);
2514 }
2515 else
2516 if (reader->getNodeType() == io::EXN_ELEMENT_END)
2517 {
2518 if (parentName == reader->getNodeName())
2519 return; // end of parent reached
2520 }
2521
2522 } // end while reader->read();
2523}
2524
2525//! parses all collada parameters inside an element and stores them in ColladaParameters
2526void CColladaFileLoader::readColladaParameters(io::IXMLReaderUTF8* reader,
2527 const core::stringc& parentName)
2528{
2529 ColladaParameters.clear();
2530
2531 const char* const paramNames[] = {"COLOR", "AMBIENT", "DIFFUSE",
2532 "SPECULAR", "SHININESS", "YFOV", "ZNEAR", "ZFAR", 0};
2533
2534 const char* const typeNames[] = {"float", "float2", "float3", 0};
2535
2536 while(reader->read())
2537 {
2538 const char* nodeName = reader->getNodeName();
2539 if (reader->getNodeType() == io::EXN_ELEMENT &&
2540 paramTagName == nodeName)
2541 {
2542 // parse param
2543 SColladaParam p;
2544
2545 // get type
2546 u32 i;
2547 core::stringc typeName = reader->getAttributeValue("type");
2548 for (i=0; typeNames[i]; ++i)
2549 if (typeName == typeNames[i])
2550 {
2551 p.Type = (ECOLLADA_PARAM_TYPE)i;
2552 break;
2553 }
2554
2555 // get name
2556 core::stringc nameName = reader->getAttributeValue("name");
2557 for (i=0; typeNames[i]; ++i)
2558 if (nameName == paramNames[i])
2559 {
2560 p.Name = (ECOLLADA_PARAM_NAME)i;
2561 break;
2562 }
2563
2564 // read parameter data inside parameter tags
2565 switch(p.Type)
2566 {
2567 case ECPT_FLOAT:
2568 case ECPT_FLOAT2:
2569 case ECPT_FLOAT3:
2570 case ECPT_FLOAT4:
2571 readFloatsInsideElement(reader, p.Floats, p.Type - ECPT_FLOAT + 1);
2572 break;
2573
2574 // TODO: other types of data (ints, bools or whatever)
2575 default:
2576 break;
2577 }
2578
2579 // add param
2580 ColladaParameters.push_back(p);
2581 }
2582 else
2583 if (reader->getNodeType() == io::EXN_ELEMENT_END)
2584 {
2585 if (parentName == reader->getNodeName())
2586 return; // end of parent reached
2587 }
2588
2589 } // end while reader->read();
2590}
2591
2592
2593//! parses a float from a char pointer and moves the pointer
2594//! to the end of the parsed float
2595inline f32 CColladaFileLoader::readFloat(const c8** p)
2596{
2597 f32 ftmp;
2598 *p = core::fast_atof_move(*p, ftmp);
2599 return ftmp;
2600}
2601
2602
2603//! parses an int from a char pointer and moves the pointer to
2604//! the end of the parsed float
2605inline s32 CColladaFileLoader::readInt(const c8** p)
2606{
2607 return (s32)readFloat(p);
2608}
2609
2610
2611//! places pointer to next begin of a token
2612void CColladaFileLoader::findNextNoneWhiteSpace(const c8** start)
2613{
2614 const c8* p = *start;
2615
2616 while(*p && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t'))
2617 ++p;
2618
2619 // TODO: skip comments <!-- -->
2620
2621 *start = p;
2622}
2623
2624
2625//! reads floats from inside of xml element until end of xml element
2626void CColladaFileLoader::readFloatsInsideElement(io::IXMLReaderUTF8* reader, f32* floats, u32 count)
2627{
2628 if (reader->isEmptyElement())
2629 return;
2630
2631 while(reader->read())
2632 {
2633 // TODO: check for comments inside the element
2634 // and ignore them.
2635
2636 if (reader->getNodeType() == io::EXN_TEXT)
2637 {
2638 // parse float data
2639 core::stringc data = reader->getNodeData();
2640 data.trim();
2641 const c8* p = &data[0];
2642
2643 for (u32 i=0; i<count; ++i)
2644 {
2645 findNextNoneWhiteSpace(&p);
2646 if (*p)
2647 floats[i] = readFloat(&p);
2648 else
2649 floats[i] = 0.0f;
2650 }
2651 }
2652 else
2653 if (reader->getNodeType() == io::EXN_ELEMENT_END)
2654 break; // end parsing text
2655 }
2656}
2657
2658
2659//! reads ints from inside of xml element until end of xml element
2660void CColladaFileLoader::readIntsInsideElement(io::IXMLReaderUTF8* reader, s32* ints, u32 count)
2661{
2662 if (reader->isEmptyElement())
2663 return;
2664
2665 while(reader->read())
2666 {
2667 // TODO: check for comments inside the element
2668 // and ignore them.
2669
2670 if (reader->getNodeType() == io::EXN_TEXT)
2671 {
2672 // parse float data
2673 core::stringc data = reader->getNodeData();
2674 data.trim();
2675 const c8* p = &data[0];
2676
2677 for (u32 i=0; i<count; ++i)
2678 {
2679 findNextNoneWhiteSpace(&p);
2680 if (*p)
2681 ints[i] = readInt(&p);
2682 else
2683 ints[i] = 0;
2684 }
2685 }
2686 else
2687 if (reader->getNodeType() == io::EXN_ELEMENT_END)
2688 break; // end parsing text
2689 }
2690}
2691
2692
2693video::SColorf CColladaFileLoader::readColorNode(io::IXMLReaderUTF8* reader)
2694{
2695 if (reader->getNodeType() == io::EXN_ELEMENT &&
2696 colorNodeName == reader->getNodeName())
2697 {
2698 f32 color[4];
2699 readFloatsInsideElement(reader,color,4);
2700 return video::SColorf(color[0], color[1], color[2], color[3]);
2701 }
2702
2703 return video::SColorf();
2704}
2705
2706
2707f32 CColladaFileLoader::readFloatNode(io::IXMLReaderUTF8* reader)
2708{
2709 #ifdef COLLADA_READER_DEBUG
2710 os::Printer::log("COLLADA reading <float>", ELL_DEBUG);
2711 #endif
2712
2713 f32 result = 0.0f;
2714 if (reader->getNodeType() == io::EXN_ELEMENT &&
2715 floatNodeName == reader->getNodeName())
2716 {
2717 readFloatsInsideElement(reader,&result,1);
2718 }
2719
2720 return result;
2721}
2722
2723
2724//! clears all loaded data
2725void CColladaFileLoader::clearData()
2726{
2727 // delete all prefabs
2728
2729 for (u32 i=0; i<Prefabs.size(); ++i)
2730 Prefabs[i]->drop();
2731
2732 Prefabs.clear();
2733
2734 // clear all parameters
2735 ColladaParameters.clear();
2736
2737 // clear all materials
2738 Images.clear();
2739
2740 // clear all materials
2741 Textures.clear();
2742
2743 // clear all materials
2744 Materials.clear();
2745
2746 // clear all inputs
2747 Inputs.clear();
2748
2749 // clear all effects
2750 for ( u32 i=0; i<Effects.size(); ++i )
2751 Effects[i].Parameters->drop();
2752 Effects.clear();
2753
2754 // clear all the materials to bind
2755 MaterialsToBind.clear();
2756 MeshesToBind.clear();
2757}
2758
2759
2760//! changes the XML URI into an internal id
2761void CColladaFileLoader::uriToId(core::stringc& str)
2762{
2763 // currently, we only remove the # from the begin if there
2764 // because we simply don't support referencing other files.
2765 if (!str.size())
2766 return;
2767
2768 if (str[0] == '#')
2769 str.erase(0);
2770}
2771
2772
2773//! read Collada Id, uses id or name if id is missing
2774core::stringc CColladaFileLoader::readId(io::IXMLReaderUTF8* reader)
2775{
2776 core::stringc id = reader->getAttributeValue("id");
2777 if (id.size()==0)
2778 id = reader->getAttributeValue("name");
2779 return id;
2780}
2781
2782
2783//! create an Irrlicht texture from the reference
2784video::ITexture* CColladaFileLoader::getTextureFromImage(core::stringc uri, SColladaEffect * effect)
2785{
2786 #ifdef COLLADA_READER_DEBUG
2787 os::Printer::log("COLLADA searching texture", uri, ELL_DEBUG);
2788 #endif
2789 video::IVideoDriver* driver = SceneManager->getVideoDriver();
2790 for (;;)
2791 {
2792 uriToId(uri);
2793 for (u32 i=0; i<Images.size(); ++i)
2794 {
2795 if (uri == Images[i].Id)
2796 {
2797 if (Images[i].Source.size() && Images[i].SourceIsFilename)
2798 {
2799 if (FileSystem->existFile(Images[i].Source))
2800 return driver->getTexture(Images[i].Source);
2801 return driver->getTexture((FileSystem->getFileDir(CurrentlyLoadingMesh)+"/"+Images[i].Source));
2802 }
2803 else
2804 if (Images[i].Source.size())
2805 {
2806 //const u32 size = Images[i].Dimension.getArea();
2807 const u32 size = Images[i].Dimension.Width * Images[i].Dimension.Height;;
2808 u32* data = new u32[size]; // we assume RGBA
2809 u32* ptrdest = data;
2810 const c8* ptrsrc = Images[i].Source.c_str();
2811 for (u32 j=0; j<size; ++j)
2812 {
2813 sscanf(ptrsrc, "%x", ptrdest);
2814 ++ptrdest;
2815 ptrsrc += 4;
2816 }
2817 video::IImage* img = driver->createImageFromData(video::ECF_A8R8G8B8, Images[i].Dimension, data, true, true);
2818 video::ITexture* tex = driver->addTexture((CurrentlyLoadingMesh+"#"+Images[i].Id).c_str(), img);
2819 img->drop();
2820 return tex;
2821 }
2822 break;
2823 }
2824 }
2825 if (effect && effect->Parameters->getAttributeType(uri.c_str())==io::EAT_STRING)
2826 {
2827 uri = effect->Parameters->getAttributeAsString(uri.c_str());
2828#ifdef COLLADA_READER_DEBUG
2829 os::Printer::log("COLLADA now searching texture", uri.c_str(), ELL_DEBUG);
2830#endif
2831 }
2832 else
2833 break;
2834 }
2835 return 0;
2836}
2837
2838
2839//! read a parameter and value
2840void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters)
2841{
2842 #ifdef COLLADA_READER_DEBUG
2843 os::Printer::log("COLLADA reading parameter", ELL_DEBUG);
2844 #endif
2845
2846 if ( !parameters )
2847 return;
2848
2849 const core::stringc name = reader->getAttributeValue("sid");
2850 if (!reader->isEmptyElement())
2851 {
2852 while(reader->read())
2853 {
2854 if (reader->getNodeType() == io::EXN_ELEMENT)
2855 {
2856 if (floatNodeName == reader->getNodeName())
2857 {
2858 const f32 f = readFloatNode(reader);
2859 parameters->addFloat(name.c_str(), f);
2860 }
2861 else
2862 if (float2NodeName == reader->getNodeName())
2863 {
2864 f32 f[2];
2865 readFloatsInsideElement(reader, f, 2);
2866// Parameters.addVector2d(name.c_str(), core::vector2df(f[0],f[1]));
2867 }
2868 else
2869 if (float3NodeName == reader->getNodeName())
2870 {
2871 f32 f[3];
2872 readFloatsInsideElement(reader, f, 3);
2873 parameters->addVector3d(name.c_str(), core::vector3df(f[0],f[1],f[2]));
2874 }
2875 else
2876 if ((initFromName == reader->getNodeName()) ||
2877 (sourceSectionName == reader->getNodeName()))
2878 {
2879 reader->read();
2880 parameters->addString(name.c_str(), reader->getNodeData());
2881 }
2882 else
2883 if (wrapsName == reader->getNodeName())
2884 {
2885 reader->read();
2886 const core::stringc val = reader->getNodeData();
2887 if (val == "WRAP")
2888 parameters->addInt(wrapsName.c_str(), (int)video::ETC_REPEAT);
2889 else if ( val== "MIRROR")
2890 parameters->addInt(wrapsName.c_str(), (int)video::ETC_MIRROR);
2891 else if ( val== "CLAMP")
2892 parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_EDGE);
2893 else if ( val== "BORDER")
2894 parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_BORDER);
2895 else if ( val== "NONE")
2896 parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_BORDER);
2897 }
2898 else
2899 if (wraptName == reader->getNodeName())
2900 {
2901 reader->read();
2902 const core::stringc val = reader->getNodeData();
2903 if (val == "WRAP")
2904 parameters->addInt(wraptName.c_str(), (int)video::ETC_REPEAT);
2905 else if ( val== "MIRROR")
2906 parameters->addInt(wraptName.c_str(), (int)video::ETC_MIRROR);
2907 else if ( val== "CLAMP")
2908 parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_EDGE);
2909 else if ( val== "BORDER")
2910 parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_BORDER);
2911 else if ( val== "NONE")
2912 parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_BORDER);
2913 }
2914 else
2915 if (minfilterName == reader->getNodeName())
2916 {
2917 reader->read();
2918 const core::stringc val = reader->getNodeData();
2919 if (val == "LINEAR_MIPMAP_LINEAR")
2920 parameters->addBool("trilinear", true);
2921 else
2922 if (val == "LINEAR_MIPMAP_NEAREST")
2923 parameters->addBool("bilinear", true);
2924 }
2925 else
2926 if (magfilterName == reader->getNodeName())
2927 {
2928 reader->read();
2929 const core::stringc val = reader->getNodeData();
2930 if (val != "LINEAR")
2931 {
2932 parameters->addBool("bilinear", false);
2933 parameters->addBool("trilinear", false);
2934 }
2935 }
2936 else
2937 if (mipfilterName == reader->getNodeName())
2938 {
2939 parameters->addBool("anisotropic", true);
2940 }
2941 }
2942 else
2943 if(reader->getNodeType() == io::EXN_ELEMENT_END)
2944 {
2945 if (newParamName == reader->getNodeName())
2946 break;
2947 }
2948 }
2949 }
2950}
2951
2952
2953} // end namespace scene
2954} // end namespace irr
2955
2956#endif // _IRR_COMPILE_WITH_COLLADA_LOADER_
2957