// 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 & 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 FaceIndices; // index of material for each face core::array 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 Vertices; core::array< s32 > Indices; // triangle indices // optional: core::array TextureCoords; core::array Normals; core::array 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 Meshes; core::array 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 Keys; // optional, from AnimationOptions: bool closed; // default true bool linearPositionQuality; // if false: spline position quality }; struct SXAnimationSet { core::stringc AnimationName; core::array 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& normals, core::array< s32 >& normalIndices, s32 triangulatedIndexCount, core::array< s32 >& indexCountPerFace); bool parseDataObjectMeshTextureCoords(core::array& textureCoords); bool parseDataObjectMeshVertexColors(core::array& 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::arrayRootFrames; core::array AnimationSets; core::array TemplateMaterials; }; } // end namespace scene } // end namespace irr #endif