added loader for the new .irrmesh format. (CIrrMeshFileLoader)
git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@931 dfc29bdd-3216-0410-991c-e03cc46cb475master
parent
c02aca0029
commit
fbd4188b83
|
@ -1,8 +1,12 @@
|
||||||
Changes in version 1.4 (... 2007)
|
Changes in version 1.4 (... 2007)
|
||||||
|
|
||||||
- Irrlicht is now able to write Meshes out into files again. Use ISceneManager::createMeshWriter()
|
- Irrlicht now has its own file format for static meshes. It is based on xml and has the
|
||||||
|
extension .irrmesh. Irrlicht is able to write every IMesh to this file format, and of course to
|
||||||
|
read it back again.
|
||||||
|
|
||||||
|
- Irrlicht is now able to write Meshes out into files. Use ISceneManager::createMeshWriter()
|
||||||
to obtain an interface with which you can write out meshes. Currently, an own .irrmesh
|
to obtain an interface with which you can write out meshes. Currently, an own .irrmesh
|
||||||
file format is supported as well as COLLADA.
|
file format is supported as well as the COLLADA file format.
|
||||||
|
|
||||||
- the base class for nearly all Irrlicht classes has been renamed from IUnknown to IReferenceCounted
|
- the base class for nearly all Irrlicht classes has been renamed from IUnknown to IReferenceCounted
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,8 @@ public:
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
//! Reads attributes from a xml file.
|
//! Reads attributes from a xml file.
|
||||||
//! \param readCurrentElementOnly: If set to true, reading only works if current element has the name 'attributes'.
|
//! \param readCurrentElementOnly: If set to true, reading only works if current element has the name 'attributes' or
|
||||||
|
//! the name specified using elementName.
|
||||||
//! \param elementName: The surrounding element name. If it is null, the default one, "attributes" will be taken.
|
//! \param elementName: The surrounding element name. If it is null, the default one, "attributes" will be taken.
|
||||||
//! If set to false, the first appearing list of attributes are read.
|
//! If set to false, the first appearing list of attributes are read.
|
||||||
virtual bool read(irr::io::IXMLReader* reader, bool readCurrentElementOnly=false, const wchar_t* elementName=0) = 0;
|
virtual bool read(irr::io::IXMLReader* reader, bool readCurrentElementOnly=false, const wchar_t* elementName=0) = 0;
|
||||||
|
@ -163,7 +164,6 @@ public:
|
||||||
//! \param writer: The XML writer to write to
|
//! \param writer: The XML writer to write to
|
||||||
//! \param writeXMLHeader: Writes a header to the XML file, required if at the beginning of the file
|
//! \param writeXMLHeader: Writes a header to the XML file, required if at the beginning of the file
|
||||||
//! \param elementName: The surrounding element name. If it is null, the default one, "attributes" will be taken.
|
//! \param elementName: The surrounding element name. If it is null, the default one, "attributes" will be taken.
|
||||||
//! and you haven't already written one with writer->writeXMLHeader()
|
|
||||||
virtual bool write(io::IXMLWriter* writer, bool writeXMLHeader=false, const wchar_t* elementName=0) = 0;
|
virtual bool write(io::IXMLWriter* writer, bool writeXMLHeader=false, const wchar_t* elementName=0) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,9 @@ B3D, MS3D or X meshes */
|
||||||
#define _IRR_COMPILE_WITH_X_LOADER_
|
#define _IRR_COMPILE_WITH_X_LOADER_
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//! Define _IRR_COMPILE_WITH_IRR_MESH_LOADER_ if you want to load Irrlicht Engine .irrmesh files
|
||||||
|
#define _IRR_COMPILE_WITH_IRR_MESH_LOADER_
|
||||||
|
|
||||||
//! Define _IRR_COMPILE_WITH_MD2_LOADER_ if you want to load Quake 2 animated files
|
//! Define _IRR_COMPILE_WITH_MD2_LOADER_ if you want to load Quake 2 animated files
|
||||||
#define _IRR_COMPILE_WITH_MD2_LOADER_
|
#define _IRR_COMPILE_WITH_MD2_LOADER_
|
||||||
//! Define _IRR_COMPILE_WITH_MD3_LOADER_ if you want to load Quake 3 animated files
|
//! Define _IRR_COMPILE_WITH_MD3_LOADER_ if you want to load Quake 3 animated files
|
||||||
|
|
|
@ -0,0 +1,586 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#include "IrrCompileConfig.h"
|
||||||
|
#ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_
|
||||||
|
|
||||||
|
#include "CIrrMeshFileLoader.h"
|
||||||
|
#include "os.h"
|
||||||
|
#include "IXMLReader.h"
|
||||||
|
#include "SAnimatedMesh.h"
|
||||||
|
#include "fast_atof.h"
|
||||||
|
#include "IReadFile.h"
|
||||||
|
#include "IAttributes.h"
|
||||||
|
#include "IMeshSceneNode.h"
|
||||||
|
#include "SMeshBufferLightMap.h"
|
||||||
|
|
||||||
|
namespace irr
|
||||||
|
{
|
||||||
|
namespace scene
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
CIrrMeshFileLoader::CIrrMeshFileLoader(video::IVideoDriver* driver,
|
||||||
|
scene::ISceneManager* smgr, io::IFileSystem* fs)
|
||||||
|
: Driver(driver), SceneManager(smgr), FileSystem(fs)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! destructor
|
||||||
|
CIrrMeshFileLoader::~CIrrMeshFileLoader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Returns true if the file maybe is able to be loaded by this class.
|
||||||
|
/** This decision should be based only on the file extension (e.g. ".cob") */
|
||||||
|
bool CIrrMeshFileLoader::isALoadableFileExtension(const c8* fileName)
|
||||||
|
{
|
||||||
|
return strstr(fileName, ".xml") ||
|
||||||
|
strstr(fileName, ".irrmesh");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! 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().
|
||||||
|
//! See IReferenceCounted::drop() for more information.
|
||||||
|
IAnimatedMesh* CIrrMeshFileLoader::createMesh(irr::io::IReadFile* file)
|
||||||
|
{
|
||||||
|
io::IXMLReader* reader = FileSystem->createXMLReader(file);
|
||||||
|
if (!reader)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// read until mesh section, skip other parts
|
||||||
|
|
||||||
|
const core::stringc meshTagName = "mesh";
|
||||||
|
IAnimatedMesh* mesh = 0;
|
||||||
|
|
||||||
|
while(reader->read())
|
||||||
|
{
|
||||||
|
if (reader->getNodeType() == io::EXN_ELEMENT)
|
||||||
|
{
|
||||||
|
if (meshTagName == reader->getNodeName())
|
||||||
|
{
|
||||||
|
mesh = readMesh(reader);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
skipSection(reader, true); // unknown section
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader->drop();
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! reads a mesh sections and creates a mesh from it
|
||||||
|
IAnimatedMesh* CIrrMeshFileLoader::readMesh(io::IXMLReader* reader)
|
||||||
|
{
|
||||||
|
SAnimatedMesh* animatedmesh = new SAnimatedMesh();
|
||||||
|
SMesh* mesh = new SMesh();
|
||||||
|
|
||||||
|
animatedmesh->addMesh(mesh);
|
||||||
|
mesh->drop();
|
||||||
|
|
||||||
|
core::stringc bbSectionName = "boundingBox";
|
||||||
|
core::stringc bufferSectionName = "buffer";
|
||||||
|
core::stringc meshSectionName = "mesh";
|
||||||
|
|
||||||
|
if (!reader->isEmptyElement())
|
||||||
|
while(reader->read())
|
||||||
|
{
|
||||||
|
if (reader->getNodeType() == io::EXN_ELEMENT)
|
||||||
|
{
|
||||||
|
const wchar_t* nodeName = reader->getNodeName();
|
||||||
|
if (bbSectionName == nodeName)
|
||||||
|
{
|
||||||
|
// inside a bounding box, ignore it for now because
|
||||||
|
// we are calculating this anyway ourselves later.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (bufferSectionName == nodeName)
|
||||||
|
{
|
||||||
|
// we've got a mesh buffer
|
||||||
|
|
||||||
|
IMeshBuffer* buffer = readMeshBuffer(reader);
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
mesh->addMeshBuffer(buffer);
|
||||||
|
buffer->drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
skipSection(reader, true); // unknown section
|
||||||
|
|
||||||
|
} // end if node type is element
|
||||||
|
else
|
||||||
|
if (reader->getNodeType() == io::EXN_ELEMENT_END)
|
||||||
|
{
|
||||||
|
if (meshSectionName == reader->getNodeName())
|
||||||
|
{
|
||||||
|
// end of mesh section reached, cancel out
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end while reader->read();
|
||||||
|
|
||||||
|
mesh->recalculateBoundingBox();
|
||||||
|
animatedmesh->recalculateBoundingBox();
|
||||||
|
|
||||||
|
return animatedmesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! reads a mesh sections and creates a mesh buffer from it
|
||||||
|
IMeshBuffer* CIrrMeshFileLoader::readMeshBuffer(io::IXMLReader* reader)
|
||||||
|
{
|
||||||
|
IMeshBuffer* buffer = 0;
|
||||||
|
SMeshBuffer* sbuffer1 = 0;
|
||||||
|
SMeshBufferLightMap* sbuffer2 = 0;
|
||||||
|
SMeshBufferTangents* sbuffer3 = 0;
|
||||||
|
|
||||||
|
core::stringc verticesSectionName = "vertices";
|
||||||
|
core::stringc bbSectionName = "boundingBox";
|
||||||
|
core::stringc materialSectionName = "material";
|
||||||
|
core::stringc indicesSectionName = "indices";
|
||||||
|
core::stringc bufferSectionName = "buffer";
|
||||||
|
|
||||||
|
bool insideVertexSection = false;
|
||||||
|
bool insideIndexSection = false;
|
||||||
|
|
||||||
|
int vertexCount = 0;
|
||||||
|
int indexCount = 0;
|
||||||
|
|
||||||
|
video::SMaterial material;
|
||||||
|
|
||||||
|
if (!reader->isEmptyElement())
|
||||||
|
while(reader->read())
|
||||||
|
{
|
||||||
|
if (reader->getNodeType() == io::EXN_ELEMENT)
|
||||||
|
{
|
||||||
|
const wchar_t* nodeName = reader->getNodeName();
|
||||||
|
if (bbSectionName == nodeName)
|
||||||
|
{
|
||||||
|
// inside a bounding box, ignore it for now because
|
||||||
|
// we are calculating this anyway ourselves later.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (materialSectionName == nodeName)
|
||||||
|
{
|
||||||
|
//we've got a material
|
||||||
|
|
||||||
|
io::IAttributes* attributes = FileSystem->createEmptyAttributes(Driver);
|
||||||
|
attributes->read(reader, true, L"material");
|
||||||
|
|
||||||
|
Driver->fillMaterialStructureFromAttributes(material, attributes);
|
||||||
|
attributes->drop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (verticesSectionName == nodeName)
|
||||||
|
{
|
||||||
|
// vertices section
|
||||||
|
|
||||||
|
core::stringc vertexTypeName1 = "standard";
|
||||||
|
core::stringc vertexTypeName2 = "2tcoords";
|
||||||
|
core::stringc vertexTypeName3 = "tangents";
|
||||||
|
|
||||||
|
const wchar_t* vertexType = reader->getAttributeValue(L"type");
|
||||||
|
vertexCount = reader->getAttributeValueAsInt(L"vertexCount");
|
||||||
|
|
||||||
|
insideVertexSection = true;
|
||||||
|
|
||||||
|
if (vertexTypeName1 == vertexType)
|
||||||
|
{
|
||||||
|
sbuffer1 = new SMeshBuffer();
|
||||||
|
sbuffer1->Vertices.reallocate(vertexCount);
|
||||||
|
sbuffer1->Material = material;
|
||||||
|
buffer = sbuffer1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (vertexTypeName2 == vertexType)
|
||||||
|
{
|
||||||
|
sbuffer2 = new SMeshBufferLightMap();
|
||||||
|
sbuffer2->Vertices.reallocate(vertexCount);
|
||||||
|
sbuffer2->Material = material;
|
||||||
|
buffer = sbuffer2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (vertexTypeName3 == vertexType)
|
||||||
|
{
|
||||||
|
sbuffer3 = new SMeshBufferTangents();
|
||||||
|
sbuffer3->Vertices.reallocate(vertexCount);
|
||||||
|
sbuffer3->Material = material;
|
||||||
|
buffer = sbuffer3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (indicesSectionName == nodeName)
|
||||||
|
{
|
||||||
|
// indices section
|
||||||
|
|
||||||
|
indexCount = reader->getAttributeValueAsInt(L"indexCount");
|
||||||
|
insideIndexSection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end if node type is element
|
||||||
|
else
|
||||||
|
if (reader->getNodeType() == io::EXN_TEXT)
|
||||||
|
{
|
||||||
|
// read vertex data
|
||||||
|
if (insideVertexSection)
|
||||||
|
{
|
||||||
|
if (sbuffer1)
|
||||||
|
readMeshBuffer(reader, vertexCount, sbuffer1);
|
||||||
|
else
|
||||||
|
if (sbuffer2)
|
||||||
|
readMeshBuffer(reader, vertexCount, sbuffer2);
|
||||||
|
else
|
||||||
|
if (sbuffer3)
|
||||||
|
readMeshBuffer(reader, vertexCount, sbuffer3);
|
||||||
|
|
||||||
|
insideVertexSection = false;
|
||||||
|
|
||||||
|
} // end reading vertex array
|
||||||
|
else
|
||||||
|
if (insideIndexSection)
|
||||||
|
{
|
||||||
|
if (sbuffer1)
|
||||||
|
readIndices(reader, indexCount, sbuffer1->Indices);
|
||||||
|
else
|
||||||
|
if (sbuffer2)
|
||||||
|
readIndices(reader, indexCount, sbuffer2->Indices);
|
||||||
|
else
|
||||||
|
if (sbuffer2)
|
||||||
|
readIndices(reader, indexCount, sbuffer3->Indices);
|
||||||
|
|
||||||
|
insideIndexSection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end if node type is text
|
||||||
|
else
|
||||||
|
if (reader->getNodeType() == io::EXN_ELEMENT_END)
|
||||||
|
{
|
||||||
|
if (bufferSectionName == reader->getNodeName())
|
||||||
|
{
|
||||||
|
// end of buffer section reached, cancel out
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end while reader->read();
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
buffer->recalculateBoundingBox();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! read indices
|
||||||
|
void CIrrMeshFileLoader::readIndices(io::IXMLReader* reader, int indexCount, core::array<u16>& indices)
|
||||||
|
{
|
||||||
|
indices.reallocate(indexCount);
|
||||||
|
|
||||||
|
core::stringc data = reader->getNodeData();
|
||||||
|
const c8* p = &data[0];
|
||||||
|
|
||||||
|
for (int i=0; i<indexCount && *p; ++i)
|
||||||
|
{
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
indices.push_back((u16)readInt(&p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CIrrMeshFileLoader::readMeshBuffer(io::IXMLReader* reader, int vertexCount, SMeshBuffer* sbuffer)
|
||||||
|
{
|
||||||
|
core::stringc data = reader->getNodeData();
|
||||||
|
const c8* p = &data[0];
|
||||||
|
|
||||||
|
if (sbuffer)
|
||||||
|
{
|
||||||
|
video::S3DVertex vtx;
|
||||||
|
|
||||||
|
for (int i=0; i<vertexCount && *p; ++i)
|
||||||
|
{
|
||||||
|
// position
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.Y = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.Z = readFloat(&p);
|
||||||
|
|
||||||
|
// normal
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.Y = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.Z = readFloat(&p);
|
||||||
|
|
||||||
|
// color
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
sscanf(p, "%08x", &vtx.Color);
|
||||||
|
skipCurrentNoneWhiteSpace(&p);
|
||||||
|
|
||||||
|
// tcoord1
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.TCoords.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.TCoords.Y = readFloat(&p);
|
||||||
|
|
||||||
|
sbuffer->Vertices.push_back(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CIrrMeshFileLoader::readMeshBuffer(io::IXMLReader* reader, int vertexCount, SMeshBufferLightMap* sbuffer)
|
||||||
|
{
|
||||||
|
core::stringc data = reader->getNodeData();
|
||||||
|
const c8* p = &data[0];
|
||||||
|
|
||||||
|
if (sbuffer)
|
||||||
|
{
|
||||||
|
video::S3DVertex2TCoords vtx;
|
||||||
|
|
||||||
|
for (int i=0; i<vertexCount && *p; ++i)
|
||||||
|
{
|
||||||
|
// position
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.Y = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.Z = readFloat(&p);
|
||||||
|
|
||||||
|
// normal
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.Y = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.Z = readFloat(&p);
|
||||||
|
|
||||||
|
// color
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
sscanf(p, "%08x", &vtx.Color);
|
||||||
|
skipCurrentNoneWhiteSpace(&p);
|
||||||
|
|
||||||
|
// tcoord1
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.TCoords.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.TCoords.Y = readFloat(&p);
|
||||||
|
|
||||||
|
// tcoord2
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.TCoords2.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.TCoords2.Y = readFloat(&p);
|
||||||
|
|
||||||
|
sbuffer->Vertices.push_back(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CIrrMeshFileLoader::readMeshBuffer(io::IXMLReader* reader, int vertexCount, SMeshBufferTangents* sbuffer)
|
||||||
|
{
|
||||||
|
core::stringc data = reader->getNodeData();
|
||||||
|
const c8* p = &data[0];
|
||||||
|
|
||||||
|
if (sbuffer)
|
||||||
|
{
|
||||||
|
video::S3DVertexTangents vtx;
|
||||||
|
|
||||||
|
for (int i=0; i<vertexCount && *p; ++i)
|
||||||
|
{
|
||||||
|
// position
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.Y = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Pos.Z = readFloat(&p);
|
||||||
|
|
||||||
|
// normal
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.Y = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Normal.Z = readFloat(&p);
|
||||||
|
|
||||||
|
// color
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
sscanf(p, "%08x", &vtx.Color);
|
||||||
|
skipCurrentNoneWhiteSpace(&p);
|
||||||
|
|
||||||
|
// tcoord1
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.TCoords.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.TCoords.Y = readFloat(&p);
|
||||||
|
|
||||||
|
// tangent
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Tangent.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Tangent.Y = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Tangent.Z = readFloat(&p);
|
||||||
|
|
||||||
|
// binormal
|
||||||
|
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Binormal.X = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Binormal.Y = readFloat(&p);
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
vtx.Binormal.Z = readFloat(&p);
|
||||||
|
|
||||||
|
sbuffer->Vertices.push_back(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! skips an (unknown) section in the irrmesh document
|
||||||
|
void CIrrMeshFileLoader::skipSection(io::IXMLReader* reader, bool reportSkipping)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
os::Printer::log("irrMesh skipping section", core::stringc(reader->getNodeName()).c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// skip if this element is empty anyway.
|
||||||
|
if (reader->isEmptyElement())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// read until we've reached the last element in this section
|
||||||
|
u32 tagCounter = 1;
|
||||||
|
|
||||||
|
while(tagCounter && reader->read())
|
||||||
|
{
|
||||||
|
if (reader->getNodeType() == io::EXN_ELEMENT &&
|
||||||
|
!reader->isEmptyElement())
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (reportSkipping)
|
||||||
|
os::Printer::log("irrMesh unknown element:", core::stringc(reader->getNodeName()).c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
++tagCounter;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (reader->getNodeType() == io::EXN_ELEMENT_END)
|
||||||
|
--tagCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! parses a float from a char pointer and moves the pointer
|
||||||
|
//! to the end of the parsed float
|
||||||
|
inline f32 CIrrMeshFileLoader::readFloat(const c8** p)
|
||||||
|
{
|
||||||
|
f32 ftmp;
|
||||||
|
*p = core::fast_atof_move(*p, ftmp);
|
||||||
|
return ftmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! parses an int from a char pointer and moves the pointer to
|
||||||
|
//! the end of the parsed float
|
||||||
|
inline s32 CIrrMeshFileLoader::readInt(const c8** p)
|
||||||
|
{
|
||||||
|
return (s32)readFloat(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! places pointer to next begin of a token
|
||||||
|
void CIrrMeshFileLoader::skipCurrentNoneWhiteSpace(const c8** start)
|
||||||
|
{
|
||||||
|
const c8* p = *start;
|
||||||
|
|
||||||
|
while(*p && !(*p==' ' || *p=='\n' || *p=='\r' || *p=='\t'))
|
||||||
|
++p;
|
||||||
|
|
||||||
|
// TODO: skip comments <!-- -->
|
||||||
|
|
||||||
|
*start = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! places pointer to next begin of a token
|
||||||
|
void CIrrMeshFileLoader::findNextNoneWhiteSpace(const c8** start)
|
||||||
|
{
|
||||||
|
const c8* p = *start;
|
||||||
|
|
||||||
|
while(*p && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t'))
|
||||||
|
++p;
|
||||||
|
|
||||||
|
// TODO: skip comments <!-- -->
|
||||||
|
|
||||||
|
*start = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! reads floats from inside of xml element until end of xml element
|
||||||
|
void CIrrMeshFileLoader::readFloatsInsideElement(io::IXMLReader* reader, f32* floats, u32 count)
|
||||||
|
{
|
||||||
|
if (reader->isEmptyElement())
|
||||||
|
return;
|
||||||
|
|
||||||
|
while(reader->read())
|
||||||
|
{
|
||||||
|
// TODO: check for comments inside the element
|
||||||
|
// and ignore them.
|
||||||
|
|
||||||
|
if (reader->getNodeType() == io::EXN_TEXT)
|
||||||
|
{
|
||||||
|
// parse float data
|
||||||
|
core::stringc data = reader->getNodeData();
|
||||||
|
const c8* p = &data[0];
|
||||||
|
|
||||||
|
for (u32 i=0; i<count; ++i)
|
||||||
|
{
|
||||||
|
findNextNoneWhiteSpace(&p);
|
||||||
|
if (*p)
|
||||||
|
floats[i] = readFloat(&p);
|
||||||
|
else
|
||||||
|
floats[i] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (reader->getNodeType() == io::EXN_ELEMENT_END)
|
||||||
|
break; // end parsing text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace scene
|
||||||
|
} // end namespace irr
|
||||||
|
|
||||||
|
#endif // _IRR_COMPILE_WITH_IRR_MESH_LOADER_
|
|
@ -0,0 +1,96 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#ifndef __C_IRR_MESH_FILE_LOADER_H_INCLUDED__
|
||||||
|
#define __C_IRR_MESH_FILE_LOADER_H_INCLUDED__
|
||||||
|
|
||||||
|
#include "IMeshLoader.h"
|
||||||
|
#include "IFileSystem.h"
|
||||||
|
#include "IVideoDriver.h"
|
||||||
|
#include "irrString.h"
|
||||||
|
#include "SMesh.h"
|
||||||
|
#include "SMeshBuffer.h"
|
||||||
|
#include "ISceneManager.h"
|
||||||
|
|
||||||
|
namespace irr
|
||||||
|
{
|
||||||
|
namespace scene
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
//! Meshloader capable of loading .irrmesh meshes, the Irrlicht Engine mesh format for static meshes
|
||||||
|
class CIrrMeshFileLoader : public IMeshLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
CIrrMeshFileLoader(video::IVideoDriver* driver,
|
||||||
|
scene::ISceneManager* smgr, io::IFileSystem* fs);
|
||||||
|
|
||||||
|
//! destructor
|
||||||
|
virtual ~CIrrMeshFileLoader();
|
||||||
|
|
||||||
|
//! returns true if the file maybe is able to be loaded by this class
|
||||||
|
//! based on the file extension (e.g. ".cob")
|
||||||
|
virtual bool isALoadableFileExtension(const c8* fileName);
|
||||||
|
|
||||||
|
//! 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().
|
||||||
|
//! See IReferenceCounted::drop() for more information.
|
||||||
|
virtual IAnimatedMesh* createMesh(irr::io::IReadFile* file);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//! reads a mesh sections and creates a mesh from it
|
||||||
|
IAnimatedMesh* readMesh(io::IXMLReader* reader);
|
||||||
|
|
||||||
|
//! reads a mesh sections and creates a mesh buffer from it
|
||||||
|
IMeshBuffer* readMeshBuffer(io::IXMLReader* reader);
|
||||||
|
|
||||||
|
//! skips an (unknown) section in the irrmesh file
|
||||||
|
void skipSection(io::IXMLReader* reader, bool reportSkipping);
|
||||||
|
|
||||||
|
//! reads a <material> element and stores it in the material section
|
||||||
|
void readMaterial(io::IXMLReader* reader);
|
||||||
|
|
||||||
|
//! parses a float from a char pointer and moves the pointer to
|
||||||
|
//! the end of the parsed float
|
||||||
|
inline f32 readFloat(const c8** p);
|
||||||
|
|
||||||
|
//! parses an int from a char pointer and moves the pointer to
|
||||||
|
//! the end of the parsed float
|
||||||
|
inline s32 readInt(const c8** p);
|
||||||
|
|
||||||
|
//! places pointer to next begin of a token
|
||||||
|
void findNextNoneWhiteSpace(const c8** p);
|
||||||
|
|
||||||
|
//! places pointer to next begin of a token
|
||||||
|
void skipCurrentNoneWhiteSpace(const c8** p);
|
||||||
|
|
||||||
|
//! reads floats from inside of xml element until end of xml element
|
||||||
|
void readFloatsInsideElement(io::IXMLReader* reader, f32* floats, u32 count);
|
||||||
|
|
||||||
|
//! read all 3 types of mesh buffers
|
||||||
|
void readMeshBuffer(io::IXMLReader* reader, int vertexCount, SMeshBuffer* sbuffer);
|
||||||
|
void readMeshBuffer(io::IXMLReader* reader, int vertexCount, SMeshBufferLightMap* sbuffer);
|
||||||
|
void readMeshBuffer(io::IXMLReader* reader, int vertexCount, SMeshBufferTangents* sbuffer);
|
||||||
|
|
||||||
|
//! read indices
|
||||||
|
void readIndices(io::IXMLReader* reader, int indexCount, core::array<u16>& indices);
|
||||||
|
|
||||||
|
|
||||||
|
// member variables
|
||||||
|
|
||||||
|
video::IVideoDriver* Driver;
|
||||||
|
scene::ISceneManager* SceneManager;
|
||||||
|
io::IFileSystem* FileSystem;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace scene
|
||||||
|
} // end namespace irr
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
#include "CGeometryCreator.h"
|
#include "CGeometryCreator.h"
|
||||||
|
|
||||||
|
#ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_
|
||||||
|
#include "CIrrMeshFileLoader.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _IRR_COMPILE_WITH_BSP_LOADER_
|
#ifdef _IRR_COMPILE_WITH_BSP_LOADER_
|
||||||
#include "CBSPMeshFileLoader.h"
|
#include "CBSPMeshFileLoader.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -169,7 +173,9 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs,
|
||||||
|
|
||||||
// add file format loaders
|
// add file format loaders
|
||||||
|
|
||||||
|
#ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_
|
||||||
|
MeshLoaderList.push_back(new CIrrMeshFileLoader(Driver, this, FileSystem));
|
||||||
|
#endif
|
||||||
#ifdef _IRR_COMPILE_WITH_BSP_LOADER_
|
#ifdef _IRR_COMPILE_WITH_BSP_LOADER_
|
||||||
MeshLoaderList.push_back(new CBSPMeshFileLoader(FileSystem, Driver, this));
|
MeshLoaderList.push_back(new CBSPMeshFileLoader(FileSystem, Driver, this));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1276,6 +1276,12 @@
|
||||||
<File
|
<File
|
||||||
RelativePath=".\CDMFLoader.h">
|
RelativePath=".\CDMFLoader.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\CIrrMeshFileLoader.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\CIrrMeshFileLoader.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\CLMTSMeshFileLoader.cpp">
|
RelativePath=".\CLMTSMeshFileLoader.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
|
Loading…
Reference in New Issue