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
5 #include "IrrCompileConfig.h"
\r
7 #include "CXMeshFileLoader.h"
\r
10 #include "fast_atof.h"
\r
11 #include "coreutil.h"
\r
12 #include "ISceneManager.h"
\r
13 #include "IVideoDriver.h"
\r
14 #include "IFileSystem.h"
\r
15 #include "IReadFile.h"
\r
18 #define _XREADER_DEBUG
\r
20 //#define BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
28 CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs)
\r
29 : AnimatedMesh(0), Buffer(0), P(0), End(0), BinaryNumCount(0), Line(0),
\r
30 CurFrame(0), MajorVersion(0), MinorVersion(0), BinaryFormat(false), FloatSize(0)
\r
33 setDebugName("CXMeshFileLoader");
\r
38 //! returns true if the file maybe is able to be loaded by this class
\r
39 //! based on the file extension (e.g. ".bsp")
\r
40 bool CXMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
\r
42 return core::hasFileExtension ( filename, "x" );
\r
46 //! creates/loads an animated mesh from the file.
\r
47 //! \return Pointer to the created mesh. Returns 0 if loading failed.
\r
48 //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
\r
49 //! See IReferenceCounted::drop() for more information.
\r
50 IAnimatedMesh* CXMeshFileLoader::createMesh(io::IReadFile* file)
\r
55 #ifdef _XREADER_DEBUG
\r
56 u32 time = os::Timer::getRealTime();
\r
59 AnimatedMesh = new CSkinnedMesh();
\r
63 AnimatedMesh->finalize();
\r
67 AnimatedMesh->drop();
\r
70 #ifdef _XREADER_DEBUG
\r
71 time = os::Timer::getRealTime() - time;
\r
72 core::stringc tmpString = "Time to load ";
\r
73 tmpString += BinaryFormat ? "binary" : "ascii";
\r
74 tmpString += " X file: ";
\r
77 os::Printer::log(tmpString.c_str());
\r
93 for (u32 i=0; i<Meshes.size(); ++i)
\r
97 return AnimatedMesh;
\r
101 bool CXMeshFileLoader::load(io::IReadFile* file)
\r
103 if (!readFileIntoMemory(file))
\r
109 for (u32 n=0; n<Meshes.size(); ++n)
\r
111 SXMesh *mesh=Meshes[n];
\r
113 // default material if nothing loaded
\r
114 if (!mesh->Materials.size())
\r
116 mesh->Materials.push_back(video::SMaterial());
\r
117 mesh->Materials[0].DiffuseColor.set(0xff777777);
\r
118 mesh->Materials[0].Shininess=0.f;
\r
119 mesh->Materials[0].SpecularColor.set(0xff777777);
\r
120 mesh->Materials[0].EmissiveColor.set(0xff000000);
\r
125 mesh->Buffers.reallocate(mesh->Materials.size());
\r
126 #ifndef BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
127 const u32 bufferOffset = AnimatedMesh->getMeshBufferCount();
\r
129 for (i=0; i<mesh->Materials.size(); ++i)
\r
131 mesh->Buffers.push_back( AnimatedMesh->addMeshBuffer() );
\r
132 mesh->Buffers.getLast()->Material = mesh->Materials[i];
\r
134 if (!mesh->HasSkinning)
\r
136 //Set up rigid animation
\r
137 if (mesh->AttachedJointID!=-1)
\r
139 AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back( AnimatedMesh->getMeshBuffers().size()-1 );
\r
144 if (!mesh->FaceMaterialIndices.size())
\r
146 mesh->FaceMaterialIndices.set_used(mesh->Indices.size() / 3);
\r
147 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
148 mesh->FaceMaterialIndices[i]=0;
\r
151 if (!mesh->HasVertexColors)
\r
153 for (u32 j=0;j<mesh->FaceMaterialIndices.size();++j)
\r
155 for (u32 id=j*3+0;id<=j*3+2;++id)
\r
157 mesh->Vertices[ mesh->Indices[id] ].Color = mesh->Buffers[mesh->FaceMaterialIndices[j]]->Material.DiffuseColor;
\r
162 #ifdef BETTER_MESHBUFFER_SPLITTING_FOR_X
\r
164 //the same vertex can be used in many different meshbuffers, but it's slow to work out
\r
166 core::array< core::array< u32 > > verticesLinkIndex;
\r
167 verticesLinkIndex.reallocate(mesh->Vertices.size());
\r
168 core::array< core::array< u16 > > verticesLinkBuffer;
\r
169 verticesLinkBuffer.reallocate(mesh->Vertices.size());
\r
171 for (i=0;i<mesh->Vertices.size();++i)
\r
173 verticesLinkIndex.push_back( core::array< u32 >() );
\r
174 verticesLinkBuffer.push_back( core::array< u16 >() );
\r
177 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
179 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
181 core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
\r
184 for (u32 j=0; j < Array.size(); ++j)
\r
186 if (Array[j]==mesh->FaceMaterialIndices[i])
\r
194 Array.push_back( mesh->FaceMaterialIndices[i] );
\r
198 for (i=0;i<verticesLinkBuffer.size();++i)
\r
200 if (!verticesLinkBuffer[i].size())
\r
201 verticesLinkBuffer[i].push_back(0);
\r
204 for (i=0;i<mesh->Vertices.size();++i)
\r
206 core::array< u16 > &Array = verticesLinkBuffer[i];
\r
207 verticesLinkIndex[i].reallocate(Array.size());
\r
208 for (u32 j=0; j < Array.size(); ++j)
\r
210 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ Array[j] ];
\r
211 verticesLinkIndex[i].push_back( buffer->Vertices_Standard.size() );
\r
212 buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
\r
216 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
218 scene::SSkinMeshBuffer *buffer=mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
\r
220 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
222 core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
\r
224 for (u32 j=0;j< Array.size() ;++j)
\r
226 if ( Array[j]== mesh->FaceMaterialIndices[i] )
\r
227 buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ][j] );
\r
232 for (u32 j=0;j<mesh->WeightJoint.size();++j)
\r
234 ISkinnedMesh::SJoint* joint = AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]];
\r
235 ISkinnedMesh::SWeight& weight = joint->Weights[mesh->WeightNum[j]];
\r
237 u32 id = weight.vertex_id;
\r
239 if (id>=verticesLinkIndex.size())
\r
241 os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
\r
243 weight.strength=0.f;
\r
246 if (verticesLinkBuffer[id].size()==1)
\r
248 weight.vertex_id=verticesLinkIndex[id][0];
\r
249 weight.buffer_id=verticesLinkBuffer[id][0];
\r
251 else if (verticesLinkBuffer[id].size() != 0)
\r
253 for (u32 k=1; k < verticesLinkBuffer[id].size(); ++k)
\r
255 ISkinnedMesh::SWeight* WeightClone = AnimatedMesh->addWeight(joint);
\r
256 WeightClone->strength = weight.strength;
\r
257 WeightClone->vertex_id = verticesLinkIndex[id][k];
\r
258 WeightClone->buffer_id = verticesLinkBuffer[id][k];
\r
265 core::array< u32 > verticesLinkIndex;
\r
266 core::array< s16 > verticesLinkBuffer;
\r
267 verticesLinkBuffer.set_used(mesh->Vertices.size());
\r
270 for (i=0;i<mesh->Vertices.size();++i)
\r
272 // watch out for vertices which are not part of the mesh
\r
273 // they will keep the -1 and can lead to out-of-bounds access
\r
274 verticesLinkBuffer[i]=-1;
\r
277 bool warned = false;
\r
278 // store meshbuffer number per vertex
\r
279 for (i=0;i<mesh->FaceMaterialIndices.size();++i)
\r
281 for (u32 id=i*3+0;id<=i*3+2;++id)
\r
283 if ((verticesLinkBuffer[mesh->Indices[id]] != -1) && (verticesLinkBuffer[mesh->Indices[id]] != (s16)mesh->FaceMaterialIndices[i]))
\r
287 os::Printer::log("X loader", "Duplicated vertex, animation might be corrupted.", ELL_WARNING);
\r
290 const u32 tmp = mesh->Vertices.size();
\r
291 mesh->Vertices.push_back(mesh->Vertices[ mesh->Indices[id] ]);
\r
292 mesh->Indices[id] = tmp;
\r
293 verticesLinkBuffer.set_used(mesh->Vertices.size());
\r
295 verticesLinkBuffer[ mesh->Indices[id] ] = mesh->FaceMaterialIndices[i];
\r
299 if (mesh->FaceMaterialIndices.size() != 0)
\r
301 // store vertices in buffers and remember relation in verticesLinkIndex
\r
302 u32* vCountArray = new u32[mesh->Buffers.size()];
\r
303 memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
\r
304 // count vertices in each buffer and reallocate
\r
305 for (i=0; i<mesh->Vertices.size(); ++i)
\r
307 if (verticesLinkBuffer[i] != -1)
\r
308 ++vCountArray[verticesLinkBuffer[i]];
\r
310 if (mesh->TCoords2.size())
\r
312 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
314 mesh->Buffers[i]->Vertices_2TCoords.reallocate(vCountArray[i]);
\r
315 mesh->Buffers[i]->VertexType=video::EVT_2TCOORDS;
\r
320 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
321 mesh->Buffers[i]->Vertices_Standard.reallocate(vCountArray[i]);
\r
324 verticesLinkIndex.set_used(mesh->Vertices.size());
\r
325 // actually store vertices
\r
326 for (i=0; i<mesh->Vertices.size(); ++i)
\r
328 // if a vertex is missing for some reason, just skip it
\r
329 if (verticesLinkBuffer[i]==-1)
\r
331 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ verticesLinkBuffer[i] ];
\r
333 if (mesh->TCoords2.size())
\r
335 verticesLinkIndex[i] = buffer->Vertices_2TCoords.size();
\r
336 buffer->Vertices_2TCoords.push_back( mesh->Vertices[i] );
\r
337 // We have a problem with correct tcoord2 handling here
\r
338 // crash fixed for now by checking the values
\r
339 buffer->Vertices_2TCoords.getLast().TCoords2=(i<mesh->TCoords2.size())?mesh->TCoords2[i]:mesh->Vertices[i].TCoords;
\r
343 verticesLinkIndex[i] = buffer->Vertices_Standard.size();
\r
344 buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
\r
348 // count indices per buffer and reallocate
\r
349 memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
\r
350 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
351 ++vCountArray[ mesh->FaceMaterialIndices[i] ];
\r
352 for (i=0; i!=mesh->Buffers.size(); ++i)
\r
353 mesh->Buffers[i]->Indices.reallocate(vCountArray[i]);
\r
354 delete [] vCountArray;
\r
355 // create indices per buffer
\r
356 for (i=0; i<mesh->FaceMaterialIndices.size(); ++i)
\r
358 scene::SSkinMeshBuffer *buffer = mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
\r
359 for (u32 id=i*3+0; id!=i*3+3; ++id)
\r
361 buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ] );
\r
366 for (u32 j=0; j<mesh->WeightJoint.size(); ++j)
\r
368 ISkinnedMesh::SWeight& weight = (AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]->Weights[mesh->WeightNum[j]]);
\r
370 u32 id = weight.vertex_id;
\r
372 if (id>=verticesLinkIndex.size())
\r
374 os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
\r
376 weight.strength=0.f;
\r
379 weight.vertex_id=verticesLinkIndex[id];
\r
380 weight.buffer_id=verticesLinkBuffer[id] + bufferOffset;
\r
391 //! Reads file into memory
\r
392 bool CXMeshFileLoader::readFileIntoMemory(io::IReadFile* file)
\r
394 const long size = file->getSize();
\r
397 os::Printer::log("X File is too small.", ELL_WARNING);
\r
401 Buffer = new c8[size];
\r
403 //! read all into memory
\r
404 if (file->read(Buffer, size) != static_cast<size_t>(size))
\r
406 os::Printer::log("Could not read from x file.", ELL_WARNING);
\r
411 End = Buffer + size;
\r
413 //! check header "xof "
\r
414 if (strncmp(Buffer, "xof ", 4)!=0)
\r
416 os::Printer::log("Not an x file, wrong header.", ELL_WARNING);
\r
420 //! read minor and major version, e.g. 0302 or 0303
\r
422 tmp[0] = Buffer[4];
\r
423 tmp[1] = Buffer[5];
\r
425 MajorVersion = core::strtoul10(tmp);
\r
427 tmp[0] = Buffer[6];
\r
428 tmp[1] = Buffer[7];
\r
429 MinorVersion = core::strtoul10(tmp);
\r
432 if (strncmp(&Buffer[8], "txt ", 4) ==0)
\r
433 BinaryFormat = false;
\r
434 else if (strncmp(&Buffer[8], "bin ", 4) ==0)
\r
435 BinaryFormat = true;
\r
438 os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING);
\r
443 //! read float size
\r
444 if (strncmp(&Buffer[12], "0032", 4) ==0)
\r
446 else if (strncmp(&Buffer[12], "0064", 4) ==0)
\r
450 os::Printer::log("Float size not supported.", ELL_WARNING);
\r
456 readUntilEndOfLine();
\r
462 //! Parses the file
\r
463 bool CXMeshFileLoader::parseFile()
\r
465 while(parseDataObject())
\r
474 //! Parses the next Data object in the file
\r
475 bool CXMeshFileLoader::parseDataObject()
\r
477 core::stringc objectName = getNextToken();
\r
479 if (objectName.size() == 0)
\r
482 // parse specific object
\r
483 #ifdef _XREADER_DEBUG
\r
484 os::Printer::log("debug DataObject:", objectName.c_str(), ELL_DEBUG);
\r
487 if (objectName == "template")
\r
488 return parseDataObjectTemplate();
\r
490 if (objectName == "Frame")
\r
492 return parseDataObjectFrame( 0 );
\r
495 if (objectName == "Mesh")
\r
497 // some meshes have no frames at all
\r
498 //CurFrame = AnimatedMesh->addJoint(0);
\r
500 SXMesh *mesh=new SXMesh;
\r
502 //mesh->Buffer=AnimatedMesh->addMeshBuffer();
\r
503 Meshes.push_back(mesh);
\r
505 return parseDataObjectMesh(*mesh);
\r
508 if (objectName == "AnimationSet")
\r
510 return parseDataObjectAnimationSet();
\r
513 if (objectName == "AnimTicksPerSecond")
\r
515 return parseDataObjectAnimationTicksPerSecond();
\r
518 if (objectName == "Material")
\r
520 return parseUnknownDataObject();
\r
523 if (objectName == "}")
\r
525 os::Printer::log("} found in dataObject", ELL_WARNING);
\r
529 os::Printer::log("Unknown data object in animation of .x file", objectName.c_str(), ELL_WARNING);
\r
531 return parseUnknownDataObject();
\r
535 bool CXMeshFileLoader::parseDataObjectTemplate()
\r
537 #ifdef _XREADER_DEBUG
\r
538 os::Printer::log("CXFileReader: Reading template", ELL_DEBUG);
\r
541 // parse a template data object. Currently not stored.
\r
542 core::stringc name;
\r
544 if (!readHeadOfDataObject(&name))
\r
546 os::Printer::log("Left delimiter in template data object missing.",
\r
547 name.c_str(), ELL_WARNING);
\r
548 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
555 // read and ignore data members
\r
558 core::stringc s = getNextToken();
\r
571 bool CXMeshFileLoader::parseDataObjectFrame(CSkinnedMesh::SJoint *Parent)
\r
573 #ifdef _XREADER_DEBUG
\r
574 os::Printer::log("CXFileReader: Reading frame", ELL_DEBUG);
\r
577 // A coordinate frame, or "frame of reference." The Frame template
\r
578 // is open and can contain any object. The Direct3D extensions (D3DX)
\r
579 // mesh-loading functions recognize Mesh, FrameTransformMatrix, and
\r
580 // Frame template instances as child objects when loading a Frame
\r
585 core::stringc name;
\r
587 if (!readHeadOfDataObject(&name))
\r
589 os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING);
\r
590 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
594 CSkinnedMesh::SJoint *joint=0;
\r
598 for (u32 n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
600 if (AnimatedMesh->getAllJoints()[n]->Name==name)
\r
602 joint=AnimatedMesh->getAllJoints()[n];
\r
611 #ifdef _XREADER_DEBUG
\r
612 os::Printer::log("creating joint ", name.c_str(), ELL_DEBUG);
\r
614 joint=AnimatedMesh->addJoint(Parent);
\r
616 JointID=AnimatedMesh->getAllJoints().size()-1;
\r
620 #ifdef _XREADER_DEBUG
\r
621 os::Printer::log("using joint ", name.c_str(), ELL_DEBUG);
\r
624 Parent->Children.push_back(joint);
\r
627 // Now inside a frame.
\r
628 // read tokens until closing brace is reached.
\r
632 core::stringc objectName = getNextToken();
\r
634 #ifdef _XREADER_DEBUG
\r
635 os::Printer::log("debug DataObject in frame:", objectName.c_str(), ELL_DEBUG);
\r
638 if (objectName.size() == 0)
\r
640 os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING);
\r
641 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
645 if (objectName == "}")
\r
647 break; // frame finished
\r
650 if (objectName == "Frame")
\r
653 if (!parseDataObjectFrame(joint))
\r
657 if (objectName == "FrameTransformMatrix")
\r
659 if (!parseDataObjectTransformationMatrix(joint->LocalMatrix))
\r
662 //joint->LocalAnimatedMatrix
\r
663 //joint->LocalAnimatedMatrix.makeInverse();
\r
664 //joint->LocalMatrix=tmp*joint->LocalAnimatedMatrix;
\r
667 if (objectName == "Mesh")
\r
670 frame.Meshes.push_back(SXMesh());
\r
671 if (!parseDataObjectMesh(frame.Meshes.getLast()))
\r
674 SXMesh *mesh=new SXMesh;
\r
676 mesh->AttachedJointID=JointID;
\r
678 Meshes.push_back(mesh);
\r
680 if (!parseDataObjectMesh(*mesh))
\r
685 os::Printer::log("Unknown data object in frame in x file", objectName.c_str(), ELL_WARNING);
\r
686 if (!parseUnknownDataObject())
\r
695 bool CXMeshFileLoader::parseDataObjectTransformationMatrix(core::matrix4 &mat)
\r
697 #ifdef _XREADER_DEBUG
\r
698 os::Printer::log("CXFileReader: Reading Transformation Matrix", ELL_DEBUG);
\r
701 if (!readHeadOfDataObject())
\r
703 os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING);
\r
704 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
710 if (!checkForOneFollowingSemicolons())
\r
712 os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING);
\r
713 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
716 if (!checkForClosingBrace())
\r
718 os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING);
\r
719 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
727 bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh)
\r
729 core::stringc name;
\r
731 if (!readHeadOfDataObject(&name))
\r
733 #ifdef _XREADER_DEBUG
\r
734 os::Printer::log("CXFileReader: Reading mesh", ELL_DEBUG);
\r
736 os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING);
\r
737 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
741 #ifdef _XREADER_DEBUG
\r
742 os::Printer::log("CXFileReader: Reading mesh", name.c_str(), ELL_DEBUG);
\r
745 // read vertex count
\r
746 const u32 nVertices = readInt();
\r
749 mesh.Vertices.set_used(nVertices);
\r
750 for (u32 n=0; n<nVertices; ++n)
\r
752 readVector3(mesh.Vertices[n].Pos);
\r
753 mesh.Vertices[n].Color=0xFFFFFFFF;
\r
754 mesh.Vertices[n].Normal=core::vector3df(0.0f);
\r
757 if (!checkForTwoFollowingSemicolons())
\r
759 os::Printer::log("No finishing semicolon in Mesh Vertex Array found in x file", ELL_WARNING);
\r
760 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
764 const u32 nFaces = readInt();
\r
766 mesh.Indices.set_used(nFaces * 3);
\r
767 mesh.IndexCountPerFace.set_used(nFaces);
\r
769 core::array<u32> polygonfaces;
\r
770 u32 currentIndex = 0;
\r
772 for (u32 k=0; k<nFaces; ++k)
\r
774 const u32 fcnt = readInt();
\r
780 os::Printer::log("Invalid face count (<3) found in Mesh x file reader.", ELL_WARNING);
\r
781 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
785 // read face indices
\r
786 polygonfaces.set_used(fcnt);
\r
787 u32 triangles = (fcnt-2);
\r
788 mesh.Indices.set_used(mesh.Indices.size() + ((triangles-1)*3));
\r
789 mesh.IndexCountPerFace[k] = (u16)(triangles * 3);
\r
791 for (u32 f=0; f<fcnt; ++f)
\r
792 polygonfaces[f] = readInt();
\r
794 for (u32 jk=0; jk<triangles; ++jk)
\r
796 mesh.Indices[currentIndex++] = polygonfaces[0];
\r
797 mesh.Indices[currentIndex++] = polygonfaces[jk+1];
\r
798 mesh.Indices[currentIndex++] = polygonfaces[jk+2];
\r
801 // TODO: change face indices in material list
\r
805 mesh.Indices[currentIndex++] = readInt();
\r
806 mesh.Indices[currentIndex++] = readInt();
\r
807 mesh.Indices[currentIndex++] = readInt();
\r
808 mesh.IndexCountPerFace[k] = 3;
\r
812 if (!checkForTwoFollowingSemicolons())
\r
814 os::Printer::log("No finishing semicolon in Mesh Face Array found in x file", ELL_WARNING);
\r
815 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
818 // here, other data objects may follow
\r
822 core::stringc objectName = getNextToken();
\r
824 if (objectName.size() == 0)
\r
826 os::Printer::log("Unexpected ending found in Mesh in x file.", ELL_WARNING);
\r
827 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
831 if (objectName == "}")
\r
833 break; // mesh finished
\r
836 #ifdef _XREADER_DEBUG
\r
837 os::Printer::log("debug DataObject in mesh:", objectName.c_str(), ELL_DEBUG);
\r
840 if (objectName == "MeshNormals")
\r
842 if (!parseDataObjectMeshNormals(mesh))
\r
846 if (objectName == "MeshTextureCoords")
\r
848 if (!parseDataObjectMeshTextureCoords(mesh))
\r
852 if (objectName == "MeshVertexColors")
\r
854 if (!parseDataObjectMeshVertexColors(mesh))
\r
858 if (objectName == "MeshMaterialList")
\r
860 if (!parseDataObjectMeshMaterialList(mesh))
\r
864 if (objectName == "VertexDuplicationIndices")
\r
866 // we'll ignore vertex duplication indices
\r
868 if (!parseUnknownDataObject())
\r
872 if (objectName == "DeclData")
\r
874 if (!readHeadOfDataObject())
\r
876 os::Printer::log("No starting brace in DeclData found.", ELL_WARNING);
\r
877 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
880 // arbitrary vertex attributes
\r
881 // first comes the number of element definitions
\r
882 // then the vertex element type definitions
\r
883 // with format type;tesselator;semantics;usageindex
\r
884 // we want to support 2;0;6;0 == tangent
\r
885 // 2;0;7;0 == binormal
\r
886 // 2;0;3;0 == normal
\r
887 // 1/2;0;5;0 == 1st uv coord
\r
888 // and 1/2;0;5;1 == 2nd uv coord
\r
889 // type==2 is 3xf32, type==1 is 2xf32
\r
891 const u32 dcnt = readInt();
\r
893 s16 normalpos = -1;
\r
896 s16 tangentpos = -1;
\r
897 s16 binormalpos = -1;
\r
898 s16 normaltype = -1;
\r
901 s16 tangenttype = -1;
\r
902 s16 binormaltype = -1;
\r
904 (void)tangentpos; // disable unused variable warnings
\r
905 (void)binormalpos; // disable unused variable warnings
\r
906 (void)tangenttype; // disable unused variable warnings
\r
907 (void)binormaltype; // disable unused variable warnings
\r
909 for (j=0; j<dcnt; ++j)
\r
911 const u32 type = readInt();
\r
912 //const u32 tesselator = readInt();
\r
914 const u32 semantics = readInt();
\r
915 const u32 index = readInt();
\r
936 tangenttype = type;
\r
939 binormalpos = size;
\r
940 binormaltype = type;
\r
994 const u32 datasize = readInt();
\r
995 u32* data = new u32[datasize];
\r
996 for (j=0; j<datasize; ++j)
\r
999 if (!checkForOneFollowingSemicolons())
\r
1001 os::Printer::log("No finishing semicolon in DeclData found.", ELL_WARNING);
\r
1002 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1004 if (!checkForClosingBrace())
\r
1006 os::Printer::log("No closing brace in DeclData.", ELL_WARNING);
\r
1007 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1011 u8* dataptr = (u8*) data;
\r
1012 if ((uv2pos != -1) && (uv2type == 1))
\r
1013 mesh.TCoords2.reallocate(mesh.Vertices.size());
\r
1014 for (j=0; j<mesh.Vertices.size(); ++j)
\r
1016 if ((normalpos != -1) && (normaltype == 2))
\r
1017 mesh.Vertices[j].Normal.set(*((core::vector3df*)(dataptr+normalpos)));
\r
1018 if ((uvpos != -1) && (uvtype == 1))
\r
1019 mesh.Vertices[j].TCoords.set(*((core::vector2df*)(dataptr+uvpos)));
\r
1020 if ((uv2pos != -1) && (uv2type == 1))
\r
1021 mesh.TCoords2.push_back(*((core::vector2df*)(dataptr+uv2pos)));
\r
1027 if (objectName == "FVFData")
\r
1029 if (!readHeadOfDataObject())
\r
1031 os::Printer::log("No starting brace in FVFData found.", ELL_WARNING);
\r
1032 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1035 const u32 dataformat = readInt();
\r
1036 const u32 datasize = readInt();
\r
1037 u32* data = new u32[datasize];
\r
1038 for (u32 j=0; j<datasize; ++j)
\r
1039 data[j]=readInt();
\r
1040 if (dataformat&0x102) // 2nd uv set
\r
1042 mesh.TCoords2.reallocate(mesh.Vertices.size());
\r
1043 u8* dataptr = (u8*) data;
\r
1044 const u32 size=((dataformat>>8)&0xf)*sizeof(core::vector2df);
\r
1045 for (u32 j=0; j<mesh.Vertices.size(); ++j)
\r
1047 mesh.TCoords2.push_back(*((core::vector2df*)(dataptr)));
\r
1052 if (!checkForOneFollowingSemicolons())
\r
1054 os::Printer::log("No finishing semicolon in FVFData found.", ELL_WARNING);
\r
1055 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1057 if (!checkForClosingBrace())
\r
1059 os::Printer::log("No closing brace in FVFData found in x file", ELL_WARNING);
\r
1060 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1065 if (objectName == "XSkinMeshHeader")
\r
1067 if (!parseDataObjectSkinMeshHeader(mesh))
\r
1071 if (objectName == "SkinWeights")
\r
1073 //mesh.SkinWeights.push_back(SXSkinWeight());
\r
1074 //if (!parseDataObjectSkinWeights(mesh.SkinWeights.getLast()))
\r
1075 if (!parseDataObjectSkinWeights(mesh))
\r
1080 os::Printer::log("Unknown data object in mesh in x file", objectName.c_str(), ELL_WARNING);
\r
1081 if (!parseUnknownDataObject())
\r
1090 bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh)
\r
1092 #ifdef _XREADER_DEBUG
\r
1093 os::Printer::log("CXFileReader: Reading mesh skin weights", ELL_DEBUG);
\r
1096 if (!readHeadOfDataObject())
\r
1098 os::Printer::log("No opening brace in Skin Weights found in .x file", ELL_WARNING);
\r
1099 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1103 core::stringc TransformNodeName;
\r
1105 if (!getNextTokenAsString(TransformNodeName))
\r
1107 os::Printer::log("Unknown syntax while reading transform node name string in .x file", ELL_WARNING);
\r
1108 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1112 mesh.HasSkinning=true;
\r
1114 CSkinnedMesh::SJoint *joint=0;
\r
1117 for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
1119 if (AnimatedMesh->getAllJoints()[n]->Name==TransformNodeName)
\r
1121 joint=AnimatedMesh->getAllJoints()[n];
\r
1128 #ifdef _XREADER_DEBUG
\r
1129 os::Printer::log("creating joint for skinning ", TransformNodeName.c_str(), ELL_DEBUG);
\r
1131 n = AnimatedMesh->getAllJoints().size();
\r
1132 joint=AnimatedMesh->addJoint(0);
\r
1133 joint->Name=TransformNodeName;
\r
1136 // read vertex weights
\r
1137 const u32 nWeights = readInt();
\r
1139 // read vertex indices
\r
1142 const u32 jointStart = joint->Weights.size();
\r
1143 joint->Weights.reallocate(jointStart+nWeights);
\r
1145 mesh.WeightJoint.reallocate( mesh.WeightJoint.size() + nWeights );
\r
1146 mesh.WeightNum.reallocate( mesh.WeightNum.size() + nWeights );
\r
1148 for (i=0; i<nWeights; ++i)
\r
1150 mesh.WeightJoint.push_back(n);
\r
1151 mesh.WeightNum.push_back(joint->Weights.size());
\r
1153 CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(joint);
\r
1155 weight->buffer_id=0;
\r
1156 weight->vertex_id=readInt();
\r
1159 // read vertex weights
\r
1161 for (i=jointStart; i<jointStart+nWeights; ++i)
\r
1162 joint->Weights[i].strength = readFloat();
\r
1164 // read matrix offset
\r
1166 // transforms the mesh vertices to the space of the bone
\r
1167 // When concatenated to the bone's transform, this provides the
\r
1168 // world space coordinates of the mesh as affected by the bone
\r
1169 core::matrix4& MatrixOffset = joint->GlobalInversedMatrix;
\r
1171 readMatrix(MatrixOffset);
\r
1173 if (!checkForOneFollowingSemicolons())
\r
1175 os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING);
\r
1176 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1179 if (!checkForClosingBrace())
\r
1181 os::Printer::log("No closing brace in Skin Weights found in x file", ELL_WARNING);
\r
1182 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1190 bool CXMeshFileLoader::parseDataObjectSkinMeshHeader(SXMesh& mesh)
\r
1192 #ifdef _XREADER_DEBUG
\r
1193 os::Printer::log("CXFileReader: Reading skin mesh header", ELL_DEBUG);
\r
1196 if (!readHeadOfDataObject())
\r
1198 os::Printer::log("No opening brace in Skin Mesh header found in .x file", ELL_WARNING);
\r
1199 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1203 mesh.MaxSkinWeightsPerVertex = readInt();
\r
1204 mesh.MaxSkinWeightsPerFace = readInt();
\r
1205 mesh.BoneCount = readInt();
\r
1207 if (!BinaryFormat)
\r
1208 getNextToken(); // skip semicolon
\r
1210 if (!checkForClosingBrace())
\r
1212 os::Printer::log("No closing brace in skin mesh header in x file", ELL_WARNING);
\r
1213 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1221 bool CXMeshFileLoader::parseDataObjectMeshNormals(SXMesh &mesh)
\r
1223 #ifdef _XREADER_DEBUG
\r
1224 os::Printer::log("CXFileReader: reading mesh normals", ELL_DEBUG);
\r
1227 if (!readHeadOfDataObject())
\r
1229 os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING);
\r
1230 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1235 const u32 nNormals = readInt();
\r
1236 core::array<core::vector3df> normals;
\r
1237 normals.set_used(nNormals);
\r
1240 for (u32 i=0; i<nNormals; ++i)
\r
1241 readVector3(normals[i]);
\r
1243 if (!checkForTwoFollowingSemicolons())
\r
1245 os::Printer::log("No finishing semicolon in Mesh Normals Array found in x file", ELL_WARNING);
\r
1246 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1249 core::array<u32> normalIndices;
\r
1250 normalIndices.set_used(mesh.Indices.size());
\r
1252 // read face normal indices
\r
1253 const u32 nFNormals = readInt();
\r
1255 u32 normalidx = 0;
\r
1256 core::array<u32> polygonfaces;
\r
1257 for (u32 k=0; k<nFNormals; ++k)
\r
1259 const u32 fcnt = readInt();
\r
1260 u32 triangles = fcnt - 2;
\r
1261 u32 indexcount = triangles * 3;
\r
1263 if (indexcount != mesh.IndexCountPerFace[k])
\r
1265 os::Printer::log("Not matching normal and face index count found in x file", ELL_WARNING);
\r
1266 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1270 if (indexcount == 3)
\r
1272 // default, only one triangle in this face
\r
1273 for (u32 h=0; h<3; ++h)
\r
1275 const u32 normalnum = readInt();
\r
1276 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[normalnum]);
\r
1281 polygonfaces.set_used(fcnt);
\r
1282 // multiple triangles in this face
\r
1283 for (u32 h=0; h<fcnt; ++h)
\r
1284 polygonfaces[h] = readInt();
\r
1286 for (u32 jk=0; jk<triangles; ++jk)
\r
1288 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[0]]);
\r
1289 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+1]]);
\r
1290 mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+2]]);
\r
1295 if (!checkForTwoFollowingSemicolons())
\r
1297 os::Printer::log("No finishing semicolon in Mesh Face Normals Array found in x file", ELL_WARNING);
\r
1298 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1301 if (!checkForClosingBrace())
\r
1303 os::Printer::log("No closing brace in Mesh Normals found in x file", ELL_WARNING);
\r
1304 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1312 bool CXMeshFileLoader::parseDataObjectMeshTextureCoords(SXMesh &mesh)
\r
1314 #ifdef _XREADER_DEBUG
\r
1315 os::Printer::log("CXFileReader: reading mesh texture coordinates", ELL_DEBUG);
\r
1318 if (!readHeadOfDataObject())
\r
1320 os::Printer::log("No opening brace in Mesh Texture Coordinates found in x file", ELL_WARNING);
\r
1321 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1325 const u32 nCoords = readInt();
\r
1326 for (u32 i=0; i<nCoords; ++i)
\r
1327 readVector2(mesh.Vertices[i].TCoords);
\r
1329 if (!checkForTwoFollowingSemicolons())
\r
1331 os::Printer::log("No finishing semicolon in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1332 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1335 if (!checkForClosingBrace())
\r
1337 os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1338 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1346 bool CXMeshFileLoader::parseDataObjectMeshVertexColors(SXMesh &mesh)
\r
1348 #ifdef _XREADER_DEBUG
\r
1349 os::Printer::log("CXFileReader: reading mesh vertex colors", ELL_DEBUG);
\r
1352 if (!readHeadOfDataObject())
\r
1354 os::Printer::log("No opening brace for Mesh Vertex Colors found in x file", ELL_WARNING);
\r
1355 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1359 mesh.HasVertexColors=true;
\r
1360 const u32 nColors = readInt();
\r
1361 for (u32 i=0; i<nColors; ++i)
\r
1363 const u32 Index=readInt();
\r
1364 if (Index>=mesh.Vertices.size())
\r
1366 os::Printer::log("index value in parseDataObjectMeshVertexColors out of bounds", ELL_WARNING);
\r
1367 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1370 readRGBA(mesh.Vertices[Index].Color);
\r
1371 checkForOneFollowingSemicolons();
\r
1374 if (!checkForOneFollowingSemicolons())
\r
1376 os::Printer::log("No finishing semicolon in Mesh Vertex Colors Array found in x file", ELL_WARNING);
\r
1377 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1380 if (!checkForClosingBrace())
\r
1382 os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
\r
1383 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1391 bool CXMeshFileLoader::parseDataObjectMeshMaterialList(SXMesh &mesh)
\r
1393 #ifdef _XREADER_DEBUG
\r
1394 os::Printer::log("CXFileReader: Reading mesh material list", ELL_DEBUG);
\r
1397 if (!readHeadOfDataObject())
\r
1399 os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING);
\r
1400 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1404 // read material count
\r
1405 mesh.Materials.reallocate(readInt());
\r
1407 // read non triangulated face material index count
\r
1408 const u32 nFaceIndices = readInt();
\r
1410 // There seems to be a compact representation of "all faces the same material"
\r
1411 // being represented as 1;1;0;; which means 1 material, 1 face with first material
\r
1412 // all the other faces have to obey then, so check is disabled
\r
1413 //if (nFaceIndices != mesh.IndexCountPerFace.size())
\r
1414 // os::Printer::log("Index count per face not equal to face material index count in x file.", ELL_WARNING);
\r
1416 // read non triangulated face indices and create triangulated ones
\r
1417 mesh.FaceMaterialIndices.set_used( mesh.Indices.size() / 3);
\r
1418 u32 triangulatedindex = 0;
\r
1420 for (u32 tfi=0; tfi<mesh.IndexCountPerFace.size(); ++tfi)
\r
1422 if (tfi<nFaceIndices)
\r
1424 const u32 fc = mesh.IndexCountPerFace[tfi]/3;
\r
1425 for (u32 k=0; k<fc; ++k)
\r
1426 mesh.FaceMaterialIndices[triangulatedindex++] = ind;
\r
1429 // in version 03.02, the face indices end with two semicolons.
\r
1430 // commented out version check, as version 03.03 exported from blender also has 2 semicolons
\r
1431 if (!BinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
\r
1437 // read following data objects
\r
1441 core::stringc objectName = getNextToken();
\r
1443 if (objectName.size() == 0)
\r
1445 os::Printer::log("Unexpected ending found in Mesh Material list in .x file.", ELL_WARNING);
\r
1446 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1450 if (objectName == "}")
\r
1452 break; // material list finished
\r
1455 if (objectName == "{")
\r
1457 // template materials now available thanks to joeWright
\r
1458 objectName = getNextToken();
\r
1459 mesh.Materials.push_back(video::SMaterial());
\r
1460 getNextToken(); // skip }
\r
1463 if (objectName == "Material")
\r
1465 mesh.Materials.push_back(video::SMaterial());
\r
1466 if (!parseUnknownDataObject())
\r
1470 if (objectName == ";")
\r
1476 os::Printer::log("Unknown data object in material list in x file", objectName.c_str(), ELL_WARNING);
\r
1477 if (!parseUnknownDataObject())
\r
1485 bool CXMeshFileLoader::parseDataObjectAnimationSet()
\r
1487 #ifdef _XREADER_DEBUG
\r
1488 os::Printer::log("CXFileReader: Reading animation set", ELL_DEBUG);
\r
1491 core::stringc AnimationName;
\r
1493 if (!readHeadOfDataObject(&AnimationName))
\r
1495 os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING);
\r
1496 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1499 os::Printer::log("Reading animationset ", AnimationName, ELL_DEBUG);
\r
1503 core::stringc objectName = getNextToken();
\r
1505 if (objectName.size() == 0)
\r
1507 os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING);
\r
1508 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1512 if (objectName == "}")
\r
1514 break; // animation set finished
\r
1517 if (objectName == "Animation")
\r
1519 if (!parseDataObjectAnimation())
\r
1524 os::Printer::log("Unknown data object in animation set in x file", objectName.c_str(), ELL_WARNING);
\r
1525 if (!parseUnknownDataObject())
\r
1532 bool CXMeshFileLoader::parseDataObjectAnimationTicksPerSecond()
\r
1534 #ifdef _XREADER_DEBUG
\r
1535 os::Printer::log("CXFileReader: reading AnimationTicksPerSecond", ELL_DEBUG);
\r
1538 if (!readHeadOfDataObject())
\r
1540 os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING);
\r
1541 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1545 const u32 ticks = readInt();
\r
1547 if (!checkForOneFollowingSemicolons())
\r
1549 os::Printer::log("No closing semicolon in AnimationTicksPerSecond in x file", ELL_WARNING);
\r
1550 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1554 if (!checkForClosingBrace())
\r
1556 os::Printer::log("No closing brace in AnimationTicksPerSecond in x file", ELL_WARNING);
\r
1557 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1561 AnimatedMesh->setAnimationSpeed(static_cast<irr::f32>(ticks));
\r
1566 bool CXMeshFileLoader::parseDataObjectAnimation()
\r
1568 #ifdef _XREADER_DEBUG
\r
1569 os::Printer::log("CXFileReader: reading animation", ELL_DEBUG);
\r
1572 if (!readHeadOfDataObject())
\r
1574 os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING);
\r
1575 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1579 //anim.closed = true;
\r
1580 //anim.linearPositionQuality = true;
\r
1581 CSkinnedMesh::SJoint animationDump;
\r
1583 core::stringc FrameName;
\r
1587 core::stringc objectName = getNextToken();
\r
1589 if (objectName.size() == 0)
\r
1591 os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
\r
1592 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1596 if (objectName == "}")
\r
1598 break; // animation finished
\r
1601 if (objectName == "AnimationKey")
\r
1603 if (!parseDataObjectAnimationKey(&animationDump))
\r
1607 if (objectName == "AnimationOptions")
\r
1609 //TODO: parse options.
\r
1610 if (!parseUnknownDataObject())
\r
1614 if (objectName == "{")
\r
1616 // read frame name
\r
1617 FrameName = getNextToken();
\r
1619 if (!checkForClosingBrace())
\r
1621 os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
\r
1622 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1628 os::Printer::log("Unknown data object in animation in x file", objectName.c_str(), ELL_WARNING);
\r
1629 if (!parseUnknownDataObject())
\r
1634 if (FrameName.size() != 0)
\r
1636 #ifdef _XREADER_DEBUG
\r
1637 os::Printer::log("frame name", FrameName.c_str(), ELL_DEBUG);
\r
1639 CSkinnedMesh::SJoint *joint=0;
\r
1642 for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
\r
1644 if (AnimatedMesh->getAllJoints()[n]->Name==FrameName)
\r
1646 joint=AnimatedMesh->getAllJoints()[n];
\r
1653 #ifdef _XREADER_DEBUG
\r
1654 os::Printer::log("creating joint for animation ", FrameName.c_str(), ELL_DEBUG);
\r
1656 joint=AnimatedMesh->addJoint(0);
\r
1657 joint->Name=FrameName;
\r
1660 joint->PositionKeys.reallocate(joint->PositionKeys.size()+animationDump.PositionKeys.size());
\r
1661 for (n=0; n<animationDump.PositionKeys.size(); ++n)
\r
1663 joint->PositionKeys.push_back(animationDump.PositionKeys[n]);
\r
1666 joint->ScaleKeys.reallocate(joint->ScaleKeys.size()+animationDump.ScaleKeys.size());
\r
1667 for (n=0; n<animationDump.ScaleKeys.size(); ++n)
\r
1669 joint->ScaleKeys.push_back(animationDump.ScaleKeys[n]);
\r
1672 joint->RotationKeys.reallocate(joint->RotationKeys.size()+animationDump.RotationKeys.size());
\r
1673 for (n=0; n<animationDump.RotationKeys.size(); ++n)
\r
1675 joint->RotationKeys.push_back(animationDump.RotationKeys[n]);
\r
1679 os::Printer::log("joint name was never given", ELL_WARNING);
\r
1685 bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint)
\r
1687 #ifdef _XREADER_DEBUG
\r
1688 os::Printer::log("CXFileReader: reading animation key", ELL_DEBUG);
\r
1691 if (!readHeadOfDataObject())
\r
1693 os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING);
\r
1694 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1700 const u32 keyType = readInt();
\r
1704 os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING);
\r
1705 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1709 // read number of keys
\r
1710 const u32 numberOfKeys = readInt();
\r
1712 // eat the semicolon after the "0". if there are keys present, readInt()
\r
1713 // does this for us. If there aren't, we need to do it explicitly
\r
1714 if (numberOfKeys == 0)
\r
1715 checkForOneFollowingSemicolons();
\r
1717 for (u32 i=0; i<numberOfKeys; ++i)
\r
1720 const f32 time = (f32)readInt();
\r
1725 case 0: //rotation
\r
1727 //read quaternions
\r
1730 if (readInt() != 4)
\r
1732 os::Printer::log("Expected 4 numbers in animation key in x file", ELL_WARNING);
\r
1733 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1737 f32 W = -readFloat();
\r
1738 f32 X = -readFloat();
\r
1739 f32 Y = -readFloat();
\r
1740 f32 Z = -readFloat();
\r
1742 if (!checkForTwoFollowingSemicolons())
\r
1744 os::Printer::log("No finishing semicolon after quaternion animation key in x file", ELL_WARNING);
\r
1745 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1748 ISkinnedMesh::SRotationKey *key=AnimatedMesh->addRotationKey(joint);
\r
1750 key->rotation.set(X,Y,Z,W);
\r
1751 key->rotation.normalize();
\r
1755 case 2: //position
\r
1760 if (readInt() != 3)
\r
1762 os::Printer::log("Expected 3 numbers in animation key in x file", ELL_WARNING);
\r
1763 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1767 core::vector3df vector;
\r
1768 readVector3(vector);
\r
1770 if (!checkForTwoFollowingSemicolons())
\r
1772 os::Printer::log("No finishing semicolon after vector animation key in x file", ELL_WARNING);
\r
1773 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1778 ISkinnedMesh::SPositionKey *key=AnimatedMesh->addPositionKey(joint);
\r
1780 key->position=vector;
\r
1784 ISkinnedMesh::SScaleKey *key=AnimatedMesh->addScaleKey(joint);
\r
1786 key->scale=vector;
\r
1796 if (readInt() != 16)
\r
1798 os::Printer::log("Expected 16 numbers in animation key in x file", ELL_WARNING);
\r
1799 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1804 core::matrix4 mat(core::matrix4::EM4CONST_NOTHING);
\r
1807 //mat=joint->LocalMatrix*mat;
\r
1809 if (!checkForOneFollowingSemicolons())
\r
1811 os::Printer::log("No finishing semicolon after matrix animation key in x file", ELL_WARNING);
\r
1812 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1815 //core::vector3df rotation = mat.getRotationDegrees();
\r
1817 ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint);
\r
1820 // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility.
\r
1821 // Not tested so far if this was correct or wrong before quaternion fix!
\r
1822 keyR->rotation= core::quaternion(mat.getTransposed());
\r
1824 ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->addPositionKey(joint);
\r
1826 keyP->position=mat.getTranslation();
\r
1829 core::vector3df scale=mat.getScale();
\r
1837 ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->addScaleKey(joint);
\r
1839 keyS->scale=scale;
\r
1846 if (!checkForOneFollowingSemicolons())
\r
1849 if (!checkForClosingBrace())
\r
1851 os::Printer::log("No closing brace in animation key in x file", ELL_WARNING);
\r
1852 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1860 bool CXMeshFileLoader::parseDataObjectTextureFilename(core::stringc& texturename)
\r
1862 #ifdef _XREADER_DEBUG
\r
1863 os::Printer::log("CXFileReader: reading texture filename", ELL_DEBUG);
\r
1866 if (!readHeadOfDataObject())
\r
1868 os::Printer::log("No opening brace in Texture filename found in x file", ELL_WARNING);
\r
1869 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1873 if (!getNextTokenAsString(texturename))
\r
1875 os::Printer::log("Unknown syntax while reading texture filename string in x file", ELL_WARNING);
\r
1876 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1880 if (!checkForClosingBrace())
\r
1882 os::Printer::log("No closing brace in Texture filename found in x file", ELL_WARNING);
\r
1883 os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
\r
1891 bool CXMeshFileLoader::parseUnknownDataObject()
\r
1893 // find opening delimiter
\r
1896 core::stringc t = getNextToken();
\r
1898 if (t.size() == 0)
\r
1907 // parse until closing delimiter
\r
1911 core::stringc t = getNextToken();
\r
1913 if (t.size() == 0)
\r
1927 //! checks for closing curly brace, returns false if not there
\r
1928 bool CXMeshFileLoader::checkForClosingBrace()
\r
1930 return (getNextToken() == "}");
\r
1934 //! checks for one following semicolon, returns false if not there
\r
1935 bool CXMeshFileLoader::checkForOneFollowingSemicolons()
\r
1940 if (getNextToken() == ";")
\r
1950 //! checks for two following semicolons, returns false if they are not there
\r
1951 bool CXMeshFileLoader::checkForTwoFollowingSemicolons()
\r
1956 for (u32 k=0; k<2; ++k)
\r
1958 if (getNextToken() != ";")
\r
1969 //! reads header of dataobject including the opening brace.
\r
1970 //! returns false if error happened, and writes name of object
\r
1971 //! if there is one
\r
1972 bool CXMeshFileLoader::readHeadOfDataObject(core::stringc* outname)
\r
1974 core::stringc nameOrBrace = getNextToken();
\r
1975 if (nameOrBrace != "{")
\r
1978 (*outname) = nameOrBrace;
\r
1980 if (getNextToken() != "{")
\r
1988 //! returns next parseable token. Returns empty string if no token there
\r
1989 core::stringc CXMeshFileLoader::getNextToken()
\r
1993 // process binary-formatted file
\r
1996 // in binary mode it will only return NAME and STRING token
\r
1997 // and (correctly) skip over other tokens.
\r
1999 s16 tok = readBinWord();
\r
2002 // standalone tokens
\r
2006 len = readBinDWord();
\r
2007 s = core::stringc(P, len);
\r
2012 len = readBinDWord();
\r
2013 s = core::stringc(P, len);
\r
2019 return "<integer>";
\r
2025 len = readBinDWord();
\r
2027 return "<int_list>";
\r
2029 len = readBinDWord();
\r
2030 P += (len * FloatSize);
\r
2031 return "<flt_list>";
\r
2055 return "template";
\r
2084 // process text-formatted file
\r
2087 findNextNoneWhiteSpace();
\r
2092 while((P < End) && !core::isspace(P[0]))
\r
2094 // either keep token delimiters when already holding a token, or return if first valid char
\r
2095 if (P[0]==';' || P[0]=='}' || P[0]=='{' || P[0]==',')
\r
2102 break; // stop for delimiter
\r
2112 //! places pointer to next begin of a token, which must be a number,
\r
2113 // and ignores comments
\r
2114 void CXMeshFileLoader::findNextNoneWhiteSpaceNumber()
\r
2119 while((P < End) && (P[0] != '-') && (P[0] != '.') &&
\r
2120 !( core::isdigit(P[0])))
\r
2122 // check if this is a comment
\r
2123 if ((P[0] == '/' && P[1] == '/') || P[0] == '#')
\r
2124 readUntilEndOfLine();
\r
2131 // places pointer to next begin of a token, and ignores comments
\r
2132 void CXMeshFileLoader::findNextNoneWhiteSpace()
\r
2139 while((P < End) && core::isspace(P[0]))
\r
2149 // check if this is a comment
\r
2150 if ((P[0] == '/' && P[1] == '/') ||
\r
2152 readUntilEndOfLine();
\r
2159 //! reads a x file style string
\r
2160 bool CXMeshFileLoader::getNextTokenAsString(core::stringc& out)
\r
2164 out=getNextToken();
\r
2167 findNextNoneWhiteSpace();
\r
2176 while(P < End && P[0]!='"')
\r
2182 if ( P[1] != ';' || P[0] != '"')
\r
2190 void CXMeshFileLoader::readUntilEndOfLine()
\r
2197 if (P[0] == '\n' || P[0] == '\r')
\r
2209 u16 CXMeshFileLoader::readBinWord()
\r
2213 #ifdef __BIG_ENDIAN__
\r
2214 const u16 tmp = os::Byteswap::byteswap(*(u16 *)P);
\r
2216 const u16 tmp = *(u16 *)P;
\r
2223 u32 CXMeshFileLoader::readBinDWord()
\r
2227 #ifdef __BIG_ENDIAN__
\r
2228 const u32 tmp = os::Byteswap::byteswap(*(u32 *)P);
\r
2230 const u32 tmp = *(u32 *)P;
\r
2237 u32 CXMeshFileLoader::readInt()
\r
2241 if (!BinaryNumCount)
\r
2243 const u16 tmp = readBinWord(); // 0x06 or 0x03
\r
2245 BinaryNumCount = readBinDWord();
\r
2247 BinaryNumCount = 1; // single int
\r
2250 return readBinDWord();
\r
2254 findNextNoneWhiteSpaceNumber();
\r
2255 return core::strtoul10(P, &P);
\r
2260 f32 CXMeshFileLoader::readFloat()
\r
2264 if (!BinaryNumCount)
\r
2266 const u16 tmp = readBinWord(); // 0x07 or 0x42
\r
2268 BinaryNumCount = readBinDWord();
\r
2270 BinaryNumCount = 1; // single int
\r
2273 if (FloatSize == 8)
\r
2275 #ifdef __BIG_ENDIAN__
\r
2276 //TODO: Check if data is properly converted here
\r
2278 ctmp[1] = os::Byteswap::byteswap(*(f32*)P);
\r
2279 ctmp[0] = os::Byteswap::byteswap(*(f32*)P+4);
\r
2280 const f32 tmp = (f32)(*(f64*)(void*)ctmp);
\r
2282 const f32 tmp = (f32)(*(f64 *)P);
\r
2289 #ifdef __BIG_ENDIAN__
\r
2290 const f32 tmp = os::Byteswap::byteswap(*(f32 *)P);
\r
2292 const f32 tmp = *(f32 *)P;
\r
2298 findNextNoneWhiteSpaceNumber();
\r
2300 P = core::fast_atof_move(P, ftmp);
\r
2305 // read 2-dimensional vector. Stops at semicolon after second value for text file format
\r
2306 bool CXMeshFileLoader::readVector2(core::vector2df& vec)
\r
2308 vec.X = readFloat();
\r
2309 vec.Y = readFloat();
\r
2314 // read 3-dimensional vector. Stops at semicolon after third value for text file format
\r
2315 bool CXMeshFileLoader::readVector3(core::vector3df& vec)
\r
2317 vec.X = readFloat();
\r
2318 vec.Y = readFloat();
\r
2319 vec.Z = readFloat();
\r
2324 // read color without alpha value. Stops after second semicolon after blue value
\r
2325 bool CXMeshFileLoader::readRGB(video::SColor& color)
\r
2327 video::SColorf tmpColor;
\r
2328 tmpColor.r = readFloat();
\r
2329 tmpColor.g = readFloat();
\r
2330 tmpColor.b = readFloat();
\r
2331 color = tmpColor.toSColor();
\r
2332 return checkForOneFollowingSemicolons();
\r
2336 // read color with alpha value. Stops after second semicolon after blue value
\r
2337 bool CXMeshFileLoader::readRGBA(video::SColor& color)
\r
2339 video::SColorf tmpColor;
\r
2340 tmpColor.r = readFloat();
\r
2341 tmpColor.g = readFloat();
\r
2342 tmpColor.b = readFloat();
\r
2343 tmpColor.a = readFloat();
\r
2344 color = tmpColor.toSColor();
\r
2345 return checkForOneFollowingSemicolons();
\r
2349 // read matrix from list of floats
\r
2350 bool CXMeshFileLoader::readMatrix(core::matrix4& mat)
\r
2352 for (u32 i=0; i<16; ++i)
\r
2353 mat[i] = readFloat();
\r
2354 return checkForOneFollowingSemicolons();
\r
2358 } // end namespace scene
\r
2359 } // end namespace irr
\r