irrlicht/source/Irrlicht/COgreMeshFileLoader.cpp
cutealien 2928a632a4 Material.ZWriteEnable is now of type E_ZWRITE instead of bool and ZWriteFineControl get removed (or merged into ZWriteEnable).
This breaks compiling. To have old values replace false with EZW_OFF and true with EWZ_AUTO.

There's a bit history to this change. ZWriteFineControl got introduced after 1.8 so it was never in a released version.
Basically it was needed after some changes had been made to allow shaders to have zwrite enabled independent
of the material-type (which worked badly for shaders). This had caused other problems as it was then enabled too often instead. 
So to quickly fix those bugs and avoid breaking compatibility I had introduced a new enum ZWriteFineControl in SMaterial.
This worked and didn't break compiling - but I noticed by now that introducing a second flag for this made maintainance for an already 
very hard to understand problem (figuring out the implementation of transparency and zwriting) even more complicated. 
So to keep maintance somewhat sane I decided to break compiling now and merge those two flags. 
The behavior should not be affected by this commit - except for users which set this flag already in their code and have to switch to the enum now.

Serialization is switched on loading old files (so SMaterial has enum already and writes that out).


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6026 dfc29bdd-3216-0410-991c-e03cc46cb475
2020-01-02 15:34:52 +00:00

1608 lines
44 KiB
C++

// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
// Originally written by Christian Stehno, modified by Nikolaus Gebhardt
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_OGRE_LOADER_
#include "COgreMeshFileLoader.h"
#include "CMeshTextureLoader.h"
#include "os.h"
#include "SMeshBuffer.h"
#include "SAnimatedMesh.h"
#include "IReadFile.h"
#include "fast_atof.h"
#include "coreutil.h"
#ifdef _DEBUG
#define IRR_OGRE_LOADER_DEBUG
#endif
namespace irr
{
namespace scene
{
namespace
{
enum OGRE_CHUNKS
{
// Main Chunks
COGRE_HEADER= 0x1000,
COGRE_SKELETON= 0x2000,
COGRE_MESH= 0x3000,
// sub chunks of COGRE_MESH
COGRE_SUBMESH= 0x4000,
COGRE_GEOMETRY= 0x5000,
COGRE_SKELETON_LINK= 0x6000,
COGRE_BONE_ASSIGNMENT= 0x7000,
COGRE_MESH_LOD= 0x8000,
COGRE_MESH_BOUNDS= 0x9000,
COGRE_MESH_SUBMESH_NAME_TABLE= 0xA000,
COGRE_MESH_EDGE_LISTS= 0xB000,
// sub chunks of COGRE_SKELETON
COGRE_BONE_PARENT= 0x3000,
COGRE_ANIMATION= 0x4000,
COGRE_ANIMATION_TRACK= 0x4100,
COGRE_ANIMATION_KEYFRAME= 0x4110,
COGRE_ANIMATION_LINK= 0x5000,
// sub chunks of COGRE_SUBMESH
COGRE_SUBMESH_OPERATION= 0x4010,
COGRE_SUBMESH_BONE_ASSIGNMENT= 0x4100,
COGRE_SUBMESH_TEXTURE_ALIAS= 0x4200,
// sub chunks of COGRE_GEOMETRY
COGRE_GEOMETRY_VERTEX_DECLARATION= 0x5100,
COGRE_GEOMETRY_VERTEX_ELEMENT= 0x5110,
COGRE_GEOMETRY_VERTEX_BUFFER= 0x5200,
COGRE_GEOMETRY_VERTEX_BUFFER_DATA= 0x5210
};
}
//! Constructor
COgreMeshFileLoader::COgreMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver)
: FileSystem(fs), Driver(driver), SwapEndian(false), Mesh(0), NumUV(0)
{
#ifdef _DEBUG
setDebugName("COgreMeshFileLoader");
#endif
if (FileSystem)
FileSystem->grab();
if (Driver)
Driver->grab();
TextureLoader = new CMeshTextureLoader( FileSystem, Driver );
}
//! destructor
COgreMeshFileLoader::~COgreMeshFileLoader()
{
clearMeshes();
if (FileSystem)
FileSystem->drop();
if (Driver)
Driver->drop();
if (Mesh)
Mesh->drop();
}
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp")
bool COgreMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "mesh" );
}
//! 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* COgreMeshFileLoader::createMesh(io::IReadFile* file)
{
if ( !file )
return 0;
if ( getMeshTextureLoader() )
getMeshTextureLoader()->setMeshFile(file);
s16 id;
file->read(&id, 2);
if (id == COGRE_HEADER)
SwapEndian=false;
else if (id == 0x0010)
SwapEndian=true;
else
return 0;
ChunkData data;
readString(file, data, Version);
if ((Version != "[MeshSerializer_v1.30]") && (Version != "[MeshSerializer_v1.40]") && (Version != "[MeshSerializer_v1.41]"))
{
os::Printer::log("Unsupported ogre mesh version", Version.c_str(), ELL_INFORMATION);
return 0;
}
clearMeshes();
if (Mesh)
Mesh->drop();
CurrentlyLoadingFromPath = FileSystem->getFileDir(file->getFileName());
loadMaterials(file);
if (readChunk(file))
{
// delete data loaded from file
clearMeshes();
if (Skeleton.Bones.size())
{
ISkinnedMesh* tmp = static_cast<CSkinnedMesh*>(Mesh);
static_cast<CSkinnedMesh*>(Mesh)->updateBoundingBox();
Skeleton.Animations.clear();
Skeleton.Bones.clear();
Mesh=0;
return tmp;
}
else
{
for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i)
((SMeshBuffer*)Mesh->getMeshBuffer(i))->recalculateBoundingBox();
((SMesh*)Mesh)->recalculateBoundingBox();
SAnimatedMesh* am = new SAnimatedMesh();
am->Type = EAMT_3DS;
am->addMesh(Mesh);
am->recalculateBoundingBox();
Mesh->drop();
Mesh = 0;
return am;
}
}
Mesh->drop();
Mesh = 0;
return 0;
}
bool COgreMeshFileLoader::readChunk(io::IReadFile* file)
{
while(file->getPos() < file->getSize())
{
ChunkData data;
readChunkData(file, data);
switch(data.header.id)
{
case COGRE_MESH:
{
Meshes.push_back(OgreMesh());
readObjectChunk(file, data, Meshes.getLast());
if (Skeleton.Bones.size())
Mesh = new CSkinnedMesh();
else
Mesh = new SMesh();
composeObject();
}
break;
default:
return true;
}
}
return true;
}
bool COgreMeshFileLoader::readObjectChunk(io::IReadFile* file, ChunkData& parent, OgreMesh& mesh)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Object Chunk", ELL_DEBUG);
#endif
readBool(file, parent, mesh.SkeletalAnimation);
bool skeleton_loaded=false;
while ((parent.read < parent.header.length)&&(file->getPos() < file->getSize()))
{
ChunkData data;
readChunkData(file, data);
switch(data.header.id)
{
case COGRE_GEOMETRY:
readGeometry(file, data, mesh.Geometry);
break;
case COGRE_SUBMESH:
mesh.SubMeshes.push_back(OgreSubMesh());
readSubMesh(file, data, mesh.SubMeshes.getLast());
break;
case COGRE_MESH_BOUNDS:
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Mesh Bounds", ELL_DEBUG);
#endif
readVector(file, data, mesh.BBoxMinEdge);
readVector(file, data, mesh.BBoxMaxEdge);
readFloat(file, data, &mesh.BBoxRadius);
}
break;
case COGRE_SKELETON_LINK:
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Skeleton link", ELL_DEBUG);
#endif
core::stringc name;
readString(file, data, name);
loadSkeleton(file, name);
skeleton_loaded=true;
}
break;
case COGRE_BONE_ASSIGNMENT:
{
mesh.BoneAssignments.push_back(OgreBoneAssignment());
readInt(file, data, &mesh.BoneAssignments.getLast().VertexID);
readShort(file, data, &mesh.BoneAssignments.getLast().BoneID);
readFloat(file, data, &mesh.BoneAssignments.getLast().Weight);
}
break;
case COGRE_MESH_LOD:
case COGRE_MESH_SUBMESH_NAME_TABLE:
case COGRE_MESH_EDGE_LISTS:
// ignore chunk
file->seek(data.header.length-data.read, true);
data.read += data.header.length-data.read;
break;
default:
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Skipping", core::stringc(data.header.id), ELL_DEBUG);
#endif
// ignore chunk
file->seek(data.header.length-data.read, true);
data.read += data.header.length-data.read;
break;
}
parent.read += data.read;
}
if (!skeleton_loaded)
loadSkeleton(file, FileSystem->getFileBasename(file->getFileName(), false));
return true;
}
bool COgreMeshFileLoader::readGeometry(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Geometry", ELL_DEBUG);
#endif
readInt(file, parent, &geometry.NumVertex);
while(parent.read < parent.header.length)
{
ChunkData data;
readChunkData(file, data);
switch(data.header.id)
{
case COGRE_GEOMETRY_VERTEX_DECLARATION:
readVertexDeclaration(file, data, geometry);
break;
case COGRE_GEOMETRY_VERTEX_BUFFER:
readVertexBuffer(file, data, geometry);
break;
default:
// ignore chunk
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Skipping", core::stringc(data.header.id), ELL_DEBUG);
#endif
file->seek(data.header.length-data.read, true);
data.read += data.header.length-data.read;
}
parent.read += data.read;
}
if (parent.read != parent.header.length)
os::Printer::log("Incorrect geometry length. File might be corrupted.");
return true;
}
bool COgreMeshFileLoader::readVertexDeclaration(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Vertex Declaration", ELL_DEBUG);
#endif
NumUV = 0;
while(parent.read < parent.header.length)
{
ChunkData data;
readChunkData(file, data);
switch(data.header.id)
{
case COGRE_GEOMETRY_VERTEX_ELEMENT:
{
geometry.Elements.push_back(OgreVertexElement());
OgreVertexElement& elem = geometry.Elements.getLast();
readShort(file, data, &elem.Source);
readShort(file, data, &elem.Type);
readShort(file, data, &elem.Semantic);
if (elem.Semantic == 7) //Tex coords
{
++NumUV;
}
readShort(file, data, &elem.Offset);
elem.Offset /= sizeof(f32);
readShort(file, data, &elem.Index);
}
break;
default:
// ignore chunk
file->seek(data.header.length-data.read, true);
data.read += data.header.length-data.read;
}
parent.read += data.read;
}
if (parent.read != parent.header.length)
os::Printer::log("Incorrect vertex declaration length. File might be corrupted.");
return true;
}
bool COgreMeshFileLoader::readVertexBuffer(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Vertex Buffer", ELL_DEBUG);
#endif
OgreVertexBuffer buf;
readShort(file, parent, &buf.BindIndex);
readShort(file, parent, &buf.VertexSize);
buf.VertexSize /= sizeof(f32);
ChunkData data;
readChunkData(file, data);
if (data.header.id == COGRE_GEOMETRY_VERTEX_BUFFER_DATA)
{
buf.Data.set_used(geometry.NumVertex*buf.VertexSize);
readFloat(file, data, buf.Data.pointer(), geometry.NumVertex*buf.VertexSize);
}
geometry.Buffers.push_back(buf);
parent.read += data.read;
if (parent.read != parent.header.length)
os::Printer::log("Incorrect vertex buffer length. File might be corrupted.");
return true;
}
bool COgreMeshFileLoader::readSubMesh(io::IReadFile* file, ChunkData& parent, OgreSubMesh& subMesh)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Submesh", ELL_DEBUG);
#endif
readString(file, parent, subMesh.Material);
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("using material", subMesh.Material, ELL_DEBUG);
#endif
readBool(file, parent, subMesh.SharedVertices);
s32 numIndices;
readInt(file, parent, &numIndices);
subMesh.Indices.set_used(numIndices);
readBool(file, parent, subMesh.Indices32Bit);
if (subMesh.Indices32Bit)
readInt(file, parent, subMesh.Indices.pointer(), numIndices);
else
{
for (s32 i=0; i<numIndices; ++i)
{
u16 num;
readShort(file, parent, &num);
subMesh.Indices[i]=num;
}
}
while(parent.read < parent.header.length)
{
ChunkData data;
readChunkData(file, data);
switch(data.header.id)
{
case COGRE_GEOMETRY:
readGeometry(file, data, subMesh.Geometry);
break;
case COGRE_SUBMESH_OPERATION:
readShort(file, data, &subMesh.Operation);
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Submesh Operation",core::stringc(subMesh.Operation), ELL_DEBUG);
#endif
if (subMesh.Operation != 4)
os::Printer::log("Primitive type != trilist not yet implemented", ELL_WARNING);
break;
case COGRE_SUBMESH_TEXTURE_ALIAS:
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Submesh Texture Alias", ELL_DEBUG);
#endif
core::stringc texture, alias;
readString(file, data, texture);
readString(file, data, alias);
subMesh.TextureAliases.push_back(OgreTextureAlias(texture,alias));
}
break;
case COGRE_SUBMESH_BONE_ASSIGNMENT:
{
subMesh.BoneAssignments.push_back(OgreBoneAssignment());
readInt(file, data, &subMesh.BoneAssignments.getLast().VertexID);
readShort(file, data, &subMesh.BoneAssignments.getLast().BoneID);
readFloat(file, data, &subMesh.BoneAssignments.getLast().Weight);
}
break;
default:
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Skipping", core::stringc(data.header.id), ELL_DEBUG);
#endif
parent.read=parent.header.length;
file->seek(-(long)sizeof(ChunkHeader), true);
return true;
}
parent.read += data.read;
}
if (parent.read != parent.header.length)
os::Printer::log("Incorrect submesh length. File might be corrupted.");
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Done with submesh", ELL_DEBUG);
#endif
return true;
}
void COgreMeshFileLoader::composeMeshBufferMaterial(scene::IMeshBuffer* mb, const core::stringc& materialName)
{
video::SMaterial& material=mb->getMaterial();
for (u32 k=0; k<Materials.size(); ++k)
{
if ((materialName==Materials[k].Name)&&(Materials[k].Techniques.size())&&(Materials[k].Techniques[0].Passes.size()))
{
material=Materials[k].Techniques[0].Passes[0].Material;
for (u32 i=0; i<Materials[k].Techniques[0].Passes[0].Texture.Filename.size(); ++i)
{
video::ITexture * texture = NULL;
if ( getMeshTextureLoader() )
{
texture = getMeshTextureLoader()->getTexture(Materials[k].Techniques[0].Passes[0].Texture.Filename[i]);
if ( texture )
material.setTexture(i, texture);
}
}
break;
}
}
}
scene::SMeshBuffer* COgreMeshFileLoader::composeMeshBuffer(const core::array<s32>& indices, const OgreGeometry& geom)
{
scene::SMeshBuffer *mb=new scene::SMeshBuffer();
u32 i;
mb->Indices.set_used(indices.size());
for (i=0; i<indices.size(); ++i)
mb->Indices[i]=indices[i];
mb->Vertices.set_used(geom.NumVertex);
for (i=0; i<geom.Elements.size(); ++i)
{
if (geom.Elements[i].Semantic==1) //Pos
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
for (s32 k=0; k<geom.NumVertex; ++k)
{
mb->Vertices[k].Color=mb->Material.DiffuseColor;
mb->Vertices[k].Pos.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]);
ePos += eSize;
}
}
}
}
if (geom.Elements[i].Semantic==4) //Normal
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
for (s32 k=0; k<geom.NumVertex; ++k)
{
mb->Vertices[k].Normal.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]);
ePos += eSize;
}
}
}
}
if (geom.Elements[i].Semantic==7) //TexCoord
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
for (s32 k=0; k<geom.NumVertex; ++k)
{
mb->Vertices[k].TCoords.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1]);
ePos += eSize;
}
}
}
}
}
return mb;
}
scene::SMeshBufferLightMap* COgreMeshFileLoader::composeMeshBufferLightMap(const core::array<s32>& indices, const OgreGeometry& geom)
{
scene::SMeshBufferLightMap *mb=new scene::SMeshBufferLightMap();
u32 i;
mb->Indices.set_used(indices.size());
for (i=0; i<indices.size(); ++i)
mb->Indices[i]=indices[i];
mb->Vertices.set_used(geom.NumVertex);
for (i=0; i<geom.Elements.size(); ++i)
{
if (geom.Elements[i].Semantic==1) //Pos
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
for (s32 k=0; k<geom.NumVertex; ++k)
{
mb->Vertices[k].Color=mb->Material.DiffuseColor;
mb->Vertices[k].Pos.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]);
ePos += eSize;
}
}
}
}
if (geom.Elements[i].Semantic==4) //Normal
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
for (s32 k=0; k<geom.NumVertex; ++k)
{
mb->Vertices[k].Normal.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]);
ePos += eSize;
}
}
}
}
if (geom.Elements[i].Semantic==7) //TexCoord
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
// make sure we have data for a second texture coord
const bool secondCoord = (eSize>ePos+3);
for (s32 k=0; k<geom.NumVertex; ++k)
{
mb->Vertices[k].TCoords.set(geom.Buffers[j].Data[ePos], geom.Buffers[j].Data[ePos+1]);
if (secondCoord)
mb->Vertices[k].TCoords2.set(geom.Buffers[j].Data[ePos+2], geom.Buffers[j].Data[ePos+3]);
else
mb->Vertices[k].TCoords2.set(geom.Buffers[j].Data[ePos], geom.Buffers[j].Data[ePos+1]);
ePos += eSize;
}
}
}
}
}
return mb;
}
scene::IMeshBuffer* COgreMeshFileLoader::composeMeshBufferSkinned(scene::CSkinnedMesh& mesh, const core::array<s32>& indices, const OgreGeometry& geom)
{
scene::SSkinMeshBuffer *mb=mesh.addMeshBuffer();
if (NumUV>1)
{
mb->convertTo2TCoords();
mb->Vertices_2TCoords.set_used(geom.NumVertex);
}
else
mb->Vertices_Standard.set_used(geom.NumVertex);
u32 i;
mb->Indices.set_used(indices.size());
for (i=0; i<indices.size(); i+=3)
{
mb->Indices[i+0]=indices[i+2];
mb->Indices[i+1]=indices[i+1];
mb->Indices[i+2]=indices[i+0];
}
for (i=0; i<geom.Elements.size(); ++i)
{
if (geom.Elements[i].Semantic==1) //Pos
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
for (s32 k=0; k<geom.NumVertex; ++k)
{
if (NumUV>1)
mb->Vertices_2TCoords[k].Color=mb->Material.DiffuseColor;
else
mb->Vertices_Standard[k].Color=mb->Material.DiffuseColor;
mb->getPosition(k).set(-geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]);
ePos += eSize;
}
}
}
}
if (geom.Elements[i].Semantic==4) //Normal
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
for (s32 k=0; k<geom.NumVertex; ++k)
{
mb->getNormal(k).set(-geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]);
ePos += eSize;
}
}
}
}
if (geom.Elements[i].Semantic==7) //TexCoord
{
for (u32 j=0; j<geom.Buffers.size(); ++j)
{
if (geom.Elements[i].Source==geom.Buffers[j].BindIndex)
{
u32 eSize=geom.Buffers[j].VertexSize;
u32 ePos=geom.Elements[i].Offset;
// make sure we have data for a second texture coord
const bool secondCoord = (eSize>ePos+3);
for (s32 k=0; k<geom.NumVertex; ++k)
{
mb->getTCoords(k).set(geom.Buffers[j].Data[ePos], geom.Buffers[j].Data[ePos+1]);
if (NumUV>1)
{
if (secondCoord)
mb->Vertices_2TCoords[k].TCoords2.set(geom.Buffers[j].Data[ePos+2], geom.Buffers[j].Data[ePos+3]);
else
mb->Vertices_2TCoords[k].TCoords2.set(geom.Buffers[j].Data[ePos], geom.Buffers[j].Data[ePos+1]);
}
ePos += eSize;
}
}
}
}
}
return mb;
}
void COgreMeshFileLoader::composeObject(void)
{
for (u32 i=0; i<Meshes.size(); ++i)
{
for (u32 j=0; j<Meshes[i].SubMeshes.size(); ++j)
{
IMeshBuffer* mb;
if (Meshes[i].SubMeshes[j].SharedVertices)
{
if (Skeleton.Bones.size())
{
mb = composeMeshBufferSkinned(*(CSkinnedMesh*)Mesh, Meshes[i].SubMeshes[j].Indices, Meshes[i].Geometry);
}
else if (NumUV < 2)
{
mb = composeMeshBuffer(Meshes[i].SubMeshes[j].Indices, Meshes[i].Geometry);
}
else
{
mb = composeMeshBufferLightMap(Meshes[i].SubMeshes[j].Indices, Meshes[i].Geometry);
}
}
else
{
if (Skeleton.Bones.size())
{
mb = composeMeshBufferSkinned(*(CSkinnedMesh*)Mesh, Meshes[i].SubMeshes[j].Indices, Meshes[i].SubMeshes[j].Geometry);
}
else if (NumUV < 2)
{
mb = composeMeshBuffer(Meshes[i].SubMeshes[j].Indices, Meshes[i].SubMeshes[j].Geometry);
}
else
{
mb = composeMeshBufferLightMap(Meshes[i].SubMeshes[j].Indices, Meshes[i].SubMeshes[j].Geometry);
}
}
if (mb != 0)
{
composeMeshBufferMaterial(mb, Meshes[i].SubMeshes[j].Material);
if (!Skeleton.Bones.size())
{
((SMesh*)Mesh)->addMeshBuffer(mb);
mb->drop();
}
}
}
}
if (Skeleton.Bones.size())
{
CSkinnedMesh* m = (CSkinnedMesh*)Mesh;
// Create Joints
for (u32 i=0; i<Skeleton.Bones.size(); ++i)
{
ISkinnedMesh::SJoint* joint = m->addJoint();
joint->Name=Skeleton.Bones[i].Name;
// IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility.
// Not tested so far if this was correct or wrong before quaternion fix!
Skeleton.Bones[i].Orientation.getMatrix_transposed(joint->LocalMatrix);
if (Skeleton.Bones[i].Scale != core::vector3df(1,1,1))
{
core::matrix4 scaleMatrix;
scaleMatrix.setScale( Skeleton.Bones[i].Scale );
joint->LocalMatrix *= scaleMatrix;
}
joint->LocalMatrix.setTranslation( Skeleton.Bones[i].Position );
}
// Joints hierarchy
for (u32 i=0; i<Skeleton.Bones.size(); ++i)
{
if (Skeleton.Bones[i].Parent<m->getJointCount())
{
m->getAllJoints()[Skeleton.Bones[i].Parent]->Children.push_back(m->getAllJoints()[Skeleton.Bones[i].Handle]);
}
}
// Weights
u32 bufCount=0;
for (u32 i=0; i<Meshes.size(); ++i)
{
for (u32 j=0; j<Meshes[i].SubMeshes.size(); ++j)
{
for (u32 k=0; k<Meshes[i].SubMeshes[j].BoneAssignments.size(); ++k)
{
const OgreBoneAssignment& ba = Meshes[i].SubMeshes[j].BoneAssignments[k];
if (ba.BoneID<m->getJointCount())
{
ISkinnedMesh::SWeight* w = m->addWeight(m->getAllJoints()[ba.BoneID]);
w->strength=ba.Weight;
w->vertex_id=ba.VertexID;
w->buffer_id=bufCount;
}
}
++bufCount;
}
}
for (u32 i=0; i<Skeleton.Animations.size(); ++i)
{
for (u32 j=0; j<Skeleton.Animations[i].Keyframes.size(); ++j)
{
OgreKeyframe& frame = Skeleton.Animations[i].Keyframes[j];
ISkinnedMesh::SJoint* keyjoint = m->getAllJoints()[frame.BoneID];
ISkinnedMesh::SPositionKey* poskey = m->addPositionKey(keyjoint);
poskey->frame=frame.Time*25;
poskey->position=keyjoint->LocalMatrix.getTranslation()+frame.Position;
ISkinnedMesh::SRotationKey* rotkey = m->addRotationKey(keyjoint);
rotkey->frame=frame.Time*25;
// IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from keyjoint->LocalMatrix to keyjoint->LocalMatrix.getTransposed() for downward compatibility.
// Not tested so far if this was correct or wrong before quaternion fix!
rotkey->rotation=core::quaternion(keyjoint->LocalMatrix.getTransposed())*frame.Orientation;
ISkinnedMesh::SScaleKey* scalekey = m->addScaleKey(keyjoint);
scalekey->frame=frame.Time*25;
scalekey->scale=frame.Scale;
}
}
m->finalize();
}
}
void COgreMeshFileLoader::getMaterialToken(io::IReadFile* file, core::stringc& token, bool noNewLine)
{
bool parseString=false;
c8 c=0;
token = "";
if (file->getPos() >= file->getSize())
return;
file->read(&c, sizeof(c8));
// search for word beginning
while ( core::isspace(c) && (file->getPos() < file->getSize()))
{
if (noNewLine && c=='\n')
{
file->seek(-1, true);
return;
}
file->read(&c, sizeof(c8));
}
// check if we read a string
if (c=='"')
{
parseString = true;
file->read(&c, sizeof(c8));
}
do
{
if (c=='/')
{
file->read(&c, sizeof(c8));
// check for comments, cannot be part of strings
if (!parseString && (c=='/'))
{
// skip comments
while(c!='\n')
file->read(&c, sizeof(c8));
if (!token.size())
{
// if we start with a comment we need to skip
// following whitespaces, so restart
getMaterialToken(file, token, noNewLine);
return;
}
else
{
// else continue with next character
file->read(&c, sizeof(c8));
continue;
}
}
else
{
// else append first slash and check if second char
// ends this token
token.append('/');
if ((!parseString && core::isspace(c)) ||
(parseString && (c=='"')))
return;
}
}
token.append(c);
file->read(&c, sizeof(c8));
// read until a token delimiter is found
}
while (((!parseString && !core::isspace(c)) || (parseString && (c!='"'))) &&
(file->getPos() < file->getSize()));
// we want to skip the last quotes of a string , but other chars might be the next
// token already.
if (!parseString)
file->seek(-1, true);
}
bool COgreMeshFileLoader::readColor(io::IReadFile* file, video::SColor& col)
{
core::stringc token;
getMaterialToken(file, token);
if (token!="vertexcolour")
{
video::SColorf col_f;
col_f.r=core::fast_atof(token.c_str());
getMaterialToken(file, token);
col_f.g=core::fast_atof(token.c_str());
getMaterialToken(file, token);
col_f.b=core::fast_atof(token.c_str());
getMaterialToken(file, token, true);
if (token.size())
col_f.a=core::fast_atof(token.c_str());
else
col_f.a=1.0f;
if ((col_f.r==0.0f)&&(col_f.g==0.0f)&&(col_f.b==0.0f))
col.set(255,255,255,255);
else
col=col_f.toSColor();
return false;
}
return true;
}
void COgreMeshFileLoader::readPass(io::IReadFile* file, OgreTechnique& technique)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Pass");
#endif
core::stringc token;
technique.Passes.push_back(OgrePass());
OgrePass& pass=technique.Passes.getLast();
getMaterialToken(file, token); //open brace or name
if (token != "{")
getMaterialToken(file, token); //open brace
getMaterialToken(file, token);
if (token == "}")
return;
u32 inBlocks=1;
u32 textureUnit=0;
while(inBlocks)
{
if (token=="ambient")
pass.AmbientTokenColor=readColor(file, pass.Material.AmbientColor);
else if (token=="diffuse")
pass.DiffuseTokenColor=readColor(file, pass.Material.DiffuseColor);
else if (token=="specular")
{
pass.SpecularTokenColor=readColor(file, pass.Material.SpecularColor);
getMaterialToken(file, token);
pass.Material.Shininess=core::fast_atof(token.c_str());
}
else if (token=="emissive")
pass.EmissiveTokenColor=readColor(file, pass.Material.EmissiveColor);
else if (token=="scene_blend")
{ // TODO: Choose correct values
getMaterialToken(file, token);
if (token=="add")
pass.Material.MaterialType=video::EMT_TRANSPARENT_ADD_COLOR;
else if (token=="modulate")
pass.Material.MaterialType=video::EMT_SOLID;
else if (token=="alpha_blend")
pass.Material.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
else if (token=="colour_blend")
pass.Material.MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA;
else
getMaterialToken(file, token);
}
else if (token=="depth_check")
{
getMaterialToken(file, token);
if (token!="on")
pass.Material.ZBuffer=video::ECFN_DISABLED;
}
else if (token=="depth_write")
{
getMaterialToken(file, token);
pass.Material.ZWriteEnable=(token=="on") ? video::EZW_ON : video::EZW_OFF;
}
else if (token=="depth_func")
{
getMaterialToken(file, token); // Function name
if (token=="always_fail")
pass.Material.ZBuffer=video::ECFN_NEVER;
else if (token=="always_pass")
pass.Material.ZBuffer=video::ECFN_ALWAYS;
else if (token=="equal")
pass.Material.ZBuffer=video::ECFN_EQUAL;
else if (token=="greater")
pass.Material.ZBuffer=video::ECFN_GREATER;
else if (token=="greater_equal")
pass.Material.ZBuffer=video::ECFN_GREATEREQUAL;
else if (token=="less")
pass.Material.ZBuffer=video::ECFN_LESS;
else if (token=="less_equal")
pass.Material.ZBuffer=video::ECFN_LESSEQUAL;
else if (token=="not_equal")
pass.Material.ZBuffer=video::ECFN_NOTEQUAL;
}
else if (token=="normalise_normals")
{
getMaterialToken(file, token);
pass.Material.NormalizeNormals=(token=="on");
}
else if (token=="depth_bias")
{
getMaterialToken(file, token); // bias value
}
else if (token=="alpha_rejection")
{
getMaterialToken(file, token); // function name
getMaterialToken(file, token); // value
pass.Material.MaterialTypeParam=core::fast_atof(token.c_str());
}
else if (token=="alpha_to_coverage")
{
getMaterialToken(file, token);
if (token=="on")
pass.Material.AntiAliasing |= video::EAAM_ALPHA_TO_COVERAGE;
}
else if (token=="colour_write")
{
getMaterialToken(file, token);
pass.Material.ColorMask = (token=="on")?video::ECP_ALL:video::ECP_NONE;
}
else if (token=="cull_hardware")
{
getMaterialToken(file, token); // rotation name
}
else if (token=="cull_software")
{
getMaterialToken(file, token); // culling side
}
else if (token=="lighting")
{
getMaterialToken(file, token);
pass.Material.Lighting=(token=="on");
}
else if (token=="shading")
{
getMaterialToken(file, token);
// We take phong as gouraud
pass.Material.GouraudShading=(token!="flat");
}
else if (token=="polygon_mode")
{
getMaterialToken(file, token);
pass.Material.Wireframe=(token=="wireframe");
pass.Material.PointCloud=(token=="points");
}
else if (token=="max_lights")
{
getMaterialToken(file, token);
pass.MaxLights=core::strtoul10(token.c_str());
}
else if (token=="point_size")
{
getMaterialToken(file, token);
pass.PointSize=core::fast_atof(token.c_str());
}
else if (token=="point_sprites")
{
getMaterialToken(file, token);
pass.PointSprites=(token=="on");
}
else if (token=="point_size_min")
{
getMaterialToken(file, token);
pass.PointSizeMin=core::strtoul10(token.c_str());
}
else if (token=="point_size_max")
{
getMaterialToken(file, token);
pass.PointSizeMax=core::strtoul10(token.c_str());
}
else if (token=="texture_unit")
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Texture unit", ELL_DEBUG);
#endif
getMaterialToken(file, token); //open brace
getMaterialToken(file, token);
while(token != "}")
{
if (token=="texture")
{
getMaterialToken(file, token);
pass.Texture.Filename.push_back(token);
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Texture", token, ELL_DEBUG);
#endif
getMaterialToken(file, pass.Texture.CoordsType, true);
getMaterialToken(file, pass.Texture.MipMaps, true);
getMaterialToken(file, pass.Texture.Alpha, true);
// Hmm, we might need more hints for other material types using two textures...
if (textureUnit>0)
pass.Material.MaterialType=video::EMT_LIGHTMAP;
}
else if (token=="filtering")
{
getMaterialToken(file, token);
pass.Material.TextureLayer[textureUnit].AnisotropicFilter=0;
if (token=="point")
{
pass.Material.TextureLayer[textureUnit].BilinearFilter=false;
pass.Material.TextureLayer[textureUnit].TrilinearFilter=false;
getMaterialToken(file, token);
getMaterialToken(file, token);
}
else if (token=="linear")
{
getMaterialToken(file, token);
if (token=="point")
{
pass.Material.TextureLayer[textureUnit].BilinearFilter=false;
pass.Material.TextureLayer[textureUnit].TrilinearFilter=false;
getMaterialToken(file, token);
}
else
{
pass.Material.TextureLayer[textureUnit].BilinearFilter=true;
getMaterialToken(file, token);
pass.Material.TextureLayer[textureUnit].TrilinearFilter=(token=="linear");
}
}
else
{
pass.Material.TextureLayer[textureUnit].BilinearFilter=(token=="bilinear");
pass.Material.TextureLayer[textureUnit].TrilinearFilter=(token=="trilinear");
pass.Material.TextureLayer[textureUnit].AnisotropicFilter=(token=="anisotropic")?2:1;
}
}
else if (token=="max_anisotropy")
{
getMaterialToken(file, token);
pass.Material.TextureLayer[textureUnit].AnisotropicFilter=(u8)core::strtoul10(token.c_str());
}
else if (token=="texture_alias")
{
getMaterialToken(file, pass.Texture.Alias);
}
else if (token=="mipmap_bias")
{
getMaterialToken(file, token);
pass.Material.TextureLayer[textureUnit].LODBias=(s8)core::fast_atof(token.c_str());
}
else if (token=="colour_op")
{ // TODO: Choose correct values
getMaterialToken(file, token);
if (token=="add")
pass.Material.MaterialType=video::EMT_TRANSPARENT_ADD_COLOR;
else if (token=="modulate")
pass.Material.MaterialType=video::EMT_SOLID;
else if (token=="alpha_blend")
pass.Material.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
else if (token=="colour_blend")
pass.Material.MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA;
else
getMaterialToken(file, token);
}
getMaterialToken(file, token);
}
++textureUnit;
}
else if (token=="shadow_caster_program_ref")
{
do
{
getMaterialToken(file, token);
} while (token != "}");
}
else if (token=="shadow_caster_vertex_program_ref")
{
do
{
getMaterialToken(file, token);
} while (token != "}");
}
else if (token=="vertex_program_ref")
{
do
{
getMaterialToken(file, token);
} while (token != "}");
}
//fog_override, iteration, point_size_attenuation
//not considered yet!
getMaterialToken(file, token);
if (token=="{")
++inBlocks;
else if (token=="}")
--inBlocks;
}
}
void COgreMeshFileLoader::readTechnique(io::IReadFile* file, OgreMaterial& mat)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Read Technique");
#endif
core::stringc token;
mat.Techniques.push_back(OgreTechnique());
OgreTechnique& technique=mat.Techniques.getLast();
getMaterialToken(file, technique.Name); //open brace or name
if (technique.Name != "{")
getMaterialToken(file, token); //open brace
else
technique.Name=core::stringc((int)mat.Techniques.size());
getMaterialToken(file, token);
while (token != "}")
{
if (token == "pass")
readPass(file, technique);
else if (token == "scheme")
getMaterialToken(file, token);
else if (token == "lod_index")
getMaterialToken(file, token);
getMaterialToken(file, token);
}
}
void COgreMeshFileLoader::loadMaterials(io::IReadFile* meshFile)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Load Materials", ELL_DEBUG);
#endif
core::stringc token;
io::IReadFile* file = 0;
io::path filename = FileSystem->getFileBasename(meshFile->getFileName(), false) + ".material";
if (FileSystem->existFile(filename))
file = FileSystem->createAndOpenFile(filename);
else
file = FileSystem->createAndOpenFile(FileSystem->getFileDir(meshFile->getFileName())+"/"+filename);
if (!file)
{
os::Printer::log("Could not load OGRE material", filename);
return;
}
getMaterialToken(file, token);
while (file->getPos() < file->getSize())
{
if ((token == "fragment_program") || (token == "vertex_program"))
{
// skip whole block
u32 blocks=1;
do
{
getMaterialToken(file, token);
} while (token != "{");
do
{
getMaterialToken(file, token);
if (token == "{")
++blocks;
else if (token == "}")
--blocks;
} while (blocks);
getMaterialToken(file, token);
continue;
}
if (token != "material")
{
if (token.trim().size())
os::Printer::log("Unknown material group", token.c_str());
break;
}
Materials.push_back(OgreMaterial());
OgreMaterial& mat = Materials.getLast();
getMaterialToken(file, mat.Name);
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Load Material", mat.Name.c_str(), ELL_DEBUG);
#endif
getMaterialToken(file, token); //open brace
getMaterialToken(file, token);
while(token != "}")
{
if (token=="lod_distances") // can have several items
getMaterialToken(file, token);
else if (token=="receive_shadows")
{
getMaterialToken(file, token);
mat.ReceiveShadows=(token=="on");
}
else if (token=="transparency_casts_shadows")
{
getMaterialToken(file, token);
mat.TransparencyCastsShadows=(token=="on");
}
else if (token=="set_texture_alias")
{
getMaterialToken(file, token);
getMaterialToken(file, token);
}
else if (token=="technique")
readTechnique(file, mat);
getMaterialToken(file, token);
}
getMaterialToken(file, token);
}
file->drop();
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Finished loading Materials", ELL_DEBUG);
#endif
}
bool COgreMeshFileLoader::loadSkeleton(io::IReadFile* meshFile, const core::stringc& name)
{
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Load Skeleton", name, ELL_DEBUG);
#endif
io::IReadFile* file = 0;
io::path filename;
if (FileSystem->existFile(name))
file = FileSystem->createAndOpenFile(name);
else if (FileSystem->existFile(filename = FileSystem->getFileDir(meshFile->getFileName())+"/"+name))
file = FileSystem->createAndOpenFile(filename);
else if (FileSystem->existFile(filename = FileSystem->getFileBasename(meshFile->getFileName(), false) + ".skeleton"))
file = FileSystem->createAndOpenFile(filename);
else
file = FileSystem->createAndOpenFile(FileSystem->getFileDir(meshFile->getFileName())+"/"+filename);
if (!file)
{
os::Printer::log("Could not load matching skeleton", name);
return false;
}
s16 id;
file->read(&id, 2);
if (SwapEndian)
id = os::Byteswap::byteswap(id);
if (id != COGRE_HEADER)
{
file->drop();
return false;
}
core::stringc skeletonVersion;
ChunkData head;
readString(file, head, skeletonVersion);
if (skeletonVersion != "[Serializer_v1.10]")
{
file->drop();
return false;
}
u16 bone=0;
f32 animationTotal=0.f;
while(file->getPos() < file->getSize())
{
ChunkData data;
readChunkData(file, data);
switch(data.header.id)
{
case COGRE_SKELETON:
{
Skeleton.Bones.push_back(OgreBone());
OgreBone& bone = Skeleton.Bones.getLast();
readString(file, data, bone.Name);
readShort(file, data, &bone.Handle);
readVector(file, data, bone.Position);
readQuaternion(file, data, bone.Orientation);
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Bone", bone.Name+" ("+core::stringc(bone.Handle)+")", ELL_DEBUG);
os::Printer::log("Position", core::stringc(bone.Position.X)+" "+core::stringc(bone.Position.Y)+" "+core::stringc(bone.Position.Z), ELL_DEBUG);
os::Printer::log("Rotation quat", core::stringc(bone.Orientation.W)+" "+core::stringc(bone.Orientation.X)+" "+core::stringc(bone.Orientation.Y)+" "+core::stringc(bone.Orientation.Z), ELL_DEBUG);
// core::vector3df rot;
// bone.Orientation.toEuler(rot);
// rot *= core::RADTODEG;
// os::Printer::log("Rotation", core::stringc(rot.X)+" "+core::stringc(rot.Y)+" "+core::stringc(rot.Z));
#endif
if (data.read<(data.header.length-bone.Name.size()))
{
readVector(file, data, bone.Scale);
bone.Scale.X *= -1.f;
}
else
bone.Scale=core::vector3df(1,1,1);
bone.Parent=0xffff;
}
break;
case COGRE_BONE_PARENT:
{
u16 parent;
readShort(file, data, &bone);
readShort(file, data, &parent);
if (bone<Skeleton.Bones.size() && parent<Skeleton.Bones.size())
Skeleton.Bones[bone].Parent=parent;
}
break;
case COGRE_ANIMATION:
{
if (Skeleton.Animations.size())
animationTotal+=Skeleton.Animations.getLast().Length;
Skeleton.Animations.push_back(OgreAnimation());
OgreAnimation& anim = Skeleton.Animations.getLast();
readString(file, data, anim.Name);
readFloat(file, data, &anim.Length);
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Animation", anim.Name, ELL_DEBUG);
os::Printer::log("Length", core::stringc(anim.Length), ELL_DEBUG);
#endif
}
break;
case COGRE_ANIMATION_TRACK:
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("for Bone ", core::stringc(bone), ELL_DEBUG);
#endif
readShort(file, data, &bone); // store current bone
break;
case COGRE_ANIMATION_KEYFRAME:
{
Skeleton.Animations.getLast().Keyframes.push_back(OgreKeyframe());
OgreKeyframe& keyframe = Skeleton.Animations.getLast().Keyframes.getLast();
readFloat(file, data, &keyframe.Time);
keyframe.Time+=animationTotal;
readQuaternion(file, data, keyframe.Orientation);
readVector(file, data, keyframe.Position);
if (data.read<data.header.length)
{
readVector(file, data, keyframe.Scale);
keyframe.Scale.X *= -1.f;
}
else
keyframe.Scale=core::vector3df(1,1,1);
keyframe.BoneID=bone;
}
break;
case COGRE_ANIMATION_LINK:
#ifdef IRR_OGRE_LOADER_DEBUG
os::Printer::log("Animation link", ELL_DEBUG);
#endif
break;
default:
break;
}
}
file->drop();
return true;
}
void COgreMeshFileLoader::readChunkData(io::IReadFile* file, ChunkData& data)
{
file->read(&data.header, sizeof(ChunkHeader));
if (SwapEndian)
{
data.header.id = os::Byteswap::byteswap(data.header.id);
data.header.length = os::Byteswap::byteswap(data.header.length);
}
data.read += sizeof(ChunkHeader);
}
void COgreMeshFileLoader::readString(io::IReadFile* file, ChunkData& data, core::stringc& out)
{
c8 c = 0;
out = "";
while (c!='\n')
{
file->read(&c, sizeof(c8));
if (c!='\n')
out.append(c);
}
data.read+=out.size()+1;
}
void COgreMeshFileLoader::readBool(io::IReadFile* file, ChunkData& data, bool& out)
{
// normal C type because we read a bit string
char c = 0;
file->read(&c, sizeof(char));
out=(c!=0);
++data.read;
}
void COgreMeshFileLoader::readInt(io::IReadFile* file, ChunkData& data, s32* out, u32 num)
{
// normal C type because we read a bit string
file->read(out, sizeof(int)*num);
if (SwapEndian)
{
for (u32 i=0; i<num; ++i)
out[i] = os::Byteswap::byteswap(out[i]);
}
data.read+=sizeof(int)*num;
}
void COgreMeshFileLoader::readShort(io::IReadFile* file, ChunkData& data, u16* out, u32 num)
{
// normal C type because we read a bit string
file->read(out, sizeof(short)*num);
if (SwapEndian)
{
for (u32 i=0; i<num; ++i)
out[i] = os::Byteswap::byteswap(out[i]);
}
data.read+=sizeof(short)*num;
}
void COgreMeshFileLoader::readFloat(io::IReadFile* file, ChunkData& data, f32* out, u32 num)
{
// normal C type because we read a bit string
file->read(out, sizeof(float)*num);
if (SwapEndian)
{
for (u32 i=0; i<num; ++i)
out[i] = os::Byteswap::byteswap(out[i]);
}
data.read+=sizeof(float)*num;
}
void COgreMeshFileLoader::readVector(io::IReadFile* file, ChunkData& data, core::vector3df& out)
{
readFloat(file, data, &out.X);
readFloat(file, data, &out.Y);
readFloat(file, data, &out.Z);
out.X *= -1.f;
}
void COgreMeshFileLoader::readQuaternion(io::IReadFile* file, ChunkData& data, core::quaternion& out)
{
readVector(file, data, *((core::vector3df*)&out.X));
readFloat(file, data, &out.W);
}
void COgreMeshFileLoader::clearMeshes()
{
for (u32 i=0; i<Meshes.size(); ++i)
{
for (int k=0; k<(int)Meshes[i].Geometry.Buffers.size(); ++k)
Meshes[i].Geometry.Buffers[k].Data.clear();
for (u32 j=0; j<Meshes[i].SubMeshes.size(); ++j)
{
for (int h=0; h<(int)Meshes[i].SubMeshes[j].Geometry.Buffers.size(); ++h)
Meshes[i].SubMeshes[j].Geometry.Buffers[h].Data.clear();
}
}
Meshes.clear();
}
} // end namespace scene
} // end namespace irr
#endif // _IRR_COMPILE_WITH_OGRE_LOADER_