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 "IReadFile.h"
\r
16 #define _XREADER_DEBUG
\r
18 //#define BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
26 CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr)
\r
27 : AnimatedMesh(0), Buffer(0), P(0), End(0), BinaryNumCount(0), Line(0),
\r
28 CurFrame(0), MajorVersion(0), MinorVersion(0), BinaryFormat(false), FloatSize(0)
\r
31 setDebugName("CXMeshFileLoader");
\r
36 //! returns true if the file maybe is able to be loaded by this class
\r
37 //! based on the file extension (e.g. ".bsp")
\r
38 bool CXMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
\r
40 return core::hasFileExtension ( filename, "x" );
\r
44 //! creates/loads an animated mesh from the file.
\r
45 //! \return Pointer to the created mesh. Returns 0 if loading failed.
\r
46 //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
\r
47 //! See IReferenceCounted::drop() for more information.
\r
48 IAnimatedMesh* CXMeshFileLoader::createMesh(io::IReadFile* file)
\r
53 #ifdef _XREADER_DEBUG
\r
54 u32 time = os::Timer::getRealTime();
\r
57 AnimatedMesh = new CSkinnedMesh();
\r
61 AnimatedMesh->finalize();
\r
65 AnimatedMesh->drop();
\r
68 #ifdef _XREADER_DEBUG
\r
69 time = os::Timer::getRealTime() - time;
\r
70 core::stringc tmpString = "Time to load ";
\r
71 tmpString += BinaryFormat ? "binary" : "ascii";
\r
72 tmpString += " X file: ";
\r
75 os::Printer::log(tmpString.c_str());
\r
91 for (u32 i=0; i<Meshes.size(); ++i)
\r
95 return AnimatedMesh;
\r
99 bool CXMeshFileLoader::load(io::IReadFile* file)
\r
101 if (!readFileIntoMemory(file))
\r
107 for (u32 n=0; n<Meshes.size(); ++n)
\r
109 SXMesh *mesh=Meshes[n];
\r
111 // default material if nothing loaded
\r
112 if (!mesh->Materials.size())
\r
114 mesh->Materials.push_back(video::SMaterial());
\r
115 mesh->Materials[0].DiffuseColor.set(0xff777777);
\r
116 mesh->Materials[0].Shininess=0.f;
\r
117 mesh->Materials[0].SpecularColor.set(0xff777777);
\r
118 mesh->Materials[0].EmissiveColor.set(0xff000000);
\r
123 mesh->Buffers.reallocate(mesh->Materials.size());
\r
124 #ifndef BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
125 const u32 bufferOffset = AnimatedMesh->getMeshBufferCount();
\r
127 for (i=0; i<mesh->Materials.size(); ++i)
\r
129 mesh->Buffers.push_back( AnimatedMesh->addMeshBuffer() );
\r
130 mesh->Buffers.getLast()->Material = mesh->Materials[i];
\r
132 if (!mesh->HasSkinning)
\r
134 //Set up rigid animation
\r
135 if (mesh->AttachedJointID!=-1)
\r
137 AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back( AnimatedMesh->getMeshBuffers().size()-1 );
\r
142 if (!mesh->FaceMaterialIndices.size())
\r
144 mesh->FaceMaterialIndices.set_used(mesh->Indices.size() / 3);
\r
145 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
146 mesh->FaceMaterialIndices[i]=0;
\r
149 if (!mesh->HasVertexColors)
\r
151 for (u32 j=0;j<mesh->FaceMaterialIndices.size();++j)
\r
153 for (u32 id=j*3+0;id<=j*3+2;++id)
\r
155 mesh->Vertices[ mesh->Indices[id] ].Color = mesh->Buffers[mesh->FaceMaterialIndices[j]]->Material.DiffuseColor;
\r
160 #ifdef BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
162 //the same vertex can be used in many different meshbuffers, but it's slow to work out
\r
164 core::array< core::array< u32 > > verticesLinkIndex;
\r
165 verticesLinkIndex.reallocate(mesh->Vertices.size());
\r
166 core::array< core::array< u16 > > verticesLinkBuffer;
\r
167 verticesLinkBuffer.reallocate(mesh->Vertices.size());
\r
169 for (i=0;i<mesh->Vertices.size();++i)
\r
171 verticesLinkIndex.push_back( core::array< u32 >() );
\r
172 verticesLinkBuffer.push_back( core::array< u16 >() );
\r
175 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
177 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
179 core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
\r
182 for (u32 j=0; j < Array.size(); ++j)
\r
184 if (Array[j]==mesh->FaceMaterialIndices[i])
\r
192 Array.push_back( mesh->FaceMaterialIndices[i] );
\r
196 for (i=0;i<verticesLinkBuffer.size();++i)
\r
198 if (!verticesLinkBuffer[i].size())
\r
199 verticesLinkBuffer[i].push_back(0);
\r
202 for (i=0;i<mesh->Vertices.size();++i)
\r
204 core::array< u16 > &Array = verticesLinkBuffer[i];
\r
205 verticesLinkIndex[i].reallocate(Array.size());
\r
206 for (u32 j=0; j < Array.size(); ++j)
\r
208 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ Array[j] ];
\r
209 verticesLinkIndex[i].push_back( buffer->Vertices_Standard.size() );
\r
210 buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
\r
214 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
216 scene::SSkinMeshBuffer *buffer=mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
\r
218 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
220 core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
\r
222 for (u32 j=0;j< Array.size() ;++j)
\r
224 if ( Array[j]== mesh->FaceMaterialIndices[i] )
\r
225 buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ][j] );
\r
230 for (u32 j=0;j<mesh->WeightJoint.size();++j)
\r
232 ISkinnedMesh::SJoint* joint = AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]];
\r
233 ISkinnedMesh::SWeight& weight = joint->Weights[mesh->WeightNum[j]];
\r
235 u32 id = weight.vertex_id;
\r
237 if (id>=verticesLinkIndex.size())
\r
239 os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
\r
241 weight.strength=0.f;
\r
244 if (verticesLinkBuffer[id].size()==1)
\r
246 weight.vertex_id=verticesLinkIndex[id][0];
\r
247 weight.buffer_id=verticesLinkBuffer[id][0];
\r
249 else if (verticesLinkBuffer[id].size() != 0)
\r
251 for (u32 k=1; k < verticesLinkBuffer[id].size(); ++k)
\r
253 ISkinnedMesh::SWeight* WeightClone = AnimatedMesh->addWeight(joint);
\r
254 WeightClone->strength = weight.strength;
\r
255 WeightClone->vertex_id = verticesLinkIndex[id][k];
\r
256 WeightClone->buffer_id = verticesLinkBuffer[id][k];
\r
263 core::array< u32 > verticesLinkIndex;
\r
264 core::array< s16 > verticesLinkBuffer;
\r
265 verticesLinkBuffer.set_used(mesh->Vertices.size());
\r
268 for (i=0;i<mesh->Vertices.size();++i)
\r
270 // watch out for vertices which are not part of the mesh
\r
271 // they will keep the -1 and can lead to out-of-bounds access
\r
272 verticesLinkBuffer[i]=-1;
\r
275 bool warned = false;
\r
276 // store meshbuffer number per vertex
\r
277 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
279 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
281 if ((verticesLinkBuffer[mesh->Indices[id]] != -1) && (verticesLinkBuffer[mesh->Indices[id]] != (s16)mesh->FaceMaterialIndices[i]))
\r
285 os::Printer::log("X loader", "Duplicated vertex, animation might be corrupted.", ELL_WARNING);
\r
288 const u32 tmp = mesh->Vertices.size();
\r
289 mesh->Vertices.push_back(mesh->Vertices[ mesh->Indices[id] ]);
\r
290 mesh->Indices[id] = tmp;
\r
291 verticesLinkBuffer.set_used(mesh->Vertices.size());
\r
293 verticesLinkBuffer[ mesh->Indices[id] ] = mesh->FaceMaterialIndices[i];
\r
297 if (mesh->FaceMaterialIndices.size() != 0)
\r
299 // store vertices in buffers and remember relation in verticesLinkIndex
\r
300 u32* vCountArray = new u32[mesh->Buffers.size()];
\r
301 memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
\r
302 // count vertices in each buffer and reallocate
\r
303 for (i=0; i<mesh->Vertices.size(); ++i)
\r
305 if (verticesLinkBuffer[i] != -1)
\r
306 ++vCountArray[verticesLinkBuffer[i]];
\r
308 if (mesh->TCoords2.size())
\r
310 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
312 mesh->Buffers[i]->Vertices_2TCoords.reallocate(vCountArray[i]);
\r
313 mesh->Buffers[i]->VertexType=video::EVT_2TCOORDS;
\r
318 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
319 mesh->Buffers[i]->Vertices_Standard.reallocate(vCountArray[i]);
\r
322 verticesLinkIndex.set_used(mesh->Vertices.size());
\r
323 // actually store vertices
\r
324 for (i=0; i<mesh->Vertices.size(); ++i)
\r
326 // if a vertex is missing for some reason, just skip it
\r
327 if (verticesLinkBuffer[i]==-1)
\r
329 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ verticesLinkBuffer[i] ];
\r
331 if (mesh->TCoords2.size())
\r
333 verticesLinkIndex[i] = buffer->Vertices_2TCoords.size();
\r
334 buffer->Vertices_2TCoords.push_back( mesh->Vertices[i] );
\r
335 // We have a problem with correct tcoord2 handling here
\r
336 // crash fixed for now by checking the values
\r
337 buffer->Vertices_2TCoords.getLast().TCoords2=(i<mesh->TCoords2.size())?mesh->TCoords2[i]:mesh->Vertices[i].TCoords;
\r
341 verticesLinkIndex[i] = buffer->Vertices_Standard.size();
\r
342 buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
\r
346 // count indices per buffer and reallocate
\r
347 memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
\r
348 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
349 ++vCountArray[ mesh->FaceMaterialIndices[i] ];
\r
350 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
351 mesh->Buffers[i]->Indices.reallocate(vCountArray[i]);
\r
352 delete [] vCountArray;
\r
353 // create indices per buffer
\r
354 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
356 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
\r
357 for (u32 id=i*3+0; id!=i*3+3; ++id)
\r
359 buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ] );
\r
364 for (u32 j=0; j<mesh->WeightJoint.size(); ++j)
\r
366 ISkinnedMesh::SWeight& weight = (AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]->Weights[mesh->WeightNum[j]]);
\r
368 u32 id = weight.vertex_id;
\r
370 if (id>=verticesLinkIndex.size())
\r
372 os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
\r
374 weight.strength=0.f;
\r
377 weight.vertex_id=verticesLinkIndex[id];
\r
378 weight.buffer_id=verticesLinkBuffer[id] + bufferOffset;
\r
389 //! Reads file into memory
\r
390 bool CXMeshFileLoader::readFileIntoMemory(io::IReadFile* file)
\r
392 const long size = file->getSize();
\r
395 os::Printer::log("X File is too small.", ELL_WARNING);
\r
399 Buffer = new c8[size];
\r
401 //! read all into memory
\r
402 if (file->read(Buffer, size) != static_cast<size_t>(size))
\r
404 os::Printer::log("Could not read from x file.", ELL_WARNING);
\r
409 End = Buffer + size;
\r
411 //! check header "xof "
\r
412 if (strncmp(Buffer, "xof ", 4)!=0)
\r
414 os::Printer::log("Not an x file, wrong header.", ELL_WARNING);
\r
418 //! read minor and major version, e.g. 0302 or 0303
\r
420 tmp[0] = Buffer[4];
\r
421 tmp[1] = Buffer[5];
\r
423 MajorVersion = core::strtoul10(tmp);
\r
425 tmp[0] = Buffer[6];
\r
426 tmp[1] = Buffer[7];
\r
427 MinorVersion = core::strtoul10(tmp);
\r
430 if (strncmp(&Buffer[8], "txt ", 4) ==0)
\r
431 BinaryFormat = false;
\r
432 else if (strncmp(&Buffer[8], "bin ", 4) ==0)
\r
433 BinaryFormat = true;
\r
436 os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING);
\r
441 //! read float size
\r
442 if (strncmp(&Buffer[12], "0032", 4) ==0)
\r
444 else if (strncmp(&Buffer[12], "0064", 4) ==0)
\r
448 os::Printer::log("Float size not supported.", ELL_WARNING);
\r
454 readUntilEndOfLine();
\r
460 //! Parses the file
\r
461 bool CXMeshFileLoader::parseFile()
\r
463 while(parseDataObject())
\r
472 //! Parses the next Data object in the file
\r
473 bool CXMeshFileLoader::parseDataObject()
\r
475 core::stringc objectName = getNextToken();
\r
477 if (objectName.size() == 0)
\r
480 // parse specific object
\r
481 #ifdef _XREADER_DEBUG
\r
482 os::Printer::log("debug DataObject:", objectName.c_str(), ELL_DEBUG);
\r
485 if (objectName == "template")
\r
486 return parseDataObjectTemplate();
\r
488 if (objectName == "Frame")
\r
490 return parseDataObjectFrame( 0 );
\r
493 if (objectName == "Mesh")
\r
495 // some meshes have no frames at all
\r
496 //CurFrame = AnimatedMesh->addJoint(0);
\r
498 SXMesh *mesh=new SXMesh;
\r
500 //mesh->Buffer=AnimatedMesh->addMeshBuffer();
\r
501 Meshes.push_back(mesh);
\r
503 return parseDataObjectMesh(*mesh);
\r
506 if (objectName == "AnimationSet")
\r
508 return parseDataObjectAnimationSet();
\r
511 if (objectName == "AnimTicksPerSecond")
\r
513 return parseDataObjectAnimationTicksPerSecond();
\r
516 if (objectName == "Material")
\r
518 return parseUnknownDataObject();
\r
521 if (objectName == "}")
\r
523 os::Printer::log("} found in dataObject", ELL_WARNING);
\r
527 os::Printer::log("Unknown data object in animation of .x file", objectName.c_str(), ELL_WARNING);
\r
529 return parseUnknownDataObject();
\r
533 bool CXMeshFileLoader::parseDataObjectTemplate()
\r
535 #ifdef _XREADER_DEBUG
\r
536 os::Printer::log("CXFileReader: Reading template", ELL_DEBUG);
\r
539 // parse a template data object. Currently not stored.
\r
540 core::stringc name;
\r
542 if (!readHeadOfDataObject(&name))
\r
544 os::Printer::log("Left delimiter in template data object missing.",
\r
545 name.c_str(), ELL_WARNING);
\r
546 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
553 // read and ignore data members
\r
556 core::stringc s = getNextToken();
\r
569 bool CXMeshFileLoader::parseDataObjectFrame(CSkinnedMesh::SJoint *Parent)
\r
571 #ifdef _XREADER_DEBUG
\r
572 os::Printer::log("CXFileReader: Reading frame", ELL_DEBUG);
\r
575 // A coordinate frame, or "frame of reference." The Frame template
\r
576 // is open and can contain any object. The Direct3D extensions (D3DX)
\r
577 // mesh-loading functions recognize Mesh, FrameTransformMatrix, and
\r
578 // Frame template instances as child objects when loading a Frame
\r
583 core::stringc name;
\r
585 if (!readHeadOfDataObject(&name))
\r
587 os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING);
\r
588 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
592 CSkinnedMesh::SJoint *joint=0;
\r
596 for (u32 n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
598 if (AnimatedMesh->getAllJoints()[n]->Name==name)
\r
600 joint=AnimatedMesh->getAllJoints()[n];
\r
609 #ifdef _XREADER_DEBUG
\r
610 os::Printer::log("creating joint ", name.c_str(), ELL_DEBUG);
\r
612 joint=AnimatedMesh->addJoint(Parent);
\r
614 JointID=AnimatedMesh->getAllJoints().size()-1;
\r
618 #ifdef _XREADER_DEBUG
\r
619 os::Printer::log("using joint ", name.c_str(), ELL_DEBUG);
\r
622 Parent->Children.push_back(joint);
\r
625 // Now inside a frame.
\r
626 // read tokens until closing brace is reached.
\r
630 core::stringc objectName = getNextToken();
\r
632 #ifdef _XREADER_DEBUG
\r
633 os::Printer::log("debug DataObject in frame:", objectName.c_str(), ELL_DEBUG);
\r
636 if (objectName.size() == 0)
\r
638 os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING);
\r
639 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
643 if (objectName == "}")
\r
645 break; // frame finished
\r
648 if (objectName == "Frame")
\r
651 if (!parseDataObjectFrame(joint))
\r
655 if (objectName == "FrameTransformMatrix")
\r
657 if (!parseDataObjectTransformationMatrix(joint->LocalMatrix))
\r
660 //joint->LocalAnimatedMatrix
\r
661 //joint->LocalAnimatedMatrix.makeInverse();
\r
662 //joint->LocalMatrix=tmp*joint->LocalAnimatedMatrix;
\r
665 if (objectName == "Mesh")
\r
668 frame.Meshes.push_back(SXMesh());
\r
669 if (!parseDataObjectMesh(frame.Meshes.getLast()))
\r
672 SXMesh *mesh=new SXMesh;
\r
674 mesh->AttachedJointID=JointID;
\r
676 Meshes.push_back(mesh);
\r
678 if (!parseDataObjectMesh(*mesh))
\r
683 os::Printer::log("Unknown data object in frame in x file", objectName.c_str(), ELL_WARNING);
\r
684 if (!parseUnknownDataObject())
\r
693 bool CXMeshFileLoader::parseDataObjectTransformationMatrix(core::matrix4 &mat)
\r
695 #ifdef _XREADER_DEBUG
\r
696 os::Printer::log("CXFileReader: Reading Transformation Matrix", ELL_DEBUG);
\r
699 if (!readHeadOfDataObject())
\r
701 os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING);
\r
702 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
708 if (!checkForOneFollowingSemicolons())
\r
710 os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING);
\r
711 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
714 if (!checkForClosingBrace())
\r
716 os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING);
\r
717 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
725 bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh)
\r
727 core::stringc name;
\r
729 if (!readHeadOfDataObject(&name))
\r
731 #ifdef _XREADER_DEBUG
\r
732 os::Printer::log("CXFileReader: Reading mesh", ELL_DEBUG);
\r
734 os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING);
\r
735 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
739 #ifdef _XREADER_DEBUG
\r
740 os::Printer::log("CXFileReader: Reading mesh", name.c_str(), ELL_DEBUG);
\r
743 // read vertex count
\r
744 const u32 nVertices = readInt();
\r
747 mesh.Vertices.set_used(nVertices);
\r
748 for (u32 n=0; n<nVertices; ++n)
\r
750 readVector3(mesh.Vertices[n].Pos);
\r
751 mesh.Vertices[n].Color=0xFFFFFFFF;
\r
752 mesh.Vertices[n].Normal=core::vector3df(0.0f);
\r
755 if (!checkForTwoFollowingSemicolons())
\r
757 os::Printer::log("No finishing semicolon in Mesh Vertex Array found in x file", ELL_WARNING);
\r
758 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
762 const u32 nFaces = readInt();
\r
764 mesh.Indices.set_used(nFaces * 3);
\r
765 mesh.IndexCountPerFace.set_used(nFaces);
\r
767 core::array<u32> polygonfaces;
\r
768 u32 currentIndex = 0;
\r
770 for (u32 k=0; k<nFaces; ++k)
\r
772 const u32 fcnt = readInt();
\r
778 os::Printer::log("Invalid face count (<3) found in Mesh x file reader.", ELL_WARNING);
\r
779 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
783 // read face indices
\r
784 polygonfaces.set_used(fcnt);
\r
785 u32 triangles = (fcnt-2);
\r
786 mesh.Indices.set_used(mesh.Indices.size() + ((triangles-1)*3));
\r
787 mesh.IndexCountPerFace[k] = (u16)(triangles * 3);
\r
789 for (u32 f=0; f<fcnt; ++f)
\r
790 polygonfaces[f] = readInt();
\r
792 for (u32 jk=0; jk<triangles; ++jk)
\r
794 mesh.Indices[currentIndex++] = polygonfaces[0];
\r
795 mesh.Indices[currentIndex++] = polygonfaces[jk+1];
\r
796 mesh.Indices[currentIndex++] = polygonfaces[jk+2];
\r
799 // TODO: change face indices in material list
\r
803 mesh.Indices[currentIndex++] = readInt();
\r
804 mesh.Indices[currentIndex++] = readInt();
\r
805 mesh.Indices[currentIndex++] = readInt();
\r
806 mesh.IndexCountPerFace[k] = 3;
\r
810 if (!checkForTwoFollowingSemicolons())
\r
812 os::Printer::log("No finishing semicolon in Mesh Face Array found in x file", ELL_WARNING);
\r
813 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
816 // here, other data objects may follow
\r
820 core::stringc objectName = getNextToken();
\r
822 if (objectName.size() == 0)
\r
824 os::Printer::log("Unexpected ending found in Mesh in x file.", ELL_WARNING);
\r
825 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
829 if (objectName == "}")
\r
831 break; // mesh finished
\r
834 #ifdef _XREADER_DEBUG
\r
835 os::Printer::log("debug DataObject in mesh:", objectName.c_str(), ELL_DEBUG);
\r
838 if (objectName == "MeshNormals")
\r
840 if (!parseDataObjectMeshNormals(mesh))
\r
844 if (objectName == "MeshTextureCoords")
\r
846 if (!parseDataObjectMeshTextureCoords(mesh))
\r
850 if (objectName == "MeshVertexColors")
\r
852 if (!parseDataObjectMeshVertexColors(mesh))
\r
856 if (objectName == "MeshMaterialList")
\r
858 if (!parseDataObjectMeshMaterialList(mesh))
\r
862 if (objectName == "VertexDuplicationIndices")
\r
864 // we'll ignore vertex duplication indices
\r
866 if (!parseUnknownDataObject())
\r
870 if (objectName == "DeclData")
\r
872 if (!readHeadOfDataObject())
\r
874 os::Printer::log("No starting brace in DeclData found.", ELL_WARNING);
\r
875 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
878 // arbitrary vertex attributes
\r
879 // first comes the number of element definitions
\r
880 // then the vertex element type definitions
\r
881 // with format type;tesselator;semantics;usageindex
\r
882 // we want to support 2;0;6;0 == tangent
\r
883 // 2;0;7;0 == binormal
\r
884 // 2;0;3;0 == normal
\r
885 // 1/2;0;5;0 == 1st uv coord
\r
886 // and 1/2;0;5;1 == 2nd uv coord
\r
887 // type==2 is 3xf32, type==1 is 2xf32
\r
889 const u32 dcnt = readInt();
\r
891 s16 normalpos = -1;
\r
894 s16 tangentpos = -1;
\r
895 s16 binormalpos = -1;
\r
896 s16 normaltype = -1;
\r
899 s16 tangenttype = -1;
\r
900 s16 binormaltype = -1;
\r
902 (void)tangentpos; // disable unused variable warnings
\r
903 (void)binormalpos; // disable unused variable warnings
\r
904 (void)tangenttype; // disable unused variable warnings
\r
905 (void)binormaltype; // disable unused variable warnings
\r
907 for (j=0; j<dcnt; ++j)
\r
909 const u32 type = readInt();
\r
910 //const u32 tesselator = readInt();
\r
912 const u32 semantics = readInt();
\r
913 const u32 index = readInt();
\r
934 tangenttype = type;
\r
937 binormalpos = size;
\r
938 binormaltype = type;
\r
992 const u32 datasize = readInt();
\r
993 u32* data = new u32[datasize];
\r
994 for (j=0; j<datasize; ++j)
\r
997 if (!checkForOneFollowingSemicolons())
\r
999 os::Printer::log("No finishing semicolon in DeclData found.", ELL_WARNING);
\r
1000 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1002 if (!checkForClosingBrace())
\r
1004 os::Printer::log("No closing brace in DeclData.", ELL_WARNING);
\r
1005 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1009 u8* dataptr = (u8*) data;
\r
1010 if ((uv2pos != -1) && (uv2type == 1))
\r
1011 mesh.TCoords2.reallocate(mesh.Vertices.size());
\r
1012 for (j=0; j<mesh.Vertices.size(); ++j)
\r
1014 if ((normalpos != -1) && (normaltype == 2))
\r
1015 mesh.Vertices[j].Normal.set(*((core::vector3df*)(dataptr+normalpos)));
\r
1016 if ((uvpos != -1) && (uvtype == 1))
\r
1017 mesh.Vertices[j].TCoords.set(*((core::vector2df*)(dataptr+uvpos)));
\r
1018 if ((uv2pos != -1) && (uv2type == 1))
\r
1019 mesh.TCoords2.push_back(*((core::vector2df*)(dataptr+uv2pos)));
\r
1025 if (objectName == "FVFData")
\r
1027 if (!readHeadOfDataObject())
\r
1029 os::Printer::log("No starting brace in FVFData found.", ELL_WARNING);
\r
1030 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1033 const u32 dataformat = readInt();
\r
1034 const u32 datasize = readInt();
\r
1035 u32* data = new u32[datasize];
\r
1036 for (u32 j=0; j<datasize; ++j)
\r
1037 data[j]=readInt();
\r
1038 if (dataformat&0x102) // 2nd uv set
\r
1040 mesh.TCoords2.reallocate(mesh.Vertices.size());
\r
1041 u8* dataptr = (u8*) data;
\r
1042 const u32 size=((dataformat>>8)&0xf)*sizeof(core::vector2df);
\r
1043 for (u32 j=0; j<mesh.Vertices.size(); ++j)
\r
1045 mesh.TCoords2.push_back(*((core::vector2df*)(dataptr)));
\r
1050 if (!checkForOneFollowingSemicolons())
\r
1052 os::Printer::log("No finishing semicolon in FVFData found.", ELL_WARNING);
\r
1053 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1055 if (!checkForClosingBrace())
\r
1057 os::Printer::log("No closing brace in FVFData found in x file", ELL_WARNING);
\r
1058 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1063 if (objectName == "XSkinMeshHeader")
\r
1065 if (!parseDataObjectSkinMeshHeader(mesh))
\r
1069 if (objectName == "SkinWeights")
\r
1071 //mesh.SkinWeights.push_back(SXSkinWeight());
\r
1072 //if (!parseDataObjectSkinWeights(mesh.SkinWeights.getLast()))
\r
1073 if (!parseDataObjectSkinWeights(mesh))
\r
1078 os::Printer::log("Unknown data object in mesh in x file", objectName.c_str(), ELL_WARNING);
\r
1079 if (!parseUnknownDataObject())
\r
1088 bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh)
\r
1090 #ifdef _XREADER_DEBUG
\r
1091 os::Printer::log("CXFileReader: Reading mesh skin weights", ELL_DEBUG);
\r
1094 if (!readHeadOfDataObject())
\r
1096 os::Printer::log("No opening brace in Skin Weights found in .x file", ELL_WARNING);
\r
1097 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1101 core::stringc TransformNodeName;
\r
1103 if (!getNextTokenAsString(TransformNodeName))
\r
1105 os::Printer::log("Unknown syntax while reading transform node name string in .x file", ELL_WARNING);
\r
1106 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1110 mesh.HasSkinning=true;
\r
1112 CSkinnedMesh::SJoint *joint=0;
\r
1115 for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
1117 if (AnimatedMesh->getAllJoints()[n]->Name==TransformNodeName)
\r
1119 joint=AnimatedMesh->getAllJoints()[n];
\r
1126 #ifdef _XREADER_DEBUG
\r
1127 os::Printer::log("creating joint for skinning ", TransformNodeName.c_str(), ELL_DEBUG);
\r
1129 n = AnimatedMesh->getAllJoints().size();
\r
1130 joint=AnimatedMesh->addJoint(0);
\r
1131 joint->Name=TransformNodeName;
\r
1134 // read vertex weights
\r
1135 const u32 nWeights = readInt();
\r
1137 // read vertex indices
\r
1140 const u32 jointStart = joint->Weights.size();
\r
1141 joint->Weights.reallocate(jointStart+nWeights);
\r
1143 mesh.WeightJoint.reallocate( mesh.WeightJoint.size() + nWeights );
\r
1144 mesh.WeightNum.reallocate( mesh.WeightNum.size() + nWeights );
\r
1146 for (i=0; i<nWeights; ++i)
\r
1148 mesh.WeightJoint.push_back(n);
\r
1149 mesh.WeightNum.push_back(joint->Weights.size());
\r
1151 CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(joint);
\r
1153 weight->buffer_id=0;
\r
1154 weight->vertex_id=readInt();
\r
1157 // read vertex weights
\r
1159 for (i=jointStart; i<jointStart+nWeights; ++i)
\r
1160 joint->Weights[i].strength = readFloat();
\r
1162 // read matrix offset
\r
1164 // transforms the mesh vertices to the space of the bone
\r
1165 // When concatenated to the bone's transform, this provides the
\r
1166 // world space coordinates of the mesh as affected by the bone
\r
1167 core::matrix4& MatrixOffset = joint->GlobalInversedMatrix;
\r
1169 readMatrix(MatrixOffset);
\r
1171 if (!checkForOneFollowingSemicolons())
\r
1173 os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING);
\r
1174 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1177 if (!checkForClosingBrace())
\r
1179 os::Printer::log("No closing brace in Skin Weights found in x file", ELL_WARNING);
\r
1180 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1188 bool CXMeshFileLoader::parseDataObjectSkinMeshHeader(SXMesh& mesh)
\r
1190 #ifdef _XREADER_DEBUG
\r
1191 os::Printer::log("CXFileReader: Reading skin mesh header", ELL_DEBUG);
\r
1194 if (!readHeadOfDataObject())
\r
1196 os::Printer::log("No opening brace in Skin Mesh header found in .x file", ELL_WARNING);
\r
1197 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1201 mesh.MaxSkinWeightsPerVertex = readInt();
\r
1202 mesh.MaxSkinWeightsPerFace = readInt();
\r
1203 mesh.BoneCount = readInt();
\r
1205 if (!BinaryFormat)
\r
1206 getNextToken(); // skip semicolon
\r
1208 if (!checkForClosingBrace())
\r
1210 os::Printer::log("No closing brace in skin mesh header in x file", ELL_WARNING);
\r
1211 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1219 bool CXMeshFileLoader::parseDataObjectMeshNormals(SXMesh &mesh)
\r
1221 #ifdef _XREADER_DEBUG
\r
1222 os::Printer::log("CXFileReader: reading mesh normals", ELL_DEBUG);
\r
1225 if (!readHeadOfDataObject())
\r
1227 os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING);
\r
1228 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1233 const u32 nNormals = readInt();
\r
1234 core::array<core::vector3df> normals;
\r
1235 normals.set_used(nNormals);
\r
1238 for (u32 i=0; i<nNormals; ++i)
\r
1239 readVector3(normals[i]);
\r
1241 if (!checkForTwoFollowingSemicolons())
\r
1243 os::Printer::log("No finishing semicolon in Mesh Normals Array found in x file", ELL_WARNING);
\r
1244 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1247 core::array<u32> normalIndices;
\r
1248 normalIndices.set_used(mesh.Indices.size());
\r
1250 // read face normal indices
\r
1251 const u32 nFNormals = readInt();
\r
1253 u32 normalidx = 0;
\r
1254 core::array<u32> polygonfaces;
\r
1255 for (u32 k=0; k<nFNormals; ++k)
\r
1257 const u32 fcnt = readInt();
\r
1258 u32 triangles = fcnt - 2;
\r
1259 u32 indexcount = triangles * 3;
\r
1261 if (indexcount != mesh.IndexCountPerFace[k])
\r
1263 os::Printer::log("Not matching normal and face index count found in x file", ELL_WARNING);
\r
1264 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1268 if (indexcount == 3)
\r
1270 // default, only one triangle in this face
\r
1271 for (u32 h=0; h<3; ++h)
\r
1273 const u32 normalnum = readInt();
\r
1274 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[normalnum]);
\r
1279 polygonfaces.set_used(fcnt);
\r
1280 // multiple triangles in this face
\r
1281 for (u32 h=0; h<fcnt; ++h)
\r
1282 polygonfaces[h] = readInt();
\r
1284 for (u32 jk=0; jk<triangles; ++jk)
\r
1286 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[0]]);
\r
1287 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+1]]);
\r
1288 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+2]]);
\r
1293 if (!checkForTwoFollowingSemicolons())
\r
1295 os::Printer::log("No finishing semicolon in Mesh Face Normals Array found in x file", ELL_WARNING);
\r
1296 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1299 if (!checkForClosingBrace())
\r
1301 os::Printer::log("No closing brace in Mesh Normals found in x file", ELL_WARNING);
\r
1302 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1310 bool CXMeshFileLoader::parseDataObjectMeshTextureCoords(SXMesh &mesh)
\r
1312 #ifdef _XREADER_DEBUG
\r
1313 os::Printer::log("CXFileReader: reading mesh texture coordinates", ELL_DEBUG);
\r
1316 if (!readHeadOfDataObject())
\r
1318 os::Printer::log("No opening brace in Mesh Texture Coordinates found in x file", ELL_WARNING);
\r
1319 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1323 const u32 nCoords = readInt();
\r
1324 for (u32 i=0; i<nCoords; ++i)
\r
1325 readVector2(mesh.Vertices[i].TCoords);
\r
1327 if (!checkForTwoFollowingSemicolons())
\r
1329 os::Printer::log("No finishing semicolon in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1330 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1333 if (!checkForClosingBrace())
\r
1335 os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1336 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1344 bool CXMeshFileLoader::parseDataObjectMeshVertexColors(SXMesh &mesh)
\r
1346 #ifdef _XREADER_DEBUG
\r
1347 os::Printer::log("CXFileReader: reading mesh vertex colors", ELL_DEBUG);
\r
1350 if (!readHeadOfDataObject())
\r
1352 os::Printer::log("No opening brace for Mesh Vertex Colors found in x file", ELL_WARNING);
\r
1353 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1357 mesh.HasVertexColors=true;
\r
1358 const u32 nColors = readInt();
\r
1359 for (u32 i=0; i<nColors; ++i)
\r
1361 const u32 Index=readInt();
\r
1362 if (Index>=mesh.Vertices.size())
\r
1364 os::Printer::log("index value in parseDataObjectMeshVertexColors out of bounds", ELL_WARNING);
\r
1365 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1368 readRGBA(mesh.Vertices[Index].Color);
\r
1369 checkForOneFollowingSemicolons();
\r
1372 if (!checkForOneFollowingSemicolons())
\r
1374 os::Printer::log("No finishing semicolon in Mesh Vertex Colors Array found in x file", ELL_WARNING);
\r
1375 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1378 if (!checkForClosingBrace())
\r
1380 os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1381 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1389 bool CXMeshFileLoader::parseDataObjectMeshMaterialList(SXMesh &mesh)
\r
1391 #ifdef _XREADER_DEBUG
\r
1392 os::Printer::log("CXFileReader: Reading mesh material list", ELL_DEBUG);
\r
1395 if (!readHeadOfDataObject())
\r
1397 os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING);
\r
1398 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1402 // read material count
\r
1403 mesh.Materials.reallocate(readInt());
\r
1405 // read non triangulated face material index count
\r
1406 const u32 nFaceIndices = readInt();
\r
1408 // There seems to be a compact representation of "all faces the same material"
\r
1409 // being represented as 1;1;0;; which means 1 material, 1 face with first material
\r
1410 // all the other faces have to obey then, so check is disabled
\r
1411 //if (nFaceIndices != mesh.IndexCountPerFace.size())
\r
1412 // os::Printer::log("Index count per face not equal to face material index count in x file.", ELL_WARNING);
\r
1414 // read non triangulated face indices and create triangulated ones
\r
1415 mesh.FaceMaterialIndices.set_used( mesh.Indices.size() / 3);
\r
1416 u32 triangulatedindex = 0;
\r
1418 for (u32 tfi=0; tfi<mesh.IndexCountPerFace.size(); ++tfi)
\r
1420 if (tfi<nFaceIndices)
\r
1422 const u32 fc = mesh.IndexCountPerFace[tfi]/3;
\r
1423 for (u32 k=0; k<fc; ++k)
\r
1424 mesh.FaceMaterialIndices[triangulatedindex++] = ind;
\r
1427 // in version 03.02, the face indices end with two semicolons.
\r
1428 // commented out version check, as version 03.03 exported from blender also has 2 semicolons
\r
1429 if (!BinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
\r
1435 // read following data objects
\r
1439 core::stringc objectName = getNextToken();
\r
1441 if (objectName.size() == 0)
\r
1443 os::Printer::log("Unexpected ending found in Mesh Material list in .x file.", ELL_WARNING);
\r
1444 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1448 if (objectName == "}")
\r
1450 break; // material list finished
\r
1453 if (objectName == "{")
\r
1455 // template materials now available thanks to joeWright
\r
1456 objectName = getNextToken();
\r
1457 mesh.Materials.push_back(video::SMaterial());
\r
1458 getNextToken(); // skip }
\r
1461 if (objectName == "Material")
\r
1463 mesh.Materials.push_back(video::SMaterial());
\r
1464 if (!parseUnknownDataObject())
\r
1468 if (objectName == ";")
\r
1474 os::Printer::log("Unknown data object in material list in x file", objectName.c_str(), ELL_WARNING);
\r
1475 if (!parseUnknownDataObject())
\r
1483 bool CXMeshFileLoader::parseDataObjectAnimationSet()
\r
1485 #ifdef _XREADER_DEBUG
\r
1486 os::Printer::log("CXFileReader: Reading animation set", ELL_DEBUG);
\r
1489 core::stringc AnimationName;
\r
1491 if (!readHeadOfDataObject(&AnimationName))
\r
1493 os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING);
\r
1494 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1497 os::Printer::log("Reading animationset ", AnimationName, ELL_DEBUG);
\r
1501 core::stringc objectName = getNextToken();
\r
1503 if (objectName.size() == 0)
\r
1505 os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING);
\r
1506 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1510 if (objectName == "}")
\r
1512 break; // animation set finished
\r
1515 if (objectName == "Animation")
\r
1517 if (!parseDataObjectAnimation())
\r
1522 os::Printer::log("Unknown data object in animation set in x file", objectName.c_str(), ELL_WARNING);
\r
1523 if (!parseUnknownDataObject())
\r
1530 bool CXMeshFileLoader::parseDataObjectAnimationTicksPerSecond()
\r
1532 #ifdef _XREADER_DEBUG
\r
1533 os::Printer::log("CXFileReader: reading AnimationTicksPerSecond", ELL_DEBUG);
\r
1536 if (!readHeadOfDataObject())
\r
1538 os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING);
\r
1539 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1543 const u32 ticks = readInt();
\r
1545 if (!checkForOneFollowingSemicolons())
\r
1547 os::Printer::log("No closing semicolon in AnimationTicksPerSecond in x file", ELL_WARNING);
\r
1548 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1552 if (!checkForClosingBrace())
\r
1554 os::Printer::log("No closing brace in AnimationTicksPerSecond in x file", ELL_WARNING);
\r
1555 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1559 AnimatedMesh->setAnimationSpeed(static_cast<irr::f32>(ticks));
\r
1564 bool CXMeshFileLoader::parseDataObjectAnimation()
\r
1566 #ifdef _XREADER_DEBUG
\r
1567 os::Printer::log("CXFileReader: reading animation", ELL_DEBUG);
\r
1570 if (!readHeadOfDataObject())
\r
1572 os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING);
\r
1573 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1577 //anim.closed = true;
\r
1578 //anim.linearPositionQuality = true;
\r
1579 CSkinnedMesh::SJoint animationDump;
\r
1581 core::stringc FrameName;
\r
1585 core::stringc objectName = getNextToken();
\r
1587 if (objectName.size() == 0)
\r
1589 os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
\r
1590 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1594 if (objectName == "}")
\r
1596 break; // animation finished
\r
1599 if (objectName == "AnimationKey")
\r
1601 if (!parseDataObjectAnimationKey(&animationDump))
\r
1605 if (objectName == "AnimationOptions")
\r
1607 //TODO: parse options.
\r
1608 if (!parseUnknownDataObject())
\r
1612 if (objectName == "{")
\r
1614 // read frame name
\r
1615 FrameName = getNextToken();
\r
1617 if (!checkForClosingBrace())
\r
1619 os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
\r
1620 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1626 os::Printer::log("Unknown data object in animation in x file", objectName.c_str(), ELL_WARNING);
\r
1627 if (!parseUnknownDataObject())
\r
1632 if (FrameName.size() != 0)
\r
1634 #ifdef _XREADER_DEBUG
\r
1635 os::Printer::log("frame name", FrameName.c_str(), ELL_DEBUG);
\r
1637 CSkinnedMesh::SJoint *joint=0;
\r
1640 for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
1642 if (AnimatedMesh->getAllJoints()[n]->Name==FrameName)
\r
1644 joint=AnimatedMesh->getAllJoints()[n];
\r
1651 #ifdef _XREADER_DEBUG
\r
1652 os::Printer::log("creating joint for animation ", FrameName.c_str(), ELL_DEBUG);
\r
1654 joint=AnimatedMesh->addJoint(0);
\r
1655 joint->Name=FrameName;
\r
1658 joint->PositionKeys.reallocate(joint->PositionKeys.size()+animationDump.PositionKeys.size());
\r
1659 for (n=0; n<animationDump.PositionKeys.size(); ++n)
\r
1661 joint->PositionKeys.push_back(animationDump.PositionKeys[n]);
\r
1664 joint->ScaleKeys.reallocate(joint->ScaleKeys.size()+animationDump.ScaleKeys.size());
\r
1665 for (n=0; n<animationDump.ScaleKeys.size(); ++n)
\r
1667 joint->ScaleKeys.push_back(animationDump.ScaleKeys[n]);
\r
1670 joint->RotationKeys.reallocate(joint->RotationKeys.size()+animationDump.RotationKeys.size());
\r
1671 for (n=0; n<animationDump.RotationKeys.size(); ++n)
\r
1673 joint->RotationKeys.push_back(animationDump.RotationKeys[n]);
\r
1677 os::Printer::log("joint name was never given", ELL_WARNING);
\r
1683 bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint)
\r
1685 #ifdef _XREADER_DEBUG
\r
1686 os::Printer::log("CXFileReader: reading animation key", ELL_DEBUG);
\r
1689 if (!readHeadOfDataObject())
\r
1691 os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING);
\r
1692 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1698 const u32 keyType = readInt();
\r
1702 os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING);
\r
1703 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1707 // read number of keys
\r
1708 const u32 numberOfKeys = readInt();
\r
1710 // eat the semicolon after the "0". if there are keys present, readInt()
\r
1711 // does this for us. If there aren't, we need to do it explicitly
\r
1712 if (numberOfKeys == 0)
\r
1713 checkForOneFollowingSemicolons();
\r
1715 for (u32 i=0; i<numberOfKeys; ++i)
\r
1718 const f32 time = (f32)readInt();
\r
1723 case 0: //rotation
\r
1725 //read quaternions
\r
1728 if (readInt() != 4)
\r
1730 os::Printer::log("Expected 4 numbers in animation key in x file", ELL_WARNING);
\r
1731 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1735 f32 W = -readFloat();
\r
1736 f32 X = -readFloat();
\r
1737 f32 Y = -readFloat();
\r
1738 f32 Z = -readFloat();
\r
1740 if (!checkForTwoFollowingSemicolons())
\r
1742 os::Printer::log("No finishing semicolon after quaternion animation key in x file", ELL_WARNING);
\r
1743 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1746 ISkinnedMesh::SRotationKey *key=AnimatedMesh->addRotationKey(joint);
\r
1748 key->rotation.set(X,Y,Z,W);
\r
1749 key->rotation.normalize();
\r
1753 case 2: //position
\r
1758 if (readInt() != 3)
\r
1760 os::Printer::log("Expected 3 numbers in animation key in x file", ELL_WARNING);
\r
1761 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1765 core::vector3df vector;
\r
1766 readVector3(vector);
\r
1768 if (!checkForTwoFollowingSemicolons())
\r
1770 os::Printer::log("No finishing semicolon after vector animation key in x file", ELL_WARNING);
\r
1771 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1776 ISkinnedMesh::SPositionKey *key=AnimatedMesh->addPositionKey(joint);
\r
1778 key->position=vector;
\r
1782 ISkinnedMesh::SScaleKey *key=AnimatedMesh->addScaleKey(joint);
\r
1784 key->scale=vector;
\r
1794 if (readInt() != 16)
\r
1796 os::Printer::log("Expected 16 numbers in animation key in x file", ELL_WARNING);
\r
1797 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1802 core::matrix4 mat(core::matrix4::EM4CONST_NOTHING);
\r
1805 //mat=joint->LocalMatrix*mat;
\r
1807 if (!checkForOneFollowingSemicolons())
\r
1809 os::Printer::log("No finishing semicolon after matrix animation key in x file", ELL_WARNING);
\r
1810 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1813 //core::vector3df rotation = mat.getRotationDegrees();
\r
1815 ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint);
\r
1818 // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility.
\r
1819 // Not tested so far if this was correct or wrong before quaternion fix!
\r
1820 keyR->rotation= core::quaternion(mat.getTransposed());
\r
1822 ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->addPositionKey(joint);
\r
1824 keyP->position=mat.getTranslation();
\r
1827 core::vector3df scale=mat.getScale();
\r
1835 ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->addScaleKey(joint);
\r
1837 keyS->scale=scale;
\r
1844 if (!checkForOneFollowingSemicolons())
\r
1847 if (!checkForClosingBrace())
\r
1849 os::Printer::log("No closing brace in animation key in x file", ELL_WARNING);
\r
1850 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1858 bool CXMeshFileLoader::parseDataObjectTextureFilename(core::stringc& texturename)
\r
1860 #ifdef _XREADER_DEBUG
\r
1861 os::Printer::log("CXFileReader: reading texture filename", ELL_DEBUG);
\r
1864 if (!readHeadOfDataObject())
\r
1866 os::Printer::log("No opening brace in Texture filename found in x file", ELL_WARNING);
\r
1867 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1871 if (!getNextTokenAsString(texturename))
\r
1873 os::Printer::log("Unknown syntax while reading texture filename string in x file", ELL_WARNING);
\r
1874 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1878 if (!checkForClosingBrace())
\r
1880 os::Printer::log("No closing brace in Texture filename found in x file", ELL_WARNING);
\r
1881 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1889 bool CXMeshFileLoader::parseUnknownDataObject()
\r
1891 // find opening delimiter
\r
1894 core::stringc t = getNextToken();
\r
1896 if (t.size() == 0)
\r
1905 // parse until closing delimiter
\r
1909 core::stringc t = getNextToken();
\r
1911 if (t.size() == 0)
\r
1925 //! checks for closing curly brace, returns false if not there
\r
1926 bool CXMeshFileLoader::checkForClosingBrace()
\r
1928 return (getNextToken() == "}");
\r
1932 //! checks for one following semicolon, returns false if not there
\r
1933 bool CXMeshFileLoader::checkForOneFollowingSemicolons()
\r
1938 if (getNextToken() == ";")
\r
1948 //! checks for two following semicolons, returns false if they are not there
\r
1949 bool CXMeshFileLoader::checkForTwoFollowingSemicolons()
\r
1954 for (u32 k=0; k<2; ++k)
\r
1956 if (getNextToken() != ";")
\r
1967 //! reads header of dataobject including the opening brace.
\r
1968 //! returns false if error happened, and writes name of object
\r
1969 //! if there is one
\r
1970 bool CXMeshFileLoader::readHeadOfDataObject(core::stringc* outname)
\r
1972 core::stringc nameOrBrace = getNextToken();
\r
1973 if (nameOrBrace != "{")
\r
1976 (*outname) = nameOrBrace;
\r
1978 if (getNextToken() != "{")
\r
1986 //! returns next parseable token. Returns empty string if no token there
\r
1987 core::stringc CXMeshFileLoader::getNextToken()
\r
1991 // process binary-formatted file
\r
1994 // in binary mode it will only return NAME and STRING token
\r
1995 // and (correctly) skip over other tokens.
\r
1997 s16 tok = readBinWord();
\r
2000 // standalone tokens
\r
2004 len = readBinDWord();
\r
2005 s = core::stringc(P, len);
\r
2010 len = readBinDWord();
\r
2011 s = core::stringc(P, len);
\r
2017 return "<integer>";
\r
2023 len = readBinDWord();
\r
2025 return "<int_list>";
\r
2027 len = readBinDWord();
\r
2028 P += (len * FloatSize);
\r
2029 return "<flt_list>";
\r
2053 return "template";
\r
2082 // process text-formatted file
\r
2085 findNextNoneWhiteSpace();
\r
2090 while((P < End) && !core::isspace(P[0]))
\r
2092 // either keep token delimiters when already holding a token, or return if first valid char
\r
2093 if (P[0]==';' || P[0]=='}' || P[0]=='{' || P[0]==',')
\r
2100 break; // stop for delimiter
\r
2110 //! places pointer to next begin of a token, which must be a number,
\r
2111 // and ignores comments
\r
2112 void CXMeshFileLoader::findNextNoneWhiteSpaceNumber()
\r
2117 while((P < End) && (P[0] != '-') && (P[0] != '.') &&
\r
2118 !( core::isdigit(P[0])))
\r
2120 // check if this is a comment
\r
2121 if ((P[0] == '/' && P[1] == '/') || P[0] == '#')
\r
2122 readUntilEndOfLine();
\r
2129 // places pointer to next begin of a token, and ignores comments
\r
2130 void CXMeshFileLoader::findNextNoneWhiteSpace()
\r
2137 while((P < End) && core::isspace(P[0]))
\r
2147 // check if this is a comment
\r
2148 if ((P[0] == '/' && P[1] == '/') ||
\r
2150 readUntilEndOfLine();
\r
2157 //! reads a x file style string
\r
2158 bool CXMeshFileLoader::getNextTokenAsString(core::stringc& out)
\r
2162 out=getNextToken();
\r
2165 findNextNoneWhiteSpace();
\r
2174 while(P < End && P[0]!='"')
\r
2180 if ( P[1] != ';' || P[0] != '"')
\r
2188 void CXMeshFileLoader::readUntilEndOfLine()
\r
2195 if (P[0] == '\n' || P[0] == '\r')
\r
2207 u16 CXMeshFileLoader::readBinWord()
\r
2211 #ifdef __BIG_ENDIAN__
\r
2212 const u16 tmp = os::Byteswap::byteswap(*(u16 *)P);
\r
2214 const u16 tmp = *(u16 *)P;
\r
2221 u32 CXMeshFileLoader::readBinDWord()
\r
2225 #ifdef __BIG_ENDIAN__
\r
2226 const u32 tmp = os::Byteswap::byteswap(*(u32 *)P);
\r
2228 const u32 tmp = *(u32 *)P;
\r
2235 u32 CXMeshFileLoader::readInt()
\r
2239 if (!BinaryNumCount)
\r
2241 const u16 tmp = readBinWord(); // 0x06 or 0x03
\r
2243 BinaryNumCount = readBinDWord();
\r
2245 BinaryNumCount = 1; // single int
\r
2248 return readBinDWord();
\r
2252 findNextNoneWhiteSpaceNumber();
\r
2253 return core::strtoul10(P, &P);
\r
2258 f32 CXMeshFileLoader::readFloat()
\r
2262 if (!BinaryNumCount)
\r
2264 const u16 tmp = readBinWord(); // 0x07 or 0x42
\r
2266 BinaryNumCount = readBinDWord();
\r
2268 BinaryNumCount = 1; // single int
\r
2271 if (FloatSize == 8)
\r
2273 #ifdef __BIG_ENDIAN__
\r
2274 //TODO: Check if data is properly converted here
\r
2276 ctmp[1] = os::Byteswap::byteswap(*(f32*)P);
\r
2277 ctmp[0] = os::Byteswap::byteswap(*(f32*)P+4);
\r
2278 const f32 tmp = (f32)(*(f64*)(void*)ctmp);
\r
2280 const f32 tmp = (f32)(*(f64 *)P);
\r
2287 #ifdef __BIG_ENDIAN__
\r
2288 const f32 tmp = os::Byteswap::byteswap(*(f32 *)P);
\r
2290 const f32 tmp = *(f32 *)P;
\r
2296 findNextNoneWhiteSpaceNumber();
\r
2298 P = core::fast_atof_move(P, ftmp);
\r
2303 // read 2-dimensional vector. Stops at semicolon after second value for text file format
\r
2304 bool CXMeshFileLoader::readVector2(core::vector2df& vec)
\r
2306 vec.X = readFloat();
\r
2307 vec.Y = readFloat();
\r
2312 // read 3-dimensional vector. Stops at semicolon after third value for text file format
\r
2313 bool CXMeshFileLoader::readVector3(core::vector3df& vec)
\r
2315 vec.X = readFloat();
\r
2316 vec.Y = readFloat();
\r
2317 vec.Z = readFloat();
\r
2322 // read color without alpha value. Stops after second semicolon after blue value
\r
2323 bool CXMeshFileLoader::readRGB(video::SColor& color)
\r
2325 video::SColorf tmpColor;
\r
2326 tmpColor.r = readFloat();
\r
2327 tmpColor.g = readFloat();
\r
2328 tmpColor.b = readFloat();
\r
2329 color = tmpColor.toSColor();
\r
2330 return checkForOneFollowingSemicolons();
\r
2334 // read color with alpha value. Stops after second semicolon after blue value
\r
2335 bool CXMeshFileLoader::readRGBA(video::SColor& color)
\r
2337 video::SColorf tmpColor;
\r
2338 tmpColor.r = readFloat();
\r
2339 tmpColor.g = readFloat();
\r
2340 tmpColor.b = readFloat();
\r
2341 tmpColor.a = readFloat();
\r
2342 color = tmpColor.toSColor();
\r
2343 return checkForOneFollowingSemicolons();
\r
2347 // read matrix from list of floats
\r
2348 bool CXMeshFileLoader::readMatrix(core::matrix4& mat)
\r
2350 for (u32 i=0; i<16; ++i)
\r
2351 mat[i] = readFloat();
\r
2352 return checkForOneFollowingSemicolons();
\r
2356 } // end namespace scene
\r
2357 } // end namespace irr
\r