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
6 #include "CXMeshFileLoader.h"
\r
9 #include "fast_atof.h"
\r
10 #include "coreutil.h"
\r
11 #include "ISceneManager.h"
\r
12 #include "IVideoDriver.h"
\r
13 #include "IFileSystem.h"
\r
14 #include "IReadFile.h"
\r
17 #define _XREADER_DEBUG
\r
19 //#define BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
27 CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs)
\r
28 : AnimatedMesh(0), Buffer(0), P(0), End(0), BinaryNumCount(0), Line(0),
\r
29 CurFrame(0), MajorVersion(0), MinorVersion(0), BinaryFormat(false), FloatSize(0)
\r
32 setDebugName("CXMeshFileLoader");
\r
37 //! returns true if the file maybe is able to be loaded by this class
\r
38 //! based on the file extension (e.g. ".bsp")
\r
39 bool CXMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
\r
41 return core::hasFileExtension ( filename, "x" );
\r
45 //! creates/loads an animated mesh from the file.
\r
46 //! \return Pointer to the created mesh. Returns 0 if loading failed.
\r
47 //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
\r
48 //! See IReferenceCounted::drop() for more information.
\r
49 IAnimatedMesh* CXMeshFileLoader::createMesh(io::IReadFile* file)
\r
54 #ifdef _XREADER_DEBUG
\r
55 u32 time = os::Timer::getRealTime();
\r
58 AnimatedMesh = new CSkinnedMesh();
\r
62 AnimatedMesh->finalize();
\r
66 AnimatedMesh->drop();
\r
69 #ifdef _XREADER_DEBUG
\r
70 time = os::Timer::getRealTime() - time;
\r
71 core::stringc tmpString = "Time to load ";
\r
72 tmpString += BinaryFormat ? "binary" : "ascii";
\r
73 tmpString += " X file: ";
\r
76 os::Printer::log(tmpString.c_str());
\r
92 for (u32 i=0; i<Meshes.size(); ++i)
\r
96 return AnimatedMesh;
\r
100 bool CXMeshFileLoader::load(io::IReadFile* file)
\r
102 if (!readFileIntoMemory(file))
\r
108 for (u32 n=0; n<Meshes.size(); ++n)
\r
110 SXMesh *mesh=Meshes[n];
\r
112 // default material if nothing loaded
\r
113 if (!mesh->Materials.size())
\r
115 mesh->Materials.push_back(video::SMaterial());
\r
116 mesh->Materials[0].DiffuseColor.set(0xff777777);
\r
117 mesh->Materials[0].Shininess=0.f;
\r
118 mesh->Materials[0].SpecularColor.set(0xff777777);
\r
119 mesh->Materials[0].EmissiveColor.set(0xff000000);
\r
124 mesh->Buffers.reallocate(mesh->Materials.size());
\r
125 #ifndef BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
126 const u32 bufferOffset = AnimatedMesh->getMeshBufferCount();
\r
128 for (i=0; i<mesh->Materials.size(); ++i)
\r
130 mesh->Buffers.push_back( AnimatedMesh->addMeshBuffer() );
\r
131 mesh->Buffers.getLast()->Material = mesh->Materials[i];
\r
133 if (!mesh->HasSkinning)
\r
135 //Set up rigid animation
\r
136 if (mesh->AttachedJointID!=-1)
\r
138 AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back( AnimatedMesh->getMeshBuffers().size()-1 );
\r
143 if (!mesh->FaceMaterialIndices.size())
\r
145 mesh->FaceMaterialIndices.set_used(mesh->Indices.size() / 3);
\r
146 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
147 mesh->FaceMaterialIndices[i]=0;
\r
150 if (!mesh->HasVertexColors)
\r
152 for (u32 j=0;j<mesh->FaceMaterialIndices.size();++j)
\r
154 for (u32 id=j*3+0;id<=j*3+2;++id)
\r
156 mesh->Vertices[ mesh->Indices[id] ].Color = mesh->Buffers[mesh->FaceMaterialIndices[j]]->Material.DiffuseColor;
\r
161 #ifdef BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
163 //the same vertex can be used in many different meshbuffers, but it's slow to work out
\r
165 core::array< core::array< u32 > > verticesLinkIndex;
\r
166 verticesLinkIndex.reallocate(mesh->Vertices.size());
\r
167 core::array< core::array< u16 > > verticesLinkBuffer;
\r
168 verticesLinkBuffer.reallocate(mesh->Vertices.size());
\r
170 for (i=0;i<mesh->Vertices.size();++i)
\r
172 verticesLinkIndex.push_back( core::array< u32 >() );
\r
173 verticesLinkBuffer.push_back( core::array< u16 >() );
\r
176 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
178 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
180 core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
\r
183 for (u32 j=0; j < Array.size(); ++j)
\r
185 if (Array[j]==mesh->FaceMaterialIndices[i])
\r
193 Array.push_back( mesh->FaceMaterialIndices[i] );
\r
197 for (i=0;i<verticesLinkBuffer.size();++i)
\r
199 if (!verticesLinkBuffer[i].size())
\r
200 verticesLinkBuffer[i].push_back(0);
\r
203 for (i=0;i<mesh->Vertices.size();++i)
\r
205 core::array< u16 > &Array = verticesLinkBuffer[i];
\r
206 verticesLinkIndex[i].reallocate(Array.size());
\r
207 for (u32 j=0; j < Array.size(); ++j)
\r
209 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ Array[j] ];
\r
210 verticesLinkIndex[i].push_back( buffer->Vertices_Standard.size() );
\r
211 buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
\r
215 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
217 scene::SSkinMeshBuffer *buffer=mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
\r
219 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
221 core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
\r
223 for (u32 j=0;j< Array.size() ;++j)
\r
225 if ( Array[j]== mesh->FaceMaterialIndices[i] )
\r
226 buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ][j] );
\r
231 for (u32 j=0;j<mesh->WeightJoint.size();++j)
\r
233 ISkinnedMesh::SJoint* joint = AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]];
\r
234 ISkinnedMesh::SWeight& weight = joint->Weights[mesh->WeightNum[j]];
\r
236 u32 id = weight.vertex_id;
\r
238 if (id>=verticesLinkIndex.size())
\r
240 os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
\r
242 weight.strength=0.f;
\r
245 if (verticesLinkBuffer[id].size()==1)
\r
247 weight.vertex_id=verticesLinkIndex[id][0];
\r
248 weight.buffer_id=verticesLinkBuffer[id][0];
\r
250 else if (verticesLinkBuffer[id].size() != 0)
\r
252 for (u32 k=1; k < verticesLinkBuffer[id].size(); ++k)
\r
254 ISkinnedMesh::SWeight* WeightClone = AnimatedMesh->addWeight(joint);
\r
255 WeightClone->strength = weight.strength;
\r
256 WeightClone->vertex_id = verticesLinkIndex[id][k];
\r
257 WeightClone->buffer_id = verticesLinkBuffer[id][k];
\r
264 core::array< u32 > verticesLinkIndex;
\r
265 core::array< s16 > verticesLinkBuffer;
\r
266 verticesLinkBuffer.set_used(mesh->Vertices.size());
\r
269 for (i=0;i<mesh->Vertices.size();++i)
\r
271 // watch out for vertices which are not part of the mesh
\r
272 // they will keep the -1 and can lead to out-of-bounds access
\r
273 verticesLinkBuffer[i]=-1;
\r
276 bool warned = false;
\r
277 // store meshbuffer number per vertex
\r
278 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
280 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
282 if ((verticesLinkBuffer[mesh->Indices[id]] != -1) && (verticesLinkBuffer[mesh->Indices[id]] != (s16)mesh->FaceMaterialIndices[i]))
\r
286 os::Printer::log("X loader", "Duplicated vertex, animation might be corrupted.", ELL_WARNING);
\r
289 const u32 tmp = mesh->Vertices.size();
\r
290 mesh->Vertices.push_back(mesh->Vertices[ mesh->Indices[id] ]);
\r
291 mesh->Indices[id] = tmp;
\r
292 verticesLinkBuffer.set_used(mesh->Vertices.size());
\r
294 verticesLinkBuffer[ mesh->Indices[id] ] = mesh->FaceMaterialIndices[i];
\r
298 if (mesh->FaceMaterialIndices.size() != 0)
\r
300 // store vertices in buffers and remember relation in verticesLinkIndex
\r
301 u32* vCountArray = new u32[mesh->Buffers.size()];
\r
302 memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
\r
303 // count vertices in each buffer and reallocate
\r
304 for (i=0; i<mesh->Vertices.size(); ++i)
\r
306 if (verticesLinkBuffer[i] != -1)
\r
307 ++vCountArray[verticesLinkBuffer[i]];
\r
309 if (mesh->TCoords2.size())
\r
311 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
313 mesh->Buffers[i]->Vertices_2TCoords.reallocate(vCountArray[i]);
\r
314 mesh->Buffers[i]->VertexType=video::EVT_2TCOORDS;
\r
319 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
320 mesh->Buffers[i]->Vertices_Standard.reallocate(vCountArray[i]);
\r
323 verticesLinkIndex.set_used(mesh->Vertices.size());
\r
324 // actually store vertices
\r
325 for (i=0; i<mesh->Vertices.size(); ++i)
\r
327 // if a vertex is missing for some reason, just skip it
\r
328 if (verticesLinkBuffer[i]==-1)
\r
330 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ verticesLinkBuffer[i] ];
\r
332 if (mesh->TCoords2.size())
\r
334 verticesLinkIndex[i] = buffer->Vertices_2TCoords.size();
\r
335 buffer->Vertices_2TCoords.push_back( mesh->Vertices[i] );
\r
336 // We have a problem with correct tcoord2 handling here
\r
337 // crash fixed for now by checking the values
\r
338 buffer->Vertices_2TCoords.getLast().TCoords2=(i<mesh->TCoords2.size())?mesh->TCoords2[i]:mesh->Vertices[i].TCoords;
\r
342 verticesLinkIndex[i] = buffer->Vertices_Standard.size();
\r
343 buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
\r
347 // count indices per buffer and reallocate
\r
348 memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
\r
349 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
350 ++vCountArray[ mesh->FaceMaterialIndices[i] ];
\r
351 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
352 mesh->Buffers[i]->Indices.reallocate(vCountArray[i]);
\r
353 delete [] vCountArray;
\r
354 // create indices per buffer
\r
355 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
357 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
\r
358 for (u32 id=i*3+0; id!=i*3+3; ++id)
\r
360 buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ] );
\r
365 for (u32 j=0; j<mesh->WeightJoint.size(); ++j)
\r
367 ISkinnedMesh::SWeight& weight = (AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]->Weights[mesh->WeightNum[j]]);
\r
369 u32 id = weight.vertex_id;
\r
371 if (id>=verticesLinkIndex.size())
\r
373 os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
\r
375 weight.strength=0.f;
\r
378 weight.vertex_id=verticesLinkIndex[id];
\r
379 weight.buffer_id=verticesLinkBuffer[id] + bufferOffset;
\r
390 //! Reads file into memory
\r
391 bool CXMeshFileLoader::readFileIntoMemory(io::IReadFile* file)
\r
393 const long size = file->getSize();
\r
396 os::Printer::log("X File is too small.", ELL_WARNING);
\r
400 Buffer = new c8[size];
\r
402 //! read all into memory
\r
403 if (file->read(Buffer, size) != static_cast<size_t>(size))
\r
405 os::Printer::log("Could not read from x file.", ELL_WARNING);
\r
410 End = Buffer + size;
\r
412 //! check header "xof "
\r
413 if (strncmp(Buffer, "xof ", 4)!=0)
\r
415 os::Printer::log("Not an x file, wrong header.", ELL_WARNING);
\r
419 //! read minor and major version, e.g. 0302 or 0303
\r
421 tmp[0] = Buffer[4];
\r
422 tmp[1] = Buffer[5];
\r
424 MajorVersion = core::strtoul10(tmp);
\r
426 tmp[0] = Buffer[6];
\r
427 tmp[1] = Buffer[7];
\r
428 MinorVersion = core::strtoul10(tmp);
\r
431 if (strncmp(&Buffer[8], "txt ", 4) ==0)
\r
432 BinaryFormat = false;
\r
433 else if (strncmp(&Buffer[8], "bin ", 4) ==0)
\r
434 BinaryFormat = true;
\r
437 os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING);
\r
442 //! read float size
\r
443 if (strncmp(&Buffer[12], "0032", 4) ==0)
\r
445 else if (strncmp(&Buffer[12], "0064", 4) ==0)
\r
449 os::Printer::log("Float size not supported.", ELL_WARNING);
\r
455 readUntilEndOfLine();
\r
461 //! Parses the file
\r
462 bool CXMeshFileLoader::parseFile()
\r
464 while(parseDataObject())
\r
473 //! Parses the next Data object in the file
\r
474 bool CXMeshFileLoader::parseDataObject()
\r
476 core::stringc objectName = getNextToken();
\r
478 if (objectName.size() == 0)
\r
481 // parse specific object
\r
482 #ifdef _XREADER_DEBUG
\r
483 os::Printer::log("debug DataObject:", objectName.c_str(), ELL_DEBUG);
\r
486 if (objectName == "template")
\r
487 return parseDataObjectTemplate();
\r
489 if (objectName == "Frame")
\r
491 return parseDataObjectFrame( 0 );
\r
494 if (objectName == "Mesh")
\r
496 // some meshes have no frames at all
\r
497 //CurFrame = AnimatedMesh->addJoint(0);
\r
499 SXMesh *mesh=new SXMesh;
\r
501 //mesh->Buffer=AnimatedMesh->addMeshBuffer();
\r
502 Meshes.push_back(mesh);
\r
504 return parseDataObjectMesh(*mesh);
\r
507 if (objectName == "AnimationSet")
\r
509 return parseDataObjectAnimationSet();
\r
512 if (objectName == "AnimTicksPerSecond")
\r
514 return parseDataObjectAnimationTicksPerSecond();
\r
517 if (objectName == "Material")
\r
519 return parseUnknownDataObject();
\r
522 if (objectName == "}")
\r
524 os::Printer::log("} found in dataObject", ELL_WARNING);
\r
528 os::Printer::log("Unknown data object in animation of .x file", objectName.c_str(), ELL_WARNING);
\r
530 return parseUnknownDataObject();
\r
534 bool CXMeshFileLoader::parseDataObjectTemplate()
\r
536 #ifdef _XREADER_DEBUG
\r
537 os::Printer::log("CXFileReader: Reading template", ELL_DEBUG);
\r
540 // parse a template data object. Currently not stored.
\r
541 core::stringc name;
\r
543 if (!readHeadOfDataObject(&name))
\r
545 os::Printer::log("Left delimiter in template data object missing.",
\r
546 name.c_str(), ELL_WARNING);
\r
547 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
554 // read and ignore data members
\r
557 core::stringc s = getNextToken();
\r
570 bool CXMeshFileLoader::parseDataObjectFrame(CSkinnedMesh::SJoint *Parent)
\r
572 #ifdef _XREADER_DEBUG
\r
573 os::Printer::log("CXFileReader: Reading frame", ELL_DEBUG);
\r
576 // A coordinate frame, or "frame of reference." The Frame template
\r
577 // is open and can contain any object. The Direct3D extensions (D3DX)
\r
578 // mesh-loading functions recognize Mesh, FrameTransformMatrix, and
\r
579 // Frame template instances as child objects when loading a Frame
\r
584 core::stringc name;
\r
586 if (!readHeadOfDataObject(&name))
\r
588 os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING);
\r
589 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
593 CSkinnedMesh::SJoint *joint=0;
\r
597 for (u32 n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
599 if (AnimatedMesh->getAllJoints()[n]->Name==name)
\r
601 joint=AnimatedMesh->getAllJoints()[n];
\r
610 #ifdef _XREADER_DEBUG
\r
611 os::Printer::log("creating joint ", name.c_str(), ELL_DEBUG);
\r
613 joint=AnimatedMesh->addJoint(Parent);
\r
615 JointID=AnimatedMesh->getAllJoints().size()-1;
\r
619 #ifdef _XREADER_DEBUG
\r
620 os::Printer::log("using joint ", name.c_str(), ELL_DEBUG);
\r
623 Parent->Children.push_back(joint);
\r
626 // Now inside a frame.
\r
627 // read tokens until closing brace is reached.
\r
631 core::stringc objectName = getNextToken();
\r
633 #ifdef _XREADER_DEBUG
\r
634 os::Printer::log("debug DataObject in frame:", objectName.c_str(), ELL_DEBUG);
\r
637 if (objectName.size() == 0)
\r
639 os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING);
\r
640 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
644 if (objectName == "}")
\r
646 break; // frame finished
\r
649 if (objectName == "Frame")
\r
652 if (!parseDataObjectFrame(joint))
\r
656 if (objectName == "FrameTransformMatrix")
\r
658 if (!parseDataObjectTransformationMatrix(joint->LocalMatrix))
\r
661 //joint->LocalAnimatedMatrix
\r
662 //joint->LocalAnimatedMatrix.makeInverse();
\r
663 //joint->LocalMatrix=tmp*joint->LocalAnimatedMatrix;
\r
666 if (objectName == "Mesh")
\r
669 frame.Meshes.push_back(SXMesh());
\r
670 if (!parseDataObjectMesh(frame.Meshes.getLast()))
\r
673 SXMesh *mesh=new SXMesh;
\r
675 mesh->AttachedJointID=JointID;
\r
677 Meshes.push_back(mesh);
\r
679 if (!parseDataObjectMesh(*mesh))
\r
684 os::Printer::log("Unknown data object in frame in x file", objectName.c_str(), ELL_WARNING);
\r
685 if (!parseUnknownDataObject())
\r
694 bool CXMeshFileLoader::parseDataObjectTransformationMatrix(core::matrix4 &mat)
\r
696 #ifdef _XREADER_DEBUG
\r
697 os::Printer::log("CXFileReader: Reading Transformation Matrix", ELL_DEBUG);
\r
700 if (!readHeadOfDataObject())
\r
702 os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING);
\r
703 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
709 if (!checkForOneFollowingSemicolons())
\r
711 os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING);
\r
712 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
715 if (!checkForClosingBrace())
\r
717 os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING);
\r
718 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
726 bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh)
\r
728 core::stringc name;
\r
730 if (!readHeadOfDataObject(&name))
\r
732 #ifdef _XREADER_DEBUG
\r
733 os::Printer::log("CXFileReader: Reading mesh", ELL_DEBUG);
\r
735 os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING);
\r
736 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
740 #ifdef _XREADER_DEBUG
\r
741 os::Printer::log("CXFileReader: Reading mesh", name.c_str(), ELL_DEBUG);
\r
744 // read vertex count
\r
745 const u32 nVertices = readInt();
\r
748 mesh.Vertices.set_used(nVertices);
\r
749 for (u32 n=0; n<nVertices; ++n)
\r
751 readVector3(mesh.Vertices[n].Pos);
\r
752 mesh.Vertices[n].Color=0xFFFFFFFF;
\r
753 mesh.Vertices[n].Normal=core::vector3df(0.0f);
\r
756 if (!checkForTwoFollowingSemicolons())
\r
758 os::Printer::log("No finishing semicolon in Mesh Vertex Array found in x file", ELL_WARNING);
\r
759 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
763 const u32 nFaces = readInt();
\r
765 mesh.Indices.set_used(nFaces * 3);
\r
766 mesh.IndexCountPerFace.set_used(nFaces);
\r
768 core::array<u32> polygonfaces;
\r
769 u32 currentIndex = 0;
\r
771 for (u32 k=0; k<nFaces; ++k)
\r
773 const u32 fcnt = readInt();
\r
779 os::Printer::log("Invalid face count (<3) found in Mesh x file reader.", ELL_WARNING);
\r
780 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
784 // read face indices
\r
785 polygonfaces.set_used(fcnt);
\r
786 u32 triangles = (fcnt-2);
\r
787 mesh.Indices.set_used(mesh.Indices.size() + ((triangles-1)*3));
\r
788 mesh.IndexCountPerFace[k] = (u16)(triangles * 3);
\r
790 for (u32 f=0; f<fcnt; ++f)
\r
791 polygonfaces[f] = readInt();
\r
793 for (u32 jk=0; jk<triangles; ++jk)
\r
795 mesh.Indices[currentIndex++] = polygonfaces[0];
\r
796 mesh.Indices[currentIndex++] = polygonfaces[jk+1];
\r
797 mesh.Indices[currentIndex++] = polygonfaces[jk+2];
\r
800 // TODO: change face indices in material list
\r
804 mesh.Indices[currentIndex++] = readInt();
\r
805 mesh.Indices[currentIndex++] = readInt();
\r
806 mesh.Indices[currentIndex++] = readInt();
\r
807 mesh.IndexCountPerFace[k] = 3;
\r
811 if (!checkForTwoFollowingSemicolons())
\r
813 os::Printer::log("No finishing semicolon in Mesh Face Array found in x file", ELL_WARNING);
\r
814 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
817 // here, other data objects may follow
\r
821 core::stringc objectName = getNextToken();
\r
823 if (objectName.size() == 0)
\r
825 os::Printer::log("Unexpected ending found in Mesh in x file.", ELL_WARNING);
\r
826 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
830 if (objectName == "}")
\r
832 break; // mesh finished
\r
835 #ifdef _XREADER_DEBUG
\r
836 os::Printer::log("debug DataObject in mesh:", objectName.c_str(), ELL_DEBUG);
\r
839 if (objectName == "MeshNormals")
\r
841 if (!parseDataObjectMeshNormals(mesh))
\r
845 if (objectName == "MeshTextureCoords")
\r
847 if (!parseDataObjectMeshTextureCoords(mesh))
\r
851 if (objectName == "MeshVertexColors")
\r
853 if (!parseDataObjectMeshVertexColors(mesh))
\r
857 if (objectName == "MeshMaterialList")
\r
859 if (!parseDataObjectMeshMaterialList(mesh))
\r
863 if (objectName == "VertexDuplicationIndices")
\r
865 // we'll ignore vertex duplication indices
\r
867 if (!parseUnknownDataObject())
\r
871 if (objectName == "DeclData")
\r
873 if (!readHeadOfDataObject())
\r
875 os::Printer::log("No starting brace in DeclData found.", ELL_WARNING);
\r
876 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
879 // arbitrary vertex attributes
\r
880 // first comes the number of element definitions
\r
881 // then the vertex element type definitions
\r
882 // with format type;tesselator;semantics;usageindex
\r
883 // we want to support 2;0;6;0 == tangent
\r
884 // 2;0;7;0 == binormal
\r
885 // 2;0;3;0 == normal
\r
886 // 1/2;0;5;0 == 1st uv coord
\r
887 // and 1/2;0;5;1 == 2nd uv coord
\r
888 // type==2 is 3xf32, type==1 is 2xf32
\r
890 const u32 dcnt = readInt();
\r
892 s16 normalpos = -1;
\r
895 s16 tangentpos = -1;
\r
896 s16 binormalpos = -1;
\r
897 s16 normaltype = -1;
\r
900 s16 tangenttype = -1;
\r
901 s16 binormaltype = -1;
\r
903 (void)tangentpos; // disable unused variable warnings
\r
904 (void)binormalpos; // disable unused variable warnings
\r
905 (void)tangenttype; // disable unused variable warnings
\r
906 (void)binormaltype; // disable unused variable warnings
\r
908 for (j=0; j<dcnt; ++j)
\r
910 const u32 type = readInt();
\r
911 //const u32 tesselator = readInt();
\r
913 const u32 semantics = readInt();
\r
914 const u32 index = readInt();
\r
935 tangenttype = type;
\r
938 binormalpos = size;
\r
939 binormaltype = type;
\r
993 const u32 datasize = readInt();
\r
994 u32* data = new u32[datasize];
\r
995 for (j=0; j<datasize; ++j)
\r
998 if (!checkForOneFollowingSemicolons())
\r
1000 os::Printer::log("No finishing semicolon in DeclData found.", ELL_WARNING);
\r
1001 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1003 if (!checkForClosingBrace())
\r
1005 os::Printer::log("No closing brace in DeclData.", ELL_WARNING);
\r
1006 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1010 u8* dataptr = (u8*) data;
\r
1011 if ((uv2pos != -1) && (uv2type == 1))
\r
1012 mesh.TCoords2.reallocate(mesh.Vertices.size());
\r
1013 for (j=0; j<mesh.Vertices.size(); ++j)
\r
1015 if ((normalpos != -1) && (normaltype == 2))
\r
1016 mesh.Vertices[j].Normal.set(*((core::vector3df*)(dataptr+normalpos)));
\r
1017 if ((uvpos != -1) && (uvtype == 1))
\r
1018 mesh.Vertices[j].TCoords.set(*((core::vector2df*)(dataptr+uvpos)));
\r
1019 if ((uv2pos != -1) && (uv2type == 1))
\r
1020 mesh.TCoords2.push_back(*((core::vector2df*)(dataptr+uv2pos)));
\r
1026 if (objectName == "FVFData")
\r
1028 if (!readHeadOfDataObject())
\r
1030 os::Printer::log("No starting brace in FVFData found.", ELL_WARNING);
\r
1031 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1034 const u32 dataformat = readInt();
\r
1035 const u32 datasize = readInt();
\r
1036 u32* data = new u32[datasize];
\r
1037 for (u32 j=0; j<datasize; ++j)
\r
1038 data[j]=readInt();
\r
1039 if (dataformat&0x102) // 2nd uv set
\r
1041 mesh.TCoords2.reallocate(mesh.Vertices.size());
\r
1042 u8* dataptr = (u8*) data;
\r
1043 const u32 size=((dataformat>>8)&0xf)*sizeof(core::vector2df);
\r
1044 for (u32 j=0; j<mesh.Vertices.size(); ++j)
\r
1046 mesh.TCoords2.push_back(*((core::vector2df*)(dataptr)));
\r
1051 if (!checkForOneFollowingSemicolons())
\r
1053 os::Printer::log("No finishing semicolon in FVFData found.", ELL_WARNING);
\r
1054 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1056 if (!checkForClosingBrace())
\r
1058 os::Printer::log("No closing brace in FVFData found in x file", ELL_WARNING);
\r
1059 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1064 if (objectName == "XSkinMeshHeader")
\r
1066 if (!parseDataObjectSkinMeshHeader(mesh))
\r
1070 if (objectName == "SkinWeights")
\r
1072 //mesh.SkinWeights.push_back(SXSkinWeight());
\r
1073 //if (!parseDataObjectSkinWeights(mesh.SkinWeights.getLast()))
\r
1074 if (!parseDataObjectSkinWeights(mesh))
\r
1079 os::Printer::log("Unknown data object in mesh in x file", objectName.c_str(), ELL_WARNING);
\r
1080 if (!parseUnknownDataObject())
\r
1089 bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh)
\r
1091 #ifdef _XREADER_DEBUG
\r
1092 os::Printer::log("CXFileReader: Reading mesh skin weights", ELL_DEBUG);
\r
1095 if (!readHeadOfDataObject())
\r
1097 os::Printer::log("No opening brace in Skin Weights found in .x file", ELL_WARNING);
\r
1098 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1102 core::stringc TransformNodeName;
\r
1104 if (!getNextTokenAsString(TransformNodeName))
\r
1106 os::Printer::log("Unknown syntax while reading transform node name string in .x file", ELL_WARNING);
\r
1107 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1111 mesh.HasSkinning=true;
\r
1113 CSkinnedMesh::SJoint *joint=0;
\r
1116 for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
1118 if (AnimatedMesh->getAllJoints()[n]->Name==TransformNodeName)
\r
1120 joint=AnimatedMesh->getAllJoints()[n];
\r
1127 #ifdef _XREADER_DEBUG
\r
1128 os::Printer::log("creating joint for skinning ", TransformNodeName.c_str(), ELL_DEBUG);
\r
1130 n = AnimatedMesh->getAllJoints().size();
\r
1131 joint=AnimatedMesh->addJoint(0);
\r
1132 joint->Name=TransformNodeName;
\r
1135 // read vertex weights
\r
1136 const u32 nWeights = readInt();
\r
1138 // read vertex indices
\r
1141 const u32 jointStart = joint->Weights.size();
\r
1142 joint->Weights.reallocate(jointStart+nWeights);
\r
1144 mesh.WeightJoint.reallocate( mesh.WeightJoint.size() + nWeights );
\r
1145 mesh.WeightNum.reallocate( mesh.WeightNum.size() + nWeights );
\r
1147 for (i=0; i<nWeights; ++i)
\r
1149 mesh.WeightJoint.push_back(n);
\r
1150 mesh.WeightNum.push_back(joint->Weights.size());
\r
1152 CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(joint);
\r
1154 weight->buffer_id=0;
\r
1155 weight->vertex_id=readInt();
\r
1158 // read vertex weights
\r
1160 for (i=jointStart; i<jointStart+nWeights; ++i)
\r
1161 joint->Weights[i].strength = readFloat();
\r
1163 // read matrix offset
\r
1165 // transforms the mesh vertices to the space of the bone
\r
1166 // When concatenated to the bone's transform, this provides the
\r
1167 // world space coordinates of the mesh as affected by the bone
\r
1168 core::matrix4& MatrixOffset = joint->GlobalInversedMatrix;
\r
1170 readMatrix(MatrixOffset);
\r
1172 if (!checkForOneFollowingSemicolons())
\r
1174 os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING);
\r
1175 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1178 if (!checkForClosingBrace())
\r
1180 os::Printer::log("No closing brace in Skin Weights found in x file", ELL_WARNING);
\r
1181 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1189 bool CXMeshFileLoader::parseDataObjectSkinMeshHeader(SXMesh& mesh)
\r
1191 #ifdef _XREADER_DEBUG
\r
1192 os::Printer::log("CXFileReader: Reading skin mesh header", ELL_DEBUG);
\r
1195 if (!readHeadOfDataObject())
\r
1197 os::Printer::log("No opening brace in Skin Mesh header found in .x file", ELL_WARNING);
\r
1198 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1202 mesh.MaxSkinWeightsPerVertex = readInt();
\r
1203 mesh.MaxSkinWeightsPerFace = readInt();
\r
1204 mesh.BoneCount = readInt();
\r
1206 if (!BinaryFormat)
\r
1207 getNextToken(); // skip semicolon
\r
1209 if (!checkForClosingBrace())
\r
1211 os::Printer::log("No closing brace in skin mesh header in x file", ELL_WARNING);
\r
1212 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1220 bool CXMeshFileLoader::parseDataObjectMeshNormals(SXMesh &mesh)
\r
1222 #ifdef _XREADER_DEBUG
\r
1223 os::Printer::log("CXFileReader: reading mesh normals", ELL_DEBUG);
\r
1226 if (!readHeadOfDataObject())
\r
1228 os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING);
\r
1229 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1234 const u32 nNormals = readInt();
\r
1235 core::array<core::vector3df> normals;
\r
1236 normals.set_used(nNormals);
\r
1239 for (u32 i=0; i<nNormals; ++i)
\r
1240 readVector3(normals[i]);
\r
1242 if (!checkForTwoFollowingSemicolons())
\r
1244 os::Printer::log("No finishing semicolon in Mesh Normals Array found in x file", ELL_WARNING);
\r
1245 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1248 core::array<u32> normalIndices;
\r
1249 normalIndices.set_used(mesh.Indices.size());
\r
1251 // read face normal indices
\r
1252 const u32 nFNormals = readInt();
\r
1254 u32 normalidx = 0;
\r
1255 core::array<u32> polygonfaces;
\r
1256 for (u32 k=0; k<nFNormals; ++k)
\r
1258 const u32 fcnt = readInt();
\r
1259 u32 triangles = fcnt - 2;
\r
1260 u32 indexcount = triangles * 3;
\r
1262 if (indexcount != mesh.IndexCountPerFace[k])
\r
1264 os::Printer::log("Not matching normal and face index count found in x file", ELL_WARNING);
\r
1265 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1269 if (indexcount == 3)
\r
1271 // default, only one triangle in this face
\r
1272 for (u32 h=0; h<3; ++h)
\r
1274 const u32 normalnum = readInt();
\r
1275 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[normalnum]);
\r
1280 polygonfaces.set_used(fcnt);
\r
1281 // multiple triangles in this face
\r
1282 for (u32 h=0; h<fcnt; ++h)
\r
1283 polygonfaces[h] = readInt();
\r
1285 for (u32 jk=0; jk<triangles; ++jk)
\r
1287 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[0]]);
\r
1288 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+1]]);
\r
1289 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+2]]);
\r
1294 if (!checkForTwoFollowingSemicolons())
\r
1296 os::Printer::log("No finishing semicolon in Mesh Face Normals Array found in x file", ELL_WARNING);
\r
1297 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1300 if (!checkForClosingBrace())
\r
1302 os::Printer::log("No closing brace in Mesh Normals found in x file", ELL_WARNING);
\r
1303 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1311 bool CXMeshFileLoader::parseDataObjectMeshTextureCoords(SXMesh &mesh)
\r
1313 #ifdef _XREADER_DEBUG
\r
1314 os::Printer::log("CXFileReader: reading mesh texture coordinates", ELL_DEBUG);
\r
1317 if (!readHeadOfDataObject())
\r
1319 os::Printer::log("No opening brace in Mesh Texture Coordinates found in x file", ELL_WARNING);
\r
1320 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1324 const u32 nCoords = readInt();
\r
1325 for (u32 i=0; i<nCoords; ++i)
\r
1326 readVector2(mesh.Vertices[i].TCoords);
\r
1328 if (!checkForTwoFollowingSemicolons())
\r
1330 os::Printer::log("No finishing semicolon in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1331 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1334 if (!checkForClosingBrace())
\r
1336 os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1337 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1345 bool CXMeshFileLoader::parseDataObjectMeshVertexColors(SXMesh &mesh)
\r
1347 #ifdef _XREADER_DEBUG
\r
1348 os::Printer::log("CXFileReader: reading mesh vertex colors", ELL_DEBUG);
\r
1351 if (!readHeadOfDataObject())
\r
1353 os::Printer::log("No opening brace for Mesh Vertex Colors found in x file", ELL_WARNING);
\r
1354 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1358 mesh.HasVertexColors=true;
\r
1359 const u32 nColors = readInt();
\r
1360 for (u32 i=0; i<nColors; ++i)
\r
1362 const u32 Index=readInt();
\r
1363 if (Index>=mesh.Vertices.size())
\r
1365 os::Printer::log("index value in parseDataObjectMeshVertexColors out of bounds", ELL_WARNING);
\r
1366 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1369 readRGBA(mesh.Vertices[Index].Color);
\r
1370 checkForOneFollowingSemicolons();
\r
1373 if (!checkForOneFollowingSemicolons())
\r
1375 os::Printer::log("No finishing semicolon in Mesh Vertex Colors Array found in x file", ELL_WARNING);
\r
1376 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1379 if (!checkForClosingBrace())
\r
1381 os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1382 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1390 bool CXMeshFileLoader::parseDataObjectMeshMaterialList(SXMesh &mesh)
\r
1392 #ifdef _XREADER_DEBUG
\r
1393 os::Printer::log("CXFileReader: Reading mesh material list", ELL_DEBUG);
\r
1396 if (!readHeadOfDataObject())
\r
1398 os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING);
\r
1399 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1403 // read material count
\r
1404 mesh.Materials.reallocate(readInt());
\r
1406 // read non triangulated face material index count
\r
1407 const u32 nFaceIndices = readInt();
\r
1409 // There seems to be a compact representation of "all faces the same material"
\r
1410 // being represented as 1;1;0;; which means 1 material, 1 face with first material
\r
1411 // all the other faces have to obey then, so check is disabled
\r
1412 //if (nFaceIndices != mesh.IndexCountPerFace.size())
\r
1413 // os::Printer::log("Index count per face not equal to face material index count in x file.", ELL_WARNING);
\r
1415 // read non triangulated face indices and create triangulated ones
\r
1416 mesh.FaceMaterialIndices.set_used( mesh.Indices.size() / 3);
\r
1417 u32 triangulatedindex = 0;
\r
1419 for (u32 tfi=0; tfi<mesh.IndexCountPerFace.size(); ++tfi)
\r
1421 if (tfi<nFaceIndices)
\r
1423 const u32 fc = mesh.IndexCountPerFace[tfi]/3;
\r
1424 for (u32 k=0; k<fc; ++k)
\r
1425 mesh.FaceMaterialIndices[triangulatedindex++] = ind;
\r
1428 // in version 03.02, the face indices end with two semicolons.
\r
1429 // commented out version check, as version 03.03 exported from blender also has 2 semicolons
\r
1430 if (!BinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
\r
1436 // read following data objects
\r
1440 core::stringc objectName = getNextToken();
\r
1442 if (objectName.size() == 0)
\r
1444 os::Printer::log("Unexpected ending found in Mesh Material list in .x file.", ELL_WARNING);
\r
1445 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1449 if (objectName == "}")
\r
1451 break; // material list finished
\r
1454 if (objectName == "{")
\r
1456 // template materials now available thanks to joeWright
\r
1457 objectName = getNextToken();
\r
1458 mesh.Materials.push_back(video::SMaterial());
\r
1459 getNextToken(); // skip }
\r
1462 if (objectName == "Material")
\r
1464 mesh.Materials.push_back(video::SMaterial());
\r
1465 if (!parseUnknownDataObject())
\r
1469 if (objectName == ";")
\r
1475 os::Printer::log("Unknown data object in material list in x file", objectName.c_str(), ELL_WARNING);
\r
1476 if (!parseUnknownDataObject())
\r
1484 bool CXMeshFileLoader::parseDataObjectAnimationSet()
\r
1486 #ifdef _XREADER_DEBUG
\r
1487 os::Printer::log("CXFileReader: Reading animation set", ELL_DEBUG);
\r
1490 core::stringc AnimationName;
\r
1492 if (!readHeadOfDataObject(&AnimationName))
\r
1494 os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING);
\r
1495 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1498 os::Printer::log("Reading animationset ", AnimationName, ELL_DEBUG);
\r
1502 core::stringc objectName = getNextToken();
\r
1504 if (objectName.size() == 0)
\r
1506 os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING);
\r
1507 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1511 if (objectName == "}")
\r
1513 break; // animation set finished
\r
1516 if (objectName == "Animation")
\r
1518 if (!parseDataObjectAnimation())
\r
1523 os::Printer::log("Unknown data object in animation set in x file", objectName.c_str(), ELL_WARNING);
\r
1524 if (!parseUnknownDataObject())
\r
1531 bool CXMeshFileLoader::parseDataObjectAnimationTicksPerSecond()
\r
1533 #ifdef _XREADER_DEBUG
\r
1534 os::Printer::log("CXFileReader: reading AnimationTicksPerSecond", ELL_DEBUG);
\r
1537 if (!readHeadOfDataObject())
\r
1539 os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING);
\r
1540 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1544 const u32 ticks = readInt();
\r
1546 if (!checkForOneFollowingSemicolons())
\r
1548 os::Printer::log("No closing semicolon in AnimationTicksPerSecond in x file", ELL_WARNING);
\r
1549 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1553 if (!checkForClosingBrace())
\r
1555 os::Printer::log("No closing brace in AnimationTicksPerSecond in x file", ELL_WARNING);
\r
1556 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1560 AnimatedMesh->setAnimationSpeed(static_cast<irr::f32>(ticks));
\r
1565 bool CXMeshFileLoader::parseDataObjectAnimation()
\r
1567 #ifdef _XREADER_DEBUG
\r
1568 os::Printer::log("CXFileReader: reading animation", ELL_DEBUG);
\r
1571 if (!readHeadOfDataObject())
\r
1573 os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING);
\r
1574 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1578 //anim.closed = true;
\r
1579 //anim.linearPositionQuality = true;
\r
1580 CSkinnedMesh::SJoint animationDump;
\r
1582 core::stringc FrameName;
\r
1586 core::stringc objectName = getNextToken();
\r
1588 if (objectName.size() == 0)
\r
1590 os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
\r
1591 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1595 if (objectName == "}")
\r
1597 break; // animation finished
\r
1600 if (objectName == "AnimationKey")
\r
1602 if (!parseDataObjectAnimationKey(&animationDump))
\r
1606 if (objectName == "AnimationOptions")
\r
1608 //TODO: parse options.
\r
1609 if (!parseUnknownDataObject())
\r
1613 if (objectName == "{")
\r
1615 // read frame name
\r
1616 FrameName = getNextToken();
\r
1618 if (!checkForClosingBrace())
\r
1620 os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
\r
1621 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1627 os::Printer::log("Unknown data object in animation in x file", objectName.c_str(), ELL_WARNING);
\r
1628 if (!parseUnknownDataObject())
\r
1633 if (FrameName.size() != 0)
\r
1635 #ifdef _XREADER_DEBUG
\r
1636 os::Printer::log("frame name", FrameName.c_str(), ELL_DEBUG);
\r
1638 CSkinnedMesh::SJoint *joint=0;
\r
1641 for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
1643 if (AnimatedMesh->getAllJoints()[n]->Name==FrameName)
\r
1645 joint=AnimatedMesh->getAllJoints()[n];
\r
1652 #ifdef _XREADER_DEBUG
\r
1653 os::Printer::log("creating joint for animation ", FrameName.c_str(), ELL_DEBUG);
\r
1655 joint=AnimatedMesh->addJoint(0);
\r
1656 joint->Name=FrameName;
\r
1659 joint->PositionKeys.reallocate(joint->PositionKeys.size()+animationDump.PositionKeys.size());
\r
1660 for (n=0; n<animationDump.PositionKeys.size(); ++n)
\r
1662 joint->PositionKeys.push_back(animationDump.PositionKeys[n]);
\r
1665 joint->ScaleKeys.reallocate(joint->ScaleKeys.size()+animationDump.ScaleKeys.size());
\r
1666 for (n=0; n<animationDump.ScaleKeys.size(); ++n)
\r
1668 joint->ScaleKeys.push_back(animationDump.ScaleKeys[n]);
\r
1671 joint->RotationKeys.reallocate(joint->RotationKeys.size()+animationDump.RotationKeys.size());
\r
1672 for (n=0; n<animationDump.RotationKeys.size(); ++n)
\r
1674 joint->RotationKeys.push_back(animationDump.RotationKeys[n]);
\r
1678 os::Printer::log("joint name was never given", ELL_WARNING);
\r
1684 bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint)
\r
1686 #ifdef _XREADER_DEBUG
\r
1687 os::Printer::log("CXFileReader: reading animation key", ELL_DEBUG);
\r
1690 if (!readHeadOfDataObject())
\r
1692 os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING);
\r
1693 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1699 const u32 keyType = readInt();
\r
1703 os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING);
\r
1704 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1708 // read number of keys
\r
1709 const u32 numberOfKeys = readInt();
\r
1711 // eat the semicolon after the "0". if there are keys present, readInt()
\r
1712 // does this for us. If there aren't, we need to do it explicitly
\r
1713 if (numberOfKeys == 0)
\r
1714 checkForOneFollowingSemicolons();
\r
1716 for (u32 i=0; i<numberOfKeys; ++i)
\r
1719 const f32 time = (f32)readInt();
\r
1724 case 0: //rotation
\r
1726 //read quaternions
\r
1729 if (readInt() != 4)
\r
1731 os::Printer::log("Expected 4 numbers in animation key in x file", ELL_WARNING);
\r
1732 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1736 f32 W = -readFloat();
\r
1737 f32 X = -readFloat();
\r
1738 f32 Y = -readFloat();
\r
1739 f32 Z = -readFloat();
\r
1741 if (!checkForTwoFollowingSemicolons())
\r
1743 os::Printer::log("No finishing semicolon after quaternion animation key in x file", ELL_WARNING);
\r
1744 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1747 ISkinnedMesh::SRotationKey *key=AnimatedMesh->addRotationKey(joint);
\r
1749 key->rotation.set(X,Y,Z,W);
\r
1750 key->rotation.normalize();
\r
1754 case 2: //position
\r
1759 if (readInt() != 3)
\r
1761 os::Printer::log("Expected 3 numbers in animation key in x file", ELL_WARNING);
\r
1762 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1766 core::vector3df vector;
\r
1767 readVector3(vector);
\r
1769 if (!checkForTwoFollowingSemicolons())
\r
1771 os::Printer::log("No finishing semicolon after vector animation key in x file", ELL_WARNING);
\r
1772 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1777 ISkinnedMesh::SPositionKey *key=AnimatedMesh->addPositionKey(joint);
\r
1779 key->position=vector;
\r
1783 ISkinnedMesh::SScaleKey *key=AnimatedMesh->addScaleKey(joint);
\r
1785 key->scale=vector;
\r
1795 if (readInt() != 16)
\r
1797 os::Printer::log("Expected 16 numbers in animation key in x file", ELL_WARNING);
\r
1798 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1803 core::matrix4 mat(core::matrix4::EM4CONST_NOTHING);
\r
1806 //mat=joint->LocalMatrix*mat;
\r
1808 if (!checkForOneFollowingSemicolons())
\r
1810 os::Printer::log("No finishing semicolon after matrix animation key in x file", ELL_WARNING);
\r
1811 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1814 //core::vector3df rotation = mat.getRotationDegrees();
\r
1816 ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint);
\r
1819 // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility.
\r
1820 // Not tested so far if this was correct or wrong before quaternion fix!
\r
1821 keyR->rotation= core::quaternion(mat.getTransposed());
\r
1823 ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->addPositionKey(joint);
\r
1825 keyP->position=mat.getTranslation();
\r
1828 core::vector3df scale=mat.getScale();
\r
1836 ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->addScaleKey(joint);
\r
1838 keyS->scale=scale;
\r
1845 if (!checkForOneFollowingSemicolons())
\r
1848 if (!checkForClosingBrace())
\r
1850 os::Printer::log("No closing brace in animation key in x file", ELL_WARNING);
\r
1851 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1859 bool CXMeshFileLoader::parseDataObjectTextureFilename(core::stringc& texturename)
\r
1861 #ifdef _XREADER_DEBUG
\r
1862 os::Printer::log("CXFileReader: reading texture filename", ELL_DEBUG);
\r
1865 if (!readHeadOfDataObject())
\r
1867 os::Printer::log("No opening brace in Texture filename found in x file", ELL_WARNING);
\r
1868 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1872 if (!getNextTokenAsString(texturename))
\r
1874 os::Printer::log("Unknown syntax while reading texture filename string in x file", ELL_WARNING);
\r
1875 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1879 if (!checkForClosingBrace())
\r
1881 os::Printer::log("No closing brace in Texture filename found in x file", ELL_WARNING);
\r
1882 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1890 bool CXMeshFileLoader::parseUnknownDataObject()
\r
1892 // find opening delimiter
\r
1895 core::stringc t = getNextToken();
\r
1897 if (t.size() == 0)
\r
1906 // parse until closing delimiter
\r
1910 core::stringc t = getNextToken();
\r
1912 if (t.size() == 0)
\r
1926 //! checks for closing curly brace, returns false if not there
\r
1927 bool CXMeshFileLoader::checkForClosingBrace()
\r
1929 return (getNextToken() == "}");
\r
1933 //! checks for one following semicolon, returns false if not there
\r
1934 bool CXMeshFileLoader::checkForOneFollowingSemicolons()
\r
1939 if (getNextToken() == ";")
\r
1949 //! checks for two following semicolons, returns false if they are not there
\r
1950 bool CXMeshFileLoader::checkForTwoFollowingSemicolons()
\r
1955 for (u32 k=0; k<2; ++k)
\r
1957 if (getNextToken() != ";")
\r
1968 //! reads header of dataobject including the opening brace.
\r
1969 //! returns false if error happened, and writes name of object
\r
1970 //! if there is one
\r
1971 bool CXMeshFileLoader::readHeadOfDataObject(core::stringc* outname)
\r
1973 core::stringc nameOrBrace = getNextToken();
\r
1974 if (nameOrBrace != "{")
\r
1977 (*outname) = nameOrBrace;
\r
1979 if (getNextToken() != "{")
\r
1987 //! returns next parseable token. Returns empty string if no token there
\r
1988 core::stringc CXMeshFileLoader::getNextToken()
\r
1992 // process binary-formatted file
\r
1995 // in binary mode it will only return NAME and STRING token
\r
1996 // and (correctly) skip over other tokens.
\r
1998 s16 tok = readBinWord();
\r
2001 // standalone tokens
\r
2005 len = readBinDWord();
\r
2006 s = core::stringc(P, len);
\r
2011 len = readBinDWord();
\r
2012 s = core::stringc(P, len);
\r
2018 return "<integer>";
\r
2024 len = readBinDWord();
\r
2026 return "<int_list>";
\r
2028 len = readBinDWord();
\r
2029 P += (len * FloatSize);
\r
2030 return "<flt_list>";
\r
2054 return "template";
\r
2083 // process text-formatted file
\r
2086 findNextNoneWhiteSpace();
\r
2091 while((P < End) && !core::isspace(P[0]))
\r
2093 // either keep token delimiters when already holding a token, or return if first valid char
\r
2094 if (P[0]==';' || P[0]=='}' || P[0]=='{' || P[0]==',')
\r
2101 break; // stop for delimiter
\r
2111 //! places pointer to next begin of a token, which must be a number,
\r
2112 // and ignores comments
\r
2113 void CXMeshFileLoader::findNextNoneWhiteSpaceNumber()
\r
2118 while((P < End) && (P[0] != '-') && (P[0] != '.') &&
\r
2119 !( core::isdigit(P[0])))
\r
2121 // check if this is a comment
\r
2122 if ((P[0] == '/' && P[1] == '/') || P[0] == '#')
\r
2123 readUntilEndOfLine();
\r
2130 // places pointer to next begin of a token, and ignores comments
\r
2131 void CXMeshFileLoader::findNextNoneWhiteSpace()
\r
2138 while((P < End) && core::isspace(P[0]))
\r
2148 // check if this is a comment
\r
2149 if ((P[0] == '/' && P[1] == '/') ||
\r
2151 readUntilEndOfLine();
\r
2158 //! reads a x file style string
\r
2159 bool CXMeshFileLoader::getNextTokenAsString(core::stringc& out)
\r
2163 out=getNextToken();
\r
2166 findNextNoneWhiteSpace();
\r
2175 while(P < End && P[0]!='"')
\r
2181 if ( P[1] != ';' || P[0] != '"')
\r
2189 void CXMeshFileLoader::readUntilEndOfLine()
\r
2196 if (P[0] == '\n' || P[0] == '\r')
\r
2208 u16 CXMeshFileLoader::readBinWord()
\r
2212 #ifdef __BIG_ENDIAN__
\r
2213 const u16 tmp = os::Byteswap::byteswap(*(u16 *)P);
\r
2215 const u16 tmp = *(u16 *)P;
\r
2222 u32 CXMeshFileLoader::readBinDWord()
\r
2226 #ifdef __BIG_ENDIAN__
\r
2227 const u32 tmp = os::Byteswap::byteswap(*(u32 *)P);
\r
2229 const u32 tmp = *(u32 *)P;
\r
2236 u32 CXMeshFileLoader::readInt()
\r
2240 if (!BinaryNumCount)
\r
2242 const u16 tmp = readBinWord(); // 0x06 or 0x03
\r
2244 BinaryNumCount = readBinDWord();
\r
2246 BinaryNumCount = 1; // single int
\r
2249 return readBinDWord();
\r
2253 findNextNoneWhiteSpaceNumber();
\r
2254 return core::strtoul10(P, &P);
\r
2259 f32 CXMeshFileLoader::readFloat()
\r
2263 if (!BinaryNumCount)
\r
2265 const u16 tmp = readBinWord(); // 0x07 or 0x42
\r
2267 BinaryNumCount = readBinDWord();
\r
2269 BinaryNumCount = 1; // single int
\r
2272 if (FloatSize == 8)
\r
2274 #ifdef __BIG_ENDIAN__
\r
2275 //TODO: Check if data is properly converted here
\r
2277 ctmp[1] = os::Byteswap::byteswap(*(f32*)P);
\r
2278 ctmp[0] = os::Byteswap::byteswap(*(f32*)P+4);
\r
2279 const f32 tmp = (f32)(*(f64*)(void*)ctmp);
\r
2281 const f32 tmp = (f32)(*(f64 *)P);
\r
2288 #ifdef __BIG_ENDIAN__
\r
2289 const f32 tmp = os::Byteswap::byteswap(*(f32 *)P);
\r
2291 const f32 tmp = *(f32 *)P;
\r
2297 findNextNoneWhiteSpaceNumber();
\r
2299 P = core::fast_atof_move(P, ftmp);
\r
2304 // read 2-dimensional vector. Stops at semicolon after second value for text file format
\r
2305 bool CXMeshFileLoader::readVector2(core::vector2df& vec)
\r
2307 vec.X = readFloat();
\r
2308 vec.Y = readFloat();
\r
2313 // read 3-dimensional vector. Stops at semicolon after third value for text file format
\r
2314 bool CXMeshFileLoader::readVector3(core::vector3df& vec)
\r
2316 vec.X = readFloat();
\r
2317 vec.Y = readFloat();
\r
2318 vec.Z = readFloat();
\r
2323 // read color without alpha value. Stops after second semicolon after blue value
\r
2324 bool CXMeshFileLoader::readRGB(video::SColor& color)
\r
2326 video::SColorf tmpColor;
\r
2327 tmpColor.r = readFloat();
\r
2328 tmpColor.g = readFloat();
\r
2329 tmpColor.b = readFloat();
\r
2330 color = tmpColor.toSColor();
\r
2331 return checkForOneFollowingSemicolons();
\r
2335 // read color with alpha value. Stops after second semicolon after blue value
\r
2336 bool CXMeshFileLoader::readRGBA(video::SColor& color)
\r
2338 video::SColorf tmpColor;
\r
2339 tmpColor.r = readFloat();
\r
2340 tmpColor.g = readFloat();
\r
2341 tmpColor.b = readFloat();
\r
2342 tmpColor.a = readFloat();
\r
2343 color = tmpColor.toSColor();
\r
2344 return checkForOneFollowingSemicolons();
\r
2348 // read matrix from list of floats
\r
2349 bool CXMeshFileLoader::readMatrix(core::matrix4& mat)
\r
2351 for (u32 i=0; i<16; ++i)
\r
2352 mat[i] = readFloat();
\r
2353 return checkForOneFollowingSemicolons();
\r
2357 } // end namespace scene
\r
2358 } // end namespace irr
\r