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