2007-05-20 11:03:49 -07:00
|
|
|
// Copyright (C) 2002-2007 Nikolaus Gebhardt
|
|
|
|
// This file is part of the "Irrlicht Engine".
|
|
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
#include "IrrCompileConfig.h"
|
|
|
|
|
|
|
|
#ifdef _IRR_COMPILE_WITH_X_LOADER_
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
#include "CXMeshFileLoader.h"
|
|
|
|
#include "os.h"
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
#include "fast_atof.h"
|
|
|
|
#include "coreutil.h"
|
2007-09-05 06:10:36 -07:00
|
|
|
#include "IVideoDriver.h"
|
2007-09-06 16:20:02 -07:00
|
|
|
#include "IReadFile.h"
|
2007-05-20 11:03:49 -07:00
|
|
|
|
2007-09-10 06:11:47 -07:00
|
|
|
#ifdef _DEBUG
|
2007-09-10 04:31:43 -07:00
|
|
|
#define _XREADER_DEBUG
|
2007-09-10 06:11:47 -07:00
|
|
|
#endif
|
2007-09-10 04:31:43 -07:00
|
|
|
//#define BETTER_MESHBUFFER_SPLITTING_FOR_X
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
namespace irr
|
|
|
|
{
|
|
|
|
namespace scene
|
|
|
|
{
|
|
|
|
|
|
|
|
//! Constructor
|
2007-09-04 11:51:42 -07:00
|
|
|
CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr)
|
2007-09-06 16:20:02 -07:00
|
|
|
: SceneManager(smgr), AnimatedMesh(0), MajorVersion(0), MinorVersion(0),
|
|
|
|
BinaryFormat(false), BinaryNumCount(0), Buffer(0), P(0), End(0),
|
|
|
|
FloatSize(0), CurFrame(0)
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! returns true if the file maybe is able to be loaded by this class
|
|
|
|
//! based on the file extension (e.g. ".bsp")
|
2007-09-16 16:41:55 -07:00
|
|
|
bool CXMeshFileLoader::isALoadableFileExtension(const c8* filename) const
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
2007-09-04 11:51:42 -07:00
|
|
|
return strstr(filename, ".x") != 0;
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! creates/loads an animated mesh from the file.
|
|
|
|
//! \return Pointer to the created mesh. Returns 0 if loading failed.
|
|
|
|
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
|
2007-09-06 23:11:47 -07:00
|
|
|
//! See IReferenceCounted::drop() for more information.
|
2007-09-19 07:08:28 -07:00
|
|
|
IAnimatedMesh* CXMeshFileLoader::createMesh(io::IReadFile* f)
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
2007-09-04 11:51:42 -07:00
|
|
|
if (!f)
|
2007-05-20 11:03:49 -07:00
|
|
|
return 0;
|
|
|
|
|
2007-09-14 17:55:30 -07:00
|
|
|
u32 time = os::Timer::getRealTime();
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
AnimatedMesh = new CSkinnedMesh();
|
2007-05-20 11:03:49 -07:00
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
if ( load(f) )
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
2007-09-04 11:51:42 -07:00
|
|
|
AnimatedMesh->finalize();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AnimatedMesh->drop();
|
|
|
|
AnimatedMesh = 0;
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
2007-09-14 17:55:30 -07:00
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
time = os::Timer::getRealTime() - time;
|
|
|
|
core::stringc tmpString = "Time to load ";
|
|
|
|
tmpString += BinaryFormat ? "binary" : "ascii";
|
|
|
|
tmpString += " X file: ";
|
|
|
|
tmpString += time;
|
|
|
|
tmpString += "ms";
|
|
|
|
os::Printer::log(tmpString.c_str());
|
|
|
|
#endif
|
2007-09-04 11:51:42 -07:00
|
|
|
//Clear up
|
2007-05-20 11:03:49 -07:00
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
MajorVersion=0;
|
|
|
|
MinorVersion=0;
|
2007-09-06 16:20:02 -07:00
|
|
|
BinaryFormat=0;
|
|
|
|
BinaryNumCount=0;
|
2007-09-04 11:51:42 -07:00
|
|
|
FloatSize=0;
|
|
|
|
P=0;
|
|
|
|
End=0;
|
|
|
|
CurFrame=0;
|
|
|
|
TemplateMaterials.clear();
|
|
|
|
|
2007-09-27 09:04:03 -07:00
|
|
|
delete [] Buffer;
|
2007-09-06 05:38:06 -07:00
|
|
|
Buffer = 0;
|
|
|
|
|
|
|
|
for (u32 i=0; i<Meshes.size(); ++i)
|
|
|
|
delete Meshes[i];
|
2007-09-04 11:51:42 -07:00
|
|
|
Meshes.clear();
|
|
|
|
|
|
|
|
return AnimatedMesh;
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
bool CXMeshFileLoader::load(io::IReadFile* file)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (!readFileIntoMemory(file))
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!parseFile())
|
|
|
|
return false;
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
for (u32 n=0; n<Meshes.size(); ++n)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
SXMesh *mesh=Meshes[n];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
// default material if nothing loaded
|
|
|
|
if (!mesh->Materials.size())
|
|
|
|
mesh->Materials.push_back(video::SMaterial());
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
u32 i;
|
|
|
|
|
2007-09-10 06:11:47 -07:00
|
|
|
mesh->Buffers.reallocate(mesh->Materials.size());
|
2007-09-18 05:00:03 -07:00
|
|
|
const u32 bufferOffset = AnimatedMesh->getMeshBufferCount();
|
2007-09-06 16:20:02 -07:00
|
|
|
for (i=0; i<mesh->Materials.size(); ++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
mesh->Buffers.push_back( AnimatedMesh->createBuffer() );
|
|
|
|
mesh->Buffers.getLast()->Material = mesh->Materials[i];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-17 04:09:07 -07:00
|
|
|
if (!mesh->HasSkinning)
|
|
|
|
{
|
|
|
|
//Set up rigid animation
|
|
|
|
if (mesh->AttachedJointID!=-1)
|
|
|
|
{
|
|
|
|
AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back( AnimatedMesh->getMeshBuffers().size()-1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
if (!mesh->HasVertexColors)
|
|
|
|
{
|
|
|
|
for (u32 j=0;j<mesh->FaceMaterialIndices.size();++j)
|
|
|
|
{
|
|
|
|
for (u32 id=j*3+0;id<=j*3+2;++id)
|
|
|
|
{
|
|
|
|
mesh->Vertices[ mesh->Indices[id] ].Color = mesh->Buffers[mesh->FaceMaterialIndices[j]]->Material.DiffuseColor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
#ifdef BETTER_MESHBUFFER_SPLITTING_FOR_X
|
2007-09-06 16:20:02 -07:00
|
|
|
{
|
2007-09-04 11:51:42 -07:00
|
|
|
//the same vertex can be used in many different meshbuffers, but it's slow to work out
|
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
core::array< core::array< u32 > > verticesLinkIndex;
|
|
|
|
verticesLinkIndex.reallocate(mesh->Vertices.size());
|
|
|
|
core::array< core::array< u16 > > verticesLinkBuffer;
|
2007-09-07 07:18:47 -07:00
|
|
|
verticesLinkBuffer.reallocate(mesh->Vertices.size());
|
2007-09-10 06:11:47 -07:00
|
|
|
|
2007-09-07 07:18:47 -07:00
|
|
|
for (i=0;i<mesh->Vertices.size();++i)
|
|
|
|
{
|
2007-09-18 05:00:03 -07:00
|
|
|
verticesLinkIndex.push_back( core::array< u32 >() );
|
|
|
|
verticesLinkBuffer.push_back( core::array< u16 >() );
|
2007-09-07 07:18:47 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-07 07:18:47 -07:00
|
|
|
for (i=0;i<mesh->FaceMaterialIndices.size();++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
for (u32 id=i*3+0;id<=i*3+2;++id)
|
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
core::array< u32 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
|
2007-09-04 11:51:42 -07:00
|
|
|
bool found=false;
|
|
|
|
|
2007-09-06 09:14:33 -07:00
|
|
|
for (u32 j=0; j < Array.size(); ++j)
|
|
|
|
{
|
2007-09-07 07:18:47 -07:00
|
|
|
if (Array[j]==mesh->FaceMaterialIndices[i])
|
2007-09-06 09:14:33 -07:00
|
|
|
{
|
|
|
|
found=true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (!found)
|
2007-09-07 07:18:47 -07:00
|
|
|
Array.push_back( mesh->FaceMaterialIndices[i] );
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
for (i=0;i<verticesLinkBuffer.size();++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (!verticesLinkBuffer[i].size())
|
|
|
|
verticesLinkBuffer[i].push_back(0);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
for (i=0;i<mesh->Vertices.size();++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-18 05:00:03 -07:00
|
|
|
core::array< u16 > &Array = verticesLinkBuffer[i];
|
|
|
|
verticesLinkIndex[i].reallocate(Array.size());
|
2007-09-06 16:20:02 -07:00
|
|
|
for (u32 j=0; j < Array.size(); ++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
scene::SSkinMeshBuffer *buffer = mesh->Buffers[ Array[j] ];
|
2007-09-18 05:00:03 -07:00
|
|
|
verticesLinkIndex[i].push_back( buffer->Vertices_Standard.size() );
|
2007-09-06 16:20:02 -07:00
|
|
|
buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-07 07:18:47 -07:00
|
|
|
for (i=0;i<mesh->FaceMaterialIndices.size();++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-07 07:18:47 -07:00
|
|
|
scene::SSkinMeshBuffer *buffer=mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
for (u32 id=i*3+0;id<=i*3+2;++id)
|
|
|
|
{
|
2007-09-18 05:00:03 -07:00
|
|
|
core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
for (u32 j=0;j< Array.size() ;++j)
|
|
|
|
{
|
2007-09-07 07:18:47 -07:00
|
|
|
if ( Array[j]== mesh->FaceMaterialIndices[i] )
|
2007-09-18 05:00:03 -07:00
|
|
|
buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ][j] );
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-17 19:51:06 -07:00
|
|
|
for (u32 j=0;j<mesh->Weights.size();++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-17 19:51:06 -07:00
|
|
|
ISkinnedMesh::SWeight& Weight = (*mesh->Weights[j]);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-17 19:51:06 -07:00
|
|
|
u32 id = Weight.vertex_id;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
if (id>=verticesLinkIndex.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-17 19:51:06 -07:00
|
|
|
os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
|
|
|
|
id=0;
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-17 19:51:06 -07:00
|
|
|
if (verticesLinkBuffer[id].size()==1)
|
|
|
|
{
|
2007-09-18 05:00:03 -07:00
|
|
|
Weight.vertex_id=verticesLinkIndex[id][0];
|
2007-09-17 19:51:06 -07:00
|
|
|
Weight.buffer_id=verticesLinkBuffer[id][0];
|
|
|
|
}
|
|
|
|
else if (verticesLinkBuffer[id].size() != 0)
|
|
|
|
{
|
|
|
|
for (u32 k=1; k < verticesLinkBuffer[id].size(); ++k)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-17 19:51:06 -07:00
|
|
|
ISkinnedMesh::SWeight* WeightClone = AnimatedMesh->createWeight(Joint);
|
|
|
|
WeightClone->strength = Weight.strength;
|
2007-09-18 05:00:03 -07:00
|
|
|
WeightClone->vertex_id = verticesLinkIndex[id][k];
|
2007-09-17 19:51:06 -07:00
|
|
|
WeightClone->buffer_id = verticesLinkBuffer[id][k];
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-09-06 16:20:02 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
#else
|
2007-09-06 16:20:02 -07:00
|
|
|
{
|
2007-09-18 05:00:03 -07:00
|
|
|
core::array< u32 > verticesLinkIndex;
|
|
|
|
core::array< u16 > verticesLinkBuffer;
|
2007-09-06 16:20:02 -07:00
|
|
|
verticesLinkBuffer.set_used(mesh->Vertices.size());
|
2007-09-18 05:00:03 -07:00
|
|
|
verticesLinkIndex.set_used(mesh->Vertices.size());
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
// init with 0
|
|
|
|
for (i=0;i<mesh->Vertices.size();++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
verticesLinkBuffer[i]=0;
|
2007-09-18 05:00:03 -07:00
|
|
|
verticesLinkIndex[i]=0;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-09-07 09:09:14 -07:00
|
|
|
// store meshbuffer number per vertex
|
2007-09-07 07:18:47 -07:00
|
|
|
for (i=0;i<mesh->FaceMaterialIndices.size();++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
for (u32 id=i*3+0;id<=i*3+2;++id)
|
|
|
|
{
|
2007-09-07 07:18:47 -07:00
|
|
|
verticesLinkBuffer[ mesh->Indices[id] ] = mesh->FaceMaterialIndices[i];
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
// store vertices in buffers and remember relation in verticesLinkIndex
|
2007-09-10 06:24:18 -07:00
|
|
|
u32* vCountArray = new u32[mesh->Buffers.size()];
|
|
|
|
memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
|
|
|
|
// count vertices in each buffer and reallocate
|
|
|
|
for (i=0;i<mesh->Vertices.size();++i)
|
|
|
|
++vCountArray[verticesLinkBuffer[i]];
|
|
|
|
for (i=0; i!=mesh->Buffers.size(); ++i)
|
|
|
|
mesh->Buffers[i]->Vertices_Standard.reallocate(vCountArray[i]);
|
2007-09-18 05:00:03 -07:00
|
|
|
|
2007-09-10 06:24:18 -07:00
|
|
|
// actually store vertices
|
2007-09-06 16:20:02 -07:00
|
|
|
for (i=0;i<mesh->Vertices.size();++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
scene::SSkinMeshBuffer *buffer = mesh->Buffers[ verticesLinkBuffer[i] ];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
verticesLinkIndex[i] = buffer->Vertices_Standard.size();
|
2007-09-06 16:20:02 -07:00
|
|
|
buffer->Vertices_Standard.push_back( mesh->Vertices[i] );
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-09-10 06:24:18 -07:00
|
|
|
// count indices per buffer and reallocate
|
|
|
|
memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32));
|
|
|
|
for (i=0;i<mesh->FaceMaterialIndices.size();++i)
|
|
|
|
++vCountArray[ mesh->FaceMaterialIndices[i] ];
|
|
|
|
for (i=0; i!=mesh->Buffers.size(); ++i)
|
|
|
|
mesh->Buffers[i]->Indices.reallocate(vCountArray[i]);
|
|
|
|
delete [] vCountArray;
|
2007-09-07 09:09:14 -07:00
|
|
|
// create indices per buffer
|
2007-09-07 07:18:47 -07:00
|
|
|
for (i=0;i<mesh->FaceMaterialIndices.size();++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-07 09:09:14 -07:00
|
|
|
scene::SSkinMeshBuffer *buffer = mesh->Buffers[ mesh->FaceMaterialIndices[i] ];
|
|
|
|
for (u32 id=i*3+0;id!=i*3+3;++id)
|
2007-09-18 05:00:03 -07:00
|
|
|
buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ] );
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-17 19:51:06 -07:00
|
|
|
for (u32 j=0;j<mesh->Weights.size();++j)
|
|
|
|
{
|
2007-09-18 05:00:03 -07:00
|
|
|
ISkinnedMesh::SWeight* weight = mesh->Weights[j];
|
2007-09-17 04:09:07 -07:00
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
u32 id = weight->vertex_id;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
if (id>=verticesLinkIndex.size())
|
2007-09-17 19:51:06 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("X loader: Weight id out of range", ELL_WARNING);
|
|
|
|
id=0;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
2007-09-17 19:51:06 -07:00
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
weight->vertex_id=verticesLinkIndex[id];
|
|
|
|
weight->buffer_id=verticesLinkBuffer[id] + bufferOffset;;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
2007-09-06 16:20:02 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
#endif
|
2007-09-17 04:09:07 -07:00
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Reads file into memory
|
2007-09-06 16:20:02 -07:00
|
|
|
bool CXMeshFileLoader::readFileIntoMemory(io::IReadFile* file)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-14 02:07:11 -07:00
|
|
|
const long size = file->getSize();
|
2007-09-06 16:20:02 -07:00
|
|
|
if (size < 12)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("X File is too small.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
Buffer = new c8[size];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
//! read all into memory
|
2007-09-06 16:20:02 -07:00
|
|
|
if (file->read(Buffer, size) != size)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("Could not read from x file.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
End = Buffer + size;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
//! check header "xof "
|
|
|
|
if (strncmp(Buffer, "xof ", 4)!=0)
|
|
|
|
{
|
|
|
|
os::Printer::log("Not an x file, wrong header.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! read minor and major version, e.g. 0302 or 0303
|
|
|
|
c8 tmp[3];
|
|
|
|
tmp[2] = 0x0;
|
|
|
|
tmp[0] = Buffer[4];
|
|
|
|
tmp[1] = Buffer[5];
|
2007-09-06 16:20:02 -07:00
|
|
|
MajorVersion = core::strtol10(tmp);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
tmp[0] = Buffer[6];
|
|
|
|
tmp[1] = Buffer[7];
|
2007-09-06 16:20:02 -07:00
|
|
|
MinorVersion = core::strtol10(tmp);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
//! read format
|
|
|
|
if (strncmp(&Buffer[8], "txt ", 4) ==0)
|
2007-09-06 16:20:02 -07:00
|
|
|
BinaryFormat = false;
|
2007-09-04 11:51:42 -07:00
|
|
|
else if (strncmp(&Buffer[8], "bin ", 4) ==0)
|
2007-09-06 16:20:02 -07:00
|
|
|
BinaryFormat = true;
|
2007-09-04 11:51:42 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
2007-09-06 16:20:02 -07:00
|
|
|
BinaryNumCount=0;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
//! read float size
|
|
|
|
if (strncmp(&Buffer[12], "0032", 4) ==0)
|
|
|
|
FloatSize = 4;
|
|
|
|
else if (strncmp(&Buffer[12], "0064", 4) ==0)
|
|
|
|
FloatSize = 8;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
os::Printer::log("Float size not supported.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
P = &Buffer[16];
|
|
|
|
|
|
|
|
readUntilEndOfLine();
|
2007-09-06 16:20:02 -07:00
|
|
|
FilePath = stripPathFromString(file->getFileName(),true);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Parses the file
|
|
|
|
bool CXMeshFileLoader::parseFile()
|
|
|
|
{
|
|
|
|
while(parseDataObject())
|
|
|
|
{
|
|
|
|
// loop
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Parses the next Data object in the file
|
|
|
|
bool CXMeshFileLoader::parseDataObject()
|
|
|
|
{
|
|
|
|
core::stringc objectName = getNextToken();
|
|
|
|
|
|
|
|
if (objectName.size() == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// parse specific object
|
2007-09-10 04:31:43 -07:00
|
|
|
#ifdef _XREADER_DEBUG
|
2007-09-04 11:51:42 -07:00
|
|
|
os::Printer::log("debug DataObject:", objectName.c_str() );
|
2007-09-04 15:23:51 -07:00
|
|
|
#endif
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (objectName == "template")
|
|
|
|
return parseDataObjectTemplate();
|
|
|
|
else
|
|
|
|
if (objectName == "Frame")
|
|
|
|
{
|
|
|
|
return parseDataObjectFrame( 0 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "Mesh")
|
|
|
|
{
|
|
|
|
// some meshes have no frames at all
|
|
|
|
//CurFrame = AnimatedMesh->createJoint(0);
|
|
|
|
|
|
|
|
//CurFrame->Meshes.push_back(SXMesh());
|
|
|
|
//return parseDataObjectMesh(CurFrame->Meshes.getLast());
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
SXMesh *mesh=new SXMesh;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
//mesh->Buffer=AnimatedMesh->createBuffer();
|
|
|
|
Meshes.push_back(mesh);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
return parseDataObjectMesh ( *mesh );
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "AnimationSet")
|
|
|
|
{
|
|
|
|
return parseDataObjectAnimationSet();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "Material")
|
|
|
|
{
|
|
|
|
// template materials now available thanks to joeWright
|
|
|
|
TemplateMaterials.push_back(SXTemplateMaterial());
|
|
|
|
TemplateMaterials.getLast().Name = getNextToken();
|
|
|
|
return parseDataObjectMaterial(TemplateMaterials.getLast().Material);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "}")
|
|
|
|
{
|
2007-09-05 01:59:46 -07:00
|
|
|
os::Printer::log("} found in dataObject", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
os::Printer::log("Unknown data object in animation of .x file", objectName.c_str(), ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
return parseUnknownDataObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectTemplate()
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: Reading template");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// parse a template data object. Currently not stored.
|
2007-09-09 16:09:06 -07:00
|
|
|
core::stringc name;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-09 16:09:06 -07:00
|
|
|
if (!readHeadOfDataObject(&name))
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("Left delimiter in template data object missing.",
|
|
|
|
name.c_str(), ELL_ERROR);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read GUID
|
|
|
|
core::stringc guid = getNextToken();
|
|
|
|
|
|
|
|
// read and ignore data members
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
core::stringc s = getNextToken();
|
|
|
|
|
|
|
|
if (s == "}")
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (s.size() == 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectFrame( CSkinnedMesh::SJoint *Parent )
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: Reading frame");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// A coordinate frame, or "frame of reference." The Frame template
|
|
|
|
// is open and can contain any object. The Direct3D extensions (D3DX)
|
|
|
|
// mesh-loading functions recognize Mesh, FrameTransformMatrix, and
|
|
|
|
// Frame template instances as child objects when loading a Frame
|
|
|
|
// instance.
|
|
|
|
|
2007-09-17 04:09:07 -07:00
|
|
|
u32 JointID=0;
|
|
|
|
|
2007-09-09 16:09:06 -07:00
|
|
|
core::stringc name;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-09 16:09:06 -07:00
|
|
|
if (!readHeadOfDataObject(&name))
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
CSkinnedMesh::SJoint *joint=0;
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (name.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
for (u32 n=0;n < AnimatedMesh->getAllJoints().size();++n)
|
|
|
|
{
|
2007-09-09 16:09:06 -07:00
|
|
|
if (AnimatedMesh->getAllJoints()[n]->Name==name)
|
2007-09-10 09:15:36 -07:00
|
|
|
{
|
2007-09-04 11:51:42 -07:00
|
|
|
joint=AnimatedMesh->getAllJoints()[n];
|
2007-09-17 04:09:07 -07:00
|
|
|
JointID=n;
|
2007-09-10 09:15:36 -07:00
|
|
|
break;
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!joint)
|
|
|
|
{
|
2007-09-10 04:31:43 -07:00
|
|
|
#ifdef _XREADER_DEBUG
|
2007-09-09 16:09:06 -07:00
|
|
|
os::Printer::log("creating joint ", name.c_str());
|
2007-09-05 01:59:46 -07:00
|
|
|
#endif
|
2007-09-04 11:51:42 -07:00
|
|
|
joint=AnimatedMesh->createJoint(Parent);
|
2007-09-09 16:09:06 -07:00
|
|
|
joint->Name=name;
|
2007-09-17 04:09:07 -07:00
|
|
|
JointID=AnimatedMesh->getAllJoints().size()-1;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-10 04:31:43 -07:00
|
|
|
#ifdef _XREADER_DEBUG
|
2007-09-09 16:09:06 -07:00
|
|
|
os::Printer::log("using joint ", name.c_str());
|
2007-09-05 01:59:46 -07:00
|
|
|
#endif
|
2007-09-04 11:51:42 -07:00
|
|
|
if (Parent)
|
|
|
|
Parent->Children.push_back(joint);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now inside a frame.
|
|
|
|
// read tokens until closing brace is reached.
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
core::stringc objectName = getNextToken();
|
|
|
|
|
2007-09-10 04:31:43 -07:00
|
|
|
#ifdef _XREADER_DEBUG
|
2007-09-04 11:51:42 -07:00
|
|
|
os::Printer::log("debug DataObject in frame:", objectName.c_str() );
|
2007-09-04 15:23:51 -07:00
|
|
|
#endif
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (objectName.size() == 0)
|
|
|
|
{
|
|
|
|
os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "}")
|
|
|
|
{
|
|
|
|
break; // frame finished
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "Frame")
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!parseDataObjectFrame(joint))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "FrameTransformMatrix")
|
|
|
|
{
|
|
|
|
if (!parseDataObjectTransformationMatrix(joint->LocalMatrix))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//joint->LocalAnimatedMatrix
|
|
|
|
//joint->LocalAnimatedMatrix.makeInverse();
|
|
|
|
//joint->LocalMatrix=tmp*joint->LocalAnimatedMatrix;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "Mesh")
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
frame.Meshes.push_back(SXMesh());
|
|
|
|
if (!parseDataObjectMesh(frame.Meshes.getLast()))
|
|
|
|
return false;
|
|
|
|
*/
|
2007-09-06 16:20:02 -07:00
|
|
|
SXMesh *mesh=new SXMesh;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-17 04:09:07 -07:00
|
|
|
mesh->AttachedJointID=JointID;
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
Meshes.push_back(mesh);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-09 01:39:21 -07:00
|
|
|
if (!parseDataObjectMesh(*mesh))
|
|
|
|
return false;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-05 01:59:46 -07:00
|
|
|
os::Printer::log("Unknown data object in frame in x file", objectName.c_str(), ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
if (!parseUnknownDataObject())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectTransformationMatrix(core::matrix4 &mat)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: Reading Transformation Matrix");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 i=0; i<4; ++i)
|
|
|
|
for (u32 j=0; j<4; ++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
mat(i,j)=readFloat();
|
|
|
|
|
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: Reading mesh");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
core::stringc name;
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject(&name))
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read vertex count
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 nVertices = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read vertices
|
2007-12-02 15:57:20 -08:00
|
|
|
mesh.Vertices.set_used(nVertices);
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 n=0; n<nVertices; ++n)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
readVector3(mesh.Vertices[n].Pos);
|
2007-09-12 10:45:29 -07:00
|
|
|
mesh.Vertices[n].Color=0xFFFFFFFF;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon in Mesh Vertex Array found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read faces
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 nFaces = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
mesh.Indices.set_used(nFaces * 3);
|
|
|
|
mesh.IndexCountPerFace.set_used(nFaces);
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
core::array<u32> polygonfaces;
|
|
|
|
u32 currentIndex = 0;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 k=0; k<nFaces; ++k)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 fcnt = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (fcnt != 3)
|
|
|
|
{
|
|
|
|
if (fcnt < 3)
|
|
|
|
{
|
|
|
|
os::Printer::log("Invalid face count (<3) found in Mesh x file reader.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read face indices
|
|
|
|
polygonfaces.set_used(fcnt);
|
2007-09-12 10:45:29 -07:00
|
|
|
u32 triangles = (fcnt-2);
|
2007-09-14 15:25:59 -07:00
|
|
|
mesh.Indices.set_used(mesh.Indices.size() + ((triangles-1)*3));
|
2007-09-04 11:51:42 -07:00
|
|
|
mesh.IndexCountPerFace[k] = triangles * 3;
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 f=0; f<fcnt; ++f)
|
2007-09-04 11:51:42 -07:00
|
|
|
polygonfaces[f] = readInt();
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 jk=0; jk<triangles; ++jk)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
mesh.Indices[currentIndex++] = polygonfaces[0];
|
|
|
|
mesh.Indices[currentIndex++] = polygonfaces[jk+1];
|
|
|
|
mesh.Indices[currentIndex++] = polygonfaces[jk+2];
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: change face indices in material list
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mesh.Indices[currentIndex++] = readInt();
|
|
|
|
mesh.Indices[currentIndex++] = readInt();
|
|
|
|
mesh.Indices[currentIndex++] = readInt();
|
|
|
|
mesh.IndexCountPerFace[k] = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-02 15:57:20 -08:00
|
|
|
if (!checkForTwoFollowingSemicolons())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon in Mesh Face Array found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// here, other data objects may follow
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
core::stringc objectName = getNextToken();
|
|
|
|
|
2007-09-10 04:31:43 -07:00
|
|
|
#ifdef _XREADER_DEBUG
|
2007-09-04 11:51:42 -07:00
|
|
|
os::Printer::log("debug DataObject in mesh:", objectName.c_str() );
|
2007-09-04 15:23:51 -07:00
|
|
|
#endif
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (objectName.size() == 0)
|
|
|
|
{
|
|
|
|
os::Printer::log("Unexpected ending found in Mesh in x file.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "}")
|
|
|
|
{
|
|
|
|
break; // mesh finished
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "MeshNormals")
|
|
|
|
{
|
|
|
|
if (!parseDataObjectMeshNormals(mesh))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "MeshTextureCoords")
|
|
|
|
{
|
|
|
|
if (!parseDataObjectMeshTextureCoords(mesh))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "MeshVertexColors")
|
|
|
|
{
|
|
|
|
if (!parseDataObjectMeshVertexColors(mesh))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "MeshMaterialList")
|
|
|
|
{
|
|
|
|
if (!parseDataObjectMeshMaterialList(mesh))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "VertexDuplicationIndices")
|
|
|
|
{
|
|
|
|
// we'll ignore vertex duplication indices
|
|
|
|
// TODO: read them
|
|
|
|
if (!parseUnknownDataObject())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "XSkinMeshHeader")
|
|
|
|
{
|
2007-09-07 09:09:14 -07:00
|
|
|
if (!parseDataObjectSkinMeshHeader(mesh))
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "SkinWeights")
|
|
|
|
{
|
|
|
|
//mesh.SkinWeights.push_back(SXSkinWeight());
|
|
|
|
//if (!parseDataObjectSkinWeights(mesh.SkinWeights.getLast()))
|
|
|
|
if (!parseDataObjectSkinWeights(mesh))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-05 01:59:46 -07:00
|
|
|
os::Printer::log("Unknown data object in mesh in x file", objectName.c_str(), ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
if (!parseUnknownDataObject())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: Reading mesh skin weights");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
2007-09-07 09:09:14 -07:00
|
|
|
os::Printer::log("No opening brace in Skin Weights found in .x file", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
core::stringc TransformNodeName;
|
|
|
|
|
|
|
|
if (!getNextTokenAsString(TransformNodeName))
|
|
|
|
{
|
2007-09-07 09:09:14 -07:00
|
|
|
os::Printer::log("Unknown syntax while reading transfrom node name string in .x file", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-17 04:09:07 -07:00
|
|
|
|
|
|
|
mesh.HasSkinning=true;
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
CSkinnedMesh::SJoint *joint=0;
|
|
|
|
|
2007-09-06 09:14:33 -07:00
|
|
|
for (u32 n=0; n < AnimatedMesh->getAllJoints().size(); ++n)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
if (AnimatedMesh->getAllJoints()[n]->Name==TransformNodeName)
|
2007-09-06 09:14:33 -07:00
|
|
|
{
|
2007-09-04 11:51:42 -07:00
|
|
|
joint=AnimatedMesh->getAllJoints()[n];
|
2007-09-06 09:14:33 -07:00
|
|
|
break;
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!joint)
|
|
|
|
{
|
2007-09-05 01:59:46 -07:00
|
|
|
#ifdef _XREADER_DEBUG
|
2007-09-10 09:15:36 -07:00
|
|
|
os::Printer::log("creating joint for skinning ", TransformNodeName.c_str());
|
2007-09-05 01:59:46 -07:00
|
|
|
#endif
|
2007-09-04 11:51:42 -07:00
|
|
|
joint=AnimatedMesh->createJoint(0);
|
|
|
|
joint->Name=TransformNodeName;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read vertex weights
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 nWeights = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read vertex indices
|
2007-09-12 10:45:29 -07:00
|
|
|
u32 i;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-07 09:09:14 -07:00
|
|
|
const u32 jointStart = joint->Weights.size();
|
|
|
|
joint->Weights.reallocate(jointStart+nWeights);
|
|
|
|
|
2007-09-17 19:51:06 -07:00
|
|
|
mesh.Weights.reallocate( mesh.Weights.size() + nWeights );
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
for (i=0; i<nWeights; ++i)
|
2007-09-07 09:09:14 -07:00
|
|
|
{
|
|
|
|
CSkinnedMesh::SWeight *weight=AnimatedMesh->createWeight(joint);
|
|
|
|
|
|
|
|
weight->buffer_id=0;
|
|
|
|
weight->vertex_id=readInt();
|
2007-09-17 19:51:06 -07:00
|
|
|
|
|
|
|
mesh.Weights.push_back(weight);
|
2007-09-07 09:09:14 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read vertex weights
|
|
|
|
|
|
|
|
for (i=0; i<nWeights; ++i)
|
2007-09-07 09:09:14 -07:00
|
|
|
joint->Weights[i].strength = readFloat();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read matrix offset
|
|
|
|
|
2007-09-07 09:09:14 -07:00
|
|
|
// transforms the mesh vertices to the space of the bone
|
|
|
|
// When concatenated to the bone's transform, this provides the
|
|
|
|
// world space coordinates of the mesh as affected by the bone
|
|
|
|
core::matrix4& MatrixOffset = joint->GlobalInversedMatrix;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
for (i=0; i<4; ++i)
|
|
|
|
{
|
|
|
|
for (u32 j=0; j<4; ++j)
|
|
|
|
MatrixOffset(i,j) = readFloat();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No closing brace in Skin Weights found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-07 09:09:14 -07:00
|
|
|
bool CXMeshFileLoader::parseDataObjectSkinMeshHeader(SXMesh& mesh)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: Reading skin mesh header");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
2007-09-07 09:09:14 -07:00
|
|
|
os::Printer::log("No opening brace in Skin Mesh header found in .x file", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-07 09:09:14 -07:00
|
|
|
mesh.MaxSkinWeightsPerVertex = readInt();
|
|
|
|
mesh.MaxSkinWeightsPerFace = readInt();
|
|
|
|
mesh.BoneCount = readInt();
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
if (!BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
getNextToken(); // skip semicolon
|
2007-09-07 09:09:14 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-10 09:15:36 -07:00
|
|
|
os::Printer::log("No closing brace in skin mesh header in x file", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectMeshNormals(SXMesh &mesh)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: reading mesh normals");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read count
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 nNormals = readInt();
|
2007-09-06 09:14:33 -07:00
|
|
|
core::array<core::vector3df> normals;
|
|
|
|
normals.set_used(nNormals);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read normals
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 i=0; i<nNormals; ++i)
|
2007-09-06 09:14:33 -07:00
|
|
|
readVector3(normals[i]);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon in Mesh Normals Array found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
core::array<u32> normalIndices;
|
|
|
|
normalIndices.set_used(mesh.Indices.size());
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read face normal indices
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 nFNormals = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
u32 normalidx = 0;
|
|
|
|
core::array<u32> polygonfaces;
|
|
|
|
for (u32 k=0; k<nFNormals; ++k)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 fcnt = readInt();
|
|
|
|
u32 triangles = fcnt - 2;
|
|
|
|
u32 indexcount = triangles * 3;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (indexcount != mesh.IndexCountPerFace[k])
|
|
|
|
{
|
|
|
|
os::Printer::log("Not matching normal and face index count found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (indexcount == 3)
|
|
|
|
{
|
|
|
|
// default, only one triangle in this face
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 h=0; h<3; ++h)
|
2007-09-06 09:14:33 -07:00
|
|
|
{
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 normalnum = readInt();
|
2007-09-06 09:14:33 -07:00
|
|
|
mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[normalnum]);
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
polygonfaces.set_used(fcnt);
|
2007-09-12 10:45:29 -07:00
|
|
|
// multiple triangles in this face
|
|
|
|
for (u32 h=0; h<fcnt; ++h)
|
2007-09-04 11:51:42 -07:00
|
|
|
polygonfaces[h] = readInt();
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 jk=0; jk<triangles; ++jk)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 09:14:33 -07:00
|
|
|
mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[0]]);
|
|
|
|
mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+1]]);
|
|
|
|
mesh.Vertices[mesh.Indices[normalidx++]].Normal.set(normals[polygonfaces[jk+2]]);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon in Mesh Face Normals Array found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
2007-09-10 09:15:36 -07:00
|
|
|
|
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No closing brace in Mesh Normals found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectMeshTextureCoords(SXMesh &mesh)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: reading mesh texture coordinates");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Mesh Texture Coordinates found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 nCoords = readInt();
|
|
|
|
for (u32 i=0; i<nCoords; ++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
readVector2(mesh.Vertices[i].TCoords);
|
|
|
|
|
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectMeshVertexColors(SXMesh &mesh)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: reading mesh vertex colors");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace for Mesh Vertex Colors found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-18 05:00:03 -07:00
|
|
|
mesh.HasVertexColors=true;
|
2007-09-10 06:11:47 -07:00
|
|
|
const u32 nColors = readInt();
|
|
|
|
for (u32 i=0; i<nColors; ++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-10 06:11:47 -07:00
|
|
|
const u32 Index=readInt();
|
2007-09-18 05:00:03 -07:00
|
|
|
if (Index>=mesh.Vertices.size())
|
|
|
|
{
|
|
|
|
os::Printer::log("index value in parseDataObjectMeshVertexColors out of bounds", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
readRGBA(mesh.Vertices[Index].Color);
|
2007-09-10 06:11:47 -07:00
|
|
|
checkForOneFollowingSemicolons();
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-09-10 06:11:47 -07:00
|
|
|
if (!checkForOneFollowingSemicolons())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon in Mesh Vertex Colors Array found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectMeshMaterialList(SXMesh &mesh)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: Reading mesh material list");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read material count
|
2007-09-07 07:18:47 -07:00
|
|
|
mesh.Materials.reallocate(readInt());
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read non triangulated face material index count
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 nFaceIndices = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
if (nFaceIndices != mesh.IndexCountPerFace.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("Index count per face not equal to face material index count in x file.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-07 07:18:47 -07:00
|
|
|
// read non triangulated face indices and create triangulated ones
|
|
|
|
mesh.FaceMaterialIndices.set_used( mesh.Indices.size() / 3);
|
2007-09-12 10:45:29 -07:00
|
|
|
u32 triangulatedindex = 0;
|
|
|
|
for (u32 tfi=0; tfi<nFaceIndices; ++tfi)
|
2007-09-07 07:18:47 -07:00
|
|
|
{
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 ind = readInt();
|
|
|
|
const u32 fc = mesh.IndexCountPerFace[tfi]/3;
|
|
|
|
for (u32 k=0; k<fc; ++k)
|
|
|
|
mesh.FaceMaterialIndices[triangulatedindex++] = ind;
|
2007-09-07 07:18:47 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// in version 03.02, the face indices end with two semicolons.
|
|
|
|
// commented out version check, as version 03.03 exported from blender also has 2 semicolons
|
2007-09-06 16:20:02 -07:00
|
|
|
if (!BinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
if (P[0] == ';')
|
|
|
|
++P;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read following data objects
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
core::stringc objectName = getNextToken();
|
|
|
|
|
|
|
|
if (objectName.size() == 0)
|
|
|
|
{
|
2007-09-07 07:18:47 -07:00
|
|
|
os::Printer::log("Unexpected ending found in Mesh Material list in .x file.", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "}")
|
|
|
|
{
|
|
|
|
break; // material list finished
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "{")
|
|
|
|
{
|
|
|
|
// template materials now available thanks to joeWright
|
|
|
|
objectName = getNextToken();
|
|
|
|
for (u32 i=0; i<TemplateMaterials.size(); ++i)
|
|
|
|
if (TemplateMaterials[i].Name == objectName)
|
|
|
|
mesh.Materials.push_back(TemplateMaterials[i].Material);
|
|
|
|
getNextToken(); // skip }
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "Material")
|
|
|
|
{
|
|
|
|
mesh.Materials.push_back(video::SMaterial());
|
|
|
|
if (!parseDataObjectMaterial(mesh.Materials.getLast()))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == ";")
|
|
|
|
{
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-05 01:59:46 -07:00
|
|
|
os::Printer::log("Unknown data object in material list in x file", objectName.c_str(), ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
if (!parseUnknownDataObject())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectMaterial(video::SMaterial& material)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: Reading mesh material");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
2007-09-07 09:09:14 -07:00
|
|
|
os::Printer::log("No opening brace in Mesh Material found in .x file", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read RGBA
|
|
|
|
readRGBA(material.DiffuseColor); checkForOneFollowingSemicolons();
|
|
|
|
|
|
|
|
// read power
|
2007-09-07 09:09:14 -07:00
|
|
|
material.Shininess = readFloat();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read specular
|
|
|
|
readRGB(material.SpecularColor); checkForOneFollowingSemicolons();
|
|
|
|
|
|
|
|
// read emissive
|
|
|
|
readRGB(material.EmissiveColor); checkForOneFollowingSemicolons();
|
|
|
|
|
|
|
|
// read other data objects
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
core::stringc objectName = getNextToken();
|
|
|
|
|
|
|
|
if (objectName.size() == 0)
|
|
|
|
{
|
2007-09-07 09:09:14 -07:00
|
|
|
os::Printer::log("Unexpected ending found in Mesh Material in .x file.", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "}")
|
|
|
|
{
|
|
|
|
break; // material finished
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName.equals_ignore_case("TextureFilename"))
|
|
|
|
{
|
|
|
|
// some exporters write "TextureFileName" instead.
|
|
|
|
core::stringc TextureFileName;
|
|
|
|
if (!parseDataObjectTextureFilename(TextureFileName))
|
|
|
|
return false;
|
|
|
|
|
2007-09-06 16:20:02 -07:00
|
|
|
// original name
|
|
|
|
SceneManager->getVideoDriver()->getTexture ( TextureFileName.c_str() );
|
|
|
|
// mesh path
|
2007-09-20 08:33:36 -07:00
|
|
|
if (!material.getTexture(0))
|
2007-09-06 16:20:02 -07:00
|
|
|
{
|
|
|
|
TextureFileName=FilePath + stripPathFromString(TextureFileName,false);
|
2007-09-20 08:33:36 -07:00
|
|
|
material.setTexture(0, SceneManager->getVideoDriver()->getTexture ( TextureFileName.c_str() ));
|
2007-09-06 16:20:02 -07:00
|
|
|
}
|
|
|
|
// working directory
|
2007-09-20 08:33:36 -07:00
|
|
|
if (!material.getTexture(0))
|
2007-09-06 16:20:02 -07:00
|
|
|
SceneManager->getVideoDriver()->getTexture ( stripPathFromString(TextureFileName,false).c_str() );
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-07 09:09:14 -07:00
|
|
|
os::Printer::log("Unknown data object in material in .x file", objectName.c_str(), ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
if (!parseUnknownDataObject())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectAnimationSet()
|
|
|
|
{
|
2007-09-10 09:15:36 -07:00
|
|
|
#ifdef _XREADER_DEBUG
|
2007-09-04 11:51:42 -07:00
|
|
|
os::Printer::log("CXFileReader: Reading animation set");
|
2007-09-10 09:15:36 -07:00
|
|
|
#endif
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
core::stringc AnimationName;
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject(&AnimationName))
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
core::stringc objectName = getNextToken();
|
|
|
|
|
|
|
|
if (objectName.size() == 0)
|
|
|
|
{
|
|
|
|
os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "}")
|
|
|
|
{
|
|
|
|
break; // animation set finished
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "Animation")
|
|
|
|
{
|
|
|
|
if (!parseDataObjectAnimation())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-05 01:59:46 -07:00
|
|
|
os::Printer::log("Unknown data object in animation set in x file", objectName.c_str(), ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
if (!parseUnknownDataObject())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectAnimation()
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: reading animation");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//anim.closed = true;
|
|
|
|
//anim.linearPositionQuality = true;
|
|
|
|
CSkinnedMesh::SJoint animationDump;
|
|
|
|
|
2007-09-10 06:11:47 -07:00
|
|
|
core::stringc FrameName;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
core::stringc objectName = getNextToken();
|
|
|
|
|
|
|
|
if (objectName.size() == 0)
|
|
|
|
{
|
|
|
|
os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "}")
|
|
|
|
{
|
|
|
|
break; // animation finished
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "AnimationKey")
|
|
|
|
{
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!parseDataObjectAnimationKey(&animationDump))
|
|
|
|
return false;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "AnimationOptions")
|
|
|
|
{
|
|
|
|
//TODO: parse options.
|
|
|
|
if (!parseUnknownDataObject())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (objectName == "{")
|
|
|
|
{
|
|
|
|
// read frame name
|
|
|
|
FrameName = getNextToken();
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-09 16:09:06 -07:00
|
|
|
os::Printer::log("Unknown data object in animation in x file", objectName.c_str(), ELL_WARNING);
|
|
|
|
if (!parseUnknownDataObject())
|
|
|
|
return false;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
2007-09-10 09:15:36 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (FrameName.size() != 0)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("getting name: ", FrameName.c_str());
|
2007-09-05 01:59:46 -07:00
|
|
|
#endif
|
2007-09-10 09:15:36 -07:00
|
|
|
CSkinnedMesh::SJoint *joint=0;
|
2007-09-06 22:55:34 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
u32 n;
|
|
|
|
for (n=0;n < AnimatedMesh->getAllJoints().size();++n)
|
|
|
|
{
|
|
|
|
if (AnimatedMesh->getAllJoints()[n]->Name==FrameName)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-10 09:15:36 -07:00
|
|
|
joint=AnimatedMesh->getAllJoints()[n];
|
|
|
|
break;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
2007-09-10 09:15:36 -07:00
|
|
|
}
|
2007-09-09 16:09:06 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!joint)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("creating joint for animation ", FrameName.c_str());
|
|
|
|
#endif
|
|
|
|
joint=AnimatedMesh->createJoint(0);
|
|
|
|
joint->Name=FrameName;
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
joint->PositionKeys.reallocate(joint->PositionKeys.size()+animationDump.PositionKeys.size());
|
|
|
|
for (n=0;n<animationDump.PositionKeys.size();++n)
|
|
|
|
{
|
|
|
|
ISkinnedMesh::SPositionKey *key=&animationDump.PositionKeys[n];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
joint->PositionKeys.push_back(*key);
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
joint->ScaleKeys.reallocate(joint->ScaleKeys.size()+animationDump.ScaleKeys.size());
|
|
|
|
for (n=0;n<animationDump.ScaleKeys.size();++n)
|
|
|
|
{
|
|
|
|
ISkinnedMesh::SScaleKey *key=&animationDump.ScaleKeys[n];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
//key->scale*=joint->LocalMatrix.getScale();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
joint->ScaleKeys.push_back(*key);
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
joint->RotationKeys.reallocate(joint->RotationKeys.size()+animationDump.RotationKeys.size());
|
|
|
|
for (n=0;n<animationDump.RotationKeys.size();++n)
|
|
|
|
{
|
|
|
|
ISkinnedMesh::SRotationKey *key=&animationDump.RotationKeys[n];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
core::matrix4 tmpMatrix;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
tmpMatrix.setRotationRadians(
|
|
|
|
core::vector3df(key->rotation.X, key->rotation.Y, key->rotation.Z) );
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
tmpMatrix=joint->LocalMatrix*tmpMatrix;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
//key->rotation = core::quaternion(tmpMatrix);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
joint->RotationKeys.push_back(*key);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
2007-09-10 09:15:36 -07:00
|
|
|
else
|
2007-09-05 01:59:46 -07:00
|
|
|
os::Printer::log("joint name was never given", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: reading animation key");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read key type
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 keyType = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
if (keyType > 4)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read number of keys
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 numberOfKeys = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// eat the semicolon after the "0". if there are keys present, readInt()
|
|
|
|
// does this for us. If there aren't, we need to do it explicitly
|
2007-09-10 09:15:36 -07:00
|
|
|
if (numberOfKeys == 0)
|
|
|
|
checkForOneFollowingSemicolons();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 i=0; i<numberOfKeys; ++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-10 09:15:36 -07:00
|
|
|
// read time
|
2007-09-12 10:45:29 -07:00
|
|
|
const u32 time = readInt();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// read keys
|
|
|
|
switch(keyType)
|
|
|
|
{
|
|
|
|
case 0: //rotation
|
|
|
|
{
|
|
|
|
//read quaternions
|
|
|
|
|
|
|
|
// read count
|
|
|
|
if (readInt() != 4)
|
|
|
|
{
|
|
|
|
os::Printer::log("Expected 4 numbers in animation key in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
f32 W = -readFloat();
|
|
|
|
f32 X = -readFloat();
|
|
|
|
f32 Y = -readFloat();
|
|
|
|
f32 Z = -readFloat();
|
|
|
|
|
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon after quaternion animation key in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ISkinnedMesh::SRotationKey *key=AnimatedMesh->createRotationKey(joint);
|
|
|
|
key->frame=(f32)time;
|
|
|
|
key->rotation.set(X,Y,Z,W);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: //scale
|
|
|
|
case 2: //position
|
|
|
|
{
|
|
|
|
// read vectors
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
// read count
|
|
|
|
if (readInt() != 3)
|
|
|
|
{
|
|
|
|
os::Printer::log("Expected 3 numbers in animation key in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
core::vector3df vector;
|
|
|
|
readVector3(vector);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon after vector animation key in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (keyType==2)
|
|
|
|
{
|
|
|
|
ISkinnedMesh::SPositionKey *key=AnimatedMesh->createPositionKey(joint);
|
|
|
|
key->frame=(f32)time;
|
|
|
|
key->position=vector;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ISkinnedMesh::SScaleKey *key=AnimatedMesh->createScaleKey(joint);
|
|
|
|
key->frame=(f32)time;
|
|
|
|
key->scale=vector;
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
// read matrix
|
|
|
|
|
|
|
|
// read count
|
|
|
|
if (readInt() != 16)
|
|
|
|
{
|
|
|
|
os::Printer::log("Expected 16 numbers in animation key in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read matrix
|
|
|
|
core::matrix4 Matrix;
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 m=0; m<4; ++m)
|
|
|
|
for (u32 n=0; n<4; ++n)
|
2007-09-04 11:51:42 -07:00
|
|
|
Matrix(m,n) = readFloat();
|
|
|
|
|
|
|
|
|
|
|
|
//Matrix=joint->LocalMatrix*Matrix;
|
|
|
|
|
|
|
|
if (!checkForTwoFollowingSemicolons())
|
|
|
|
{
|
|
|
|
os::Printer::log("No finishing semicolon after matrix animation key in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//core::vector3df rotation = Matrix.getRotationDegrees();
|
|
|
|
|
|
|
|
ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->createRotationKey(joint);
|
|
|
|
keyR->frame=(f32)time;
|
|
|
|
//keyR->rotation.set(rotation.X*core::DEGTORAD,rotation.Y*core::DEGTORAD,rotation.Z*core::DEGTORAD);
|
|
|
|
keyR->rotation= core::quaternion(Matrix);
|
|
|
|
|
|
|
|
|
|
|
|
ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->createPositionKey(joint);
|
|
|
|
keyP->frame=(f32)time;
|
|
|
|
keyP->position=Matrix.getTranslation();
|
|
|
|
|
|
|
|
core::vector3df scale=Matrix.getScale();
|
|
|
|
|
|
|
|
//if (scale.X==0) scale.X=1;
|
|
|
|
//if (scale.Y==0) scale.Y=1;
|
|
|
|
//if (scale.Z==0) scale.Z=1;
|
|
|
|
/*
|
|
|
|
ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->createScaleKey(joint);
|
|
|
|
keyS->frame=(f32)time;
|
|
|
|
keyS->scale=scale;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} // end switch
|
|
|
|
}
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
checkForOneFollowingSemicolons();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-10 09:15:36 -07:00
|
|
|
os::Printer::log("No closing brace in animation key in x file", ELL_WARNING);
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseDataObjectTextureFilename(core::stringc& texturename)
|
|
|
|
{
|
|
|
|
#ifdef _XREADER_DEBUG
|
|
|
|
os::Printer::log("CXFileReader: reading texture filename");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!readHeadOfDataObject())
|
|
|
|
{
|
|
|
|
os::Printer::log("No opening brace in Texture filename found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!getNextTokenAsString(texturename))
|
|
|
|
{
|
|
|
|
os::Printer::log("Unknown syntax while reading texture filename string in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
if (!checkForClosingBrace())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
os::Printer::log("No closing brace in Texture filename found in x file", ELL_WARNING);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CXMeshFileLoader::parseUnknownDataObject()
|
|
|
|
{
|
|
|
|
// find opening delimiter
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
core::stringc t = getNextToken();
|
|
|
|
|
|
|
|
if (t.size() == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (t == "{")
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
u32 counter = 1;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// parse until closing delimiter
|
|
|
|
|
|
|
|
while(counter)
|
|
|
|
{
|
|
|
|
core::stringc t = getNextToken();
|
|
|
|
|
|
|
|
if (t.size() == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (t == "{")
|
|
|
|
++counter;
|
|
|
|
else
|
|
|
|
if (t == "}")
|
|
|
|
--counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-10 09:15:36 -07:00
|
|
|
//! checks for closing curly brace, returns false if not there
|
|
|
|
bool CXMeshFileLoader::checkForClosingBrace()
|
|
|
|
{
|
|
|
|
return (getNextToken() == "}");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! checks for one following semicolon, returns false if not there
|
2007-09-04 11:51:42 -07:00
|
|
|
bool CXMeshFileLoader::checkForOneFollowingSemicolons()
|
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
return true;
|
|
|
|
|
2007-09-10 06:11:47 -07:00
|
|
|
return (getNextToken() == ";");
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! checks for two following semicolons, returns false if they are not there
|
|
|
|
bool CXMeshFileLoader::checkForTwoFollowingSemicolons()
|
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
return true;
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
for (u32 k=0; k<2; ++k)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-10 06:11:47 -07:00
|
|
|
if (getNextToken() != ";")
|
2007-09-04 11:51:42 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! reads header of dataobject including the opening brace.
|
|
|
|
//! returns false if error happened, and writes name of object
|
|
|
|
//! if there is one
|
|
|
|
bool CXMeshFileLoader::readHeadOfDataObject(core::stringc* outname)
|
|
|
|
{
|
|
|
|
core::stringc nameOrBrace = getNextToken();
|
|
|
|
if (nameOrBrace != "{")
|
|
|
|
{
|
|
|
|
if (outname)
|
|
|
|
(*outname) = nameOrBrace;
|
|
|
|
|
|
|
|
if (getNextToken() != "{")
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! returns next parseable token. Returns empty string if no token there
|
|
|
|
core::stringc CXMeshFileLoader::getNextToken()
|
|
|
|
{
|
|
|
|
core::stringc s;
|
|
|
|
|
|
|
|
// process binary-formatted file
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
// in binary mode it will only return NAME and STRING token
|
|
|
|
// and (correctly) skip over other tokens.
|
|
|
|
|
|
|
|
s16 tok = readBinWord();
|
2007-09-12 10:45:29 -07:00
|
|
|
u32 len;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// standalone tokens
|
|
|
|
switch (tok) {
|
|
|
|
case 1:
|
|
|
|
// name token
|
|
|
|
len = readBinDWord();
|
|
|
|
s = core::stringc(P, len);
|
|
|
|
P += len;
|
|
|
|
return s;
|
|
|
|
case 2:
|
|
|
|
// string token
|
|
|
|
len = readBinDWord();
|
|
|
|
s = core::stringc(P, len);
|
|
|
|
P += (len + 2);
|
|
|
|
return s;
|
|
|
|
case 3:
|
|
|
|
// integer token
|
|
|
|
P += 4;
|
|
|
|
return "<integer>";
|
|
|
|
case 5:
|
|
|
|
// GUID token
|
|
|
|
P += 16;
|
|
|
|
return "<guid>";
|
|
|
|
case 6:
|
|
|
|
len = readBinDWord();
|
|
|
|
P += (len * 4);
|
|
|
|
return "<int_list>";
|
|
|
|
case 7:
|
|
|
|
len = readBinDWord();
|
|
|
|
P += (len * FloatSize);
|
|
|
|
return "<flt_list>";
|
|
|
|
case 0x0a:
|
|
|
|
return "{";
|
|
|
|
case 0x0b:
|
|
|
|
return "}";
|
|
|
|
case 0x0c:
|
|
|
|
return "(";
|
|
|
|
case 0x0d:
|
|
|
|
return ")";
|
|
|
|
case 0x0e:
|
|
|
|
return "[";
|
|
|
|
case 0x0f:
|
|
|
|
return "]";
|
|
|
|
case 0x10:
|
|
|
|
return "<";
|
|
|
|
case 0x11:
|
|
|
|
return ">";
|
|
|
|
case 0x12:
|
|
|
|
return ".";
|
|
|
|
case 0x13:
|
|
|
|
return ",";
|
|
|
|
case 0x14:
|
|
|
|
return ";";
|
|
|
|
case 0x1f:
|
|
|
|
return "template";
|
|
|
|
case 0x28:
|
|
|
|
return "WORD";
|
|
|
|
case 0x29:
|
|
|
|
return "DWORD";
|
|
|
|
case 0x2a:
|
|
|
|
return "FLOAT";
|
|
|
|
case 0x2b:
|
|
|
|
return "DOUBLE";
|
|
|
|
case 0x2c:
|
|
|
|
return "CHAR";
|
|
|
|
case 0x2d:
|
|
|
|
return "UCHAR";
|
|
|
|
case 0x2e:
|
|
|
|
return "SWORD";
|
|
|
|
case 0x2f:
|
|
|
|
return "SDWORD";
|
|
|
|
case 0x30:
|
|
|
|
return "void";
|
|
|
|
case 0x31:
|
|
|
|
return "string";
|
|
|
|
case 0x32:
|
|
|
|
return "unicode";
|
2007-09-10 06:11:47 -07:00
|
|
|
case 0x33:
|
|
|
|
return "cstring";
|
2007-09-04 11:51:42 -07:00
|
|
|
case 0x34:
|
|
|
|
return "array";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// process text-formatted file
|
|
|
|
else
|
|
|
|
{
|
|
|
|
findNextNoneWhiteSpace();
|
|
|
|
|
|
|
|
if (P >= End)
|
|
|
|
return s;
|
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
while((P < End) && !core::isspace(P[0]))
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
// either keep token delimiters when already holding a token, or return if first valid char
|
|
|
|
if (P[0]==';' || P[0]=='}' || P[0]=='{' || P[0]==',')
|
|
|
|
{
|
|
|
|
if (!s.size())
|
|
|
|
{
|
|
|
|
s.append(P[0]);
|
|
|
|
++P;
|
|
|
|
}
|
|
|
|
break; // stop for delimiter
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
s.append(P[0]);
|
|
|
|
++P;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! places pointer to next begin of a token, which must be a number,
|
|
|
|
// and ignores comments
|
|
|
|
void CXMeshFileLoader::findNextNoneWhiteSpaceNumber()
|
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
while((P < End) && (P[0] != '-') && (P[0] != '.') &&
|
|
|
|
!( core::isdigit(P[0])))
|
|
|
|
++P;
|
|
|
|
|
|
|
|
if (P >= End)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// check if this is a comment
|
|
|
|
if ((P[0] == '/' && P[1] == '/') || P[0] == '#')
|
|
|
|
readUntilEndOfLine();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-09 16:09:06 -07:00
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
// places pointer to next begin of a token, and ignores comments
|
|
|
|
void CXMeshFileLoader::findNextNoneWhiteSpace()
|
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
while((P < End) && core::isspace(P[0]))
|
2007-09-04 11:51:42 -07:00
|
|
|
++P;
|
|
|
|
|
|
|
|
if (P >= End)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// check if this is a comment
|
|
|
|
if ((P[0] == '/' && P[1] == '/') ||
|
|
|
|
P[0] == '#')
|
|
|
|
readUntilEndOfLine();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! reads a x file style string
|
|
|
|
bool CXMeshFileLoader::getNextTokenAsString(core::stringc& out)
|
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
out=getNextToken();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
findNextNoneWhiteSpace();
|
|
|
|
|
|
|
|
if (P >= End)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (P[0] != '"')
|
|
|
|
return false;
|
|
|
|
++P;
|
|
|
|
|
|
|
|
while(P < End && P[0]!='"')
|
|
|
|
{
|
|
|
|
out.append(P[0]);
|
|
|
|
++P;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( P[1] != ';' || P[0] != '"')
|
|
|
|
return false;
|
|
|
|
P+=2;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CXMeshFileLoader::readUntilEndOfLine()
|
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
while(P < End)
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
if (P[0] == '\n' || P[0] == '\r')
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
++P;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
++P;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u16 CXMeshFileLoader::readBinWord()
|
|
|
|
{
|
|
|
|
u8 *Q = (u8 *)P;
|
|
|
|
u16 tmp = 0;
|
|
|
|
tmp = Q[0] + (Q[1] << 8);
|
|
|
|
P += 2;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u32 CXMeshFileLoader::readBinDWord()
|
|
|
|
{
|
|
|
|
u8 *Q = (u8 *)P;
|
|
|
|
u32 tmp = 0;
|
|
|
|
tmp = Q[0] + (Q[1] << 8) + (Q[2] << 16) + (Q[3] << 24);
|
|
|
|
P += 4;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-12 10:45:29 -07:00
|
|
|
u32 CXMeshFileLoader::readInt()
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (!BinaryNumCount)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-10 06:11:47 -07:00
|
|
|
u16 tmp = readBinWord(); // 0x06 or 0x03
|
|
|
|
if (tmp == 0x06)
|
|
|
|
BinaryNumCount = readBinDWord();
|
|
|
|
else
|
|
|
|
BinaryNumCount = 1; // single int
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
2007-09-06 16:20:02 -07:00
|
|
|
--BinaryNumCount;
|
2007-09-04 11:51:42 -07:00
|
|
|
return readBinDWord();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
findNextNoneWhiteSpaceNumber();
|
2007-09-12 10:45:29 -07:00
|
|
|
return core::strtol10(P, &P);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
f32 CXMeshFileLoader::readFloat()
|
|
|
|
{
|
2007-09-06 16:20:02 -07:00
|
|
|
if (BinaryFormat)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-10 06:11:47 -07:00
|
|
|
if (!BinaryNumCount)
|
|
|
|
{
|
|
|
|
u16 tmp = readBinWord(); // 0x07 or 0x42
|
|
|
|
if (tmp == 0x07)
|
|
|
|
BinaryNumCount = readBinDWord();
|
|
|
|
else
|
|
|
|
BinaryNumCount = 1; // single int
|
|
|
|
}
|
|
|
|
--BinaryNumCount;
|
2007-09-04 11:51:42 -07:00
|
|
|
if (FloatSize == 8)
|
|
|
|
{
|
|
|
|
char tmp[8];
|
|
|
|
memcpy(tmp, P, 8);
|
|
|
|
P += 8;
|
|
|
|
return (f32)(*(f64 *)tmp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char tmp[4];
|
|
|
|
memcpy(tmp, P, 4);
|
|
|
|
P += 4;
|
|
|
|
return *(f32 *)tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
findNextNoneWhiteSpaceNumber();
|
|
|
|
f32 ftmp;
|
|
|
|
P = core::fast_atof_move(P, ftmp);
|
|
|
|
return ftmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read 2-dimensional vector. Stops at semicolon after second value for text file format
|
|
|
|
bool CXMeshFileLoader::readVector2(core::vector2df& vec)
|
|
|
|
{
|
|
|
|
vec.X = readFloat();
|
|
|
|
vec.Y = readFloat();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read 3-dimensional vector. Stops at semicolon after third value for text file format
|
|
|
|
bool CXMeshFileLoader::readVector3(core::vector3df& vec)
|
|
|
|
{
|
|
|
|
vec.X = readFloat();
|
|
|
|
vec.Y = readFloat();
|
|
|
|
vec.Z = readFloat();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read color without alpha value. Stops after second semicolon after blue value
|
|
|
|
bool CXMeshFileLoader::readRGB(video::SColor& color)
|
|
|
|
{
|
2007-12-02 15:57:20 -08:00
|
|
|
color.setRed( (u32)(readFloat()*255.f)) ;
|
|
|
|
color.setGreen( (u32)(readFloat()*255.f)) ;
|
|
|
|
color.setBlue( (u32)(readFloat()*255.f)) ;
|
2007-09-04 11:51:42 -07:00
|
|
|
color.setAlpha( 255 );
|
|
|
|
return checkForOneFollowingSemicolons();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read color with alpha value. Stops after second semicolon after blue value
|
|
|
|
bool CXMeshFileLoader::readRGBA(video::SColor& color)
|
|
|
|
{
|
|
|
|
color.setRed( (u32)(readFloat()*255)) ;
|
|
|
|
color.setGreen( (u32)(readFloat()*255)) ;
|
|
|
|
color.setBlue( (u32)(readFloat()*255)) ;
|
|
|
|
color.setAlpha( (u32)(readFloat()*255)) ;
|
|
|
|
return checkForOneFollowingSemicolons();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
core::stringc CXMeshFileLoader::stripPathFromString(core::stringc string, bool returnPath)
|
|
|
|
{
|
|
|
|
s32 slashIndex=string.findLast('/'); // forward slash
|
|
|
|
s32 backSlash=string.findLast('\\'); // back slash
|
|
|
|
|
|
|
|
if (backSlash>slashIndex) slashIndex=backSlash;
|
|
|
|
|
|
|
|
if (slashIndex==-1)//no slashes found
|
2007-12-08 05:11:39 -08:00
|
|
|
{
|
2007-09-04 11:51:42 -07:00
|
|
|
if (returnPath)
|
|
|
|
return core::stringc(); //no path to return
|
|
|
|
else
|
|
|
|
return string;
|
2007-12-08 05:11:39 -08:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (returnPath)
|
|
|
|
return string.subString(0, slashIndex + 1);
|
|
|
|
else
|
|
|
|
return string.subString(slashIndex+1, string.size() - (slashIndex+1));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // end namespace scene
|
|
|
|
} // end namespace irr
|
|
|
|
|
|
|
|
#endif // _IRR_COMPILE_WITH_X_LOADER_
|
2007-05-20 11:03:49 -07:00
|
|
|
|