// 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 #ifndef __C_COLLADA_MESH_FILE_LOADER_H_INCLUDED__ #define __C_COLLADA_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" #include "irrMap.h" #include "CAttributes.h" namespace irr { namespace scene { #ifdef _DEBUG //#define COLLADA_READER_DEBUG #endif class IColladaPrefab; enum ECOLLADA_PARAM_NAME { ECPN_COLOR = 0, ECPN_AMBIENT, ECPN_DIFFUSE, ECPN_SPECULAR, ECPN_SHININESS, ECPN_TRANSPARENCY, ECPN_YFOV, ECPN_ZNEAR, ECPN_ZFAR, ECPN_COUNT }; enum ECOLLADA_PARAM_TYPE { ECPT_FLOAT = 0, ECPT_FLOAT2, ECPT_FLOAT3, ECPT_FLOAT4, ECPT_COUNT }; //! Collada Parameter struct SColladaParam { SColladaParam() : Name(ECPN_COUNT), Type(ECPT_COUNT) { for (int i=0; i<4; ++i) Floats[i] = 0; } ECOLLADA_PARAM_NAME Name; ECOLLADA_PARAM_TYPE Type; f32 Floats[4]; }; enum ECOLLADA_INPUT_SEMANTIC { ECIS_POSITION = 0, ECIS_VERTEX, ECIS_NORMAL, ECIS_TEXCOORD, ECIS_UV, ECIS_TANGENT, ECIS_IMAGE, ECIS_TEXTURE, ECIS_COLOR, ECIS_COUNT }; //! Collada Input struct SColladaInput { SColladaInput() : Semantic(ECIS_COUNT), Data(0), Offset(0), Set(0), Stride(1) { } ECOLLADA_INPUT_SEMANTIC Semantic; core::stringc Source; f32* Data; u32 Offset; u32 Set; u32 Stride; }; //! Collada images struct SColladaImage { core::stringc Id; core::stringc Source; core::dimension2du Dimension; bool SourceIsFilename; }; //! Collada texture struct SColladaTexture { video::ITexture* Texture; core::stringc Id; }; //! Collada material struct SColladaMaterial { video::SMaterial Mat; core::stringc Id; core::stringc InstanceEffectId; f32 Transparency; inline bool operator< (const SColladaMaterial & other) const { return Id < other.Id; } }; //! Collada effect (materials, shaders, and programs) struct SColladaEffect { core::stringc Id; f32 Transparency; core::array Textures; video::SMaterial Mat; // TODO: Parameters looks somewhat lazy workaround, I think we should really read all parameters correct. io::IAttributes * Parameters; inline bool operator< (const SColladaEffect & other) const { return Id < other.Id; } }; struct SNumberArray // for storing float and int arrays { core::stringc Name; core::array Data; }; struct SAccessor { SAccessor() : Count(0), Offset(0), Stride(1) {} // I don't store the source of the accessor here because I assume // it to use the array of the source this accessor is located in. int Count; int Offset; int Stride; core::array Parameters; // parameters defining the accessor }; struct SSource { core::stringc Id; SNumberArray Array; core::array Accessors; }; class CScenePrefab; //! Meshloader capable of loading COLLADA meshes and scene descriptions into Irrlicht. class CColladaFileLoader : public IMeshLoader { public: //! Constructor CColladaFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs); //! destructor virtual ~CColladaFileLoader(); //! 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 io::path& filename) const IRR_OVERRIDE; //! 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(io::IReadFile* file) IRR_OVERRIDE; private: //! skips an (unknown) section in the collada document void skipSection(io::IXMLReaderUTF8* reader, bool reportSkipping); //! reads the section and its content void readColladaSection(io::IXMLReaderUTF8* reader); //! reads a section and its content void readLibrarySection(io::IXMLReaderUTF8* reader); //! reads a element and stores it as a prefab void readVisualScene(io::IXMLReaderUTF8* reader); //! reads a section and its content void readSceneSection(io::IXMLReaderUTF8* reader); //! reads a section and its content void readAssetSection(io::IXMLReaderUTF8* reader); //! reads a section and its content //! if a prefab pointer is passed the nodes are created as scene prefabs children of that prefab void readNodeSection(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, CScenePrefab* p=0); //! reads a element and its content and creates a matrix from it core::matrix4 readLookAtNode(io::IXMLReaderUTF8* reader); //! reads a element and its content and creates a matrix from it core::matrix4 readMatrixNode(io::IXMLReaderUTF8* reader); //! reads a element and its content and creates a matrix from it core::matrix4 readPerspectiveNode(io::IXMLReaderUTF8* reader); //! reads a element and its content and creates a matrix from it core::matrix4 readRotateNode(io::IXMLReaderUTF8* reader); //! reads a element and its content and creates a matrix from it core::matrix4 readSkewNode(io::IXMLReaderUTF8* reader); //! reads a element and its content and stores it in bbox void readBboxNode(io::IXMLReaderUTF8* reader, core::aabbox3df& bbox); //! reads a element and its content and creates a matrix from it core::matrix4 readScaleNode(io::IXMLReaderUTF8* reader); //! reads a element and its content and creates a matrix from it core::matrix4 readTranslateNode(io::IXMLReaderUTF8* reader); //! reads a element video::SColorf readColorNode(io::IXMLReaderUTF8* reader); //! reads a element f32 readFloatNode(io::IXMLReaderUTF8* reader); //! reads a node void readInstanceNode(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, scene::ISceneNode** outNode, CScenePrefab* p=0, const core::stringc& type=core::stringc()); //! creates a scene node from Prefabs (with name given in 'url') void instantiateNode(scene::ISceneNode* parent, scene::ISceneNode** outNode=0, CScenePrefab* p=0, const core::stringc& url="", const core::stringc& type=core::stringc()); //! reads a element and stores it as prefab void readLightPrefab(io::IXMLReaderUTF8* reader); //! reads a element and stores it as prefab void readCameraPrefab(io::IXMLReaderUTF8* reader); //! reads a element and stores it in the image section void readImage(io::IXMLReaderUTF8* reader); //! reads a element and stores it in the texture section void readTexture(io::IXMLReaderUTF8* reader); //! reads a element and stores it in the material section void readMaterial(io::IXMLReaderUTF8* reader); //! reads a element and stores it in the effects section void readEffect(io::IXMLReaderUTF8* reader, SColladaEffect * effect = 0); //! reads a element and stores it as mesh if possible void readGeometry(io::IXMLReaderUTF8* 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); //! reads floats from inside of xml element until end of xml element void readFloatsInsideElement(io::IXMLReaderUTF8* reader, f32* floats, u32 count); //! reads ints from inside of xml element until end of xml element void readIntsInsideElement(io::IXMLReaderUTF8* reader, s32* ints, u32 count); //! clears all loaded data void clearData(); //! parses all collada parameters inside an element and stores them in ColladaParameters void readColladaParameters(io::IXMLReaderUTF8* reader, const core::stringc& parentName); //! returns a collada parameter or none if not found SColladaParam* getColladaParameter(ECOLLADA_PARAM_NAME name); //! parses all collada inputs inside an element and stores them in Inputs. Reads //! until first tag which is not an input tag or the end of the parent is reached void readColladaInputs(io::IXMLReaderUTF8* reader, const core::stringc& parentName); //! reads a collada input tag and adds it to the input parameter void readColladaInput(io::IXMLReaderUTF8* reader, core::array& inputs); //! returns a collada input or none if not found SColladaInput* getColladaInput(ECOLLADA_INPUT_SEMANTIC input); //! read Collada Id, uses id or name if id is missing core::stringc readId(io::IXMLReaderUTF8* reader); //! changes the XML URI into an internal id void uriToId(core::stringc& str); //! reads a polygons section and creates a mesh from it void readPolygonSection(io::IXMLReaderUTF8* reader, core::array& sources, scene::SMesh* mesh, const core::stringc& geometryId); //! finds a material, possible instancing it const SColladaMaterial * findMaterial(const core::stringc & materialName); //! reads and bind materials as given by the symbol->target bind mapping void readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id); //! create an Irrlicht texture from the SColladaImage video::ITexture* getTextureFromImage(core::stringc uri, SColladaEffect * effect); //! read a parameter and value void readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters); //! Flip z axis in matrix around to convert between right-handed and left-handed coordinate system. //! Note that function is symmetric (no difference if called before or after a transpose). core::matrix4 flipZAxis(const core::matrix4& m); //! replace escape characters with the unescaped ones void unescape(irr::core::stringc& uri); scene::ISceneManager* SceneManager; io::IFileSystem* FileSystem; scene::IAnimatedMesh* DummyMesh; core::stringc CurrentlyLoadingMesh; scene::IAnimatedMesh* FirstLoadedMesh; io::path FirstLoadedMeshName; s32 LoadedMeshCount; u32 Version; bool FlipAxis; core::array Prefabs; core::array ColladaParameters; core::array Images; core::array Textures; core::array Materials; core::array Inputs; core::array Effects; //! meshbuffer reference ("geomid/matname") -> index into MeshesToBind core::map MaterialsToBind; //! Array of buffers for each material binding core::array< core::array > MeshesToBind; bool CreateInstances; struct EscapeCharacterURL { EscapeCharacterURL(irr::c8 c, const irr::c8* e) : Character(c) { Escape = e; } irr::c8 Character; // unescaped (like ' ') irr::core::stringc Escape; // escaped (like '%20') }; irr::core::array EscapeCharsAnyURI; }; //! following class is for holding and createing instances of library objects, //! named prefabs in this loader. class IColladaPrefab : public virtual IReferenceCounted { public: //! creates an instance of this prefab virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, scene::ISceneManager* mgr) = 0; //! returns id of this prefab virtual const core::stringc& getId() = 0; }; } // end namespace scene } // end namespace irr #endif