aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CXMeshFileLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CXMeshFileLoader.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CXMeshFileLoader.cpp2423
1 files changed, 2423 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CXMeshFileLoader.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CXMeshFileLoader.cpp
new file mode 100644
index 0000000..0c4922a
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CXMeshFileLoader.cpp
@@ -0,0 +1,2423 @@
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
7#ifdef _IRR_COMPILE_WITH_X_LOADER_
8
9#include "CXMeshFileLoader.h"
10#include "os.h"
11
12#include "fast_atof.h"
13#include "coreutil.h"
14#include "ISceneManager.h"
15#include "IVideoDriver.h"
16#include "IFileSystem.h"
17#include "IReadFile.h"
18
19#ifdef _DEBUG
20#define _XREADER_DEBUG
21#endif
22//#define BETTER_MESHBUFFER_SPLITTING_FOR_X
23
24namespace irr
25{
26namespace scene
27{
28
29//! Constructor
30CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs)
31: SceneManager(smgr), FileSystem(fs), AllJoints(0), AnimatedMesh(0),
32 Buffer(0), P(0), End(0), BinaryNumCount(0), Line(0),
33 CurFrame(0), MajorVersion(0), MinorVersion(0), BinaryFormat(false), FloatSize(0)
34{
35 #ifdef _DEBUG
36 setDebugName("CXMeshFileLoader");
37 #endif
38}
39
40
41//! returns true if the file maybe is able to be loaded by this class
42//! based on the file extension (e.g. ".bsp")
43bool CXMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
44{
45 return core::hasFileExtension ( filename, "x" );
46}
47
48
49//! creates/loads an animated mesh from the file.
50//! \return Pointer to the created mesh. Returns 0 if loading failed.
51//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
52//! See IReferenceCounted::drop() for more information.
53IAnimatedMesh* CXMeshFileLoader::createMesh(io::IReadFile* f)
54{
55 if (!f)
56 return 0;
57
58#ifdef _XREADER_DEBUG
59 u32 time = os::Timer::getRealTime();
60#endif
61
62 AnimatedMesh = new CSkinnedMesh();
63
64 if (load(f))
65 {
66 AnimatedMesh->finalize();
67 }
68 else
69 {
70 AnimatedMesh->drop();
71 AnimatedMesh = 0;
72 }
73#ifdef _XREADER_DEBUG
74 time = os::Timer::getRealTime() - time;
75 core::stringc tmpString = "Time to load ";
76 tmpString += BinaryFormat ? "binary" : "ascii";
77 tmpString += " X file: ";
78 tmpString += time;
79 tmpString += "ms";
80 os::Printer::log(tmpString.c_str());
81#endif
82 //Clear up
83
84 MajorVersion=0;
85 MinorVersion=0;
86 BinaryFormat=0;
87 BinaryNumCount=0;
88 FloatSize=0;
89 P=0;
90 End=0;
91 CurFrame=0;
92 TemplateMaterials.clear();
93
94 delete [] Buffer;
95 Buffer = 0;
96
97 for (u32 i=0; i<Meshes.size(); ++i)
98 delete Meshes[i];
99 Meshes.clear();
100
101 return AnimatedMesh;
102}
103
104
105bool CXMeshFileLoader::load(io::IReadFile* file)
106{
107 if (!readFileIntoMemory(file))
108 return false;
109
110 if (!parseFile())
111 return false;
112
113 for (u32 n=0; n<Meshes.size(); ++n)
114 {
115 SXMesh *mesh=Meshes[n];
116
117 // default material if nothing loaded
118 if (!mesh->Materials.size())
119 {
120 mesh->Materials.push_back(video::SMaterial());
121 mesh->Materials[0].DiffuseColor.set(0xff777777);
122 mesh->Materials[0].Shininess=0.f;
123 mesh->Materials[0].SpecularColor.set(0xff777777);
124 mesh->Materials[0].EmissiveColor.set(0xff000000);
125 }
126
127 u32 i;
128
129 mesh->Buffers.reallocate(mesh->Materials.size());
130#ifndef BETTER_MESHBUFFER_SPLITTING_FOR_X
131 const u32 bufferOffset = AnimatedMesh->getMeshBufferCount();
132#endif
133 for (i=0; i<mesh->Materials.size(); ++i)
134 {
135 mesh->Buffers.push_back( AnimatedMesh->addMeshBuffer() );
136 mesh->Buffers.getLast()->Material = mesh->Materials[i];
137
138 if (!mesh->HasSkinning)
139 {
140 //Set up rigid animation
141 if (mesh->AttachedJointID!=-1)
142 {
143 AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back( AnimatedMesh->getMeshBuffers().size()-1 );
144 }
145 }
146 }
147
148 if (!mesh->FaceMaterialIndices.size())
149 {
150 mesh->FaceMaterialIndices.set_used(mesh->Indices.size() / 3);
151 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
152 mesh->FaceMaterialIndices[i]=0;
153 }
154
155 if (!mesh->HasVertexColors)
156 {
157 for (u32 j=0;j<mesh->FaceMaterialIndices.size();++j)
158 {
159 for (u32 id=j*3+0;id<=j*3+2;++id)
160 {
161 mesh->Vertices[ mesh->Indices[id] ].Color = mesh->Buffers[mesh->FaceMaterialIndices[j]]->Material.DiffuseColor;
162 }
163 }
164 }
165
166 #ifdef BETTER_MESHBUFFER_SPLITTING_FOR_X
167 {
168 //the same vertex can be used in many different meshbuffers, but it's slow to work out
169
170 core::array< core::array< u32 > > verticesLinkIndex;
171 verticesLinkIndex.reallocate(mesh->Vertices.size());
172 core::array< core::array< u16 > > verticesLinkBuffer;
173 verticesLinkBuffer.reallocate(mesh->Vertices.size());
174
175 for (i=0;i<mesh->Vertices.size();++i)
176 {
177 verticesLinkIndex.push_back( core::array< u32 >() );
178 verticesLinkBuffer.push_back( core::array< u16 >() );
179 }
180
181 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
182 {
183 for (u32 id=i*3+0;id<=i*3+2;++id)
184 {
185 core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
186 bool found=false;
187
188 for (u32 j=0; j < Array.size(); ++j)
189 {
190 if (Array[j]==mesh->FaceMaterialIndices[i])
191 {
192 found=true;
193 break;
194 }
195 }
196
197 if (!found)
198 Array.push_back( mesh->FaceMaterialIndices[i] );
199 }
200 }
201
202 for (i=0;i<verticesLinkBuffer.size();++i)
203 {
204 if (!verticesLinkBuffer[i].size())
205 verticesLinkBuffer[i].push_back(0);
206 }
207
208 for (i=0;i<mesh->Vertices.size();++i)
209 {
210 core::array< u16 > &Array = verticesLinkBuffer[i];
211 verticesLinkIndex[i].reallocate(Array.size());
212 for (u32 j=0; j < Array.size(); ++j)
213 {
214 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ Array[j] ];
215 verticesLinkIndex[i].push_back( buffer->Vertices_Standard.size() );
216 buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
217 }
218 }
219
220 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
221 {
222 scene::SSkinMeshBuffer *buffer=mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
223
224 for (u32 id=i*3+0;id<=i*3+2;++id)
225 {
226 core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
227
228 for (u32 j=0;j< Array.size() ;++j)
229 {
230 if ( Array[j]== mesh->FaceMaterialIndices[i] )
231 buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ][j] );
232 }
233 }
234 }
235
236 for (u32 j=0;j<mesh->WeightJoint.size();++j)
237 {
238 ISkinnedMesh::SJoint* joint = AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]];
239 ISkinnedMesh::SWeight& weight = joint->Weights[mesh->WeightNum[j]];
240
241 u32 id = weight.vertex_id;
242
243 if (id>=verticesLinkIndex.size())
244 {
245 os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
246 id=0;
247 weight.strength=0.f;
248 }
249
250 if (verticesLinkBuffer[id].size()==1)
251 {
252 weight.vertex_id=verticesLinkIndex[id][0];
253 weight.buffer_id=verticesLinkBuffer[id][0];
254 }
255 else if (verticesLinkBuffer[id].size() != 0)
256 {
257 for (u32 k=1; k < verticesLinkBuffer[id].size(); ++k)
258 {
259 ISkinnedMesh::SWeight* WeightClone = AnimatedMesh->addWeight(joint);
260 WeightClone->strength = weight.strength;
261 WeightClone->vertex_id = verticesLinkIndex[id][k];
262 WeightClone->buffer_id = verticesLinkBuffer[id][k];
263 }
264 }
265 }
266 }
267 #else
268 {
269 core::array< u32 > verticesLinkIndex;
270 core::array< s16 > verticesLinkBuffer;
271 verticesLinkBuffer.set_used(mesh->Vertices.size());
272
273 // init with 0
274 for (i=0;i<mesh->Vertices.size();++i)
275 {
276 // watch out for vertices which are not part of the mesh
277 // they will keep the -1 and can lead to out-of-bounds access
278 verticesLinkBuffer[i]=-1;
279 }
280
281 bool warned = false;
282 // store meshbuffer number per vertex
283 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
284 {
285 for (u32 id=i*3+0;id<=i*3+2;++id)
286 {
287 if ((verticesLinkBuffer[mesh->Indices[id]] != -1) && (verticesLinkBuffer[mesh->Indices[id]] != (s16)mesh->FaceMaterialIndices[i]))
288 {
289 if (!warned)
290 {
291 os::Printer::log("X loader", "Duplicated vertex, animation might be corrupted.", ELL_WARNING);
292 warned=true;
293 }
294 const u32 tmp = mesh->Vertices.size();
295 mesh->Vertices.push_back(mesh->Vertices[ mesh->Indices[id] ]);
296 mesh->Indices[id] = tmp;
297 verticesLinkBuffer.set_used(mesh->Vertices.size());
298 }
299 verticesLinkBuffer[ mesh->Indices[id] ] = mesh->FaceMaterialIndices[i];
300 }
301 }
302
303 if (mesh->FaceMaterialIndices.size() != 0)
304 {
305 // store vertices in buffers and remember relation in verticesLinkIndex
306 u32* vCountArray = new u32[mesh->Buffers.size()];
307 memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
308 // count vertices in each buffer and reallocate
309 for (i=0; i<mesh->Vertices.size(); ++i)
310 {
311 if (verticesLinkBuffer[i] != -1)
312 ++vCountArray[verticesLinkBuffer[i]];
313 }
314 if (mesh->TCoords2.size())
315 {
316 for (i=0; i!=mesh->Buffers.size(); ++i)
317 {
318 mesh->Buffers[i]->Vertices_2TCoords.reallocate(vCountArray[i]);
319 mesh->Buffers[i]->VertexType=video::EVT_2TCOORDS;
320 }
321 }
322 else
323 {
324 for (i=0; i!=mesh->Buffers.size(); ++i)
325 mesh->Buffers[i]->Vertices_Standard.reallocate(vCountArray[i]);
326 }
327
328 verticesLinkIndex.set_used(mesh->Vertices.size());
329 // actually store vertices
330 for (i=0; i<mesh->Vertices.size(); ++i)
331 {
332 // if a vertex is missing for some reason, just skip it
333 if (verticesLinkBuffer[i]==-1)
334 continue;
335 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ verticesLinkBuffer[i] ];
336
337 if (mesh->TCoords2.size())
338 {
339 verticesLinkIndex[i] = buffer->Vertices_2TCoords.size();
340 buffer->Vertices_2TCoords.push_back( mesh->Vertices[i] );
341 // We have a problem with correct tcoord2 handling here
342 // crash fixed for now by checking the values
343 buffer->Vertices_2TCoords.getLast().TCoords2=(i<mesh->TCoords2.size())?mesh->TCoords2[i]:mesh->Vertices[i].TCoords;
344 }
345 else
346 {
347 verticesLinkIndex[i] = buffer->Vertices_Standard.size();
348 buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
349 }
350 }
351
352 // count indices per buffer and reallocate
353 memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
354 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
355 ++vCountArray[ mesh->FaceMaterialIndices[i] ];
356 for (i=0; i!=mesh->Buffers.size(); ++i)
357 mesh->Buffers[i]->Indices.reallocate(vCountArray[i]);
358 delete [] vCountArray;
359 // create indices per buffer
360 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
361 {
362 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
363 for (u32 id=i*3+0; id!=i*3+3; ++id)
364 {
365 buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ] );
366 }
367 }
368 }
369
370 for (u32 j=0; j<mesh->WeightJoint.size(); ++j)
371 {
372 ISkinnedMesh::SWeight& weight = (AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]->Weights[mesh->WeightNum[j]]);
373
374 u32 id = weight.vertex_id;
375
376 if (id>=verticesLinkIndex.size())
377 {
378 os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
379 id=0;
380 weight.strength=0.f;
381 }
382
383 weight.vertex_id=verticesLinkIndex[id];
384 weight.buffer_id=verticesLinkBuffer[id] + bufferOffset;
385 }
386 }
387 #endif
388
389 }
390
391 return true;
392}
393
394
395//! Reads file into memory
396bool CXMeshFileLoader::readFileIntoMemory(io::IReadFile* file)
397{
398 const long size = file->getSize();
399 if (size < 12)
400 {
401 os::Printer::log("X File is too small.", ELL_WARNING);
402 return false;
403 }
404
405 Buffer = new c8[size];
406
407 //! read all into memory
408 if (file->read(Buffer, size) != size)
409 {
410 os::Printer::log("Could not read from x file.", ELL_WARNING);
411 return false;
412 }
413
414 Line = 1;
415 End = Buffer + size;
416
417 //! check header "xof "
418 if (strncmp(Buffer, "xof ", 4)!=0)
419 {
420 os::Printer::log("Not an x file, wrong header.", ELL_WARNING);
421 return false;
422 }
423
424 //! read minor and major version, e.g. 0302 or 0303
425 c8 tmp[3];
426 tmp[0] = Buffer[4];
427 tmp[1] = Buffer[5];
428 tmp[2] = 0x0;
429 MajorVersion = core::strtoul10(tmp);
430
431 tmp[0] = Buffer[6];
432 tmp[1] = Buffer[7];
433 MinorVersion = core::strtoul10(tmp);
434
435 //! read format
436 if (strncmp(&Buffer[8], "txt ", 4) ==0)
437 BinaryFormat = false;
438 else if (strncmp(&Buffer[8], "bin ", 4) ==0)
439 BinaryFormat = true;
440 else
441 {
442 os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING);
443 return false;
444 }
445 BinaryNumCount=0;
446
447 //! read float size
448 if (strncmp(&Buffer[12], "0032", 4) ==0)
449 FloatSize = 4;
450 else if (strncmp(&Buffer[12], "0064", 4) ==0)
451 FloatSize = 8;
452 else
453 {
454 os::Printer::log("Float size not supported.", ELL_WARNING);
455 return false;
456 }
457
458 P = &Buffer[16];
459
460 readUntilEndOfLine();
461 FilePath = FileSystem->getFileDir(file->getFileName()) + "/";
462
463 return true;
464}
465
466
467//! Parses the file
468bool CXMeshFileLoader::parseFile()
469{
470 while(parseDataObject())
471 {
472 // loop
473 }
474
475 return true;
476}
477
478
479//! Parses the next Data object in the file
480bool CXMeshFileLoader::parseDataObject()
481{
482 core::stringc objectName = getNextToken();
483
484 if (objectName.size() == 0)
485 return false;
486
487 // parse specific object
488#ifdef _XREADER_DEBUG
489 os::Printer::log("debug DataObject:", objectName.c_str(), ELL_DEBUG);
490#endif
491
492 if (objectName == "template")
493 return parseDataObjectTemplate();
494 else
495 if (objectName == "Frame")
496 {
497 return parseDataObjectFrame( 0 );
498 }
499 else
500 if (objectName == "Mesh")
501 {
502 // some meshes have no frames at all
503 //CurFrame = AnimatedMesh->addJoint(0);
504
505 SXMesh *mesh=new SXMesh;
506
507 //mesh->Buffer=AnimatedMesh->addMeshBuffer();
508 Meshes.push_back(mesh);
509
510 return parseDataObjectMesh(*mesh);
511 }
512 else
513 if (objectName == "AnimationSet")
514 {
515 return parseDataObjectAnimationSet();
516 }
517 else
518 if (objectName == "Material")
519 {
520 // template materials now available thanks to joeWright
521 TemplateMaterials.push_back(SXTemplateMaterial());
522 TemplateMaterials.getLast().Name = getNextToken();
523 return parseDataObjectMaterial(TemplateMaterials.getLast().Material);
524 }
525 else
526 if (objectName == "}")
527 {
528 os::Printer::log("} found in dataObject", ELL_WARNING);
529 return true;
530 }
531
532 os::Printer::log("Unknown data object in animation of .x file", objectName.c_str(), ELL_WARNING);
533
534 return parseUnknownDataObject();
535}
536
537
538bool CXMeshFileLoader::parseDataObjectTemplate()
539{
540#ifdef _XREADER_DEBUG
541 os::Printer::log("CXFileReader: Reading template", ELL_DEBUG);
542#endif
543
544 // parse a template data object. Currently not stored.
545 core::stringc name;
546
547 if (!readHeadOfDataObject(&name))
548 {
549 os::Printer::log("Left delimiter in template data object missing.",
550 name.c_str(), ELL_WARNING);
551 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
552 return false;
553 }
554
555 // read GUID
556 getNextToken();
557
558 // read and ignore data members
559 while(true)
560 {
561 core::stringc s = getNextToken();
562
563 if (s == "}")
564 break;
565
566 if (s.size() == 0)
567 return false;
568 }
569
570 return true;
571}
572
573
574bool CXMeshFileLoader::parseDataObjectFrame(CSkinnedMesh::SJoint *Parent)
575{
576#ifdef _XREADER_DEBUG
577 os::Printer::log("CXFileReader: Reading frame", ELL_DEBUG);
578#endif
579
580 // A coordinate frame, or "frame of reference." The Frame template
581 // is open and can contain any object. The Direct3D extensions (D3DX)
582 // mesh-loading functions recognize Mesh, FrameTransformMatrix, and
583 // Frame template instances as child objects when loading a Frame
584 // instance.
585
586 u32 JointID=0;
587
588 core::stringc name;
589
590 if (!readHeadOfDataObject(&name))
591 {
592 os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING);
593 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
594 return false;
595 }
596
597 CSkinnedMesh::SJoint *joint=0;
598
599 if (name.size())
600 {
601 for (u32 n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
602 {
603 if (AnimatedMesh->getAllJoints()[n]->Name==name)
604 {
605 joint=AnimatedMesh->getAllJoints()[n];
606 JointID=n;
607 break;
608 }
609 }
610 }
611
612 if (!joint)
613 {
614#ifdef _XREADER_DEBUG
615 os::Printer::log("creating joint ", name.c_str(), ELL_DEBUG);
616#endif
617 joint=AnimatedMesh->addJoint(Parent);
618 joint->Name=name;
619 JointID=AnimatedMesh->getAllJoints().size()-1;
620 }
621 else
622 {
623#ifdef _XREADER_DEBUG
624 os::Printer::log("using joint ", name.c_str(), ELL_DEBUG);
625#endif
626 if (Parent)
627 Parent->Children.push_back(joint);
628 }
629
630 // Now inside a frame.
631 // read tokens until closing brace is reached.
632
633 while(true)
634 {
635 core::stringc objectName = getNextToken();
636
637#ifdef _XREADER_DEBUG
638 os::Printer::log("debug DataObject in frame:", objectName.c_str(), ELL_DEBUG);
639#endif
640
641 if (objectName.size() == 0)
642 {
643 os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING);
644 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
645 return false;
646 }
647 else
648 if (objectName == "}")
649 {
650 break; // frame finished
651 }
652 else
653 if (objectName == "Frame")
654 {
655
656 if (!parseDataObjectFrame(joint))
657 return false;
658 }
659 else
660 if (objectName == "FrameTransformMatrix")
661 {
662 if (!parseDataObjectTransformationMatrix(joint->LocalMatrix))
663 return false;
664
665 //joint->LocalAnimatedMatrix
666 //joint->LocalAnimatedMatrix.makeInverse();
667 //joint->LocalMatrix=tmp*joint->LocalAnimatedMatrix;
668 }
669 else
670 if (objectName == "Mesh")
671 {
672 /*
673 frame.Meshes.push_back(SXMesh());
674 if (!parseDataObjectMesh(frame.Meshes.getLast()))
675 return false;
676 */
677 SXMesh *mesh=new SXMesh;
678
679 mesh->AttachedJointID=JointID;
680
681 Meshes.push_back(mesh);
682
683 if (!parseDataObjectMesh(*mesh))
684 return false;
685 }
686 else
687 {
688 os::Printer::log("Unknown data object in frame in x file", objectName.c_str(), ELL_WARNING);
689 if (!parseUnknownDataObject())
690 return false;
691 }
692 }
693
694 return true;
695}
696
697
698bool CXMeshFileLoader::parseDataObjectTransformationMatrix(core::matrix4 &mat)
699{
700#ifdef _XREADER_DEBUG
701 os::Printer::log("CXFileReader: Reading Transformation Matrix", ELL_DEBUG);
702#endif
703
704 if (!readHeadOfDataObject())
705 {
706 os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING);
707 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
708 return false;
709 }
710
711 readMatrix(mat);
712
713 if (!checkForOneFollowingSemicolons())
714 {
715 os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING);
716 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
717 }
718
719 if (!checkForClosingBrace())
720 {
721 os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING);
722 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
723 return false;
724 }
725
726 return true;
727}
728
729
730bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh)
731{
732 core::stringc name;
733
734 if (!readHeadOfDataObject(&name))
735 {
736#ifdef _XREADER_DEBUG
737 os::Printer::log("CXFileReader: Reading mesh", ELL_DEBUG);
738#endif
739 os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING);
740 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
741 return false;
742 }
743
744#ifdef _XREADER_DEBUG
745 os::Printer::log("CXFileReader: Reading mesh", name.c_str(), ELL_DEBUG);
746#endif
747
748 // read vertex count
749 const u32 nVertices = readInt();
750
751 // read vertices
752 mesh.Vertices.set_used(nVertices);
753 for (u32 n=0; n<nVertices; ++n)
754 {
755 readVector3(mesh.Vertices[n].Pos);
756 mesh.Vertices[n].Color=0xFFFFFFFF;
757 }
758
759 if (!checkForTwoFollowingSemicolons())
760 {
761 os::Printer::log("No finishing semicolon in Mesh Vertex Array found in x file", ELL_WARNING);
762 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
763 }
764
765 // read faces
766 const u32 nFaces = readInt();
767
768 mesh.Indices.set_used(nFaces * 3);
769 mesh.IndexCountPerFace.set_used(nFaces);
770
771 core::array<u32> polygonfaces;
772 u32 currentIndex = 0;
773
774 for (u32 k=0; k<nFaces; ++k)
775 {
776 const u32 fcnt = readInt();
777
778 if (fcnt != 3)
779 {
780 if (fcnt < 3)
781 {
782 os::Printer::log("Invalid face count (<3) found in Mesh x file reader.", ELL_WARNING);
783 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
784 return false;
785 }
786
787 // read face indices
788 polygonfaces.set_used(fcnt);
789 u32 triangles = (fcnt-2);
790 mesh.Indices.set_used(mesh.Indices.size() + ((triangles-1)*3));
791 mesh.IndexCountPerFace[k] = (u16)(triangles * 3);
792
793 for (u32 f=0; f<fcnt; ++f)
794 polygonfaces[f] = readInt();
795
796 for (u32 jk=0; jk<triangles; ++jk)
797 {
798 mesh.Indices[currentIndex++] = polygonfaces[0];
799 mesh.Indices[currentIndex++] = polygonfaces[jk+1];
800 mesh.Indices[currentIndex++] = polygonfaces[jk+2];
801 }
802
803 // TODO: change face indices in material list
804 }
805 else
806 {
807 mesh.Indices[currentIndex++] = readInt();
808 mesh.Indices[currentIndex++] = readInt();
809 mesh.Indices[currentIndex++] = readInt();
810 mesh.IndexCountPerFace[k] = 3;
811 }
812 }
813
814 if (!checkForTwoFollowingSemicolons())
815 {
816 os::Printer::log("No finishing semicolon in Mesh Face Array found in x file", ELL_WARNING);
817 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
818 }
819
820 // here, other data objects may follow
821
822 while(true)
823 {
824 core::stringc objectName = getNextToken();
825
826 if (objectName.size() == 0)
827 {
828 os::Printer::log("Unexpected ending found in Mesh in x file.", ELL_WARNING);
829 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
830 return false;
831 }
832 else
833 if (objectName == "}")
834 {
835 break; // mesh finished
836 }
837
838#ifdef _XREADER_DEBUG
839 os::Printer::log("debug DataObject in mesh:", objectName.c_str(), ELL_DEBUG);
840#endif
841
842 if (objectName == "MeshNormals")
843 {
844 if (!parseDataObjectMeshNormals(mesh))
845 return false;
846 }
847 else
848 if (objectName == "MeshTextureCoords")
849 {
850 if (!parseDataObjectMeshTextureCoords(mesh))
851 return false;
852 }
853 else
854 if (objectName == "MeshVertexColors")
855 {
856 if (!parseDataObjectMeshVertexColors(mesh))
857 return false;
858 }
859 else
860 if (objectName == "MeshMaterialList")
861 {
862 if (!parseDataObjectMeshMaterialList(mesh))
863 return false;
864 }
865 else
866 if (objectName == "VertexDuplicationIndices")
867 {
868 // we'll ignore vertex duplication indices
869 // TODO: read them
870 if (!parseUnknownDataObject())
871 return false;
872 }
873 else
874 if (objectName == "DeclData")
875 {
876 // arbitrary vertex attributes
877 // first comes the number of element definitions
878 // then the vertex element type definitions
879 // with format type;tesselator;semantics;usageindex
880 // we want to support 2;0;6;0 == tangent
881 // 2;0;7;0 == binormal
882 // 2;0;3;0 == normal
883 // 1/2;0;5;0 == 1st uv coord
884 // and 1/2;0;5;1 == 2nd uv coord
885 // type==2 is 3xf32, type==1 is 2xf32
886 u32 j;
887 const u32 dcnt = readInt();
888 u16 size = 0;
889 s16 normalpos = -1;
890 s16 uvpos = -1;
891 s16 uv2pos = -1;
892 s16 tangentpos = -1;
893 s16 binormalpos = -1;
894 s16 normaltype = -1;
895 s16 uvtype = -1;
896 s16 uv2type = -1;
897 s16 tangenttype = -1;
898 s16 binormaltype = -1;
899 for (j=0; j<dcnt; ++j)
900 {
901 const u32 type = readInt();
902 //const u32 tesselator = readInt();
903 readInt();
904 const u32 semantics = readInt();
905 const u32 index = readInt();
906 switch (semantics)
907 {
908 case 3:
909 normalpos = size;
910 normaltype = type;
911 break;
912 case 5:
913 if (index==0)
914 {
915 uvpos = size;
916 uvtype = type;
917 }
918 else if (index==1)
919 {
920 uv2pos = size;
921 uv2type = type;
922 }
923 break;
924 case 6:
925 tangentpos = size;
926 tangenttype = type;
927 break;
928 case 7:
929 binormalpos = size;
930 binormaltype = type;
931 break;
932 default:
933 break;
934 }
935 switch (type)
936 {
937 case 0:
938 size += 4;
939 break;
940 case 1:
941 size += 8;
942 break;
943 case 2:
944 size += 12;
945 break;
946 case 3:
947 size += 16;
948 break;
949 case 4:
950 case 5:
951 case 6:
952 size += 4;
953 break;
954 case 7:
955 size += 8;
956 break;
957 case 8:
958 case 9:
959 size += 4;
960 break;
961 case 10:
962 size += 8;
963 break;
964 case 11:
965 size += 4;
966 break;
967 case 12:
968 size += 8;
969 break;
970 case 13:
971 size += 4;
972 break;
973 case 14:
974 size += 4;
975 break;
976 case 15:
977 size += 4;
978 break;
979 case 16:
980 size += 8;
981 break;
982 }
983 }
984 const u32 datasize = readInt();
985 u32* data = new u32[datasize];
986 for (j=0; j<datasize; ++j)
987 data[j]=readInt();
988
989 if (!checkForOneFollowingSemicolons())
990 {
991 os::Printer::log("No finishing semicolon in DeclData found.", ELL_WARNING);
992 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
993 }
994 if (!checkForClosingBrace())
995 {
996 os::Printer::log("No closing brace in DeclData.", ELL_WARNING);
997 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
998 delete [] data;
999 return false;
1000 }
1001 u8* dataptr = (u8*) data;
1002 if ((uv2pos != -1) && (uv2type == 1))
1003 mesh.TCoords2.reallocate(mesh.Vertices.size());
1004 for (j=0; j<mesh.Vertices.size(); ++j)
1005 {
1006 if ((normalpos != -1) && (normaltype == 2))
1007 mesh.Vertices[j].Normal.set(*((core::vector3df*)(dataptr+normalpos)));
1008 if ((uvpos != -1) && (uvtype == 1))
1009 mesh.Vertices[j].TCoords.set(*((core::vector2df*)(dataptr+uvpos)));
1010 if ((uv2pos != -1) && (uv2type == 1))
1011 mesh.TCoords2.push_back(*((core::vector2df*)(dataptr+uv2pos)));
1012 dataptr += size;
1013 }
1014 delete [] data;
1015 }
1016 else
1017 if (objectName == "FVFData")
1018 {
1019 if (!readHeadOfDataObject())
1020 {
1021 os::Printer::log("No starting brace in FVFData found.", ELL_WARNING);
1022 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1023 return false;
1024 }
1025 const u32 dataformat = readInt();
1026 const u32 datasize = readInt();
1027 u32* data = new u32[datasize];
1028 for (u32 j=0; j<datasize; ++j)
1029 data[j]=readInt();
1030 if (dataformat&0x102) // 2nd uv set
1031 {
1032 mesh.TCoords2.reallocate(mesh.Vertices.size());
1033 u8* dataptr = (u8*) data;
1034 const u32 size=((dataformat>>8)&0xf)*sizeof(core::vector2df);
1035 for (u32 j=0; j<mesh.Vertices.size(); ++j)
1036 {
1037 mesh.TCoords2.push_back(*((core::vector2df*)(dataptr)));
1038 dataptr += size;
1039 }
1040 }
1041 delete [] data;
1042 if (!checkForOneFollowingSemicolons())
1043 {
1044 os::Printer::log("No finishing semicolon in FVFData found.", ELL_WARNING);
1045 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1046 }
1047 if (!checkForClosingBrace())
1048 {
1049 os::Printer::log("No closing brace in FVFData found in x file", ELL_WARNING);
1050 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1051 return false;
1052 }
1053 }
1054 else
1055 if (objectName == "XSkinMeshHeader")
1056 {
1057 if (!parseDataObjectSkinMeshHeader(mesh))
1058 return false;
1059 }
1060 else
1061 if (objectName == "SkinWeights")
1062 {
1063 //mesh.SkinWeights.push_back(SXSkinWeight());
1064 //if (!parseDataObjectSkinWeights(mesh.SkinWeights.getLast()))
1065 if (!parseDataObjectSkinWeights(mesh))
1066 return false;
1067 }
1068 else
1069 {
1070 os::Printer::log("Unknown data object in mesh in x file", objectName.c_str(), ELL_WARNING);
1071 if (!parseUnknownDataObject())
1072 return false;
1073 }
1074 }
1075
1076 return true;
1077}
1078
1079
1080bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh)
1081{
1082#ifdef _XREADER_DEBUG
1083 os::Printer::log("CXFileReader: Reading mesh skin weights", ELL_DEBUG);
1084#endif
1085
1086 if (!readHeadOfDataObject())
1087 {
1088 os::Printer::log("No opening brace in Skin Weights found in .x file", ELL_WARNING);
1089 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1090 return false;
1091 }
1092
1093 core::stringc TransformNodeName;
1094
1095 if (!getNextTokenAsString(TransformNodeName))
1096 {
1097 os::Printer::log("Unknown syntax while reading transfrom node name string in .x file", ELL_WARNING);
1098 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1099 return false;
1100 }
1101
1102 mesh.HasSkinning=true;
1103
1104 CSkinnedMesh::SJoint *joint=0;
1105
1106 u32 n;
1107 for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
1108 {
1109 if (AnimatedMesh->getAllJoints()[n]->Name==TransformNodeName)
1110 {
1111 joint=AnimatedMesh->getAllJoints()[n];
1112 break;
1113 }
1114 }
1115
1116 if (!joint)
1117 {
1118#ifdef _XREADER_DEBUG
1119 os::Printer::log("creating joint for skinning ", TransformNodeName.c_str(), ELL_DEBUG);
1120#endif
1121 n = AnimatedMesh->getAllJoints().size();
1122 joint=AnimatedMesh->addJoint(0);
1123 joint->Name=TransformNodeName;
1124 }
1125
1126 // read vertex weights
1127 const u32 nWeights = readInt();
1128
1129 // read vertex indices
1130 u32 i;
1131
1132 const u32 jointStart = joint->Weights.size();
1133 joint->Weights.reallocate(jointStart+nWeights);
1134
1135 mesh.WeightJoint.reallocate( mesh.WeightJoint.size() + nWeights );
1136 mesh.WeightNum.reallocate( mesh.WeightNum.size() + nWeights );
1137
1138 for (i=0; i<nWeights; ++i)
1139 {
1140 mesh.WeightJoint.push_back(n);
1141 mesh.WeightNum.push_back(joint->Weights.size());
1142
1143 CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(joint);
1144
1145 weight->buffer_id=0;
1146 weight->vertex_id=readInt();
1147 }
1148
1149 // read vertex weights
1150
1151 for (i=jointStart; i<jointStart+nWeights; ++i)
1152 joint->Weights[i].strength = readFloat();
1153
1154 // read matrix offset
1155
1156 // transforms the mesh vertices to the space of the bone
1157 // When concatenated to the bone's transform, this provides the
1158 // world space coordinates of the mesh as affected by the bone
1159 core::matrix4& MatrixOffset = joint->GlobalInversedMatrix;
1160
1161 readMatrix(MatrixOffset);
1162
1163 if (!checkForOneFollowingSemicolons())
1164 {
1165 os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING);
1166 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1167 }
1168
1169 if (!checkForClosingBrace())
1170 {
1171 os::Printer::log("No closing brace in Skin Weights found in x file", ELL_WARNING);
1172 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1173 return false;
1174 }
1175
1176 return true;
1177}
1178
1179
1180bool CXMeshFileLoader::parseDataObjectSkinMeshHeader(SXMesh& mesh)
1181{
1182#ifdef _XREADER_DEBUG
1183 os::Printer::log("CXFileReader: Reading skin mesh header", ELL_DEBUG);
1184#endif
1185
1186 if (!readHeadOfDataObject())
1187 {
1188 os::Printer::log("No opening brace in Skin Mesh header found in .x file", ELL_WARNING);
1189 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1190 return false;
1191 }
1192
1193 mesh.MaxSkinWeightsPerVertex = readInt();
1194 mesh.MaxSkinWeightsPerFace = readInt();
1195 mesh.BoneCount = readInt();
1196
1197 if (!BinaryFormat)
1198 getNextToken(); // skip semicolon
1199
1200 if (!checkForClosingBrace())
1201 {
1202 os::Printer::log("No closing brace in skin mesh header in x file", ELL_WARNING);
1203 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1204 return false;
1205 }
1206
1207 return true;
1208}
1209
1210
1211bool CXMeshFileLoader::parseDataObjectMeshNormals(SXMesh &mesh)
1212{
1213#ifdef _XREADER_DEBUG
1214 os::Printer::log("CXFileReader: reading mesh normals", ELL_DEBUG);
1215#endif
1216
1217 if (!readHeadOfDataObject())
1218 {
1219 os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING);
1220 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1221 return false;
1222 }
1223
1224 // read count
1225 const u32 nNormals = readInt();
1226 core::array<core::vector3df> normals;
1227 normals.set_used(nNormals);
1228
1229 // read normals
1230 for (u32 i=0; i<nNormals; ++i)
1231 readVector3(normals[i]);
1232
1233 if (!checkForTwoFollowingSemicolons())
1234 {
1235 os::Printer::log("No finishing semicolon in Mesh Normals Array found in x file", ELL_WARNING);
1236 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1237 }
1238
1239 core::array<u32> normalIndices;
1240 normalIndices.set_used(mesh.Indices.size());
1241
1242 // read face normal indices
1243 const u32 nFNormals = readInt();
1244
1245 u32 normalidx = 0;
1246 core::array<u32> polygonfaces;
1247 for (u32 k=0; k<nFNormals; ++k)
1248 {
1249 const u32 fcnt = readInt();
1250 u32 triangles = fcnt - 2;
1251 u32 indexcount = triangles * 3;
1252
1253 if (indexcount != mesh.IndexCountPerFace[k])
1254 {
1255 os::Printer::log("Not matching normal and face index count found in x file", ELL_WARNING);
1256 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1257 return false;
1258 }
1259
1260 if (indexcount == 3)
1261 {
1262 // default, only one triangle in this face
1263 for (u32 h=0; h<3; ++h)
1264 {
1265 const u32 normalnum = readInt();
1266 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[normalnum]);
1267 }
1268 }
1269 else
1270 {
1271 polygonfaces.set_used(fcnt);
1272 // multiple triangles in this face
1273 for (u32 h=0; h<fcnt; ++h)
1274 polygonfaces[h] = readInt();
1275
1276 for (u32 jk=0; jk<triangles; ++jk)
1277 {
1278 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[0]]);
1279 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+1]]);
1280 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+2]]);
1281 }
1282 }
1283 }
1284
1285 if (!checkForTwoFollowingSemicolons())
1286 {
1287 os::Printer::log("No finishing semicolon in Mesh Face Normals Array found in x file", ELL_WARNING);
1288 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1289 }
1290
1291 if (!checkForClosingBrace())
1292 {
1293 os::Printer::log("No closing brace in Mesh Normals found in x file", ELL_WARNING);
1294 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1295 return false;
1296 }
1297
1298 return true;
1299}
1300
1301
1302bool CXMeshFileLoader::parseDataObjectMeshTextureCoords(SXMesh &mesh)
1303{
1304#ifdef _XREADER_DEBUG
1305 os::Printer::log("CXFileReader: reading mesh texture coordinates", ELL_DEBUG);
1306#endif
1307
1308 if (!readHeadOfDataObject())
1309 {
1310 os::Printer::log("No opening brace in Mesh Texture Coordinates found in x file", ELL_WARNING);
1311 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1312 return false;
1313 }
1314
1315 const u32 nCoords = readInt();
1316 for (u32 i=0; i<nCoords; ++i)
1317 readVector2(mesh.Vertices[i].TCoords);
1318
1319 if (!checkForTwoFollowingSemicolons())
1320 {
1321 os::Printer::log("No finishing semicolon in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
1322 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1323 }
1324
1325 if (!checkForClosingBrace())
1326 {
1327 os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
1328 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1329 return false;
1330 }
1331
1332 return true;
1333}
1334
1335
1336bool CXMeshFileLoader::parseDataObjectMeshVertexColors(SXMesh &mesh)
1337{
1338#ifdef _XREADER_DEBUG
1339 os::Printer::log("CXFileReader: reading mesh vertex colors", ELL_DEBUG);
1340#endif
1341
1342 if (!readHeadOfDataObject())
1343 {
1344 os::Printer::log("No opening brace for Mesh Vertex Colors found in x file", ELL_WARNING);
1345 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1346 return false;
1347 }
1348
1349 mesh.HasVertexColors=true;
1350 const u32 nColors = readInt();
1351 for (u32 i=0; i<nColors; ++i)
1352 {
1353 const u32 Index=readInt();
1354 if (Index>=mesh.Vertices.size())
1355 {
1356 os::Printer::log("index value in parseDataObjectMeshVertexColors out of bounds", ELL_WARNING);
1357 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1358 return false;
1359 }
1360 readRGBA(mesh.Vertices[Index].Color);
1361 checkForOneFollowingSemicolons();
1362 }
1363
1364 if (!checkForOneFollowingSemicolons())
1365 {
1366 os::Printer::log("No finishing semicolon in Mesh Vertex Colors Array found in x file", ELL_WARNING);
1367 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1368 }
1369
1370 if (!checkForClosingBrace())
1371 {
1372 os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
1373 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1374 return false;
1375 }
1376
1377 return true;
1378}
1379
1380
1381bool CXMeshFileLoader::parseDataObjectMeshMaterialList(SXMesh &mesh)
1382{
1383#ifdef _XREADER_DEBUG
1384 os::Printer::log("CXFileReader: Reading mesh material list", ELL_DEBUG);
1385#endif
1386
1387 if (!readHeadOfDataObject())
1388 {
1389 os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING);
1390 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1391 return false;
1392 }
1393
1394 // read material count
1395 mesh.Materials.reallocate(readInt());
1396
1397 // read non triangulated face material index count
1398 const u32 nFaceIndices = readInt();
1399
1400 // There seems to be a compact representation of "all faces the same material"
1401 // being represented as 1;1;0;; which means 1 material, 1 face with first material
1402 // all the other faces have to obey then, so check is disabled
1403 //if (nFaceIndices != mesh.IndexCountPerFace.size())
1404 // os::Printer::log("Index count per face not equal to face material index count in x file.", ELL_WARNING);
1405
1406 // read non triangulated face indices and create triangulated ones
1407 mesh.FaceMaterialIndices.set_used( mesh.Indices.size() / 3);
1408 u32 triangulatedindex = 0;
1409 u32 ind = 0;
1410 for (u32 tfi=0; tfi<mesh.IndexCountPerFace.size(); ++tfi)
1411 {
1412 if (tfi<nFaceIndices)
1413 ind = readInt();
1414 const u32 fc = mesh.IndexCountPerFace[tfi]/3;
1415 for (u32 k=0; k<fc; ++k)
1416 mesh.FaceMaterialIndices[triangulatedindex++] = ind;
1417 }
1418
1419 // in version 03.02, the face indices end with two semicolons.
1420 // commented out version check, as version 03.03 exported from blender also has 2 semicolons
1421 if (!BinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
1422 {
1423 if (P[0] == ';')
1424 ++P;
1425 }
1426
1427 // read following data objects
1428
1429 while(true)
1430 {
1431 core::stringc objectName = getNextToken();
1432
1433 if (objectName.size() == 0)
1434 {
1435 os::Printer::log("Unexpected ending found in Mesh Material list in .x file.", ELL_WARNING);
1436 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1437 return false;
1438 }
1439 else
1440 if (objectName == "}")
1441 {
1442 break; // material list finished
1443 }
1444 else
1445 if (objectName == "{")
1446 {
1447 // template materials now available thanks to joeWright
1448 objectName = getNextToken();
1449 for (u32 i=0; i<TemplateMaterials.size(); ++i)
1450 if (TemplateMaterials[i].Name == objectName)
1451 mesh.Materials.push_back(TemplateMaterials[i].Material);
1452 getNextToken(); // skip }
1453 }
1454 else
1455 if (objectName == "Material")
1456 {
1457 mesh.Materials.push_back(video::SMaterial());
1458 if (!parseDataObjectMaterial(mesh.Materials.getLast()))
1459 return false;
1460 }
1461 else
1462 if (objectName == ";")
1463 {
1464 // ignore
1465 }
1466 else
1467 {
1468 os::Printer::log("Unknown data object in material list in x file", objectName.c_str(), ELL_WARNING);
1469 if (!parseUnknownDataObject())
1470 return false;
1471 }
1472 }
1473 return true;
1474}
1475
1476
1477bool CXMeshFileLoader::parseDataObjectMaterial(video::SMaterial& material)
1478{
1479#ifdef _XREADER_DEBUG
1480 os::Printer::log("CXFileReader: Reading mesh material", ELL_DEBUG);
1481#endif
1482
1483 if (!readHeadOfDataObject())
1484 {
1485 os::Printer::log("No opening brace in Mesh Material found in .x file", ELL_WARNING);
1486 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1487 return false;
1488 }
1489
1490 // read RGBA
1491 readRGBA(material.DiffuseColor); checkForOneFollowingSemicolons();
1492
1493 // read power
1494 material.Shininess = readFloat();
1495
1496 // read specular
1497 readRGB(material.SpecularColor); checkForOneFollowingSemicolons();
1498
1499 // read emissive
1500 readRGB(material.EmissiveColor); checkForOneFollowingSemicolons();
1501
1502 // read other data objects
1503 int textureLayer=0;
1504 while(true)
1505 {
1506 core::stringc objectName = getNextToken();
1507
1508 if (objectName.size() == 0)
1509 {
1510 os::Printer::log("Unexpected ending found in Mesh Material in .x file.", ELL_WARNING);
1511 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1512 return false;
1513 }
1514 else
1515 if (objectName == "}")
1516 {
1517 break; // material finished
1518 }
1519 else
1520 if (objectName.equals_ignore_case("TextureFilename"))
1521 {
1522 // some exporters write "TextureFileName" instead.
1523 core::stringc TextureFileName;
1524 if (!parseDataObjectTextureFilename(TextureFileName))
1525 return false;
1526
1527 // original name
1528 if (FileSystem->existFile(TextureFileName))
1529 material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName));
1530 // mesh path
1531 else
1532 {
1533 TextureFileName=FilePath + FileSystem->getFileBasename(TextureFileName);
1534 if (FileSystem->existFile(TextureFileName))
1535 material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName));
1536 // working directory
1537 else
1538 material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(FileSystem->getFileBasename(TextureFileName)));
1539 }
1540 ++textureLayer;
1541 if (textureLayer==2)
1542 material.MaterialType=video::EMT_LIGHTMAP;
1543 }
1544 else
1545 if (objectName.equals_ignore_case("NormalmapFilename"))
1546 {
1547 // some exporters write "NormalmapFileName" instead.
1548 core::stringc TextureFileName;
1549 if (!parseDataObjectTextureFilename(TextureFileName))
1550 return false;
1551
1552 // original name
1553 if (FileSystem->existFile(TextureFileName))
1554 material.setTexture(1, SceneManager->getVideoDriver()->getTexture(TextureFileName));
1555 // mesh path
1556 else
1557 {
1558 TextureFileName=FilePath + FileSystem->getFileBasename(TextureFileName);
1559 if (FileSystem->existFile(TextureFileName))
1560 material.setTexture(1, SceneManager->getVideoDriver()->getTexture(TextureFileName));
1561 // working directory
1562 else
1563 material.setTexture(1, SceneManager->getVideoDriver()->getTexture(FileSystem->getFileBasename(TextureFileName)));
1564 }
1565 if (textureLayer==1)
1566 ++textureLayer;
1567 }
1568 else
1569 {
1570 os::Printer::log("Unknown data object in material in .x file", objectName.c_str(), ELL_WARNING);
1571 if (!parseUnknownDataObject())
1572 return false;
1573 }
1574 }
1575
1576 return true;
1577}
1578
1579
1580bool CXMeshFileLoader::parseDataObjectAnimationSet()
1581{
1582#ifdef _XREADER_DEBUG
1583 os::Printer::log("CXFileReader: Reading animation set", ELL_DEBUG);
1584#endif
1585
1586 core::stringc AnimationName;
1587
1588 if (!readHeadOfDataObject(&AnimationName))
1589 {
1590 os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING);
1591 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1592 return false;
1593 }
1594 os::Printer::log("Reading animationset ", AnimationName, ELL_DEBUG);
1595
1596 while(true)
1597 {
1598 core::stringc objectName = getNextToken();
1599
1600 if (objectName.size() == 0)
1601 {
1602 os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING);
1603 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1604 return false;
1605 }
1606 else
1607 if (objectName == "}")
1608 {
1609 break; // animation set finished
1610 }
1611 else
1612 if (objectName == "Animation")
1613 {
1614 if (!parseDataObjectAnimation())
1615 return false;
1616 }
1617 else
1618 {
1619 os::Printer::log("Unknown data object in animation set in x file", objectName.c_str(), ELL_WARNING);
1620 if (!parseUnknownDataObject())
1621 return false;
1622 }
1623 }
1624 return true;
1625}
1626
1627
1628bool CXMeshFileLoader::parseDataObjectAnimation()
1629{
1630#ifdef _XREADER_DEBUG
1631 os::Printer::log("CXFileReader: reading animation", ELL_DEBUG);
1632#endif
1633
1634 if (!readHeadOfDataObject())
1635 {
1636 os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING);
1637 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1638 return false;
1639 }
1640
1641 //anim.closed = true;
1642 //anim.linearPositionQuality = true;
1643 CSkinnedMesh::SJoint animationDump;
1644
1645 core::stringc FrameName;
1646
1647 while(true)
1648 {
1649 core::stringc objectName = getNextToken();
1650
1651 if (objectName.size() == 0)
1652 {
1653 os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
1654 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1655 return false;
1656 }
1657 else
1658 if (objectName == "}")
1659 {
1660 break; // animation finished
1661 }
1662 else
1663 if (objectName == "AnimationKey")
1664 {
1665 if (!parseDataObjectAnimationKey(&animationDump))
1666 return false;
1667 }
1668 else
1669 if (objectName == "AnimationOptions")
1670 {
1671 //TODO: parse options.
1672 if (!parseUnknownDataObject())
1673 return false;
1674 }
1675 else
1676 if (objectName == "{")
1677 {
1678 // read frame name
1679 FrameName = getNextToken();
1680
1681 if (!checkForClosingBrace())
1682 {
1683 os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
1684 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1685 return false;
1686 }
1687 }
1688 else
1689 {
1690 os::Printer::log("Unknown data object in animation in x file", objectName.c_str(), ELL_WARNING);
1691 if (!parseUnknownDataObject())
1692 return false;
1693 }
1694 }
1695
1696 if (FrameName.size() != 0)
1697 {
1698#ifdef _XREADER_DEBUG
1699 os::Printer::log("frame name", FrameName.c_str(), ELL_DEBUG);
1700#endif
1701 CSkinnedMesh::SJoint *joint=0;
1702
1703 u32 n;
1704 for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
1705 {
1706 if (AnimatedMesh->getAllJoints()[n]->Name==FrameName)
1707 {
1708 joint=AnimatedMesh->getAllJoints()[n];
1709 break;
1710 }
1711 }
1712
1713 if (!joint)
1714 {
1715#ifdef _XREADER_DEBUG
1716 os::Printer::log("creating joint for animation ", FrameName.c_str(), ELL_DEBUG);
1717#endif
1718 joint=AnimatedMesh->addJoint(0);
1719 joint->Name=FrameName;
1720 }
1721
1722 joint->PositionKeys.reallocate(joint->PositionKeys.size()+animationDump.PositionKeys.size());
1723 for (n=0; n<animationDump.PositionKeys.size(); ++n)
1724 {
1725 joint->PositionKeys.push_back(animationDump.PositionKeys[n]);
1726 }
1727
1728 joint->ScaleKeys.reallocate(joint->ScaleKeys.size()+animationDump.ScaleKeys.size());
1729 for (n=0; n<animationDump.ScaleKeys.size(); ++n)
1730 {
1731 joint->ScaleKeys.push_back(animationDump.ScaleKeys[n]);
1732 }
1733
1734 joint->RotationKeys.reallocate(joint->RotationKeys.size()+animationDump.RotationKeys.size());
1735 for (n=0; n<animationDump.RotationKeys.size(); ++n)
1736 {
1737 joint->RotationKeys.push_back(animationDump.RotationKeys[n]);
1738 }
1739 }
1740 else
1741 os::Printer::log("joint name was never given", ELL_WARNING);
1742
1743 return true;
1744}
1745
1746
1747bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint)
1748{
1749#ifdef _XREADER_DEBUG
1750 os::Printer::log("CXFileReader: reading animation key", ELL_DEBUG);
1751#endif
1752
1753 if (!readHeadOfDataObject())
1754 {
1755 os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING);
1756 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1757 return false;
1758 }
1759
1760 // read key type
1761
1762 const u32 keyType = readInt();
1763
1764 if (keyType > 4)
1765 {
1766 os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING);
1767 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1768 return false;
1769 }
1770
1771 // read number of keys
1772 const u32 numberOfKeys = readInt();
1773
1774 // eat the semicolon after the "0". if there are keys present, readInt()
1775 // does this for us. If there aren't, we need to do it explicitly
1776 if (numberOfKeys == 0)
1777 checkForOneFollowingSemicolons();
1778
1779 for (u32 i=0; i<numberOfKeys; ++i)
1780 {
1781 // read time
1782 const f32 time = (f32)readInt();
1783
1784 // read keys
1785 switch(keyType)
1786 {
1787 case 0: //rotation
1788 {
1789 //read quaternions
1790
1791 // read count
1792 if (readInt() != 4)
1793 {
1794 os::Printer::log("Expected 4 numbers in animation key in x file", ELL_WARNING);
1795 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1796 return false;
1797 }
1798
1799 f32 W = -readFloat();
1800 f32 X = -readFloat();
1801 f32 Y = -readFloat();
1802 f32 Z = -readFloat();
1803
1804 if (!checkForTwoFollowingSemicolons())
1805 {
1806 os::Printer::log("No finishing semicolon after quaternion animation key in x file", ELL_WARNING);
1807 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1808 }
1809
1810 ISkinnedMesh::SRotationKey *key=AnimatedMesh->addRotationKey(joint);
1811 key->frame=time;
1812 key->rotation.set(X,Y,Z,W);
1813 }
1814 break;
1815 case 1: //scale
1816 case 2: //position
1817 {
1818 // read vectors
1819
1820 // read count
1821 if (readInt() != 3)
1822 {
1823 os::Printer::log("Expected 3 numbers in animation key in x file", ELL_WARNING);
1824 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1825 return false;
1826 }
1827
1828 core::vector3df vector;
1829 readVector3(vector);
1830
1831 if (!checkForTwoFollowingSemicolons())
1832 {
1833 os::Printer::log("No finishing semicolon after vector animation key in x file", ELL_WARNING);
1834 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1835 }
1836
1837 if (keyType==2)
1838 {
1839 ISkinnedMesh::SPositionKey *key=AnimatedMesh->addPositionKey(joint);
1840 key->frame=time;
1841 key->position=vector;
1842 }
1843 else
1844 {
1845 ISkinnedMesh::SScaleKey *key=AnimatedMesh->addScaleKey(joint);
1846 key->frame=time;
1847 key->scale=vector;
1848 }
1849 }
1850 break;
1851 case 3:
1852 case 4:
1853 {
1854 // read matrix
1855
1856 // read count
1857 if (readInt() != 16)
1858 {
1859 os::Printer::log("Expected 16 numbers in animation key in x file", ELL_WARNING);
1860 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1861 return false;
1862 }
1863
1864 // read matrix
1865 core::matrix4 mat(core::matrix4::EM4CONST_NOTHING);
1866 readMatrix(mat);
1867
1868 //mat=joint->LocalMatrix*mat;
1869
1870 if (!checkForOneFollowingSemicolons())
1871 {
1872 os::Printer::log("No finishing semicolon after matrix animation key in x file", ELL_WARNING);
1873 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1874 }
1875
1876 //core::vector3df rotation = mat.getRotationDegrees();
1877
1878 ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint);
1879 keyR->frame=time;
1880
1881 // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility.
1882 // Not tested so far if this was correct or wrong before quaternion fix!
1883 keyR->rotation= core::quaternion(mat.getTransposed());
1884
1885 ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->addPositionKey(joint);
1886 keyP->frame=time;
1887 keyP->position=mat.getTranslation();
1888
1889/*
1890 core::vector3df scale=mat.getScale();
1891
1892 if (scale.X==0)
1893 scale.X=1;
1894 if (scale.Y==0)
1895 scale.Y=1;
1896 if (scale.Z==0)
1897 scale.Z=1;
1898 ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->addScaleKey(joint);
1899 keyS->frame=time;
1900 keyS->scale=scale;
1901*/
1902 }
1903 break;
1904 } // end switch
1905 }
1906
1907 if (!checkForOneFollowingSemicolons())
1908 --P;
1909
1910 if (!checkForClosingBrace())
1911 {
1912 os::Printer::log("No closing brace in animation key in x file", ELL_WARNING);
1913 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1914 return false;
1915 }
1916
1917 return true;
1918}
1919
1920
1921bool CXMeshFileLoader::parseDataObjectTextureFilename(core::stringc& texturename)
1922{
1923#ifdef _XREADER_DEBUG
1924 os::Printer::log("CXFileReader: reading texture filename", ELL_DEBUG);
1925#endif
1926
1927 if (!readHeadOfDataObject())
1928 {
1929 os::Printer::log("No opening brace in Texture filename found in x file", ELL_WARNING);
1930 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1931 return false;
1932 }
1933
1934 if (!getNextTokenAsString(texturename))
1935 {
1936 os::Printer::log("Unknown syntax while reading texture filename string in x file", ELL_WARNING);
1937 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1938 return false;
1939 }
1940
1941 if (!checkForClosingBrace())
1942 {
1943 os::Printer::log("No closing brace in Texture filename found in x file", ELL_WARNING);
1944 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
1945 return false;
1946 }
1947
1948 return true;
1949}
1950
1951
1952bool CXMeshFileLoader::parseUnknownDataObject()
1953{
1954 // find opening delimiter
1955 while(true)
1956 {
1957 core::stringc t = getNextToken();
1958
1959 if (t.size() == 0)
1960 return false;
1961
1962 if (t == "{")
1963 break;
1964 }
1965
1966 u32 counter = 1;
1967
1968 // parse until closing delimiter
1969
1970 while(counter)
1971 {
1972 core::stringc t = getNextToken();
1973
1974 if (t.size() == 0)
1975 return false;
1976
1977 if (t == "{")
1978 ++counter;
1979 else
1980 if (t == "}")
1981 --counter;
1982 }
1983
1984 return true;
1985}
1986
1987
1988//! checks for closing curly brace, returns false if not there
1989bool CXMeshFileLoader::checkForClosingBrace()
1990{
1991 return (getNextToken() == "}");
1992}
1993
1994
1995//! checks for one following semicolon, returns false if not there
1996bool CXMeshFileLoader::checkForOneFollowingSemicolons()
1997{
1998 if (BinaryFormat)
1999 return true;
2000
2001 if (getNextToken() == ";")
2002 return true;
2003 else
2004 {
2005 --P;
2006 return false;
2007 }
2008}
2009
2010
2011//! checks for two following semicolons, returns false if they are not there
2012bool CXMeshFileLoader::checkForTwoFollowingSemicolons()
2013{
2014 if (BinaryFormat)
2015 return true;
2016
2017 for (u32 k=0; k<2; ++k)
2018 {
2019 if (getNextToken() != ";")
2020 {
2021 --P;
2022 return false;
2023 }
2024 }
2025
2026 return true;
2027}
2028
2029
2030//! reads header of dataobject including the opening brace.
2031//! returns false if error happened, and writes name of object
2032//! if there is one
2033bool CXMeshFileLoader::readHeadOfDataObject(core::stringc* outname)
2034{
2035 core::stringc nameOrBrace = getNextToken();
2036 if (nameOrBrace != "{")
2037 {
2038 if (outname)
2039 (*outname) = nameOrBrace;
2040
2041 if (getNextToken() != "{")
2042 return false;
2043 }
2044
2045 return true;
2046}
2047
2048
2049//! returns next parseable token. Returns empty string if no token there
2050core::stringc CXMeshFileLoader::getNextToken()
2051{
2052 core::stringc s;
2053
2054 // process binary-formatted file
2055 if (BinaryFormat)
2056 {
2057 // in binary mode it will only return NAME and STRING token
2058 // and (correctly) skip over other tokens.
2059
2060 s16 tok = readBinWord();
2061 u32 len;
2062
2063 // standalone tokens
2064 switch (tok) {
2065 case 1:
2066 // name token
2067 len = readBinDWord();
2068 s = core::stringc(P, len);
2069 P += len;
2070 return s;
2071 case 2:
2072 // string token
2073 len = readBinDWord();
2074 s = core::stringc(P, len);
2075 P += (len + 2);
2076 return s;
2077 case 3:
2078 // integer token
2079 P += 4;
2080 return "<integer>";
2081 case 5:
2082 // GUID token
2083 P += 16;
2084 return "<guid>";
2085 case 6:
2086 len = readBinDWord();
2087 P += (len * 4);
2088 return "<int_list>";
2089 case 7:
2090 len = readBinDWord();
2091 P += (len * FloatSize);
2092 return "<flt_list>";
2093 case 0x0a:
2094 return "{";
2095 case 0x0b:
2096 return "}";
2097 case 0x0c:
2098 return "(";
2099 case 0x0d:
2100 return ")";
2101 case 0x0e:
2102 return "[";
2103 case 0x0f:
2104 return "]";
2105 case 0x10:
2106 return "<";
2107 case 0x11:
2108 return ">";
2109 case 0x12:
2110 return ".";
2111 case 0x13:
2112 return ",";
2113 case 0x14:
2114 return ";";
2115 case 0x1f:
2116 return "template";
2117 case 0x28:
2118 return "WORD";
2119 case 0x29:
2120 return "DWORD";
2121 case 0x2a:
2122 return "FLOAT";
2123 case 0x2b:
2124 return "DOUBLE";
2125 case 0x2c:
2126 return "CHAR";
2127 case 0x2d:
2128 return "UCHAR";
2129 case 0x2e:
2130 return "SWORD";
2131 case 0x2f:
2132 return "SDWORD";
2133 case 0x30:
2134 return "void";
2135 case 0x31:
2136 return "string";
2137 case 0x32:
2138 return "unicode";
2139 case 0x33:
2140 return "cstring";
2141 case 0x34:
2142 return "array";
2143 }
2144 }
2145 // process text-formatted file
2146 else
2147 {
2148 findNextNoneWhiteSpace();
2149
2150 if (P >= End)
2151 return s;
2152
2153 while((P < End) && !core::isspace(P[0]))
2154 {
2155 // either keep token delimiters when already holding a token, or return if first valid char
2156 if (P[0]==';' || P[0]=='}' || P[0]=='{' || P[0]==',')
2157 {
2158 if (!s.size())
2159 {
2160 s.append(P[0]);
2161 ++P;
2162 }
2163 break; // stop for delimiter
2164 }
2165 s.append(P[0]);
2166 ++P;
2167 }
2168 }
2169 return s;
2170}
2171
2172
2173//! places pointer to next begin of a token, which must be a number,
2174// and ignores comments
2175void CXMeshFileLoader::findNextNoneWhiteSpaceNumber()
2176{
2177 if (BinaryFormat)
2178 return;
2179
2180 while((P < End) && (P[0] != '-') && (P[0] != '.') &&
2181 !( core::isdigit(P[0])))
2182 {
2183 // check if this is a comment
2184 if ((P[0] == '/' && P[1] == '/') || P[0] == '#')
2185 readUntilEndOfLine();
2186 else
2187 ++P;
2188 }
2189}
2190
2191
2192// places pointer to next begin of a token, and ignores comments
2193void CXMeshFileLoader::findNextNoneWhiteSpace()
2194{
2195 if (BinaryFormat)
2196 return;
2197
2198 while(true)
2199 {
2200 while((P < End) && core::isspace(P[0]))
2201 {
2202 if (*P=='\n')
2203 ++Line;
2204 ++P;
2205 }
2206
2207 if (P >= End)
2208 return;
2209
2210 // check if this is a comment
2211 if ((P[0] == '/' && P[1] == '/') ||
2212 P[0] == '#')
2213 readUntilEndOfLine();
2214 else
2215 break;
2216 }
2217}
2218
2219
2220//! reads a x file style string
2221bool CXMeshFileLoader::getNextTokenAsString(core::stringc& out)
2222{
2223 if (BinaryFormat)
2224 {
2225 out=getNextToken();
2226 return true;
2227 }
2228 findNextNoneWhiteSpace();
2229
2230 if (P >= End)
2231 return false;
2232
2233 if (P[0] != '"')
2234 return false;
2235 ++P;
2236
2237 while(P < End && P[0]!='"')
2238 {
2239 out.append(P[0]);
2240 ++P;
2241 }
2242
2243 if ( P[1] != ';' || P[0] != '"')
2244 return false;
2245 P+=2;
2246
2247 return true;
2248}
2249
2250
2251void CXMeshFileLoader::readUntilEndOfLine()
2252{
2253 if (BinaryFormat)
2254 return;
2255
2256 while(P < End)
2257 {
2258 if (P[0] == '\n' || P[0] == '\r')
2259 {
2260 ++P;
2261 ++Line;
2262 return;
2263 }
2264
2265 ++P;
2266 }
2267}
2268
2269
2270u16 CXMeshFileLoader::readBinWord()
2271{
2272 if (P>=End)
2273 return 0;
2274#ifdef __BIG_ENDIAN__
2275 const u16 tmp = os::Byteswap::byteswap(*(u16 *)P);
2276#else
2277 const u16 tmp = *(u16 *)P;
2278#endif
2279 P += 2;
2280 return tmp;
2281}
2282
2283
2284u32 CXMeshFileLoader::readBinDWord()
2285{
2286 if (P>=End)
2287 return 0;
2288#ifdef __BIG_ENDIAN__
2289 const u32 tmp = os::Byteswap::byteswap(*(u32 *)P);
2290#else
2291 const u32 tmp = *(u32 *)P;
2292#endif
2293 P += 4;
2294 return tmp;
2295}
2296
2297
2298u32 CXMeshFileLoader::readInt()
2299{
2300 if (BinaryFormat)
2301 {
2302 if (!BinaryNumCount)
2303 {
2304 const u16 tmp = readBinWord(); // 0x06 or 0x03
2305 if (tmp == 0x06)
2306 BinaryNumCount = readBinDWord();
2307 else
2308 BinaryNumCount = 1; // single int
2309 }
2310 --BinaryNumCount;
2311 return readBinDWord();
2312 }
2313 else
2314 {
2315 findNextNoneWhiteSpaceNumber();
2316 return core::strtoul10(P, &P);
2317 }
2318}
2319
2320
2321f32 CXMeshFileLoader::readFloat()
2322{
2323 if (BinaryFormat)
2324 {
2325 if (!BinaryNumCount)
2326 {
2327 const u16 tmp = readBinWord(); // 0x07 or 0x42
2328 if (tmp == 0x07)
2329 BinaryNumCount = readBinDWord();
2330 else
2331 BinaryNumCount = 1; // single int
2332 }
2333 --BinaryNumCount;
2334 if (FloatSize == 8)
2335 {
2336#ifdef __BIG_ENDIAN__
2337 //TODO: Check if data is properly converted here
2338 f32 ctmp[2];
2339 ctmp[1] = os::Byteswap::byteswap(*(f32*)P);
2340 ctmp[0] = os::Byteswap::byteswap(*(f32*)P+4);
2341 const f32 tmp = (f32)(*(f64*)(void*)ctmp);
2342#else
2343 const f32 tmp = (f32)(*(f64 *)P);
2344#endif
2345 P += 8;
2346 return tmp;
2347 }
2348 else
2349 {
2350#ifdef __BIG_ENDIAN__
2351 const f32 tmp = os::Byteswap::byteswap(*(f32 *)P);
2352#else
2353 const f32 tmp = *(f32 *)P;
2354#endif
2355 P += 4;
2356 return tmp;
2357 }
2358 }
2359 findNextNoneWhiteSpaceNumber();
2360 f32 ftmp;
2361 P = core::fast_atof_move(P, ftmp);
2362 return ftmp;
2363}
2364
2365
2366// read 2-dimensional vector. Stops at semicolon after second value for text file format
2367bool CXMeshFileLoader::readVector2(core::vector2df& vec)
2368{
2369 vec.X = readFloat();
2370 vec.Y = readFloat();
2371 return true;
2372}
2373
2374
2375// read 3-dimensional vector. Stops at semicolon after third value for text file format
2376bool CXMeshFileLoader::readVector3(core::vector3df& vec)
2377{
2378 vec.X = readFloat();
2379 vec.Y = readFloat();
2380 vec.Z = readFloat();
2381 return true;
2382}
2383
2384
2385// read color without alpha value. Stops after second semicolon after blue value
2386bool CXMeshFileLoader::readRGB(video::SColor& color)
2387{
2388 video::SColorf tmpColor;
2389 tmpColor.r = readFloat();
2390 tmpColor.g = readFloat();
2391 tmpColor.b = readFloat();
2392 color = tmpColor.toSColor();
2393 return checkForOneFollowingSemicolons();
2394}
2395
2396
2397// read color with alpha value. Stops after second semicolon after blue value
2398bool CXMeshFileLoader::readRGBA(video::SColor& color)
2399{
2400 video::SColorf tmpColor;
2401 tmpColor.r = readFloat();
2402 tmpColor.g = readFloat();
2403 tmpColor.b = readFloat();
2404 tmpColor.a = readFloat();
2405 color = tmpColor.toSColor();
2406 return checkForOneFollowingSemicolons();
2407}
2408
2409
2410// read matrix from list of floats
2411bool CXMeshFileLoader::readMatrix(core::matrix4& mat)
2412{
2413 for (u32 i=0; i<16; ++i)
2414 mat[i] = readFloat();
2415 return checkForOneFollowingSemicolons();
2416}
2417
2418
2419} // end namespace scene
2420} // end namespace irr
2421
2422#endif // _IRR_COMPILE_WITH_X_LOADER_
2423