/src/assimp/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h
Line | Count | Source |
1 | | /* |
2 | | --------------------------------------------------------------------------- |
3 | | Open Asset Import Library (assimp) |
4 | | --------------------------------------------------------------------------- |
5 | | |
6 | | Copyright (c) 2006-2026, assimp team |
7 | | |
8 | | All rights reserved. |
9 | | |
10 | | Redistribution and use of this software in source and binary forms, |
11 | | with or without modification, are permitted provided that the following |
12 | | conditions are met: |
13 | | |
14 | | * Redistributions of source code must retain the above |
15 | | copyright notice, this list of conditions and the |
16 | | following disclaimer. |
17 | | |
18 | | * Redistributions in binary form must reproduce the above |
19 | | copyright notice, this list of conditions and the |
20 | | following disclaimer in the documentation and/or other |
21 | | materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the assimp team, nor the names of its |
24 | | contributors may be used to endorse or promote products |
25 | | derived from this software without specific prior |
26 | | written permission of the assimp team. |
27 | | |
28 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
29 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
31 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
32 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
33 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
34 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
35 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
36 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
37 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
38 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
39 | | --------------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | /** @file HL1MDLLoader.h |
43 | | * @brief Declaration of the Half-Life 1 MDL loader. |
44 | | */ |
45 | | |
46 | | #ifndef AI_HL1MDLLOADER_INCLUDED |
47 | | #define AI_HL1MDLLOADER_INCLUDED |
48 | | |
49 | | #include "HL1FileData.h" |
50 | | #include "HL1DataBuffer.h" |
51 | | #include "HL1ImportSettings.h" |
52 | | #include "UniqueNameGenerator.h" |
53 | | |
54 | | #include <memory> |
55 | | #include <string> |
56 | | |
57 | | #include <assimp/types.h> |
58 | | #include <assimp/scene.h> |
59 | | #include <assimp/texture.h> |
60 | | #include <assimp/IOSystem.hpp> |
61 | | #include <assimp/DefaultIOSystem.h> |
62 | | #include <assimp/Exceptional.h> |
63 | | |
64 | | namespace Assimp { |
65 | | namespace MDL { |
66 | | namespace HalfLife { |
67 | | |
68 | | class HL1MDLLoader { |
69 | | public: |
70 | | HL1MDLLoader() = delete; |
71 | | HL1MDLLoader(const HL1MDLLoader &) = delete; |
72 | | |
73 | | /** See variables descriptions at the end for more details. */ |
74 | | HL1MDLLoader( |
75 | | aiScene *scene, |
76 | | IOSystem *io, |
77 | | const unsigned char *buffer, |
78 | | size_t buffer_length, |
79 | | const std::string &file_path, |
80 | | const HL1ImportSettings &import_settings); |
81 | | |
82 | | ~HL1MDLLoader(); |
83 | | |
84 | | void load_file(); |
85 | | |
86 | | protected: |
87 | | /** \brief Validate the header data structure of a Half-Life 1 MDL file. |
88 | | * \param[in] header Input header to be validated. |
89 | | * \param[in] is_texture_header Whether or not we are reading an MDL |
90 | | * texture file. |
91 | | */ |
92 | | void validate_header(const Header_HL1 *header, bool is_texture_header); |
93 | | |
94 | | void load_texture_file(); |
95 | | void load_sequence_groups_files(); |
96 | | void read_textures(); |
97 | | void read_skins(); |
98 | | void read_bones(); |
99 | | void read_meshes(); |
100 | | void read_animations(); |
101 | | void read_sequence_groups_info(); |
102 | | void read_sequence_infos(); |
103 | | void read_sequence_transitions(); |
104 | | void read_attachments(); |
105 | | void read_hitboxes(); |
106 | | void read_bone_controllers(); |
107 | | void read_global_info(); |
108 | | |
109 | | private: |
110 | | void release_resources(); |
111 | | |
112 | | /** \brief Load a file and copy it's content to a buffer. |
113 | | * \param file_path The path to the file to be loaded. |
114 | | * \param buffer A buffer to receive the data. |
115 | | */ |
116 | | template <typename MDLFileHeader> |
117 | | void load_file_into_buffer(const std::string &file_path, HL1DataBuffer &buffer); |
118 | | |
119 | | /** \brief Get a pointer to the specified data type in texture buffer. |
120 | | * \param offset Offset in bytes. |
121 | | * \param elements Elements count. |
122 | | */ |
123 | | template <typename DataType> |
124 | | const DataType *get_texture_buffer_data(int offset, int elements); |
125 | | |
126 | | /** \brief Get a pointer to the specified data type in animation buffer. |
127 | | * \param animation Animation index. |
128 | | * \param offset Offset in bytes. |
129 | | * \param elements Elements count. |
130 | | */ |
131 | | template <typename DataType> |
132 | | const DataType *get_anim_buffer_data(int animation, int offset, int elements); |
133 | | |
134 | | /** \brief Get a pointer to the specified data type in MDL buffer. |
135 | | * \param offset Offset in bytes. |
136 | | * \param elements Elements count. |
137 | | */ |
138 | | template <typename DataType> |
139 | | const DataType *get_buffer_data(int offset, int elements); |
140 | | |
141 | | /** \brief Read an MDL texture. |
142 | | * \param[in] ptexture A pointer to an MDL texture. |
143 | | * \param[in] data A pointer to the data from \p ptexture. |
144 | | * \param[in] pal A pointer to the texture palette from \p ptexture. |
145 | | * \param[in,out] pResult A pointer to the output resulting Assimp texture. |
146 | | * \param[in,out] last_palette_color The last color from the image palette. |
147 | | */ |
148 | | void read_texture(const Texture_HL1 *ptexture, |
149 | | const uint8_t *data, const uint8_t *pal, aiTexture *pResult, |
150 | | aiColor3D &last_palette_color); |
151 | | |
152 | | /** \brief This method reads a compressed anim value. |
153 | | * \param[in] panimvalue A pointer to the animation data. |
154 | | * \param[in] frame The frame to look for. |
155 | | * \param[in] bone_scale The current bone scale to apply to the compressed value. |
156 | | * \param[in,out] value The decompressed anim value at \p frame. |
157 | | */ |
158 | | void extract_anim_value(const AnimValue_HL1 *panimvalue, |
159 | | int frame, float bone_scale, ai_real &value); |
160 | | |
161 | | /** |
162 | | * \brief Given the number of blend animations, determine the number of blend controllers. |
163 | | * |
164 | | * \param[in] num_blend_animations The number of blend animations. |
165 | | * \param[out] num_blend_controllers The number of blend controllers. |
166 | | * \return True if the number of blend controllers was determined. False otherwise. |
167 | | */ |
168 | | static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers); |
169 | | |
170 | | /** |
171 | | * \brief Build a bone's node children hierarchy. |
172 | | * |
173 | | * \param[in] bone The bone for which we must build all children hierarchy. |
174 | | */ |
175 | | struct TempBone; |
176 | | void build_bone_children_hierarchy(const TempBone& bone); |
177 | | |
178 | | /** Output scene to be filled */ |
179 | | aiScene *scene_; |
180 | | |
181 | | /** Output I/O handler. Required for additional IO operations. */ |
182 | | IOSystem *io_; |
183 | | |
184 | | /** Buffer from MDLLoader class. */ |
185 | | const HL1DataBuffer buffer_; |
186 | | |
187 | | /** The full file path to the MDL file we are trying to load. |
188 | | * Used to locate other MDL files since MDL may store resources |
189 | | * in external MDL files. */ |
190 | | const std::string &file_path_; |
191 | | |
192 | | /** Configuration for HL1 MDL */ |
193 | | const HL1ImportSettings &import_settings_; |
194 | | |
195 | | /** Main MDL header. */ |
196 | | const Header_HL1 *header_; |
197 | | |
198 | | /** External MDL texture header. */ |
199 | | const Header_HL1 *texture_header_; |
200 | | |
201 | | /** External MDL animation headers. |
202 | | * One for each loaded animation file. */ |
203 | | std::vector<const SequenceHeader_HL1*> anim_headers_; |
204 | | |
205 | | /** Texture file data. */ |
206 | | HL1DataBuffer texture_buffer_; |
207 | | |
208 | | /** Animation files data. */ |
209 | | std::vector<HL1DataBuffer> anim_buffers_; |
210 | | |
211 | | /** The number of sequence groups. */ |
212 | | int num_sequence_groups_; |
213 | | |
214 | | /** The list of children to be appended to the scene's root node. */ |
215 | | std::vector<aiNode *> rootnode_children_; |
216 | | |
217 | | /** A unique name generator. Used to generate names for MDL values |
218 | | * that may have empty/duplicate names. */ |
219 | | UniqueNameGenerator unique_name_generator_; |
220 | | |
221 | | /** The list of unique sequence names. */ |
222 | | std::vector<std::string> unique_sequence_names_; |
223 | | |
224 | | /** The list of unique sequence groups names. */ |
225 | | std::vector<std::string> unique_sequence_groups_names_; |
226 | | |
227 | | /** Structure to store temporary bone information. */ |
228 | | struct TempBone { |
229 | | |
230 | | TempBone() : |
231 | 0 | node(nullptr), |
232 | 0 | absolute_transform(), |
233 | 0 | offset_matrix(), |
234 | 0 | children() {} |
235 | | |
236 | | aiNode *node; |
237 | | aiMatrix4x4 absolute_transform; |
238 | | aiMatrix4x4 offset_matrix; |
239 | | std::vector<int> children; // Bone children |
240 | | }; |
241 | | |
242 | | std::vector<TempBone> temp_bones_; |
243 | | |
244 | | /** The number of available bone controllers in the model. */ |
245 | | int num_blend_controllers_; |
246 | | |
247 | | /** Self explanatory. */ |
248 | | int total_models_; |
249 | | }; |
250 | | |
251 | | // ------------------------------------------------------------------------------------------------ |
252 | | template <typename MDLFileHeader> |
253 | 0 | void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, HL1DataBuffer &buffer) { |
254 | 0 | if (!io_->Exists(file_path)) |
255 | 0 | throw DeadlyImportError("Missing file ", DefaultIOSystem::fileName(file_path), "."); |
256 | | |
257 | 0 | std::unique_ptr<IOStream> file(io_->Open(file_path)); |
258 | |
|
259 | 0 | if (file == nullptr) { |
260 | 0 | throw DeadlyImportError("Failed to open MDL file ", DefaultIOSystem::fileName(file_path), "."); |
261 | 0 | } |
262 | | |
263 | 0 | const size_t file_size = file->FileSize(); |
264 | 0 | if (file_size < sizeof(MDLFileHeader)) { |
265 | 0 | throw DeadlyImportError("MDL file is too small."); |
266 | 0 | } |
267 | | |
268 | 0 | std::unique_ptr<unsigned char[]> data(new unsigned char[1 + file_size]); |
269 | 0 | file->Read(data.get(), 1, file_size); |
270 | 0 | data[file_size] = '\0'; |
271 | |
|
272 | 0 | buffer = HL1DataBuffer::owning(std::move(data), file_size); |
273 | 0 | } Unexecuted instantiation: void Assimp::MDL::HalfLife::HL1MDLLoader::load_file_into_buffer<Assimp::MDL::HalfLife::Header_HL1>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, Assimp::MDL::HalfLife::HL1DataBuffer&) Unexecuted instantiation: void Assimp::MDL::HalfLife::HL1MDLLoader::load_file_into_buffer<Assimp::MDL::HalfLife::SequenceHeader_HL1>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, Assimp::MDL::HalfLife::HL1DataBuffer&) |
274 | | |
275 | | template <typename DataType> |
276 | 0 | const DataType *HL1MDLLoader::get_texture_buffer_data(int offset, int elements) { |
277 | 0 | return texture_buffer_.get_data<DataType>(offset, elements); |
278 | 0 | } Unexecuted instantiation: Assimp::MDL::HalfLife::Header_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_texture_buffer_data<Assimp::MDL::HalfLife::Header_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::Texture_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_texture_buffer_data<Assimp::MDL::HalfLife::Texture_HL1>(int, int) Unexecuted instantiation: unsigned char const* Assimp::MDL::HalfLife::HL1MDLLoader::get_texture_buffer_data<unsigned char>(int, int) Unexecuted instantiation: short const* Assimp::MDL::HalfLife::HL1MDLLoader::get_texture_buffer_data<short>(int, int) |
279 | | |
280 | | template <typename DataType> |
281 | 0 | const DataType *HL1MDLLoader::get_anim_buffer_data(int animation, int offset, int elements) { |
282 | 0 | if (animation < 0 || animation >= num_sequence_groups_) { |
283 | 0 | throw DeadlyImportError("MDL file contains invalid sequence group index (", animation, ")"); |
284 | 0 | } |
285 | | |
286 | 0 | return anim_buffers_[animation].get_data<DataType>(offset, elements); |
287 | 0 | } Unexecuted instantiation: Assimp::MDL::HalfLife::SequenceHeader_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_anim_buffer_data<Assimp::MDL::HalfLife::SequenceHeader_HL1>(int, int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::AnimValueOffset_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_anim_buffer_data<Assimp::MDL::HalfLife::AnimValueOffset_HL1>(int, int, int) |
288 | | |
289 | | template <typename DataType> |
290 | 0 | const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) { |
291 | 0 | return buffer_.get_data<DataType>(offset, elements); |
292 | 0 | } Unexecuted instantiation: Assimp::MDL::HalfLife::Header_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::Header_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::Bone_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::Bone_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::Bodypart_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::Bodypart_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::Model_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::Model_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::Mesh_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::Mesh_HL1>(int, int) Unexecuted instantiation: unsigned char const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<unsigned char>(int, int) Unexecuted instantiation: float const (*Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<float [3]>(int, int)) [3] Unexecuted instantiation: Assimp::MDL::HalfLife::SequenceDesc_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::SequenceDesc_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::SequenceGroup_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::SequenceGroup_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::AnimValueOffset_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::AnimValueOffset_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::AnimEvent_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::AnimEvent_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::Attachment_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::Attachment_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::Hitbox_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::Hitbox_HL1>(int, int) Unexecuted instantiation: Assimp::MDL::HalfLife::BoneController_HL1 const* Assimp::MDL::HalfLife::HL1MDLLoader::get_buffer_data<Assimp::MDL::HalfLife::BoneController_HL1>(int, int) |
293 | | |
294 | | } // namespace HalfLife |
295 | | } // namespace MDL |
296 | | } // namespace Assimp |
297 | | |
298 | | #endif // AI_HL1MDLLOADER_INCLUDED |