diff options
author | sanine <sanine.not@pm.me> | 2023-02-12 23:53:22 -0600 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2023-02-12 23:53:22 -0600 |
commit | f1fe73d1909a2448a004a88362a1a532d0d4f7c3 (patch) | |
tree | ab37ae3837e2f858de2932bcee9f26e69fab3db1 /libs/assimp/code/AssetLib/MDL | |
parent | f567ea1e2798fd3156a416e61f083ea3e6b95719 (diff) |
switch to tinyobj and nanovg from assimp and cairo
Diffstat (limited to 'libs/assimp/code/AssetLib/MDL')
15 files changed, 0 insertions, 7152 deletions
diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1FileData.h b/libs/assimp/code/AssetLib/MDL/HalfLife/HL1FileData.h deleted file mode 100644 index 28b1b28..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1FileData.h +++ /dev/null @@ -1,600 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file HL1FileData.h - * @brief Definition of in-memory structures for the - * Half-Life 1 MDL file format. - */ - -#ifndef AI_HL1FILEDATA_INCLUDED -#define AI_HL1FILEDATA_INCLUDED - -#include "HalfLifeMDLBaseHeader.h" - -#include <assimp/Compiler/pushpack1.h> -#include <assimp/types.h> - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -using vec3_t = float[3]; - -/** \struct Header_HL1 - * \brief Data structure for the HL1 MDL file header. - */ -struct Header_HL1 : HalfLifeMDLBaseHeader { - //! The model name. - char name[64]; - - //! The total file size in bytes. - int32_t length; - - //! Ideal eye position. - vec3_t eyeposition; - - //! Ideal movement hull size. - vec3_t min; - vec3_t max; - - //! Clipping bounding box. - vec3_t bbmin; - vec3_t bbmax; - - //! Was "flags". - int32_t unused; - - //! The number of bones. - int32_t numbones; - - //! Offset to the first bone chunk. - int32_t boneindex; - - //! The number of bone controllers. - int32_t numbonecontrollers; - - //! Offset to the first bone controller chunk. - int32_t bonecontrollerindex; - - //! The number of hitboxes. - int32_t numhitboxes; - - //! Offset to the first hitbox chunk. - int32_t hitboxindex; - - //! The number of sequences. - int32_t numseq; - - //! Offset to the first sequence description chunk. - int32_t seqindex; - - //! The number of sequence groups. - int32_t numseqgroups; - - //! Offset to the first sequence group chunk. - int32_t seqgroupindex; - - //! The number of textures. - int32_t numtextures; - - //! Offset to the first texture chunk. - int32_t textureindex; - - //! Offset to the first texture's image data. - int32_t texturedataindex; - - //! The number of replaceable textures. - int32_t numskinref; - - //! The number of skin families. - int32_t numskinfamilies; - - //! Offset to the first replaceable texture. - int32_t skinindex; - - //! The number of bodyparts. - int32_t numbodyparts; - - //! Offset the the first bodypart. - int32_t bodypartindex; - - //! The number of attachments. - int32_t numattachments; - - //! Offset the the first attachment chunk. - int32_t attachmentindex; - - //! Was "soundtable". - int32_t unused2; - - //! Was "soundindex". - int32_t unused3; - - //! Was "soundgroups". - int32_t unused4; - - //! Was "soundgroupindex". - int32_t unused5; - - //! The number of nodes in the sequence transition graph. - int32_t numtransitions; - - //! Offset the the first sequence transition. - int32_t transitionindex; -} PACK_STRUCT; - -/** \struct SequenceHeader_HL1 - * \brief Data structure for the file header of a demand loaded - * HL1 MDL sequence group file. - */ -struct SequenceHeader_HL1 : HalfLifeMDLBaseHeader { - //! The sequence group file name. - char name[64]; - - //! The total file size in bytes. - int32_t length; -} PACK_STRUCT; - -/** \struct Bone_HL1 - * \brief Data structure for a bone in HL1 MDL files. - */ -struct Bone_HL1 { - //! The bone name. - char name[32]; - - //! The parent bone index. (-1) If it has no parent. - int32_t parent; - - //! Was "flags". - int32_t unused; - - //! Available bone controller per motion type. - //! (-1) if no controller is available. - int32_t bonecontroller[6]; - - /*! Default position and rotation values where - * scale[0] = position.X - * scale[1] = position.Y - * scale[2] = position.Z - * scale[3] = rotation.X - * scale[4] = rotation.Y - * scale[5] = rotation.Z - */ - float value[6]; - - /*! Compressed scale values where - * scale[0] = position.X scale - * scale[1] = position.Y scale - * scale[2] = position.Z scale - * scale[3] = rotation.X scale - * scale[4] = rotation.Y scale - * scale[5] = rotation.Z scale - */ - float scale[6]; -} PACK_STRUCT; - -/** \struct BoneController_HL1 - * \brief Data structure for a bone controller in HL1 MDL files. - */ -struct BoneController_HL1 { - //! Bone affected by this controller. - int32_t bone; - - //! The motion type. - int32_t type; - - //! The minimum and maximum values. - float start; - float end; - - // Was "rest". - int32_t unused; - - // The bone controller channel. - int32_t index; -} PACK_STRUCT; - -/** \struct Hitbox_HL1 - * \brief Data structure for a hitbox in HL1 MDL files. - */ -struct Hitbox_HL1 { - //! The bone this hitbox follows. - int32_t bone; - - //! The hit group. - int32_t group; - - //! The hitbox minimum and maximum extents. - vec3_t bbmin; - vec3_t bbmax; -} PACK_STRUCT; - -/** \struct SequenceGroup_HL1 - * \brief Data structure for a sequence group in HL1 MDL files. - */ -struct SequenceGroup_HL1 { - //! A textual name for this sequence group. - char label[32]; - - //! The file name. - char name[64]; - - //! Was "cache". - int32_t unused; - - //! Was "data". - int32_t unused2; -} PACK_STRUCT; - -//! The type of blending for a sequence. -enum SequenceBlendMode_HL1 { - NoBlend = 1, - TwoWayBlending = 2, - FourWayBlending = 4, -}; - -/** \struct SequenceDesc_HL1 - * \brief Data structure for a sequence description in HL1 MDL files. - */ -struct SequenceDesc_HL1 { - //! The sequence name. - char label[32]; - - //! Frames per second. - float fps; - - //! looping/non-looping flags. - int32_t flags; - - //! The sequence activity. - int32_t activity; - - //! The sequence activity weight. - int32_t actweight; - - //! The number of animation events. - int32_t numevents; - - //! Offset the the first animation event chunk. - int32_t eventindex; - - //! The number of frames in the sequence. - int32_t numframes; - - //! Was "numpivots". - int32_t unused; - - //! Was "pivotindex". - int32_t unused2; - - //! Linear motion type. - int32_t motiontype; - - //! Linear motion bone. - int32_t motionbone; - - //! Linear motion. - vec3_t linearmovement; - - //! Was "automoveposindex". - int32_t unused3; - - //! Was "automoveangleindex". - int32_t unused4; - - //! The sequence minimum and maximum extents. - vec3_t bbmin; - vec3_t bbmax; - - //! The number of blend animations. - int32_t numblends; - - //! Offset to first the AnimValueOffset_HL1 chunk. - //! This offset is relative to the SequenceHeader_HL1 of the file - //! that contains the animation data. - int32_t animindex; - - //! The motion type of each blend controller. - int32_t blendtype[2]; - - //! The starting value of each blend controller. - float blendstart[2]; - - //! The ending value of each blend controller. - float blendend[2]; - - //! Was "blendparent". - int32_t unused5; - - //! The sequence group. - int32_t seqgroup; - - //! The node at entry in the sequence transition graph. - int32_t entrynode; - - //! The node at exit in the sequence transition graph. - int32_t exitnode; - - //! Transition rules. - int32_t nodeflags; - - //! Was "nextseq" - int32_t unused6; -} PACK_STRUCT; - -/** \struct AnimEvent_HL1 - * \brief Data structure for an animation event in HL1 MDL files. - */ -struct AnimEvent_HL1 { - //! The frame at which this animation event occurs. - int32_t frame; - - //! The script event type. - int32_t event; - - //! was "type" - int32_t unused; - - //! Options. Could be path to sound WAVE files. - char options[64]; -} PACK_STRUCT; - -/** \struct Attachment_HL1 - * \brief Data structure for an attachment in HL1 MDL files. - */ -struct Attachment_HL1 { - //! Was "name". - char unused[32]; - - //! Was "type". - int32_t unused2; - - //! The bone this attachment follows. - int32_t bone; - - //! The attachment origin. - vec3_t org; - - //! Was "vectors" - vec3_t unused3[3]; -} PACK_STRUCT; - -/** \struct AnimValueOffset_HL1 - * \brief Data structure to hold offsets (one per motion type) - * to the first animation frame value for a single bone - * in HL1 MDL files. - */ -struct AnimValueOffset_HL1 { - unsigned short offset[6]; -} PACK_STRUCT; - -/** \struct AnimValue_HL1 - * \brief Data structure for an animation frame in HL1 MDL files. - */ -union AnimValue_HL1 { - struct { - uint8_t valid; - uint8_t total; - } num; - short value; -} PACK_STRUCT; - -/** \struct Bodypart_HL1 - * \brief Data structure for a bodypart in HL1 MDL files. - */ -struct Bodypart_HL1 { - //! The bodypart name. - char name[64]; - - //! The number of available models for this bodypart. - int32_t nummodels; - - //! Used to convert from a global model index - //! to a local bodypart model index. - int32_t base; - - //! The offset to the first model chunk. - int32_t modelindex; -} PACK_STRUCT; - -/** \struct Texture_HL1 - * \brief Data structure for a texture in HL1 MDL files. - */ -struct Texture_HL1 { - //! Texture file name. - char name[64]; - - //! Texture flags. - int32_t flags; - - //! Texture width in pixels. - int32_t width; - - //! Texture height in pixels. - int32_t height; - - //! Offset to the image data. - //! This offset is relative to the texture file header. - int32_t index; -} PACK_STRUCT; - -/** \struct Model_HL1 - * \brief Data structure for a model in HL1 MDL files. - */ -struct Model_HL1 { - //! Model name. - char name[64]; - - //! Was "type". - int32_t unused; - - //! Was "boundingradius". - float unused2; - - //! The number of meshes in the model. - int32_t nummesh; - - //! Offset to the first mesh chunk. - int32_t meshindex; - - //! The number of unique vertices. - int32_t numverts; - - //! Offset to the vertex bone array. - int32_t vertinfoindex; - - //! Offset to the vertex array. - int32_t vertindex; - - //! The number of unique normals. - int32_t numnorms; - - //! Offset to the normal bone array. - int32_t norminfoindex; - - //! Offset to the normal array. - int32_t normindex; - - //! Was "numgroups". - int32_t unused3; - - //! Was "groupindex". - int32_t unused4; -} PACK_STRUCT; - -/** \struct Mesh_HL1 - * \brief Data structure for a mesh in HL1 MDL files. - */ -struct Mesh_HL1 { - //! Can be interpreted as the number of triangles in the mesh. - int32_t numtris; - - //! Offset to the start of the tris sequence. - int32_t triindex; - - //! The skin index. - int32_t skinref; - - //! The number of normals in the mesh. - int32_t numnorms; - - //! Was "normindex". - int32_t unused; -} PACK_STRUCT; - -/** \struct Trivert - * \brief Data structure for a trivert in HL1 MDL files. - */ -struct Trivert { - //! Index into Model_HL1 vertex array. - short vertindex; - - //! Index into Model_HL1 normal array. - short normindex; - - //! Texture coordinates in absolute space (unnormalized). - short s, t; -} PACK_STRUCT; - -#include <assimp/Compiler/poppack1.h> - -#if (!defined AI_MDL_HL1_VERSION) -#define AI_MDL_HL1_VERSION 10 -#endif -#if (!defined AI_MDL_HL1_MAX_TRIANGLES) -#define AI_MDL_HL1_MAX_TRIANGLES 20000 -#endif -#if (!defined AI_MDL_HL1_MAX_VERTICES) -#define AI_MDL_HL1_MAX_VERTICES 2048 -#endif -#if (!defined AI_MDL_HL1_MAX_SEQUENCES) -#define AI_MDL_HL1_MAX_SEQUENCES 2048 -#endif -#if (!defined AI_MDL_HL1_MAX_SEQUENCE_GROUPS) -#define AI_MDL_HL1_MAX_SEQUENCE_GROUPS 32 -#endif -#if (!defined AI_MDL_HL1_MAX_TEXTURES) -#define AI_MDL_HL1_MAX_TEXTURES 100 -#endif -#if (!defined AI_MDL_HL1_MAX_SKIN_FAMILIES) -#define AI_MDL_HL1_MAX_SKIN_FAMILIES 100 -#endif -#if (!defined AI_MDL_HL1_MAX_BONES) -#define AI_MDL_HL1_MAX_BONES 128 -#endif -#if (!defined AI_MDL_HL1_MAX_BODYPARTS) -#define AI_MDL_HL1_MAX_BODYPARTS 32 -#endif -#if (!defined AI_MDL_HL1_MAX_MODELS) -#define AI_MDL_HL1_MAX_MODELS 32 -#endif -#if (!defined AI_MDL_HL1_MAX_MESHES) -#define AI_MDL_HL1_MAX_MESHES 256 -#endif -#if (!defined AI_MDL_HL1_MAX_EVENTS) -#define AI_MDL_HL1_MAX_EVENTS 1024 -#endif -#if (!defined AI_MDL_HL1_MAX_BONE_CONTROLLERS) -#define AI_MDL_HL1_MAX_BONE_CONTROLLERS 8 -#endif -#if (!defined AI_MDL_HL1_MAX_ATTACHMENTS) -#define AI_MDL_HL1_MAX_ATTACHMENTS 512 -#endif - -// lighting options -#if (!defined AI_MDL_HL1_STUDIO_NF_FLATSHADE) -#define AI_MDL_HL1_STUDIO_NF_FLATSHADE 0x0001 -#endif -#if (!defined AI_MDL_HL1_STUDIO_NF_CHROME) -#define AI_MDL_HL1_STUDIO_NF_CHROME 0x0002 -#endif -#if (!defined AI_MDL_HL1_STUDIO_NF_ADDITIVE) -#define AI_MDL_HL1_STUDIO_NF_ADDITIVE 0x0020 -#endif -#if (!defined AI_MDL_HL1_STUDIO_NF_MASKED) -#define AI_MDL_HL1_STUDIO_NF_MASKED 0x0040 -#endif - -} // namespace HalfLife -} // namespace MDL -} // namespace Assimp - -#endif // AI_HL1FILEDATA_INCLUDED diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1ImportDefinitions.h b/libs/assimp/code/AssetLib/MDL/HalfLife/HL1ImportDefinitions.h deleted file mode 100644 index d412aee..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1ImportDefinitions.h +++ /dev/null @@ -1,64 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file HL1ImportDefinitions.h - * @brief HL1 MDL loader specific definitions. - */ - -#ifndef AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED -#define AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED - -#define AI_MDL_HL1_NODE_ROOT "<MDL_root>" -#define AI_MDL_HL1_NODE_BODYPARTS "<MDL_bodyparts>" -#define AI_MDL_HL1_NODE_BONES "<MDL_bones>" -#define AI_MDL_HL1_NODE_BONE_CONTROLLERS "<MDL_bone_controllers>" -#define AI_MDL_HL1_NODE_SEQUENCE_INFOS "<MDL_sequence_infos>" -#define AI_MDL_HL1_NODE_SEQUENCE_GROUPS "<MDL_sequence_groups>" -#define AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH "<MDL_sequence_transition_graph>" -#define AI_MDL_HL1_NODE_ATTACHMENTS "<MDL_attachments>" -#define AI_MDL_HL1_NODE_HITBOXES "<MDL_hitboxes>" -#define AI_MDL_HL1_NODE_GLOBAL_INFO "<MDL_global_info>" -#define AI_MDL_HL1_NODE_ANIMATION_EVENTS "AnimationEvents" -#define AI_MDL_HL1_NODE_BLEND_CONTROLLERS "BlendControllers" - -#define AI_MDL_HL1_MATKEY_CHROME(type, N) "$mat.HL1.chrome", type, N - -#endif // AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1ImportSettings.h b/libs/assimp/code/AssetLib/MDL/HalfLife/HL1ImportSettings.h deleted file mode 100644 index 340ba2d..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1ImportSettings.h +++ /dev/null @@ -1,85 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file HL1ImportSettings.h - * @brief Half-Life 1 MDL loader configuration settings. - */ - -#ifndef AI_HL1IMPORTSETTINGS_INCLUDED -#define AI_HL1IMPORTSETTINGS_INCLUDED - -#include <string> - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -struct HL1ImportSettings { - HL1ImportSettings() : - read_animations(false), - read_animation_events(false), - read_blend_controllers(false), - read_sequence_groups_info(false), - read_sequence_transitions(false), - read_attachments(false), - read_bone_controllers(false), - read_hitboxes(false), - read_textures(false), - read_misc_global_info(false) { - } - - bool read_animations; - bool read_animation_events; - bool read_blend_controllers; - bool read_sequence_groups_info; - bool read_sequence_transitions; - bool read_attachments; - bool read_bone_controllers; - bool read_hitboxes; - bool read_textures; - bool read_misc_global_info; -}; - -} // namespace HalfLife -} // namespace MDL -} // namespace Assimp - -#endif // AI_HL1IMPORTSETTINGS_INCLUDED diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp b/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp deleted file mode 100644 index 93d3753..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp +++ /dev/null @@ -1,1353 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file HL1MDLLoader.cpp - * @brief Implementation for the Half-Life 1 MDL loader. - */ - -#include "HL1MDLLoader.h" -#include "HL1ImportDefinitions.h" -#include "HL1MeshTrivert.h" -#include "UniqueNameGenerator.h" - -#include <assimp/BaseImporter.h> -#include <assimp/StringUtils.h> -#include <assimp/ai_assert.h> -#include <assimp/qnan.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/Importer.hpp> - -#include <iomanip> -#include <sstream> -#include <map> - -#ifdef MDL_HALFLIFE_LOG_WARN_HEADER -#undef MDL_HALFLIFE_LOG_WARN_HEADER -#endif -#define MDL_HALFLIFE_LOG_HEADER "[Half-Life 1 MDL] " -#include "LogFunctions.h" - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -#ifdef _MSC_VER -# pragma warning(disable : 4706) -#endif // _MSC_VER - -// ------------------------------------------------------------------------------------------------ -HL1MDLLoader::HL1MDLLoader( - aiScene *scene, - IOSystem *io, - const unsigned char *buffer, - const std::string &file_path, - const HL1ImportSettings &import_settings) : - scene_(scene), - io_(io), - buffer_(buffer), - file_path_(file_path), - import_settings_(import_settings), - header_(nullptr), - texture_header_(nullptr), - anim_headers_(nullptr), - texture_buffer_(nullptr), - anim_buffers_(nullptr), - num_sequence_groups_(0), - rootnode_children_(), - unique_name_generator_(), - unique_sequence_names_(), - unique_sequence_groups_names_(), - temp_bones_(), - num_blend_controllers_(0), - total_models_(0) { - load_file(); -} - -// ------------------------------------------------------------------------------------------------ -HL1MDLLoader::~HL1MDLLoader() { - release_resources(); -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::release_resources() { - if (buffer_ != texture_buffer_) { - delete[] texture_buffer_; - texture_buffer_ = nullptr; - } - - if (num_sequence_groups_ && anim_buffers_) { - for (int i = 1; i < num_sequence_groups_; ++i) { - if (anim_buffers_[i]) { - delete[] anim_buffers_[i]; - anim_buffers_[i] = nullptr; - } - } - - delete[] anim_buffers_; - anim_buffers_ = nullptr; - } - - if (anim_headers_) { - delete[] anim_headers_; - anim_headers_ = nullptr; - } - - // Root has some children nodes. so let's proceed them - if (!rootnode_children_.empty()) { - // Here, it means that the nodes were not added to the - // scene root node. We still have to delete them. - for (auto it = rootnode_children_.begin(); it != rootnode_children_.end(); ++it) { - if (*it) { - delete *it; - } - } - // Ensure this happens only once. - rootnode_children_.clear(); - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::load_file() { - try { - header_ = (const Header_HL1 *)buffer_; - validate_header(header_, false); - - // Create the root scene node. - scene_->mRootNode = new aiNode(AI_MDL_HL1_NODE_ROOT); - - load_texture_file(); - - if (import_settings_.read_animations) { - load_sequence_groups_files(); - } - - read_textures(); - read_skins(); - - read_bones(); - read_meshes(); - - if (import_settings_.read_animations) { - read_sequence_groups_info(); - read_animations(); - read_sequence_infos(); - if (import_settings_.read_sequence_transitions) - read_sequence_transitions(); - } - - if (import_settings_.read_attachments) { - read_attachments(); - } - - if (import_settings_.read_hitboxes) { - read_hitboxes(); - } - - if (import_settings_.read_bone_controllers) { - read_bone_controllers(); - } - - read_global_info(); - - if (!header_->numbodyparts) { - // This could be an MDL external texture file. In this case, - // add this flag to allow the scene to be loaded even if it - // has no meshes. - scene_->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } - - // Append children to root node. - if (rootnode_children_.size()) { - scene_->mRootNode->addChildren( - static_cast<unsigned int>(rootnode_children_.size()), - rootnode_children_.data()); - - // Clear the list of nodes so they will not be destroyed - // when resources are released. - rootnode_children_.clear(); - } - - release_resources(); - - } catch (...) { - release_resources(); - throw; - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::validate_header(const Header_HL1 *header, bool is_texture_header) { - if (is_texture_header) { - // Every single Half-Life model is assumed to have at least one texture. - if (!header->numtextures) { - throw DeadlyImportError(MDL_HALFLIFE_LOG_HEADER "There are no textures in the file"); - } - - if (header->numtextures > AI_MDL_HL1_MAX_TEXTURES) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_TEXTURES>(header->numtextures, "textures"); - } - - if (header->numskinfamilies > AI_MDL_HL1_MAX_SKIN_FAMILIES) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_SKIN_FAMILIES>(header->numskinfamilies, "skin families"); - } - - } else { - - if (header->numbodyparts > AI_MDL_HL1_MAX_BODYPARTS) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_BODYPARTS>(header->numbodyparts, "bodyparts"); - } - - if (header->numbones > AI_MDL_HL1_MAX_BONES) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_BONES>(header->numbones, "bones"); - } - - if (header->numbonecontrollers > AI_MDL_HL1_MAX_BONE_CONTROLLERS) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_BONE_CONTROLLERS>(header->numbonecontrollers, "bone controllers"); - } - - if (header->numseq > AI_MDL_HL1_MAX_SEQUENCES) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_SEQUENCES>(header->numseq, "sequences"); - } - - if (header->numseqgroups > AI_MDL_HL1_MAX_SEQUENCE_GROUPS) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_SEQUENCE_GROUPS>(header->numseqgroups, "sequence groups"); - } - - if (header->numattachments > AI_MDL_HL1_MAX_ATTACHMENTS) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_ATTACHMENTS>(header->numattachments, "attachments"); - } - } -} - -// ------------------------------------------------------------------------------------------------ -/* - Load textures. - - There are two ways for textures to be stored in a Half-Life model: - - 1. Directly in the MDL file (filePath) or - 2. In an external MDL file. - - Due to the way StudioMDL works (tool used to compile SMDs into MDLs), - it is assumed that an external texture file follows the naming - convention: <YourModelName>T.mdl. Note the extra (T) at the end of the - model name. - - .e.g For a given model named MyModel.mdl - - The external texture file name would be MyModelT.mdl -*/ -void HL1MDLLoader::load_texture_file() { - if (header_->numtextures == 0) { - // Load an external MDL texture file. - std::string texture_file_path = - DefaultIOSystem::absolutePath(file_path_) + io_->getOsSeparator() + - DefaultIOSystem::completeBaseName(file_path_) + "T." + - BaseImporter::GetExtension(file_path_); - - load_file_into_buffer<Header_HL1>(texture_file_path, texture_buffer_); - } else { - // Model has no external texture file. This means the texture is stored inside the main MDL file. - texture_buffer_ = const_cast<unsigned char *>(buffer_); - } - - texture_header_ = (const Header_HL1 *)texture_buffer_; - - // Validate texture header. - validate_header(texture_header_, true); -} - -// ------------------------------------------------------------------------------------------------ -/* - Load sequence group files if any. - - Due to the way StudioMDL works (tool used to compile SMDs into MDLs), - it is assumed that a sequence group file follows the naming - convention: <YourModelName>0X.mdl. Note the extra (0X) at the end of - the model name, where (X) is the sequence group. - - .e.g For a given model named MyModel.mdl - - Sequence group 1 => MyModel01.mdl - Sequence group 2 => MyModel02.mdl - Sequence group X => MyModel0X.mdl - -*/ -void HL1MDLLoader::load_sequence_groups_files() { - if (header_->numseqgroups <= 1) { - return; - } - - num_sequence_groups_ = header_->numseqgroups; - - anim_buffers_ = new unsigned char *[num_sequence_groups_]; - anim_headers_ = new SequenceHeader_HL1 *[num_sequence_groups_]; - for (int i = 0; i < num_sequence_groups_; ++i) { - anim_buffers_[i] = nullptr; - anim_headers_[i] = nullptr; - } - - std::string file_path_without_extension = - DefaultIOSystem::absolutePath(file_path_) + - io_->getOsSeparator() + - DefaultIOSystem::completeBaseName(file_path_); - - for (int i = 1; i < num_sequence_groups_; ++i) { - std::stringstream ss; - ss << file_path_without_extension; - ss << std::setw(2) << std::setfill('0') << i; - ss << '.' << BaseImporter::GetExtension(file_path_); - - std::string sequence_file_path = ss.str(); - - load_file_into_buffer<SequenceHeader_HL1>(sequence_file_path, anim_buffers_[i]); - - anim_headers_[i] = (SequenceHeader_HL1 *)anim_buffers_[i]; - } -} - -// ------------------------------------------------------------------------------------------------ -// Read an MDL texture. -void HL1MDLLoader::read_texture(const Texture_HL1 *ptexture, - uint8_t *data, uint8_t *pal, aiTexture *pResult, - aiColor3D &last_palette_color) { - pResult->mFilename = ptexture->name; - pResult->mWidth = static_cast<unsigned int>(ptexture->width); - pResult->mHeight = static_cast<unsigned int>(ptexture->height); - pResult->achFormatHint[0] = 'r'; - pResult->achFormatHint[1] = 'g'; - pResult->achFormatHint[2] = 'b'; - pResult->achFormatHint[3] = 'a'; - pResult->achFormatHint[4] = '8'; - pResult->achFormatHint[5] = '8'; - pResult->achFormatHint[6] = '8'; - pResult->achFormatHint[7] = '8'; - pResult->achFormatHint[8] = '\0'; - - const size_t num_pixels = pResult->mWidth * pResult->mHeight; - aiTexel *out = pResult->pcData = new aiTexel[num_pixels]; - - // Convert indexed 8 bit to 32 bit RGBA. - for (size_t i = 0; i < num_pixels; ++i, ++out) { - out->r = pal[data[i] * 3]; - out->g = pal[data[i] * 3 + 1]; - out->b = pal[data[i] * 3 + 2]; - out->a = 255; - } - - // Get the last palette color. - last_palette_color.r = pal[255 * 3]; - last_palette_color.g = pal[255 * 3 + 1]; - last_palette_color.b = pal[255 * 3 + 2]; -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_textures() { - const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex); - unsigned char *pin = texture_buffer_; - - scene_->mNumTextures = scene_->mNumMaterials = texture_header_->numtextures; - scene_->mTextures = new aiTexture *[scene_->mNumTextures]; - scene_->mMaterials = new aiMaterial *[scene_->mNumMaterials]; - - for (int i = 0; i < texture_header_->numtextures; ++i) { - scene_->mTextures[i] = new aiTexture(); - - aiColor3D last_palette_color; - read_texture(&ptexture[i], - pin + ptexture[i].index, - pin + ptexture[i].width * ptexture[i].height + ptexture[i].index, - scene_->mTextures[i], - last_palette_color); - - aiMaterial *scene_material = scene_->mMaterials[i] = new aiMaterial(); - - const aiTextureType texture_type = aiTextureType_DIFFUSE; - aiString texture_name(ptexture[i].name); - scene_material->AddProperty(&texture_name, AI_MATKEY_TEXTURE(texture_type, 0)); - - // Is this a chrome texture? - int chrome = ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_CHROME ? 1 : 0; - scene_material->AddProperty(&chrome, 1, AI_MDL_HL1_MATKEY_CHROME(texture_type, 0)); - - if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_FLATSHADE) { - // Flat shading. - const aiShadingMode shading_mode = aiShadingMode_Flat; - scene_material->AddProperty(&shading_mode, 1, AI_MATKEY_SHADING_MODEL); - } - - if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_ADDITIVE) { - // Additive texture. - const aiBlendMode blend_mode = aiBlendMode_Additive; - scene_material->AddProperty(&blend_mode, 1, AI_MATKEY_BLEND_FUNC); - } else if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_MASKED) { - // Texture with 1 bit alpha test. - const aiTextureFlags use_alpha = aiTextureFlags_UseAlpha; - scene_material->AddProperty(&use_alpha, 1, AI_MATKEY_TEXFLAGS(texture_type, 0)); - scene_material->AddProperty(&last_palette_color, 1, AI_MATKEY_COLOR_TRANSPARENT); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_skins() { - // Read skins, if any. - if (texture_header_->numskinfamilies <= 1) { - return; - } - - // Pointer to base texture index. - short *default_skin_ptr = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex); - - // Start at first replacement skin. - short *replacement_skin_ptr = default_skin_ptr + texture_header_->numskinref; - - for (int i = 1; i < texture_header_->numskinfamilies; ++i, replacement_skin_ptr += texture_header_->numskinref) { - for (int j = 0; j < texture_header_->numskinref; ++j) { - if (default_skin_ptr[j] != replacement_skin_ptr[j]) { - // Save replacement textures. - aiString skinMaterialId(scene_->mTextures[replacement_skin_ptr[j]]->mFilename); - scene_->mMaterials[default_skin_ptr[j]]->AddProperty(&skinMaterialId, AI_MATKEY_TEXTURE_DIFFUSE(i)); - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_bones() { - if (!header_->numbones) { - return; - } - - const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex); - - std::vector<std::string> unique_bones_names(header_->numbones); - for (int i = 0; i < header_->numbones; ++i) { - unique_bones_names[i] = pbone[i].name; - } - - // Ensure bones have unique names. - unique_name_generator_.set_template_name("Bone"); - unique_name_generator_.make_unique(unique_bones_names); - - temp_bones_.resize(header_->numbones); - - aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES); - rootnode_children_.push_back(bones_node); - bones_node->mNumChildren = static_cast<unsigned int>(header_->numbones); - bones_node->mChildren = new aiNode *[bones_node->mNumChildren]; - - // Create bone matrices in local space. - for (int i = 0; i < header_->numbones; ++i) { - aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]); - - aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]); - temp_bones_[i].absolute_transform = bone_node->mTransformation = - aiMatrix4x4(aiVector3D(1), aiQuaternion(angles.y, angles.z, angles.x), - aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2])); - - if (pbone[i].parent == -1) { - bone_node->mParent = scene_->mRootNode; - } else { - bone_node->mParent = bones_node->mChildren[pbone[i].parent]; - - temp_bones_[i].absolute_transform = - temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation; - } - - temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform; - temp_bones_[i].offset_matrix.Inverse(); - } -} - -// ------------------------------------------------------------------------------------------------ -/* - Read meshes. - - Half-Life MDLs are structured such that each MDL - contains one or more 'bodypart(s)', which contain one - or more 'model(s)', which contains one or more mesh(es). - - * Bodyparts are used to group models that may be replaced - in the game .e.g a character could have a 'heads' group, - 'torso' group, 'shoes' group, with each group containing - different 'model(s)'. - - * Models, also called 'sub models', contain vertices as - well as a reference to each mesh used by the sub model. - - * Meshes contain a list of tris, also known as 'triverts'. - Each tris contains the following information: - - 1. The index of the position to use for the vertex. - 2. The index of the normal to use for the vertex. - 3. The S coordinate to use for the vertex UV. - 4. The T coordinate ^ - - These tris represent the way to represent the triangles - for each mesh. Depending on how the tool compiled the MDL, - those triangles were saved as strips and or fans. - - NOTE: Each tris is NOT unique. This means that you - might encounter the same vertex index but with a different - normal index, S coordinate, T coordinate. - - In addition, each mesh contains the texture's index. - - ------------------------------------------------------ - With the details above, there are several things to - take into consideration. - - * The Half-Life models store the vertices by sub model - rather than by mesh. Due to Assimp's structure, it - is necessary to remap each model vertex to be used - per mesh. Unfortunately, this has the consequence - to duplicate vertices. - - * Because the mesh triangles are comprised of strips and - fans, it is necessary to convert each primitive to - triangles, respectively (3 indices per face). -*/ -void HL1MDLLoader::read_meshes() { - if (!header_->numbodyparts) { - return; - } - - int total_verts = 0; - int total_triangles = 0; - total_models_ = 0; - - const Bodypart_HL1 *pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); - const Model_HL1 *pmodel = nullptr; - const Mesh_HL1 *pmesh = nullptr; - - const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex); - short *pskinref = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex); - - scene_->mNumMeshes = 0; - - std::vector<std::string> unique_bodyparts_names; - unique_bodyparts_names.resize(header_->numbodyparts); - - // Count the number of meshes. - - for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) { - unique_bodyparts_names[i] = pbodypart->name; - - pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); - for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel) { - scene_->mNumMeshes += pmodel->nummesh; - total_verts += pmodel->numverts; - } - - total_models_ += pbodypart->nummodels; - } - - // Display limit infos. - if (total_verts > AI_MDL_HL1_MAX_VERTICES) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_VERTICES>(total_verts, "vertices"); - } - - if (scene_->mNumMeshes > AI_MDL_HL1_MAX_MESHES) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_MESHES>(scene_->mNumMeshes, "meshes"); - } - - if (total_models_ > AI_MDL_HL1_MAX_MODELS) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_MODELS>(total_models_, "models"); - } - - // Ensure bodyparts have unique names. - unique_name_generator_.set_template_name("Bodypart"); - unique_name_generator_.make_unique(unique_bodyparts_names); - - // Now do the same for each model. - pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); - - // Prepare template name for bodypart models. - std::vector<std::string> unique_models_names; - unique_models_names.resize(total_models_); - - unsigned int model_index = 0; - - for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) { - pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); - for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel, ++model_index) - unique_models_names[model_index] = pmodel->name; - } - - unique_name_generator_.set_template_name("Model"); - unique_name_generator_.make_unique(unique_models_names); - - unsigned int mesh_index = 0; - - scene_->mMeshes = new aiMesh *[scene_->mNumMeshes]; - - pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); - - /* Create a node that will represent the mesh hierarchy. - - <MDL_bodyparts> - | - +-- bodypart --+-- model -- [mesh index, mesh index, ...] - | | - | +-- model -- [mesh index, mesh index, ...] - | | - | ... - | - |-- bodypart -- ... - | - ... - */ - aiNode *bodyparts_node = new aiNode(AI_MDL_HL1_NODE_BODYPARTS); - rootnode_children_.push_back(bodyparts_node); - bodyparts_node->mNumChildren = static_cast<unsigned int>(header_->numbodyparts); - bodyparts_node->mChildren = new aiNode *[bodyparts_node->mNumChildren]; - aiNode **bodyparts_node_ptr = bodyparts_node->mChildren; - - // The following variables are defined here so they don't have - // to be recreated every iteration. - - // Model_HL1 vertices, in bind pose space. - std::vector<aiVector3D> bind_pose_vertices; - - // Model_HL1 normals, in bind pose space. - std::vector<aiVector3D> bind_pose_normals; - - // Used to contain temporary information for building a mesh. - std::vector<HL1MeshTrivert> triverts; - - std::vector<short> tricmds; - - // Which triverts to use for the mesh. - std::vector<short> mesh_triverts_indices; - - std::vector<HL1MeshFace> mesh_faces; - - /* triverts that have the same vertindex, but have different normindex,s,t values. - Similar triverts are mapped from vertindex to a list of similar triverts. */ - std::map<short, std::set<short>> triverts_similars; - - // triverts per bone. - std::map<int, std::set<short>> bone_triverts; - - /** This function adds a trivert index to the list of triverts per bone. - * \param[in] bone The bone that affects the trivert at index \p trivert_index. - * \param[in] trivert_index The trivert index. - */ - auto AddTrivertToBone = [&](int bone, short trivert_index) { - if (bone_triverts.count(bone) == 0) - bone_triverts.insert({ bone, std::set<short>{ trivert_index }}); - else - bone_triverts[bone].insert(trivert_index); - }; - - /** This function creates and appends a new trivert to the list of triverts. - * \param[in] trivert The trivert to use as a prototype. - * \param[in] bone The bone that affects \p trivert. - */ - auto AddSimilarTrivert = [&](const Trivert &trivert, const int bone) { - HL1MeshTrivert new_trivert(trivert); - new_trivert.localindex = static_cast<short>(mesh_triverts_indices.size()); - - short new_trivert_index = static_cast<short>(triverts.size()); - - if (triverts_similars.count(trivert.vertindex) == 0) - triverts_similars.insert({ trivert.vertindex, std::set<short>{ new_trivert_index }}); - else - triverts_similars[trivert.vertindex].insert(new_trivert_index); - - triverts.push_back(new_trivert); - - mesh_triverts_indices.push_back(new_trivert_index); - tricmds.push_back(new_trivert.localindex); - AddTrivertToBone(bone, new_trivert.localindex); - }; - - model_index = 0; - - for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart, ++bodyparts_node_ptr) { - pmodel = (const Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); - - // Create bodypart node for the mesh tree hierarchy. - aiNode *bodypart_node = (*bodyparts_node_ptr) = new aiNode(unique_bodyparts_names[i]); - bodypart_node->mParent = bodyparts_node; - bodypart_node->mMetaData = aiMetadata::Alloc(1); - bodypart_node->mMetaData->Set(0, "Base", pbodypart->base); - - bodypart_node->mNumChildren = static_cast<unsigned int>(pbodypart->nummodels); - bodypart_node->mChildren = new aiNode *[bodypart_node->mNumChildren]; - aiNode **bodypart_models_ptr = bodypart_node->mChildren; - - for (int j = 0; j < pbodypart->nummodels; - ++j, ++pmodel, ++bodypart_models_ptr, ++model_index) { - - pmesh = (const Mesh_HL1 *)((uint8_t *)header_ + pmodel->meshindex); - - uint8_t *pvertbone = ((uint8_t *)header_ + pmodel->vertinfoindex); - uint8_t *pnormbone = ((uint8_t *)header_ + pmodel->norminfoindex); - vec3_t *pstudioverts = (vec3_t *)((uint8_t *)header_ + pmodel->vertindex); - vec3_t *pstudionorms = (vec3_t *)((uint8_t *)header_ + pmodel->normindex); - - // Each vertex and normal is in local space, so transform - // each of them to bring them in bind pose. - bind_pose_vertices.resize(pmodel->numverts); - bind_pose_normals.resize(pmodel->numnorms); - for (size_t k = 0; k < bind_pose_vertices.size(); ++k) { - const vec3_t &vert = pstudioverts[k]; - bind_pose_vertices[k] = temp_bones_[pvertbone[k]].absolute_transform * aiVector3D(vert[0], vert[1], vert[2]); - } - for (size_t k = 0; k < bind_pose_normals.size(); ++k) { - const vec3_t &norm = pstudionorms[k]; - // Compute the normal matrix to transform the normal into bind pose, - // without affecting its length. - const aiMatrix4x4 normal_matrix = aiMatrix4x4(temp_bones_[pnormbone[k]].absolute_transform).Inverse().Transpose(); - bind_pose_normals[k] = normal_matrix * aiVector3D(norm[0], norm[1], norm[2]); - } - - // Create model node for the mesh tree hierarchy. - aiNode *model_node = (*bodypart_models_ptr) = new aiNode(unique_models_names[model_index]); - model_node->mParent = bodypart_node; - model_node->mNumMeshes = static_cast<unsigned int>(pmodel->nummesh); - model_node->mMeshes = new unsigned int[model_node->mNumMeshes]; - unsigned int *model_meshes_ptr = model_node->mMeshes; - - for (int k = 0; k < pmodel->nummesh; ++k, ++pmesh, ++mesh_index, ++model_meshes_ptr) { - *model_meshes_ptr = mesh_index; - - // Read triverts. - short *ptricmds = (short *)((uint8_t *)header_ + pmesh->triindex); - float texcoords_s_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].width; - float texcoords_t_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].height; - - // Reset the data for the upcoming mesh. - triverts.clear(); - triverts.resize(pmodel->numverts); - mesh_triverts_indices.clear(); - mesh_faces.clear(); - triverts_similars.clear(); - bone_triverts.clear(); - - int l; - while ((l = *(ptricmds++))) { - bool is_triangle_fan = false; - - if (l < 0) { - l = -l; - is_triangle_fan = true; - } - - // Clear the list of tris for the upcoming tris. - tricmds.clear(); - - for (; l > 0; l--, ptricmds += 4) { - const Trivert *input_trivert = reinterpret_cast<const Trivert *>(ptricmds); - const int bone = pvertbone[input_trivert->vertindex]; - - HL1MeshTrivert *private_trivert = &triverts[input_trivert->vertindex]; - if (private_trivert->localindex == -1) { - // First time referenced. - *private_trivert = *input_trivert; - private_trivert->localindex = static_cast<short>(mesh_triverts_indices.size()); - mesh_triverts_indices.push_back(input_trivert->vertindex); - tricmds.push_back(private_trivert->localindex); - AddTrivertToBone(bone, private_trivert->localindex); - } else if (*private_trivert == *input_trivert) { - // Exists and is the same. - tricmds.push_back(private_trivert->localindex); - } else { - // No similar trivert associated to the trivert currently processed. - if (triverts_similars.count(input_trivert->vertindex) == 0) - AddSimilarTrivert(*input_trivert, bone); - else { - // Search in the list of similar triverts to see if the - // trivert in process is already registered. - short similar_index = -1; - for (auto it = triverts_similars[input_trivert->vertindex].cbegin(); - similar_index == -1 && it != triverts_similars[input_trivert->vertindex].cend(); - ++it) { - if (triverts[*it] == *input_trivert) - similar_index = *it; - } - - // If a similar trivert has been found, reuse it. - // Otherwise, add it. - if (similar_index == -1) - AddSimilarTrivert(*input_trivert, bone); - else - tricmds.push_back(triverts[similar_index].localindex); - } - } - } - - // Build mesh faces. - const int num_faces = static_cast<int>(tricmds.size() - 2); - mesh_faces.reserve(num_faces); - - if (is_triangle_fan) { - for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) { - mesh_faces.push_back(HL1MeshFace{ - tricmds[0], - tricmds[faceIdx + 1], - tricmds[faceIdx + 2] }); - } - } else { - for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) { - if (faceIdx & 1) { - // Preserve winding order. - mesh_faces.push_back(HL1MeshFace{ - tricmds[faceIdx + 1], - tricmds[faceIdx], - tricmds[faceIdx + 2] }); - } else { - mesh_faces.push_back(HL1MeshFace{ - tricmds[faceIdx], - tricmds[faceIdx + 1], - tricmds[faceIdx + 2] }); - } - } - } - - total_triangles += num_faces; - } - - // Create the scene mesh. - aiMesh *scene_mesh = scene_->mMeshes[mesh_index] = new aiMesh(); - scene_mesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_TRIANGLE; - scene_mesh->mMaterialIndex = pskinref[pmesh->skinref]; - - scene_mesh->mNumVertices = static_cast<unsigned int>(mesh_triverts_indices.size()); - - if (scene_mesh->mNumVertices) { - scene_mesh->mVertices = new aiVector3D[scene_mesh->mNumVertices]; - scene_mesh->mNormals = new aiVector3D[scene_mesh->mNumVertices]; - - scene_mesh->mNumUVComponents[0] = 2; - scene_mesh->mTextureCoords[0] = new aiVector3D[scene_mesh->mNumVertices]; - - // Add vertices. - for (unsigned int v = 0; v < scene_mesh->mNumVertices; ++v) { - const HL1MeshTrivert *pTrivert = &triverts[mesh_triverts_indices[v]]; - scene_mesh->mVertices[v] = bind_pose_vertices[pTrivert->vertindex]; - scene_mesh->mNormals[v] = bind_pose_normals[pTrivert->normindex]; - scene_mesh->mTextureCoords[0][v] = aiVector3D( - pTrivert->s * texcoords_s_scale, - pTrivert->t * -texcoords_t_scale, 0); - } - - // Add face and indices. - scene_mesh->mNumFaces = static_cast<unsigned int>(mesh_faces.size()); - scene_mesh->mFaces = new aiFace[scene_mesh->mNumFaces]; - - for (unsigned int f = 0; f < scene_mesh->mNumFaces; ++f) { - aiFace *face = &scene_mesh->mFaces[f]; - face->mNumIndices = 3; - face->mIndices = new unsigned int[3]; - face->mIndices[0] = mesh_faces[f].v2; - face->mIndices[1] = mesh_faces[f].v1; - face->mIndices[2] = mesh_faces[f].v0; - } - - // Add mesh bones. - scene_mesh->mNumBones = static_cast<unsigned int>(bone_triverts.size()); - scene_mesh->mBones = new aiBone *[scene_mesh->mNumBones]; - - aiBone **scene_bone_ptr = scene_mesh->mBones; - - for (auto bone_it = bone_triverts.cbegin(); - bone_it != bone_triverts.cend(); - ++bone_it, ++scene_bone_ptr) { - const int bone_index = bone_it->first; - - aiBone *scene_bone = (*scene_bone_ptr) = new aiBone(); - scene_bone->mName = temp_bones_[bone_index].node->mName; - - scene_bone->mOffsetMatrix = temp_bones_[bone_index].offset_matrix; - - auto vertex_ids = bone_triverts.at(bone_index); - - // Add vertex weight per bone. - scene_bone->mNumWeights = static_cast<unsigned int>(vertex_ids.size()); - aiVertexWeight *vertex_weight_ptr = scene_bone->mWeights = new aiVertexWeight[scene_bone->mNumWeights]; - - for (auto vertex_it = vertex_ids.begin(); - vertex_it != vertex_ids.end(); - ++vertex_it, ++vertex_weight_ptr) { - vertex_weight_ptr->mVertexId = *vertex_it; - vertex_weight_ptr->mWeight = 1.0f; - } - } - } - } - } - } - - if (total_triangles > AI_MDL_HL1_MAX_TRIANGLES) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_TRIANGLES>(total_triangles, "triangles"); - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_animations() { - if (!header_->numseq) { - return; - } - - const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); - const SequenceGroup_HL1 *pseqgroup = nullptr; - const AnimValueOffset_HL1 *panim = nullptr; - const AnimValue_HL1 *panimvalue = nullptr; - - unique_sequence_names_.resize(header_->numseq); - for (int i = 0; i < header_->numseq; ++i) - unique_sequence_names_[i] = pseqdesc[i].label; - - // Ensure sequences have unique names. - unique_name_generator_.set_template_name("Sequence"); - unique_name_generator_.make_unique(unique_sequence_names_); - - scene_->mNumAnimations = 0; - - int highest_num_blend_animations = SequenceBlendMode_HL1::NoBlend; - - // Count the total number of animations. - for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) { - scene_->mNumAnimations += pseqdesc->numblends; - highest_num_blend_animations = std::max(pseqdesc->numblends, highest_num_blend_animations); - } - - // Get the number of available blend controllers for global info. - get_num_blend_controllers(highest_num_blend_animations, num_blend_controllers_); - - pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); - - aiAnimation **scene_animations_ptr = scene_->mAnimations = new aiAnimation *[scene_->mNumAnimations]; - - for (int sequence = 0; sequence < header_->numseq; ++sequence, ++pseqdesc) { - pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex) + pseqdesc->seqgroup; - - if (pseqdesc->seqgroup == 0) { - panim = (const AnimValueOffset_HL1 *)((uint8_t *)header_ + pseqgroup->unused2 + pseqdesc->animindex); - } else { - panim = (const AnimValueOffset_HL1 *)((uint8_t *)anim_headers_[pseqdesc->seqgroup] + pseqdesc->animindex); - } - - for (int blend = 0; blend < pseqdesc->numblends; ++blend, ++scene_animations_ptr) { - - const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex); - - aiAnimation *scene_animation = (*scene_animations_ptr) = new aiAnimation(); - - scene_animation->mName = unique_sequence_names_[sequence]; - scene_animation->mTicksPerSecond = pseqdesc->fps; - scene_animation->mDuration = static_cast<double>(pseqdesc->fps) * pseqdesc->numframes; - scene_animation->mNumChannels = static_cast<unsigned int>(header_->numbones); - scene_animation->mChannels = new aiNodeAnim *[scene_animation->mNumChannels]; - - for (int bone = 0; bone < header_->numbones; bone++, ++pbone, ++panim) { - aiNodeAnim *node_anim = scene_animation->mChannels[bone] = new aiNodeAnim(); - node_anim->mNodeName = temp_bones_[bone].node->mName; - - node_anim->mNumPositionKeys = pseqdesc->numframes; - node_anim->mNumRotationKeys = node_anim->mNumPositionKeys; - node_anim->mNumScalingKeys = 0; - - node_anim->mPositionKeys = new aiVectorKey[node_anim->mNumPositionKeys]; - node_anim->mRotationKeys = new aiQuatKey[node_anim->mNumRotationKeys]; - - for (int frame = 0; frame < pseqdesc->numframes; ++frame) { - aiVectorKey *position_key = &node_anim->mPositionKeys[frame]; - aiQuatKey *rotation_key = &node_anim->mRotationKeys[frame]; - - aiVector3D angle1; - for (int j = 0; j < 3; ++j) { - if (panim->offset[j + 3] != 0) { - // Read compressed rotation delta. - panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j + 3]); - extract_anim_value(panimvalue, frame, pbone->scale[j + 3], angle1[j]); - } - - // Add the default rotation value. - angle1[j] += pbone->value[j + 3]; - - if (panim->offset[j] != 0) { - // Read compressed position delta. - panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j]); - extract_anim_value(panimvalue, frame, pbone->scale[j], position_key->mValue[j]); - } - - // Add the default position value. - position_key->mValue[j] += pbone->value[j]; - } - - position_key->mTime = rotation_key->mTime = static_cast<double>(frame); - /* The Half-Life engine uses X as forward, Y as left, Z as up. Therefore, - pitch,yaw,roll is represented as (YZX). */ - rotation_key->mValue = aiQuaternion(angle1.y, angle1.z, angle1.x); - rotation_key->mValue.Normalize(); - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_sequence_groups_info() { - if (!header_->numseqgroups) { - return; - } - - aiNode *sequence_groups_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_GROUPS); - rootnode_children_.push_back(sequence_groups_node); - - sequence_groups_node->mNumChildren = static_cast<unsigned int>(header_->numseqgroups); - sequence_groups_node->mChildren = new aiNode *[sequence_groups_node->mNumChildren]; - - const SequenceGroup_HL1 *pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex); - - unique_sequence_groups_names_.resize(header_->numseqgroups); - for (int i = 0; i < header_->numseqgroups; ++i) { - unique_sequence_groups_names_[i] = pseqgroup[i].label; - } - - // Ensure sequence groups have unique names. - unique_name_generator_.set_template_name("SequenceGroup"); - unique_name_generator_.make_unique(unique_sequence_groups_names_); - - for (int i = 0; i < header_->numseqgroups; ++i, ++pseqgroup) { - aiNode *sequence_group_node = sequence_groups_node->mChildren[i] = new aiNode(unique_sequence_groups_names_[i]); - sequence_group_node->mParent = sequence_groups_node; - - aiMetadata *md = sequence_group_node->mMetaData = aiMetadata::Alloc(1); - if (i == 0) { - /* StudioMDL does not write the file name for the default sequence group, - so we will write it. */ - md->Set(0, "File", aiString(file_path_)); - } else { - md->Set(0, "File", aiString(pseqgroup->name)); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_sequence_infos() { - if (!header_->numseq) { - return; - } - - const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); - - aiNode *sequence_infos_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS); - rootnode_children_.push_back(sequence_infos_node); - - sequence_infos_node->mNumChildren = static_cast<unsigned int>(header_->numseq); - sequence_infos_node->mChildren = new aiNode *[sequence_infos_node->mNumChildren]; - - std::vector<aiNode *> sequence_info_node_children; - - int animation_index = 0; - for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) { - // Clear the list of children for the upcoming sequence info node. - sequence_info_node_children.clear(); - - aiNode *sequence_info_node = sequence_infos_node->mChildren[i] = new aiNode(unique_sequence_names_[i]); - sequence_info_node->mParent = sequence_infos_node; - - // Setup sequence info node Metadata. - aiMetadata *md = sequence_info_node->mMetaData = aiMetadata::Alloc(16); - md->Set(0, "AnimationIndex", animation_index); - animation_index += pseqdesc->numblends; - - // Reference the sequence group by name. This allows us to search a particular - // sequence group by name using aiNode(s). - md->Set(1, "SequenceGroup", aiString(unique_sequence_groups_names_[pseqdesc->seqgroup])); - md->Set(2, "FramesPerSecond", pseqdesc->fps); - md->Set(3, "NumFrames", pseqdesc->numframes); - md->Set(4, "NumBlends", pseqdesc->numblends); - md->Set(5, "Activity", pseqdesc->activity); - md->Set(6, "ActivityWeight", pseqdesc->actweight); - md->Set(7, "MotionFlags", pseqdesc->motiontype); - md->Set(8, "MotionBone", temp_bones_[pseqdesc->motionbone].node->mName); - md->Set(9, "LinearMovement", aiVector3D(pseqdesc->linearmovement[0], pseqdesc->linearmovement[1], pseqdesc->linearmovement[2])); - md->Set(10, "BBMin", aiVector3D(pseqdesc->bbmin[0], pseqdesc->bbmin[1], pseqdesc->bbmin[2])); - md->Set(11, "BBMax", aiVector3D(pseqdesc->bbmax[0], pseqdesc->bbmax[1], pseqdesc->bbmax[2])); - md->Set(12, "EntryNode", pseqdesc->entrynode); - md->Set(13, "ExitNode", pseqdesc->exitnode); - md->Set(14, "NodeFlags", pseqdesc->nodeflags); - md->Set(15, "Flags", pseqdesc->flags); - - if (import_settings_.read_blend_controllers) { - int num_blend_controllers; - if (get_num_blend_controllers(pseqdesc->numblends, num_blend_controllers) && num_blend_controllers) { - // Read blend controllers info. - aiNode *blend_controllers_node = new aiNode(AI_MDL_HL1_NODE_BLEND_CONTROLLERS); - sequence_info_node_children.push_back(blend_controllers_node); - blend_controllers_node->mParent = sequence_info_node; - blend_controllers_node->mNumChildren = static_cast<unsigned int>(num_blend_controllers); - blend_controllers_node->mChildren = new aiNode *[blend_controllers_node->mNumChildren]; - - for (unsigned int j = 0; j < blend_controllers_node->mNumChildren; ++j) { - aiNode *blend_controller_node = blend_controllers_node->mChildren[j] = new aiNode(); - blend_controller_node->mParent = blend_controllers_node; - - aiMetadata *metaData = blend_controller_node->mMetaData = aiMetadata::Alloc(3); - metaData->Set(0, "Start", pseqdesc->blendstart[j]); - metaData->Set(1, "End", pseqdesc->blendend[j]); - metaData->Set(2, "MotionFlags", pseqdesc->blendtype[j]); - } - } - } - - if (import_settings_.read_animation_events && pseqdesc->numevents) { - // Read animation events. - - if (pseqdesc->numevents > AI_MDL_HL1_MAX_EVENTS) { - log_warning_limit_exceeded<AI_MDL_HL1_MAX_EVENTS>( - "Sequence " + std::string(pseqdesc->label), - pseqdesc->numevents, "animation events"); - } - - const AnimEvent_HL1 *pevent = (const AnimEvent_HL1 *)((uint8_t *)header_ + pseqdesc->eventindex); - - aiNode *pEventsNode = new aiNode(AI_MDL_HL1_NODE_ANIMATION_EVENTS); - sequence_info_node_children.push_back(pEventsNode); - pEventsNode->mParent = sequence_info_node; - pEventsNode->mNumChildren = static_cast<unsigned int>(pseqdesc->numevents); - pEventsNode->mChildren = new aiNode *[pEventsNode->mNumChildren]; - - for (unsigned int j = 0; j < pEventsNode->mNumChildren; ++j, ++pevent) { - aiNode *pEvent = pEventsNode->mChildren[j] = new aiNode(); - pEvent->mParent = pEventsNode; - - aiMetadata *metaData = pEvent->mMetaData = aiMetadata::Alloc(3); - metaData->Set(0, "Frame", pevent->frame); - metaData->Set(1, "ScriptEvent", pevent->event); - metaData->Set(2, "Options", aiString(pevent->options)); - } - } - - if (sequence_info_node_children.size()) { - sequence_info_node->addChildren( - static_cast<unsigned int>(sequence_info_node_children.size()), - sequence_info_node_children.data()); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_sequence_transitions() { - if (!header_->numtransitions) { - return; - } - - // Read sequence transition graph. - aiNode *transition_graph_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH); - rootnode_children_.push_back(transition_graph_node); - - uint8_t *ptransitions = ((uint8_t *)header_ + header_->transitionindex); - aiMetadata *md = transition_graph_node->mMetaData = aiMetadata::Alloc(header_->numtransitions * header_->numtransitions); - for (unsigned int i = 0; i < md->mNumProperties; ++i) - md->Set(i, std::to_string(i), static_cast<int>(ptransitions[i])); -} - -void HL1MDLLoader::read_attachments() { - if (!header_->numattachments) { - return; - } - - const Attachment_HL1 *pattach = (const Attachment_HL1 *)((uint8_t *)header_ + header_->attachmentindex); - - aiNode *attachments_node = new aiNode(AI_MDL_HL1_NODE_ATTACHMENTS); - rootnode_children_.push_back(attachments_node); - attachments_node->mNumChildren = static_cast<unsigned int>(header_->numattachments); - attachments_node->mChildren = new aiNode *[attachments_node->mNumChildren]; - - for (int i = 0; i < header_->numattachments; ++i, ++pattach) { - aiNode *attachment_node = attachments_node->mChildren[i] = new aiNode(); - attachment_node->mParent = attachments_node; - attachment_node->mMetaData = aiMetadata::Alloc(2); - attachment_node->mMetaData->Set(0, "Position", aiVector3D(pattach->org[0], pattach->org[1], pattach->org[2])); - // Reference the bone by name. This allows us to search a particular - // bone by name using aiNode(s). - attachment_node->mMetaData->Set(1, "Bone", temp_bones_[pattach->bone].node->mName); - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_hitboxes() { - if (!header_->numhitboxes) { - return; - } - - const Hitbox_HL1 *phitbox = (const Hitbox_HL1 *)((uint8_t *)header_ + header_->hitboxindex); - - aiNode *hitboxes_node = new aiNode(AI_MDL_HL1_NODE_HITBOXES); - rootnode_children_.push_back(hitboxes_node); - hitboxes_node->mNumChildren = static_cast<unsigned int>(header_->numhitboxes); - hitboxes_node->mChildren = new aiNode *[hitboxes_node->mNumChildren]; - - for (int i = 0; i < header_->numhitboxes; ++i, ++phitbox) { - aiNode *hitbox_node = hitboxes_node->mChildren[i] = new aiNode(); - hitbox_node->mParent = hitboxes_node; - - aiMetadata *md = hitbox_node->mMetaData = aiMetadata::Alloc(4); - // Reference the bone by name. This allows us to search a particular - // bone by name using aiNode(s). - md->Set(0, "Bone", temp_bones_[phitbox->bone].node->mName); - md->Set(1, "HitGroup", phitbox->group); - md->Set(2, "BBMin", aiVector3D(phitbox->bbmin[0], phitbox->bbmin[1], phitbox->bbmin[2])); - md->Set(3, "BBMax", aiVector3D(phitbox->bbmax[0], phitbox->bbmax[1], phitbox->bbmax[2])); - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_bone_controllers() { - if (!header_->numbonecontrollers) { - return; - } - - const BoneController_HL1 *pbonecontroller = (const BoneController_HL1 *)((uint8_t *)header_ + header_->bonecontrollerindex); - - aiNode *bones_controller_node = new aiNode(AI_MDL_HL1_NODE_BONE_CONTROLLERS); - rootnode_children_.push_back(bones_controller_node); - bones_controller_node->mNumChildren = static_cast<unsigned int>(header_->numbonecontrollers); - bones_controller_node->mChildren = new aiNode *[bones_controller_node->mNumChildren]; - - for (int i = 0; i < header_->numbonecontrollers; ++i, ++pbonecontroller) { - aiNode *bone_controller_node = bones_controller_node->mChildren[i] = new aiNode(); - bone_controller_node->mParent = bones_controller_node; - - aiMetadata *md = bone_controller_node->mMetaData = aiMetadata::Alloc(5); - // Reference the bone by name. This allows us to search a particular - // bone by name using aiNode(s). - md->Set(0, "Bone", temp_bones_[pbonecontroller->bone].node->mName); - md->Set(1, "MotionFlags", pbonecontroller->type); - md->Set(2, "Start", pbonecontroller->start); - md->Set(3, "End", pbonecontroller->end); - md->Set(4, "Channel", pbonecontroller->index); - } -} - -// ------------------------------------------------------------------------------------------------ -void HL1MDLLoader::read_global_info() { - aiNode *global_info_node = new aiNode(AI_MDL_HL1_NODE_GLOBAL_INFO); - rootnode_children_.push_back(global_info_node); - - aiMetadata *md = global_info_node->mMetaData = aiMetadata::Alloc(import_settings_.read_misc_global_info ? 16 : 11); - md->Set(0, "Version", AI_MDL_HL1_VERSION); - md->Set(1, "NumBodyparts", header_->numbodyparts); - md->Set(2, "NumModels", total_models_); - md->Set(3, "NumBones", header_->numbones); - md->Set(4, "NumAttachments", import_settings_.read_attachments ? header_->numattachments : 0); - md->Set(5, "NumSkinFamilies", texture_header_->numskinfamilies); - md->Set(6, "NumHitboxes", import_settings_.read_hitboxes ? header_->numhitboxes : 0); - md->Set(7, "NumBoneControllers", import_settings_.read_bone_controllers ? header_->numbonecontrollers : 0); - md->Set(8, "NumSequences", import_settings_.read_animations ? header_->numseq : 0); - md->Set(9, "NumBlendControllers", import_settings_.read_blend_controllers ? num_blend_controllers_ : 0); - md->Set(10, "NumTransitionNodes", import_settings_.read_sequence_transitions ? header_->numtransitions : 0); - - if (import_settings_.read_misc_global_info) { - md->Set(11, "EyePosition", aiVector3D(header_->eyeposition[0], header_->eyeposition[1], header_->eyeposition[2])); - md->Set(12, "HullMin", aiVector3D(header_->min[0], header_->min[1], header_->min[2])); - md->Set(13, "HullMax", aiVector3D(header_->max[0], header_->max[1], header_->max[2])); - md->Set(14, "CollisionMin", aiVector3D(header_->bbmin[0], header_->bbmin[1], header_->bbmin[2])); - md->Set(15, "CollisionMax", aiVector3D(header_->bbmax[0], header_->bbmax[1], header_->bbmax[2])); - } -} - -// ------------------------------------------------------------------------------------------------ -/** @brief This method reads a compressed anim value. -* -* @note The structure of this method is taken from HL2 source code. -* Although this is from HL2, it's implementation is almost identical -* to code found in HL1 SDK. See HL1 and HL2 SDKs for more info. -* -* source: -* HL1 source code. -* file: studio_render.cpp -* function(s): CalcBoneQuaternion and CalcBonePosition -* -* HL2 source code. -* file: bone_setup.cpp -* function(s): ExtractAnimValue -*/ -void HL1MDLLoader::extract_anim_value( - const AnimValue_HL1 *panimvalue, - int frame, float bone_scale, ai_real &value) { - int k = frame; - - // find span of values that includes the frame we want - while (panimvalue->num.total <= k) { - k -= panimvalue->num.total; - panimvalue += panimvalue->num.valid + 1; - } - - // Bah, missing blend! - if (panimvalue->num.valid > k) { - value = panimvalue[k + 1].value * bone_scale; - } else { - value = panimvalue[panimvalue->num.valid].value * bone_scale; - } -} - -// ------------------------------------------------------------------------------------------------ -// Get the number of blend controllers. -bool HL1MDLLoader::get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers) { - - switch (num_blend_animations) { - case SequenceBlendMode_HL1::NoBlend: - num_blend_controllers = 0; - return true; - case SequenceBlendMode_HL1::TwoWayBlending: - num_blend_controllers = 1; - return true; - case SequenceBlendMode_HL1::FourWayBlending: - num_blend_controllers = 2; - return true; - default: - num_blend_controllers = 0; - ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER "Unsupported number of blend animations (", num_blend_animations, ")"); - return false; - } -} - -} // namespace HalfLife -} // namespace MDL -} // namespace Assimp diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h b/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h deleted file mode 100644 index d87d6d3..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h +++ /dev/null @@ -1,243 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file HL1MDLLoader.h - * @brief Declaration of the Half-Life 1 MDL loader. - */ - -#ifndef AI_HL1MDLLOADER_INCLUDED -#define AI_HL1MDLLOADER_INCLUDED - -#include "HL1FileData.h" -#include "HL1ImportSettings.h" -#include "UniqueNameGenerator.h" - -#include <memory> -#include <string> - -#include <assimp/types.h> -#include <assimp/scene.h> -#include <assimp/texture.h> -#include <assimp/IOSystem.hpp> -#include <assimp/DefaultIOSystem.h> -#include <assimp/Exceptional.h> - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -class HL1MDLLoader { -public: - HL1MDLLoader() = delete; - HL1MDLLoader(const HL1MDLLoader &) = delete; - - /** See variables descriptions at the end for more details. */ - HL1MDLLoader( - aiScene *scene, - IOSystem *io, - const unsigned char *buffer, - const std::string &file_path, - const HL1ImportSettings &import_settings); - - ~HL1MDLLoader(); - - void load_file(); - -protected: - /** \brief Validate the header data structure of a Half-Life 1 MDL file. - * \param[in] header Input header to be validated. - * \param[in] is_texture_header Whether or not we are reading an MDL - * texture file. - */ - void validate_header(const Header_HL1 *header, bool is_texture_header); - - void load_texture_file(); - void load_sequence_groups_files(); - void read_textures(); - void read_skins(); - void read_bones(); - void read_meshes(); - void read_animations(); - void read_sequence_groups_info(); - void read_sequence_infos(); - void read_sequence_transitions(); - void read_attachments(); - void read_hitboxes(); - void read_bone_controllers(); - void read_global_info(); - -private: - void release_resources(); - - /** \brief Load a file and copy it's content to a buffer. - * \param file_path The path to the file to be loaded. - * \param buffer A pointer to a buffer to receive the data. - */ - template <typename MDLFileHeader> - void load_file_into_buffer(const std::string &file_path, unsigned char *&buffer); - - /** \brief Read an MDL texture. - * \param[in] ptexture A pointer to an MDL texture. - * \param[in] data A pointer to the data from \p ptexture. - * \param[in] pal A pointer to the texture palette from \p ptexture. - * \param[in,out] pResult A pointer to the output resulting Assimp texture. - * \param[in,out] last_palette_color The last color from the image palette. - */ - void read_texture(const Texture_HL1 *ptexture, - uint8_t *data, uint8_t *pal, aiTexture *pResult, - aiColor3D &last_palette_color); - - /** \brief This method reads a compressed anim value. - * \param[in] panimvalue A pointer to the animation data. - * \param[in] frame The frame to look for. - * \param[in] bone_scale The current bone scale to apply to the compressed value. - * \param[in,out] value The decompressed anim value at \p frame. - */ - void extract_anim_value(const AnimValue_HL1 *panimvalue, - int frame, float bone_scale, ai_real &value); - - /** - * \brief Given the number of blend animations, determine the number of blend controllers. - * - * \param[in] num_blend_animations The number of blend animations. - * \param[out] num_blend_controllers The number of blend controllers. - * \return True if the number of blend controllers was determined. False otherwise. - */ - static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers); - - /** Output scene to be filled */ - aiScene *scene_; - - /** Output I/O handler. Required for additional IO operations. */ - IOSystem *io_; - - /** Buffer from MDLLoader class. */ - const unsigned char *buffer_; - - /** The full file path to the MDL file we are trying to load. - * Used to locate other MDL files since MDL may store resources - * in external MDL files. */ - const std::string &file_path_; - - /** Configuration for HL1 MDL */ - const HL1ImportSettings &import_settings_; - - /** Main MDL header. */ - const Header_HL1 *header_; - - /** External MDL texture header. */ - const Header_HL1 *texture_header_; - - /** External MDL animation headers. - * One for each loaded animation file. */ - SequenceHeader_HL1 **anim_headers_; - - /** Texture file data. */ - unsigned char *texture_buffer_; - - /** Animation files data. */ - unsigned char **anim_buffers_; - - /** The number of sequence groups. */ - int num_sequence_groups_; - - /** The list of children to be appended to the scene's root node. */ - std::vector<aiNode *> rootnode_children_; - - /** A unique name generator. Used to generate names for MDL values - * that may have empty/duplicate names. */ - UniqueNameGenerator unique_name_generator_; - - /** The list of unique sequence names. */ - std::vector<std::string> unique_sequence_names_; - - /** The list of unique sequence groups names. */ - std::vector<std::string> unique_sequence_groups_names_; - - /** Structure to store temporary bone information. */ - struct TempBone { - - TempBone() : - node(nullptr), - absolute_transform(), - offset_matrix() {} - - aiNode *node; - aiMatrix4x4 absolute_transform; - aiMatrix4x4 offset_matrix; - }; - - std::vector<TempBone> temp_bones_; - - /** The number of available bone controllers in the model. */ - int num_blend_controllers_; - - /** Self explanatory. */ - int total_models_; -}; - -// ------------------------------------------------------------------------------------------------ -template <typename MDLFileHeader> -void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) { - if (!io_->Exists(file_path)) - throw DeadlyImportError("Missing file ", DefaultIOSystem::fileName(file_path), "."); - - std::unique_ptr<IOStream> file(io_->Open(file_path)); - - if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open MDL file ", DefaultIOSystem::fileName(file_path), "."); - } - - const size_t file_size = file->FileSize(); - if (file_size < sizeof(MDLFileHeader)) { - throw DeadlyImportError("MDL file is too small."); - } - - buffer = new unsigned char[1 + file_size]; - file->Read((void *)buffer, 1, file_size); - buffer[file_size] = '\0'; -} - -} // namespace HalfLife -} // namespace MDL -} // namespace Assimp - -#endif // AI_HL1MDLLOADER_INCLUDED diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MeshTrivert.h b/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MeshTrivert.h deleted file mode 100644 index 4ef8a13..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/HL1MeshTrivert.h +++ /dev/null @@ -1,127 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file HL1MeshTrivert.h - * @brief This file contains the class declaration for the - * HL1 mesh trivert class. - */ - -#ifndef AI_HL1MESHTRIVERT_INCLUDED -#define AI_HL1MESHTRIVERT_INCLUDED - -#include "HL1FileData.h" - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -/* A class to help map model triverts to mesh triverts. */ -struct HL1MeshTrivert { - HL1MeshTrivert() : - vertindex(-1), - normindex(-1), - s(0), - t(0), - localindex(-1) { - } - - HL1MeshTrivert(short vertindex, short normindex, short s, short t, short localindex) : - vertindex(vertindex), - normindex(normindex), - s(s), - t(t), - localindex(localindex) { - } - - HL1MeshTrivert(const Trivert &a) : - vertindex(a.vertindex), - normindex(a.normindex), - s(a.s), - t(a.t), - localindex(-1) { - } - - inline bool operator==(const Trivert &a) const { - return vertindex == a.vertindex && - normindex == a.normindex && - s == a.s && - t == a.t; - } - - inline bool operator!=(const Trivert &a) const { - return !(*this == a); - } - - inline bool operator==(const HL1MeshTrivert &a) const { - return localindex == a.localindex && - vertindex == a.vertindex && - normindex == a.normindex && - s == a.s && - t == a.t; - } - - inline bool operator!=(const HL1MeshTrivert &a) const { - return !(*this == a); - } - - inline HL1MeshTrivert &operator=(const Trivert &other) { - vertindex = other.vertindex; - normindex = other.normindex; - s = other.s; - t = other.t; - return *this; - } - - short vertindex; - short normindex; - short s, t; - short localindex; -}; - -struct HL1MeshFace { - short v0, v1, v2; -}; - -} // namespace HalfLife -} // namespace MDL -} // namespace Assimp - -#endif // AI_HL1MESHTRIVERT_INCLUDED diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h b/libs/assimp/code/AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h deleted file mode 100644 index c7808c4..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h +++ /dev/null @@ -1,67 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file HalfLifeMDLBaseHeader.h */ - -#ifndef AI_HALFLIFEMDLBASEHEADER_INCLUDED -#define AI_HALFLIFEMDLBASEHEADER_INCLUDED - -#include <assimp/types.h> - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -/** Used to interface different Valve MDL formats. */ -struct HalfLifeMDLBaseHeader -{ - //! Magic number: "IDST"/"IDSQ" - char ident[4]; - - //! The file format version. - int32_t version; -}; - -} -} -} - -#endif // AI_HALFLIFEMDLBASEHEADER_INCLUDED diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/LogFunctions.h b/libs/assimp/code/AssetLib/MDL/HalfLife/LogFunctions.h deleted file mode 100644 index 003774d..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/LogFunctions.h +++ /dev/null @@ -1,95 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file LogFunctions.h */ - -#ifndef AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED -#define AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED - -#include <assimp/Logger.hpp> -#include <string> - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -/** - * \brief A function to log precise messages regarding limits exceeded. - * - * \param[in] subject Subject. - * \param[in] current_amount Current amount. - * \param[in] direct_object Direct object. - * LIMIT Limit constant. - * - * Example: Model has 100 textures, which exceeds the limit (50) - * - * where \p subject is 'Model' - * \p current_amount is '100' - * \p direct_object is 'textures' - * LIMIT is '50' - */ -template <int LIMIT> -static inline void log_warning_limit_exceeded( - const std::string &subject, int current_amount, - const std::string &direct_object) { - - ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER - + subject - + " has " - + std::to_string(current_amount) + " " - + direct_object - + ", which exceeds the limit (" - + std::to_string(LIMIT) - + ")"); -} - -/** \brief Same as above, but uses 'Model' as the subject. */ -template <int LIMIT> -static inline void log_warning_limit_exceeded(int current_amount, - const std::string &direct_object) { - log_warning_limit_exceeded<LIMIT>("Model", current_amount, direct_object); -} - -} // namespace HalfLife -} // namespace MDL -} // namespace Assimp - -#endif // AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp b/libs/assimp/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp deleted file mode 100644 index 6fc8b11..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file UniqueNameGenerator.cpp - * @brief Implementation for the unique name generator. - */ - -#include "UniqueNameGenerator.h" -#include <algorithm> -#include <list> -#include <map> -#include <numeric> - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -UniqueNameGenerator::UniqueNameGenerator() : - template_name_("unnamed"), - separator_("_") { -} - -UniqueNameGenerator::UniqueNameGenerator(const char *template_name) : - template_name_(template_name), - separator_("_") { -} - -UniqueNameGenerator::UniqueNameGenerator(const char *template_name, const char *separator) : - template_name_(template_name), - separator_(separator) { -} - -UniqueNameGenerator::~UniqueNameGenerator() { -} - -void UniqueNameGenerator::make_unique(std::vector<std::string> &names) { - struct DuplicateInfo { - DuplicateInfo() : - indices(), - next_id(0) { - } - - std::list<size_t> indices; - size_t next_id; - }; - - std::vector<size_t> empty_names_indices; - std::vector<size_t> template_name_duplicates; - std::map<std::string, DuplicateInfo> names_to_duplicates; - - const std::string template_name_with_separator(template_name_ + separator_); - - auto format_name = [&](const std::string &base_name, size_t id) -> std::string { - return base_name + separator_ + std::to_string(id); - }; - - auto generate_unique_name = [&](const std::string &base_name) -> std::string { - auto *duplicate_info = &names_to_duplicates[base_name]; - - std::string new_name; - - bool found_identical_name; - bool tried_with_base_name_only = false; - do { - // Assume that no identical name exists. - found_identical_name = false; - - if (!tried_with_base_name_only) { - // First try with only the base name. - new_name = base_name; - } else { - // Create the name expected to be unique. - new_name = format_name(base_name, duplicate_info->next_id); - } - - // Check in the list of duplicates for an identical name. - for (size_t i = 0; - i < names.size() && - !found_identical_name; - ++i) { - if (new_name == names[i]) - found_identical_name = true; - } - - if (tried_with_base_name_only) - ++duplicate_info->next_id; - - tried_with_base_name_only = true; - - } while (found_identical_name); - - return new_name; - }; - - for (size_t i = 0; i < names.size(); ++i) { - // Check for empty names. - if (names[i].find_first_not_of(' ') == std::string::npos) { - empty_names_indices.push_back(i); - continue; - } - - /* Check for potential duplicate. - a) Either if this name is the same as the template name or - b) <template name><separator> is found at the beginning. */ - if (names[i] == template_name_ || - names[i].substr(0, template_name_with_separator.length()) == template_name_with_separator) - template_name_duplicates.push_back(i); - - // Map each unique name to it's duplicate. - if (names_to_duplicates.count(names[i]) == 0) - names_to_duplicates.insert({ names[i], DuplicateInfo()}); - else - names_to_duplicates[names[i]].indices.push_back(i); - } - - // Make every non-empty name unique. - for (auto it = names_to_duplicates.begin(); - it != names_to_duplicates.end(); ++it) { - for (auto it2 = it->second.indices.begin(); - it2 != it->second.indices.end(); - ++it2) - names[*it2] = generate_unique_name(it->first); - } - - // Generate a unique name for every empty string. - if (template_name_duplicates.size()) { - // At least one string ressembles to <template name>. - for (auto it = empty_names_indices.begin(); - it != empty_names_indices.end(); ++it) - names[*it] = generate_unique_name(template_name_); - } else { - // No string alike <template name> exists. - size_t i = 0; - for (auto it = empty_names_indices.begin(); - it != empty_names_indices.end(); ++it, ++i) - names[*it] = format_name(template_name_, i); - } -} - -} // namespace HalfLife -} // namespace MDL -} // namespace Assimp diff --git a/libs/assimp/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.h b/libs/assimp/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.h deleted file mode 100644 index 73b6f9e..0000000 --- a/libs/assimp/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.h +++ /dev/null @@ -1,81 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file UniqueNameGenerator.h - * @brief Declaration of the unique name generator. - */ - -#ifndef AI_UNIQUENAMEGENERATOR_INCLUDED -#define AI_UNIQUENAMEGENERATOR_INCLUDED - -#include <string> -#include <vector> - -namespace Assimp { -namespace MDL { -namespace HalfLife { - -class UniqueNameGenerator { -public: - UniqueNameGenerator(); - UniqueNameGenerator(const char *template_name); - UniqueNameGenerator(const char *template_name, const char *separator); - ~UniqueNameGenerator(); - - inline void set_template_name(const char *template_name) { - template_name_ = template_name; - } - inline void set_separator(const char *separator) { - separator_ = separator; - } - - void make_unique(std::vector<std::string> &names); - -private: - std::string template_name_; - std::string separator_; -}; - -} // namespace HalfLife -} // namespace MDL -} // namespace Assimp - -#endif // AI_UNIQUENAMEGENERATOR_INCLUDED diff --git a/libs/assimp/code/AssetLib/MDL/MDLDefaultColorMap.h b/libs/assimp/code/AssetLib/MDL/MDLDefaultColorMap.h deleted file mode 100644 index 2eecac2..0000000 --- a/libs/assimp/code/AssetLib/MDL/MDLDefaultColorMap.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - - -/** @file Defines the default color map used for Quake 1 model textures - * - * The lib tries to load colormap.lmp from the model's directory. - * This table is only used when required. - */ - -#ifndef AI_MDL_DEFAULTLMP_H_INC -#define AI_MDL_DEFAULTLMP_H_INC - -const unsigned char g_aclrDefaultColorMap[256][3] = { -{ 0, 0, 0}, { 15, 15, 15}, { 31, 31, 31}, { 47, 47, 47}, -{ 63, 63, 63}, { 75, 75, 75}, { 91, 91, 91}, {107, 107, 107}, -{123, 123, 123}, {139, 139, 139}, {155, 155, 155}, {171, 171, 171}, -{187, 187, 187}, {203, 203, 203}, {219, 219, 219}, {235, 235, 235}, -{ 15, 11, 7}, { 23, 15, 11}, { 31, 23, 11}, { 39, 27, 15}, -{ 47, 35, 19}, { 55, 43, 23}, { 63, 47, 23}, { 75, 55, 27}, -{ 83, 59, 27}, { 91, 67, 31}, { 99, 75, 31}, {107, 83, 31}, -{115, 87, 31}, {123, 95, 35}, {131, 103, 35}, {143, 111, 35}, -{ 11, 11, 15}, { 19, 19, 27}, { 27, 27, 39}, { 39, 39, 51}, -{ 47, 47, 63}, { 55, 55, 75}, { 63, 63, 87}, { 71, 71, 103}, -{ 79, 79, 115}, { 91, 91, 127}, { 99, 99, 139}, {107, 107, 151}, -{115, 115, 163}, {123, 123, 175}, {131, 131, 187}, {139, 139, 203}, -{ 0, 0, 0}, { 7, 7, 0}, { 11, 11, 0}, { 19, 19, 0}, -{ 27, 27, 0}, { 35, 35, 0}, { 43, 43, 7}, { 47, 47, 7}, -{ 55, 55, 7}, { 63, 63, 7}, { 71, 71, 7}, { 75, 75, 11}, -{ 83, 83, 11}, { 91, 91, 11}, { 99, 99, 11}, {107, 107, 15}, -{ 7, 0, 0}, { 15, 0, 0}, { 23, 0, 0}, { 31, 0, 0}, -{ 39, 0, 0}, { 47, 0, 0}, { 55, 0, 0}, { 63, 0, 0}, -{ 71, 0, 0}, { 79, 0, 0}, { 87, 0, 0}, { 95, 0, 0}, -{103, 0, 0}, {111, 0, 0}, {119, 0, 0}, {127, 0, 0}, -{ 19, 19, 0}, { 27, 27, 0}, { 35, 35, 0}, { 47, 43, 0}, -{ 55, 47, 0}, { 67, 55, 0}, { 75, 59, 7}, { 87, 67, 7}, -{ 95, 71, 7}, {107, 75, 11}, {119, 83, 15}, {131, 87, 19}, -{139, 91, 19}, {151, 95, 27}, {163, 99, 31}, {175, 103, 35}, -{ 35, 19, 7}, { 47, 23, 11}, { 59, 31, 15}, { 75, 35, 19}, -{ 87, 43, 23}, { 99, 47, 31}, {115, 55, 35}, {127, 59, 43}, -{143, 67, 51}, {159, 79, 51}, {175, 99, 47}, {191, 119, 47}, -{207, 143, 43}, {223, 171, 39}, {239, 203, 31}, {255, 243, 27}, -{ 11, 7, 0}, { 27, 19, 0}, { 43, 35, 15}, { 55, 43, 19}, -{ 71, 51, 27}, { 83, 55, 35}, { 99, 63, 43}, {111, 71, 51}, -{127, 83, 63}, {139, 95, 71}, {155, 107, 83}, {167, 123, 95}, -{183, 135, 107}, {195, 147, 123}, {211, 163, 139}, {227, 179, 151}, -{171, 139, 163}, {159, 127, 151}, {147, 115, 135}, {139, 103, 123}, -{127, 91, 111}, {119, 83, 99}, {107, 75, 87}, { 95, 63, 75}, -{ 87, 55, 67}, { 75, 47, 55}, { 67, 39, 47}, { 55, 31, 35}, -{ 43, 23, 27}, { 35, 19, 19}, { 23, 11, 11}, { 15, 7, 7}, -{187, 115, 159}, {175, 107, 143}, {163, 95, 131}, {151, 87, 119}, -{139, 79, 107}, {127, 75, 95}, {115, 67, 83}, {107, 59, 75}, -{ 95, 51, 63}, { 83, 43, 55}, { 71, 35, 43}, { 59, 31, 35}, -{ 47, 23, 27}, { 35, 19, 19}, { 23, 11, 11}, { 15, 7, 7}, -{219, 195, 187}, {203, 179, 167}, {191, 163, 155}, {175, 151, 139}, -{163, 135, 123}, {151, 123, 111}, {135, 111, 95}, {123, 99, 83}, -{107, 87, 71}, { 95, 75, 59}, { 83, 63, 51}, { 67, 51, 39}, -{ 55, 43, 31}, { 39, 31, 23}, { 27, 19, 15}, { 15, 11, 7}, -{111, 131, 123}, {103, 123, 111}, { 95, 115, 103}, { 87, 107, 95}, -{ 79, 99, 87}, { 71, 91, 79}, { 63, 83, 71}, { 55, 75, 63}, -{ 47, 67, 55}, { 43, 59, 47}, { 35, 51, 39}, { 31, 43, 31}, -{ 23, 35, 23}, { 15, 27, 19}, { 11, 19, 11}, { 7, 11, 7}, -{255, 243, 27}, {239, 223, 23}, {219, 203, 19}, {203, 183, 15}, -{187, 167, 15}, {171, 151, 11}, {155, 131, 7}, {139, 115, 7}, -{123, 99, 7}, {107, 83, 0}, { 91, 71, 0}, { 75, 55, 0}, -{ 59, 43, 0}, { 43, 31, 0}, { 27, 15, 0}, { 11, 7, 0}, -{ 0, 0, 255}, { 11, 11, 239}, { 19, 19, 223}, { 27, 27, 207}, -{ 35, 35, 191}, { 43, 43, 175}, { 47, 47, 159}, { 47, 47, 143}, -{ 47, 47, 127}, { 47, 47, 111}, { 47, 47, 95}, { 43, 43, 79}, -{ 35, 35, 63}, { 27, 27, 47}, { 19, 19, 31}, { 11, 11, 15}, -{ 43, 0, 0}, { 59, 0, 0}, { 75, 7, 0}, { 95, 7, 0}, -{111, 15, 0}, {127, 23, 7}, {147, 31, 7}, {163, 39, 11}, -{183, 51, 15}, {195, 75, 27}, {207, 99, 43}, {219, 127, 59}, -{227, 151, 79}, {231, 171, 95}, {239, 191, 119}, {247, 211, 139}, -{167, 123, 59}, {183, 155, 55}, {199, 195, 55}, {231, 227, 87}, -{127, 191, 255}, {171, 231, 255}, {215, 255, 255}, {103, 0, 0}, -{139, 0, 0}, {179, 0, 0}, {215, 0, 0}, {255, 0, 0}, -{255, 243, 147}, {255, 247, 199}, {255, 255, 255}, {159, 91, 83} }; - - -#endif // !! AI_MDL_DEFAULTLMP_H_INC diff --git a/libs/assimp/code/AssetLib/MDL/MDLFileData.h b/libs/assimp/code/AssetLib/MDL/MDLFileData.h deleted file mode 100644 index 7ec2afe..0000000 --- a/libs/assimp/code/AssetLib/MDL/MDLFileData.h +++ /dev/null @@ -1,945 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - - -/** - * @file MDLFileData.h - * @brief Definition of in-memory structures for the MDL file format. - * - * The specification has been taken from various sources on the internet. - * - http://tfc.duke.free.fr/coding/mdl-specs-en.html - * - Conitec's MED SDK - * - Many quite long HEX-editor sessions - */ - -#ifndef AI_MDLFILEHELPER_H_INC -#define AI_MDLFILEHELPER_H_INC - -#include <assimp/anim.h> -#include <assimp/mesh.h> -#include <assimp/Compiler/pushpack1.h> -#include <assimp/ByteSwapper.h> -#include <stdint.h> -#include <vector> - -struct aiMaterial; - -namespace Assimp { -namespace MDL { - -// ------------------------------------------------------------------------------------- -// to make it easier for us, we test the magic word against both "endianesses" - -// magic bytes used in Quake 1 MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDPO") -#define AI_MDL_MAGIC_NUMBER_LE AI_MAKE_MAGIC("OPDI") - -// magic bytes used in GameStudio A<very low> MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE_GS3 AI_MAKE_MAGIC("MDL2") -#define AI_MDL_MAGIC_NUMBER_LE_GS3 AI_MAKE_MAGIC("2LDM") - -// magic bytes used in GameStudio A4 MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE_GS4 AI_MAKE_MAGIC("MDL3") -#define AI_MDL_MAGIC_NUMBER_LE_GS4 AI_MAKE_MAGIC("3LDM") - -// magic bytes used in GameStudio A5+ MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE_GS5a AI_MAKE_MAGIC("MDL4") -#define AI_MDL_MAGIC_NUMBER_LE_GS5a AI_MAKE_MAGIC("4LDM") -#define AI_MDL_MAGIC_NUMBER_BE_GS5b AI_MAKE_MAGIC("MDL5") -#define AI_MDL_MAGIC_NUMBER_LE_GS5b AI_MAKE_MAGIC("5LDM") - -// magic bytes used in GameStudio A7+ MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE_GS7 AI_MAKE_MAGIC("MDL7") -#define AI_MDL_MAGIC_NUMBER_LE_GS7 AI_MAKE_MAGIC("7LDM") - -// common limitations for Quake1 meshes. The loader does not check them, -// (however it warns) but models should not exceed these limits. -#if (!defined AI_MDL_VERSION) -# define AI_MDL_VERSION 6 -#endif -#if (!defined AI_MDL_MAX_FRAMES) -# define AI_MDL_MAX_FRAMES 256 -#endif -#if (!defined AI_MDL_MAX_UVS) -# define AI_MDL_MAX_UVS 1024 -#endif -#if (!defined AI_MDL_MAX_VERTS) -# define AI_MDL_MAX_VERTS 1024 -#endif -#if (!defined AI_MDL_MAX_TRIANGLES) -# define AI_MDL_MAX_TRIANGLES 2048 -#endif - -// material key that is set for dummy materials that are -// just referencing another material -#if (!defined AI_MDL7_REFERRER_MATERIAL) -# define AI_MDL7_REFERRER_MATERIAL "&&&referrer&&&",0,0 -#endif - -// ------------------------------------------------------------------------------------- -/** \struct Header - * \brief Data structure for the MDL main header - */ -struct Header { - //! magic number: "IDPO" - uint32_t ident; - - //! version number: 6 - int32_t version; - - //! scale factors for each axis - ai_real scale[3]; - - //! translation factors for each axis - ai_real translate[3]; - - //! bounding radius of the mesh - float boundingradius; - - //! Position of the viewer's exe. Ignored - ai_real vEyePos[3]; - - //! Number of textures - int32_t num_skins; - - //! Texture width in pixels - int32_t skinwidth; - - //! Texture height in pixels - int32_t skinheight; - - //! Number of vertices contained in the file - int32_t num_verts; - - //! Number of triangles contained in the file - int32_t num_tris; - - //! Number of frames contained in the file - int32_t num_frames; - - //! 0 = synchron, 1 = random . Ignored - //! (MDLn formats: number of texture coordinates) - int32_t synctype; - - //! State flag - int32_t flags; - - //! Could be the total size of the file (and not a float) - float size; -} PACK_STRUCT; - - -// ------------------------------------------------------------------------------------- -/** \struct Header_MDL7 - * \brief Data structure for the MDL 7 main header - */ -struct Header_MDL7 { - //! magic number: "MDL7" - char ident[4]; - - //! Version number. Ignored - int32_t version; - - //! Number of bones in file - uint32_t bones_num; - - //! Number of groups in file - uint32_t groups_num; - - //! Size of data in the file - uint32_t data_size; - - //! Ignored. Used to store entity specific information - int32_t entlump_size; - - //! Ignored. Used to store MED related data - int32_t medlump_size; - - //! Size of the Bone_MDL7 data structure used in the file - uint16_t bone_stc_size; - - //! Size of the Skin_MDL 7 data structure used in the file - uint16_t skin_stc_size; - - //! Size of a single color (e.g. in a material) - uint16_t colorvalue_stc_size; - - //! Size of the Material_MDL7 data structure used in the file - uint16_t material_stc_size; - - //! Size of a texture coordinate set in the file - uint16_t skinpoint_stc_size; - - //! Size of a triangle in the file - uint16_t triangle_stc_size; - - //! Size of a normal vertex in the file - uint16_t mainvertex_stc_size; - - //! Size of a per-frame animated vertex in the file - //! (this is not supported) - uint16_t framevertex_stc_size; - - //! Size of a bone animation matrix - uint16_t bonetrans_stc_size; - - //! Size of the Frame_MDL7 data structure used in the file - uint16_t frame_stc_size; -} PACK_STRUCT; - - -// ------------------------------------------------------------------------------------- -/** \struct Bone_MDL7 - * \brief Data structure for a bone in a MDL7 file - */ -struct Bone_MDL7 { - //! Index of the parent bone of *this* bone. 0xffff means: - //! "hey, I have no parent, I'm an orphan" - uint16_t parent_index; - uint8_t _unused_[2]; - - //! Relative position of the bone (relative to the - //! parent bone) - float x,y,z; - - //! Optional name of the bone - char name[1 /* DUMMY SIZE */]; -} PACK_STRUCT; - -#if (!defined AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS) -# define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS (16 + 20) -#endif - -#if (!defined AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS) -# define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS (16 + 32) -#endif - -#if (!defined AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE) -# define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE (16) -#endif - -#if (!defined AI_MDL7_MAX_GROUPNAMESIZE) -# define AI_MDL7_MAX_GROUPNAMESIZE 16 -#endif // ! AI_MDL7_MAX_GROUPNAMESIZE - -// ------------------------------------------------------------------------------------- -/** \struct Group_MDL7 - * \brief Group in a MDL7 file - */ -struct Group_MDL7 { - //! = '1' -> triangle based Mesh - unsigned char typ; - - int8_t deformers; - int8_t max_weights; - int8_t _unused_; - - //! size of data for this group in bytes ( MD7_GROUP stc. included). - int32_t groupdata_size; - char name[AI_MDL7_MAX_GROUPNAMESIZE]; - - //! Number of skins - int32_t numskins; - - //! Number of texture coordinates - int32_t num_stpts; - - //! Number of triangles - int32_t numtris; - - //! Number of vertices - int32_t numverts; - - //! Number of frames - int32_t numframes; -} PACK_STRUCT; - -#define AI_MDL7_SKINTYPE_MIPFLAG 0x08 -#define AI_MDL7_SKINTYPE_MATERIAL 0x10 -#define AI_MDL7_SKINTYPE_MATERIAL_ASCDEF 0x20 -#define AI_MDL7_SKINTYPE_RGBFLAG 0x80 - -#if (!defined AI_MDL7_MAX_BONENAMESIZE) -# define AI_MDL7_MAX_BONENAMESIZE 20 -#endif // !! AI_MDL7_MAX_BONENAMESIZE - -// ------------------------------------------------------------------------------------- -/** \struct Deformer_MDL7 - * \brief Deformer in a MDL7 file - */ -struct Deformer_MDL7 { - int8_t deformer_version; // 0 - int8_t deformer_typ; // 0 - bones - int8_t _unused_[2]; - int32_t group_index; - int32_t elements; - int32_t deformerdata_size; -} PACK_STRUCT; - - -// ------------------------------------------------------------------------------------- -/** \struct DeformerElement_MDL7 - * \brief Deformer element in a MDL7 file - */ -struct DeformerElement_MDL7 { - //! bei deformer_typ==0 (==bones) element_index == bone index - int32_t element_index; - char element_name[AI_MDL7_MAX_BONENAMESIZE]; - int32_t weights; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct DeformerWeight_MDL7 - * \brief Deformer weight in a MDL7 file - */ -struct DeformerWeight_MDL7 { - //! for deformer_typ==0 (==bones) index == vertex index - int32_t index; - float weight; -} PACK_STRUCT; - -// don't know why this was in the original headers ... -typedef int32_t MD7_MATERIAL_ASCDEFSIZE; - -// ------------------------------------------------------------------------------------- -/** \struct ColorValue_MDL7 - * \brief Data structure for a color value in a MDL7 file - */ -struct ColorValue_MDL7 { - float r,g,b,a; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct Material_MDL7 - * \brief Data structure for a Material in a MDL7 file - */ -struct Material_MDL7 { - //! Diffuse base color of the material - ColorValue_MDL7 Diffuse; - - //! Ambient base color of the material - ColorValue_MDL7 Ambient; - - //! Specular base color of the material - ColorValue_MDL7 Specular; - - //! Emissive base color of the material - ColorValue_MDL7 Emissive; - - //! Phong power - float Power; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct Skin - * \brief Skin data structure #1 - used by Quake1, MDL2, MDL3 and MDL4 - */ -struct Skin { - //! 0 = single (Skin), 1 = group (GroupSkin) - //! For MDL3-5: Defines the type of the skin and there - //! fore the size of the data to skip: - //------------------------------------------------------- - //! 2 for 565 RGB, - //! 3 for 4444 ARGB, - //! 10 for 565 mipmapped, - //! 11 for 4444 mipmapped (bpp = 2), - //! 12 for 888 RGB mipmapped (bpp = 3), - //! 13 for 8888 ARGB mipmapped (bpp = 4) - //------------------------------------------------------- - int32_t group; - - //! Texture data - uint8_t *data; -} PACK_STRUCT; - - -// ------------------------------------------------------------------------------------- -/** \struct Skin - * \brief Skin data structure #2 - used by MDL5, MDL6 and MDL7 - * \see Skin - */ -struct Skin_MDL5 { - int32_t size, width, height; - uint8_t *data; -} PACK_STRUCT; - -// maximum length of texture file name -#if (!defined AI_MDL7_MAX_TEXNAMESIZE) -# define AI_MDL7_MAX_TEXNAMESIZE 0x10 -#endif - -// --------------------------------------------------------------------------- -/** \struct Skin_MDL7 - * \brief Skin data structure #3 - used by MDL7 and HMP7 - */ -struct Skin_MDL7 { - uint8_t typ; - int8_t _unused_[3]; - int32_t width; - int32_t height; - char texture_name[AI_MDL7_MAX_TEXNAMESIZE]; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct RGB565 - * \brief Data structure for a RGB565 pixel in a texture - */ -struct RGB565 { - uint16_t r : 5; - uint16_t g : 6; - uint16_t b : 5; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct ARGB4 - * \brief Data structure for a ARGB4444 pixel in a texture - */ -struct ARGB4 { - uint16_t a : 4; - uint16_t r : 4; - uint16_t g : 4; - uint16_t b : 4; -} /*PACK_STRUCT*/; - -// ------------------------------------------------------------------------------------- -/** \struct GroupSkin - * \brief Skin data structure #2 (group of pictures) - */ -struct GroupSkin { - //! 0 = single (Skin), 1 = group (GroupSkin) - int32_t group; - - //! Number of images - int32_t nb; - - //! Time for each image - float *time; - - //! Data of each image - uint8_t **data; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct TexCoord - * \brief Texture coordinate data structure used by the Quake1 MDL format - */ -struct TexCoord { - //! Is the vertex on the noundary between front and back piece? - int32_t onseam; - - //! Texture coordinate in the tx direction - int32_t s; - - //! Texture coordinate in the ty direction - int32_t t; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct TexCoord_MDL3 - * \brief Data structure for an UV coordinate in the 3DGS MDL3 format - */ -struct TexCoord_MDL3 { - //! position, horizontally in range 0..skinwidth-1 - int16_t u; - - //! position, vertically in range 0..skinheight-1 - int16_t v; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct TexCoord_MDL7 - * \brief Data structure for an UV coordinate in the 3DGS MDL7 format - */ -struct TexCoord_MDL7 { - //! position, horizontally in range 0..1 - float u; - - //! position, vertically in range 0..1 - float v; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct SkinSet_MDL7 - * \brief Skin set data structure for the 3DGS MDL7 format - * MDL7 references UV coordinates per face via an index list. - * This allows the use of multiple skins per face with just one - * UV coordinate set. - */ -struct SkinSet_MDL7 -{ - //! Index into the UV coordinate list - uint16_t st_index[3]; // size 6 - - //! Material index - int32_t material; // size 4 -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct Triangle - * \brief Triangle data structure for the Quake1 MDL format - */ -struct Triangle -{ - //! 0 = backface, 1 = frontface - int32_t facesfront; - - //! Vertex indices - int32_t vertex[3]; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct Triangle_MDL3 - * \brief Triangle data structure for the 3DGS MDL3 format - */ -struct Triangle_MDL3 -{ - //! Index of 3 3D vertices in range 0..numverts - uint16_t index_xyz[3]; - - //! Index of 3 skin vertices in range 0..numskinverts - uint16_t index_uv[3]; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct Triangle_MDL7 - * \brief Triangle data structure for the 3DGS MDL7 format - */ -struct Triangle_MDL7 -{ - //! Vertex indices - uint16_t v_index[3]; // size 6 - - //! Two skinsets. The second will be used for multi-texturing - SkinSet_MDL7 skinsets[2]; -} PACK_STRUCT; - -#if (!defined AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) -# define AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV (6+sizeof(SkinSet_MDL7)-sizeof(uint32_t)) -#endif -#if (!defined AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX) -# define AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX (6+sizeof(SkinSet_MDL7)) -#endif -#if (!defined AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) -# define AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV (6+2*sizeof(SkinSet_MDL7)) -#endif - -// Helper constants for Triangle::facesfront -#if (!defined AI_MDL_BACKFACE) -# define AI_MDL_BACKFACE 0x0 -#endif -#if (!defined AI_MDL_FRONTFACE) -# define AI_MDL_FRONTFACE 0x1 -#endif - -// ------------------------------------------------------------------------------------- -/** \struct Vertex - * \brief Vertex data structure - */ -struct Vertex -{ - uint8_t v[3]; - uint8_t normalIndex; -} PACK_STRUCT; - - -// ------------------------------------------------------------------------------------- -struct Vertex_MDL4 -{ - uint16_t v[3]; - uint8_t normalIndex; - uint8_t unused; -} PACK_STRUCT; - -#define AI_MDL7_FRAMEVERTEX120503_STCSIZE 16 -#define AI_MDL7_FRAMEVERTEX030305_STCSIZE 26 - -// ------------------------------------------------------------------------------------- -/** \struct Vertex_MDL7 - * \brief Vertex data structure used in MDL7 files - */ -struct Vertex_MDL7 -{ - float x,y,z; - uint16_t vertindex; // = bone index - union { - uint8_t norm162index; - float norm[3]; - }; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct BoneTransform_MDL7 - * \brief bone transformation matrix structure used in MDL7 files - */ -struct BoneTransform_MDL7 -{ - //! 4*3 - float m [4*4]; - - //! the index of this vertex, 0.. header::bones_num - 1 - uint16_t bone_index; - - //! I HATE 3DGS AND THE SILLY DEVELOPER WHO DESIGNED - //! THIS STUPID FILE FORMAT! - int8_t _unused_[2]; -} PACK_STRUCT; - - -#define AI_MDL7_MAX_FRAMENAMESIZE 16 - -// ------------------------------------------------------------------------------------- -/** \struct Frame_MDL7 - * \brief Frame data structure used by MDL7 files - */ -struct Frame_MDL7 -{ - char frame_name[AI_MDL7_MAX_FRAMENAMESIZE]; - uint32_t vertices_count; - uint32_t transmatrix_count; -}; - - -// ------------------------------------------------------------------------------------- -/** \struct SimpleFrame - * \brief Data structure for a simple frame - */ -struct SimpleFrame -{ - //! Minimum vertex of the bounding box - Vertex bboxmin; - - //! Maximum vertex of the bounding box - Vertex bboxmax; - - //! Name of the frame - char name[16]; - - //! Vertex list of the frame - Vertex *verts; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct Frame - * \brief Model frame data structure - */ -struct Frame -{ - //! 0 = simple frame, !0 = group frame - int32_t type; - - //! Frame data - SimpleFrame frame; -} PACK_STRUCT; - - -// ------------------------------------------------------------------------------------- -struct SimpleFrame_MDLn_SP -{ - //! Minimum vertex of the bounding box - Vertex_MDL4 bboxmin; - - //! Maximum vertex of the bounding box - Vertex_MDL4 bboxmax; - - //! Name of the frame - char name[16]; - - //! Vertex list of the frame - Vertex_MDL4 *verts; -} PACK_STRUCT; - -// ------------------------------------------------------------------------------------- -/** \struct GroupFrame - * \brief Data structure for a group of frames - */ -struct GroupFrame -{ - //! 0 = simple frame, !0 = group frame - int32_t type; - - int32_t numframes; - - //! Minimum vertex for all single frames - Vertex min; - - //! Maximum vertex for all single frames - Vertex max; - - //! List of times for all single frames - float *times; - - //! List of single frames - SimpleFrame *frames; -} PACK_STRUCT; - -#include <assimp/Compiler/poppack1.h> - -// ------------------------------------------------------------------------------------- -/** \struct IntFace_MDL7 - * \brief Internal data structure to temporarily represent a face - */ -struct IntFace_MDL7 { - // provide a constructor for our own convenience - IntFace_MDL7() AI_NO_EXCEPT { - ::memset( mIndices, 0, sizeof(uint32_t) *3); - ::memset( iMatIndex, 0, sizeof( unsigned int) *2); - } - - //! Vertex indices - uint32_t mIndices[3]; - - //! Material index (maximally two channels, which are joined later) - unsigned int iMatIndex[2]; -}; - -// ------------------------------------------------------------------------------------- -/** \struct IntMaterial_MDL7 - * \brief Internal data structure to temporarily represent a material - * which has been created from two single materials along with the - * original material indices. - */ -struct IntMaterial_MDL7 { - // provide a constructor for our own convenience - IntMaterial_MDL7() AI_NO_EXCEPT - : pcMat( nullptr ) { - ::memset( iOldMatIndices, 0, sizeof(unsigned int) *2); - } - - //! Material instance - aiMaterial* pcMat; - - //! Old material indices - unsigned int iOldMatIndices[2]; -}; - -// ------------------------------------------------------------------------------------- -/** \struct IntBone_MDL7 - * \brief Internal data structure to represent a bone in a MDL7 file with - * all of its animation channels assigned to it. - */ -struct IntBone_MDL7 : aiBone -{ - //! Default constructor - IntBone_MDL7() AI_NO_EXCEPT : iParent (0xffff) - { - pkeyPositions.reserve(30); - pkeyScalings.reserve(30); - pkeyRotations.reserve(30); - } - - //! Parent bone of the bone - uint64_t iParent; - - //! Relative position of the bone - aiVector3D vPosition; - - //! Array of position keys - std::vector<aiVectorKey> pkeyPositions; - - //! Array of scaling keys - std::vector<aiVectorKey> pkeyScalings; - - //! Array of rotation keys - std::vector<aiQuatKey> pkeyRotations; -}; - -// ------------------------------------------------------------------------------------- -//! Describes a MDL7 frame -struct IntFrameInfo_MDL7 -{ - //! Construction from an existing frame header - IntFrameInfo_MDL7(BE_NCONST MDL::Frame_MDL7* _pcFrame,unsigned int _iIndex) - : iIndex(_iIndex) - , pcFrame(_pcFrame) - {} - - //! Index of the frame - unsigned int iIndex; - - //! Points to the header of the frame - BE_NCONST MDL::Frame_MDL7* pcFrame; -}; - -// ------------------------------------------------------------------------------------- -//! Describes a MDL7 mesh group -struct IntGroupInfo_MDL7 -{ - //! Default constructor - IntGroupInfo_MDL7() AI_NO_EXCEPT - : iIndex(0) - , pcGroup(nullptr) - , pcGroupUVs(nullptr) - , pcGroupTris(nullptr) - , pcGroupVerts(nullptr) - {} - - //! Construction from an existing group header - IntGroupInfo_MDL7(BE_NCONST MDL::Group_MDL7* _pcGroup, unsigned int _iIndex) - : iIndex(_iIndex) - , pcGroup(_pcGroup) - , pcGroupUVs() - , pcGroupTris() - , pcGroupVerts() - {} - - //! Index of the group - unsigned int iIndex; - - //! Points to the header of the group - BE_NCONST MDL::Group_MDL7* pcGroup; - - //! Points to the beginning of the uv coordinate section - BE_NCONST MDL::TexCoord_MDL7* pcGroupUVs; - - //! Points to the beginning of the triangle section - MDL::Triangle_MDL7* pcGroupTris; - - //! Points to the beginning of the vertex section - BE_NCONST MDL::Vertex_MDL7* pcGroupVerts; -}; - -// ------------------------------------------------------------------------------------- -//! Holds the data that belongs to a MDL7 mesh group -struct IntGroupData_MDL7 -{ - IntGroupData_MDL7() AI_NO_EXCEPT - : bNeed2UV(false) - {} - - //! Array of faces that belong to the group - std::vector<MDL::IntFace_MDL7> pcFaces; - - //! Array of vertex positions - std::vector<aiVector3D> vPositions; - - //! Array of vertex normals - std::vector<aiVector3D> vNormals; - - //! Array of bones indices - std::vector<unsigned int> aiBones; - - //! First UV coordinate set - std::vector<aiVector3D> vTextureCoords1; - - //! Optional second UV coordinate set - std::vector<aiVector3D> vTextureCoords2; - - //! Specifies whether there are two texture - //! coordinate sets required - bool bNeed2UV; -}; - -// ------------------------------------------------------------------------------------- -//! Holds data from an MDL7 file that is shared by all mesh groups -struct IntSharedData_MDL7 { - //! Default constructor - IntSharedData_MDL7() AI_NO_EXCEPT - : apcOutBones(), - iNum() - { - abNeedMaterials.reserve(10); - } - - //! Destruction: properly delete all allocated resources - ~IntSharedData_MDL7() - { - // kill all bones - if (this->apcOutBones) - { - for (unsigned int m = 0; m < iNum;++m) - delete this->apcOutBones[m]; - delete[] this->apcOutBones; - } - } - - //! Specifies which materials are used - std::vector<bool> abNeedMaterials; - - //! List of all materials - std::vector<aiMaterial*> pcMats; - - //! List of all bones - IntBone_MDL7** apcOutBones; - - //! number of bones - unsigned int iNum; -}; - -// ------------------------------------------------------------------------------------- -//! Contains input data for GenerateOutputMeshes_3DGS_MDL7 -struct IntSplitGroupData_MDL7 -{ - //! Construction from a given shared data set - IntSplitGroupData_MDL7(IntSharedData_MDL7& _shared, - std::vector<aiMesh*>& _avOutList) - - : aiSplit(), shared(_shared), avOutList(_avOutList) - { - } - - //! Destruction: properly delete all allocated resources - ~IntSplitGroupData_MDL7() - { - // kill all face lists - if(this->aiSplit) - { - for (unsigned int m = 0; m < shared.pcMats.size();++m) - delete this->aiSplit[m]; - delete[] this->aiSplit; - } - } - - //! Contains a list of all faces per material - std::vector<unsigned int>** aiSplit; - - //! Shared data for all groups of the model - IntSharedData_MDL7& shared; - - //! List of meshes - std::vector<aiMesh*>& avOutList; -}; - - -} -} // end namespaces - -#endif // !! AI_MDLFILEHELPER_H_INC diff --git a/libs/assimp/code/AssetLib/MDL/MDLLoader.cpp b/libs/assimp/code/AssetLib/MDL/MDLLoader.cpp deleted file mode 100644 index 1e90c8e..0000000 --- a/libs/assimp/code/AssetLib/MDL/MDLLoader.cpp +++ /dev/null @@ -1,1976 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file MDLLoader.cpp - * @brief Implementation of the main parts of the MDL importer class - * *TODO* Cleanup and further testing of some parts necessary - */ - -// internal headers - -#ifndef ASSIMP_BUILD_NO_MDL_IMPORTER - -#include "AssetLib/MDL/MDLLoader.h" -#include "AssetLib/MD2/MD2FileData.h" -#include "AssetLib/MDL/HalfLife/HL1MDLLoader.h" -#include "AssetLib/MDL/MDLDefaultColorMap.h" - -#include <assimp/StringUtils.h> -#include <assimp/importerdesc.h> -#include <assimp/qnan.h> -#include <assimp/scene.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/IOSystem.hpp> -#include <assimp/Importer.hpp> - -#include <memory> - -using namespace Assimp; - -static const aiImporterDesc desc = { - "Quake Mesh / 3D GameStudio Mesh Importer", - "", - "", - "", - aiImporterFlags_SupportBinaryFlavour, - 0, - 0, - 7, - 0, - "mdl" -}; - -// ------------------------------------------------------------------------------------------------ -// Ugly stuff ... nevermind -#define _AI_MDL7_ACCESS(_data, _index, _limit, _type) \ - (*((const _type *)(((const char *)_data) + _index * _limit))) - -#define _AI_MDL7_ACCESS_PTR(_data, _index, _limit, _type) \ - ((BE_NCONST _type *)(((const char *)_data) + _index * _limit)) - -#define _AI_MDL7_ACCESS_VERT(_data, _index, _limit) \ - _AI_MDL7_ACCESS(_data, _index, _limit, MDL::Vertex_MDL7) - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -MDLImporter::MDLImporter() : - configFrameID(), mBuffer(), iGSFileVersion(), mIOHandler(nullptr), pScene(), iFileSize() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -MDLImporter::~MDLImporter() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. -bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { - static const uint32_t tokens[] = { - AI_MDL_MAGIC_NUMBER_LE_HL2a, - AI_MDL_MAGIC_NUMBER_LE_HL2b, - AI_MDL_MAGIC_NUMBER_LE_GS7, - AI_MDL_MAGIC_NUMBER_LE_GS5b, - AI_MDL_MAGIC_NUMBER_LE_GS5a, - AI_MDL_MAGIC_NUMBER_LE_GS4, - AI_MDL_MAGIC_NUMBER_LE_GS3, - AI_MDL_MAGIC_NUMBER_LE - }; - return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); -} - -// ------------------------------------------------------------------------------------------------ -// Setup configuration properties -void MDLImporter::SetupProperties(const Importer *pImp) { - configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDL_KEYFRAME, -1); - - // The - // AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the - // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. - if (static_cast<unsigned int>(-1) == configFrameID) { - configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME, 0); - } - - // AI_CONFIG_IMPORT_MDL_COLORMAP - palette file - configPalette = pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP, "colormap.lmp"); - - // Read configuration specific to MDL (Half-Life 1). - mHL1ImportSettings.read_animations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATIONS, true); - if (mHL1ImportSettings.read_animations) { - mHL1ImportSettings.read_animation_events = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATION_EVENTS, true); - mHL1ImportSettings.read_blend_controllers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_BLEND_CONTROLLERS, true); - mHL1ImportSettings.read_sequence_transitions = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_SEQUENCE_TRANSITIONS, true); - } - mHL1ImportSettings.read_attachments = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ATTACHMENTS, true); - mHL1ImportSettings.read_bone_controllers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_BONE_CONTROLLERS, true); - mHL1ImportSettings.read_hitboxes = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_HITBOXES, true); - mHL1ImportSettings.read_misc_global_info = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_MISC_GLOBAL_INFO, true); -} - -// ------------------------------------------------------------------------------------------------ -// Get a list of all supported extensions -const aiImporterDesc *MDLImporter::GetInfo() const { - return &desc; -} - -// ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void MDLImporter::InternReadFile(const std::string &pFile, - aiScene *_pScene, IOSystem *pIOHandler) { - pScene = _pScene; - mIOHandler = pIOHandler; - std::unique_ptr<IOStream> file(pIOHandler->Open(pFile)); - - // Check whether we can read from the file - if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open MDL file ", pFile, "."); - } - - // This should work for all other types of MDL files, too ... - // the HL1 sequence group header is one of the smallest, afaik - iFileSize = (unsigned int)file->FileSize(); - if (iFileSize < sizeof(MDL::HalfLife::SequenceHeader_HL1)) { - throw DeadlyImportError("MDL File is too small."); - } - - // delete the file buffer and cleanup. - auto DeleteBufferAndCleanup = [&]() { - if (mBuffer) { - delete[] mBuffer; - mBuffer = nullptr; - } - AI_DEBUG_INVALIDATE_PTR(mIOHandler); - AI_DEBUG_INVALIDATE_PTR(pScene); - }; - - try { - // Allocate storage and copy the contents of the file to a memory buffer - mBuffer = new unsigned char[iFileSize + 1]; - file->Read((void *)mBuffer, 1, iFileSize); - - // Append a binary zero to the end of the buffer. - // this is just for safety that string parsing routines - // find the end of the buffer ... - mBuffer[iFileSize] = '\0'; - const uint32_t iMagicWord = *((uint32_t *)mBuffer); - - // Determine the file subtype and call the appropriate member function - bool is_half_life = false; - - // Original Quake1 format - if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) { - ASSIMP_LOG_DEBUG("MDL subtype: Quake 1, magic word is IDPO"); - iGSFileVersion = 0; - InternReadFile_Quake1(); - } - // GameStudio A<old> MDL2 format - used by some test models that come with 3DGS - else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) { - ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A2, magic word is MDL2"); - iGSFileVersion = 2; - InternReadFile_Quake1(); - } - // GameStudio A4 MDL3 format - else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) { - ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A4, magic word is MDL3"); - iGSFileVersion = 3; - InternReadFile_3DGS_MDL345(); - } - // GameStudio A5+ MDL4 format - else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) { - ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A4, magic word is MDL4"); - iGSFileVersion = 4; - InternReadFile_3DGS_MDL345(); - } - // GameStudio A5+ MDL5 format - else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) { - ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A5, magic word is MDL5"); - iGSFileVersion = 5; - InternReadFile_3DGS_MDL345(); - } - // GameStudio A7 MDL7 format - else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) { - ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A7, magic word is MDL7"); - iGSFileVersion = 7; - InternReadFile_3DGS_MDL7(); - } - // IDST/IDSQ Format (CS:S/HL^2, etc ...) - else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord || - AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord) { - iGSFileVersion = 0; - is_half_life = true; - - HalfLife::HalfLifeMDLBaseHeader *pHeader = (HalfLife::HalfLifeMDLBaseHeader *)mBuffer; - if (pHeader->version == AI_MDL_HL1_VERSION) { - ASSIMP_LOG_DEBUG("MDL subtype: Half-Life 1/Goldsrc Engine, magic word is IDST/IDSQ"); - InternReadFile_HL1(pFile, iMagicWord); - } else { - ASSIMP_LOG_DEBUG("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ"); - InternReadFile_HL2(); - } - } else { - // print the magic word to the log file - throw DeadlyImportError("Unknown MDL subformat ", pFile, - ". Magic word (", ai_str_toprintable((const char *)&iMagicWord, sizeof(iMagicWord)), ") is not known"); - } - - if (is_half_life){ - // Now rotate the whole scene 90 degrees around the z and x axes to convert to internal coordinate system - pScene->mRootNode->mTransformation = aiMatrix4x4( - 0.f, -1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -1.f, 0.f, 0.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - } - else { - // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system - pScene->mRootNode->mTransformation = aiMatrix4x4(1.f, 0.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f); - } - - DeleteBufferAndCleanup(); - } catch (...) { - DeleteBufferAndCleanup(); - throw; - } -} - -// ------------------------------------------------------------------------------------------------ -// Check whether we're still inside the valid file range -void MDLImporter::SizeCheck(const void *szPos) { - if (!szPos || (const unsigned char *)szPos > this->mBuffer + this->iFileSize) { - throw DeadlyImportError("Invalid MDL file. The file is too small " - "or contains invalid data."); - } -} - -// ------------------------------------------------------------------------------------------------ -// Just for debugging purposes -void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) { - ai_assert(nullptr != szFile); - if (!szPos || (const unsigned char *)szPos > mBuffer + iFileSize) { - // remove a directory if there is one - const char *szFilePtr = ::strrchr(szFile, '\\'); - if (!szFilePtr) { - szFilePtr = ::strrchr(szFile, '/'); - if (nullptr == szFilePtr) { - szFilePtr = szFile; - } - } - if (szFilePtr) { - ++szFilePtr; - } - - char szBuffer[1024]; - ::sprintf(szBuffer, "Invalid MDL file. The file is too small " - "or contains invalid data (File: %s Line: %u)", - szFilePtr, iLine); - - throw DeadlyImportError(szBuffer); - } -} - -// ------------------------------------------------------------------------------------------------ -// Validate a quake file header -void MDLImporter::ValidateHeader_Quake1(const MDL::Header *pcHeader) { - // some values may not be nullptr - if (!pcHeader->num_frames) - throw DeadlyImportError("[Quake 1 MDL] There are no frames in the file"); - - if (!pcHeader->num_verts) - throw DeadlyImportError("[Quake 1 MDL] There are no vertices in the file"); - - if (!pcHeader->num_tris) - throw DeadlyImportError("[Quake 1 MDL] There are no triangles in the file"); - - // check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only - if (!this->iGSFileVersion) { - if (pcHeader->num_verts > AI_MDL_MAX_VERTS) - ASSIMP_LOG_WARN("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices"); - - if (pcHeader->num_tris > AI_MDL_MAX_TRIANGLES) - ASSIMP_LOG_WARN("Quake 1 MDL model has more than AI_MDL_MAX_TRIANGLES triangles"); - - if (pcHeader->num_frames > AI_MDL_MAX_FRAMES) - ASSIMP_LOG_WARN("Quake 1 MDL model has more than AI_MDL_MAX_FRAMES frames"); - - // (this does not apply for 3DGS MDLs) - if (!this->iGSFileVersion && pcHeader->version != AI_MDL_VERSION) - ASSIMP_LOG_WARN("Quake 1 MDL model has an unknown version: AI_MDL_VERSION (=6) is " - "the expected file format version"); - if (pcHeader->num_skins && (!pcHeader->skinwidth || !pcHeader->skinheight)) - ASSIMP_LOG_WARN("Skin width or height are 0"); - } -} - -#ifdef AI_BUILD_BIG_ENDIAN -// ------------------------------------------------------------------------------------------------ -void FlipQuakeHeader(BE_NCONST MDL::Header *pcHeader) { - AI_SWAP4(pcHeader->ident); - AI_SWAP4(pcHeader->version); - AI_SWAP4(pcHeader->boundingradius); - AI_SWAP4(pcHeader->flags); - AI_SWAP4(pcHeader->num_frames); - AI_SWAP4(pcHeader->num_skins); - AI_SWAP4(pcHeader->num_tris); - AI_SWAP4(pcHeader->num_verts); - for (unsigned int i = 0; i < 3; ++i) { - AI_SWAP4(pcHeader->scale[i]); - AI_SWAP4(pcHeader->translate[i]); - } - AI_SWAP4(pcHeader->size); - AI_SWAP4(pcHeader->skinheight); - AI_SWAP4(pcHeader->skinwidth); - AI_SWAP4(pcHeader->synctype); -} -#endif - -// ------------------------------------------------------------------------------------------------ -// Read a Quake 1 file -void MDLImporter::InternReadFile_Quake1() { - ai_assert(nullptr != pScene); - - BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header *)this->mBuffer; - -#ifdef AI_BUILD_BIG_ENDIAN - FlipQuakeHeader(pcHeader); -#endif - - ValidateHeader_Quake1(pcHeader); - - // current cursor position in the file - const unsigned char *szCurrent = (const unsigned char *)(pcHeader + 1); - - // need to read all textures - for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins; ++i) { - union { - BE_NCONST MDL::Skin *pcSkin; - BE_NCONST MDL::GroupSkin *pcGroupSkin; - }; - if (szCurrent + sizeof(MDL::Skin) > this->mBuffer + this->iFileSize) { - throw DeadlyImportError("[Quake 1 MDL] Unexpected EOF"); - } - pcSkin = (BE_NCONST MDL::Skin *)szCurrent; - - AI_SWAP4(pcSkin->group); - - // Quake 1 group-skins - if (1 == pcSkin->group) { - AI_SWAP4(pcGroupSkin->nb); - - // need to skip multiple images - const unsigned int iNumImages = (unsigned int)pcGroupSkin->nb; - szCurrent += sizeof(uint32_t) * 2; - - if (0 != iNumImages) { - if (!i) { - // however, create only one output image (the first) - this->CreateTextureARGB8_3DGS_MDL3(szCurrent + iNumImages * sizeof(float)); - } - // go to the end of the skin section / the beginning of the next skin - szCurrent += pcHeader->skinheight * pcHeader->skinwidth + - sizeof(float) * iNumImages; - } - } else { - szCurrent += sizeof(uint32_t); - unsigned int iSkip = i ? UINT_MAX : 0; - CreateTexture_3DGS_MDL4(szCurrent, pcSkin->group, &iSkip); - szCurrent += iSkip; - } - } - // get a pointer to the texture coordinates - BE_NCONST MDL::TexCoord *pcTexCoords = (BE_NCONST MDL::TexCoord *)szCurrent; - szCurrent += sizeof(MDL::TexCoord) * pcHeader->num_verts; - - // get a pointer to the triangles - BE_NCONST MDL::Triangle *pcTriangles = (BE_NCONST MDL::Triangle *)szCurrent; - szCurrent += sizeof(MDL::Triangle) * pcHeader->num_tris; - VALIDATE_FILE_SIZE(szCurrent); - - // now get a pointer to the first frame in the file - BE_NCONST MDL::Frame *pcFrames = (BE_NCONST MDL::Frame *)szCurrent; - MDL::SimpleFrame *pcFirstFrame; - - if (0 == pcFrames->type) { - // get address of single frame - pcFirstFrame = (MDL::SimpleFrame *)&pcFrames->frame; - } else { - // get the first frame in the group - BE_NCONST MDL::GroupFrame *pcFrames2 = (BE_NCONST MDL::GroupFrame *)szCurrent; - pcFirstFrame = (MDL::SimpleFrame *)( szCurrent + sizeof(MDL::GroupFrame::type) + sizeof(MDL::GroupFrame::numframes) - + sizeof(MDL::GroupFrame::min) + sizeof(MDL::GroupFrame::max) + sizeof(*MDL::GroupFrame::times) * pcFrames2->numframes ); - } - BE_NCONST MDL::Vertex *pcVertices = (BE_NCONST MDL::Vertex *)((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); - VALIDATE_FILE_SIZE((const unsigned char *)(pcVertices + pcHeader->num_verts)); - -#ifdef AI_BUILD_BIG_ENDIAN - for (int i = 0; i < pcHeader->num_verts; ++i) { - AI_SWAP4(pcTexCoords[i].onseam); - AI_SWAP4(pcTexCoords[i].s); - AI_SWAP4(pcTexCoords[i].t); - } - - for (int i = 0; i < pcHeader->num_tris; ++i) { - AI_SWAP4(pcTriangles[i].facesfront); - AI_SWAP4(pcTriangles[i].vertex[0]); - AI_SWAP4(pcTriangles[i].vertex[1]); - AI_SWAP4(pcTriangles[i].vertex[2]); - } -#endif - - // setup materials - SetupMaterialProperties_3DGS_MDL5_Quake1(); - - // allocate enough storage to hold all vertices and triangles - aiMesh *pcMesh = new aiMesh(); - - pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - pcMesh->mNumVertices = pcHeader->num_tris * 3; - pcMesh->mNumFaces = pcHeader->num_tris; - pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; - pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mNumUVComponents[0] = 2; - - // there won't be more than one mesh inside the file - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mNumMeshes = 1; - pScene->mRootNode->mMeshes = new unsigned int[1]; - pScene->mRootNode->mMeshes[0] = 0; - pScene->mNumMeshes = 1; - pScene->mMeshes = new aiMesh *[1]; - pScene->mMeshes[0] = pcMesh; - - // now iterate through all triangles - unsigned int iCurrent = 0; - for (unsigned int i = 0; i < (unsigned int)pcHeader->num_tris; ++i) { - pcMesh->mFaces[i].mIndices = new unsigned int[3]; - pcMesh->mFaces[i].mNumIndices = 3; - - unsigned int iTemp = iCurrent; - for (unsigned int c = 0; c < 3; ++c, ++iCurrent) { - pcMesh->mFaces[i].mIndices[c] = iCurrent; - - // read vertices - unsigned int iIndex = pcTriangles->vertex[c]; - if (iIndex >= (unsigned int)pcHeader->num_verts) { - iIndex = pcHeader->num_verts - 1; - ASSIMP_LOG_WARN("Index overflow in Q1-MDL vertex list."); - } - - aiVector3D &vec = pcMesh->mVertices[iCurrent]; - vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; - vec.x += pcHeader->translate[0]; - - vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; - vec.y += pcHeader->translate[1]; - //vec.y *= -1.0f; - - vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; - vec.z += pcHeader->translate[2]; - - // read the normal vector from the precalculated normal table - MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex, pcMesh->mNormals[iCurrent]); - //pcMesh->mNormals[iCurrent].y *= -1.0f; - - // read texture coordinates - float s = (float)pcTexCoords[iIndex].s; - float t = (float)pcTexCoords[iIndex].t; - - // translate texture coordinates - if (0 == pcTriangles->facesfront && 0 != pcTexCoords[iIndex].onseam) { - s += pcHeader->skinwidth * 0.5f; - } - - // Scale s and t to range from 0.0 to 1.0 - pcMesh->mTextureCoords[0][iCurrent].x = (s + 0.5f) / pcHeader->skinwidth; - pcMesh->mTextureCoords[0][iCurrent].y = 1.0f - (t + 0.5f) / pcHeader->skinheight; - } - pcMesh->mFaces[i].mIndices[0] = iTemp + 2; - pcMesh->mFaces[i].mIndices[1] = iTemp + 1; - pcMesh->mFaces[i].mIndices[2] = iTemp + 0; - pcTriangles++; - } - return; -} - -// ------------------------------------------------------------------------------------------------ -// Setup material properties for Quake and older GameStudio files -void MDLImporter::SetupMaterialProperties_3DGS_MDL5_Quake1() { - const MDL::Header *const pcHeader = (const MDL::Header *)this->mBuffer; - - // allocate ONE material - pScene->mMaterials = new aiMaterial *[1]; - pScene->mMaterials[0] = new aiMaterial(); - pScene->mNumMaterials = 1; - - // setup the material's properties - const int iMode = (int)aiShadingMode_Gouraud; - aiMaterial *const pcHelper = (aiMaterial *)pScene->mMaterials[0]; - pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - aiColor4D clr; - if (0 != pcHeader->num_skins && pScene->mNumTextures) { - // can we replace the texture with a single color? - clr = this->ReplaceTextureWithColor(pScene->mTextures[0]); - if (is_not_qnan(clr.r)) { - delete pScene->mTextures[0]; - delete[] pScene->mTextures; - - pScene->mTextures = nullptr; - pScene->mNumTextures = 0; - } else { - clr.b = clr.a = clr.g = clr.r = 1.0f; - aiString szString; - ::memcpy(szString.data, AI_MAKE_EMBEDDED_TEXNAME(0), 3); - szString.length = 2; - pcHelper->AddProperty(&szString, AI_MATKEY_TEXTURE_DIFFUSE(0)); - } - } - - pcHelper->AddProperty<aiColor4D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); - pcHelper->AddProperty<aiColor4D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR); - - clr.r *= 0.05f; - clr.g *= 0.05f; - clr.b *= 0.05f; - clr.a = 1.0f; - pcHelper->AddProperty<aiColor4D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT); -} - -// ------------------------------------------------------------------------------------------------ -// Read a MDL 3,4,5 file -void MDLImporter::InternReadFile_3DGS_MDL345() { - ai_assert(nullptr != pScene); - - // the header of MDL 3/4/5 is nearly identical to the original Quake1 header - BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header *)this->mBuffer; -#ifdef AI_BUILD_BIG_ENDIAN - FlipQuakeHeader(pcHeader); -#endif - ValidateHeader_Quake1(pcHeader); - - // current cursor position in the file - const unsigned char *szCurrent = (const unsigned char *)(pcHeader + 1); - const unsigned char *szEnd = mBuffer + iFileSize; - - // need to read all textures - for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins; ++i) { - if (szCurrent + sizeof(uint32_t) > szEnd) { - throw DeadlyImportError("Texture data past end of file."); - } - BE_NCONST MDL::Skin *pcSkin; - pcSkin = (BE_NCONST MDL::Skin *)szCurrent; - AI_SWAP4(pcSkin->group); - // create one output image - unsigned int iSkip = i ? UINT_MAX : 0; - if (5 <= iGSFileVersion) { - // MDL5 format could contain MIPmaps - CreateTexture_3DGS_MDL5((unsigned char *)pcSkin + sizeof(uint32_t), - pcSkin->group, &iSkip); - } else { - CreateTexture_3DGS_MDL4((unsigned char *)pcSkin + sizeof(uint32_t), - pcSkin->group, &iSkip); - } - // need to skip one image - szCurrent += iSkip + sizeof(uint32_t); - } - // get a pointer to the texture coordinates - BE_NCONST MDL::TexCoord_MDL3 *pcTexCoords = (BE_NCONST MDL::TexCoord_MDL3 *)szCurrent; - szCurrent += sizeof(MDL::TexCoord_MDL3) * pcHeader->synctype; - - // NOTE: for MDLn formats "synctype" corresponds to the number of UV coords - - // get a pointer to the triangles - BE_NCONST MDL::Triangle_MDL3 *pcTriangles = (BE_NCONST MDL::Triangle_MDL3 *)szCurrent; - szCurrent += sizeof(MDL::Triangle_MDL3) * pcHeader->num_tris; - -#ifdef AI_BUILD_BIG_ENDIAN - - for (int i = 0; i < pcHeader->synctype; ++i) { - AI_SWAP2(pcTexCoords[i].u); - AI_SWAP2(pcTexCoords[i].v); - } - - for (int i = 0; i < pcHeader->num_tris; ++i) { - AI_SWAP2(pcTriangles[i].index_xyz[0]); - AI_SWAP2(pcTriangles[i].index_xyz[1]); - AI_SWAP2(pcTriangles[i].index_xyz[2]); - AI_SWAP2(pcTriangles[i].index_uv[0]); - AI_SWAP2(pcTriangles[i].index_uv[1]); - AI_SWAP2(pcTriangles[i].index_uv[2]); - } - -#endif - - VALIDATE_FILE_SIZE(szCurrent); - - // setup materials - SetupMaterialProperties_3DGS_MDL5_Quake1(); - - // allocate enough storage to hold all vertices and triangles - aiMesh *pcMesh = new aiMesh(); - pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - - pcMesh->mNumVertices = pcHeader->num_tris * 3; - pcMesh->mNumFaces = pcHeader->num_tris; - pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; - - // there won't be more than one mesh inside the file - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mNumMeshes = 1; - pScene->mRootNode->mMeshes = new unsigned int[1]; - pScene->mRootNode->mMeshes[0] = 0; - pScene->mNumMeshes = 1; - pScene->mMeshes = new aiMesh *[1]; - pScene->mMeshes[0] = pcMesh; - - // allocate output storage - pcMesh->mNumVertices = (unsigned int)pcHeader->num_tris * 3; - pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; - - if (pcHeader->synctype) { - pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mNumUVComponents[0] = 2; - } - - // now get a pointer to the first frame in the file - BE_NCONST MDL::Frame *pcFrames = (BE_NCONST MDL::Frame *)szCurrent; - AI_SWAP4(pcFrames->type); - - // byte packed vertices - // FIXME: these two snippets below are almost identical ... join them? - ///////////////////////////////////////////////////////////////////////////////////// - if (0 == pcFrames->type || 3 >= this->iGSFileVersion) { - - const MDL::SimpleFrame *pcFirstFrame = (const MDL::SimpleFrame *)(szCurrent + sizeof(uint32_t)); - const MDL::Vertex *pcVertices = (const MDL::Vertex *)((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); - - VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); - - // now iterate through all triangles - unsigned int iCurrent = 0; - for (unsigned int i = 0; i < (unsigned int)pcHeader->num_tris; ++i) { - pcMesh->mFaces[i].mIndices = new unsigned int[3]; - pcMesh->mFaces[i].mNumIndices = 3; - - unsigned int iTemp = iCurrent; - for (unsigned int c = 0; c < 3; ++c, ++iCurrent) { - // read vertices - unsigned int iIndex = pcTriangles->index_xyz[c]; - if (iIndex >= (unsigned int)pcHeader->num_verts) { - iIndex = pcHeader->num_verts - 1; - ASSIMP_LOG_WARN("Index overflow in MDLn vertex list"); - } - - aiVector3D &vec = pcMesh->mVertices[iCurrent]; - vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; - vec.x += pcHeader->translate[0]; - - vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; - vec.y += pcHeader->translate[1]; - // vec.y *= -1.0f; - - vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; - vec.z += pcHeader->translate[2]; - - // read the normal vector from the precalculated normal table - MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex, pcMesh->mNormals[iCurrent]); - // pcMesh->mNormals[iCurrent].y *= -1.0f; - - // read texture coordinates - if (pcHeader->synctype) { - ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent], - pcTexCoords, pcTriangles->index_uv[c]); - } - } - pcMesh->mFaces[i].mIndices[0] = iTemp + 2; - pcMesh->mFaces[i].mIndices[1] = iTemp + 1; - pcMesh->mFaces[i].mIndices[2] = iTemp + 0; - pcTriangles++; - } - - } - // short packed vertices - ///////////////////////////////////////////////////////////////////////////////////// - else { - // now get a pointer to the first frame in the file - const MDL::SimpleFrame_MDLn_SP *pcFirstFrame = (const MDL::SimpleFrame_MDLn_SP *)(szCurrent + sizeof(uint32_t)); - - // get a pointer to the vertices - const MDL::Vertex_MDL4 *pcVertices = (const MDL::Vertex_MDL4 *)((pcFirstFrame->name) + - sizeof(pcFirstFrame->name)); - - VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); - - // now iterate through all triangles - unsigned int iCurrent = 0; - for (unsigned int i = 0; i < (unsigned int)pcHeader->num_tris; ++i) { - pcMesh->mFaces[i].mIndices = new unsigned int[3]; - pcMesh->mFaces[i].mNumIndices = 3; - - unsigned int iTemp = iCurrent; - for (unsigned int c = 0; c < 3; ++c, ++iCurrent) { - // read vertices - unsigned int iIndex = pcTriangles->index_xyz[c]; - if (iIndex >= (unsigned int)pcHeader->num_verts) { - iIndex = pcHeader->num_verts - 1; - ASSIMP_LOG_WARN("Index overflow in MDLn vertex list"); - } - - aiVector3D &vec = pcMesh->mVertices[iCurrent]; - vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; - vec.x += pcHeader->translate[0]; - - vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; - vec.y += pcHeader->translate[1]; - // vec.y *= -1.0f; - - vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; - vec.z += pcHeader->translate[2]; - - // read the normal vector from the precalculated normal table - MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex, pcMesh->mNormals[iCurrent]); - // pcMesh->mNormals[iCurrent].y *= -1.0f; - - // read texture coordinates - if (pcHeader->synctype) { - ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent], - pcTexCoords, pcTriangles->index_uv[c]); - } - } - pcMesh->mFaces[i].mIndices[0] = iTemp + 2; - pcMesh->mFaces[i].mIndices[1] = iTemp + 1; - pcMesh->mFaces[i].mIndices[2] = iTemp + 0; - pcTriangles++; - } - } - - // For MDL5 we will need to build valid texture coordinates - // basing upon the file loaded (only support one file as skin) - if (0x5 == iGSFileVersion) - CalculateUVCoordinates_MDL5(); - return; -} - -// ------------------------------------------------------------------------------------------------ -// Get a single UV coordinate for Quake and older GameStudio files -void MDLImporter::ImportUVCoordinate_3DGS_MDL345( - aiVector3D &vOut, - const MDL::TexCoord_MDL3 *pcSrc, - unsigned int iIndex) { - ai_assert(nullptr != pcSrc); - const MDL::Header *const pcHeader = (const MDL::Header *)this->mBuffer; - - // validate UV indices - if (iIndex >= (unsigned int)pcHeader->synctype) { - iIndex = pcHeader->synctype - 1; - ASSIMP_LOG_WARN("Index overflow in MDLn UV coord list"); - } - - float s = (float)pcSrc[iIndex].u; - float t = (float)pcSrc[iIndex].v; - - // Scale s and t to range from 0.0 to 1.0 - if (0x5 != iGSFileVersion) { - s = (s + 0.5f) / pcHeader->skinwidth; - t = 1.0f - (t + 0.5f) / pcHeader->skinheight; - } - - vOut.x = s; - vOut.y = t; - vOut.z = 0.0f; -} - -// ------------------------------------------------------------------------------------------------ -// Compute UV coordinates for a MDL5 file -void MDLImporter::CalculateUVCoordinates_MDL5() { - const MDL::Header *const pcHeader = (const MDL::Header *)this->mBuffer; - if (pcHeader->num_skins && this->pScene->mNumTextures) { - const aiTexture *pcTex = this->pScene->mTextures[0]; - - // if the file is loaded in DDS format: get the size of the - // texture from the header of the DDS file - // skip three DWORDs and read first height, then the width - unsigned int iWidth, iHeight; - if (!pcTex->mHeight) { - const uint32_t *piPtr = (uint32_t *)pcTex->pcData; - - piPtr += 3; - iHeight = (unsigned int)*piPtr++; - iWidth = (unsigned int)*piPtr; - if (!iHeight || !iWidth) { - ASSIMP_LOG_WARN("Either the width or the height of the " - "embedded DDS texture is zero. Unable to compute final texture " - "coordinates. The texture coordinates remain in their original " - "0-x/0-y (x,y = texture size) range."); - iWidth = 1; - iHeight = 1; - } - } else { - iWidth = pcTex->mWidth; - iHeight = pcTex->mHeight; - } - - if (1 != iWidth || 1 != iHeight) { - const float fWidth = (float)iWidth; - const float fHeight = (float)iHeight; - aiMesh *pcMesh = this->pScene->mMeshes[0]; - for (unsigned int i = 0; i < pcMesh->mNumVertices; ++i) { - pcMesh->mTextureCoords[0][i].x /= fWidth; - pcMesh->mTextureCoords[0][i].y /= fHeight; - pcMesh->mTextureCoords[0][i].y = 1.0f - pcMesh->mTextureCoords[0][i].y; // DX to OGL - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Validate the header of a MDL7 file -void MDLImporter::ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7 *pcHeader) { - ai_assert(nullptr != pcHeader); - - // There are some fixed sizes ... - if (sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size) { - throw DeadlyImportError( - "[3DGS MDL7] sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size"); - } - if (sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size) { - throw DeadlyImportError( - "[3DGS MDL7] sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size"); - } - if (sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size) { - throw DeadlyImportError( - "sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size"); - } - - // if there are no groups ... how should we load such a file? - if (!pcHeader->groups_num) { - throw DeadlyImportError("[3DGS MDL7] No frames found"); - } -} - -// ------------------------------------------------------------------------------------------------ -// resolve bone animation matrices -void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7 **apcOutBones) { - const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7 *)this->mBuffer; - const MDL::Bone_MDL7 *pcBones = (const MDL::Bone_MDL7 *)(pcHeader + 1); - ai_assert(nullptr != apcOutBones); - - // first find the bone that has NO parent, calculate the - // animation matrix for it, then go on and search for the next parent - // index (0) and so on until we can't find a new node. - uint16_t iParent = 0xffff; - uint32_t iIterations = 0; - while (iIterations++ < pcHeader->bones_num) { - for (uint32_t iBone = 0; iBone < pcHeader->bones_num; ++iBone) { - BE_NCONST MDL::Bone_MDL7 *pcBone = _AI_MDL7_ACCESS_PTR(pcBones, iBone, - pcHeader->bone_stc_size, MDL::Bone_MDL7); - - AI_SWAP2(pcBone->parent_index); - AI_SWAP4(pcBone->x); - AI_SWAP4(pcBone->y); - AI_SWAP4(pcBone->z); - - if (iParent == pcBone->parent_index) { - // MDL7 readme - //////////////////////////////////////////////////////////////// - /* - The animation matrix is then calculated the following way: - - vector3 bPos = <absolute bone position> - matrix44 laM; // local animation matrix - sphrvector key_rotate = <bone rotation> - - matrix44 m1,m2; - create_trans_matrix(m1, -bPos.x, -bPos.y, -bPos.z); - create_trans_matrix(m2, -bPos.x, -bPos.y, -bPos.z); - - create_rotation_matrix(laM,key_rotate); - - laM = sm1 * laM; - laM = laM * sm2; - */ - ///////////////////////////////////////////////////////////////// - - MDL::IntBone_MDL7 *const pcOutBone = apcOutBones[iBone]; - - // store the parent index of the bone - pcOutBone->iParent = pcBone->parent_index; - if (0xffff != iParent) { - const MDL::IntBone_MDL7 *pcParentBone = apcOutBones[iParent]; - pcOutBone->mOffsetMatrix.a4 = -pcParentBone->vPosition.x; - pcOutBone->mOffsetMatrix.b4 = -pcParentBone->vPosition.y; - pcOutBone->mOffsetMatrix.c4 = -pcParentBone->vPosition.z; - } - pcOutBone->vPosition.x = pcBone->x; - pcOutBone->vPosition.y = pcBone->y; - pcOutBone->vPosition.z = pcBone->z; - pcOutBone->mOffsetMatrix.a4 -= pcBone->x; - pcOutBone->mOffsetMatrix.b4 -= pcBone->y; - pcOutBone->mOffsetMatrix.c4 -= pcBone->z; - - if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) { - // no real name for our poor bone is specified :-( - pcOutBone->mName.length = ai_snprintf(pcOutBone->mName.data, MAXLEN, - "UnnamedBone_%i", iBone); - } else { - // Make sure we won't run over the buffer's end if there is no - // terminal 0 character (however the documentation says there - // should be one) - uint32_t iMaxLen = pcHeader->bone_stc_size - 16; - for (uint32_t qq = 0; qq < iMaxLen; ++qq) { - if (!pcBone->name[qq]) { - iMaxLen = qq; - break; - } - } - - // store the name of the bone - pcOutBone->mName.length = (size_t)iMaxLen; - ::memcpy(pcOutBone->mName.data, pcBone->name, pcOutBone->mName.length); - pcOutBone->mName.data[pcOutBone->mName.length] = '\0'; - } - } - } - ++iParent; - } -} - -// ------------------------------------------------------------------------------------------------ -// read bones from a MDL7 file -MDL::IntBone_MDL7 **MDLImporter::LoadBones_3DGS_MDL7() { - const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7 *)this->mBuffer; - if (pcHeader->bones_num) { - // validate the size of the bone data structure in the file - if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS != pcHeader->bone_stc_size && - AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS != pcHeader->bone_stc_size && - AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE != pcHeader->bone_stc_size) { - ASSIMP_LOG_WARN("Unknown size of bone data structure"); - return nullptr; - } - - MDL::IntBone_MDL7 **apcBonesOut = new MDL::IntBone_MDL7 *[pcHeader->bones_num]; - for (uint32_t crank = 0; crank < pcHeader->bones_num; ++crank) - apcBonesOut[crank] = new MDL::IntBone_MDL7(); - - // and calculate absolute bone offset matrices ... - CalcAbsBoneMatrices_3DGS_MDL7(apcBonesOut); - return apcBonesOut; - } - return nullptr; -} - -// ------------------------------------------------------------------------------------------------ -// read faces from a MDL7 file -void MDLImporter::ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7 &groupInfo, - MDL::IntGroupData_MDL7 &groupData) { - const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7 *)this->mBuffer; - MDL::Triangle_MDL7 *pcGroupTris = groupInfo.pcGroupTris; - - // iterate through all triangles and build valid display lists - unsigned int iOutIndex = 0; - for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) { - AI_SWAP2(pcGroupTris->v_index[0]); - AI_SWAP2(pcGroupTris->v_index[1]); - AI_SWAP2(pcGroupTris->v_index[2]); - - // iterate through all indices of the current triangle - for (unsigned int c = 0; c < 3; ++c, ++iOutIndex) { - - // validate the vertex index - unsigned int iIndex = pcGroupTris->v_index[c]; - if (iIndex > (unsigned int)groupInfo.pcGroup->numverts) { - // (we might need to read this section a second time - to process frame vertices correctly) - pcGroupTris->v_index[c] = (uint16_t)(iIndex = groupInfo.pcGroup->numverts - 1); - ASSIMP_LOG_WARN("Index overflow in MDL7 vertex list"); - } - - // write the output face index - groupData.pcFaces[iTriangle].mIndices[2 - c] = iOutIndex; - - aiVector3D &vPosition = groupData.vPositions[iOutIndex]; - vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).x; - vPosition.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).y; - vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).z; - - // if we have bones, save the index - if (!groupData.aiBones.empty()) { - groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, - iIndex, pcHeader->mainvertex_stc_size) - .vertindex; - } - - // now read the normal vector - if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) { - // read the full normal vector - aiVector3D &vNormal = groupData.vNormals[iOutIndex]; - vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).norm[0]; - AI_SWAP4(vNormal.x); - vNormal.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).norm[1]; - AI_SWAP4(vNormal.y); - vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, pcHeader->mainvertex_stc_size).norm[2]; - AI_SWAP4(vNormal.z); - } else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) { - // read the normal vector from Quake2's smart table - aiVector3D &vNormal = groupData.vNormals[iOutIndex]; - MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts, iIndex, - pcHeader->mainvertex_stc_size) - .norm162index, - vNormal); - } - // validate and process the first uv coordinate set - if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) { - - if (groupInfo.pcGroup->num_stpts) { - AI_SWAP2(pcGroupTris->skinsets[0].st_index[0]); - AI_SWAP2(pcGroupTris->skinsets[0].st_index[1]); - AI_SWAP2(pcGroupTris->skinsets[0].st_index[2]); - - iIndex = pcGroupTris->skinsets[0].st_index[c]; - if (iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) { - iIndex = groupInfo.pcGroup->num_stpts - 1; - ASSIMP_LOG_WARN("Index overflow in MDL7 UV coordinate list (#1)"); - } - - float u = groupInfo.pcGroupUVs[iIndex].u; - float v = 1.0f - groupInfo.pcGroupUVs[iIndex].v; // DX to OGL - - groupData.vTextureCoords1[iOutIndex].x = u; - groupData.vTextureCoords1[iOutIndex].y = v; - } - // assign the material index, but only if it is existing - if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX) { - AI_SWAP4(pcGroupTris->skinsets[0].material); - groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material; - } - } - // validate and process the second uv coordinate set - if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) { - - if (groupInfo.pcGroup->num_stpts) { - AI_SWAP2(pcGroupTris->skinsets[1].st_index[0]); - AI_SWAP2(pcGroupTris->skinsets[1].st_index[1]); - AI_SWAP2(pcGroupTris->skinsets[1].st_index[2]); - AI_SWAP4(pcGroupTris->skinsets[1].material); - - iIndex = pcGroupTris->skinsets[1].st_index[c]; - if (iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) { - iIndex = groupInfo.pcGroup->num_stpts - 1; - ASSIMP_LOG_WARN("Index overflow in MDL7 UV coordinate list (#2)"); - } - - float u = groupInfo.pcGroupUVs[iIndex].u; - float v = 1.0f - groupInfo.pcGroupUVs[iIndex].v; - - groupData.vTextureCoords2[iOutIndex].x = u; - groupData.vTextureCoords2[iOutIndex].y = v; // DX to OGL - - // check whether we do really need the second texture - // coordinate set ... wastes memory and loading time - if (0 != iIndex && (u != groupData.vTextureCoords1[iOutIndex].x || - v != groupData.vTextureCoords1[iOutIndex].y)) - groupData.bNeed2UV = true; - - // if the material differs, we need a second skin, too - if (pcGroupTris->skinsets[1].material != pcGroupTris->skinsets[0].material) - groupData.bNeed2UV = true; - } - // assign the material index - groupData.pcFaces[iTriangle].iMatIndex[1] = pcGroupTris->skinsets[1].material; - } - } - // get the next triangle in the list - pcGroupTris = (MDL::Triangle_MDL7 *)((const char *)pcGroupTris + pcHeader->triangle_stc_size); - } -} - -// ------------------------------------------------------------------------------------------------ -// handle frames in a MDL7 file -bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7 &groupInfo, - MDL::IntGroupData_MDL7 &groupData, - MDL::IntSharedData_MDL7 &shared, - const unsigned char *szCurrent, - const unsigned char **szCurrentOut) { - ai_assert(nullptr != szCurrent); - ai_assert(nullptr != szCurrentOut); - - const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7 *)mBuffer; - - // if we have no bones we can simply skip all frames, - // otherwise we'll need to process them. - // FIX: If we need another frame than the first we must apply frame vertex replacements ... - for (unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes; ++iFrame) { - MDL::IntFrameInfo_MDL7 frame((BE_NCONST MDL::Frame_MDL7 *)szCurrent, iFrame); - - AI_SWAP4(frame.pcFrame->vertices_count); - AI_SWAP4(frame.pcFrame->transmatrix_count); - - const unsigned int iAdd = pcHeader->frame_stc_size + - frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size + - frame.pcFrame->transmatrix_count * pcHeader->bonetrans_stc_size; - - if (((const char *)szCurrent - (const char *)pcHeader) + iAdd > (unsigned int)pcHeader->data_size) { - ASSIMP_LOG_WARN("Index overflow in frame area. " - "Ignoring all frames and all further mesh groups, too."); - - // don't parse more groups if we can't even read one - // FIXME: sometimes this seems to occur even for valid files ... - *szCurrentOut = szCurrent; - return false; - } - // our output frame? - if (configFrameID == iFrame) { - BE_NCONST MDL::Vertex_MDL7 *pcFrameVertices = (BE_NCONST MDL::Vertex_MDL7 *)(szCurrent + pcHeader->frame_stc_size); - - for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count; ++qq) { - // I assume this are simple replacements for normal vertices, the bone index serving - // as the index of the vertex to be replaced. - uint16_t iIndex = _AI_MDL7_ACCESS(pcFrameVertices, qq, pcHeader->framevertex_stc_size, MDL::Vertex_MDL7).vertindex; - AI_SWAP2(iIndex); - if (iIndex >= groupInfo.pcGroup->numverts) { - ASSIMP_LOG_WARN("Invalid vertex index in frame vertex section"); - continue; - } - - aiVector3D vPosition, vNormal; - - vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).x; - AI_SWAP4(vPosition.x); - vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).y; - AI_SWAP4(vPosition.y); - vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).z; - AI_SWAP4(vPosition.z); - - // now read the normal vector - if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) { - // read the full normal vector - vNormal.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).norm[0]; - AI_SWAP4(vNormal.x); - vNormal.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).norm[1]; - AI_SWAP4(vNormal.y); - vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, pcHeader->framevertex_stc_size).norm[2]; - AI_SWAP4(vNormal.z); - } else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) { - // read the normal vector from Quake2's smart table - MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices, qq, - pcHeader->framevertex_stc_size) - .norm162index, - vNormal); - } - - // FIXME: O(n^2) at the moment ... - BE_NCONST MDL::Triangle_MDL7 *pcGroupTris = groupInfo.pcGroupTris; - unsigned int iOutIndex = 0; - for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) { - // iterate through all indices of the current triangle - for (unsigned int c = 0; c < 3; ++c, ++iOutIndex) { - // replace the vertex with the new data - const unsigned int iCurIndex = pcGroupTris->v_index[c]; - if (iCurIndex == iIndex) { - groupData.vPositions[iOutIndex] = vPosition; - groupData.vNormals[iOutIndex] = vNormal; - } - } - // get the next triangle in the list - pcGroupTris = (BE_NCONST MDL::Triangle_MDL7 *)((const char *) - pcGroupTris + - pcHeader->triangle_stc_size); - } - } - } - // parse bone trafo matrix keys (only if there are bones ...) - if (shared.apcOutBones) { - ParseBoneTrafoKeys_3DGS_MDL7(groupInfo, frame, shared); - } - szCurrent += iAdd; - } - *szCurrentOut = szCurrent; - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Sort faces by material, handle multiple UVs correctly -void MDLImporter::SortByMaterials_3DGS_MDL7( - const MDL::IntGroupInfo_MDL7 &groupInfo, - MDL::IntGroupData_MDL7 &groupData, - MDL::IntSplitGroupData_MDL7 &splitGroupData) { - const unsigned int iNumMaterials = (unsigned int)splitGroupData.shared.pcMats.size(); - if (!groupData.bNeed2UV) { - // if we don't need a second set of texture coordinates there is no reason to keep it in memory ... - groupData.vTextureCoords2.clear(); - - // allocate the array - splitGroupData.aiSplit = new std::vector<unsigned int> *[iNumMaterials]; - - for (unsigned int m = 0; m < iNumMaterials; ++m) - splitGroupData.aiSplit[m] = new std::vector<unsigned int>(); - - // iterate through all faces and sort by material - for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris; ++iFace) { - // check range - if (groupData.pcFaces[iFace].iMatIndex[0] >= iNumMaterials) { - // use the last material instead - splitGroupData.aiSplit[iNumMaterials - 1]->push_back(iFace); - - // sometimes MED writes -1, but normally only if there is only - // one skin assigned. No warning in this case - if (0xFFFFFFFF != groupData.pcFaces[iFace].iMatIndex[0]) - ASSIMP_LOG_WARN("Index overflow in MDL7 material list [#0]"); - } else - splitGroupData.aiSplit[groupData.pcFaces[iFace].iMatIndex[0]]->push_back(iFace); - } - } else { - // we need to build combined materials for each combination of - std::vector<MDL::IntMaterial_MDL7> avMats; - avMats.reserve(iNumMaterials * 2); - - // fixme: why on the heap? - std::vector<std::vector<unsigned int> *> aiTempSplit(iNumMaterials * 2); - for (unsigned int m = 0; m < iNumMaterials; ++m) - aiTempSplit[m] = new std::vector<unsigned int>(); - - // iterate through all faces and sort by material - for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris; ++iFace) { - // check range - unsigned int iMatIndex = groupData.pcFaces[iFace].iMatIndex[0]; - if (iMatIndex >= iNumMaterials) { - // sometimes MED writes -1, but normally only if there is only - // one skin assigned. No warning in this case - if (UINT_MAX != iMatIndex) - ASSIMP_LOG_WARN("Index overflow in MDL7 material list [#1]"); - iMatIndex = iNumMaterials - 1; - } - unsigned int iMatIndex2 = groupData.pcFaces[iFace].iMatIndex[1]; - - unsigned int iNum = iMatIndex; - if (UINT_MAX != iMatIndex2 && iMatIndex != iMatIndex2) { - if (iMatIndex2 >= iNumMaterials) { - // sometimes MED writes -1, but normally only if there is only - // one skin assigned. No warning in this case - ASSIMP_LOG_WARN("Index overflow in MDL7 material list [#2]"); - iMatIndex2 = iNumMaterials - 1; - } - - // do a slow search in the list ... - iNum = 0; - bool bFound = false; - for (std::vector<MDL::IntMaterial_MDL7>::iterator i = avMats.begin(); i != avMats.end(); ++i, ++iNum) { - if ((*i).iOldMatIndices[0] == iMatIndex && (*i).iOldMatIndices[1] == iMatIndex2) { - // reuse this material - bFound = true; - break; - } - } - if (!bFound) { - // build a new material ... - MDL::IntMaterial_MDL7 sHelper; - sHelper.pcMat = new aiMaterial(); - sHelper.iOldMatIndices[0] = iMatIndex; - sHelper.iOldMatIndices[1] = iMatIndex2; - JoinSkins_3DGS_MDL7(splitGroupData.shared.pcMats[iMatIndex], - splitGroupData.shared.pcMats[iMatIndex2], sHelper.pcMat); - - // and add it to the list - avMats.push_back(sHelper); - iNum = (unsigned int)avMats.size() - 1; - } - // adjust the size of the file array - if (iNum == aiTempSplit.size()) { - aiTempSplit.push_back(new std::vector<unsigned int>()); - } - } - aiTempSplit[iNum]->push_back(iFace); - } - - // now add the newly created materials to the old list - if (0 == groupInfo.iIndex) { - splitGroupData.shared.pcMats.resize(avMats.size()); - for (unsigned int o = 0; o < avMats.size(); ++o) - splitGroupData.shared.pcMats[o] = avMats[o].pcMat; - } else { - // This might result in redundant materials ... - splitGroupData.shared.pcMats.resize(iNumMaterials + avMats.size()); - for (unsigned int o = iNumMaterials; o < avMats.size(); ++o) - splitGroupData.shared.pcMats[o] = avMats[o].pcMat; - } - - // and build the final face-to-material array - splitGroupData.aiSplit = new std::vector<unsigned int> *[aiTempSplit.size()]; - for (unsigned int m = 0; m < iNumMaterials; ++m) - splitGroupData.aiSplit[m] = aiTempSplit[m]; - } -} - -// ------------------------------------------------------------------------------------------------ -// Read a MDL7 file -void MDLImporter::InternReadFile_3DGS_MDL7() { - ai_assert(nullptr != pScene); - - MDL::IntSharedData_MDL7 sharedData; - - // current cursor position in the file - BE_NCONST MDL::Header_MDL7 *pcHeader = (BE_NCONST MDL::Header_MDL7 *)this->mBuffer; - const unsigned char *szCurrent = (const unsigned char *)(pcHeader + 1); - - AI_SWAP4(pcHeader->version); - AI_SWAP4(pcHeader->bones_num); - AI_SWAP4(pcHeader->groups_num); - AI_SWAP4(pcHeader->data_size); - AI_SWAP4(pcHeader->entlump_size); - AI_SWAP4(pcHeader->medlump_size); - AI_SWAP2(pcHeader->bone_stc_size); - AI_SWAP2(pcHeader->skin_stc_size); - AI_SWAP2(pcHeader->colorvalue_stc_size); - AI_SWAP2(pcHeader->material_stc_size); - AI_SWAP2(pcHeader->skinpoint_stc_size); - AI_SWAP2(pcHeader->triangle_stc_size); - AI_SWAP2(pcHeader->mainvertex_stc_size); - AI_SWAP2(pcHeader->framevertex_stc_size); - AI_SWAP2(pcHeader->bonetrans_stc_size); - AI_SWAP2(pcHeader->frame_stc_size); - - // validate the header of the file. There are some structure - // sizes that are expected by the loader to be constant - this->ValidateHeader_3DGS_MDL7(pcHeader); - - // load all bones (they are shared by all groups, so - // we'll need to add them to all groups/meshes later) - // apcBonesOut is a list of all bones or nullptr if they could not been loaded - szCurrent += pcHeader->bones_num * pcHeader->bone_stc_size; - sharedData.apcOutBones = this->LoadBones_3DGS_MDL7(); - - // vector to held all created meshes - std::vector<aiMesh *> *avOutList; - - // 3 meshes per group - that should be OK for most models - avOutList = new std::vector<aiMesh *>[pcHeader->groups_num]; - for (uint32_t i = 0; i < pcHeader->groups_num; ++i) - avOutList[i].reserve(3); - - // buffer to held the names of all groups in the file - const size_t buffersize(AI_MDL7_MAX_GROUPNAMESIZE * pcHeader->groups_num); - char *aszGroupNameBuffer = new char[buffersize]; - - // read all groups - for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num; ++iGroup) { - MDL::IntGroupInfo_MDL7 groupInfo((BE_NCONST MDL::Group_MDL7 *)szCurrent, iGroup); - szCurrent = (const unsigned char *)(groupInfo.pcGroup + 1); - - VALIDATE_FILE_SIZE(szCurrent); - - AI_SWAP4(groupInfo.pcGroup->groupdata_size); - AI_SWAP4(groupInfo.pcGroup->numskins); - AI_SWAP4(groupInfo.pcGroup->num_stpts); - AI_SWAP4(groupInfo.pcGroup->numtris); - AI_SWAP4(groupInfo.pcGroup->numverts); - AI_SWAP4(groupInfo.pcGroup->numframes); - - if (1 != groupInfo.pcGroup->typ) { - // Not a triangle-based mesh - ASSIMP_LOG_WARN("[3DGS MDL7] Not a triangle mesh group. Continuing happily"); - } - - // store the name of the group - const unsigned int ofs = iGroup * AI_MDL7_MAX_GROUPNAMESIZE; - ::memcpy(&aszGroupNameBuffer[ofs], - groupInfo.pcGroup->name, AI_MDL7_MAX_GROUPNAMESIZE); - - // make sure '\0' is at the end - aszGroupNameBuffer[ofs + AI_MDL7_MAX_GROUPNAMESIZE - 1] = '\0'; - - // read all skins - sharedData.pcMats.reserve(sharedData.pcMats.size() + groupInfo.pcGroup->numskins); - sharedData.abNeedMaterials.resize(sharedData.abNeedMaterials.size() + - groupInfo.pcGroup->numskins, - false); - - for (unsigned int iSkin = 0; iSkin < (unsigned int)groupInfo.pcGroup->numskins; ++iSkin) { - ParseSkinLump_3DGS_MDL7(szCurrent, &szCurrent, sharedData.pcMats); - } - // if we have absolutely no skin loaded we need to generate a default material - if (sharedData.pcMats.empty()) { - const int iMode = (int)aiShadingMode_Gouraud; - sharedData.pcMats.push_back(new aiMaterial()); - aiMaterial *pcHelper = (aiMaterial *)sharedData.pcMats[0]; - pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - aiColor3D clr; - clr.b = clr.g = clr.r = 0.6f; - pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); - pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR); - - clr.b = clr.g = clr.r = 0.05f; - pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT); - - aiString szName; - szName.Set(AI_DEFAULT_MATERIAL_NAME); - pcHelper->AddProperty(&szName, AI_MATKEY_NAME); - - sharedData.abNeedMaterials.resize(1, false); - } - - // now get a pointer to all texture coords in the group - groupInfo.pcGroupUVs = (BE_NCONST MDL::TexCoord_MDL7 *)szCurrent; - for (int i = 0; i < groupInfo.pcGroup->num_stpts; ++i) { - AI_SWAP4(groupInfo.pcGroupUVs[i].u); - AI_SWAP4(groupInfo.pcGroupUVs[i].v); - } - szCurrent += pcHeader->skinpoint_stc_size * groupInfo.pcGroup->num_stpts; - - // now get a pointer to all triangle in the group - groupInfo.pcGroupTris = (Triangle_MDL7 *)szCurrent; - szCurrent += pcHeader->triangle_stc_size * groupInfo.pcGroup->numtris; - - // now get a pointer to all vertices in the group - groupInfo.pcGroupVerts = (BE_NCONST MDL::Vertex_MDL7 *)szCurrent; - for (int i = 0; i < groupInfo.pcGroup->numverts; ++i) { - AI_SWAP4(groupInfo.pcGroupVerts[i].x); - AI_SWAP4(groupInfo.pcGroupVerts[i].y); - AI_SWAP4(groupInfo.pcGroupVerts[i].z); - - AI_SWAP2(groupInfo.pcGroupVerts[i].vertindex); - //We can not swap the normal information now as we don't know which of the two kinds it is - } - szCurrent += pcHeader->mainvertex_stc_size * groupInfo.pcGroup->numverts; - VALIDATE_FILE_SIZE(szCurrent); - - MDL::IntSplitGroupData_MDL7 splitGroupData(sharedData, avOutList[iGroup]); - MDL::IntGroupData_MDL7 groupData; - if (groupInfo.pcGroup->numtris && groupInfo.pcGroup->numverts) { - // build output vectors - const unsigned int iNumVertices = groupInfo.pcGroup->numtris * 3; - groupData.vPositions.resize(iNumVertices); - groupData.vNormals.resize(iNumVertices); - - if (sharedData.apcOutBones) groupData.aiBones.resize(iNumVertices, UINT_MAX); - - // it is also possible that there are 0 UV coordinate sets - if (groupInfo.pcGroup->num_stpts) { - groupData.vTextureCoords1.resize(iNumVertices, aiVector3D()); - - // check whether the triangle data structure is large enough - // to contain a second UV coordinate set - if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV) { - groupData.vTextureCoords2.resize(iNumVertices, aiVector3D()); - groupData.bNeed2UV = true; - } - } - groupData.pcFaces.resize(groupInfo.pcGroup->numtris); - - // read all faces into the preallocated arrays - ReadFaces_3DGS_MDL7(groupInfo, groupData); - - // sort by materials - SortByMaterials_3DGS_MDL7(groupInfo, groupData, - splitGroupData); - - for (unsigned int qq = 0; qq < sharedData.pcMats.size(); ++qq) { - if (!splitGroupData.aiSplit[qq]->empty()) - sharedData.abNeedMaterials[qq] = true; - } - } else - ASSIMP_LOG_WARN("[3DGS MDL7] Mesh group consists of 0 " - "vertices or faces. It will be skipped."); - - // process all frames and generate output meshes - ProcessFrames_3DGS_MDL7(groupInfo, groupData, sharedData, szCurrent, &szCurrent); - GenerateOutputMeshes_3DGS_MDL7(groupData, splitGroupData); - } - - // generate a nodegraph and subnodes for each group - pScene->mRootNode = new aiNode(); - - // now we need to build a final mesh list - for (uint32_t i = 0; i < pcHeader->groups_num; ++i) - pScene->mNumMeshes += (unsigned int)avOutList[i].size(); - - pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; - { - unsigned int p = 0, q = 0; - for (uint32_t i = 0; i < pcHeader->groups_num; ++i) { - for (unsigned int a = 0; a < avOutList[i].size(); ++a) { - pScene->mMeshes[p++] = avOutList[i][a]; - } - if (!avOutList[i].empty()) ++pScene->mRootNode->mNumChildren; - } - // we will later need an extra node to serve as parent for all bones - if (sharedData.apcOutBones) ++pScene->mRootNode->mNumChildren; - this->pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren]; - p = 0; - for (uint32_t i = 0; i < pcHeader->groups_num; ++i) { - if (avOutList[i].empty()) continue; - - aiNode *const pcNode = pScene->mRootNode->mChildren[p] = new aiNode(); - pcNode->mNumMeshes = (unsigned int)avOutList[i].size(); - pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; - pcNode->mParent = this->pScene->mRootNode; - for (unsigned int a = 0; a < pcNode->mNumMeshes; ++a) - pcNode->mMeshes[a] = q + a; - q += (unsigned int)avOutList[i].size(); - - // setup the name of the node - char *const szBuffer = &aszGroupNameBuffer[i * AI_MDL7_MAX_GROUPNAMESIZE]; - if ('\0' == *szBuffer) { - const size_t maxSize(buffersize - (i * AI_MDL7_MAX_GROUPNAMESIZE)); - pcNode->mName.length = ai_snprintf(szBuffer, maxSize, "Group_%u", p); - } else { - pcNode->mName.length = (ai_uint32)::strlen(szBuffer); - } - ::strncpy(pcNode->mName.data, szBuffer, MAXLEN - 1); - ++p; - } - } - - // if there is only one root node with a single child we can optimize it a bit ... - if (1 == pScene->mRootNode->mNumChildren && !sharedData.apcOutBones) { - aiNode *pcOldRoot = this->pScene->mRootNode; - pScene->mRootNode = pcOldRoot->mChildren[0]; - pcOldRoot->mChildren[0] = nullptr; - delete pcOldRoot; - pScene->mRootNode->mParent = nullptr; - } else - pScene->mRootNode->mName.Set("<mesh_root>"); - - delete[] avOutList; - delete[] aszGroupNameBuffer; - AI_DEBUG_INVALIDATE_PTR(avOutList); - AI_DEBUG_INVALIDATE_PTR(aszGroupNameBuffer); - - // build a final material list. - CopyMaterials_3DGS_MDL7(sharedData); - HandleMaterialReferences_3DGS_MDL7(); - - // generate output bone animations and add all bones to the scenegraph - if (sharedData.apcOutBones) { - // this step adds empty dummy bones to the nodegraph - // insert another dummy node to avoid name conflicts - aiNode *const pc = pScene->mRootNode->mChildren[pScene->mRootNode->mNumChildren - 1] = new aiNode(); - - pc->mName.Set("<skeleton_root>"); - - // add bones to the nodegraph - AddBonesToNodeGraph_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **) - sharedData.apcOutBones, - pc, 0xffff); - - // this steps build a valid output animation - BuildOutputAnims_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **) - sharedData.apcOutBones); - } -} - -// ------------------------------------------------------------------------------------------------ -// Copy materials -void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared) { - pScene->mNumMaterials = (unsigned int)shared.pcMats.size(); - pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; - for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) - pScene->mMaterials[i] = shared.pcMats[i]; -} - -// ------------------------------------------------------------------------------------------------ -// Process material references -void MDLImporter::HandleMaterialReferences_3DGS_MDL7() { - // search for referrer materials - for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) { - int iIndex = 0; - if (AI_SUCCESS == aiGetMaterialInteger(pScene->mMaterials[i], AI_MDL7_REFERRER_MATERIAL, &iIndex)) { - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - aiMesh *const pcMesh = pScene->mMeshes[a]; - if (i == pcMesh->mMaterialIndex) { - pcMesh->mMaterialIndex = iIndex; - } - } - // collapse the rest of the array - delete pScene->mMaterials[i]; - for (unsigned int pp = i; pp < pScene->mNumMaterials - 1; ++pp) { - - pScene->mMaterials[pp] = pScene->mMaterials[pp + 1]; - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - aiMesh *const pcMesh = pScene->mMeshes[a]; - if (pcMesh->mMaterialIndex > i) --pcMesh->mMaterialIndex; - } - } - --pScene->mNumMaterials; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Read bone transformation keys -void MDLImporter::ParseBoneTrafoKeys_3DGS_MDL7( - const MDL::IntGroupInfo_MDL7 &groupInfo, - IntFrameInfo_MDL7 &frame, - MDL::IntSharedData_MDL7 &shared) { - const MDL::Header_MDL7 *const pcHeader = (const MDL::Header_MDL7 *)this->mBuffer; - - // only the first group contains bone animation keys - if (frame.pcFrame->transmatrix_count) { - if (!groupInfo.iIndex) { - // skip all frames vertices. We can't support them - const MDL::BoneTransform_MDL7 *pcBoneTransforms = (const MDL::BoneTransform_MDL7 *)(((const char *)frame.pcFrame) + pcHeader->frame_stc_size + - frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size); - - // read all transformation matrices - for (unsigned int iTrafo = 0; iTrafo < frame.pcFrame->transmatrix_count; ++iTrafo) { - if (pcBoneTransforms->bone_index >= pcHeader->bones_num) { - ASSIMP_LOG_WARN("Index overflow in frame area. " - "Unable to parse this bone transformation"); - } else { - AddAnimationBoneTrafoKey_3DGS_MDL7(frame.iIndex, - pcBoneTransforms, shared.apcOutBones); - } - pcBoneTransforms = (const MDL::BoneTransform_MDL7 *)((const char *)pcBoneTransforms + pcHeader->bonetrans_stc_size); - } - } else { - ASSIMP_LOG_WARN("Ignoring animation keyframes in groups != 0"); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Attach bones to the output nodegraph -void MDLImporter::AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7 **apcBones, - aiNode *pcParent, uint16_t iParentIndex) { - ai_assert(nullptr != apcBones); - ai_assert(nullptr != pcParent); - - // get a pointer to the header ... - const MDL::Header_MDL7 *const pcHeader = (const MDL::Header_MDL7 *)this->mBuffer; - - const MDL::IntBone_MDL7 **apcBones2 = apcBones; - for (uint32_t i = 0; i < pcHeader->bones_num; ++i) { - - const MDL::IntBone_MDL7 *const pcBone = *apcBones2++; - if (pcBone->iParent == iParentIndex) { - ++pcParent->mNumChildren; - } - } - pcParent->mChildren = new aiNode *[pcParent->mNumChildren]; - unsigned int qq = 0; - for (uint32_t i = 0; i < pcHeader->bones_num; ++i) { - - const MDL::IntBone_MDL7 *const pcBone = *apcBones++; - if (pcBone->iParent != iParentIndex) continue; - - aiNode *pcNode = pcParent->mChildren[qq++] = new aiNode(); - pcNode->mName = aiString(pcBone->mName); - - AddBonesToNodeGraph_3DGS_MDL7(apcBones, pcNode, (uint16_t)i); - } -} - -// ------------------------------------------------------------------------------------------------ -// Build output animations -void MDLImporter::BuildOutputAnims_3DGS_MDL7( - const MDL::IntBone_MDL7 **apcBonesOut) { - ai_assert(nullptr != apcBonesOut); - const MDL::Header_MDL7 *const pcHeader = (const MDL::Header_MDL7 *)mBuffer; - - // one animation ... - aiAnimation *pcAnim = new aiAnimation(); - for (uint32_t i = 0; i < pcHeader->bones_num; ++i) { - if (!apcBonesOut[i]->pkeyPositions.empty()) { - - // get the last frame ... (needn't be equal to pcHeader->frames_num) - for (size_t qq = 0; qq < apcBonesOut[i]->pkeyPositions.size(); ++qq) { - pcAnim->mDuration = std::max(pcAnim->mDuration, (double) - apcBonesOut[i] - ->pkeyPositions[qq] - .mTime); - } - ++pcAnim->mNumChannels; - } - } - if (pcAnim->mDuration) { - pcAnim->mChannels = new aiNodeAnim *[pcAnim->mNumChannels]; - - unsigned int iCnt = 0; - for (uint32_t i = 0; i < pcHeader->bones_num; ++i) { - if (!apcBonesOut[i]->pkeyPositions.empty()) { - const MDL::IntBone_MDL7 *const intBone = apcBonesOut[i]; - - aiNodeAnim *const pcNodeAnim = pcAnim->mChannels[iCnt++] = new aiNodeAnim(); - pcNodeAnim->mNodeName = aiString(intBone->mName); - - // allocate enough storage for all keys - pcNodeAnim->mNumPositionKeys = (unsigned int)intBone->pkeyPositions.size(); - pcNodeAnim->mNumScalingKeys = (unsigned int)intBone->pkeyPositions.size(); - pcNodeAnim->mNumRotationKeys = (unsigned int)intBone->pkeyPositions.size(); - - pcNodeAnim->mPositionKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys]; - pcNodeAnim->mScalingKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys]; - pcNodeAnim->mRotationKeys = new aiQuatKey[pcNodeAnim->mNumPositionKeys]; - - // copy all keys - for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys; ++qq) { - pcNodeAnim->mPositionKeys[qq] = intBone->pkeyPositions[qq]; - pcNodeAnim->mScalingKeys[qq] = intBone->pkeyScalings[qq]; - pcNodeAnim->mRotationKeys[qq] = intBone->pkeyRotations[qq]; - } - } - } - - // store the output animation - pScene->mNumAnimations = 1; - pScene->mAnimations = new aiAnimation *[1]; - pScene->mAnimations[0] = pcAnim; - } else - delete pcAnim; -} - -// ------------------------------------------------------------------------------------------------ -void MDLImporter::AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo, - const MDL::BoneTransform_MDL7 *pcBoneTransforms, - MDL::IntBone_MDL7 **apcBonesOut) { - ai_assert(nullptr != pcBoneTransforms); - ai_assert(nullptr != apcBonesOut); - - // first .. get the transformation matrix - aiMatrix4x4 mTransform; - mTransform.a1 = pcBoneTransforms->m[0]; - mTransform.b1 = pcBoneTransforms->m[1]; - mTransform.c1 = pcBoneTransforms->m[2]; - mTransform.d1 = pcBoneTransforms->m[3]; - - mTransform.a2 = pcBoneTransforms->m[4]; - mTransform.b2 = pcBoneTransforms->m[5]; - mTransform.c2 = pcBoneTransforms->m[6]; - mTransform.d2 = pcBoneTransforms->m[7]; - - mTransform.a3 = pcBoneTransforms->m[8]; - mTransform.b3 = pcBoneTransforms->m[9]; - mTransform.c3 = pcBoneTransforms->m[10]; - mTransform.d3 = pcBoneTransforms->m[11]; - - // now decompose the transformation matrix into separate - // scaling, rotation and translation - aiVectorKey vScaling, vPosition; - aiQuatKey qRotation; - - // FIXME: Decompose will assert in debug builds if the matrix is invalid ... - mTransform.Decompose(vScaling.mValue, qRotation.mValue, vPosition.mValue); - - // now generate keys - vScaling.mTime = qRotation.mTime = vPosition.mTime = (double)iTrafo; - - // add the keys to the bone - MDL::IntBone_MDL7 *const pcBoneOut = apcBonesOut[pcBoneTransforms->bone_index]; - pcBoneOut->pkeyPositions.push_back(vPosition); - pcBoneOut->pkeyScalings.push_back(vScaling); - pcBoneOut->pkeyRotations.push_back(qRotation); -} - -// ------------------------------------------------------------------------------------------------ -// Construct output meshes -void MDLImporter::GenerateOutputMeshes_3DGS_MDL7( - MDL::IntGroupData_MDL7 &groupData, - MDL::IntSplitGroupData_MDL7 &splitGroupData) { - const MDL::IntSharedData_MDL7 &shared = splitGroupData.shared; - - // get a pointer to the header ... - const MDL::Header_MDL7 *const pcHeader = (const MDL::Header_MDL7 *)this->mBuffer; - const unsigned int iNumOutBones = pcHeader->bones_num; - - for (std::vector<aiMaterial *>::size_type i = 0; i < shared.pcMats.size(); ++i) { - if (!splitGroupData.aiSplit[i]->empty()) { - - // allocate the output mesh - aiMesh *pcMesh = new aiMesh(); - - pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - pcMesh->mMaterialIndex = (unsigned int)i; - - // allocate output storage - pcMesh->mNumFaces = (unsigned int)splitGroupData.aiSplit[i]->size(); - pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; - - pcMesh->mNumVertices = pcMesh->mNumFaces * 3; - pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; - - if (!groupData.vTextureCoords1.empty()) { - pcMesh->mNumUVComponents[0] = 2; - pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; - if (!groupData.vTextureCoords2.empty()) { - pcMesh->mNumUVComponents[1] = 2; - pcMesh->mTextureCoords[1] = new aiVector3D[pcMesh->mNumVertices]; - } - } - - // iterate through all faces and build an unique set of vertices - unsigned int iCurrent = 0; - for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces; ++iFace) { - pcMesh->mFaces[iFace].mNumIndices = 3; - pcMesh->mFaces[iFace].mIndices = new unsigned int[3]; - - unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace); - const MDL::IntFace_MDL7 &oldFace = groupData.pcFaces[iSrcFace]; - - // iterate through all face indices - for (unsigned int c = 0; c < 3; ++c) { - const uint32_t iIndex = oldFace.mIndices[c]; - pcMesh->mVertices[iCurrent] = groupData.vPositions[iIndex]; - pcMesh->mNormals[iCurrent] = groupData.vNormals[iIndex]; - - if (!groupData.vTextureCoords1.empty()) { - - pcMesh->mTextureCoords[0][iCurrent] = groupData.vTextureCoords1[iIndex]; - if (!groupData.vTextureCoords2.empty()) { - pcMesh->mTextureCoords[1][iCurrent] = groupData.vTextureCoords2[iIndex]; - } - } - pcMesh->mFaces[iFace].mIndices[c] = iCurrent++; - } - } - - // if we have bones in the mesh we'll need to generate - // proper vertex weights for them - if (!groupData.aiBones.empty()) { - std::vector<std::vector<unsigned int>> aaiVWeightList; - aaiVWeightList.resize(iNumOutBones); - - int iCurrentWeight = 0; - for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces; ++iFace) { - unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace); - const MDL::IntFace_MDL7 &oldFace = groupData.pcFaces[iSrcFace]; - - // iterate through all face indices - for (unsigned int c = 0; c < 3; ++c) { - unsigned int iBone = groupData.aiBones[oldFace.mIndices[c]]; - if (UINT_MAX != iBone) { - if (iBone >= iNumOutBones) { - ASSIMP_LOG_ERROR("Bone index overflow. " - "The bone index of a vertex exceeds the allowed range. "); - iBone = iNumOutBones - 1; - } - aaiVWeightList[iBone].push_back(iCurrentWeight); - } - ++iCurrentWeight; - } - } - // now check which bones are required ... - for (std::vector<std::vector<unsigned int>>::const_iterator k = aaiVWeightList.begin(); k != aaiVWeightList.end(); ++k) { - if (!(*k).empty()) { - ++pcMesh->mNumBones; - } - } - pcMesh->mBones = new aiBone *[pcMesh->mNumBones]; - iCurrent = 0; - for (std::vector<std::vector<unsigned int>>::const_iterator k = aaiVWeightList.begin(); k != aaiVWeightList.end(); ++k, ++iCurrent) { - if ((*k).empty()) - continue; - - // seems we'll need this node - aiBone *pcBone = pcMesh->mBones[iCurrent] = new aiBone(); - pcBone->mName = aiString(shared.apcOutBones[iCurrent]->mName); - pcBone->mOffsetMatrix = shared.apcOutBones[iCurrent]->mOffsetMatrix; - - // setup vertex weights - pcBone->mNumWeights = (unsigned int)(*k).size(); - pcBone->mWeights = new aiVertexWeight[pcBone->mNumWeights]; - - for (unsigned int weight = 0; weight < pcBone->mNumWeights; ++weight) { - pcBone->mWeights[weight].mVertexId = (*k)[weight]; - pcBone->mWeights[weight].mWeight = 1.0f; - } - } - } - // add the mesh to the list of output meshes - splitGroupData.avOutList.push_back(pcMesh); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Join to materials -void MDLImporter::JoinSkins_3DGS_MDL7( - aiMaterial *pcMat1, - aiMaterial *pcMat2, - aiMaterial *pcMatOut) { - ai_assert(nullptr != pcMat1); - ai_assert(nullptr != pcMat2); - ai_assert(nullptr != pcMatOut); - - // first create a full copy of the first skin property set - // and assign it to the output material - aiMaterial::CopyPropertyList(pcMatOut, pcMat1); - - int iVal = 0; - pcMatOut->AddProperty<int>(&iVal, 1, AI_MATKEY_UVWSRC_DIFFUSE(0)); - - // then extract the diffuse texture from the second skin, - // setup 1 as UV source and we have it - aiString sString; - if (AI_SUCCESS == aiGetMaterialString(pcMat2, AI_MATKEY_TEXTURE_DIFFUSE(0), &sString)) { - iVal = 1; - pcMatOut->AddProperty<int>(&iVal, 1, AI_MATKEY_UVWSRC_DIFFUSE(1)); - pcMatOut->AddProperty(&sString, AI_MATKEY_TEXTURE_DIFFUSE(1)); - } -} - -// ------------------------------------------------------------------------------------------------ -// Read a Half-life 1 MDL -void MDLImporter::InternReadFile_HL1(const std::string &pFile, const uint32_t iMagicWord) { - // We can't correctly load an MDL from a MDL "sequence" file. - if (iMagicWord == AI_MDL_MAGIC_NUMBER_BE_HL2b || iMagicWord == AI_MDL_MAGIC_NUMBER_LE_HL2b) - throw DeadlyImportError("Impossible to properly load a model from an MDL sequence file."); - - // Read the MDL file. - HalfLife::HL1MDLLoader loader( - pScene, - mIOHandler, - mBuffer, - pFile, - mHL1ImportSettings); -} - -// ------------------------------------------------------------------------------------------------ -// Read a half-life 2 MDL -void MDLImporter::InternReadFile_HL2() { - //const MDL::Header_HL2* pcHeader = (const MDL::Header_HL2*)this->mBuffer; - throw DeadlyImportError("HL2 MDLs are not implemented"); -} - -#endif // !! ASSIMP_BUILD_NO_MDL_IMPORTER diff --git a/libs/assimp/code/AssetLib/MDL/MDLLoader.h b/libs/assimp/code/AssetLib/MDL/MDLLoader.h deleted file mode 100644 index b7d87e8..0000000 --- a/libs/assimp/code/AssetLib/MDL/MDLLoader.h +++ /dev/null @@ -1,451 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - - -/** @file MDLLoader.h - * @brief Declaration of the loader for MDL files - */ -#pragma once -#ifndef AI_MDLLOADER_H_INCLUDED -#define AI_MDLLOADER_H_INCLUDED - -#include <assimp/BaseImporter.h> -#include "MDLFileData.h" -#include "AssetLib/HMP/HalfLifeFileData.h" -#include "AssetLib/MDL/HalfLife/HL1ImportSettings.h" - -struct aiNode; -struct aiTexture; - -namespace Assimp { - -using namespace MDL; - -// -------------------------------------------------------------------------------------- -// Include file/line information in debug builds -#ifdef ASSIMP_BUILD_DEBUG -# define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__) -#else -# define VALIDATE_FILE_SIZE(msg) SizeCheck(msg) -#endif - -// -------------------------------------------------------------------------------------- -/** @brief Class to load MDL files. - * - * Several subformats exist: - * <ul> - * <li>Quake I</li> - * <li>3D Game Studio MDL3, MDL4</li> - * <li>3D Game Studio MDL5</li> - * <li>3D Game Studio MDL7</li> - * <li>Halflife 1</li> - * <li>Halflife 2</li> - * </ul> - * These formats are partially identical and it would be possible to load - * them all with a single 1000-line function-beast. However, it has been - * split into several code paths to make the code easier to read and maintain. -*/ -class MDLImporter : public BaseImporter -{ -public: - MDLImporter(); - ~MDLImporter() override; - - // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, - bool checkSig) const override; - - // ------------------------------------------------------------------- - /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp) override; - -protected: - // ------------------------------------------------------------------- - /** Return importer meta information. - * See #BaseImporter::GetInfo for the details - */ - const aiImporterDesc* GetInfo () const override; - - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details - */ - void InternReadFile( const std::string& pFile, aiScene* pScene, - IOSystem* pIOHandler) override; - - // ------------------------------------------------------------------- - /** Import a quake 1 MDL file (IDPO) - */ - void InternReadFile_Quake1( ); - - // ------------------------------------------------------------------- - /** Import a GameStudio A4/A5 file (MDL 3,4,5) - */ - void InternReadFile_3DGS_MDL345( ); - - // ------------------------------------------------------------------- - /** Import a GameStudio A7 file (MDL 7) - */ - void InternReadFile_3DGS_MDL7( ); - - // ------------------------------------------------------------------- - /** Import a Half-Life 1 MDL file - */ - void InternReadFile_HL1(const std::string& pFile, const uint32_t iMagicWord); - - // ------------------------------------------------------------------- - /** Import a CS:S/HL2 MDL file (not fully implemented) - */ - void InternReadFile_HL2( ); - - // ------------------------------------------------------------------- - /** Check whether a given position is inside the valid range - * Throw a DeadlyImportError if it is not - * \param szPos Cursor position - * \param szFile Name of the source file from which the function was called - * \param iLine Source code line from which the function was called - */ - void SizeCheck(const void* szPos); - void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine); - - // ------------------------------------------------------------------- - /** Validate the header data structure of a game studio MDL7 file - * \param pcHeader Input header to be validated - */ - void ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7* pcHeader); - - // ------------------------------------------------------------------- - /** Validate the header data structure of a Quake 1 model - * \param pcHeader Input header to be validated - */ - void ValidateHeader_Quake1(const MDL::Header* pcHeader); - - // ------------------------------------------------------------------- - /** Try to load a palette from the current directory (colormap.lmp) - * If it is not found the default palette of Quake1 is returned - */ - void SearchPalette(const unsigned char** pszColorMap); - - // ------------------------------------------------------------------- - /** Free a palette created with a previous call to SearchPalette() - */ - void FreePalette(const unsigned char* pszColorMap); - - // ------------------------------------------------------------------- - /** Load a palletized texture from the file and convert it to 32bpp - */ - void CreateTextureARGB8_3DGS_MDL3(const unsigned char* szData); - - // ------------------------------------------------------------------- - /** Used to load textures from MDL3/4 - * \param szData Input data - * \param iType Color data type - * \param piSkip Receive: Size to skip, in bytes - */ - void CreateTexture_3DGS_MDL4(const unsigned char* szData, - unsigned int iType, - unsigned int* piSkip); - - // ------------------------------------------------------------------- - /** Used to load textures from MDL5 - * \param szData Input data - * \param iType Color data type - * \param piSkip Receive: Size to skip, in bytes - */ - void CreateTexture_3DGS_MDL5(const unsigned char* szData, - unsigned int iType, - unsigned int* piSkip); - - // ------------------------------------------------------------------- - /** Checks whether a texture can be replaced with a single color - * This is useful for all file formats before MDL7 (all those - * that are not containing material colors separate from textures). - * MED seems to write dummy 8x8 monochrome images instead. - * \param pcTexture Input texture - * \return aiColor.r is set to qnan if the function fails and no - * color can be found. - */ - aiColor4D ReplaceTextureWithColor(const aiTexture* pcTexture); - - // ------------------------------------------------------------------- - /** Converts the absolute texture coordinates in MDL5 files to - * relative in a range between 0 and 1 - */ - void CalculateUVCoordinates_MDL5(); - - // ------------------------------------------------------------------- - /** Read an UV coordinate from the file. If the file format is not - * MDL5, the function calculates relative texture coordinates - * \param vOut Receives the output UV coord - * \param pcSrc UV coordinate buffer - * \param UV coordinate index - */ - void ImportUVCoordinate_3DGS_MDL345( aiVector3D& vOut, - const MDL::TexCoord_MDL3* pcSrc, - unsigned int iIndex); - - // ------------------------------------------------------------------- - /** Setup the material properties for Quake and MDL<7 models. - * These formats don't support more than one material per mesh, - * therefore the method processes only ONE skin and removes - * all others. - */ - void SetupMaterialProperties_3DGS_MDL5_Quake1( ); - - // ------------------------------------------------------------------- - /** Parse a skin lump in a MDL7/HMP7 file with all of its features - * variant 1: Current cursor position is the beginning of the skin header - * \param szCurrent Current data pointer - * \param szCurrentOut Output data pointer - * \param pcMats Material list for this group. To be filled ... - */ - void ParseSkinLump_3DGS_MDL7( - const unsigned char* szCurrent, - const unsigned char** szCurrentOut, - std::vector<aiMaterial*>& pcMats); - - // ------------------------------------------------------------------- - /** Parse a skin lump in a MDL7/HMP7 file with all of its features - * variant 2: Current cursor position is the beginning of the skin data - * \param szCurrent Current data pointer - * \param szCurrentOut Output data pointer - * \param pcMatOut Output material - * \param iType header.typ - * \param iWidth header.width - * \param iHeight header.height - */ - void ParseSkinLump_3DGS_MDL7( - const unsigned char* szCurrent, - const unsigned char** szCurrentOut, - aiMaterial* pcMatOut, - unsigned int iType, - unsigned int iWidth, - unsigned int iHeight); - - // ------------------------------------------------------------------- - /** Skip a skin lump in a MDL7/HMP7 file - * \param szCurrent Current data pointer - * \param szCurrentOut Output data pointer. Points to the byte just - * behind the last byte of the skin. - * \param iType header.typ - * \param iWidth header.width - * \param iHeight header.height - */ - void SkipSkinLump_3DGS_MDL7(const unsigned char* szCurrent, - const unsigned char** szCurrentOut, - unsigned int iType, - unsigned int iWidth, - unsigned int iHeight); - - // ------------------------------------------------------------------- - /** Parse texture color data for MDL5, MDL6 and MDL7 formats - * \param szData Current data pointer - * \param iType type of the texture data. No DDS or external - * \param piSkip Receive the number of bytes to skip - * \param pcNew Must point to fully initialized data. Width and - * height must be set. If pcNew->pcData is set to UINT_MAX, - * piSkip will receive the size of the texture, in bytes, but no - * color data will be read. - */ - void ParseTextureColorData(const unsigned char* szData, - unsigned int iType, - unsigned int* piSkip, - aiTexture* pcNew); - - // ------------------------------------------------------------------- - /** Join two materials / skins. Setup UV source ... etc - * \param pcMat1 First input material - * \param pcMat2 Second input material - * \param pcMatOut Output material instance to be filled. Must be empty - */ - void JoinSkins_3DGS_MDL7(aiMaterial* pcMat1, - aiMaterial* pcMat2, - aiMaterial* pcMatOut); - - // ------------------------------------------------------------------- - /** Add a bone transformation key to an animation - * \param iTrafo Index of the transformation (always==frame index?) - * No need to validate this index, it is always valid. - * \param pcBoneTransforms Bone transformation for this index - * \param apcOutBones Output bones array - */ - void AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo, - const MDL::BoneTransform_MDL7* pcBoneTransforms, - MDL::IntBone_MDL7** apcBonesOut); - - // ------------------------------------------------------------------- - /** Load the bone list of a MDL7 file - * \return If the bones could be loaded successfully, a valid - * array containing pointers to a temporary bone - * representation. nullptr if the bones could not be loaded. - */ - MDL::IntBone_MDL7** LoadBones_3DGS_MDL7(); - - // ------------------------------------------------------------------- - /** Load bone transformation keyframes from a file chunk - * \param groupInfo -> doc of data structure - * \param frame -> doc of data structure - * \param shared -> doc of data structure - */ - void ParseBoneTrafoKeys_3DGS_MDL7( - const MDL::IntGroupInfo_MDL7& groupInfo, - IntFrameInfo_MDL7& frame, - MDL::IntSharedData_MDL7& shared); - - // ------------------------------------------------------------------- - /** Calculate absolute bone animation matrices for each bone - * \param apcOutBones Output bones array - */ - void CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones); - - // ------------------------------------------------------------------- - /** Add all bones to the nodegraph (as children of the root node) - * \param apcBonesOut List of bones - * \param pcParent Parent node. New nodes will be added to this node - * \param iParentIndex Index of the parent bone - */ - void AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7** apcBonesOut, - aiNode* pcParent,uint16_t iParentIndex); - - // ------------------------------------------------------------------- - /** Build output animations - * \param apcBonesOut List of bones - */ - void BuildOutputAnims_3DGS_MDL7(const MDL::IntBone_MDL7** apcBonesOut); - - // ------------------------------------------------------------------- - /** Handles materials that are just referencing another material - * There is no test file for this feature, but Conitec's doc - * say it is used. - */ - void HandleMaterialReferences_3DGS_MDL7(); - - // ------------------------------------------------------------------- - /** Copies only the material that are referenced by at least one - * mesh to the final output material list. All other materials - * will be discarded. - * \param shared -> doc of data structure - */ - void CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared); - - // ------------------------------------------------------------------- - /** Process the frame section at the end of a group - * \param groupInfo -> doc of data structure - * \param shared -> doc of data structure - * \param szCurrent Pointer to the start of the frame section - * \param szCurrentOut Receives a pointer to the first byte of the - * next data section. - * \return false to read no further groups (a small workaround for - * some tiny and unsolved problems ... ) - */ - bool ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo, - MDL::IntGroupData_MDL7& groupData, - MDL::IntSharedData_MDL7& shared, - const unsigned char* szCurrent, - const unsigned char** szCurrentOut); - - // ------------------------------------------------------------------- - /** Sort all faces by their materials. If the mesh is using - * multiple materials per face (that are blended together) the function - * might create new materials. - * \param groupInfo -> doc of data structure - * \param groupData -> doc of data structure - * \param splitGroupData -> doc of data structure - */ - void SortByMaterials_3DGS_MDL7( - const MDL::IntGroupInfo_MDL7& groupInfo, - MDL::IntGroupData_MDL7& groupData, - MDL::IntSplitGroupData_MDL7& splitGroupData); - - // ------------------------------------------------------------------- - /** Read all faces and vertices from a MDL7 group. The function fills - * preallocated memory buffers. - * \param groupInfo -> doc of data structure - * \param groupData -> doc of data structure - */ - void ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo, - MDL::IntGroupData_MDL7& groupData); - - // ------------------------------------------------------------------- - /** Generate the final output meshes for a7 models - * \param groupData -> doc of data structure - * \param splitGroupData -> doc of data structure - */ - void GenerateOutputMeshes_3DGS_MDL7( - MDL::IntGroupData_MDL7& groupData, - MDL::IntSplitGroupData_MDL7& splitGroupData); - -protected: - - /** Configuration option: frame to be loaded */ - unsigned int configFrameID; - - /** Configuration option: palette to be used to decode palletized images*/ - std::string configPalette; - - /** Buffer to hold the loaded file */ - unsigned char* mBuffer; - - /** For GameStudio MDL files: The number in the magic word, either 3,4 or 5 - * (MDL7 doesn't need this, the format has a separate loader) */ - unsigned int iGSFileVersion; - - /** Output I/O handler. used to load external lmp files */ - IOSystem* mIOHandler; - - /** Output scene to be filled */ - aiScene* pScene; - - /** Size of the input file in bytes */ - unsigned int iFileSize; - - /* Configuration for HL1 MDL */ - HalfLife::HL1ImportSettings mHL1ImportSettings; -}; - -} // end of namespace Assimp - -#endif // AI_3DSIMPORTER_H_INC diff --git a/libs/assimp/code/AssetLib/MDL/MDLMaterialLoader.cpp b/libs/assimp/code/AssetLib/MDL/MDLMaterialLoader.cpp deleted file mode 100644 index eebb9d1..0000000 --- a/libs/assimp/code/AssetLib/MDL/MDLMaterialLoader.cpp +++ /dev/null @@ -1,765 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the material part of the MDL importer class */ - -#ifndef ASSIMP_BUILD_NO_MDL_IMPORTER - -#include "MDLDefaultColorMap.h" -#include "MDLLoader.h" - -#include <assimp/StringUtils.h> -#include <assimp/qnan.h> -#include <assimp/scene.h> -#include <assimp/texture.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/IOSystem.hpp> - -#include <memory> - -using namespace Assimp; - -static aiTexel *const bad_texel = reinterpret_cast<aiTexel *>(SIZE_MAX); - -// ------------------------------------------------------------------------------------------------ -// Find a suitable palette file or take the default one -void MDLImporter::SearchPalette(const unsigned char **pszColorMap) { - // now try to find the color map in the current directory - IOStream *pcStream = mIOHandler->Open(configPalette, "rb"); - - const unsigned char *szColorMap = (const unsigned char *)::g_aclrDefaultColorMap; - if (pcStream) { - if (pcStream->FileSize() >= 768) { - size_t len = 256 * 3; - unsigned char *colorMap = new unsigned char[len]; - szColorMap = colorMap; - pcStream->Read(colorMap, len, 1); - ASSIMP_LOG_INFO("Found valid colormap.lmp in directory. " - "It will be used to decode embedded textures in palletized formats."); - } - delete pcStream; - pcStream = nullptr; - } - *pszColorMap = szColorMap; -} - -// ------------------------------------------------------------------------------------------------ -// Free the palette again -void MDLImporter::FreePalette(const unsigned char *szColorMap) { - if (szColorMap != (const unsigned char *)::g_aclrDefaultColorMap) { - delete[] szColorMap; - } -} - -// ------------------------------------------------------------------------------------------------ -// Check whether we can replace a texture with a single color -aiColor4D MDLImporter::ReplaceTextureWithColor(const aiTexture *pcTexture) { - ai_assert(nullptr != pcTexture); - - aiColor4D clrOut; - clrOut.r = get_qnan(); - if (!pcTexture->mHeight || !pcTexture->mWidth) - return clrOut; - - const unsigned int iNumPixels = pcTexture->mHeight * pcTexture->mWidth; - const aiTexel *pcTexel = pcTexture->pcData + 1; - const aiTexel *const pcTexelEnd = &pcTexture->pcData[iNumPixels]; - - while (pcTexel != pcTexelEnd) { - if (*pcTexel != *(pcTexel - 1)) { - pcTexel = nullptr; - break; - } - ++pcTexel; - } - if (pcTexel) { - clrOut.r = pcTexture->pcData->r / 255.0f; - clrOut.g = pcTexture->pcData->g / 255.0f; - clrOut.b = pcTexture->pcData->b / 255.0f; - clrOut.a = pcTexture->pcData->a / 255.0f; - } - return clrOut; -} - -// ------------------------------------------------------------------------------------------------ -// Read a texture from a MDL3 file -void MDLImporter::CreateTextureARGB8_3DGS_MDL3(const unsigned char *szData) { - const MDL::Header *pcHeader = (const MDL::Header *)mBuffer; //the endianness is already corrected in the InternReadFile_3DGS_MDL345 function - - VALIDATE_FILE_SIZE(szData + pcHeader->skinwidth * - pcHeader->skinheight); - - // allocate a new texture object - aiTexture *pcNew = new aiTexture(); - pcNew->mWidth = pcHeader->skinwidth; - pcNew->mHeight = pcHeader->skinheight; - - if(pcNew->mWidth != 0 && pcNew->mHeight > UINT_MAX/pcNew->mWidth) { - throw DeadlyImportError("Invalid MDL file. A texture is too big."); - } - pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight]; - - const unsigned char *szColorMap; - this->SearchPalette(&szColorMap); - - // copy texture data - for (unsigned int i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) { - const unsigned char val = szData[i]; - const unsigned char *sz = &szColorMap[val * 3]; - - pcNew->pcData[i].a = 0xFF; - pcNew->pcData[i].r = *sz++; - pcNew->pcData[i].g = *sz++; - pcNew->pcData[i].b = *sz; - } - - FreePalette(szColorMap); - - // store the texture - aiTexture **pc = this->pScene->mTextures; - this->pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1]; - for (unsigned int i = 0; i < pScene->mNumTextures; ++i) - pScene->mTextures[i] = pc[i]; - - pScene->mTextures[this->pScene->mNumTextures] = pcNew; - pScene->mNumTextures++; - delete[] pc; -} - -// ------------------------------------------------------------------------------------------------ -// Read a texture from a MDL4 file -void MDLImporter::CreateTexture_3DGS_MDL4(const unsigned char *szData, - unsigned int iType, - unsigned int *piSkip) { - ai_assert(nullptr != piSkip); - - const MDL::Header *pcHeader = (const MDL::Header *)mBuffer; //the endianness is already corrected in the InternReadFile_3DGS_MDL345 function - - if (iType == 1 || iType > 3) { - ASSIMP_LOG_ERROR("Unsupported texture file format"); - return; - } - - const bool bNoRead = *piSkip == UINT_MAX; - - // allocate a new texture object - aiTexture *pcNew = new aiTexture(); - pcNew->mWidth = pcHeader->skinwidth; - pcNew->mHeight = pcHeader->skinheight; - - if (bNoRead) pcNew->pcData = bad_texel; - ParseTextureColorData(szData, iType, piSkip, pcNew); - - // store the texture - if (!bNoRead) { - if (!this->pScene->mNumTextures) { - pScene->mNumTextures = 1; - pScene->mTextures = new aiTexture *[1]; - pScene->mTextures[0] = pcNew; - } else { - aiTexture **pc = pScene->mTextures; - pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1]; - for (unsigned int i = 0; i < this->pScene->mNumTextures; ++i) - pScene->mTextures[i] = pc[i]; - pScene->mTextures[pScene->mNumTextures] = pcNew; - pScene->mNumTextures++; - delete[] pc; - } - } else { - pcNew->pcData = nullptr; - delete pcNew; - } - return; -} - -// ------------------------------------------------------------------------------------------------ -// Load color data of a texture and convert it to our output format -void MDLImporter::ParseTextureColorData(const unsigned char *szData, - unsigned int iType, - unsigned int *piSkip, - aiTexture *pcNew) { - const bool do_read = bad_texel != pcNew->pcData; - - // allocate storage for the texture image - if (do_read) { - if(pcNew->mWidth != 0 && pcNew->mHeight > UINT_MAX/pcNew->mWidth) { - throw DeadlyImportError("Invalid MDL file. A texture is too big."); - } - pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight]; - } - - // R5G6B5 format (with or without MIPs) - // **************************************************************** - if (2 == iType || 10 == iType) { - VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 2); - - // copy texture data - unsigned int i; - if (do_read) { - for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) { - MDL::RGB565 val = ((MDL::RGB565 *)szData)[i]; - AI_SWAP2(val); - - pcNew->pcData[i].a = 0xFF; - pcNew->pcData[i].r = (unsigned char)val.b << 3; - pcNew->pcData[i].g = (unsigned char)val.g << 2; - pcNew->pcData[i].b = (unsigned char)val.r << 3; - } - } else { - i = pcNew->mWidth * pcNew->mHeight; - } - *piSkip = i * 2; - - // apply MIP maps - if (10 == iType) { - *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1; - VALIDATE_FILE_SIZE(szData + *piSkip); - } - } - // ARGB4 format (with or without MIPs) - // **************************************************************** - else if (3 == iType || 11 == iType) { - VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 4); - - // copy texture data - unsigned int i; - if (do_read) { - for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) { - MDL::ARGB4 val = ((MDL::ARGB4 *)szData)[i]; - AI_SWAP2(val); - - pcNew->pcData[i].a = (unsigned char)val.a << 4; - pcNew->pcData[i].r = (unsigned char)val.r << 4; - pcNew->pcData[i].g = (unsigned char)val.g << 4; - pcNew->pcData[i].b = (unsigned char)val.b << 4; - } - } else - i = pcNew->mWidth * pcNew->mHeight; - *piSkip = i * 2; - - // apply MIP maps - if (11 == iType) { - *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1; - VALIDATE_FILE_SIZE(szData + *piSkip); - } - } - // RGB8 format (with or without MIPs) - // **************************************************************** - else if (4 == iType || 12 == iType) { - VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 3); - - // copy texture data - unsigned int i; - if (do_read) { - for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) { - const unsigned char *_szData = &szData[i * 3]; - - pcNew->pcData[i].a = 0xFF; - pcNew->pcData[i].b = *_szData++; - pcNew->pcData[i].g = *_szData++; - pcNew->pcData[i].r = *_szData; - } - } else - i = pcNew->mWidth * pcNew->mHeight; - - // apply MIP maps - *piSkip = i * 3; - if (12 == iType) { - *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) * 3; - VALIDATE_FILE_SIZE(szData + *piSkip); - } - } - // ARGB8 format (with ir without MIPs) - // **************************************************************** - else if (5 == iType || 13 == iType) { - VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 4); - - // copy texture data - unsigned int i; - if (do_read) { - for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) { - const unsigned char *_szData = &szData[i * 4]; - - pcNew->pcData[i].b = *_szData++; - pcNew->pcData[i].g = *_szData++; - pcNew->pcData[i].r = *_szData++; - pcNew->pcData[i].a = *_szData; - } - } else { - i = pcNew->mWidth * pcNew->mHeight; - } - - // apply MIP maps - *piSkip = i << 2; - if (13 == iType) { - *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 2; - } - } - // palletized 8 bit texture. As for Quake 1 - // **************************************************************** - else if (0 == iType) { - VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight); - - // copy texture data - unsigned int i; - if (do_read) { - - const unsigned char *szColorMap; - SearchPalette(&szColorMap); - - for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) { - const unsigned char val = szData[i]; - const unsigned char *sz = &szColorMap[val * 3]; - - pcNew->pcData[i].a = 0xFF; - pcNew->pcData[i].r = *sz++; - pcNew->pcData[i].g = *sz++; - pcNew->pcData[i].b = *sz; - } - this->FreePalette(szColorMap); - - } else - i = pcNew->mWidth * pcNew->mHeight; - *piSkip = i; - - // FIXME: Also support for MIP maps? - } -} - -// ------------------------------------------------------------------------------------------------ -// Get a texture from a MDL5 file -void MDLImporter::CreateTexture_3DGS_MDL5(const unsigned char *szData, - unsigned int iType, - unsigned int *piSkip) { - ai_assert(nullptr != piSkip); - bool bNoRead = *piSkip == UINT_MAX; - - // allocate a new texture object - aiTexture *pcNew = new aiTexture(); - - VALIDATE_FILE_SIZE(szData + 8); - - // first read the size of the texture - pcNew->mWidth = *((uint32_t *)szData); - AI_SWAP4(pcNew->mWidth); - szData += sizeof(uint32_t); - - pcNew->mHeight = *((uint32_t *)szData); - AI_SWAP4(pcNew->mHeight); - szData += sizeof(uint32_t); - - if (bNoRead) { - pcNew->pcData = bad_texel; - } - - // this should not occur - at least the docs say it shouldn't. - // however, one can easily try out what MED does if you have - // a model with a DDS texture and export it to MDL5 ... - // yeah, it embeds the DDS file. - if (6 == iType) { - // this is a compressed texture in DDS format - *piSkip = pcNew->mWidth; - VALIDATE_FILE_SIZE(szData + *piSkip); - - if (!bNoRead) { - // place a hint and let the application know that this is a DDS file - pcNew->mHeight = 0; - pcNew->achFormatHint[0] = 'd'; - pcNew->achFormatHint[1] = 'd'; - pcNew->achFormatHint[2] = 's'; - pcNew->achFormatHint[3] = '\0'; - - pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth]; - ::memcpy(pcNew->pcData, szData, pcNew->mWidth); - } - } else { - // parse the color data of the texture - ParseTextureColorData(szData, iType, piSkip, pcNew); - } - *piSkip += sizeof(uint32_t) * 2; - - if (!bNoRead) { - // store the texture - if (!this->pScene->mNumTextures) { - pScene->mNumTextures = 1; - pScene->mTextures = new aiTexture *[1]; - pScene->mTextures[0] = pcNew; - } else { - aiTexture **pc = pScene->mTextures; - pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1]; - for (unsigned int i = 0; i < pScene->mNumTextures; ++i) - this->pScene->mTextures[i] = pc[i]; - - pScene->mTextures[pScene->mNumTextures] = pcNew; - pScene->mNumTextures++; - delete[] pc; - } - } else { - pcNew->pcData = nullptr; - delete pcNew; - } - return; -} - -// ------------------------------------------------------------------------------------------------ -// Get a skin from a MDL7 file - more complex than all other subformats -void MDLImporter::ParseSkinLump_3DGS_MDL7( - const unsigned char *szCurrent, - const unsigned char **szCurrentOut, - aiMaterial *pcMatOut, - unsigned int iType, - unsigned int iWidth, - unsigned int iHeight) { - std::unique_ptr<aiTexture> pcNew; - - // get the type of the skin - unsigned int iMasked = (unsigned int)(iType & 0xF); - - if (0x1 == iMasked) { - // ***** REFERENCE TO ANOTHER SKIN INDEX ***** - int referrer = (int)iWidth; - pcMatOut->AddProperty<int>(&referrer, 1, AI_MDL7_REFERRER_MATERIAL); - } else if (0x6 == iMasked) { - // ***** EMBEDDED DDS FILE ***** - if (1 != iHeight) { - ASSIMP_LOG_WARN("Found a reference to an embedded DDS texture, " - "but texture height is not equal to 1, which is not supported by MED"); - } - if (iWidth == 0) { - ASSIMP_LOG_ERROR("Found a reference to an embedded DDS texture, but texture width is zero, aborting import."); - return; - } - - pcNew.reset(new aiTexture); - pcNew->mHeight = 0; - pcNew->mWidth = iWidth; - - // place a proper format hint - pcNew->achFormatHint[0] = 'd'; - pcNew->achFormatHint[1] = 'd'; - pcNew->achFormatHint[2] = 's'; - pcNew->achFormatHint[3] = '\0'; - - pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth]; - memcpy(pcNew->pcData, szCurrent, pcNew->mWidth); - szCurrent += iWidth; - } else if (0x7 == iMasked) { - // ***** REFERENCE TO EXTERNAL FILE ***** - if (1 != iHeight) { - ASSIMP_LOG_WARN("Found a reference to an external texture, " - "but texture height is not equal to 1, which is not supported by MED"); - } - - aiString szFile; - const size_t iLen = strlen((const char *)szCurrent); - size_t iLen2 = iLen + 1; - iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2; - memcpy(szFile.data, (const char *)szCurrent, iLen2); - szFile.length = (ai_uint32)iLen; - - szCurrent += iLen2; - - // place this as diffuse texture - pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0)); - } else if (iMasked || !iType || (iType && iWidth && iHeight)) { - pcNew.reset(new aiTexture()); - if (!iHeight || !iWidth) { - ASSIMP_LOG_WARN("Found embedded texture, but its width " - "an height are both 0. Is this a joke?"); - - // generate an empty chess pattern - pcNew->mWidth = pcNew->mHeight = 8; - pcNew->pcData = new aiTexel[64]; - for (unsigned int x = 0; x < 8; ++x) { - for (unsigned int y = 0; y < 8; ++y) { - const bool bSet = ((0 == x % 2 && 0 != y % 2) || - (0 != x % 2 && 0 == y % 2)); - - aiTexel *pc = &pcNew->pcData[y * 8 + x]; - pc->r = pc->b = pc->g = (bSet ? 0xFF : 0); - pc->a = 0xFF; - } - } - } else { - // it is a standard color texture. Fill in width and height - // and call the same function we used for loading MDL5 files - - pcNew->mWidth = iWidth; - pcNew->mHeight = iHeight; - - unsigned int iSkip = 0; - ParseTextureColorData(szCurrent, iMasked, &iSkip, pcNew.get()); - - // skip length of texture data - szCurrent += iSkip; - } - } - - // sometimes there are MDL7 files which have a monochrome - // texture instead of material colors ... possible they have - // been converted to MDL7 from other formats, such as MDL5 - aiColor4D clrTexture; - if (pcNew) - clrTexture = ReplaceTextureWithColor(pcNew.get()); - else - clrTexture.r = get_qnan(); - - // check whether a material definition is contained in the skin - if (iType & AI_MDL7_SKINTYPE_MATERIAL) { - BE_NCONST MDL::Material_MDL7 *pcMatIn = (BE_NCONST MDL::Material_MDL7 *)szCurrent; - szCurrent = (unsigned char *)(pcMatIn + 1); - VALIDATE_FILE_SIZE(szCurrent); - - aiColor3D clrTemp; - -#define COLOR_MULTIPLY_RGB() \ - if (is_not_qnan(clrTexture.r)) { \ - clrTemp.r *= clrTexture.r; \ - clrTemp.g *= clrTexture.g; \ - clrTemp.b *= clrTexture.b; \ - } - - // read diffuse color - clrTemp.r = pcMatIn->Diffuse.r; - AI_SWAP4(clrTemp.r); - clrTemp.g = pcMatIn->Diffuse.g; - AI_SWAP4(clrTemp.g); - clrTemp.b = pcMatIn->Diffuse.b; - AI_SWAP4(clrTemp.b); - COLOR_MULTIPLY_RGB(); - pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_DIFFUSE); - - // read specular color - clrTemp.r = pcMatIn->Specular.r; - AI_SWAP4(clrTemp.r); - clrTemp.g = pcMatIn->Specular.g; - AI_SWAP4(clrTemp.g); - clrTemp.b = pcMatIn->Specular.b; - AI_SWAP4(clrTemp.b); - COLOR_MULTIPLY_RGB(); - pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_SPECULAR); - - // read ambient color - clrTemp.r = pcMatIn->Ambient.r; - AI_SWAP4(clrTemp.r); - clrTemp.g = pcMatIn->Ambient.g; - AI_SWAP4(clrTemp.g); - clrTemp.b = pcMatIn->Ambient.b; - AI_SWAP4(clrTemp.b); - COLOR_MULTIPLY_RGB(); - pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_AMBIENT); - - // read emissive color - clrTemp.r = pcMatIn->Emissive.r; - AI_SWAP4(clrTemp.r); - clrTemp.g = pcMatIn->Emissive.g; - AI_SWAP4(clrTemp.g); - clrTemp.b = pcMatIn->Emissive.b; - AI_SWAP4(clrTemp.b); - pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_EMISSIVE); - -#undef COLOR_MULITPLY_RGB - - // FIX: Take the opacity from the ambient color. - // The doc say something else, but it is fact that MED exports the - // opacity like this .... oh well. - clrTemp.r = pcMatIn->Ambient.a; - AI_SWAP4(clrTemp.r); - if (is_not_qnan(clrTexture.r)) { - clrTemp.r *= clrTexture.a; - } - pcMatOut->AddProperty<ai_real>(&clrTemp.r, 1, AI_MATKEY_OPACITY); - - // read phong power - int iShadingMode = (int)aiShadingMode_Gouraud; - AI_SWAP4(pcMatIn->Power); - if (0.0f != pcMatIn->Power) { - iShadingMode = (int)aiShadingMode_Phong; - // pcMatIn is packed, we can't form pointers to its members - float power = pcMatIn->Power; - pcMatOut->AddProperty<float>(&power, 1, AI_MATKEY_SHININESS); - } - pcMatOut->AddProperty<int>(&iShadingMode, 1, AI_MATKEY_SHADING_MODEL); - } else if (is_not_qnan(clrTexture.r)) { - pcMatOut->AddProperty<aiColor4D>(&clrTexture, 1, AI_MATKEY_COLOR_DIFFUSE); - pcMatOut->AddProperty<aiColor4D>(&clrTexture, 1, AI_MATKEY_COLOR_SPECULAR); - } - // if the texture could be replaced by a single material color - // we don't need the texture anymore - if (is_not_qnan(clrTexture.r)) { - pcNew.reset(); - } - - // If an ASCII effect description (HLSL?) is contained in the file, - // we can simply ignore it ... - if (iType & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF) { - VALIDATE_FILE_SIZE(szCurrent); - int32_t iMe = *((int32_t *)szCurrent); - AI_SWAP4(iMe); - szCurrent += sizeof(char) * iMe + sizeof(int32_t); - VALIDATE_FILE_SIZE(szCurrent); - } - - // If an embedded texture has been loaded setup the corresponding - // data structures in the aiScene instance - if (pcNew && pScene->mNumTextures <= 999) { - // place this as diffuse texture - char current[5]; - ai_snprintf(current, 5, "*%i", this->pScene->mNumTextures); - - aiString szFile; - const size_t iLen = strlen((const char *)current); - ::memcpy(szFile.data, (const char *)current, iLen + 1); - szFile.length = (ai_uint32)iLen; - - pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0)); - - // store the texture - if (!pScene->mNumTextures) { - pScene->mNumTextures = 1; - pScene->mTextures = new aiTexture *[1]; - pScene->mTextures[0] = pcNew.release(); - } else { - aiTexture **pc = pScene->mTextures; - pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1]; - for (unsigned int i = 0; i < pScene->mNumTextures; ++i) { - pScene->mTextures[i] = pc[i]; - } - - pScene->mTextures[pScene->mNumTextures] = pcNew.release(); - pScene->mNumTextures++; - delete[] pc; - } - } - VALIDATE_FILE_SIZE(szCurrent); - *szCurrentOut = szCurrent; -} - -// ------------------------------------------------------------------------------------------------ -// Skip a skin lump -void MDLImporter::SkipSkinLump_3DGS_MDL7( - const unsigned char *szCurrent, - const unsigned char **szCurrentOut, - unsigned int iType, - unsigned int iWidth, - unsigned int iHeight) { - // get the type of the skin - const unsigned int iMasked = (unsigned int)(iType & 0xF); - - if (0x6 == iMasked) { - szCurrent += iWidth; - } - if (0x7 == iMasked) { - const size_t iLen = std::strlen((const char *)szCurrent); - szCurrent += iLen + 1; - } else if (iMasked || !iType) { - if (iMasked || !iType || (iType && iWidth && iHeight)) { - // ParseTextureColorData(..., aiTexture::pcData == bad_texel) will simply - // return the size of the color data in bytes in iSkip - unsigned int iSkip = 0; - - aiTexture tex; - tex.pcData = bad_texel; - tex.mHeight = iHeight; - tex.mWidth = iWidth; - ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex); - - // FIX: Important, otherwise the destructor will crash - tex.pcData = nullptr; - - // skip length of texture data - szCurrent += iSkip; - } - } - - // check whether a material definition is contained in the skin - if (iType & AI_MDL7_SKINTYPE_MATERIAL) { - BE_NCONST MDL::Material_MDL7 *pcMatIn = (BE_NCONST MDL::Material_MDL7 *)szCurrent; - szCurrent = (unsigned char *)(pcMatIn + 1); - } - - // if an ASCII effect description (HLSL?) is contained in the file, - // we can simply ignore it ... - if (iType & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF) { - int32_t iMe = *((int32_t *)szCurrent); - AI_SWAP4(iMe); - szCurrent += sizeof(char) * iMe + sizeof(int32_t); - } - *szCurrentOut = szCurrent; -} - -// ------------------------------------------------------------------------------------------------ -void MDLImporter::ParseSkinLump_3DGS_MDL7( - const unsigned char *szCurrent, - const unsigned char **szCurrentOut, - std::vector<aiMaterial *> &pcMats) { - ai_assert(nullptr != szCurrent); - ai_assert(nullptr != szCurrentOut); - - *szCurrentOut = szCurrent; - BE_NCONST MDL::Skin_MDL7 *pcSkin = (BE_NCONST MDL::Skin_MDL7 *)szCurrent; - AI_SWAP4(pcSkin->width); - AI_SWAP4(pcSkin->height); - szCurrent += 12; - - // allocate an output material - aiMaterial *pcMatOut = new aiMaterial(); - pcMats.push_back(pcMatOut); - - // skip length of file name - szCurrent += AI_MDL7_MAX_TEXNAMESIZE; - - ParseSkinLump_3DGS_MDL7(szCurrent, szCurrentOut, pcMatOut, - pcSkin->typ, pcSkin->width, pcSkin->height); - - // place the name of the skin in the material - if (pcSkin->texture_name[0]) { - // the 0 termination could be there or not - we can't know - aiString szFile; - ::memcpy(szFile.data, pcSkin->texture_name, sizeof(pcSkin->texture_name)); - szFile.data[sizeof(pcSkin->texture_name)] = '\0'; - szFile.length = (ai_uint32)::strlen(szFile.data); - - pcMatOut->AddProperty(&szFile, AI_MATKEY_NAME); - } -} - -#endif // !! ASSIMP_BUILD_NO_MDL_IMPORTER |