1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2021, 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 Implementation of the material part of the MDL importer class */
43
44 #ifndef ASSIMP_BUILD_NO_MDL_IMPORTER
45
46 #include "MDLDefaultColorMap.h"
47 #include "MDLLoader.h"
48
49 #include <assimp/StringUtils.h>
50 #include <assimp/qnan.h>
51 #include <assimp/scene.h>
52 #include <assimp/texture.h>
53 #include <assimp/DefaultLogger.hpp>
54 #include <assimp/IOSystem.hpp>
55
56 #include <memory>
57
58 using namespace Assimp;
59
60 static aiTexel *const bad_texel = reinterpret_cast<aiTexel *>(SIZE_MAX);
61
62 // ------------------------------------------------------------------------------------------------
63 // Find a suitable palette file or take the default one
SearchPalette(const unsigned char ** pszColorMap)64 void MDLImporter::SearchPalette(const unsigned char **pszColorMap) {
65 // now try to find the color map in the current directory
66 IOStream *pcStream = mIOHandler->Open(configPalette, "rb");
67
68 const unsigned char *szColorMap = (const unsigned char *)::g_aclrDefaultColorMap;
69 if (pcStream) {
70 if (pcStream->FileSize() >= 768) {
71 size_t len = 256 * 3;
72 unsigned char *colorMap = new unsigned char[len];
73 szColorMap = colorMap;
74 pcStream->Read(colorMap, len, 1);
75 ASSIMP_LOG_INFO("Found valid colormap.lmp in directory. "
76 "It will be used to decode embedded textures in palletized formats.");
77 }
78 delete pcStream;
79 pcStream = nullptr;
80 }
81 *pszColorMap = szColorMap;
82 }
83
84 // ------------------------------------------------------------------------------------------------
85 // Free the palette again
FreePalette(const unsigned char * szColorMap)86 void MDLImporter::FreePalette(const unsigned char *szColorMap) {
87 if (szColorMap != (const unsigned char *)::g_aclrDefaultColorMap) {
88 delete[] szColorMap;
89 }
90 }
91
92 // ------------------------------------------------------------------------------------------------
93 // Check whether we can replace a texture with a single color
ReplaceTextureWithColor(const aiTexture * pcTexture)94 aiColor4D MDLImporter::ReplaceTextureWithColor(const aiTexture *pcTexture) {
95 ai_assert(nullptr != pcTexture);
96
97 aiColor4D clrOut;
98 clrOut.r = get_qnan();
99 if (!pcTexture->mHeight || !pcTexture->mWidth)
100 return clrOut;
101
102 const unsigned int iNumPixels = pcTexture->mHeight * pcTexture->mWidth;
103 const aiTexel *pcTexel = pcTexture->pcData + 1;
104 const aiTexel *const pcTexelEnd = &pcTexture->pcData[iNumPixels];
105
106 while (pcTexel != pcTexelEnd) {
107 if (*pcTexel != *(pcTexel - 1)) {
108 pcTexel = nullptr;
109 break;
110 }
111 ++pcTexel;
112 }
113 if (pcTexel) {
114 clrOut.r = pcTexture->pcData->r / 255.0f;
115 clrOut.g = pcTexture->pcData->g / 255.0f;
116 clrOut.b = pcTexture->pcData->b / 255.0f;
117 clrOut.a = pcTexture->pcData->a / 255.0f;
118 }
119 return clrOut;
120 }
121
122 // ------------------------------------------------------------------------------------------------
123 // Read a texture from a MDL3 file
CreateTextureARGB8_3DGS_MDL3(const unsigned char * szData)124 void MDLImporter::CreateTextureARGB8_3DGS_MDL3(const unsigned char *szData) {
125 const MDL::Header *pcHeader = (const MDL::Header *)mBuffer; //the endianness is already corrected in the InternReadFile_3DGS_MDL345 function
126
127 VALIDATE_FILE_SIZE(szData + pcHeader->skinwidth *
128 pcHeader->skinheight);
129
130 // allocate a new texture object
131 aiTexture *pcNew = new aiTexture();
132 pcNew->mWidth = pcHeader->skinwidth;
133 pcNew->mHeight = pcHeader->skinheight;
134
135 if(pcNew->mWidth != 0 && pcNew->mHeight > UINT_MAX/pcNew->mWidth) {
136 throw DeadlyImportError("Invalid MDL file. A texture is too big.");
137 }
138 pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight];
139
140 const unsigned char *szColorMap;
141 this->SearchPalette(&szColorMap);
142
143 // copy texture data
144 for (unsigned int i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
145 const unsigned char val = szData[i];
146 const unsigned char *sz = &szColorMap[val * 3];
147
148 pcNew->pcData[i].a = 0xFF;
149 pcNew->pcData[i].r = *sz++;
150 pcNew->pcData[i].g = *sz++;
151 pcNew->pcData[i].b = *sz;
152 }
153
154 FreePalette(szColorMap);
155
156 // store the texture
157 aiTexture **pc = this->pScene->mTextures;
158 this->pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1];
159 for (unsigned int i = 0; i < pScene->mNumTextures; ++i)
160 pScene->mTextures[i] = pc[i];
161
162 pScene->mTextures[this->pScene->mNumTextures] = pcNew;
163 pScene->mNumTextures++;
164 delete[] pc;
165 }
166
167 // ------------------------------------------------------------------------------------------------
168 // Read a texture from a MDL4 file
CreateTexture_3DGS_MDL4(const unsigned char * szData,unsigned int iType,unsigned int * piSkip)169 void MDLImporter::CreateTexture_3DGS_MDL4(const unsigned char *szData,
170 unsigned int iType,
171 unsigned int *piSkip) {
172 ai_assert(nullptr != piSkip);
173
174 const MDL::Header *pcHeader = (const MDL::Header *)mBuffer; //the endianness is already corrected in the InternReadFile_3DGS_MDL345 function
175
176 if (iType == 1 || iType > 3) {
177 ASSIMP_LOG_ERROR("Unsupported texture file format");
178 return;
179 }
180
181 const bool bNoRead = *piSkip == UINT_MAX;
182
183 // allocate a new texture object
184 aiTexture *pcNew = new aiTexture();
185 pcNew->mWidth = pcHeader->skinwidth;
186 pcNew->mHeight = pcHeader->skinheight;
187
188 if (bNoRead) pcNew->pcData = bad_texel;
189 ParseTextureColorData(szData, iType, piSkip, pcNew);
190
191 // store the texture
192 if (!bNoRead) {
193 if (!this->pScene->mNumTextures) {
194 pScene->mNumTextures = 1;
195 pScene->mTextures = new aiTexture *[1];
196 pScene->mTextures[0] = pcNew;
197 } else {
198 aiTexture **pc = pScene->mTextures;
199 pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1];
200 for (unsigned int i = 0; i < this->pScene->mNumTextures; ++i)
201 pScene->mTextures[i] = pc[i];
202 pScene->mTextures[pScene->mNumTextures] = pcNew;
203 pScene->mNumTextures++;
204 delete[] pc;
205 }
206 } else {
207 pcNew->pcData = nullptr;
208 delete pcNew;
209 }
210 return;
211 }
212
213 // ------------------------------------------------------------------------------------------------
214 // Load color data of a texture and convert it to our output format
ParseTextureColorData(const unsigned char * szData,unsigned int iType,unsigned int * piSkip,aiTexture * pcNew)215 void MDLImporter::ParseTextureColorData(const unsigned char *szData,
216 unsigned int iType,
217 unsigned int *piSkip,
218 aiTexture *pcNew) {
219 const bool do_read = bad_texel != pcNew->pcData;
220
221 // allocate storage for the texture image
222 if (do_read) {
223 if(pcNew->mWidth != 0 && pcNew->mHeight > UINT_MAX/pcNew->mWidth) {
224 throw DeadlyImportError("Invalid MDL file. A texture is too big.");
225 }
226 pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight];
227 }
228
229 // R5G6B5 format (with or without MIPs)
230 // ****************************************************************
231 if (2 == iType || 10 == iType) {
232 VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 2);
233
234 // copy texture data
235 unsigned int i;
236 if (do_read) {
237 for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
238 MDL::RGB565 val = ((MDL::RGB565 *)szData)[i];
239 AI_SWAP2(val);
240
241 pcNew->pcData[i].a = 0xFF;
242 pcNew->pcData[i].r = (unsigned char)val.b << 3;
243 pcNew->pcData[i].g = (unsigned char)val.g << 2;
244 pcNew->pcData[i].b = (unsigned char)val.r << 3;
245 }
246 } else {
247 i = pcNew->mWidth * pcNew->mHeight;
248 }
249 *piSkip = i * 2;
250
251 // apply MIP maps
252 if (10 == iType) {
253 *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1;
254 VALIDATE_FILE_SIZE(szData + *piSkip);
255 }
256 }
257 // ARGB4 format (with or without MIPs)
258 // ****************************************************************
259 else if (3 == iType || 11 == iType) {
260 VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 4);
261
262 // copy texture data
263 unsigned int i;
264 if (do_read) {
265 for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
266 MDL::ARGB4 val = ((MDL::ARGB4 *)szData)[i];
267 AI_SWAP2(val);
268
269 pcNew->pcData[i].a = (unsigned char)val.a << 4;
270 pcNew->pcData[i].r = (unsigned char)val.r << 4;
271 pcNew->pcData[i].g = (unsigned char)val.g << 4;
272 pcNew->pcData[i].b = (unsigned char)val.b << 4;
273 }
274 } else
275 i = pcNew->mWidth * pcNew->mHeight;
276 *piSkip = i * 2;
277
278 // apply MIP maps
279 if (11 == iType) {
280 *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1;
281 VALIDATE_FILE_SIZE(szData + *piSkip);
282 }
283 }
284 // RGB8 format (with or without MIPs)
285 // ****************************************************************
286 else if (4 == iType || 12 == iType) {
287 VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 3);
288
289 // copy texture data
290 unsigned int i;
291 if (do_read) {
292 for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
293 const unsigned char *_szData = &szData[i * 3];
294
295 pcNew->pcData[i].a = 0xFF;
296 pcNew->pcData[i].b = *_szData++;
297 pcNew->pcData[i].g = *_szData++;
298 pcNew->pcData[i].r = *_szData;
299 }
300 } else
301 i = pcNew->mWidth * pcNew->mHeight;
302
303 // apply MIP maps
304 *piSkip = i * 3;
305 if (12 == iType) {
306 *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) * 3;
307 VALIDATE_FILE_SIZE(szData + *piSkip);
308 }
309 }
310 // ARGB8 format (with ir without MIPs)
311 // ****************************************************************
312 else if (5 == iType || 13 == iType) {
313 VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight * 4);
314
315 // copy texture data
316 unsigned int i;
317 if (do_read) {
318 for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
319 const unsigned char *_szData = &szData[i * 4];
320
321 pcNew->pcData[i].b = *_szData++;
322 pcNew->pcData[i].g = *_szData++;
323 pcNew->pcData[i].r = *_szData++;
324 pcNew->pcData[i].a = *_szData;
325 }
326 } else {
327 i = pcNew->mWidth * pcNew->mHeight;
328 }
329
330 // apply MIP maps
331 *piSkip = i << 2;
332 if (13 == iType) {
333 *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 2;
334 }
335 }
336 // palletized 8 bit texture. As for Quake 1
337 // ****************************************************************
338 else if (0 == iType) {
339 VALIDATE_FILE_SIZE(szData + pcNew->mWidth * pcNew->mHeight);
340
341 // copy texture data
342 unsigned int i;
343 if (do_read) {
344
345 const unsigned char *szColorMap;
346 SearchPalette(&szColorMap);
347
348 for (i = 0; i < pcNew->mWidth * pcNew->mHeight; ++i) {
349 const unsigned char val = szData[i];
350 const unsigned char *sz = &szColorMap[val * 3];
351
352 pcNew->pcData[i].a = 0xFF;
353 pcNew->pcData[i].r = *sz++;
354 pcNew->pcData[i].g = *sz++;
355 pcNew->pcData[i].b = *sz;
356 }
357 this->FreePalette(szColorMap);
358
359 } else
360 i = pcNew->mWidth * pcNew->mHeight;
361 *piSkip = i;
362
363 // FIXME: Also support for MIP maps?
364 }
365 }
366
367 // ------------------------------------------------------------------------------------------------
368 // Get a texture from a MDL5 file
CreateTexture_3DGS_MDL5(const unsigned char * szData,unsigned int iType,unsigned int * piSkip)369 void MDLImporter::CreateTexture_3DGS_MDL5(const unsigned char *szData,
370 unsigned int iType,
371 unsigned int *piSkip) {
372 ai_assert(nullptr != piSkip);
373 bool bNoRead = *piSkip == UINT_MAX;
374
375 // allocate a new texture object
376 aiTexture *pcNew = new aiTexture();
377
378 VALIDATE_FILE_SIZE(szData + 8);
379
380 // first read the size of the texture
381 pcNew->mWidth = *((uint32_t *)szData);
382 AI_SWAP4(pcNew->mWidth);
383 szData += sizeof(uint32_t);
384
385 pcNew->mHeight = *((uint32_t *)szData);
386 AI_SWAP4(pcNew->mHeight);
387 szData += sizeof(uint32_t);
388
389 if (bNoRead) {
390 pcNew->pcData = bad_texel;
391 }
392
393 // this should not occur - at least the docs say it shouldn't.
394 // however, one can easily try out what MED does if you have
395 // a model with a DDS texture and export it to MDL5 ...
396 // yeah, it embeds the DDS file.
397 if (6 == iType) {
398 // this is a compressed texture in DDS format
399 *piSkip = pcNew->mWidth;
400 VALIDATE_FILE_SIZE(szData + *piSkip);
401
402 if (!bNoRead) {
403 // place a hint and let the application know that this is a DDS file
404 pcNew->mHeight = 0;
405 pcNew->achFormatHint[0] = 'd';
406 pcNew->achFormatHint[1] = 'd';
407 pcNew->achFormatHint[2] = 's';
408 pcNew->achFormatHint[3] = '\0';
409
410 pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth];
411 ::memcpy(pcNew->pcData, szData, pcNew->mWidth);
412 }
413 } else {
414 // parse the color data of the texture
415 ParseTextureColorData(szData, iType, piSkip, pcNew);
416 }
417 *piSkip += sizeof(uint32_t) * 2;
418
419 if (!bNoRead) {
420 // store the texture
421 if (!this->pScene->mNumTextures) {
422 pScene->mNumTextures = 1;
423 pScene->mTextures = new aiTexture *[1];
424 pScene->mTextures[0] = pcNew;
425 } else {
426 aiTexture **pc = pScene->mTextures;
427 pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1];
428 for (unsigned int i = 0; i < pScene->mNumTextures; ++i)
429 this->pScene->mTextures[i] = pc[i];
430
431 pScene->mTextures[pScene->mNumTextures] = pcNew;
432 pScene->mNumTextures++;
433 delete[] pc;
434 }
435 } else {
436 pcNew->pcData = nullptr;
437 delete pcNew;
438 }
439 return;
440 }
441
442 // ------------------------------------------------------------------------------------------------
443 // Get a skin from a MDL7 file - more complex than all other subformats
ParseSkinLump_3DGS_MDL7(const unsigned char * szCurrent,const unsigned char ** szCurrentOut,aiMaterial * pcMatOut,unsigned int iType,unsigned int iWidth,unsigned int iHeight)444 void MDLImporter::ParseSkinLump_3DGS_MDL7(
445 const unsigned char *szCurrent,
446 const unsigned char **szCurrentOut,
447 aiMaterial *pcMatOut,
448 unsigned int iType,
449 unsigned int iWidth,
450 unsigned int iHeight) {
451 std::unique_ptr<aiTexture> pcNew;
452
453 // get the type of the skin
454 unsigned int iMasked = (unsigned int)(iType & 0xF);
455
456 if (0x1 == iMasked) {
457 // ***** REFERENCE TO ANOTHER SKIN INDEX *****
458 int referrer = (int)iWidth;
459 pcMatOut->AddProperty<int>(&referrer, 1, AI_MDL7_REFERRER_MATERIAL);
460 } else if (0x6 == iMasked) {
461 // ***** EMBEDDED DDS FILE *****
462 if (1 != iHeight) {
463 ASSIMP_LOG_WARN("Found a reference to an embedded DDS texture, "
464 "but texture height is not equal to 1, which is not supported by MED");
465 }
466
467 pcNew.reset(new aiTexture());
468 pcNew->mHeight = 0;
469 pcNew->mWidth = iWidth;
470
471 // place a proper format hint
472 pcNew->achFormatHint[0] = 'd';
473 pcNew->achFormatHint[1] = 'd';
474 pcNew->achFormatHint[2] = 's';
475 pcNew->achFormatHint[3] = '\0';
476
477 pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth];
478 memcpy(pcNew->pcData, szCurrent, pcNew->mWidth);
479 szCurrent += iWidth;
480 } else if (0x7 == iMasked) {
481 // ***** REFERENCE TO EXTERNAL FILE *****
482 if (1 != iHeight) {
483 ASSIMP_LOG_WARN("Found a reference to an external texture, "
484 "but texture height is not equal to 1, which is not supported by MED");
485 }
486
487 aiString szFile;
488 const size_t iLen = strlen((const char *)szCurrent);
489 size_t iLen2 = iLen + 1;
490 iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
491 memcpy(szFile.data, (const char *)szCurrent, iLen2);
492 szFile.length = (ai_uint32)iLen;
493
494 szCurrent += iLen2;
495
496 // place this as diffuse texture
497 pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0));
498 } else if (iMasked || !iType || (iType && iWidth && iHeight)) {
499 pcNew.reset(new aiTexture());
500 if (!iHeight || !iWidth) {
501 ASSIMP_LOG_WARN("Found embedded texture, but its width "
502 "an height are both 0. Is this a joke?");
503
504 // generate an empty chess pattern
505 pcNew->mWidth = pcNew->mHeight = 8;
506 pcNew->pcData = new aiTexel[64];
507 for (unsigned int x = 0; x < 8; ++x) {
508 for (unsigned int y = 0; y < 8; ++y) {
509 const bool bSet = ((0 == x % 2 && 0 != y % 2) ||
510 (0 != x % 2 && 0 == y % 2));
511
512 aiTexel *pc = &pcNew->pcData[y * 8 + x];
513 pc->r = pc->b = pc->g = (bSet ? 0xFF : 0);
514 pc->a = 0xFF;
515 }
516 }
517 } else {
518 // it is a standard color texture. Fill in width and height
519 // and call the same function we used for loading MDL5 files
520
521 pcNew->mWidth = iWidth;
522 pcNew->mHeight = iHeight;
523
524 unsigned int iSkip = 0;
525 ParseTextureColorData(szCurrent, iMasked, &iSkip, pcNew.get());
526
527 // skip length of texture data
528 szCurrent += iSkip;
529 }
530 }
531
532 // sometimes there are MDL7 files which have a monochrome
533 // texture instead of material colors ... possible they have
534 // been converted to MDL7 from other formats, such as MDL5
535 aiColor4D clrTexture;
536 if (pcNew)
537 clrTexture = ReplaceTextureWithColor(pcNew.get());
538 else
539 clrTexture.r = get_qnan();
540
541 // check whether a material definition is contained in the skin
542 if (iType & AI_MDL7_SKINTYPE_MATERIAL) {
543 BE_NCONST MDL::Material_MDL7 *pcMatIn = (BE_NCONST MDL::Material_MDL7 *)szCurrent;
544 szCurrent = (unsigned char *)(pcMatIn + 1);
545 VALIDATE_FILE_SIZE(szCurrent);
546
547 aiColor3D clrTemp;
548
549 #define COLOR_MULTIPLY_RGB() \
550 if (is_not_qnan(clrTexture.r)) { \
551 clrTemp.r *= clrTexture.r; \
552 clrTemp.g *= clrTexture.g; \
553 clrTemp.b *= clrTexture.b; \
554 }
555
556 // read diffuse color
557 clrTemp.r = pcMatIn->Diffuse.r;
558 AI_SWAP4(clrTemp.r);
559 clrTemp.g = pcMatIn->Diffuse.g;
560 AI_SWAP4(clrTemp.g);
561 clrTemp.b = pcMatIn->Diffuse.b;
562 AI_SWAP4(clrTemp.b);
563 COLOR_MULTIPLY_RGB();
564 pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_DIFFUSE);
565
566 // read specular color
567 clrTemp.r = pcMatIn->Specular.r;
568 AI_SWAP4(clrTemp.r);
569 clrTemp.g = pcMatIn->Specular.g;
570 AI_SWAP4(clrTemp.g);
571 clrTemp.b = pcMatIn->Specular.b;
572 AI_SWAP4(clrTemp.b);
573 COLOR_MULTIPLY_RGB();
574 pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_SPECULAR);
575
576 // read ambient color
577 clrTemp.r = pcMatIn->Ambient.r;
578 AI_SWAP4(clrTemp.r);
579 clrTemp.g = pcMatIn->Ambient.g;
580 AI_SWAP4(clrTemp.g);
581 clrTemp.b = pcMatIn->Ambient.b;
582 AI_SWAP4(clrTemp.b);
583 COLOR_MULTIPLY_RGB();
584 pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_AMBIENT);
585
586 // read emissive color
587 clrTemp.r = pcMatIn->Emissive.r;
588 AI_SWAP4(clrTemp.r);
589 clrTemp.g = pcMatIn->Emissive.g;
590 AI_SWAP4(clrTemp.g);
591 clrTemp.b = pcMatIn->Emissive.b;
592 AI_SWAP4(clrTemp.b);
593 pcMatOut->AddProperty<aiColor3D>(&clrTemp, 1, AI_MATKEY_COLOR_EMISSIVE);
594
595 #undef COLOR_MULITPLY_RGB
596
597 // FIX: Take the opacity from the ambient color.
598 // The doc say something else, but it is fact that MED exports the
599 // opacity like this .... oh well.
600 clrTemp.r = pcMatIn->Ambient.a;
601 AI_SWAP4(clrTemp.r);
602 if (is_not_qnan(clrTexture.r)) {
603 clrTemp.r *= clrTexture.a;
604 }
605 pcMatOut->AddProperty<ai_real>(&clrTemp.r, 1, AI_MATKEY_OPACITY);
606
607 // read phong power
608 int iShadingMode = (int)aiShadingMode_Gouraud;
609 AI_SWAP4(pcMatIn->Power);
610 if (0.0f != pcMatIn->Power) {
611 iShadingMode = (int)aiShadingMode_Phong;
612 // pcMatIn is packed, we can't form pointers to its members
613 float power = pcMatIn->Power;
614 pcMatOut->AddProperty<float>(&power, 1, AI_MATKEY_SHININESS);
615 }
616 pcMatOut->AddProperty<int>(&iShadingMode, 1, AI_MATKEY_SHADING_MODEL);
617 } else if (is_not_qnan(clrTexture.r)) {
618 pcMatOut->AddProperty<aiColor4D>(&clrTexture, 1, AI_MATKEY_COLOR_DIFFUSE);
619 pcMatOut->AddProperty<aiColor4D>(&clrTexture, 1, AI_MATKEY_COLOR_SPECULAR);
620 }
621 // if the texture could be replaced by a single material color
622 // we don't need the texture anymore
623 if (is_not_qnan(clrTexture.r)) {
624 pcNew.reset();
625 }
626
627 // If an ASCII effect description (HLSL?) is contained in the file,
628 // we can simply ignore it ...
629 if (iType & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF) {
630 VALIDATE_FILE_SIZE(szCurrent);
631 int32_t iMe = *((int32_t *)szCurrent);
632 AI_SWAP4(iMe);
633 szCurrent += sizeof(char) * iMe + sizeof(int32_t);
634 VALIDATE_FILE_SIZE(szCurrent);
635 }
636
637 // If an embedded texture has been loaded setup the corresponding
638 // data structures in the aiScene instance
639 if (pcNew && pScene->mNumTextures <= 999) {
640 // place this as diffuse texture
641 char current[5];
642 ai_snprintf(current, 5, "*%i", this->pScene->mNumTextures);
643
644 aiString szFile;
645 const size_t iLen = strlen((const char *)current);
646 ::memcpy(szFile.data, (const char *)current, iLen + 1);
647 szFile.length = (ai_uint32)iLen;
648
649 pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0));
650
651 // store the texture
652 if (!pScene->mNumTextures) {
653 pScene->mNumTextures = 1;
654 pScene->mTextures = new aiTexture *[1];
655 pScene->mTextures[0] = pcNew.release();
656 } else {
657 aiTexture **pc = pScene->mTextures;
658 pScene->mTextures = new aiTexture *[pScene->mNumTextures + 1];
659 for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {
660 pScene->mTextures[i] = pc[i];
661 }
662
663 pScene->mTextures[pScene->mNumTextures] = pcNew.release();
664 pScene->mNumTextures++;
665 delete[] pc;
666 }
667 }
668 VALIDATE_FILE_SIZE(szCurrent);
669 *szCurrentOut = szCurrent;
670 }
671
672 // ------------------------------------------------------------------------------------------------
673 // Skip a skin lump
SkipSkinLump_3DGS_MDL7(const unsigned char * szCurrent,const unsigned char ** szCurrentOut,unsigned int iType,unsigned int iWidth,unsigned int iHeight)674 void MDLImporter::SkipSkinLump_3DGS_MDL7(
675 const unsigned char *szCurrent,
676 const unsigned char **szCurrentOut,
677 unsigned int iType,
678 unsigned int iWidth,
679 unsigned int iHeight) {
680 // get the type of the skin
681 const unsigned int iMasked = (unsigned int)(iType & 0xF);
682
683 if (0x6 == iMasked) {
684 szCurrent += iWidth;
685 }
686 if (0x7 == iMasked) {
687 const size_t iLen = std::strlen((const char *)szCurrent);
688 szCurrent += iLen + 1;
689 } else if (iMasked || !iType) {
690 if (iMasked || !iType || (iType && iWidth && iHeight)) {
691 // ParseTextureColorData(..., aiTexture::pcData == bad_texel) will simply
692 // return the size of the color data in bytes in iSkip
693 unsigned int iSkip = 0;
694
695 aiTexture tex;
696 tex.pcData = bad_texel;
697 tex.mHeight = iHeight;
698 tex.mWidth = iWidth;
699 ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex);
700
701 // FIX: Important, otherwise the destructor will crash
702 tex.pcData = nullptr;
703
704 // skip length of texture data
705 szCurrent += iSkip;
706 }
707 }
708
709 // check whether a material definition is contained in the skin
710 if (iType & AI_MDL7_SKINTYPE_MATERIAL) {
711 BE_NCONST MDL::Material_MDL7 *pcMatIn = (BE_NCONST MDL::Material_MDL7 *)szCurrent;
712 szCurrent = (unsigned char *)(pcMatIn + 1);
713 }
714
715 // if an ASCII effect description (HLSL?) is contained in the file,
716 // we can simply ignore it ...
717 if (iType & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF) {
718 int32_t iMe = *((int32_t *)szCurrent);
719 AI_SWAP4(iMe);
720 szCurrent += sizeof(char) * iMe + sizeof(int32_t);
721 }
722 *szCurrentOut = szCurrent;
723 }
724
725 // ------------------------------------------------------------------------------------------------
ParseSkinLump_3DGS_MDL7(const unsigned char * szCurrent,const unsigned char ** szCurrentOut,std::vector<aiMaterial * > & pcMats)726 void MDLImporter::ParseSkinLump_3DGS_MDL7(
727 const unsigned char *szCurrent,
728 const unsigned char **szCurrentOut,
729 std::vector<aiMaterial *> &pcMats) {
730 ai_assert(nullptr != szCurrent);
731 ai_assert(nullptr != szCurrentOut);
732
733 *szCurrentOut = szCurrent;
734 BE_NCONST MDL::Skin_MDL7 *pcSkin = (BE_NCONST MDL::Skin_MDL7 *)szCurrent;
735 AI_SWAP4(pcSkin->width);
736 AI_SWAP4(pcSkin->height);
737 szCurrent += 12;
738
739 // allocate an output material
740 aiMaterial *pcMatOut = new aiMaterial();
741 pcMats.push_back(pcMatOut);
742
743 // skip length of file name
744 szCurrent += AI_MDL7_MAX_TEXNAMESIZE;
745
746 ParseSkinLump_3DGS_MDL7(szCurrent, szCurrentOut, pcMatOut,
747 pcSkin->typ, pcSkin->width, pcSkin->height);
748
749 // place the name of the skin in the material
750 if (pcSkin->texture_name[0]) {
751 // the 0 termination could be there or not - we can't know
752 aiString szFile;
753 ::memcpy(szFile.data, pcSkin->texture_name, sizeof(pcSkin->texture_name));
754 szFile.data[sizeof(pcSkin->texture_name)] = '\0';
755 szFile.length = (ai_uint32)::strlen(szFile.data);
756
757 pcMatOut->AddProperty(&szFile, AI_MATKEY_NAME);
758 }
759 }
760
761 #endif // !! ASSIMP_BUILD_NO_MDL_IMPORTER
762