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