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