1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2015, 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 MDLLoader.cpp
43  *  @brief Implementation of the main parts of the MDL importer class
44  *  *TODO* Cleanup and further testing of some parts necessary
45  */
46 
47 // internal headers
48 
49 #ifndef ASSIMP_BUILD_NO_MDL_IMPORTER
50 
51 #include "MDLLoader.h"
52 #include "MDLDefaultColorMap.h"
53 #include "MD2FileData.h"
54 #include "../include/assimp/Importer.hpp"
55 #include <boost/scoped_ptr.hpp>
56 #include "../include/assimp/IOSystem.hpp"
57 #include "../include/assimp/scene.h"
58 #include "../include/assimp/DefaultLogger.hpp"
59 #include "Macros.h"
60 #include "qnan.h"
61 
62 
63 using namespace Assimp;
64 
65 static const aiImporterDesc desc = {
66     "Quake Mesh / 3D GameStudio Mesh Importer",
67     "",
68     "",
69     "",
70     aiImporterFlags_SupportBinaryFlavour,
71     0,
72     0,
73     7,
74     0,
75     "mdl"
76 };
77 
78 // ------------------------------------------------------------------------------------------------
79 // Ugly stuff ... nevermind
80 #define _AI_MDL7_ACCESS(_data, _index, _limit, _type)               \
81     (*((const _type*)(((const char*)_data) + _index * _limit)))
82 
83 #define _AI_MDL7_ACCESS_PTR(_data, _index, _limit, _type)           \
84     ((BE_NCONST _type*)(((const char*)_data) + _index * _limit))
85 
86 #define _AI_MDL7_ACCESS_VERT(_data, _index, _limit)                 \
87     _AI_MDL7_ACCESS(_data,_index,_limit,MDL::Vertex_MDL7)
88 
89 // ------------------------------------------------------------------------------------------------
90 // Constructor to be privately used by Importer
MDLImporter()91 MDLImporter::MDLImporter()
92     : configFrameID(),
93     mBuffer(),
94     iGSFileVersion(),
95     pIOHandler(),
96     pScene(),
97     iFileSize()
98 {}
99 
100 // ------------------------------------------------------------------------------------------------
101 // Destructor, private as well
~MDLImporter()102 MDLImporter::~MDLImporter()
103 {}
104 
105 // ------------------------------------------------------------------------------------------------
106 // Returns whether the class can handle the format of the given file.
CanRead(const std::string & pFile,IOSystem * pIOHandler,bool checkSig) const107 bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
108 {
109     const std::string extension = GetExtension(pFile);
110 
111     // if check for extension is not enough, check for the magic tokens
112     if (extension == "mdl"  || !extension.length() || checkSig) {
113         uint32_t tokens[8];
114         tokens[0] = AI_MDL_MAGIC_NUMBER_LE_HL2a;
115         tokens[1] = AI_MDL_MAGIC_NUMBER_LE_HL2b;
116         tokens[2] = AI_MDL_MAGIC_NUMBER_LE_GS7;
117         tokens[3] = AI_MDL_MAGIC_NUMBER_LE_GS5b;
118         tokens[4] = AI_MDL_MAGIC_NUMBER_LE_GS5a;
119         tokens[5] = AI_MDL_MAGIC_NUMBER_LE_GS4;
120         tokens[6] = AI_MDL_MAGIC_NUMBER_LE_GS3;
121         tokens[7] = AI_MDL_MAGIC_NUMBER_LE;
122         return CheckMagicToken(pIOHandler,pFile,tokens,8,0);
123     }
124     return false;
125 }
126 
127 // ------------------------------------------------------------------------------------------------
128 // Setup configuration properties
SetupProperties(const Importer * pImp)129 void MDLImporter::SetupProperties(const Importer* pImp)
130 {
131     configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDL_KEYFRAME,-1);
132 
133     // The
134     // AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
135     // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
136     if(static_cast<unsigned int>(-1) == configFrameID)  {
137         configFrameID =  pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
138     }
139 
140     // AI_CONFIG_IMPORT_MDL_COLORMAP - pallette file
141     configPalette =  pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP,"colormap.lmp");
142 }
143 
144 // ------------------------------------------------------------------------------------------------
145 // Get a list of all supported extensions
GetInfo() const146 const aiImporterDesc* MDLImporter::GetInfo () const
147 {
148     return &desc;
149 }
150 
151 // ------------------------------------------------------------------------------------------------
152 // Imports the given file into the given scene structure.
InternReadFile(const std::string & pFile,aiScene * _pScene,IOSystem * _pIOHandler)153 void MDLImporter::InternReadFile( const std::string& pFile,
154     aiScene* _pScene, IOSystem* _pIOHandler)
155 {
156     pScene     = _pScene;
157     pIOHandler = _pIOHandler;
158     boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
159 
160     // Check whether we can read from the file
161     if( file.get() == NULL) {
162         throw DeadlyImportError( "Failed to open MDL file " + pFile + ".");
163     }
164 
165     // This should work for all other types of MDL files, too ...
166     // the quake header is one of the smallest, afaik
167     iFileSize = (unsigned int)file->FileSize();
168     if( iFileSize < sizeof(MDL::Header)) {
169         throw DeadlyImportError( "MDL File is too small.");
170     }
171 
172     // Allocate storage and copy the contents of the file to a memory buffer
173     std::vector<unsigned char> buffer(iFileSize+1);
174     mBuffer = &buffer[0];
175     file->Read( (void*)mBuffer, 1, iFileSize);
176 
177     // Append a binary zero to the end of the buffer.
178     // this is just for safety that string parsing routines
179     // find the end of the buffer ...
180     mBuffer[iFileSize] = '\0';
181     const uint32_t iMagicWord = *((uint32_t*)mBuffer);
182 
183     // Determine the file subtype and call the appropriate member function
184 
185     // Original Quake1 format
186     if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord)   {
187         DefaultLogger::get()->debug("MDL subtype: Quake 1, magic word is IDPO");
188         iGSFileVersion = 0;
189         InternReadFile_Quake1();
190     }
191     // GameStudio A<old> MDL2 format - used by some test models that come with 3DGS
192     else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord)  {
193         DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A2, magic word is MDL2");
194         iGSFileVersion = 2;
195         InternReadFile_Quake1();
196     }
197     // GameStudio A4 MDL3 format
198     else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord)  {
199         DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL3");
200         iGSFileVersion = 3;
201         InternReadFile_3DGS_MDL345();
202     }
203     // GameStudio A5+ MDL4 format
204     else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord)    {
205         DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL4");
206         iGSFileVersion = 4;
207         InternReadFile_3DGS_MDL345();
208     }
209     // GameStudio A5+ MDL5 format
210     else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord)    {
211         DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A5, magic word is MDL5");
212         iGSFileVersion = 5;
213         InternReadFile_3DGS_MDL345();
214     }
215     // GameStudio A7 MDL7 format
216     else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord)  {
217         DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A7, magic word is MDL7");
218         iGSFileVersion = 7;
219         InternReadFile_3DGS_MDL7();
220     }
221     // IDST/IDSQ Format (CS:S/HL^2, etc ...)
222     else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
223         AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord)
224     {
225         DefaultLogger::get()->debug("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ");
226         iGSFileVersion = 0;
227         InternReadFile_HL2();
228     }
229     else    {
230         // print the magic word to the log file
231         throw DeadlyImportError( "Unknown MDL subformat " + pFile +
232             ". Magic word (" + std::string((char*)&iMagicWord,4) + ") is not known");
233     }
234 
235     // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
236     pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
237         0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
238 
239     // delete the file buffer and cleanup
240     AI_DEBUG_INVALIDATE_PTR(mBuffer);
241     AI_DEBUG_INVALIDATE_PTR(pIOHandler);
242     AI_DEBUG_INVALIDATE_PTR(pScene);
243 }
244 
245 // ------------------------------------------------------------------------------------------------
246 // Check whether we're still inside the valid file range
SizeCheck(const void * szPos)247 void MDLImporter::SizeCheck(const void* szPos)
248 {
249     if (!szPos || (const unsigned char*)szPos > this->mBuffer + this->iFileSize)
250     {
251         throw DeadlyImportError("Invalid MDL file. The file is too small "
252             "or contains invalid data.");
253     }
254 }
255 
256 // ------------------------------------------------------------------------------------------------
257 // Just for debgging purposes
SizeCheck(const void * szPos,const char * szFile,unsigned int iLine)258 void MDLImporter::SizeCheck(const void* szPos, const char* szFile, unsigned int iLine)
259 {
260     ai_assert(NULL != szFile);
261     if (!szPos || (const unsigned char*)szPos > mBuffer + iFileSize)
262     {
263         // remove a directory if there is one
264         const char* szFilePtr = ::strrchr(szFile,'\\');
265         if (!szFilePtr) {
266             if(!(szFilePtr = ::strrchr(szFile,'/')))
267                 szFilePtr = szFile;
268         }
269         if (szFilePtr)++szFilePtr;
270 
271         char szBuffer[1024];
272         ::sprintf(szBuffer,"Invalid MDL file. The file is too small "
273             "or contains invalid data (File: %s Line: %u)",szFilePtr,iLine);
274 
275         throw DeadlyImportError(szBuffer);
276     }
277 }
278 
279 // ------------------------------------------------------------------------------------------------
280 // Validate a quake file header
ValidateHeader_Quake1(const MDL::Header * pcHeader)281 void MDLImporter::ValidateHeader_Quake1(const MDL::Header* pcHeader)
282 {
283     // some values may not be NULL
284     if (!pcHeader->num_frames)
285         throw DeadlyImportError( "[Quake 1 MDL] There are no frames in the file");
286 
287     if (!pcHeader->num_verts)
288         throw DeadlyImportError( "[Quake 1 MDL] There are no vertices in the file");
289 
290     if (!pcHeader->num_tris)
291         throw DeadlyImportError( "[Quake 1 MDL] There are no triangles in the file");
292 
293     // check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only
294     if (!this->iGSFileVersion)
295     {
296         if (pcHeader->num_verts > AI_MDL_MAX_VERTS)
297             DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices");
298 
299         if (pcHeader->num_tris > AI_MDL_MAX_TRIANGLES)
300             DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_TRIANGLES triangles");
301 
302         if (pcHeader->num_frames > AI_MDL_MAX_FRAMES)
303             DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_FRAMES frames");
304 
305         // (this does not apply for 3DGS MDLs)
306         if (!this->iGSFileVersion && pcHeader->version != AI_MDL_VERSION)
307             DefaultLogger::get()->warn("Quake 1 MDL model has an unknown version: AI_MDL_VERSION (=6) is "
308                 "the expected file format version");
309         if(pcHeader->num_skins && (!pcHeader->skinwidth || !pcHeader->skinheight))
310             DefaultLogger::get()->warn("Skin width or height are 0");
311     }
312 }
313 
314 #ifdef AI_BUILD_BIG_ENDIAN
315 // ------------------------------------------------------------------------------------------------
FlipQuakeHeader(BE_NCONST MDL::Header * pcHeader)316 void FlipQuakeHeader(BE_NCONST MDL::Header* pcHeader)
317 {
318     AI_SWAP4( pcHeader->ident);
319     AI_SWAP4( pcHeader->version);
320     AI_SWAP4( pcHeader->boundingradius);
321     AI_SWAP4( pcHeader->flags);
322     AI_SWAP4( pcHeader->num_frames);
323     AI_SWAP4( pcHeader->num_skins);
324     AI_SWAP4( pcHeader->num_tris);
325     AI_SWAP4( pcHeader->num_verts);
326     for (unsigned int i = 0; i < 3;++i)
327     {
328         AI_SWAP4( pcHeader->scale[i]);
329         AI_SWAP4( pcHeader->translate[i]);
330     }
331     AI_SWAP4( pcHeader->size);
332     AI_SWAP4( pcHeader->skinheight);
333     AI_SWAP4( pcHeader->skinwidth);
334     AI_SWAP4( pcHeader->synctype);
335 }
336 #endif
337 
338 // ------------------------------------------------------------------------------------------------
339 // Read a Quake 1 file
InternReadFile_Quake1()340 void MDLImporter::InternReadFile_Quake1( )
341 {
342     ai_assert(NULL != pScene);
343     BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header*)this->mBuffer;
344 
345 #ifdef AI_BUILD_BIG_ENDIAN
346     FlipQuakeHeader(pcHeader);
347 #endif
348 
349     ValidateHeader_Quake1(pcHeader);
350 
351     // current cursor position in the file
352     const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1);
353 
354     // need to read all textures
355     for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i)
356     {
357         union{BE_NCONST MDL::Skin* pcSkin;BE_NCONST MDL::GroupSkin* pcGroupSkin;};
358         if (szCurrent + sizeof(MDL::Skin) > this->mBuffer + this->iFileSize) {
359             throw DeadlyImportError("[Quake 1 MDL] Unexpected EOF");
360         }
361         pcSkin = (BE_NCONST MDL::Skin*)szCurrent;
362 
363         AI_SWAP4( pcSkin->group );
364 
365         // Quake 1 groupskins
366         if (1 == pcSkin->group)
367         {
368             AI_SWAP4( pcGroupSkin->nb );
369 
370             // need to skip multiple images
371             const unsigned int iNumImages = (unsigned int)pcGroupSkin->nb;
372             szCurrent += sizeof(uint32_t) * 2;
373 
374             if (0 != iNumImages)
375             {
376                 if (!i) {
377                     // however, create only one output image (the first)
378                     this->CreateTextureARGB8_3DGS_MDL3(szCurrent + iNumImages * sizeof(float));
379                 }
380                 // go to the end of the skin section / the beginning of the next skin
381                 szCurrent += pcHeader->skinheight * pcHeader->skinwidth +
382                     sizeof(float) * iNumImages;
383             }
384         }
385         // 3DGS has a few files that are using other 3DGS like texture formats here
386         else
387         {
388             szCurrent += sizeof(uint32_t);
389             unsigned int iSkip = i ? UINT_MAX : 0;
390             CreateTexture_3DGS_MDL4(szCurrent,pcSkin->group,&iSkip);
391             szCurrent += iSkip;
392         }
393     }
394     // get a pointer to the texture coordinates
395     BE_NCONST MDL::TexCoord* pcTexCoords = (BE_NCONST MDL::TexCoord*)szCurrent;
396     szCurrent += sizeof(MDL::TexCoord) * pcHeader->num_verts;
397 
398     // get a pointer to the triangles
399     BE_NCONST MDL::Triangle* pcTriangles = (BE_NCONST MDL::Triangle*)szCurrent;
400     szCurrent += sizeof(MDL::Triangle) * pcHeader->num_tris;
401     VALIDATE_FILE_SIZE(szCurrent);
402 
403     // now get a pointer to the first frame in the file
404     BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent;
405     BE_NCONST MDL::SimpleFrame* pcFirstFrame;
406 
407     if (0 == pcFrames->type)
408     {
409         // get address of single frame
410         pcFirstFrame = &pcFrames->frame;
411     }
412     else
413     {
414         // get the first frame in the group
415         BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*)pcFrames;
416         pcFirstFrame = (BE_NCONST MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type);
417     }
418     BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
419     VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts));
420 
421 #ifdef AI_BUILD_BIG_ENDIAN
422     for (int i = 0; i<pcHeader->num_verts;++i)
423     {
424         AI_SWAP4( pcTexCoords[i].onseam );
425         AI_SWAP4( pcTexCoords[i].s );
426         AI_SWAP4( pcTexCoords[i].t );
427     }
428 
429     for (int i = 0; i<pcHeader->num_tris;++i)
430     {
431         AI_SWAP4( pcTriangles[i].facesfront);
432         AI_SWAP4( pcTriangles[i].vertex[0]);
433         AI_SWAP4( pcTriangles[i].vertex[1]);
434         AI_SWAP4( pcTriangles[i].vertex[2]);
435     }
436 #endif
437 
438     // setup materials
439     SetupMaterialProperties_3DGS_MDL5_Quake1();
440 
441     // allocate enough storage to hold all vertices and triangles
442     aiMesh* pcMesh = new aiMesh();
443 
444     pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
445     pcMesh->mNumVertices = pcHeader->num_tris * 3;
446     pcMesh->mNumFaces = pcHeader->num_tris;
447     pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
448     pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
449     pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
450     pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
451     pcMesh->mNumUVComponents[0] = 2;
452 
453     // there won't be more than one mesh inside the file
454     pScene->mRootNode = new aiNode();
455     pScene->mRootNode->mNumMeshes = 1;
456     pScene->mRootNode->mMeshes = new unsigned int[1];
457     pScene->mRootNode->mMeshes[0] = 0;
458     pScene->mNumMeshes = 1;
459     pScene->mMeshes = new aiMesh*[1];
460     pScene->mMeshes[0] = pcMesh;
461 
462     // now iterate through all triangles
463     unsigned int iCurrent = 0;
464     for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i)
465     {
466         pcMesh->mFaces[i].mIndices = new unsigned int[3];
467         pcMesh->mFaces[i].mNumIndices = 3;
468 
469         unsigned int iTemp = iCurrent;
470         for (unsigned int c = 0; c < 3;++c,++iCurrent)
471         {
472             pcMesh->mFaces[i].mIndices[c] = iCurrent;
473 
474             // read vertices
475             unsigned int iIndex = pcTriangles->vertex[c];
476             if (iIndex >= (unsigned int)pcHeader->num_verts)
477             {
478                 iIndex = pcHeader->num_verts-1;
479                 DefaultLogger::get()->warn("Index overflow in Q1-MDL vertex list.");
480             }
481 
482             aiVector3D& vec = pcMesh->mVertices[iCurrent];
483             vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
484             vec.x += pcHeader->translate[0];
485 
486             vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
487             vec.y += pcHeader->translate[1];
488             //vec.y *= -1.0f;
489 
490             vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
491             vec.z += pcHeader->translate[2];
492 
493             // read the normal vector from the precalculated normal table
494             MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
495             //pcMesh->mNormals[iCurrent].y *= -1.0f;
496 
497             // read texture coordinates
498             float s = (float)pcTexCoords[iIndex].s;
499             float t = (float)pcTexCoords[iIndex].t;
500 
501             // translate texture coordinates
502             if (0 == pcTriangles->facesfront && 0 != pcTexCoords[iIndex].onseam)    {
503                 s += pcHeader->skinwidth * 0.5f;
504             }
505 
506             // Scale s and t to range from 0.0 to 1.0
507             pcMesh->mTextureCoords[0][iCurrent].x = (s + 0.5f) / pcHeader->skinwidth;
508             pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-(t + 0.5f) / pcHeader->skinheight;
509 
510         }
511         pcMesh->mFaces[i].mIndices[0] = iTemp+2;
512         pcMesh->mFaces[i].mIndices[1] = iTemp+1;
513         pcMesh->mFaces[i].mIndices[2] = iTemp+0;
514         pcTriangles++;
515     }
516     return;
517 }
518 
519 // ------------------------------------------------------------------------------------------------
520 // Setup material properties for Quake and older GameStudio files
SetupMaterialProperties_3DGS_MDL5_Quake1()521 void MDLImporter::SetupMaterialProperties_3DGS_MDL5_Quake1( )
522 {
523     const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer;
524 
525     // allocate ONE material
526     pScene->mMaterials    = new aiMaterial*[1];
527     pScene->mMaterials[0] = new aiMaterial();
528     pScene->mNumMaterials = 1;
529 
530     // setup the material's properties
531     const int iMode = (int)aiShadingMode_Gouraud;
532     aiMaterial* const pcHelper = (aiMaterial*)pScene->mMaterials[0];
533     pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
534 
535     aiColor4D clr;
536     if (0 != pcHeader->num_skins && pScene->mNumTextures)   {
537         // can we replace the texture with a single color?
538         clr = this->ReplaceTextureWithColor(pScene->mTextures[0]);
539         if (is_not_qnan(clr.r)) {
540             delete pScene->mTextures[0];
541             delete[] pScene->mTextures;
542 
543             pScene->mTextures = NULL;
544             pScene->mNumTextures = 0;
545         }
546         else    {
547             clr.b = clr.a = clr.g = clr.r = 1.0f;
548             aiString szString;
549             ::memcpy(szString.data,AI_MAKE_EMBEDDED_TEXNAME(0),3);
550             szString.length = 2;
551             pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
552         }
553     }
554 
555     pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
556     pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
557 
558     clr.r *= 0.05f;clr.g *= 0.05f;
559     clr.b *= 0.05f;clr.a  = 1.0f;
560     pcHelper->AddProperty<aiColor4D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
561 }
562 
563 // ------------------------------------------------------------------------------------------------
564 // Read a MDL 3,4,5 file
InternReadFile_3DGS_MDL345()565 void MDLImporter::InternReadFile_3DGS_MDL345( )
566 {
567     ai_assert(NULL != pScene);
568 
569     // the header of MDL 3/4/5 is nearly identical to the original Quake1 header
570     BE_NCONST MDL::Header *pcHeader = (BE_NCONST MDL::Header*)this->mBuffer;
571 #ifdef AI_BUILD_BIG_ENDIAN
572     FlipQuakeHeader(pcHeader);
573 #endif
574     ValidateHeader_Quake1(pcHeader);
575 
576     // current cursor position in the file
577     const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1);
578 
579     // need to read all textures
580     for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i) {
581         BE_NCONST MDL::Skin* pcSkin;
582         pcSkin = (BE_NCONST  MDL::Skin*)szCurrent;
583         AI_SWAP4( pcSkin->group);
584         // create one output image
585         unsigned int iSkip = i ? UINT_MAX : 0;
586         if (5 <= iGSFileVersion)
587         {
588             // MDL5 format could contain MIPmaps
589             CreateTexture_3DGS_MDL5((unsigned char*)pcSkin + sizeof(uint32_t),
590                 pcSkin->group,&iSkip);
591         }
592         else    {
593             CreateTexture_3DGS_MDL4((unsigned char*)pcSkin + sizeof(uint32_t),
594                 pcSkin->group,&iSkip);
595         }
596         // need to skip one image
597         szCurrent += iSkip + sizeof(uint32_t);
598 
599     }
600     // get a pointer to the texture coordinates
601     BE_NCONST MDL::TexCoord_MDL3* pcTexCoords = (BE_NCONST MDL::TexCoord_MDL3*)szCurrent;
602     szCurrent += sizeof(MDL::TexCoord_MDL3) * pcHeader->synctype;
603 
604     // NOTE: for MDLn formats "synctype" corresponds to the number of UV coords
605 
606     // get a pointer to the triangles
607     BE_NCONST MDL::Triangle_MDL3* pcTriangles = (BE_NCONST MDL::Triangle_MDL3*)szCurrent;
608     szCurrent += sizeof(MDL::Triangle_MDL3) * pcHeader->num_tris;
609 
610 #ifdef AI_BUILD_BIG_ENDIAN
611 
612     for (int i = 0; i<pcHeader->synctype;++i)   {
613         AI_SWAP2( pcTexCoords[i].u );
614         AI_SWAP2( pcTexCoords[i].v );
615     }
616 
617     for (int i = 0; i<pcHeader->num_tris;++i)   {
618         AI_SWAP2( pcTriangles[i].index_xyz[0]);
619         AI_SWAP2( pcTriangles[i].index_xyz[1]);
620         AI_SWAP2( pcTriangles[i].index_xyz[2]);
621         AI_SWAP2( pcTriangles[i].index_uv[0]);
622         AI_SWAP2( pcTriangles[i].index_uv[1]);
623         AI_SWAP2( pcTriangles[i].index_uv[2]);
624     }
625 
626 #endif
627 
628     VALIDATE_FILE_SIZE(szCurrent);
629 
630     // setup materials
631     SetupMaterialProperties_3DGS_MDL5_Quake1();
632 
633     // allocate enough storage to hold all vertices and triangles
634     aiMesh* pcMesh = new aiMesh();
635     pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
636 
637     pcMesh->mNumVertices = pcHeader->num_tris * 3;
638     pcMesh->mNumFaces = pcHeader->num_tris;
639     pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
640 
641     // there won't be more than one mesh inside the file
642     pScene->mRootNode = new aiNode();
643     pScene->mRootNode->mNumMeshes = 1;
644     pScene->mRootNode->mMeshes = new unsigned int[1];
645     pScene->mRootNode->mMeshes[0] = 0;
646     pScene->mNumMeshes = 1;
647     pScene->mMeshes = new aiMesh*[1];
648     pScene->mMeshes[0] = pcMesh;
649 
650     // allocate output storage
651     pcMesh->mNumVertices = (unsigned int)pcHeader->num_tris*3;
652     pcMesh->mVertices    = new aiVector3D[pcMesh->mNumVertices];
653     pcMesh->mNormals     = new aiVector3D[pcMesh->mNumVertices];
654 
655     if (pcHeader->synctype) {
656         pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
657         pcMesh->mNumUVComponents[0] = 2;
658     }
659 
660     // now get a pointer to the first frame in the file
661     BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent;
662     AI_SWAP4(pcFrames->type);
663 
664     // byte packed vertices
665     // FIXME: these two snippets below are almost identical ... join them?
666     /////////////////////////////////////////////////////////////////////////////////////
667     if (0 == pcFrames->type || 3 >= this->iGSFileVersion)   {
668 
669         const MDL::SimpleFrame* pcFirstFrame = (const MDL::SimpleFrame*)(szCurrent + sizeof(uint32_t));
670         const MDL::Vertex* pcVertices = (const MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
671 
672         VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts);
673 
674         // now iterate through all triangles
675         unsigned int iCurrent = 0;
676         for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) {
677             pcMesh->mFaces[i].mIndices = new unsigned int[3];
678             pcMesh->mFaces[i].mNumIndices = 3;
679 
680             unsigned int iTemp = iCurrent;
681             for (unsigned int c = 0; c < 3;++c,++iCurrent)  {
682                 // read vertices
683                 unsigned int iIndex = pcTriangles->index_xyz[c];
684                 if (iIndex >= (unsigned int)pcHeader->num_verts)    {
685                     iIndex = pcHeader->num_verts-1;
686                     DefaultLogger::get()->warn("Index overflow in MDLn vertex list");
687                 }
688 
689                 aiVector3D& vec = pcMesh->mVertices[iCurrent];
690                 vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
691                 vec.x += pcHeader->translate[0];
692 
693                 vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
694                 vec.y += pcHeader->translate[1];
695                 // vec.y *= -1.0f;
696 
697                 vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
698                 vec.z += pcHeader->translate[2];
699 
700                 // read the normal vector from the precalculated normal table
701                 MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
702                 // pcMesh->mNormals[iCurrent].y *= -1.0f;
703 
704                 // read texture coordinates
705                 if (pcHeader->synctype) {
706                     ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent],
707                         pcTexCoords,pcTriangles->index_uv[c]);
708                 }
709             }
710             pcMesh->mFaces[i].mIndices[0] = iTemp+2;
711             pcMesh->mFaces[i].mIndices[1] = iTemp+1;
712             pcMesh->mFaces[i].mIndices[2] = iTemp+0;
713             pcTriangles++;
714         }
715 
716     }
717     // short packed vertices
718     /////////////////////////////////////////////////////////////////////////////////////
719     else    {
720         // now get a pointer to the first frame in the file
721         const MDL::SimpleFrame_MDLn_SP* pcFirstFrame = (const MDL::SimpleFrame_MDLn_SP*) (szCurrent + sizeof(uint32_t));
722 
723         // get a pointer to the vertices
724         const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) ((pcFirstFrame->name) +
725             sizeof(pcFirstFrame->name));
726 
727         VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts);
728 
729         // now iterate through all triangles
730         unsigned int iCurrent = 0;
731         for (unsigned int i = 0; i < (unsigned int) pcHeader->num_tris;++i) {
732             pcMesh->mFaces[i].mIndices = new unsigned int[3];
733             pcMesh->mFaces[i].mNumIndices = 3;
734 
735             unsigned int iTemp = iCurrent;
736             for (unsigned int c = 0; c < 3;++c,++iCurrent)  {
737                 // read vertices
738                 unsigned int iIndex = pcTriangles->index_xyz[c];
739                 if (iIndex >= (unsigned int)pcHeader->num_verts)    {
740                     iIndex = pcHeader->num_verts-1;
741                     DefaultLogger::get()->warn("Index overflow in MDLn vertex list");
742                 }
743 
744                 aiVector3D& vec = pcMesh->mVertices[iCurrent];
745                 vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
746                 vec.x += pcHeader->translate[0];
747 
748                 vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
749                 vec.y += pcHeader->translate[1];
750                 // vec.y *= -1.0f;
751 
752                 vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
753                 vec.z += pcHeader->translate[2];
754 
755                 // read the normal vector from the precalculated normal table
756                 MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
757                 // pcMesh->mNormals[iCurrent].y *= -1.0f;
758 
759                 // read texture coordinates
760                 if (pcHeader->synctype) {
761                     ImportUVCoordinate_3DGS_MDL345(pcMesh->mTextureCoords[0][iCurrent],
762                         pcTexCoords,pcTriangles->index_uv[c]);
763                 }
764             }
765             pcMesh->mFaces[i].mIndices[0] = iTemp+2;
766             pcMesh->mFaces[i].mIndices[1] = iTemp+1;
767             pcMesh->mFaces[i].mIndices[2] = iTemp+0;
768             pcTriangles++;
769         }
770     }
771 
772     // For MDL5 we will need to build valid texture coordinates
773     // basing upon the file loaded (only support one file as skin)
774     if (0x5 == iGSFileVersion)
775         CalculateUVCoordinates_MDL5();
776     return;
777 }
778 
779 // ------------------------------------------------------------------------------------------------
780 // Get a single UV coordinate for Quake and older GameStudio files
ImportUVCoordinate_3DGS_MDL345(aiVector3D & vOut,const MDL::TexCoord_MDL3 * pcSrc,unsigned int iIndex)781 void MDLImporter::ImportUVCoordinate_3DGS_MDL345(
782     aiVector3D& vOut,
783     const MDL::TexCoord_MDL3* pcSrc,
784     unsigned int iIndex)
785 {
786     ai_assert(NULL != pcSrc);
787     const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer;
788 
789     // validate UV indices
790     if (iIndex >= (unsigned int) pcHeader->synctype)    {
791         iIndex = pcHeader->synctype-1;
792         DefaultLogger::get()->warn("Index overflow in MDLn UV coord list");
793     }
794 
795     float s = (float)pcSrc[iIndex].u;
796     float t = (float)pcSrc[iIndex].v;
797 
798     // Scale s and t to range from 0.0 to 1.0
799     if (0x5 != iGSFileVersion)  {
800         s = (s + 0.5f)      / pcHeader->skinwidth;
801         t = 1.0f-(t + 0.5f) / pcHeader->skinheight;
802     }
803 
804     vOut.x = s;
805     vOut.y = t;
806     vOut.z = 0.0f;
807 }
808 
809 // ------------------------------------------------------------------------------------------------
810 // Compute UV coordinates for a MDL5 file
CalculateUVCoordinates_MDL5()811 void MDLImporter::CalculateUVCoordinates_MDL5()
812 {
813     const MDL::Header* const pcHeader = (const MDL::Header*)this->mBuffer;
814     if (pcHeader->num_skins && this->pScene->mNumTextures)  {
815         const aiTexture* pcTex = this->pScene->mTextures[0];
816 
817         // if the file is loaded in DDS format: get the size of the
818         // texture from the header of the DDS file
819         // skip three DWORDs and read first height, then the width
820         unsigned int iWidth, iHeight;
821         if (!pcTex->mHeight)    {
822             const uint32_t* piPtr = (uint32_t*)pcTex->pcData;
823 
824             piPtr += 3;
825             iHeight = (unsigned int)*piPtr++;
826             iWidth  = (unsigned int)*piPtr;
827             if (!iHeight || !iWidth)
828             {
829                 DefaultLogger::get()->warn("Either the width or the height of the "
830                     "embedded DDS texture is zero. Unable to compute final texture "
831                     "coordinates. The texture coordinates remain in their original "
832                     "0-x/0-y (x,y = texture size) range.");
833                 iWidth  = 1;
834                 iHeight = 1;
835             }
836         }
837         else    {
838             iWidth  = pcTex->mWidth;
839             iHeight = pcTex->mHeight;
840         }
841 
842         if (1 != iWidth || 1 != iHeight)    {
843             const float fWidth = (float)iWidth;
844             const float fHeight = (float)iHeight;
845             aiMesh* pcMesh = this->pScene->mMeshes[0];
846             for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
847             {
848                 pcMesh->mTextureCoords[0][i].x /= fWidth;
849                 pcMesh->mTextureCoords[0][i].y /= fHeight;
850                 pcMesh->mTextureCoords[0][i].y = 1.0f - pcMesh->mTextureCoords[0][i].y; // DX to OGL
851             }
852         }
853     }
854 }
855 
856 // ------------------------------------------------------------------------------------------------
857 // Validate the header of a MDL7 file
ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7 * pcHeader)858 void MDLImporter::ValidateHeader_3DGS_MDL7(const MDL::Header_MDL7* pcHeader)
859 {
860     ai_assert(NULL != pcHeader);
861 
862     // There are some fixed sizes ...
863     if (sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size)  {
864         throw DeadlyImportError(
865             "[3DGS MDL7] sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size");
866     }
867     if (sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size) {
868         throw DeadlyImportError(
869             "[3DGS MDL7] sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size");
870     }
871     if (sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size)  {
872         throw DeadlyImportError(
873             "sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size");
874     }
875 
876     // if there are no groups ... how should we load such a file?
877     if(!pcHeader->groups_num)   {
878         throw DeadlyImportError( "[3DGS MDL7] No frames found");
879     }
880 }
881 
882 // ------------------------------------------------------------------------------------------------
883 // resolve bone animation matrices
CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7 ** apcOutBones)884 void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7** apcOutBones)
885 {
886     const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
887     const MDL::Bone_MDL7* pcBones = (const MDL::Bone_MDL7*)(pcHeader+1);
888     ai_assert(NULL != apcOutBones);
889 
890     // first find the bone that has NO parent, calculate the
891     // animation matrix for it, then go on and search for the next parent
892     // index (0) and so on until we can't find a new node.
893     uint16_t iParent = 0xffff;
894     uint32_t iIterations = 0;
895     while (iIterations++ < pcHeader->bones_num) {
896         for (uint32_t iBone = 0; iBone < pcHeader->bones_num;++iBone)   {
897             BE_NCONST MDL::Bone_MDL7* pcBone = _AI_MDL7_ACCESS_PTR(pcBones,iBone,
898                 pcHeader->bone_stc_size,MDL::Bone_MDL7);
899 
900             AI_SWAP2(pcBone->parent_index);
901             AI_SWAP4(pcBone->x);
902             AI_SWAP4(pcBone->y);
903             AI_SWAP4(pcBone->z);
904 
905             if (iParent == pcBone->parent_index)    {
906                 // MDL7 readme
907                 ////////////////////////////////////////////////////////////////
908                 /*
909                 The animation matrix is then calculated the following way:
910 
911                 vector3 bPos = <absolute bone position>
912                 matrix44 laM;   // local animation matrix
913                 sphrvector key_rotate = <bone rotation>
914 
915                 matrix44 m1,m2;
916                 create_trans_matrix(m1, -bPos.x, -bPos.y, -bPos.z);
917                 create_trans_matrix(m2, -bPos.x, -bPos.y, -bPos.z);
918 
919                 create_rotation_matrix(laM,key_rotate);
920 
921                 laM = sm1 * laM;
922                 laM = laM * sm2;
923                 */
924                 /////////////////////////////////////////////////////////////////
925 
926                 MDL::IntBone_MDL7* const pcOutBone = apcOutBones[iBone];
927 
928                 // store the parent index of the bone
929                 pcOutBone->iParent = pcBone->parent_index;
930                 if (0xffff != iParent)  {
931                     const MDL::IntBone_MDL7* pcParentBone = apcOutBones[iParent];
932                     pcOutBone->mOffsetMatrix.a4 = -pcParentBone->vPosition.x;
933                     pcOutBone->mOffsetMatrix.b4 = -pcParentBone->vPosition.y;
934                     pcOutBone->mOffsetMatrix.c4 = -pcParentBone->vPosition.z;
935                 }
936                 pcOutBone->vPosition.x = pcBone->x;
937                 pcOutBone->vPosition.y = pcBone->y;
938                 pcOutBone->vPosition.z = pcBone->z;
939                 pcOutBone->mOffsetMatrix.a4 -= pcBone->x;
940                 pcOutBone->mOffsetMatrix.b4 -= pcBone->y;
941                 pcOutBone->mOffsetMatrix.c4 -= pcBone->z;
942 
943                 if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) {
944                     // no real name for our poor bone is specified :-(
945                     pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data,
946                         "UnnamedBone_%i",iBone);
947                 }
948                 else    {
949                     // Make sure we won't run over the buffer's end if there is no
950                     // terminal 0 character (however the documentation says there
951                     // should be one)
952                     uint32_t iMaxLen = pcHeader->bone_stc_size-16;
953                     for (uint32_t qq = 0; qq < iMaxLen;++qq)    {
954                         if (!pcBone->name[qq])  {
955                             iMaxLen = qq;
956                             break;
957                         }
958                     }
959 
960                     // store the name of the bone
961                     pcOutBone->mName.length = (size_t)iMaxLen;
962                     ::memcpy(pcOutBone->mName.data,pcBone->name,pcOutBone->mName.length);
963                     pcOutBone->mName.data[pcOutBone->mName.length] = '\0';
964                 }
965             }
966         }
967         ++iParent;
968     }
969 }
970 
971 // ------------------------------------------------------------------------------------------------
972 // read bones from a MDL7 file
LoadBones_3DGS_MDL7()973 MDL::IntBone_MDL7** MDLImporter::LoadBones_3DGS_MDL7()
974 {
975   const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
976     if (pcHeader->bones_num)    {
977         // validate the size of the bone data structure in the file
978         if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS  != pcHeader->bone_stc_size &&
979             AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_32_CHARS  != pcHeader->bone_stc_size &&
980             AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE != pcHeader->bone_stc_size)
981         {
982             DefaultLogger::get()->warn("Unknown size of bone data structure");
983             return NULL;
984         }
985 
986         MDL::IntBone_MDL7** apcBonesOut = new MDL::IntBone_MDL7*[pcHeader->bones_num];
987         for (uint32_t crank = 0; crank < pcHeader->bones_num;++crank)
988             apcBonesOut[crank] = new MDL::IntBone_MDL7();
989 
990         // and calculate absolute bone offset matrices ...
991         CalcAbsBoneMatrices_3DGS_MDL7(apcBonesOut);
992         return apcBonesOut;
993     }
994     return NULL;
995 }
996 
997 // ------------------------------------------------------------------------------------------------
998 // read faces from a MDL7 file
ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7 & groupInfo,MDL::IntGroupData_MDL7 & groupData)999 void MDLImporter::ReadFaces_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo,
1000     MDL::IntGroupData_MDL7& groupData)
1001 {
1002     const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
1003     MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris;
1004 
1005     // iterate through all triangles and build valid display lists
1006     unsigned int iOutIndex = 0;
1007     for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) {
1008         AI_SWAP2(pcGroupTris->v_index[0]);
1009         AI_SWAP2(pcGroupTris->v_index[1]);
1010         AI_SWAP2(pcGroupTris->v_index[2]);
1011 
1012         // iterate through all indices of the current triangle
1013         for (unsigned int c = 0; c < 3;++c,++iOutIndex) {
1014 
1015             // validate the vertex index
1016             unsigned int iIndex = pcGroupTris->v_index[c];
1017             if(iIndex > (unsigned int)groupInfo.pcGroup->numverts)  {
1018                 // (we might need to read this section a second time - to process frame vertices correctly)
1019                 pcGroupTris->v_index[c] = iIndex = groupInfo.pcGroup->numverts-1;
1020                 DefaultLogger::get()->warn("Index overflow in MDL7 vertex list");
1021             }
1022 
1023             // write the output face index
1024             groupData.pcFaces[iTriangle].mIndices[2-c] = iOutIndex;
1025 
1026             aiVector3D& vPosition = groupData.vPositions[ iOutIndex ];
1027             vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, pcHeader->mainvertex_stc_size) .x;
1028             vPosition.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y;
1029             vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z;
1030 
1031             // if we have bones, save the index
1032             if (!groupData.aiBones.empty()) {
1033                 groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,
1034                     iIndex,pcHeader->mainvertex_stc_size).vertindex;
1035             }
1036 
1037             // now read the normal vector
1038             if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) {
1039                 // read the full normal vector
1040                 aiVector3D& vNormal = groupData.vNormals[ iOutIndex ];
1041                 vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[0];
1042                 AI_SWAP4(vNormal.x);
1043                 vNormal.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1];
1044                 AI_SWAP4(vNormal.y);
1045                 vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2];
1046                 AI_SWAP4(vNormal.z);
1047             }
1048             else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size)    {
1049                 // read the normal vector from Quake2's smart table
1050                 aiVector3D& vNormal = groupData.vNormals[ iOutIndex ];
1051                 MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,
1052                     pcHeader->mainvertex_stc_size) .norm162index,vNormal);
1053             }
1054             // validate and process the first uv coordinate set
1055             if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV)    {
1056 
1057                 if (groupInfo.pcGroup->num_stpts)   {
1058                     AI_SWAP2(pcGroupTris->skinsets[0].st_index[0]);
1059                     AI_SWAP2(pcGroupTris->skinsets[0].st_index[1]);
1060                     AI_SWAP2(pcGroupTris->skinsets[0].st_index[2]);
1061 
1062                     iIndex = pcGroupTris->skinsets[0].st_index[c];
1063                     if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) {
1064                         iIndex = groupInfo.pcGroup->num_stpts-1;
1065                         DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#1)");
1066                     }
1067 
1068                     float u = groupInfo.pcGroupUVs[iIndex].u;
1069                     float v = 1.0f-groupInfo.pcGroupUVs[iIndex].v; // DX to OGL
1070 
1071                     groupData.vTextureCoords1[iOutIndex].x = u;
1072                     groupData.vTextureCoords1[iOutIndex].y = v;
1073                 }
1074                 // assign the material index, but only if it is existing
1075                 if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX){
1076                     AI_SWAP4(pcGroupTris->skinsets[0].material);
1077                     groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material;
1078                 }
1079             }
1080             // validate and process the second uv coordinate set
1081             if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV)    {
1082 
1083                 if (groupInfo.pcGroup->num_stpts)   {
1084                     AI_SWAP2(pcGroupTris->skinsets[1].st_index[0]);
1085                     AI_SWAP2(pcGroupTris->skinsets[1].st_index[1]);
1086                     AI_SWAP2(pcGroupTris->skinsets[1].st_index[2]);
1087                     AI_SWAP4(pcGroupTris->skinsets[1].material);
1088 
1089                     iIndex = pcGroupTris->skinsets[1].st_index[c];
1090                     if(iIndex > (unsigned int)groupInfo.pcGroup->num_stpts) {
1091                         iIndex = groupInfo.pcGroup->num_stpts-1;
1092                         DefaultLogger::get()->warn("Index overflow in MDL7 UV coordinate list (#2)");
1093                     }
1094 
1095                     float u = groupInfo.pcGroupUVs[ iIndex ].u;
1096                     float v = 1.0f-groupInfo.pcGroupUVs[ iIndex ].v;
1097 
1098                     groupData.vTextureCoords2[ iOutIndex ].x = u;
1099                     groupData.vTextureCoords2[ iOutIndex ].y = v; // DX to OGL
1100 
1101                     // check whether we do really need the second texture
1102                     // coordinate set ... wastes memory and loading time
1103                     if (0 != iIndex && (u != groupData.vTextureCoords1[ iOutIndex ].x ||
1104                         v != groupData.vTextureCoords1[ iOutIndex ].y ) )
1105                         groupData.bNeed2UV = true;
1106 
1107                     // if the material differs, we need a second skin, too
1108                     if (pcGroupTris->skinsets[ 1 ].material != pcGroupTris->skinsets[ 0 ].material)
1109                         groupData.bNeed2UV = true;
1110                 }
1111                 // assign the material index
1112                 groupData.pcFaces[ iTriangle ].iMatIndex[ 1 ] = pcGroupTris->skinsets[ 1 ].material;
1113             }
1114         }
1115         // get the next triangle in the list
1116         pcGroupTris = (MDL::Triangle_MDL7*)((const char*)pcGroupTris + pcHeader->triangle_stc_size);
1117     }
1118 }
1119 
1120 // ------------------------------------------------------------------------------------------------
1121 // handle frames in a MDL7 file
ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7 & groupInfo,MDL::IntGroupData_MDL7 & groupData,MDL::IntSharedData_MDL7 & shared,const unsigned char * szCurrent,const unsigned char ** szCurrentOut)1122 bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo,
1123     MDL::IntGroupData_MDL7&  groupData,
1124     MDL::IntSharedData_MDL7& shared,
1125     const unsigned char*     szCurrent,
1126     const unsigned char**    szCurrentOut)
1127 {
1128     ai_assert(NULL != szCurrent && NULL != szCurrentOut);
1129     const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)mBuffer;
1130 
1131     // if we have no bones we can simply skip all frames,
1132     // otherwise we'll need to process them.
1133     // FIX: If we need another frame than the first we must apply frame vertex replacements ...
1134     for(unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes;++iFrame)  {
1135         MDL::IntFrameInfo_MDL7 frame ((BE_NCONST MDL::Frame_MDL7*)szCurrent,iFrame);
1136 
1137         AI_SWAP4(frame.pcFrame->vertices_count);
1138         AI_SWAP4(frame.pcFrame->transmatrix_count);
1139 
1140         const unsigned int iAdd = pcHeader->frame_stc_size +
1141             frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size +
1142             frame.pcFrame->transmatrix_count * pcHeader->bonetrans_stc_size;
1143 
1144         if (((const char*)szCurrent - (const char*)pcHeader) + iAdd > (unsigned int)pcHeader->data_size)    {
1145             DefaultLogger::get()->warn("Index overflow in frame area. "
1146                 "Ignoring all frames and all further mesh groups, too.");
1147 
1148             // don't parse more groups if we can't even read one
1149             // FIXME: sometimes this seems to occur even for valid files ...
1150             *szCurrentOut = szCurrent;
1151             return false;
1152         }
1153         // our output frame?
1154         if (configFrameID == iFrame)    {
1155             BE_NCONST MDL::Vertex_MDL7* pcFrameVertices = (BE_NCONST MDL::Vertex_MDL7*)(szCurrent+pcHeader->frame_stc_size);
1156 
1157             for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count;++qq)  {
1158                 // I assume this are simple replacements for normal vertices, the bone index serving
1159                 // as the index of the vertex to be replaced.
1160                 uint16_t iIndex = _AI_MDL7_ACCESS(pcFrameVertices,qq,pcHeader->framevertex_stc_size,MDL::Vertex_MDL7).vertindex;
1161                 AI_SWAP2(iIndex);
1162                 if (iIndex >= groupInfo.pcGroup->numverts)  {
1163                     DefaultLogger::get()->warn("Invalid vertex index in frame vertex section");
1164                     continue;
1165                 }
1166 
1167                 aiVector3D vPosition,vNormal;
1168 
1169                 vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .x;
1170                 AI_SWAP4(vPosition.x);
1171                 vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y;
1172                 AI_SWAP4(vPosition.y);
1173                 vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z;
1174                 AI_SWAP4(vPosition.z);
1175 
1176                 // now read the normal vector
1177                 if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) {
1178                     // read the full normal vector
1179                     vNormal.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[0];
1180                     AI_SWAP4(vNormal.x);
1181                     vNormal.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[1];
1182                     AI_SWAP4(vNormal.y);
1183                     vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[2];
1184                     AI_SWAP4(vNormal.z);
1185                 }
1186                 else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size)    {
1187                     // read the normal vector from Quake2's smart table
1188                     MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,
1189                         pcHeader->framevertex_stc_size) .norm162index,vNormal);
1190                 }
1191 
1192                 // FIXME: O(n^2) at the moment ...
1193                 BE_NCONST MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris;
1194                 unsigned int iOutIndex = 0;
1195                 for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) {
1196                     // iterate through all indices of the current triangle
1197                     for (unsigned int c = 0; c < 3;++c,++iOutIndex) {
1198                         // replace the vertex with the new data
1199                         const unsigned int iCurIndex = pcGroupTris->v_index[c];
1200                         if (iCurIndex == iIndex)    {
1201                             groupData.vPositions[iOutIndex] = vPosition;
1202                             groupData.vNormals[iOutIndex] = vNormal;
1203                         }
1204                     }
1205                     // get the next triangle in the list
1206                     pcGroupTris = (BE_NCONST MDL::Triangle_MDL7*)((const char*)
1207                         pcGroupTris + pcHeader->triangle_stc_size);
1208                 }
1209             }
1210         }
1211         // parse bone trafo matrix keys (only if there are bones ...)
1212         if (shared.apcOutBones) {
1213             ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared);
1214         }
1215         szCurrent += iAdd;
1216     }
1217     *szCurrentOut = szCurrent;
1218     return true;
1219 }
1220 
1221 // ------------------------------------------------------------------------------------------------
1222 // Sort faces by material, handle multiple UVs correctly
SortByMaterials_3DGS_MDL7(const MDL::IntGroupInfo_MDL7 & groupInfo,MDL::IntGroupData_MDL7 & groupData,MDL::IntSplitGroupData_MDL7 & splitGroupData)1223 void MDLImporter::SortByMaterials_3DGS_MDL7(
1224     const MDL::IntGroupInfo_MDL7&   groupInfo,
1225     MDL::IntGroupData_MDL7&         groupData,
1226     MDL::IntSplitGroupData_MDL7& splitGroupData)
1227 {
1228     const unsigned int iNumMaterials = (unsigned int)splitGroupData.shared.pcMats.size();
1229     if (!groupData.bNeed2UV)    {
1230         // if we don't need a second set of texture coordinates there is no reason to keep it in memory ...
1231         groupData.vTextureCoords2.clear();
1232 
1233         // allocate the array
1234         splitGroupData.aiSplit = new std::vector<unsigned int>*[iNumMaterials];
1235 
1236         for (unsigned int m = 0; m < iNumMaterials;++m)
1237             splitGroupData.aiSplit[m] = new std::vector<unsigned int>();
1238 
1239         // iterate through all faces and sort by material
1240         for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace)  {
1241             // check range
1242             if (groupData.pcFaces[iFace].iMatIndex[0] >= iNumMaterials) {
1243                 // use the last material instead
1244                 splitGroupData.aiSplit[iNumMaterials-1]->push_back(iFace);
1245 
1246                 // sometimes MED writes -1, but normally only if there is only
1247                 // one skin assigned. No warning in this case
1248                 if(0xFFFFFFFF != groupData.pcFaces[iFace].iMatIndex[0])
1249                     DefaultLogger::get()->warn("Index overflow in MDL7 material list [#0]");
1250             }
1251             else splitGroupData.aiSplit[groupData.pcFaces[iFace].
1252                 iMatIndex[0]]->push_back(iFace);
1253         }
1254     }
1255     else
1256     {
1257         // we need to build combined materials for each combination of
1258         std::vector<MDL::IntMaterial_MDL7> avMats;
1259         avMats.reserve(iNumMaterials*2);
1260 
1261         // fixme: why on the heap?
1262         std::vector<std::vector<unsigned int>* > aiTempSplit(iNumMaterials*2);
1263         for (unsigned int m = 0; m < iNumMaterials;++m)
1264             aiTempSplit[m] = new std::vector<unsigned int>();
1265 
1266         // iterate through all faces and sort by material
1267         for (unsigned int iFace = 0; iFace < (unsigned int)groupInfo.pcGroup->numtris;++iFace)  {
1268             // check range
1269             unsigned int iMatIndex = groupData.pcFaces[iFace].iMatIndex[0];
1270             if (iMatIndex >= iNumMaterials) {
1271                 // sometimes MED writes -1, but normally only if there is only
1272                 // one skin assigned. No warning in this case
1273                 if(UINT_MAX != iMatIndex)
1274                     DefaultLogger::get()->warn("Index overflow in MDL7 material list [#1]");
1275                 iMatIndex = iNumMaterials-1;
1276             }
1277             unsigned int iMatIndex2 = groupData.pcFaces[iFace].iMatIndex[1];
1278 
1279             unsigned int iNum = iMatIndex;
1280             if (UINT_MAX != iMatIndex2 && iMatIndex != iMatIndex2)  {
1281                 if (iMatIndex2 >= iNumMaterials)    {
1282                     // sometimes MED writes -1, but normally only if there is only
1283                     // one skin assigned. No warning in this case
1284                     DefaultLogger::get()->warn("Index overflow in MDL7 material list [#2]");
1285                     iMatIndex2 = iNumMaterials-1;
1286                 }
1287 
1288                 // do a slow seach in the list ...
1289                 iNum = 0;
1290                 bool bFound = false;
1291                 for (std::vector<MDL::IntMaterial_MDL7>::iterator i =  avMats.begin();i != avMats.end();++i,++iNum){
1292                     if ((*i).iOldMatIndices[0] == iMatIndex && (*i).iOldMatIndices[1] == iMatIndex2)    {
1293                         // reuse this material
1294                         bFound = true;
1295                         break;
1296                     }
1297                 }
1298                 if (!bFound)    {
1299                     //  build a new material ...
1300                     MDL::IntMaterial_MDL7 sHelper;
1301                     sHelper.pcMat = new aiMaterial();
1302                     sHelper.iOldMatIndices[0] = iMatIndex;
1303                     sHelper.iOldMatIndices[1] = iMatIndex2;
1304                     JoinSkins_3DGS_MDL7(splitGroupData.shared.pcMats[iMatIndex],
1305                         splitGroupData.shared.pcMats[iMatIndex2],sHelper.pcMat);
1306 
1307                     // and add it to the list
1308                     avMats.push_back(sHelper);
1309                     iNum = (unsigned int)avMats.size()-1;
1310                 }
1311                 // adjust the size of the file array
1312                 if (iNum == aiTempSplit.size()) {
1313                     aiTempSplit.push_back(new std::vector<unsigned int>());
1314                 }
1315             }
1316             aiTempSplit[iNum]->push_back(iFace);
1317         }
1318 
1319         // now add the newly created materials to the old list
1320         if (0 == groupInfo.iIndex)  {
1321             splitGroupData.shared.pcMats.resize(avMats.size());
1322             for (unsigned int o = 0; o < avMats.size();++o)
1323                 splitGroupData.shared.pcMats[o] = avMats[o].pcMat;
1324         }
1325         else    {
1326             // This might result in redundant materials ...
1327             splitGroupData.shared.pcMats.resize(iNumMaterials + avMats.size());
1328             for (unsigned int o = iNumMaterials; o < avMats.size();++o)
1329                 splitGroupData.shared.pcMats[o] = avMats[o].pcMat;
1330         }
1331 
1332         // and build the final face-to-material array
1333         splitGroupData.aiSplit = new std::vector<unsigned int>*[aiTempSplit.size()];
1334         for (unsigned int m = 0; m < iNumMaterials;++m)
1335             splitGroupData.aiSplit[m] = aiTempSplit[m];
1336     }
1337 }
1338 
1339 // ------------------------------------------------------------------------------------------------
1340 // Read a MDL7 file
InternReadFile_3DGS_MDL7()1341 void MDLImporter::InternReadFile_3DGS_MDL7( )
1342 {
1343     ai_assert(NULL != pScene);
1344 
1345     MDL::IntSharedData_MDL7 sharedData;
1346 
1347     // current cursor position in the file
1348     BE_NCONST MDL::Header_MDL7 *pcHeader = (BE_NCONST MDL::Header_MDL7*)this->mBuffer;
1349     const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1);
1350 
1351     AI_SWAP4(pcHeader->version);
1352     AI_SWAP4(pcHeader->bones_num);
1353     AI_SWAP4(pcHeader->groups_num);
1354     AI_SWAP4(pcHeader->data_size);
1355     AI_SWAP4(pcHeader->entlump_size);
1356     AI_SWAP4(pcHeader->medlump_size);
1357     AI_SWAP2(pcHeader->bone_stc_size);
1358     AI_SWAP2(pcHeader->skin_stc_size);
1359     AI_SWAP2(pcHeader->colorvalue_stc_size);
1360     AI_SWAP2(pcHeader->material_stc_size);
1361     AI_SWAP2(pcHeader->skinpoint_stc_size);
1362     AI_SWAP2(pcHeader->triangle_stc_size);
1363     AI_SWAP2(pcHeader->mainvertex_stc_size);
1364     AI_SWAP2(pcHeader->framevertex_stc_size);
1365     AI_SWAP2(pcHeader->bonetrans_stc_size);
1366     AI_SWAP2(pcHeader->frame_stc_size);
1367 
1368     // validate the header of the file. There are some structure
1369     // sizes that are expected by the loader to be constant
1370     this->ValidateHeader_3DGS_MDL7(pcHeader);
1371 
1372     // load all bones (they are shared by all groups, so
1373     // we'll need to add them to all groups/meshes later)
1374     // apcBonesOut is a list of all bones or NULL if they could not been loaded
1375     szCurrent += pcHeader->bones_num * pcHeader->bone_stc_size;
1376     sharedData.apcOutBones = this->LoadBones_3DGS_MDL7();
1377 
1378     // vector to held all created meshes
1379     std::vector<aiMesh*>* avOutList;
1380 
1381     // 3 meshes per group - that should be OK for most models
1382     avOutList = new std::vector<aiMesh*>[pcHeader->groups_num];
1383     for (uint32_t i = 0; i < pcHeader->groups_num;++i)
1384         avOutList[i].reserve(3);
1385 
1386     // buffer to held the names of all groups in the file
1387     char* aszGroupNameBuffer = new char[AI_MDL7_MAX_GROUPNAMESIZE*pcHeader->groups_num];
1388 
1389     // read all groups
1390     for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num;++iGroup) {
1391         MDL::IntGroupInfo_MDL7 groupInfo((BE_NCONST MDL::Group_MDL7*)szCurrent,iGroup);
1392         szCurrent = (const unsigned char*)(groupInfo.pcGroup+1);
1393 
1394         VALIDATE_FILE_SIZE(szCurrent);
1395 
1396         AI_SWAP4(groupInfo.pcGroup->groupdata_size);
1397         AI_SWAP4(groupInfo.pcGroup->numskins);
1398         AI_SWAP4(groupInfo.pcGroup->num_stpts);
1399         AI_SWAP4(groupInfo.pcGroup->numtris);
1400         AI_SWAP4(groupInfo.pcGroup->numverts);
1401         AI_SWAP4(groupInfo.pcGroup->numframes);
1402 
1403         if (1 != groupInfo.pcGroup->typ)    {
1404             // Not a triangle-based mesh
1405             DefaultLogger::get()->warn("[3DGS MDL7] Not a triangle mesh group. Continuing happily");
1406         }
1407 
1408         // store the name of the group
1409         const unsigned int ofs = iGroup*AI_MDL7_MAX_GROUPNAMESIZE;
1410         ::memcpy(&aszGroupNameBuffer[ofs],
1411             groupInfo.pcGroup->name,AI_MDL7_MAX_GROUPNAMESIZE);
1412 
1413         // make sure '\0' is at the end
1414         aszGroupNameBuffer[ofs+AI_MDL7_MAX_GROUPNAMESIZE-1] = '\0';
1415 
1416         // read all skins
1417         sharedData.pcMats.reserve(sharedData.pcMats.size() + groupInfo.pcGroup->numskins);
1418         sharedData.abNeedMaterials.resize(sharedData.abNeedMaterials.size() +
1419             groupInfo.pcGroup->numskins,false);
1420 
1421         for (unsigned int iSkin = 0; iSkin < (unsigned int)groupInfo.pcGroup->numskins;++iSkin) {
1422             ParseSkinLump_3DGS_MDL7(szCurrent,&szCurrent,sharedData.pcMats);
1423         }
1424         // if we have absolutely no skin loaded we need to generate a default material
1425         if (sharedData.pcMats.empty())  {
1426             const int iMode = (int)aiShadingMode_Gouraud;
1427             sharedData.pcMats.push_back(new aiMaterial());
1428             aiMaterial* pcHelper = (aiMaterial*)sharedData.pcMats[0];
1429             pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
1430 
1431             aiColor3D clr;
1432             clr.b = clr.g = clr.r = 0.6f;
1433             pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
1434             pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
1435 
1436             clr.b = clr.g = clr.r = 0.05f;
1437             pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
1438 
1439             aiString szName;
1440             szName.Set(AI_DEFAULT_MATERIAL_NAME);
1441             pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
1442 
1443             sharedData.abNeedMaterials.resize(1,false);
1444         }
1445 
1446         // now get a pointer to all texture coords in the group
1447         groupInfo.pcGroupUVs = (BE_NCONST MDL::TexCoord_MDL7*)szCurrent;
1448         for(int i = 0; i < groupInfo.pcGroup->num_stpts; ++i){
1449             AI_SWAP4(groupInfo.pcGroupUVs[i].u);
1450             AI_SWAP4(groupInfo.pcGroupUVs[i].v);
1451         }
1452         szCurrent += pcHeader->skinpoint_stc_size * groupInfo.pcGroup->num_stpts;
1453 
1454         // now get a pointer to all triangle in the group
1455         groupInfo.pcGroupTris = (Triangle_MDL7*)szCurrent;
1456         szCurrent += pcHeader->triangle_stc_size * groupInfo.pcGroup->numtris;
1457 
1458         // now get a pointer to all vertices in the group
1459         groupInfo.pcGroupVerts = (BE_NCONST MDL::Vertex_MDL7*)szCurrent;
1460         for(int i = 0; i < groupInfo.pcGroup->numverts; ++i){
1461             AI_SWAP4(groupInfo.pcGroupVerts[i].x);
1462             AI_SWAP4(groupInfo.pcGroupVerts[i].y);
1463             AI_SWAP4(groupInfo.pcGroupVerts[i].z);
1464 
1465             AI_SWAP2(groupInfo.pcGroupVerts[i].vertindex);
1466             //We can not swap the normal information now as we don't know which of the two kinds it is
1467         }
1468         szCurrent += pcHeader->mainvertex_stc_size * groupInfo.pcGroup->numverts;
1469         VALIDATE_FILE_SIZE(szCurrent);
1470 
1471         MDL::IntSplitGroupData_MDL7 splitGroupData(sharedData,avOutList[iGroup]);
1472         MDL::IntGroupData_MDL7 groupData;
1473         if (groupInfo.pcGroup->numtris && groupInfo.pcGroup->numverts)
1474         {
1475             // build output vectors
1476             const unsigned int iNumVertices = groupInfo.pcGroup->numtris*3;
1477             groupData.vPositions.resize(iNumVertices);
1478             groupData.vNormals.resize(iNumVertices);
1479 
1480             if (sharedData.apcOutBones)groupData.aiBones.resize(iNumVertices,UINT_MAX);
1481 
1482             // it is also possible that there are 0 UV coordinate sets
1483             if (groupInfo.pcGroup->num_stpts){
1484                 groupData.vTextureCoords1.resize(iNumVertices,aiVector3D());
1485 
1486                 // check whether the triangle data structure is large enough
1487                 // to contain a second UV coodinate set
1488                 if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_TWO_UV)    {
1489                     groupData.vTextureCoords2.resize(iNumVertices,aiVector3D());
1490                     groupData.bNeed2UV = true;
1491                 }
1492             }
1493             groupData.pcFaces = new MDL::IntFace_MDL7[groupInfo.pcGroup->numtris];
1494 
1495             // read all faces into the preallocated arrays
1496             ReadFaces_3DGS_MDL7(groupInfo, groupData);
1497 
1498             // sort by materials
1499             SortByMaterials_3DGS_MDL7(groupInfo, groupData,
1500                 splitGroupData);
1501 
1502             for (unsigned int qq = 0; qq < sharedData.pcMats.size();++qq)   {
1503                 if (!splitGroupData.aiSplit[qq]->empty())
1504                     sharedData.abNeedMaterials[qq] = true;
1505             }
1506         }
1507         else DefaultLogger::get()->warn("[3DGS MDL7] Mesh group consists of 0 "
1508             "vertices or faces. It will be skipped.");
1509 
1510         // process all frames and generate output meshes
1511         ProcessFrames_3DGS_MDL7(groupInfo,groupData, sharedData,szCurrent,&szCurrent);
1512         GenerateOutputMeshes_3DGS_MDL7(groupData,splitGroupData);
1513     }
1514 
1515     // generate a nodegraph and subnodes for each group
1516     pScene->mRootNode = new aiNode();
1517 
1518     // now we need to build a final mesh list
1519     for (uint32_t i = 0; i < pcHeader->groups_num;++i)
1520         pScene->mNumMeshes += (unsigned int)avOutList[i].size();
1521 
1522     pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];  {
1523         unsigned int p = 0,q = 0;
1524         for (uint32_t i = 0; i < pcHeader->groups_num;++i)  {
1525             for (unsigned int a = 0; a < avOutList[i].size();++a)   {
1526                 pScene->mMeshes[p++] = avOutList[i][a];
1527             }
1528             if (!avOutList[i].empty())++pScene->mRootNode->mNumChildren;
1529         }
1530         // we will later need an extra node to serve as parent for all bones
1531         if (sharedData.apcOutBones)++pScene->mRootNode->mNumChildren;
1532         this->pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
1533         p = 0;
1534         for (uint32_t i = 0; i < pcHeader->groups_num;++i)  {
1535             if (avOutList[i].empty())continue;
1536 
1537             aiNode* const pcNode = pScene->mRootNode->mChildren[p] = new aiNode();
1538             pcNode->mNumMeshes = (unsigned int)avOutList[i].size();
1539             pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
1540             pcNode->mParent = this->pScene->mRootNode;
1541             for (unsigned int a = 0; a < pcNode->mNumMeshes;++a)
1542                 pcNode->mMeshes[a] = q + a;
1543             q += (unsigned int)avOutList[i].size();
1544 
1545             // setup the name of the node
1546             char* const szBuffer = &aszGroupNameBuffer[i*AI_MDL7_MAX_GROUPNAMESIZE];
1547             if ('\0' == *szBuffer)
1548                 pcNode->mName.length = ::sprintf(szBuffer,"Group_%u",p);
1549             else pcNode->mName.length = ::strlen(szBuffer);
1550             ::strcpy(pcNode->mName.data,szBuffer);
1551             ++p;
1552         }
1553     }
1554 
1555     // if there is only one root node with a single child we can optimize it a bit ...
1556     if (1 == pScene->mRootNode->mNumChildren && !sharedData.apcOutBones)    {
1557         aiNode* pcOldRoot = this->pScene->mRootNode;
1558         pScene->mRootNode = pcOldRoot->mChildren[0];
1559         pcOldRoot->mChildren[0] = NULL;
1560         delete pcOldRoot;
1561         pScene->mRootNode->mParent = NULL;
1562     }
1563     else pScene->mRootNode->mName.Set("<mesh_root>");
1564 
1565     delete[] avOutList;
1566     delete[] aszGroupNameBuffer;
1567     AI_DEBUG_INVALIDATE_PTR(avOutList);
1568     AI_DEBUG_INVALIDATE_PTR(aszGroupNameBuffer);
1569 
1570     // build a final material list.
1571     CopyMaterials_3DGS_MDL7(sharedData);
1572     HandleMaterialReferences_3DGS_MDL7();
1573 
1574     // generate output bone animations and add all bones to the scenegraph
1575     if (sharedData.apcOutBones) {
1576         // this step adds empty dummy bones to the nodegraph
1577         // insert another dummy node to avoid name conflicts
1578         aiNode* const pc = pScene->mRootNode->mChildren[pScene->mRootNode->mNumChildren-1] = new aiNode();
1579 
1580         pc->mName.Set("<skeleton_root>");
1581 
1582         // add bones to the nodegraph
1583         AddBonesToNodeGraph_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **)
1584             sharedData.apcOutBones,pc,0xffff);
1585 
1586         // this steps build a valid output animation
1587         BuildOutputAnims_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **)
1588             sharedData.apcOutBones);
1589     }
1590 }
1591 
1592 // ------------------------------------------------------------------------------------------------
1593 // Copy materials
CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 & shared)1594 void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared)
1595 {
1596     pScene->mNumMaterials = (unsigned int)shared.pcMats.size();
1597     pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
1598     for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
1599         pScene->mMaterials[i] = shared.pcMats[i];
1600 }
1601 
1602 
1603 // ------------------------------------------------------------------------------------------------
1604 // Process material references
HandleMaterialReferences_3DGS_MDL7()1605 void MDLImporter::HandleMaterialReferences_3DGS_MDL7()
1606 {
1607     // search for referrer materials
1608     for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
1609         int iIndex = 0;
1610         if (AI_SUCCESS == aiGetMaterialInteger(pScene->mMaterials[i],AI_MDL7_REFERRER_MATERIAL, &iIndex) )  {
1611             for (unsigned int a = 0; a < pScene->mNumMeshes;++a)    {
1612                 aiMesh* const pcMesh = pScene->mMeshes[a];
1613                 if (i == pcMesh->mMaterialIndex) {
1614                     pcMesh->mMaterialIndex = iIndex;
1615                 }
1616             }
1617             // collapse the rest of the array
1618             delete pScene->mMaterials[i];
1619             for (unsigned int pp = i; pp < pScene->mNumMaterials-1;++pp)    {
1620 
1621                 pScene->mMaterials[pp] = pScene->mMaterials[pp+1];
1622                 for (unsigned int a = 0; a < pScene->mNumMeshes;++a)    {
1623                     aiMesh* const pcMesh = pScene->mMeshes[a];
1624                     if (pcMesh->mMaterialIndex > i)--pcMesh->mMaterialIndex;
1625                 }
1626             }
1627             --pScene->mNumMaterials;
1628         }
1629     }
1630 }
1631 
1632 // ------------------------------------------------------------------------------------------------
1633 // Read bone transformation keys
ParseBoneTrafoKeys_3DGS_MDL7(const MDL::IntGroupInfo_MDL7 & groupInfo,IntFrameInfo_MDL7 & frame,MDL::IntSharedData_MDL7 & shared)1634 void MDLImporter::ParseBoneTrafoKeys_3DGS_MDL7(
1635     const MDL::IntGroupInfo_MDL7& groupInfo,
1636     IntFrameInfo_MDL7&            frame,
1637     MDL::IntSharedData_MDL7&      shared)
1638 {
1639     const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
1640 
1641     // only the first group contains bone animation keys
1642     if (frame.pcFrame->transmatrix_count)   {
1643         if (!groupInfo.iIndex)  {
1644             // skip all frames vertices. We can't support them
1645             const MDL::BoneTransform_MDL7* pcBoneTransforms = (const MDL::BoneTransform_MDL7*)
1646                 (((const char*)frame.pcFrame) + pcHeader->frame_stc_size +
1647                 frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size);
1648 
1649             // read all transformation matrices
1650             for (unsigned int iTrafo = 0; iTrafo < frame.pcFrame->transmatrix_count;++iTrafo)   {
1651                 if(pcBoneTransforms->bone_index >= pcHeader->bones_num) {
1652                     DefaultLogger::get()->warn("Index overflow in frame area. "
1653                         "Unable to parse this bone transformation");
1654                 }
1655                 else    {
1656                     AddAnimationBoneTrafoKey_3DGS_MDL7(frame.iIndex,
1657                         pcBoneTransforms,shared.apcOutBones);
1658                 }
1659                 pcBoneTransforms = (const MDL::BoneTransform_MDL7*)(
1660                     (const char*)pcBoneTransforms + pcHeader->bonetrans_stc_size);
1661             }
1662         }
1663         else    {
1664             DefaultLogger::get()->warn("Ignoring animation keyframes in groups != 0");
1665         }
1666     }
1667 }
1668 
1669 // ------------------------------------------------------------------------------------------------
1670 // Attach bones to the output nodegraph
AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7 ** apcBones,aiNode * pcParent,uint16_t iParentIndex)1671 void MDLImporter::AddBonesToNodeGraph_3DGS_MDL7(const MDL::IntBone_MDL7** apcBones,
1672     aiNode* pcParent,uint16_t iParentIndex)
1673 {
1674     ai_assert(NULL != apcBones && NULL != pcParent);
1675 
1676     // get a pointer to the header ...
1677     const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
1678 
1679     const MDL::IntBone_MDL7** apcBones2 = apcBones;
1680     for (uint32_t i = 0; i <  pcHeader->bones_num;++i)  {
1681 
1682         const MDL::IntBone_MDL7* const pcBone = *apcBones2++;
1683         if (pcBone->iParent == iParentIndex) {
1684             ++pcParent->mNumChildren;
1685         }
1686     }
1687     pcParent->mChildren = new aiNode*[pcParent->mNumChildren];
1688     unsigned int qq = 0;
1689     for (uint32_t i = 0; i <  pcHeader->bones_num;++i)  {
1690 
1691         const MDL::IntBone_MDL7* const pcBone = *apcBones++;
1692         if (pcBone->iParent != iParentIndex)continue;
1693 
1694         aiNode* pcNode = pcParent->mChildren[qq++] = new aiNode();
1695         pcNode->mName = aiString( pcBone->mName );
1696 
1697         AddBonesToNodeGraph_3DGS_MDL7(apcBones,pcNode,(uint16_t)i);
1698     }
1699 }
1700 
1701 // ------------------------------------------------------------------------------------------------
1702 // Build output animations
BuildOutputAnims_3DGS_MDL7(const MDL::IntBone_MDL7 ** apcBonesOut)1703 void MDLImporter::BuildOutputAnims_3DGS_MDL7(
1704     const MDL::IntBone_MDL7** apcBonesOut)
1705 {
1706     ai_assert(NULL != apcBonesOut);
1707     const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)mBuffer;
1708 
1709     // one animation ...
1710     aiAnimation* pcAnim = new aiAnimation();
1711     for (uint32_t i = 0; i < pcHeader->bones_num;++i)   {
1712         if (!apcBonesOut[i]->pkeyPositions.empty()) {
1713 
1714             // get the last frame ... (needn't be equal to pcHeader->frames_num)
1715             for (size_t qq = 0; qq < apcBonesOut[i]->pkeyPositions.size();++qq) {
1716                 pcAnim->mDuration = std::max(pcAnim->mDuration, (double)
1717                     apcBonesOut[i]->pkeyPositions[qq].mTime);
1718             }
1719             ++pcAnim->mNumChannels;
1720         }
1721     }
1722     if (pcAnim->mDuration)  {
1723         pcAnim->mChannels = new aiNodeAnim*[pcAnim->mNumChannels];
1724 
1725         unsigned int iCnt = 0;
1726         for (uint32_t i = 0; i < pcHeader->bones_num;++i)   {
1727             if (!apcBonesOut[i]->pkeyPositions.empty()) {
1728                 const MDL::IntBone_MDL7* const intBone = apcBonesOut[i];
1729 
1730                 aiNodeAnim* const pcNodeAnim = pcAnim->mChannels[iCnt++] = new aiNodeAnim();
1731                 pcNodeAnim->mNodeName = aiString( intBone->mName );
1732 
1733                 // allocate enough storage for all keys
1734                 pcNodeAnim->mNumPositionKeys = (unsigned int)intBone->pkeyPositions.size();
1735                 pcNodeAnim->mNumScalingKeys  = (unsigned int)intBone->pkeyPositions.size();
1736                 pcNodeAnim->mNumRotationKeys = (unsigned int)intBone->pkeyPositions.size();
1737 
1738                 pcNodeAnim->mPositionKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys];
1739                 pcNodeAnim->mScalingKeys  = new aiVectorKey[pcNodeAnim->mNumPositionKeys];
1740                 pcNodeAnim->mRotationKeys = new aiQuatKey[pcNodeAnim->mNumPositionKeys];
1741 
1742                 // copy all keys
1743                 for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys;++qq)   {
1744                     pcNodeAnim->mPositionKeys[qq] = intBone->pkeyPositions[qq];
1745                     pcNodeAnim->mScalingKeys[qq] = intBone->pkeyScalings[qq];
1746                     pcNodeAnim->mRotationKeys[qq] = intBone->pkeyRotations[qq];
1747                 }
1748             }
1749         }
1750 
1751         // store the output animation
1752         pScene->mNumAnimations = 1;
1753         pScene->mAnimations = new aiAnimation*[1];
1754         pScene->mAnimations[0] = pcAnim;
1755     }
1756     else delete pcAnim;
1757 }
1758 
1759 // ------------------------------------------------------------------------------------------------
AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo,const MDL::BoneTransform_MDL7 * pcBoneTransforms,MDL::IntBone_MDL7 ** apcBonesOut)1760 void MDLImporter::AddAnimationBoneTrafoKey_3DGS_MDL7(unsigned int iTrafo,
1761     const MDL::BoneTransform_MDL7* pcBoneTransforms,
1762     MDL::IntBone_MDL7** apcBonesOut)
1763 {
1764     ai_assert(NULL != pcBoneTransforms);
1765     ai_assert(NULL != apcBonesOut);
1766 
1767     // first .. get the transformation matrix
1768     aiMatrix4x4 mTransform;
1769     mTransform.a1 = pcBoneTransforms->m[0];
1770     mTransform.b1 = pcBoneTransforms->m[1];
1771     mTransform.c1 = pcBoneTransforms->m[2];
1772     mTransform.d1 = pcBoneTransforms->m[3];
1773 
1774     mTransform.a2 = pcBoneTransforms->m[4];
1775     mTransform.b2 = pcBoneTransforms->m[5];
1776     mTransform.c2 = pcBoneTransforms->m[6];
1777     mTransform.d2 = pcBoneTransforms->m[7];
1778 
1779     mTransform.a3 = pcBoneTransforms->m[8];
1780     mTransform.b3 = pcBoneTransforms->m[9];
1781     mTransform.c3 = pcBoneTransforms->m[10];
1782     mTransform.d3 = pcBoneTransforms->m[11];
1783 
1784     // now decompose the transformation matrix into separate
1785     // scaling, rotation and translation
1786     aiVectorKey vScaling,vPosition;
1787     aiQuatKey qRotation;
1788 
1789     // FIXME: Decompose will assert in debug builds if the matrix is invalid ...
1790     mTransform.Decompose(vScaling.mValue,qRotation.mValue,vPosition.mValue);
1791 
1792     // now generate keys
1793     vScaling.mTime = qRotation.mTime = vPosition.mTime = (double)iTrafo;
1794 
1795     // add the keys to the bone
1796     MDL::IntBone_MDL7* const pcBoneOut = apcBonesOut[pcBoneTransforms->bone_index];
1797     pcBoneOut->pkeyPositions.push_back  ( vPosition );
1798     pcBoneOut->pkeyScalings.push_back   ( vScaling  );
1799     pcBoneOut->pkeyRotations.push_back  ( qRotation );
1800 }
1801 
1802 // ------------------------------------------------------------------------------------------------
1803 // Construct output meshes
GenerateOutputMeshes_3DGS_MDL7(MDL::IntGroupData_MDL7 & groupData,MDL::IntSplitGroupData_MDL7 & splitGroupData)1804 void MDLImporter::GenerateOutputMeshes_3DGS_MDL7(
1805     MDL::IntGroupData_MDL7& groupData,
1806     MDL::IntSplitGroupData_MDL7& splitGroupData)
1807 {
1808     const MDL::IntSharedData_MDL7& shared = splitGroupData.shared;
1809 
1810     // get a pointer to the header ...
1811     const MDL::Header_MDL7* const pcHeader = (const MDL::Header_MDL7*)this->mBuffer;
1812     const unsigned int iNumOutBones = pcHeader->bones_num;
1813 
1814     for (std::vector<aiMaterial*>::size_type i = 0; i < shared.pcMats.size();++i)   {
1815         if (!splitGroupData.aiSplit[i]->empty())    {
1816 
1817             // allocate the output mesh
1818             aiMesh* pcMesh = new aiMesh();
1819 
1820             pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
1821             pcMesh->mMaterialIndex = (unsigned int)i;
1822 
1823             // allocate output storage
1824             pcMesh->mNumFaces = (unsigned int)splitGroupData.aiSplit[i]->size();
1825             pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
1826 
1827             pcMesh->mNumVertices = pcMesh->mNumFaces*3;
1828             pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
1829             pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
1830 
1831             if (!groupData.vTextureCoords1.empty()) {
1832                 pcMesh->mNumUVComponents[0] = 2;
1833                 pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
1834                 if (!groupData.vTextureCoords2.empty()) {
1835                     pcMesh->mNumUVComponents[1] = 2;
1836                     pcMesh->mTextureCoords[1] = new aiVector3D[pcMesh->mNumVertices];
1837                 }
1838             }
1839 
1840             // iterate through all faces and build an unique set of vertices
1841             unsigned int iCurrent = 0;
1842             for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) {
1843                 pcMesh->mFaces[iFace].mNumIndices = 3;
1844                 pcMesh->mFaces[iFace].mIndices = new unsigned int[3];
1845 
1846                 unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace);
1847                 const MDL::IntFace_MDL7& oldFace = groupData.pcFaces[iSrcFace];
1848 
1849                 // iterate through all face indices
1850                 for (unsigned int c = 0; c < 3;++c) {
1851                     const uint32_t iIndex = oldFace.mIndices[c];
1852                     pcMesh->mVertices[iCurrent] = groupData.vPositions[iIndex];
1853                     pcMesh->mNormals[iCurrent] = groupData.vNormals[iIndex];
1854 
1855                     if (!groupData.vTextureCoords1.empty()) {
1856 
1857                         pcMesh->mTextureCoords[0][iCurrent] = groupData.vTextureCoords1[iIndex];
1858                         if (!groupData.vTextureCoords2.empty()) {
1859                             pcMesh->mTextureCoords[1][iCurrent] = groupData.vTextureCoords2[iIndex];
1860                         }
1861                     }
1862                     pcMesh->mFaces[iFace].mIndices[c] = iCurrent++;
1863                 }
1864             }
1865 
1866             // if we have bones in the mesh we'll need to generate
1867             // proper vertex weights for them
1868             if (!groupData.aiBones.empty()) {
1869                 std::vector<std::vector<unsigned int> > aaiVWeightList;
1870                 aaiVWeightList.resize(iNumOutBones);
1871 
1872                 int iCurrent = 0;
1873                 for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) {
1874                     unsigned int iSrcFace = splitGroupData.aiSplit[i]->operator[](iFace);
1875                     const MDL::IntFace_MDL7& oldFace = groupData.pcFaces[iSrcFace];
1876 
1877                     // iterate through all face indices
1878                     for (unsigned int c = 0; c < 3;++c) {
1879                         unsigned int iBone = groupData.aiBones[ oldFace.mIndices[c] ];
1880                         if (UINT_MAX != iBone)  {
1881                             if (iBone >= iNumOutBones)  {
1882                                 DefaultLogger::get()->error("Bone index overflow. "
1883                                     "The bone index of a vertex exceeds the allowed range. ");
1884                                 iBone = iNumOutBones-1;
1885                             }
1886                             aaiVWeightList[ iBone ].push_back ( iCurrent );
1887                         }
1888                         ++iCurrent;
1889                     }
1890                 }
1891                 // now check which bones are required ...
1892                 for (std::vector<std::vector<unsigned int> >::const_iterator k =  aaiVWeightList.begin();k != aaiVWeightList.end();++k) {
1893                     if (!(*k).empty()) {
1894                         ++pcMesh->mNumBones;
1895                     }
1896                 }
1897                 pcMesh->mBones = new aiBone*[pcMesh->mNumBones];
1898                 iCurrent = 0;
1899                 for (std::vector<std::vector<unsigned int> >::const_iterator k = aaiVWeightList.begin();k!= aaiVWeightList.end();++k,++iCurrent)
1900                 {
1901                     if ((*k).empty())
1902                         continue;
1903 
1904                     // seems we'll need this node
1905                     aiBone* pcBone = pcMesh->mBones[ iCurrent ] = new aiBone();
1906                     pcBone->mName = aiString(shared.apcOutBones[ iCurrent ]->mName);
1907                     pcBone->mOffsetMatrix = shared.apcOutBones[ iCurrent ]->mOffsetMatrix;
1908 
1909                     // setup vertex weights
1910                     pcBone->mNumWeights = (unsigned int)(*k).size();
1911                     pcBone->mWeights = new aiVertexWeight[pcBone->mNumWeights];
1912 
1913                     for (unsigned int weight = 0; weight < pcBone->mNumWeights;++weight)    {
1914                         pcBone->mWeights[weight].mVertexId = (*k)[weight];
1915                         pcBone->mWeights[weight].mWeight = 1.0f;
1916                     }
1917                 }
1918             }
1919             // add the mesh to the list of output meshes
1920             splitGroupData.avOutList.push_back(pcMesh);
1921         }
1922     }
1923 }
1924 
1925 // ------------------------------------------------------------------------------------------------
1926 // Join to materials
JoinSkins_3DGS_MDL7(aiMaterial * pcMat1,aiMaterial * pcMat2,aiMaterial * pcMatOut)1927 void MDLImporter::JoinSkins_3DGS_MDL7(
1928     aiMaterial* pcMat1,
1929     aiMaterial* pcMat2,
1930     aiMaterial* pcMatOut)
1931 {
1932     ai_assert(NULL != pcMat1 && NULL != pcMat2 && NULL != pcMatOut);
1933 
1934     // first create a full copy of the first skin property set
1935     // and assign it to the output material
1936     aiMaterial::CopyPropertyList(pcMatOut,pcMat1);
1937 
1938     int iVal = 0;
1939     pcMatOut->AddProperty<int>(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(0));
1940 
1941     // then extract the diffuse texture from the second skin,
1942     // setup 1 as UV source and we have it
1943     aiString sString;
1944     if(AI_SUCCESS == aiGetMaterialString ( pcMat2, AI_MATKEY_TEXTURE_DIFFUSE(0),&sString )) {
1945         iVal = 1;
1946         pcMatOut->AddProperty<int>(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(1));
1947         pcMatOut->AddProperty(&sString,AI_MATKEY_TEXTURE_DIFFUSE(1));
1948     }
1949 }
1950 
1951 // ------------------------------------------------------------------------------------------------
1952 // Read a half-life 2 MDL
InternReadFile_HL2()1953 void MDLImporter::InternReadFile_HL2( )
1954 {
1955     //const MDL::Header_HL2* pcHeader = (const MDL::Header_HL2*)this->mBuffer;
1956     throw DeadlyImportError("HL2 MDLs are not implemented");
1957 }
1958 
1959 #endif // !! ASSIMP_BUILD_NO_MDL_IMPORTER
1960