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