1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2019, 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.cpp
43  *  @brief Implementation for the Half-Life 1 MDL loader.
44  */
45 
46 #include "HL1MDLLoader.h"
47 #include "HL1ImportDefinitions.h"
48 #include "HL1MeshTrivert.h"
49 #include "UniqueNameGenerator.h"
50 
51 #include <assimp/BaseImporter.h>
52 #include <assimp/StringUtils.h>
53 #include <assimp/ai_assert.h>
54 #include <assimp/qnan.h>
55 #include <assimp/DefaultLogger.hpp>
56 #include <assimp/Importer.hpp>
57 
58 #include <iomanip>
59 #include <sstream>
60 
61 #ifdef MDL_HALFLIFE_LOG_WARN_HEADER
62 #undef MDL_HALFLIFE_LOG_WARN_HEADER
63 #endif
64 #define MDL_HALFLIFE_LOG_HEADER "[Half-Life 1 MDL] "
65 #include "LogFunctions.h"
66 
67 namespace Assimp {
68 namespace MDL {
69 namespace HalfLife {
70 
71 // ------------------------------------------------------------------------------------------------
HL1MDLLoader(aiScene * scene,IOSystem * io,const unsigned char * buffer,const std::string & file_path,const HL1ImportSettings & import_settings)72 HL1MDLLoader::HL1MDLLoader(
73     aiScene *scene,
74     IOSystem *io,
75     const unsigned char *buffer,
76     const std::string &file_path,
77     const HL1ImportSettings &import_settings) :
78     scene_(scene),
79     io_(io),
80     buffer_(buffer),
81     file_path_(file_path),
82     import_settings_(import_settings),
83     header_(nullptr),
84     texture_header_(nullptr),
85     anim_headers_(nullptr),
86     texture_buffer_(nullptr),
87     anim_buffers_(nullptr),
88     num_sequence_groups_(0),
89     rootnode_children_(),
90     unique_name_generator_(),
91     unique_sequence_names_(),
92     unique_sequence_groups_names_(),
93     temp_bones_(),
94     num_blend_controllers_(0),
95     total_models_(0) {
96     load_file();
97 }
98 
99 // ------------------------------------------------------------------------------------------------
~HL1MDLLoader()100 HL1MDLLoader::~HL1MDLLoader() {
101     release_resources();
102 }
103 
104 // ------------------------------------------------------------------------------------------------
release_resources()105 void HL1MDLLoader::release_resources() {
106     if (buffer_ != texture_buffer_) {
107         delete[] texture_buffer_;
108         texture_buffer_ = nullptr;
109     }
110 
111     if (num_sequence_groups_ && anim_buffers_) {
112         for (int i = 1; i < num_sequence_groups_; ++i) {
113             if (anim_buffers_[i]) {
114                 delete[] anim_buffers_[i];
115                 anim_buffers_[i] = nullptr;
116             }
117         }
118 
119         delete[] anim_buffers_;
120         anim_buffers_ = nullptr;
121     }
122 
123     if (anim_headers_) {
124         delete[] anim_headers_;
125         anim_headers_ = nullptr;
126     }
127 }
128 
129 // ------------------------------------------------------------------------------------------------
load_file()130 void HL1MDLLoader::load_file() {
131 
132     try {
133         header_ = (const Header_HL1 *)buffer_;
134         validate_header(header_, false);
135 
136         // Create the root scene node.
137         scene_->mRootNode = new aiNode(AI_MDL_HL1_NODE_ROOT);
138 
139         load_texture_file();
140 
141         if (import_settings_.read_animations)
142             load_sequence_groups_files();
143 
144         read_textures();
145         read_skins();
146 
147         read_bones();
148         read_meshes();
149 
150         if (import_settings_.read_animations) {
151             read_sequence_groups_info();
152             read_animations();
153             read_sequence_infos();
154             if (import_settings_.read_sequence_transitions)
155                 read_sequence_transitions();
156         }
157 
158         if (import_settings_.read_attachments)
159             read_attachments();
160 
161         if (import_settings_.read_hitboxes)
162             read_hitboxes();
163 
164         if (import_settings_.read_bone_controllers)
165             read_bone_controllers();
166 
167         read_global_info();
168 
169         // Append children to root node.
170         if (rootnode_children_.size()) {
171             scene_->mRootNode->addChildren(
172                     static_cast<unsigned int>(rootnode_children_.size()),
173                     rootnode_children_.data());
174         }
175 
176         release_resources();
177 
178     } catch (const std::exception &e) {
179         release_resources();
180         throw e;
181     }
182 }
183 
184 // ------------------------------------------------------------------------------------------------
validate_header(const Header_HL1 * header,bool is_texture_header)185 void HL1MDLLoader::validate_header(const Header_HL1 *header, bool is_texture_header) {
186     if (is_texture_header) {
187         // Every single Half-Life model is assumed to have at least one texture.
188         if (!header->numtextures)
189             throw DeadlyImportError(MDL_HALFLIFE_LOG_HEADER "There are no textures in the file");
190 
191         if (header->numtextures > AI_MDL_HL1_MAX_TEXTURES)
192             log_warning_limit_exceeded<AI_MDL_HL1_MAX_TEXTURES>(header->numtextures, "textures");
193 
194         if (header->numskinfamilies > AI_MDL_HL1_MAX_SKIN_FAMILIES)
195             log_warning_limit_exceeded<AI_MDL_HL1_MAX_SKIN_FAMILIES>(header->numskinfamilies, "skin families");
196 
197     } else {
198         // Every single Half-Life model is assumed to have at least one bodypart.
199         if (!header->numbodyparts)
200             throw DeadlyImportError(MDL_HALFLIFE_LOG_HEADER "Model has no bodyparts");
201 
202         // Every single Half-Life model is assumed to have at least one bone.
203         if (!header->numbones)
204             throw DeadlyImportError(MDL_HALFLIFE_LOG_HEADER "Model has no bones");
205 
206         // Every single Half-Life model is assumed to have at least one sequence group,
207         // which is the "default" sequence group.
208         if (!header->numseqgroups)
209             throw DeadlyImportError(MDL_HALFLIFE_LOG_HEADER "Model has no sequence groups");
210 
211         if (header->numbodyparts > AI_MDL_HL1_MAX_BODYPARTS)
212             log_warning_limit_exceeded<AI_MDL_HL1_MAX_BODYPARTS>(header->numbodyparts, "bodyparts");
213 
214         if (header->numbones > AI_MDL_HL1_MAX_BONES)
215             log_warning_limit_exceeded<AI_MDL_HL1_MAX_BONES>(header->numbones, "bones");
216 
217         if (header->numbonecontrollers > AI_MDL_HL1_MAX_BONE_CONTROLLERS)
218             log_warning_limit_exceeded<AI_MDL_HL1_MAX_BONE_CONTROLLERS>(header->numbonecontrollers, "bone controllers");
219 
220         if (header->numseq > AI_MDL_HL1_MAX_SEQUENCES)
221             log_warning_limit_exceeded<AI_MDL_HL1_MAX_SEQUENCES>(header->numseq, "sequences");
222 
223         if (header->numseqgroups > AI_MDL_HL1_MAX_SEQUENCE_GROUPS)
224             log_warning_limit_exceeded<AI_MDL_HL1_MAX_SEQUENCE_GROUPS>(header->numseqgroups, "sequence groups");
225 
226         if (header->numattachments > AI_MDL_HL1_MAX_ATTACHMENTS)
227             log_warning_limit_exceeded<AI_MDL_HL1_MAX_ATTACHMENTS>(header->numattachments, "attachments");
228     }
229 }
230 
231 // ------------------------------------------------------------------------------------------------
232 /*
233     Load textures.
234 
235     There are two ways for textures to be stored in a Half-Life model:
236 
237     1. Directly in the MDL file (filePath) or
238     2. In an external MDL file.
239 
240     Due to the way StudioMDL works (tool used to compile SMDs into MDLs),
241     it is assumed that an external texture file follows the naming
242     convention: <YourModelName>T.mdl. Note the extra (T) at the end of the
243     model name.
244 
245     .e.g For a given model named MyModel.mdl
246 
247     The external texture file name would be MyModelT.mdl
248 */
load_texture_file()249 void HL1MDLLoader::load_texture_file() {
250     if (header_->numtextures == 0) {
251         // Load an external MDL texture file.
252         std::string texture_file_path =
253                 DefaultIOSystem::absolutePath(file_path_) + io_->getOsSeparator() +
254                 DefaultIOSystem::completeBaseName(file_path_) + "T." +
255                 BaseImporter::GetExtension(file_path_);
256 
257         load_file_into_buffer<Header_HL1>(texture_file_path, texture_buffer_);
258     } else {
259         /* Model has no external texture file. This means the texture
260         is stored inside the main MDL file. */
261         texture_buffer_ = const_cast<unsigned char *>(buffer_);
262     }
263 
264     texture_header_ = (const Header_HL1 *)texture_buffer_;
265 
266     // Validate texture header.
267     validate_header(texture_header_, true);
268 }
269 
270 // ------------------------------------------------------------------------------------------------
271 /*
272     Load sequence group files if any.
273 
274     Due to the way StudioMDL works (tool used to compile SMDs into MDLs),
275     it is assumed that a sequence group file follows the naming
276     convention: <YourModelName>0X.mdl. Note the extra (0X) at the end of
277     the model name, where (X) is the sequence group.
278 
279     .e.g For a given model named MyModel.mdl
280 
281     Sequence group 1 => MyModel01.mdl
282     Sequence group 2 => MyModel02.mdl
283     Sequence group X => MyModel0X.mdl
284 
285 */
load_sequence_groups_files()286 void HL1MDLLoader::load_sequence_groups_files() {
287     if (header_->numseqgroups <= 1)
288         return;
289 
290     num_sequence_groups_ = header_->numseqgroups;
291 
292     anim_buffers_ = new unsigned char *[num_sequence_groups_];
293     anim_headers_ = new SequenceHeader_HL1 *[num_sequence_groups_];
294     for (int i = 0; i < num_sequence_groups_; ++i) {
295         anim_buffers_[i] = NULL;
296         anim_headers_[i] = NULL;
297     }
298 
299     std::string file_path_without_extension =
300             DefaultIOSystem::absolutePath(file_path_) +
301             io_->getOsSeparator() +
302             DefaultIOSystem::completeBaseName(file_path_);
303 
304     for (int i = 1; i < num_sequence_groups_; ++i) {
305         std::stringstream ss;
306         ss << file_path_without_extension;
307         ss << std::setw(2) << std::setfill('0') << i;
308         ss << '.' << BaseImporter::GetExtension(file_path_);
309 
310         std::string sequence_file_path = ss.str();
311 
312         load_file_into_buffer<SequenceHeader_HL1>(sequence_file_path, anim_buffers_[i]);
313 
314         anim_headers_[i] = (SequenceHeader_HL1 *)anim_buffers_[i];
315     }
316 }
317 
318 // ------------------------------------------------------------------------------------------------
319 /** @brief Read an MDL texture.
320 *
321 *   @note This method is taken from HL1 source code.
322 *   source: file: studio_utils.c
323 *           function(s): UploadTexture
324 */
read_texture(const Texture_HL1 * ptexture,uint8_t * data,uint8_t * pal,aiTexture * pResult,aiColor3D & last_palette_color)325 void HL1MDLLoader::read_texture(const Texture_HL1 *ptexture,
326         uint8_t *data, uint8_t *pal, aiTexture *pResult,
327         aiColor3D &last_palette_color) {
328     int outwidth, outheight;
329     int i, j;
330     int row1[256], row2[256], col1[256], col2[256];
331     unsigned char *pix1, *pix2, *pix3, *pix4;
332 
333     // convert texture to power of 2
334     for (outwidth = 1; outwidth < ptexture->width; outwidth <<= 1)
335         ;
336 
337     if (outwidth > 256)
338         outwidth = 256;
339 
340     for (outheight = 1; outheight < ptexture->height; outheight <<= 1)
341         ;
342 
343     if (outheight > 256)
344         outheight = 256;
345 
346     pResult->mFilename = ptexture->name;
347     pResult->mWidth = outwidth;
348     pResult->mHeight = outheight;
349     pResult->achFormatHint[0] = 'b';
350     pResult->achFormatHint[1] = 'g';
351     pResult->achFormatHint[2] = 'r';
352     pResult->achFormatHint[3] = 'a';
353     pResult->achFormatHint[4] = '8';
354     pResult->achFormatHint[5] = '8';
355     pResult->achFormatHint[6] = '8';
356     pResult->achFormatHint[7] = '8';
357     pResult->achFormatHint[8] = '\0';
358 
359     aiTexel *out = pResult->pcData = new aiTexel[outwidth * outheight];
360 
361     for (i = 0; i < outwidth; i++) {
362         col1[i] = (int)((i + 0.25) * (ptexture->width / (float)outwidth));
363         col2[i] = (int)((i + 0.75) * (ptexture->width / (float)outwidth));
364     }
365 
366     for (i = 0; i < outheight; i++) {
367         row1[i] = (int)((i + 0.25) * (ptexture->height / (float)outheight)) * ptexture->width;
368         row2[i] = (int)((i + 0.75) * (ptexture->height / (float)outheight)) * ptexture->width;
369     }
370 
371     // scale down and convert to 32bit RGB
372     for (i = 0; i < outheight; i++) {
373         for (j = 0; j < outwidth; j++, out++) {
374             pix1 = &pal[data[row1[i] + col1[j]] * 3];
375             pix2 = &pal[data[row1[i] + col2[j]] * 3];
376             pix3 = &pal[data[row2[i] + col1[j]] * 3];
377             pix4 = &pal[data[row2[i] + col2[j]] * 3];
378 
379             out->r = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2;
380             out->g = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2;
381             out->b = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2;
382             out->a = 0xFF;
383         }
384     }
385 
386     // Get the last palette color.
387     last_palette_color.r = pal[255 * 3];
388     last_palette_color.g = pal[255 * 3 + 1];
389     last_palette_color.b = pal[255 * 3 + 2];
390 }
391 
392 // ------------------------------------------------------------------------------------------------
read_textures()393 void HL1MDLLoader::read_textures() {
394     const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex);
395     unsigned char *pin = texture_buffer_;
396 
397     scene_->mNumTextures = scene_->mNumMaterials = texture_header_->numtextures;
398     scene_->mTextures = new aiTexture *[scene_->mNumTextures];
399     scene_->mMaterials = new aiMaterial *[scene_->mNumMaterials];
400 
401     for (int i = 0; i < texture_header_->numtextures; ++i) {
402         scene_->mTextures[i] = new aiTexture();
403 
404         aiColor3D last_palette_color;
405         read_texture(&ptexture[i],
406                 pin + ptexture[i].index,
407                 pin + ptexture[i].width * ptexture[i].height + ptexture[i].index,
408                 scene_->mTextures[i],
409                 last_palette_color);
410 
411         aiMaterial *scene_material = scene_->mMaterials[i] = new aiMaterial();
412 
413         const aiTextureType texture_type = aiTextureType_DIFFUSE;
414         aiString texture_name(ptexture[i].name);
415         scene_material->AddProperty(&texture_name, AI_MATKEY_TEXTURE(texture_type, 0));
416 
417         // Is this a chrome texture?
418         int chrome = ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_CHROME ? 1 : 0;
419         scene_material->AddProperty(&chrome, 1, AI_MDL_HL1_MATKEY_CHROME(texture_type, 0));
420 
421         if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_FLATSHADE) {
422             // Flat shading.
423             const aiShadingMode shading_mode = aiShadingMode_Flat;
424             scene_material->AddProperty(&shading_mode, 1, AI_MATKEY_SHADING_MODEL);
425         }
426 
427         if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_ADDITIVE) {
428             // Additive texture.
429             const aiBlendMode blend_mode = aiBlendMode_Additive;
430             scene_material->AddProperty(&blend_mode, 1, AI_MATKEY_BLEND_FUNC);
431         } else if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_MASKED) {
432             // Texture with 1 bit alpha test.
433             const aiTextureFlags use_alpha = aiTextureFlags_UseAlpha;
434             scene_material->AddProperty(&use_alpha, 1, AI_MATKEY_TEXFLAGS(texture_type, 0));
435             scene_material->AddProperty(&last_palette_color, 1, AI_MATKEY_COLOR_TRANSPARENT);
436         }
437     }
438 }
439 
440 // ------------------------------------------------------------------------------------------------
read_skins()441 void HL1MDLLoader::read_skins() {
442     // Read skins, if any.
443     if (texture_header_->numskinfamilies <= 1)
444         return;
445 
446     // Pointer to base texture index.
447     short *default_skin_ptr = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex);
448 
449     // Start at first replacement skin.
450     short *replacement_skin_ptr = default_skin_ptr + texture_header_->numskinref;
451 
452     for (int i = 1; i < texture_header_->numskinfamilies; ++i, replacement_skin_ptr += texture_header_->numskinref) {
453         for (int j = 0; j < texture_header_->numskinref; ++j) {
454             if (default_skin_ptr[j] != replacement_skin_ptr[j]) {
455                 // Save replacement textures.
456                 aiString skinMaterialId(scene_->mTextures[replacement_skin_ptr[j]]->mFilename);
457                 scene_->mMaterials[default_skin_ptr[j]]->AddProperty(&skinMaterialId, AI_MATKEY_TEXTURE_DIFFUSE(i));
458             }
459         }
460     }
461 }
462 
463 // ------------------------------------------------------------------------------------------------
read_bones()464 void HL1MDLLoader::read_bones() {
465     const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex);
466 
467     std::vector<std::string> unique_bones_names(header_->numbones);
468     for (int i = 0; i < header_->numbones; ++i)
469         unique_bones_names[i] = pbone[i].name;
470 
471     // Ensure bones have unique names.
472     unique_name_generator_.set_template_name("Bone");
473     unique_name_generator_.make_unique(unique_bones_names);
474 
475     temp_bones_.resize(header_->numbones);
476 
477     aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES);
478     rootnode_children_.push_back(bones_node);
479     bones_node->mNumChildren = static_cast<unsigned int>(header_->numbones);
480     bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
481 
482     // Create bone matrices in local space.
483     for (int i = 0; i < header_->numbones; ++i) {
484         aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]);
485 
486         aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]);
487         temp_bones_[i].absolute_transform = bone_node->mTransformation =
488                 aiMatrix4x4(aiVector3D(1), aiQuaternion(angles.y, angles.z, angles.x),
489                         aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2]));
490 
491         if (pbone[i].parent == -1) {
492             bone_node->mParent = scene_->mRootNode;
493         } else {
494             bone_node->mParent = bones_node->mChildren[pbone[i].parent];
495 
496             temp_bones_[i].absolute_transform =
497                     temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation;
498         }
499 
500         temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform;
501         temp_bones_[i].offset_matrix.Inverse();
502     }
503 }
504 
505 // ------------------------------------------------------------------------------------------------
506 /*
507     Read meshes.
508 
509     Half-Life MDLs are structured such that each MDL
510     contains one or more 'bodypart(s)', which contain one
511     or more 'model(s)', which contains one or more mesh(es).
512 
513     * Bodyparts are used to group models that may be replaced
514     in the game .e.g a character could have a 'heads' group,
515     'torso' group, 'shoes' group, with each group containing
516     different 'model(s)'.
517 
518     * Models, also called 'sub models', contain vertices as
519     well as a reference to each mesh used by the sub model.
520 
521     * Meshes contain a list of tris, also known as 'triverts'.
522     Each tris contains the following information:
523 
524         1. The index of the position to use for the vertex.
525         2. The index of the normal to use for the vertex.
526         3. The S coordinate to use for the vertex UV.
527         4. The T coordinate ^
528 
529     These tris represent the way to represent the triangles
530     for each mesh. Depending on how the tool compiled the MDL,
531     those triangles were saved as strips and or fans.
532 
533     NOTE: Each tris is NOT unique. This means that you
534     might encounter the same vertex index but with a different
535     normal index, S coordinate, T coordinate.
536 
537     In addition, each mesh contains the texture's index.
538 
539     ------------------------------------------------------
540     With the details above, there are several things to
541     take into consideration.
542 
543     * The Half-Life models store the vertices by sub model
544     rather than by mesh. Due to Assimp's structure, it
545     is necessary to remap each model vertex to be used
546     per mesh. Unfortunately, this has the consequence
547     to duplicate vertices.
548 
549     * Because the mesh triangles are comprised of strips and
550     fans, it is necessary to convert each primitive to
551     triangles, respectively (3 indices per face).
552 */
read_meshes()553 void HL1MDLLoader::read_meshes() {
554 
555     int total_verts = 0;
556     int total_triangles = 0;
557     total_models_ = 0;
558 
559     const Bodypart_HL1 *pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex);
560     const Model_HL1 *pmodel = nullptr;
561     const Mesh_HL1 *pmesh = nullptr;
562 
563     const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex);
564     short *pskinref = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex);
565 
566     scene_->mNumMeshes = 0;
567 
568     std::vector<std::string> unique_bodyparts_names;
569     unique_bodyparts_names.resize(header_->numbodyparts);
570 
571     // Count the number of meshes.
572 
573     for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) {
574         unique_bodyparts_names[i] = pbodypart->name;
575 
576         pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex);
577         for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel) {
578             scene_->mNumMeshes += pmodel->nummesh;
579             total_verts += pmodel->numverts;
580         }
581 
582         total_models_ += pbodypart->nummodels;
583     }
584 
585     // Display limit infos.
586     if (total_verts > AI_MDL_HL1_MAX_VERTICES)
587         log_warning_limit_exceeded<AI_MDL_HL1_MAX_VERTICES>(total_verts, "vertices");
588 
589     if (scene_->mNumMeshes > AI_MDL_HL1_MAX_MESHES)
590         log_warning_limit_exceeded<AI_MDL_HL1_MAX_MESHES>(scene_->mNumMeshes, "meshes");
591 
592     if (total_models_ > AI_MDL_HL1_MAX_MODELS)
593         log_warning_limit_exceeded<AI_MDL_HL1_MAX_MODELS>(total_models_, "models");
594 
595     // Ensure bodyparts have unique names.
596     unique_name_generator_.set_template_name("Bodypart");
597     unique_name_generator_.make_unique(unique_bodyparts_names);
598 
599     // Now do the same for each model.
600     pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex);
601 
602     // Prepare template name for bodypart models.
603     std::vector<std::string> unique_models_names;
604     unique_models_names.resize(total_models_);
605 
606     unsigned int model_index = 0;
607 
608     for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) {
609         pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex);
610         for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel, ++model_index)
611             unique_models_names[model_index] = pmodel->name;
612     }
613 
614     unique_name_generator_.set_template_name("Model");
615     unique_name_generator_.make_unique(unique_models_names);
616 
617     unsigned int mesh_index = 0;
618 
619     scene_->mMeshes = new aiMesh *[scene_->mNumMeshes];
620 
621     pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex);
622 
623     /* Create a node that will represent the mesh hierarchy.
624 
625         <MDL_bodyparts>
626             |
627             +-- bodypart --+-- model -- [mesh index, mesh index, ...]
628             |              |
629             |              +-- model -- [mesh index, mesh index, ...]
630             |              |
631             |              ...
632             |
633             |-- bodypart -- ...
634             |
635             ...
636      */
637     aiNode *bodyparts_node = new aiNode(AI_MDL_HL1_NODE_BODYPARTS);
638     rootnode_children_.push_back(bodyparts_node);
639     bodyparts_node->mNumChildren = static_cast<unsigned int>(header_->numbodyparts);
640     bodyparts_node->mChildren = new aiNode *[bodyparts_node->mNumChildren];
641     aiNode **bodyparts_node_ptr = bodyparts_node->mChildren;
642 
643     // The following variables are defined here so they don't have
644     // to be recreated every iteration.
645 
646     // Model_HL1 vertices, in bind pose space.
647     std::vector<aiVector3D> bind_pose_vertices;
648 
649     // Model_HL1 normals, in bind pose space.
650     std::vector<aiVector3D> bind_pose_normals;
651 
652     // Used to contain temporary information for building a mesh.
653     std::vector<HL1MeshTrivert> triverts;
654 
655     std::vector<short> tricmds;
656 
657     // Which triverts to use for the mesh.
658     std::vector<short> mesh_triverts_indices;
659 
660     std::vector<HL1MeshFace> mesh_faces;
661 
662     /* triverts that have the same vertindex, but have different normindex,s,t values.
663        Similar triverts are mapped from vertindex to a list of similar triverts. */
664     std::map<short, std::set<short>> triverts_similars;
665 
666     // triverts per bone.
667     std::map<int, std::set<short>> bone_triverts;
668 
669     /** This function adds a trivert index to the list of triverts per bone.
670      * \param[in] bone The bone that affects the trivert at index \p trivert_index.
671      * \param[in] trivert_index The trivert index.
672      */
673     auto AddTrivertToBone = [&](int bone, short trivert_index) {
674         if (bone_triverts.count(bone) == 0)
675             bone_triverts.insert({ bone, std::set<short>{ trivert_index }});
676         else
677             bone_triverts[bone].insert(trivert_index);
678     };
679 
680     /** This function creates and appends a new trivert to the list of triverts.
681      * \param[in] trivert The trivert to use as a prototype.
682      * \param[in] bone The bone that affects \p trivert.
683      */
684     auto AddSimilarTrivert = [&](const Trivert &trivert, const int bone) {
685         HL1MeshTrivert new_trivert(trivert);
686         new_trivert.localindex = static_cast<short>(mesh_triverts_indices.size());
687 
688         short new_trivert_index = static_cast<short>(triverts.size());
689 
690         if (triverts_similars.count(trivert.vertindex) == 0)
691             triverts_similars.insert({ trivert.vertindex, std::set<short>{ new_trivert_index }});
692         else
693             triverts_similars[trivert.vertindex].insert(new_trivert_index);
694 
695         triverts.push_back(new_trivert);
696 
697         mesh_triverts_indices.push_back(new_trivert_index);
698         tricmds.push_back(new_trivert.localindex);
699         AddTrivertToBone(bone, new_trivert.localindex);
700     };
701 
702     model_index = 0;
703 
704     for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart, ++bodyparts_node_ptr) {
705         pmodel = (const Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex);
706 
707         // Create bodypart node for the mesh tree hierarchy.
708         aiNode *bodypart_node = (*bodyparts_node_ptr) = new aiNode(unique_bodyparts_names[i]);
709         bodypart_node->mParent = bodyparts_node;
710         bodypart_node->mMetaData = aiMetadata::Alloc(1);
711         bodypart_node->mMetaData->Set(0, "Base", pbodypart->base);
712 
713         bodypart_node->mNumChildren = static_cast<unsigned int>(pbodypart->nummodels);
714         bodypart_node->mChildren = new aiNode *[bodypart_node->mNumChildren];
715         aiNode **bodypart_models_ptr = bodypart_node->mChildren;
716 
717         for (int j = 0; j < pbodypart->nummodels;
718                 ++j, ++pmodel, ++bodypart_models_ptr, ++model_index) {
719 
720             pmesh = (const Mesh_HL1 *)((uint8_t *)header_ + pmodel->meshindex);
721 
722             uint8_t *pvertbone = ((uint8_t *)header_ + pmodel->vertinfoindex);
723             uint8_t *pnormbone = ((uint8_t *)header_ + pmodel->norminfoindex);
724             vec3_t *pstudioverts = (vec3_t *)((uint8_t *)header_ + pmodel->vertindex);
725             vec3_t *pstudionorms = (vec3_t *)((uint8_t *)header_ + pmodel->normindex);
726 
727             // Each vertex and normal is in local space, so transform
728             // each of them to bring them in bind pose.
729             bind_pose_vertices.resize(pmodel->numverts);
730             bind_pose_normals.resize(pmodel->numnorms);
731             for (size_t k = 0; k < bind_pose_vertices.size(); ++k) {
732                 const vec3_t &vert = pstudioverts[k];
733                 bind_pose_vertices[k] = temp_bones_[pvertbone[k]].absolute_transform * aiVector3D(vert[0], vert[1], vert[2]);
734             }
735             for (size_t k = 0; k < bind_pose_normals.size(); ++k) {
736                 const vec3_t &norm = pstudionorms[k];
737                 // Compute the normal matrix to transform the normal into bind pose,
738                 // without affecting its length.
739                 const aiMatrix4x4 normal_matrix = aiMatrix4x4(temp_bones_[pnormbone[k]].absolute_transform).Inverse().Transpose();
740                 bind_pose_normals[k] = normal_matrix * aiVector3D(norm[0], norm[1], norm[2]);
741             }
742 
743             // Create model node for the mesh tree hierarchy.
744             aiNode *model_node = (*bodypart_models_ptr) = new aiNode(unique_models_names[model_index]);
745             model_node->mParent = bodypart_node;
746             model_node->mNumMeshes = static_cast<unsigned int>(pmodel->nummesh);
747             model_node->mMeshes = new unsigned int[model_node->mNumMeshes];
748             unsigned int *model_meshes_ptr = model_node->mMeshes;
749 
750             for (int k = 0; k < pmodel->nummesh; ++k, ++pmesh, ++mesh_index, ++model_meshes_ptr) {
751                 *model_meshes_ptr = mesh_index;
752 
753                 // Read triverts.
754                 short *ptricmds = (short *)((uint8_t *)header_ + pmesh->triindex);
755                 float texcoords_s_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].width;
756                 float texcoords_t_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].height;
757 
758                 // Reset the data for the upcoming mesh.
759                 triverts.clear();
760                 triverts.resize(pmodel->numverts);
761                 mesh_triverts_indices.clear();
762                 mesh_faces.clear();
763                 triverts_similars.clear();
764                 bone_triverts.clear();
765 
766                 int l;
767                 while ((l = *(ptricmds++))) {
768                     bool is_triangle_fan = false;
769 
770                     if (l < 0) {
771                         l = -l;
772                         is_triangle_fan = true;
773                     }
774 
775                     // Clear the list of tris for the upcoming tris.
776                     tricmds.clear();
777 
778                     for (; l > 0; l--, ptricmds += 4) {
779                         const Trivert *input_trivert = reinterpret_cast<const Trivert *>(ptricmds);
780                         const int bone = pvertbone[input_trivert->vertindex];
781 
782                         HL1MeshTrivert *private_trivert = &triverts[input_trivert->vertindex];
783                         if (private_trivert->localindex == -1) {
784                             // First time referenced.
785                             *private_trivert = *input_trivert;
786                             private_trivert->localindex = static_cast<short>(mesh_triverts_indices.size());
787                             mesh_triverts_indices.push_back(input_trivert->vertindex);
788                             tricmds.push_back(private_trivert->localindex);
789                             AddTrivertToBone(bone, private_trivert->localindex);
790                         } else if (*private_trivert == *input_trivert) {
791                             // Exists and is the same.
792                             tricmds.push_back(private_trivert->localindex);
793                         } else {
794                             // No similar trivert associated to the trivert currently processed.
795                             if (triverts_similars.count(input_trivert->vertindex) == 0)
796                                 AddSimilarTrivert(*input_trivert, bone);
797                             else {
798                                 // Search in the list of similar triverts to see if the
799                                 // trivert in process is already registered.
800                                 short similar_index = -1;
801                                 for (auto it = triverts_similars[input_trivert->vertindex].cbegin();
802                                         similar_index == -1 && it != triverts_similars[input_trivert->vertindex].cend();
803                                         ++it) {
804                                     if (triverts[*it] == *input_trivert)
805                                         similar_index = *it;
806                                 }
807 
808                                 // If a similar trivert has been found, reuse it.
809                                 // Otherwise, add it.
810                                 if (similar_index == -1)
811                                     AddSimilarTrivert(*input_trivert, bone);
812                                 else
813                                     tricmds.push_back(triverts[similar_index].localindex);
814                             }
815                         }
816                     }
817 
818                     // Build mesh faces.
819                     const int num_faces = static_cast<int>(tricmds.size() - 2);
820                     mesh_faces.reserve(num_faces);
821 
822                     if (is_triangle_fan) {
823                         for (int i = 0; i < num_faces; ++i) {
824                             mesh_faces.push_back(HL1MeshFace{
825                                     tricmds[0],
826                                     tricmds[i + 1],
827                                     tricmds[i + 2] });
828                         }
829                     } else {
830                         for (int i = 0; i < num_faces; ++i) {
831                             if (i & 1) {
832                                 // Preserve winding order.
833                                 mesh_faces.push_back(HL1MeshFace{
834                                         tricmds[i + 1],
835                                         tricmds[i],
836                                         tricmds[i + 2] });
837                             } else {
838                                 mesh_faces.push_back(HL1MeshFace{
839                                         tricmds[i],
840                                         tricmds[i + 1],
841                                         tricmds[i + 2] });
842                             }
843                         }
844                     }
845 
846                     total_triangles += num_faces;
847                 }
848 
849                 // Create the scene mesh.
850                 aiMesh *scene_mesh = scene_->mMeshes[mesh_index] = new aiMesh();
851                 scene_mesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_TRIANGLE;
852                 scene_mesh->mMaterialIndex = pskinref[pmesh->skinref];
853 
854                 scene_mesh->mNumVertices = static_cast<unsigned int>(mesh_triverts_indices.size());
855 
856                 if (scene_mesh->mNumVertices) {
857                     scene_mesh->mVertices = new aiVector3D[scene_mesh->mNumVertices];
858                     scene_mesh->mNormals = new aiVector3D[scene_mesh->mNumVertices];
859 
860                     scene_mesh->mNumUVComponents[0] = 2;
861                     scene_mesh->mTextureCoords[0] = new aiVector3D[scene_mesh->mNumVertices];
862 
863                     // Add vertices.
864                     for (unsigned int v = 0; v < scene_mesh->mNumVertices; ++v) {
865                         const HL1MeshTrivert *pTrivert = &triverts[mesh_triverts_indices[v]];
866                         scene_mesh->mVertices[v] = bind_pose_vertices[pTrivert->vertindex];
867                         scene_mesh->mNormals[v] = bind_pose_normals[pTrivert->normindex];
868                         scene_mesh->mTextureCoords[0][v] = aiVector3D(
869                                 pTrivert->s * texcoords_s_scale,
870                                 pTrivert->t * texcoords_t_scale, 0);
871                     }
872 
873                     // Add face and indices.
874                     scene_mesh->mNumFaces = static_cast<unsigned int>(mesh_faces.size());
875                     scene_mesh->mFaces = new aiFace[scene_mesh->mNumFaces];
876 
877                     for (unsigned int f = 0; f < scene_mesh->mNumFaces; ++f) {
878                         aiFace *face = &scene_mesh->mFaces[f];
879                         face->mNumIndices = 3;
880                         face->mIndices = new unsigned int[3];
881                         face->mIndices[0] = mesh_faces[f].v0;
882                         face->mIndices[1] = mesh_faces[f].v1;
883                         face->mIndices[2] = mesh_faces[f].v2;
884                     }
885 
886                     // Add mesh bones.
887                     scene_mesh->mNumBones = static_cast<unsigned int>(bone_triverts.size());
888                     scene_mesh->mBones = new aiBone *[scene_mesh->mNumBones];
889 
890                     aiBone **scene_bone_ptr = scene_mesh->mBones;
891 
892                     for (auto bone_it = bone_triverts.cbegin();
893                             bone_it != bone_triverts.cend();
894                             ++bone_it, ++scene_bone_ptr) {
895                         const int bone_index = bone_it->first;
896 
897                         aiBone *scene_bone = (*scene_bone_ptr) = new aiBone();
898                         scene_bone->mName = temp_bones_[bone_index].node->mName;
899 
900                         scene_bone->mOffsetMatrix = temp_bones_[bone_index].offset_matrix;
901 
902                         auto vertex_ids = bone_triverts.at(bone_index);
903 
904                         // Add vertex weight per bone.
905                         scene_bone->mNumWeights = static_cast<unsigned int>(vertex_ids.size());
906                         aiVertexWeight *vertex_weight_ptr = scene_bone->mWeights = new aiVertexWeight[scene_bone->mNumWeights];
907 
908                         for (auto vertex_it = vertex_ids.begin();
909                                 vertex_it != vertex_ids.end();
910                                 ++vertex_it, ++vertex_weight_ptr) {
911                             vertex_weight_ptr->mVertexId = *vertex_it;
912                             vertex_weight_ptr->mWeight = 1.0f;
913                         }
914                     }
915                 }
916             }
917         }
918     }
919 
920     if (total_triangles > AI_MDL_HL1_MAX_TRIANGLES)
921         log_warning_limit_exceeded<AI_MDL_HL1_MAX_TRIANGLES>(total_triangles, "triangles");
922 }
923 
924 // ------------------------------------------------------------------------------------------------
read_animations()925 void HL1MDLLoader::read_animations() {
926     if (!header_->numseq)
927         return;
928 
929     const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex);
930     const SequenceGroup_HL1 *pseqgroup = nullptr;
931     const AnimValueOffset_HL1 *panim = nullptr;
932     const AnimValue_HL1 *panimvalue = nullptr;
933 
934     unique_sequence_names_.resize(header_->numseq);
935     for (int i = 0; i < header_->numseq; ++i)
936         unique_sequence_names_[i] = pseqdesc[i].label;
937 
938     // Ensure sequences have unique names.
939     unique_name_generator_.set_template_name("Sequence");
940     unique_name_generator_.make_unique(unique_sequence_names_);
941 
942     scene_->mNumAnimations = 0;
943 
944     int highest_num_blend_animations = SequenceBlendMode_HL1::NoBlend;
945 
946     // Count the total number of animations.
947     for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) {
948         scene_->mNumAnimations += pseqdesc->numblends;
949         highest_num_blend_animations = std::max(pseqdesc->numblends, highest_num_blend_animations);
950     }
951 
952     // Get the number of available blend controllers for global info.
953     get_num_blend_controllers(highest_num_blend_animations, num_blend_controllers_);
954 
955     pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex);
956 
957     aiAnimation **scene_animations_ptr = scene_->mAnimations = new aiAnimation *[scene_->mNumAnimations];
958 
959     for (int sequence = 0; sequence < header_->numseq; ++sequence, ++pseqdesc) {
960         pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex) + pseqdesc->seqgroup;
961 
962         if (pseqdesc->seqgroup == 0)
963             panim = (const AnimValueOffset_HL1 *)((uint8_t *)header_ + pseqgroup->unused2 + pseqdesc->animindex);
964         else
965             panim = (const AnimValueOffset_HL1 *)((uint8_t *)anim_headers_[pseqdesc->seqgroup] + pseqdesc->animindex);
966 
967         for (int blend = 0; blend < pseqdesc->numblends; ++blend, ++scene_animations_ptr) {
968 
969             const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex);
970 
971             aiAnimation *scene_animation = (*scene_animations_ptr) = new aiAnimation();
972 
973             scene_animation->mName = unique_sequence_names_[sequence];
974             scene_animation->mTicksPerSecond = pseqdesc->fps;
975             scene_animation->mDuration = static_cast<double>(pseqdesc->fps) * pseqdesc->numframes;
976             scene_animation->mNumChannels = static_cast<unsigned int>(header_->numbones);
977             scene_animation->mChannels = new aiNodeAnim *[scene_animation->mNumChannels];
978 
979             for (int bone = 0; bone < header_->numbones; bone++, ++pbone, ++panim) {
980                 aiNodeAnim *node_anim = scene_animation->mChannels[bone] = new aiNodeAnim();
981                 node_anim->mNodeName = temp_bones_[bone].node->mName;
982 
983                 node_anim->mNumPositionKeys = pseqdesc->numframes;
984                 node_anim->mNumRotationKeys = node_anim->mNumPositionKeys;
985                 node_anim->mNumScalingKeys = 0;
986 
987                 node_anim->mPositionKeys = new aiVectorKey[node_anim->mNumPositionKeys];
988                 node_anim->mRotationKeys = new aiQuatKey[node_anim->mNumRotationKeys];
989 
990                 for (int frame = 0; frame < pseqdesc->numframes; ++frame) {
991                     aiVectorKey *position_key = &node_anim->mPositionKeys[frame];
992                     aiQuatKey *rotation_key = &node_anim->mRotationKeys[frame];
993 
994                     aiVector3D angle1;
995                     for (int j = 0; j < 3; ++j) {
996                         if (panim->offset[j + 3] != 0) {
997                             // Read compressed rotation delta.
998                             panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j + 3]);
999                             extract_anim_value(panimvalue, frame, pbone->scale[j + 3], angle1[j]);
1000                         }
1001 
1002                         // Add the default rotation value.
1003                         angle1[j] += pbone->value[j + 3];
1004 
1005                         if (panim->offset[j] != 0) {
1006                             // Read compressed position delta.
1007                             panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j]);
1008                             extract_anim_value(panimvalue, frame, pbone->scale[j], position_key->mValue[j]);
1009                         }
1010 
1011                         // Add the default position value.
1012                         position_key->mValue[j] += pbone->value[j];
1013                     }
1014 
1015                     position_key->mTime = rotation_key->mTime = static_cast<double>(frame);
1016                     /* The Half-Life engine uses X as forward, Y as left, Z as up. Therefore,
1017                        pitch,yaw,roll is represented as (YZX). */
1018                     rotation_key->mValue = aiQuaternion(angle1.y, angle1.z, angle1.x);
1019                     rotation_key->mValue.Normalize();
1020                 }
1021             }
1022         }
1023     }
1024 }
1025 
1026 // ------------------------------------------------------------------------------------------------
read_sequence_groups_info()1027 void HL1MDLLoader::read_sequence_groups_info() {
1028 
1029     aiNode *sequence_groups_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_GROUPS);
1030     rootnode_children_.push_back(sequence_groups_node);
1031 
1032     sequence_groups_node->mNumChildren = static_cast<unsigned int>(header_->numseqgroups);
1033     sequence_groups_node->mChildren = new aiNode *[sequence_groups_node->mNumChildren];
1034 
1035     const SequenceGroup_HL1 *pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex);
1036 
1037     unique_sequence_groups_names_.resize(header_->numseqgroups);
1038     for (int i = 0; i < header_->numseqgroups; ++i)
1039         unique_sequence_groups_names_[i] = pseqgroup[i].label;
1040 
1041     // Ensure sequence groups have unique names.
1042     unique_name_generator_.set_template_name("SequenceGroup");
1043     unique_name_generator_.make_unique(unique_sequence_groups_names_);
1044 
1045     for (int i = 0; i < header_->numseqgroups; ++i, ++pseqgroup) {
1046         aiNode *sequence_group_node = sequence_groups_node->mChildren[i] = new aiNode(unique_sequence_groups_names_[i]);
1047         sequence_group_node->mParent = sequence_groups_node;
1048 
1049         aiMetadata *md = sequence_group_node->mMetaData = aiMetadata::Alloc(1);
1050         if (i == 0) {
1051             /* StudioMDL does not write the file name for the default sequence group,
1052                so we will write it. */
1053             md->Set(0, "File", aiString(file_path_));
1054         } else {
1055             md->Set(0, "File", aiString(pseqgroup->name));
1056         }
1057     }
1058 }
1059 
1060 // ------------------------------------------------------------------------------------------------
read_sequence_infos()1061 void HL1MDLLoader::read_sequence_infos() {
1062     if (!header_->numseq)
1063         return;
1064 
1065     const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex);
1066 
1067     aiNode *sequence_infos_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS);
1068     rootnode_children_.push_back(sequence_infos_node);
1069 
1070     sequence_infos_node->mNumChildren = static_cast<unsigned int>(header_->numseq);
1071     sequence_infos_node->mChildren = new aiNode *[sequence_infos_node->mNumChildren];
1072 
1073     std::vector<aiNode *> sequence_info_node_children;
1074 
1075     int animation_index = 0;
1076     for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) {
1077         // Clear the list of children for the upcoming sequence info node.
1078         sequence_info_node_children.clear();
1079 
1080         aiNode *sequence_info_node = sequence_infos_node->mChildren[i] = new aiNode(unique_sequence_names_[i]);
1081         sequence_info_node->mParent = sequence_infos_node;
1082 
1083         // Setup sequence info node Metadata.
1084         aiMetadata *md = sequence_info_node->mMetaData = aiMetadata::Alloc(16);
1085         md->Set(0, "AnimationIndex", animation_index);
1086         animation_index += pseqdesc->numblends;
1087 
1088         // Reference the sequence group by name. This allows us to search a particular
1089         // sequence group by name using aiNode(s).
1090         md->Set(1, "SequenceGroup", aiString(unique_sequence_groups_names_[pseqdesc->seqgroup]));
1091         md->Set(2, "FramesPerSecond", pseqdesc->fps);
1092         md->Set(3, "NumFrames", pseqdesc->numframes);
1093         md->Set(4, "NumBlends", pseqdesc->numblends);
1094         md->Set(5, "Activity", pseqdesc->activity);
1095         md->Set(6, "ActivityWeight", pseqdesc->actweight);
1096         md->Set(7, "MotionFlags", pseqdesc->motiontype);
1097         md->Set(8, "MotionBone", temp_bones_[pseqdesc->motionbone].node->mName);
1098         md->Set(9, "LinearMovement", aiVector3D(pseqdesc->linearmovement[0], pseqdesc->linearmovement[1], pseqdesc->linearmovement[2]));
1099         md->Set(10, "BBMin", aiVector3D(pseqdesc->bbmin[0], pseqdesc->bbmin[1], pseqdesc->bbmin[2]));
1100         md->Set(11, "BBMax", aiVector3D(pseqdesc->bbmax[0], pseqdesc->bbmax[1], pseqdesc->bbmax[2]));
1101         md->Set(12, "EntryNode", pseqdesc->entrynode);
1102         md->Set(13, "ExitNode", pseqdesc->exitnode);
1103         md->Set(14, "NodeFlags", pseqdesc->nodeflags);
1104         md->Set(15, "Flags", pseqdesc->flags);
1105 
1106         if (import_settings_.read_blend_controllers) {
1107             int num_blend_controllers;
1108             if (get_num_blend_controllers(pseqdesc->numblends, num_blend_controllers) && num_blend_controllers) {
1109                 // Read blend controllers info.
1110                 aiNode *blend_controllers_node = new aiNode(AI_MDL_HL1_NODE_BLEND_CONTROLLERS);
1111                 sequence_info_node_children.push_back(blend_controllers_node);
1112                 blend_controllers_node->mParent = sequence_info_node;
1113                 blend_controllers_node->mNumChildren = static_cast<unsigned int>(num_blend_controllers);
1114                 blend_controllers_node->mChildren = new aiNode *[blend_controllers_node->mNumChildren];
1115 
1116                 for (unsigned int j = 0; j < blend_controllers_node->mNumChildren; ++j) {
1117                     aiNode *blend_controller_node = blend_controllers_node->mChildren[j] = new aiNode();
1118                     blend_controller_node->mParent = blend_controllers_node;
1119 
1120                     aiMetadata *md = blend_controller_node->mMetaData = aiMetadata::Alloc(3);
1121                     md->Set(0, "Start", pseqdesc->blendstart[j]);
1122                     md->Set(1, "End", pseqdesc->blendend[j]);
1123                     md->Set(2, "MotionFlags", pseqdesc->blendtype[j]);
1124                 }
1125             }
1126         }
1127 
1128         if (import_settings_.read_animation_events && pseqdesc->numevents) {
1129             // Read animation events.
1130 
1131             if (pseqdesc->numevents > AI_MDL_HL1_MAX_EVENTS) {
1132                 log_warning_limit_exceeded<AI_MDL_HL1_MAX_EVENTS>(
1133                         "Sequence " + std::string(pseqdesc->label),
1134                         pseqdesc->numevents, "animation events");
1135             }
1136 
1137             const AnimEvent_HL1 *pevent = (const AnimEvent_HL1 *)((uint8_t *)header_ + pseqdesc->eventindex);
1138 
1139             aiNode *pEventsNode = new aiNode(AI_MDL_HL1_NODE_ANIMATION_EVENTS);
1140             sequence_info_node_children.push_back(pEventsNode);
1141             pEventsNode->mParent = sequence_info_node;
1142             pEventsNode->mNumChildren = static_cast<unsigned int>(pseqdesc->numevents);
1143             pEventsNode->mChildren = new aiNode *[pEventsNode->mNumChildren];
1144 
1145             for (unsigned int j = 0; j < pEventsNode->mNumChildren; ++j, ++pevent) {
1146                 aiNode *pEvent = pEventsNode->mChildren[j] = new aiNode();
1147                 pEvent->mParent = pEventsNode;
1148 
1149                 aiMetadata *md = pEvent->mMetaData = aiMetadata::Alloc(3);
1150                 md->Set(0, "Frame", pevent->frame);
1151                 md->Set(1, "ScriptEvent", pevent->event);
1152                 md->Set(2, "Options", aiString(pevent->options));
1153             }
1154         }
1155 
1156         if (sequence_info_node_children.size()) {
1157             sequence_info_node->addChildren(
1158                     static_cast<unsigned int>(sequence_info_node_children.size()),
1159                     sequence_info_node_children.data());
1160         }
1161     }
1162 }
1163 
1164 // ------------------------------------------------------------------------------------------------
read_sequence_transitions()1165 void HL1MDLLoader::read_sequence_transitions() {
1166     if (!header_->numtransitions)
1167         return;
1168 
1169     // Read sequence transition graph.
1170     aiNode *transition_graph_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH);
1171     rootnode_children_.push_back(transition_graph_node);
1172 
1173     uint8_t *ptransitions = ((uint8_t *)header_ + header_->transitionindex);
1174     aiMetadata *md = transition_graph_node->mMetaData = aiMetadata::Alloc(header_->numtransitions * header_->numtransitions);
1175     for (unsigned int i = 0; i < md->mNumProperties; ++i)
1176         md->Set(i, std::to_string(i), static_cast<int>(ptransitions[i]));
1177 }
1178 
read_attachments()1179 void HL1MDLLoader::read_attachments() {
1180     if (!header_->numattachments)
1181         return;
1182 
1183     const Attachment_HL1 *pattach = (const Attachment_HL1 *)((uint8_t *)header_ + header_->attachmentindex);
1184 
1185     aiNode *attachments_node = new aiNode(AI_MDL_HL1_NODE_ATTACHMENTS);
1186     rootnode_children_.push_back(attachments_node);
1187     attachments_node->mNumChildren = static_cast<unsigned int>(header_->numattachments);
1188     attachments_node->mChildren = new aiNode *[attachments_node->mNumChildren];
1189 
1190     for (int i = 0; i < header_->numattachments; ++i, ++pattach) {
1191         aiNode *attachment_node = attachments_node->mChildren[i] = new aiNode();
1192         attachment_node->mParent = attachments_node;
1193         attachment_node->mMetaData = aiMetadata::Alloc(2);
1194         attachment_node->mMetaData->Set(0, "Position", aiVector3D(pattach->org[0], pattach->org[1], pattach->org[2]));
1195         // Reference the bone by name. This allows us to search a particular
1196         // bone by name using aiNode(s).
1197         attachment_node->mMetaData->Set(1, "Bone", temp_bones_[pattach->bone].node->mName);
1198     }
1199 }
1200 
1201 // ------------------------------------------------------------------------------------------------
read_hitboxes()1202 void HL1MDLLoader::read_hitboxes() {
1203     if (!header_->numhitboxes)
1204         return;
1205 
1206     const Hitbox_HL1 *phitbox = (const Hitbox_HL1 *)((uint8_t *)header_ + header_->hitboxindex);
1207 
1208     aiNode *hitboxes_node = new aiNode(AI_MDL_HL1_NODE_HITBOXES);
1209     rootnode_children_.push_back(hitboxes_node);
1210     hitboxes_node->mNumChildren = static_cast<unsigned int>(header_->numhitboxes);
1211     hitboxes_node->mChildren = new aiNode *[hitboxes_node->mNumChildren];
1212 
1213     for (int i = 0; i < header_->numhitboxes; ++i, ++phitbox) {
1214         aiNode *hitbox_node = hitboxes_node->mChildren[i] = new aiNode();
1215         hitbox_node->mParent = hitboxes_node;
1216 
1217         aiMetadata *md = hitbox_node->mMetaData = aiMetadata::Alloc(4);
1218         // Reference the bone by name. This allows us to search a particular
1219         // bone by name using aiNode(s).
1220         md->Set(0, "Bone", temp_bones_[phitbox->bone].node->mName);
1221         md->Set(1, "HitGroup", phitbox->group);
1222         md->Set(2, "BBMin", aiVector3D(phitbox->bbmin[0], phitbox->bbmin[1], phitbox->bbmin[2]));
1223         md->Set(3, "BBMax", aiVector3D(phitbox->bbmax[0], phitbox->bbmax[1], phitbox->bbmax[2]));
1224     }
1225 }
1226 
1227 // ------------------------------------------------------------------------------------------------
read_bone_controllers()1228 void HL1MDLLoader::read_bone_controllers() {
1229     if (!header_->numbonecontrollers)
1230         return;
1231 
1232     const BoneController_HL1 *pbonecontroller = (const BoneController_HL1 *)((uint8_t *)header_ + header_->bonecontrollerindex);
1233 
1234     aiNode *bones_controller_node = new aiNode(AI_MDL_HL1_NODE_BONE_CONTROLLERS);
1235     rootnode_children_.push_back(bones_controller_node);
1236     bones_controller_node->mNumChildren = static_cast<unsigned int>(header_->numbonecontrollers);
1237     bones_controller_node->mChildren = new aiNode *[bones_controller_node->mNumChildren];
1238 
1239     for (int i = 0; i < header_->numbonecontrollers; ++i, ++pbonecontroller) {
1240         aiNode *bone_controller_node = bones_controller_node->mChildren[i] = new aiNode();
1241         bone_controller_node->mParent = bones_controller_node;
1242 
1243         aiMetadata *md = bone_controller_node->mMetaData = aiMetadata::Alloc(5);
1244         // Reference the bone by name. This allows us to search a particular
1245         // bone by name using aiNode(s).
1246         md->Set(0, "Bone", temp_bones_[pbonecontroller->bone].node->mName);
1247         md->Set(1, "MotionFlags", pbonecontroller->type);
1248         md->Set(2, "Start", pbonecontroller->start);
1249         md->Set(3, "End", pbonecontroller->end);
1250         md->Set(4, "Channel", pbonecontroller->index);
1251     }
1252 }
1253 
1254 // ------------------------------------------------------------------------------------------------
read_global_info()1255 void HL1MDLLoader::read_global_info() {
1256     aiNode *global_info_node = new aiNode(AI_MDL_HL1_NODE_GLOBAL_INFO);
1257     rootnode_children_.push_back(global_info_node);
1258 
1259     aiMetadata *md = global_info_node->mMetaData = aiMetadata::Alloc(import_settings_.read_misc_global_info ? 16 : 11);
1260     md->Set(0, "Version", AI_MDL_HL1_VERSION);
1261     md->Set(1, "NumBodyparts", header_->numbodyparts);
1262     md->Set(2, "NumModels", total_models_);
1263     md->Set(3, "NumBones", header_->numbones);
1264     md->Set(4, "NumAttachments", import_settings_.read_attachments ? header_->numattachments : 0);
1265     md->Set(5, "NumSkinFamilies", texture_header_->numskinfamilies);
1266     md->Set(6, "NumHitboxes", import_settings_.read_hitboxes ? header_->numhitboxes : 0);
1267     md->Set(7, "NumBoneControllers", import_settings_.read_bone_controllers ? header_->numbonecontrollers : 0);
1268     md->Set(8, "NumSequences", import_settings_.read_animations ? header_->numseq : 0);
1269     md->Set(9, "NumBlendControllers", import_settings_.read_blend_controllers ? num_blend_controllers_ : 0);
1270     md->Set(10, "NumTransitionNodes", import_settings_.read_sequence_transitions ? header_->numtransitions : 0);
1271 
1272     if (import_settings_.read_misc_global_info) {
1273         md->Set(11, "EyePosition", aiVector3D(header_->eyeposition[0], header_->eyeposition[1], header_->eyeposition[2]));
1274         md->Set(12, "HullMin", aiVector3D(header_->min[0], header_->min[1], header_->min[2]));
1275         md->Set(13, "HullMax", aiVector3D(header_->max[0], header_->max[1], header_->max[2]));
1276         md->Set(14, "CollisionMin", aiVector3D(header_->bbmin[0], header_->bbmin[1], header_->bbmin[2]));
1277         md->Set(15, "CollisionMax", aiVector3D(header_->bbmax[0], header_->bbmax[1], header_->bbmax[2]));
1278     }
1279 }
1280 
1281 // ------------------------------------------------------------------------------------------------
1282 /** @brief This method reads a compressed anim value.
1283 *
1284 *   @note The structure of this method is taken from HL2 source code.
1285 *   Although this is from HL2, it's implementation is almost identical
1286 *   to code found in HL1 SDK. See HL1 and HL2 SDKs for more info.
1287 *
1288 *   source:
1289 *       HL1 source code.
1290 *           file: studio_render.cpp
1291 *           function(s): CalcBoneQuaternion and CalcBonePosition
1292 *
1293 *       HL2 source code.
1294 *           file: bone_setup.cpp
1295 *           function(s): ExtractAnimValue
1296 */
extract_anim_value(const AnimValue_HL1 * panimvalue,int frame,float bone_scale,float & value)1297 void HL1MDLLoader::extract_anim_value(
1298         const AnimValue_HL1 *panimvalue,
1299         int frame, float bone_scale, float &value) {
1300     int k = frame;
1301 
1302     // find span of values that includes the frame we want
1303     while (panimvalue->num.total <= k) {
1304         k -= panimvalue->num.total;
1305         panimvalue += panimvalue->num.valid + 1;
1306     }
1307 
1308     // Bah, missing blend!
1309     if (panimvalue->num.valid > k)
1310         value = panimvalue[k + 1].value * bone_scale;
1311     else
1312         value = panimvalue[panimvalue->num.valid].value * bone_scale;
1313 }
1314 
1315 // ------------------------------------------------------------------------------------------------
1316 // Get the number of blend controllers.
get_num_blend_controllers(const int num_blend_animations,int & num_blend_controllers)1317 bool HL1MDLLoader::get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers) {
1318 
1319     switch (num_blend_animations) {
1320         case SequenceBlendMode_HL1::NoBlend:
1321             num_blend_controllers = 0;
1322             return true;
1323         case SequenceBlendMode_HL1::TwoWayBlending:
1324             num_blend_controllers = 1;
1325             return true;
1326         case SequenceBlendMode_HL1::FourWayBlending:
1327             num_blend_controllers = 2;
1328             return true;
1329         default:
1330             num_blend_controllers = 0;
1331             ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER "Unsupported number of blend animations (" + std::to_string(num_blend_animations) + ")");
1332             return false;
1333     }
1334 }
1335 
1336 } // namespace HalfLife
1337 } // namespace MDL
1338 } // namespace Assimp
1339