nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: nuclear@0: /** @file MDLLoader.h nuclear@0: * @brief Declaration of the loader for MDL files nuclear@0: */ nuclear@0: nuclear@0: #ifndef AI_MDLLOADER_H_INCLUDED nuclear@0: #define AI_MDLLOADER_H_INCLUDED nuclear@0: nuclear@0: #include "BaseImporter.h" nuclear@0: nuclear@0: struct aiNode; nuclear@0: #include "MDLFileData.h" nuclear@0: #include "HalfLifeFileData.h" nuclear@0: nuclear@0: namespace Assimp { nuclear@0: nuclear@0: nuclear@0: using namespace MDL; nuclear@0: nuclear@0: // -------------------------------------------------------------------------------------- nuclear@0: // Include file/line information in debug builds nuclear@0: #ifdef ASSIMP_BUILD_DEBUG nuclear@0: # define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__) nuclear@0: #else nuclear@0: # define VALIDATE_FILE_SIZE(msg) SizeCheck(msg) nuclear@0: #endif nuclear@0: nuclear@0: // -------------------------------------------------------------------------------------- nuclear@0: /** @brief Class to load MDL files. nuclear@0: * nuclear@0: * Several subformats exist: nuclear@0: * nuclear@0: * These formats are partially identical and it would be possible to load nuclear@0: * them all with a single 1000-line function-beast. However, it has been nuclear@0: * split into several code paths to make the code easier to read and maintain. nuclear@0: */ nuclear@0: class MDLImporter : public BaseImporter nuclear@0: { nuclear@0: public: nuclear@0: MDLImporter(); nuclear@0: ~MDLImporter(); nuclear@0: nuclear@0: nuclear@0: public: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Returns whether the class can handle the format of the given file. nuclear@0: * See BaseImporter::CanRead() for details. */ nuclear@0: bool CanRead( const std::string& pFile, IOSystem* pIOHandler, nuclear@0: bool checkSig) const; nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Called prior to ReadFile(). nuclear@0: * The function is a request to the importer to update its configuration nuclear@0: * basing on the Importer's configuration property list. nuclear@0: */ nuclear@0: void SetupProperties(const Importer* pImp); nuclear@0: nuclear@0: protected: nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Return importer meta information. nuclear@0: * See #BaseImporter::GetInfo for the details nuclear@0: */ nuclear@0: const aiImporterDesc* GetInfo () const; nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Imports the given file into the given scene structure. nuclear@0: * See BaseImporter::InternReadFile() for details nuclear@0: */ nuclear@0: void InternReadFile( const std::string& pFile, aiScene* pScene, nuclear@0: IOSystem* pIOHandler); nuclear@0: nuclear@0: protected: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Import a quake 1 MDL file (IDPO) nuclear@0: */ nuclear@0: void InternReadFile_Quake1( ); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Import a GameStudio A4/A5 file (MDL 3,4,5) nuclear@0: */ nuclear@0: void InternReadFile_3DGS_MDL345( ); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Import a GameStudio A7 file (MDL 7) nuclear@0: */ nuclear@0: void InternReadFile_3DGS_MDL7( ); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Import a CS:S/HL2 MDL file (not fully implemented) nuclear@0: */ nuclear@0: void InternReadFile_HL2( ); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Check whether a given position is inside the valid range nuclear@0: * Throw a DeadlyImportError if it is not nuclear@0: * \param szPos Cursor position nuclear@0: * \param szFile Name of the source file from which the function was called nuclear@0: * \param iLine Source code line from which the function was called nuclear@0: */ nuclear@0: void SizeCheck(const void* szPos); nuclear@0: void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine); nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Validate the header data structure of a game studio MDL7 file nuclear@0: * \param pcHeader Input header to be validated nuclear@0: */ nuclear@0: void ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7* pcHeader); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Validate the header data structure of a Quake 1 model nuclear@0: * \param pcHeader Input header to be validated nuclear@0: */ nuclear@0: void ValidateHeader_Quake1(const MDL::Header* pcHeader); nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Try to load a palette from the current directory (colormap.lmp) nuclear@0: * If it is not found the default palette of Quake1 is returned nuclear@0: */ nuclear@0: void SearchPalette(const unsigned char** pszColorMap); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Free a palette created with a previous call to SearchPalette() nuclear@0: */ nuclear@0: void FreePalette(const unsigned char* pszColorMap); nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Load a paletized texture from the file and convert it to 32bpp nuclear@0: */ nuclear@0: void CreateTextureARGB8_3DGS_MDL3(const unsigned char* szData); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Used to load textures from MDL3/4 nuclear@0: * \param szData Input data nuclear@0: * \param iType Color data type nuclear@0: * \param piSkip Receive: Size to skip, in bytes nuclear@0: */ nuclear@0: void CreateTexture_3DGS_MDL4(const unsigned char* szData, nuclear@0: unsigned int iType, nuclear@0: unsigned int* piSkip); nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Used to load textures from MDL5 nuclear@0: * \param szData Input data nuclear@0: * \param iType Color data type nuclear@0: * \param piSkip Receive: Size to skip, in bytes nuclear@0: */ nuclear@0: void CreateTexture_3DGS_MDL5(const unsigned char* szData, nuclear@0: unsigned int iType, nuclear@0: unsigned int* piSkip); nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Checks whether a texture can be replaced with a single color nuclear@0: * This is useful for all file formats before MDL7 (all those nuclear@0: * that are not containing material colors separate from textures). nuclear@0: * MED seems to write dummy 8x8 monochrome images instead. nuclear@0: * \param pcTexture Input texture nuclear@0: * \return aiColor.r is set to qnan if the function fails and no nuclear@0: * color can be found. nuclear@0: */ nuclear@0: aiColor4D ReplaceTextureWithColor(const aiTexture* pcTexture); nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Converts the absolute texture coordinates in MDL5 files to nuclear@0: * relative in a range between 0 and 1 nuclear@0: */ nuclear@0: void CalculateUVCoordinates_MDL5(); nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Read an UV coordinate from the file. If the file format is not nuclear@0: * MDL5, the function calculates relative texture coordinates nuclear@0: * \param vOut Receives the output UV coord nuclear@0: * \param pcSrc UV coordinate buffer nuclear@0: * \param UV coordinate index nuclear@0: */ nuclear@0: void ImportUVCoordinate_3DGS_MDL345( aiVector3D& vOut, nuclear@0: const MDL::TexCoord_MDL3* pcSrc, nuclear@0: unsigned int iIndex); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Setup the material properties for Quake and MDL<7 models. nuclear@0: * These formats don't support more than one material per mesh, nuclear@0: * therefore the method processes only ONE skin and removes nuclear@0: * all others. nuclear@0: */ nuclear@0: void SetupMaterialProperties_3DGS_MDL5_Quake1( ); nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Parse a skin lump in a MDL7/HMP7 file with all of its features nuclear@0: * variant 1: Current cursor position is the beginning of the skin header nuclear@0: * \param szCurrent Current data pointer nuclear@0: * \param szCurrentOut Output data pointer nuclear@0: * \param pcMats Material list for this group. To be filled ... nuclear@0: */ nuclear@0: void ParseSkinLump_3DGS_MDL7( nuclear@0: const unsigned char* szCurrent, nuclear@0: const unsigned char** szCurrentOut, nuclear@0: std::vector& pcMats); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Parse a skin lump in a MDL7/HMP7 file with all of its features nuclear@0: * variant 2: Current cursor position is the beginning of the skin data nuclear@0: * \param szCurrent Current data pointer nuclear@0: * \param szCurrentOut Output data pointer nuclear@0: * \param pcMatOut Output material nuclear@0: * \param iType header.typ nuclear@0: * \param iWidth header.width nuclear@0: * \param iHeight header.height nuclear@0: */ nuclear@0: void ParseSkinLump_3DGS_MDL7( nuclear@0: const unsigned char* szCurrent, nuclear@0: const unsigned char** szCurrentOut, nuclear@0: aiMaterial* pcMatOut, nuclear@0: unsigned int iType, nuclear@0: unsigned int iWidth, nuclear@0: unsigned int iHeight); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Skip a skin lump in a MDL7/HMP7 file nuclear@0: * \param szCurrent Current data pointer nuclear@0: * \param szCurrentOut Output data pointer. Points to the byte just nuclear@0: * behind the last byte of the skin. nuclear@0: * \param iType header.typ nuclear@0: * \param iWidth header.width nuclear@0: * \param iHeight header.height nuclear@0: */ nuclear@0: void SkipSkinLump_3DGS_MDL7(const unsigned char* szCurrent, nuclear@0: const unsigned char** szCurrentOut, nuclear@0: unsigned int iType, nuclear@0: unsigned int iWidth, nuclear@0: unsigned int iHeight); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Parse texture color data for MDL5, MDL6 and MDL7 formats nuclear@0: * \param szData Current data pointer nuclear@0: * \param iType type of the texture data. No DDS or external nuclear@0: * \param piSkip Receive the number of bytes to skip nuclear@0: * \param pcNew Must point to fully initialized data. Width and nuclear@0: * height must be set. If pcNew->pcData is set to UINT_MAX, nuclear@0: * piSkip will receive the size of the texture, in bytes, but no nuclear@0: * color data will be read. nuclear@0: */ nuclear@0: void ParseTextureColorData(const unsigned char* szData, nuclear@0: unsigned int iType, nuclear@0: unsigned int* piSkip, nuclear@0: aiTexture* pcNew); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Join two materials / skins. Setup UV source ... etc nuclear@0: * \param pcMat1 First input material nuclear@0: * \param pcMat2 Second input material nuclear@0: * \param pcMatOut Output material instance to be filled. Must be empty nuclear@0: */ nuclear@0: void JoinSkins_3DGS_MDL7(aiMaterial* pcMat1, nuclear@0: aiMaterial* pcMat2, nuclear@0: aiMaterial* pcMatOut); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Add a bone transformation key to an animation nuclear@0: * \param iTrafo Index of the transformation (always==frame index?) nuclear@0: * No need to validate this index, it is always valid. nuclear@0: * \param pcBoneTransforms Bone transformation for this index nuclear@0: * \param apcOutBones Output bones array nuclear@0: */ nuclear@0: void AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo, nuclear@0: const MDL::BoneTransform_MDL7* pcBoneTransforms, nuclear@0: MDL::IntBone_MDL7** apcBonesOut); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Load the bone list of a MDL7 file nuclear@0: * \return If the bones could be loaded successfully, a valid nuclear@0: * array containing pointers to a temporary bone nuclear@0: * representation. NULL if the bones could not be loaded. nuclear@0: */ nuclear@0: MDL::IntBone_MDL7** LoadBones_3DGS_MDL7(); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Load bone transformation keyframes from a file chunk nuclear@0: * \param groupInfo -> doc of data structure nuclear@0: * \param frame -> doc of data structure nuclear@0: * \param shared -> doc of data structure nuclear@0: */ nuclear@0: void ParseBoneTrafoKeys_3DGS_MDL7( nuclear@0: const MDL::IntGroupInfo_MDL7& groupInfo, nuclear@0: IntFrameInfo_MDL7& frame, nuclear@0: MDL::IntSharedData_MDL7& shared); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Calculate absolute bone animation matrices for each bone nuclear@0: * \param apcOutBones Output bones array nuclear@0: */ nuclear@0: void CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Add all bones to the nodegraph (as children of the root node) nuclear@0: * \param apcBonesOut List of bones nuclear@0: * \param pcParent Parent node. New nodes will be added to this node nuclear@0: * \param iParentIndex Index of the parent bone nuclear@0: */ nuclear@0: void AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7** apcBonesOut, nuclear@0: aiNode* pcParent,uint16_t iParentIndex); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Build output animations nuclear@0: * \param apcBonesOut List of bones nuclear@0: */ nuclear@0: void BuildOutputAnims_3DGS_MDL7(const MDL::IntBone_MDL7** apcBonesOut); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Handles materials that are just referencing another material nuclear@0: * There is no test file for this feature, but Conitec's doc nuclear@0: * say it is used. nuclear@0: */ nuclear@0: void HandleMaterialReferences_3DGS_MDL7(); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Copies only the material that are referenced by at least one nuclear@0: * mesh to the final output material list. All other materials nuclear@0: * will be discarded. nuclear@0: * \param shared -> doc of data structure nuclear@0: */ nuclear@0: void CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Process the frame section at the end of a group nuclear@0: * \param groupInfo -> doc of data structure nuclear@0: * \param shared -> doc of data structure nuclear@0: * \param szCurrent Pointer to the start of the frame section nuclear@0: * \param szCurrentOut Receives a pointer to the first byte of the nuclear@0: * next data section. nuclear@0: * \return false to read no further groups (a small workaround for nuclear@0: * some tiny and unsolved problems ... ) nuclear@0: */ nuclear@0: bool ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo, nuclear@0: MDL::IntGroupData_MDL7& groupData, nuclear@0: MDL::IntSharedData_MDL7& shared, nuclear@0: const unsigned char* szCurrent, nuclear@0: const unsigned char** szCurrentOut); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Sort all faces by their materials. If the mesh is using nuclear@0: * multiple materials per face (that are blended together) the function nuclear@0: * might create new materials. nuclear@0: * \param groupInfo -> doc of data structure nuclear@0: * \param groupData -> doc of data structure nuclear@0: * \param splitGroupData -> doc of data structure nuclear@0: */ nuclear@0: void SortByMaterials_3DGS_MDL7( nuclear@0: const MDL::IntGroupInfo_MDL7& groupInfo, nuclear@0: MDL::IntGroupData_MDL7& groupData, nuclear@0: MDL::IntSplitGroupData_MDL7& splitGroupData); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Read all faces and vertices from a MDL7 group. The function fills nuclear@0: * preallocated memory buffers. nuclear@0: * \param groupInfo -> doc of data structure nuclear@0: * \param groupData -> doc of data structure nuclear@0: */ nuclear@0: void ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo, nuclear@0: MDL::IntGroupData_MDL7& groupData); nuclear@0: nuclear@0: // ------------------------------------------------------------------- nuclear@0: /** Generate the final output meshes for a7 models nuclear@0: * \param groupData -> doc of data structure nuclear@0: * \param splitGroupData -> doc of data structure nuclear@0: */ nuclear@0: void GenerateOutputMeshes_3DGS_MDL7( nuclear@0: MDL::IntGroupData_MDL7& groupData, nuclear@0: MDL::IntSplitGroupData_MDL7& splitGroupData); nuclear@0: nuclear@0: protected: nuclear@0: nuclear@0: /** Configuration option: frame to be loaded */ nuclear@0: unsigned int configFrameID; nuclear@0: nuclear@0: /** Configuration option: palette to be used to decode palletized images*/ nuclear@0: std::string configPalette; nuclear@0: nuclear@0: /** Buffer to hold the loaded file */ nuclear@0: unsigned char* mBuffer; nuclear@0: nuclear@0: /** For GameStudio MDL files: The number in the magic word, either 3,4 or 5 nuclear@0: * (MDL7 doesn't need this, the format has a separate loader) */ nuclear@0: unsigned int iGSFileVersion; nuclear@0: nuclear@0: /** Output I/O handler. used to load external lmp files */ nuclear@0: IOSystem* pIOHandler; nuclear@0: nuclear@0: /** Output scene to be filled */ nuclear@0: aiScene* pScene; nuclear@0: nuclear@0: /** Size of the input file in bytes */ nuclear@0: unsigned int iFileSize; nuclear@0: }; nuclear@0: nuclear@0: } // end of namespace Assimp nuclear@0: nuclear@0: #endif // AI_3DSIMPORTER_H_INC