1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42
43/** @file MDLLoader.h
44 * @brief Declaration of the loader for MDL files
45 */
46
47#ifndef AI_MDLLOADER_H_INCLUDED
48#define AI_MDLLOADER_H_INCLUDED
49
50#include "BaseImporter.h"
51#include "MDLFileData.h"
52#include "HalfLifeFileData.h"
53
54struct aiNode;
55struct aiTexture;
56
57namespace Assimp {
58
59
60using namespace MDL;
61
62// --------------------------------------------------------------------------------------
63// Include file/line information in debug builds
64#ifdef ASSIMP_BUILD_DEBUG
65# define VALIDATE_FILE_SIZE(msg) SizeCheck(msg,__FILE__,__LINE__)
66#else
67# define VALIDATE_FILE_SIZE(msg) SizeCheck(msg)
68#endif
69
70// --------------------------------------------------------------------------------------
71/** @brief Class to load MDL files.
72 *
73 * Several subformats exist:
74 * <ul>
75 * <li>Quake I</li>
76 * <li>3D Game Studio MDL3, MDL4</li>
77 * <li>3D Game Studio MDL5</li>
78 * <li>3D Game Studio MDL7</li>
79 * <li>Halflife 2</li>
80 * </ul>
81 * These formats are partially identical and it would be possible to load
82 * them all with a single 1000-line function-beast. However, it has been
83 * split into several code paths to make the code easier to read and maintain.
84*/
85class MDLImporter : public BaseImporter
86{
87public:
88 MDLImporter();
89 ~MDLImporter();
90
91
92public:
93
94 // -------------------------------------------------------------------
95 /** Returns whether the class can handle the format of the given file.
96 * See BaseImporter::CanRead() for details. */
97 bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
98 bool checkSig) const;
99
100
101 // -------------------------------------------------------------------
102 /** Called prior to ReadFile().
103 * The function is a request to the importer to update its configuration
104 * basing on the Importer's configuration property list.
105 */
106 void SetupProperties(const Importer* pImp);
107
108protected:
109
110
111 // -------------------------------------------------------------------
112 /** Return importer meta information.
113 * See #BaseImporter::GetInfo for the details
114 */
115 const aiImporterDesc* GetInfo () const;
116
117 // -------------------------------------------------------------------
118 /** Imports the given file into the given scene structure.
119 * See BaseImporter::InternReadFile() for details
120 */
121 void InternReadFile( const std::string& pFile, aiScene* pScene,
122 IOSystem* pIOHandler);
123
124protected:
125
126 // -------------------------------------------------------------------
127 /** Import a quake 1 MDL file (IDPO)
128 */
129 void InternReadFile_Quake1( );
130
131 // -------------------------------------------------------------------
132 /** Import a GameStudio A4/A5 file (MDL 3,4,5)
133 */
134 void InternReadFile_3DGS_MDL345( );
135
136 // -------------------------------------------------------------------
137 /** Import a GameStudio A7 file (MDL 7)
138 */
139 void InternReadFile_3DGS_MDL7( );
140
141 // -------------------------------------------------------------------
142 /** Import a CS:S/HL2 MDL file (not fully implemented)
143 */
144 void InternReadFile_HL2( );
145
146 // -------------------------------------------------------------------
147 /** Check whether a given position is inside the valid range
148 * Throw a DeadlyImportError if it is not
149 * \param szPos Cursor position
150 * \param szFile Name of the source file from which the function was called
151 * \param iLine Source code line from which the function was called
152 */
153 void SizeCheck(const void* szPos);
154 void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine);
155
156
157 // -------------------------------------------------------------------
158 /** Validate the header data structure of a game studio MDL7 file
159 * \param pcHeader Input header to be validated
160 */
161 void ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7* pcHeader);
162
163 // -------------------------------------------------------------------
164 /** Validate the header data structure of a Quake 1 model
165 * \param pcHeader Input header to be validated
166 */
167 void ValidateHeader_Quake1(const MDL::Header* pcHeader);
168
169
170 // -------------------------------------------------------------------
171 /** Try to load a palette from the current directory (colormap.lmp)
172 * If it is not found the default palette of Quake1 is returned
173 */
174 void SearchPalette(const unsigned char** pszColorMap);
175
176 // -------------------------------------------------------------------
177 /** Free a palette created with a previous call to SearchPalette()
178 */
179 void FreePalette(const unsigned char* pszColorMap);
180
181
182 // -------------------------------------------------------------------
183 /** Load a paletized texture from the file and convert it to 32bpp
184 */
185 void CreateTextureARGB8_3DGS_MDL3(const unsigned char* szData);
186
187 // -------------------------------------------------------------------
188 /** Used to load textures from MDL3/4
189 * \param szData Input data
190 * \param iType Color data type
191 * \param piSkip Receive: Size to skip, in bytes
192 */
193 void CreateTexture_3DGS_MDL4(const unsigned char* szData,
194 unsigned int iType,
195 unsigned int* piSkip);
196
197
198 // -------------------------------------------------------------------
199 /** Used to load textures from MDL5
200 * \param szData Input data
201 * \param iType Color data type
202 * \param piSkip Receive: Size to skip, in bytes
203 */
204 void CreateTexture_3DGS_MDL5(const unsigned char* szData,
205 unsigned int iType,
206 unsigned int* piSkip);
207
208
209 // -------------------------------------------------------------------
210 /** Checks whether a texture can be replaced with a single color
211 * This is useful for all file formats before MDL7 (all those
212 * that are not containing material colors separate from textures).
213 * MED seems to write dummy 8x8 monochrome images instead.
214 * \param pcTexture Input texture
215 * \return aiColor.r is set to qnan if the function fails and no
216 * color can be found.
217 */
218 aiColor4D ReplaceTextureWithColor(const aiTexture* pcTexture);
219
220
221 // -------------------------------------------------------------------
222 /** Converts the absolute texture coordinates in MDL5 files to
223 * relative in a range between 0 and 1
224 */
225 void CalculateUVCoordinates_MDL5();
226
227
228 // -------------------------------------------------------------------
229 /** Read an UV coordinate from the file. If the file format is not
230 * MDL5, the function calculates relative texture coordinates
231 * \param vOut Receives the output UV coord
232 * \param pcSrc UV coordinate buffer
233 * \param UV coordinate index
234 */
235 void ImportUVCoordinate_3DGS_MDL345( aiVector3D& vOut,
236 const MDL::TexCoord_MDL3* pcSrc,
237 unsigned int iIndex);
238
239 // -------------------------------------------------------------------
240 /** Setup the material properties for Quake and MDL<7 models.
241 * These formats don't support more than one material per mesh,
242 * therefore the method processes only ONE skin and removes
243 * all others.
244 */
245 void SetupMaterialProperties_3DGS_MDL5_Quake1( );
246
247
248 // -------------------------------------------------------------------
249 /** Parse a skin lump in a MDL7/HMP7 file with all of its features
250 * variant 1: Current cursor position is the beginning of the skin header
251 * \param szCurrent Current data pointer
252 * \param szCurrentOut Output data pointer
253 * \param pcMats Material list for this group. To be filled ...
254 */
255 void ParseSkinLump_3DGS_MDL7(
256 const unsigned char* szCurrent,
257 const unsigned char** szCurrentOut,
258 std::vector<aiMaterial*>& pcMats);
259
260 // -------------------------------------------------------------------
261 /** Parse a skin lump in a MDL7/HMP7 file with all of its features
262 * variant 2: Current cursor position is the beginning of the skin data
263 * \param szCurrent Current data pointer
264 * \param szCurrentOut Output data pointer
265 * \param pcMatOut Output material
266 * \param iType header.typ
267 * \param iWidth header.width
268 * \param iHeight header.height
269 */
270 void ParseSkinLump_3DGS_MDL7(
271 const unsigned char* szCurrent,
272 const unsigned char** szCurrentOut,
273 aiMaterial* pcMatOut,
274 unsigned int iType,
275 unsigned int iWidth,
276 unsigned int iHeight);
277
278 // -------------------------------------------------------------------
279 /** Skip a skin lump in a MDL7/HMP7 file
280 * \param szCurrent Current data pointer
281 * \param szCurrentOut Output data pointer. Points to the byte just
282 * behind the last byte of the skin.
283 * \param iType header.typ
284 * \param iWidth header.width
285 * \param iHeight header.height
286 */
287 void SkipSkinLump_3DGS_MDL7(const unsigned char* szCurrent,
288 const unsigned char** szCurrentOut,
289 unsigned int iType,
290 unsigned int iWidth,
291 unsigned int iHeight);
292
293 // -------------------------------------------------------------------
294 /** Parse texture color data for MDL5, MDL6 and MDL7 formats
295 * \param szData Current data pointer
296 * \param iType type of the texture data. No DDS or external
297 * \param piSkip Receive the number of bytes to skip
298 * \param pcNew Must point to fully initialized data. Width and
299 * height must be set. If pcNew->pcData is set to UINT_MAX,
300 * piSkip will receive the size of the texture, in bytes, but no
301 * color data will be read.
302 */
303 void ParseTextureColorData(const unsigned char* szData,
304 unsigned int iType,
305 unsigned int* piSkip,
306 aiTexture* pcNew);
307
308 // -------------------------------------------------------------------
309 /** Join two materials / skins. Setup UV source ... etc
310 * \param pcMat1 First input material
311 * \param pcMat2 Second input material
312 * \param pcMatOut Output material instance to be filled. Must be empty
313 */
314 void JoinSkins_3DGS_MDL7(aiMaterial* pcMat1,
315 aiMaterial* pcMat2,
316 aiMaterial* pcMatOut);
317
318 // -------------------------------------------------------------------
319 /** Add a bone transformation key to an animation
320 * \param iTrafo Index of the transformation (always==frame index?)
321 * No need to validate this index, it is always valid.
322 * \param pcBoneTransforms Bone transformation for this index
323 * \param apcOutBones Output bones array
324 */
325 void AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo,
326 const MDL::BoneTransform_MDL7* pcBoneTransforms,
327 MDL::IntBone_MDL7** apcBonesOut);
328
329 // -------------------------------------------------------------------
330 /** Load the bone list of a MDL7 file
331 * \return If the bones could be loaded successfully, a valid
332 * array containing pointers to a temporary bone
333 * representation. NULL if the bones could not be loaded.
334 */
335 MDL::IntBone_MDL7** LoadBones_3DGS_MDL7();
336
337 // -------------------------------------------------------------------
338 /** Load bone transformation keyframes from a file chunk
339 * \param groupInfo -> doc of data structure
340 * \param frame -> doc of data structure
341 * \param shared -> doc of data structure
342 */
343 void ParseBoneTrafoKeys_3DGS_MDL7(
344 const MDL::IntGroupInfo_MDL7& groupInfo,
345 IntFrameInfo_MDL7& frame,
346 MDL::IntSharedData_MDL7& shared);
347
348 // -------------------------------------------------------------------
349 /** Calculate absolute bone animation matrices for each bone
350 * \param apcOutBones Output bones array
351 */
352 void CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones);
353
354 // -------------------------------------------------------------------
355 /** Add all bones to the nodegraph (as children of the root node)
356 * \param apcBonesOut List of bones
357 * \param pcParent Parent node. New nodes will be added to this node
358 * \param iParentIndex Index of the parent bone
359 */
360 void AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7** apcBonesOut,
361 aiNode* pcParent,uint16_t iParentIndex);
362
363 // -------------------------------------------------------------------
364 /** Build output animations
365 * \param apcBonesOut List of bones
366 */
367 void BuildOutputAnims_3DGS_MDL7(const MDL::IntBone_MDL7** apcBonesOut);
368
369 // -------------------------------------------------------------------
370 /** Handles materials that are just referencing another material
371 * There is no test file for this feature, but Conitec's doc
372 * say it is used.
373 */
374 void HandleMaterialReferences_3DGS_MDL7();
375
376 // -------------------------------------------------------------------
377 /** Copies only the material that are referenced by at least one
378 * mesh to the final output material list. All other materials
379 * will be discarded.
380 * \param shared -> doc of data structure
381 */
382 void CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared);
383
384 // -------------------------------------------------------------------
385 /** Process the frame section at the end of a group
386 * \param groupInfo -> doc of data structure
387 * \param shared -> doc of data structure
388 * \param szCurrent Pointer to the start of the frame section
389 * \param szCurrentOut Receives a pointer to the first byte of the
390 * next data section.
391 * \return false to read no further groups (a small workaround for
392 * some tiny and unsolved problems ... )
393 */
394 bool ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo,
395 MDL::IntGroupData_MDL7& groupData,
396 MDL::IntSharedData_MDL7& shared,
397 const unsigned char* szCurrent,
398 const unsigned char** szCurrentOut);
399
400 // -------------------------------------------------------------------
401 /** Sort all faces by their materials. If the mesh is using
402 * multiple materials per face (that are blended together) the function
403 * might create new materials.
404 * \param groupInfo -> doc of data structure
405 * \param groupData -> doc of data structure
406 * \param splitGroupData -> doc of data structure
407 */
408 void SortByMaterials_3DGS_MDL7(
409 const MDL::IntGroupInfo_MDL7& groupInfo,
410 MDL::IntGroupData_MDL7& groupData,
411 MDL::IntSplitGroupData_MDL7& splitGroupData);
412
413 // -------------------------------------------------------------------
414 /** Read all faces and vertices from a MDL7 group. The function fills
415 * preallocated memory buffers.
416 * \param groupInfo -> doc of data structure
417 * \param groupData -> doc of data structure
418 */
419 void ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo,
420 MDL::IntGroupData_MDL7& groupData);
421
422 // -------------------------------------------------------------------
423 /** Generate the final output meshes for a7 models
424 * \param groupData -> doc of data structure
425 * \param splitGroupData -> doc of data structure
426 */
427 void GenerateOutputMeshes_3DGS_MDL7(
428 MDL::IntGroupData_MDL7& groupData,
429 MDL::IntSplitGroupData_MDL7& splitGroupData);
430
431protected:
432
433 /** Configuration option: frame to be loaded */
434 unsigned int configFrameID;
435
436 /** Configuration option: palette to be used to decode palletized images*/
437 std::string configPalette;
438
439 /** Buffer to hold the loaded file */
440 unsigned char* mBuffer;
441
442 /** For GameStudio MDL files: The number in the magic word, either 3,4 or 5
443 * (MDL7 doesn't need this, the format has a separate loader) */
444 unsigned int iGSFileVersion;
445
446 /** Output I/O handler. used to load external lmp files */
447 IOSystem* pIOHandler;
448
449 /** Output scene to be filled */
450 aiScene* pScene;
451
452 /** Size of the input file in bytes */
453 unsigned int iFileSize;
454};
455
456} // end of namespace Assimp
457
458#endif // AI_3DSIMPORTER_H_INC
459