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