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: * - Quake I
nuclear@0: * - 3D Game Studio MDL3, MDL4
nuclear@0: * - 3D Game Studio MDL5
nuclear@0: * - 3D Game Studio MDL7
nuclear@0: * - Halflife 2
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