irrlicht/source/Irrlicht/CXFileReader.h

311 lines
8.1 KiB
C++

// 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_X_FILE_READER_H_INCLUDED__
#define __C_X_FILE_READER_H_INCLUDED__
#include "IReadFile.h"
#include "irrString.h"
#include "matrix4.h"
#include "SColor.h"
#include "irrArray.h"
#include "vector2d.h"
#include "quaternion.h"
//#define _XREADER_DEBUG
namespace irr
{
namespace scene
{
//! This is a .x file reader. It only reads data from uncompressed .x files.
class CXFileReader : public virtual IUnknown
{
public:
struct SXAnimationSet;
struct SXFrame;
CXFileReader(io::IReadFile* file);
~CXFileReader();
//! Returns an error occured during reading the file
bool errorHappened() const;
//! Returns if the loaded mesh is static
bool isStaticMesh() const;
//! returns count of animations
s32 getAnimationSetCount() const;
//! returns a specific animation set
SXAnimationSet& getAnimationSet(s32 i);
//! returns array of root frames
core::array<SXFrame> & getRootFrames();
struct SXMaterial
{
video::SColorf FaceColor; // note: RGBA
f32 Power;
video::SColorf Specular; // RGB
video::SColorf Emissive; // RGB
core::stringc TextureFileName;
};
struct SXMeshMaterialList
{
core::array<s32> FaceIndices; // index of material for each face
core::array<SXMaterial> Materials; // material array
};
struct SXTemplateMaterial
{
core::stringc Name; // template name from Xfile
SXMaterial Material; // material
};
struct SXIndexedColor
{
s32 Index;
video::SColorf Color;
};
struct SXSkinMeshHeader
{
s32 MaxSkinWeightsPerVertex; // Maximum number of transforms that affect a vertex in the mesh.
s32 MaxSkinWeightsPerFace; // Maximum number of unique transforms that affect the three vertices of any face.
s32 BoneCount; // Number of bones that affect vertices in this mesh.
};
struct SXWeight
{
SXWeight() {};
SXWeight(s32 vtidx): VertexIndex(vtidx) {}
s32 VertexIndex;
f32 Weight;
bool operator <(const SXWeight& other) const
{
return VertexIndex < other.VertexIndex;
}
};
struct SXSkinWeight
{
core::stringc TransformNodeName; // name of the bone
core::array< SXWeight > Weights;
core::matrix4 MatrixOffset; // 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
};
struct SXMesh
{
// this mesh contains triangulated texture data.
// because in an .x file, faces can be made of more than 3
// vertices, the indices data structure is triangulated during the
// loading process. The IndexCountPerFace array is filled during
// this triangulation process and stores how much indices belong to
// every face. This data structure can be ignored, because all data
// in this structure is triangulated.
core::stringc Name;
core::array<core::vector3df> Vertices;
core::array< s32 > Indices; // triangle indices
// optional:
core::array<core::vector2df> TextureCoords;
core::array<core::vector3df> Normals;
core::array<s32> NormalIndices; // amount is equal to Indices amount
core::array< s32 > IndexCountPerFace; // default 3, but could be more
core::array< SXIndexedColor > VertexColors;
core::array< SXSkinWeight > SkinWeights;
SXMeshMaterialList MaterialList;
SXSkinMeshHeader SkinMeshHeader;
};
struct SXFrame
{
SXFrame() : iLevel(0), pParent(0) { }
int iLevel;
SXFrame * pParent;
core::stringc Name;
core::matrix4 LocalMatrix;
core::matrix4 GlobalMatrix;
core::array<SXMesh> Meshes;
core::array<SXFrame> ChildFrames;
};
struct SXAnimationKey
{
SXAnimationKey() : keyType(-1), numberOfKeys(0), time(0), data(0) { }
void del()
{
delete [] time;
switch(keyType)
{
case -1: break;
case 0 : delete [] (core::quaternion*)data; break;
case 1 :
case 2 : delete [] (core::vector3df*)data; break;
case 3 :
case 4 : delete [] (core::matrix4*)data; break;
}
}
void init()
{
time = new s32[numberOfKeys];
switch(keyType)
{
case 0 : data = new core::quaternion[numberOfKeys]; break;
case 1 :
case 2 : data = new core::vector3df[numberOfKeys]; break;
case 3 :
case 4 : data = new core::matrix4[numberOfKeys]; break;
}
}
core::matrix4& getMatrix(s32 nr) const
{
return ((core::matrix4*)data)[nr];
}
core::vector3df& getVector(s32 nr) const
{
return ((core::vector3df*)data)[nr];
}
core::quaternion& getQuaternion(s32 nr) const
{
return ((core::quaternion*)data)[nr];
}
s32 keyType; // 0=rotation, 1=scale, 2=position, 3=matrix
s32 numberOfKeys;
s32* time;
void* data;
};
struct SXAnimation
{
core::stringc FrameName;
core::array<SXAnimationKey> Keys;
// optional, from AnimationOptions:
bool closed; // default true
bool linearPositionQuality; // if false: spline position quality
};
struct SXAnimationSet
{
core::stringc AnimationName;
core::array<SXAnimation> Animations;
};
private:
//! Parses the file
bool parseFile();
//! Reads file into memory
bool readFileIntoMemory(io::IReadFile* file);
//! Parses the next Data object in the file
bool parseDataObject();
//! places pointer to next begin of a token, and ignores comments
void findNextNoneWhiteSpace();
//! places pointer to next begin of a token, which must be a number,
// and ignores comments
void findNextNoneWhiteSpaceNumber();
//! returns next parseable token. Returns empty string if no token there
core::stringc getNextToken();
//! reads header of dataobject including the opening brace.
//! returns false if error happened, and writes name of object
//! if there is one
bool readHeadOfDataObject(core::stringc* outname=0);
//! checks for two following semicolons, returns false if they are not there
bool checkForTwoFollowingSemicolons();
//! reads a x file style string
bool getNextTokenAsString(core::stringc& out);
inline u16 readBinWord();
inline u32 readBinDWord();
inline s32 readInt();
inline f32 readFloat();
inline bool readVector2(core::vector2df& vec);
inline bool readVector3(core::vector3df& vec);
inline bool readRGB(video::SColorf& color);
inline bool readRGBA(video::SColorf& color);
bool parseDataObjectTemplate();
bool parseDataObjectFrame(SXFrame &frame);
bool parseDataObjectTransformationMatrix(core::matrix4 &mat);
bool parseDataObjectMesh(SXMesh &mesh);
bool parseDataObjectMeshNormals(core::array<core::vector3df>& normals,
core::array< s32 >& normalIndices, s32 triangulatedIndexCount,
core::array< s32 >& indexCountPerFace);
bool parseDataObjectMeshTextureCoords(core::array<core::vector2df>& textureCoords);
bool parseDataObjectMeshVertexColors(core::array<SXIndexedColor>& vertexColors);
bool parseDataObjectMeshMaterialList(SXMeshMaterialList& materiallist,
s32 triangulatedIndexCount, core::array< s32 >& indexCountPerFace);
bool parseDataObjectMaterial(SXMaterial& material);
bool parseDataObjectTextureFilename(core::stringc& texturename);
bool parseDataObjectSkinMeshHeader(SXSkinMeshHeader& header);
bool parseDataObjectSkinWeights(SXSkinWeight& weights);
bool parseDataObjectAnimationSet(SXAnimationSet& set);
bool parseDataObjectAnimation(SXAnimation& anim);
bool parseDataObjectAnimationKey(SXAnimationKey& animkey);
bool parseUnknownDataObject();
void readUntilEndOfLine();
void computeGlobalFrameMatrices(SXFrame& frame, const SXFrame* const parent);
void optimizeFrames( SXFrame * pgFrame, SXFrame * pgParent );
bool validateMesh(SXFrame* frame);
s32 MajorVersion;
s32 MinorVersion;
bool binary;
s32 binaryNumCount;
c8* Buffer;
s32 Size;
c8 FloatSize;
const c8* P;
c8* End;
bool ErrorHappened;
bool m_bFrameRemoved;
SXFrame * m_pgCurFrame;
core::array<SXFrame>RootFrames;
core::array<SXAnimationSet> AnimationSets;
core::array<SXTemplateMaterial> TemplateMaterials;
};
} // end namespace scene
} // end namespace irr
#endif