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 #include "assimp_view.h"
42
43 #include "MaterialManager.h"
44 #include "AssetHelper.h"
45
46 #include <assimp/cimport.h>
47 #include <assimp/Importer.hpp>
48 #include <assimp/ai_assert.h>
49 #include <assimp/cfileio.h>
50 #include <assimp/postprocess.h>
51 #include <assimp/scene.h>
52 #include <assimp/IOSystem.hpp>
53 #include <assimp/IOStream.hpp>
54 #include <assimp/LogStream.hpp>
55 #include <assimp/DefaultLogger.hpp>
56 #include <assimp/StringComparison.h>
57
58 #include <vector>
59 #include <algorithm>
60
61 namespace AssimpView {
62
63 using namespace Assimp;
64
65 extern std::string g_szMaterialShader;
66 extern HINSTANCE g_hInstance /*= NULL*/;
67 extern HWND g_hDlg /*= NULL*/;
68 extern IDirect3D9* g_piD3D /*= NULL*/;
69 extern IDirect3DDevice9* g_piDevice /*= NULL*/;
70 extern IDirect3DVertexDeclaration9* gDefaultVertexDecl /*= NULL*/;
71 extern double g_fFPS /*= 0.0f*/;
72 extern char g_szFileName[ MAX_PATH ];
73 extern ID3DXEffect* g_piDefaultEffect /*= NULL*/;
74 extern ID3DXEffect* g_piNormalsEffect /*= NULL*/;
75 extern ID3DXEffect* g_piPassThroughEffect /*= NULL*/;
76 extern ID3DXEffect* g_piPatternEffect /*= NULL*/;
77 extern bool g_bMousePressed /*= false*/;
78 extern bool g_bMousePressedR /*= false*/;
79 extern bool g_bMousePressedM /*= false*/;
80 extern bool g_bMousePressedBoth /*= false*/;
81 extern float g_fElpasedTime /*= 0.0f*/;
82 extern D3DCAPS9 g_sCaps;
83 extern bool g_bLoadingFinished /*= false*/;
84 extern HANDLE g_hThreadHandle /*= NULL*/;
85 extern float g_fWheelPos /*= -10.0f*/;
86 extern bool g_bLoadingCanceled /*= false*/;
87 extern IDirect3DTexture9* g_pcTexture /*= NULL*/;
88
89 extern aiMatrix4x4 g_mWorld;
90 extern aiMatrix4x4 g_mWorldRotate;
91 extern aiVector3D g_vRotateSpeed /*= aiVector3D(0.5f,0.5f,0.5f)*/;
92
93 extern aiVector3D g_avLightDirs[ 1 ] /* =
94 { aiVector3D(-0.5f,0.6f,0.2f) ,
95 aiVector3D(-0.5f,0.5f,0.5f)} */;
96
97
98 extern POINT g_mousePos /*= {0,0};*/;
99 extern POINT g_LastmousePos /*= {0,0}*/;
100 extern bool g_bFPSView /*= false*/;
101 extern bool g_bInvert /*= false*/;
102 extern EClickPos g_eClick;
103 extern unsigned int g_iCurrentColor /*= 0*/;
104
105 // NOTE: The light intensity is separated from the color, it can
106 // directly be manipulated using the middle mouse button.
107 // When the user chooses a color from the palette the intensity
108 // is reset to 1.0
109 // index[2] is the ambient color
110 extern float g_fLightIntensity /*=0.0f*/;
111 extern D3DCOLOR g_avLightColors[ 3 ];
112
113 extern RenderOptions g_sOptions;
114 extern Camera g_sCamera;
115 extern AssetHelper *g_pcAsset /*= NULL*/;
116
117
118 //
119 // Contains the mask image for the HUD
120 // (used to determine the position of a click)
121 //
122 // The size of the image is identical to the size of the main
123 // HUD texture
124 //
125 extern unsigned char* g_szImageMask /*= NULL*/;
126
127
128 extern float g_fACMR /*= 3.0f*/;
129 extern IDirect3DQuery9* g_piQuery;
130
131 extern bool g_bPlay /*= false*/;
132
133 extern double g_dCurrent;
134 extern float g_smoothAngle /*= 80.f*/;
135
136 extern unsigned int ppsteps, ppstepsdefault;
137 extern bool nopointslines;
138
139 CMaterialManager CMaterialManager::s_cInstance;
140
141 //-------------------------------------------------------------------------------
142 // D3DX callback function to fill a texture with a checkers pattern
143 //
144 // This pattern is used to mark textures which could not be loaded
145 //-------------------------------------------------------------------------------
FillFunc(D3DXVECTOR4 * pOut,CONST D3DXVECTOR2 * pTexCoord,CONST D3DXVECTOR2 * pTexelSize,LPVOID pData)146 VOID WINAPI FillFunc(D3DXVECTOR4* pOut,
147 CONST D3DXVECTOR2* pTexCoord,
148 CONST D3DXVECTOR2* pTexelSize,
149 LPVOID pData)
150 {
151 UNREFERENCED_PARAMETER(pData);
152 UNREFERENCED_PARAMETER(pTexelSize);
153
154 // generate a nice checker pattern (yellow/black)
155 // size of a square: 32 * 32 px
156 unsigned int iX = (unsigned int)(pTexCoord->x * 256.0f);
157 unsigned int iY = (unsigned int)(pTexCoord->y * 256.0f);
158
159 bool bBlack = false;
160 if ((iX / 32) % 2 == 0)
161 {
162 if ((iY / 32) % 2 == 0)bBlack = true;
163 }
164 else
165 {
166 if ((iY / 32) % 2 != 0)bBlack = true;
167 }
168 pOut->w = 1.0f;
169 if (bBlack)
170 {
171 pOut->x = pOut->y = pOut->z = 0.0f;
172 }
173 else
174 {
175 pOut->x = pOut->y = 1.0f;
176 pOut->z = 0.0f;
177 }
178 return;
179 }
180
181 //-------------------------------------------------------------------------------
UpdateSpecularMaterials()182 int CMaterialManager::UpdateSpecularMaterials()
183 {
184 if (g_pcAsset && g_pcAsset->pcScene)
185 {
186 for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
187 {
188 if (aiShadingMode_Phong == g_pcAsset->apcMeshes[i]->eShadingMode)
189 {
190 this->DeleteMaterial(g_pcAsset->apcMeshes[i]);
191 this->CreateMaterial(g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]);
192 }
193 }
194 }
195 return 1;
196 }
197 //-------------------------------------------------------------------------------
SetDefaultTexture(IDirect3DTexture9 ** p_ppiOut)198 int CMaterialManager::SetDefaultTexture(IDirect3DTexture9** p_ppiOut)
199 {
200 if (sDefaultTexture) {
201 sDefaultTexture->AddRef();
202 *p_ppiOut = sDefaultTexture;
203 return 1;
204 }
205 if(FAILED(g_piDevice->CreateTexture(
206 256,
207 256,
208 0,
209 0,
210 D3DFMT_A8R8G8B8,
211 D3DPOOL_MANAGED,
212 p_ppiOut,
213 nullptr)))
214 {
215 CLogDisplay::Instance().AddEntry("[ERROR] Unable to create default texture",
216 D3DCOLOR_ARGB(0xFF,0xFF,0,0));
217
218 *p_ppiOut = nullptr;
219 return 0;
220 }
221 D3DXFillTexture(*p_ppiOut,&FillFunc,nullptr);
222 sDefaultTexture = *p_ppiOut;
223 sDefaultTexture->AddRef();
224
225 // {9785DA94-1D96-426b-B3CB-BADC36347F5E}
226 static const GUID guidPrivateData =
227 { 0x9785da94, 0x1d96, 0x426b,
228 { 0xb3, 0xcb, 0xba, 0xdc, 0x36, 0x34, 0x7f, 0x5e } };
229
230 uint32_t iData = 0xFFFFFFFF;
231 (*p_ppiOut)->SetPrivateData(guidPrivateData,&iData,4,0);
232 return 1;
233 }
234 //-------------------------------------------------------------------------------
TryLongerPath(char * szTemp,aiString * p_szString)235 bool CMaterialManager::TryLongerPath(char* szTemp,aiString* p_szString)
236 {
237 char szTempB[MAX_PATH];
238 strcpy(szTempB,szTemp);
239
240 // go to the beginning of the file name
241 char* szFile = strrchr(szTempB,'\\');
242 if (!szFile)szFile = strrchr(szTempB,'/');
243
244 char* szFile2 = szTemp + (szFile - szTempB)+1;
245 szFile++;
246 char* szExt = strrchr(szFile,'.');
247 if (!szExt)return false;
248 szExt++;
249 *szFile = 0;
250
251 strcat(szTempB,"*.*");
252 const unsigned int iSize = (const unsigned int) ( szExt - 1 - szFile );
253
254 HANDLE h;
255 WIN32_FIND_DATA info;
256
257 // build a list of files
258 h = FindFirstFile(szTempB, &info);
259 if (h != INVALID_HANDLE_VALUE)
260 {
261 do
262 {
263 if (!(strcmp(info.cFileName, ".") == 0 || strcmp(info.cFileName, "..") == 0))
264 {
265 char* szExtFound = strrchr(info.cFileName, '.');
266 if (szExtFound)
267 {
268 ++szExtFound;
269 if (0 == ASSIMP_stricmp(szExtFound,szExt))
270 {
271 const unsigned int iSizeFound = (const unsigned int) (
272 szExtFound - 1 - info.cFileName);
273
274 for (unsigned int i = 0; i < iSizeFound;++i)
275 info.cFileName[i] = (CHAR)tolower((unsigned char)info.cFileName[i]);
276
277 if (0 == memcmp(info.cFileName,szFile2, std::min(iSizeFound,iSize)))
278 {
279 // we have it. Build the full path ...
280 char* sz = strrchr(szTempB,'*');
281 *(sz-2) = 0x0;
282
283 strcat(szTempB,info.cFileName);
284
285 // copy the result string back to the aiString
286 const size_t iLen = strlen(szTempB);
287 size_t iLen2 = iLen+1;
288 iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
289 memcpy(p_szString->data,szTempB,iLen2);
290 p_szString->length = static_cast<ai_uint32>(iLen);
291 return true;
292 }
293 }
294 // check whether the 8.3 DOS name is matching
295 if (0 == ASSIMP_stricmp(info.cAlternateFileName,p_szString->data))
296 {
297 strcat(szTempB,info.cAlternateFileName);
298
299 // copy the result string back to the aiString
300 const size_t iLen = strlen(szTempB);
301 size_t iLen2 = iLen+1;
302 iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
303 memcpy(p_szString->data,szTempB,iLen2);
304 p_szString->length = static_cast<ai_uint32>(iLen);
305 return true;
306 }
307 }
308 }
309 }
310 while (FindNextFile(h, &info));
311
312 FindClose(h);
313 }
314 return false;
315 }
316 //-------------------------------------------------------------------------------
FindValidPath(aiString * p_szString)317 int CMaterialManager::FindValidPath(aiString* p_szString)
318 {
319 ai_assert(nullptr != p_szString);
320 aiString pcpy = *p_szString;
321 if ('*' == p_szString->data[0]) {
322 // '*' as first character indicates an embedded file
323 return 5;
324 }
325
326 // first check whether we can directly load the file
327 FILE* pFile = fopen(p_szString->data,"rb");
328 if (pFile) {
329 fclose(pFile);
330 }
331 else {
332 // check whether we can use the directory of the asset as relative base
333 char szTemp[MAX_PATH*2], tmp2[MAX_PATH*2];
334 strcpy(szTemp, g_szFileName);
335 strcpy(tmp2,szTemp);
336
337 char* szData = p_szString->data;
338 if (*szData == '\\' || *szData == '/')++szData;
339
340 char* szEnd = strrchr(szTemp,'\\');
341 if (!szEnd)
342 {
343 szEnd = strrchr(szTemp,'/');
344 if (!szEnd)szEnd = szTemp;
345 }
346 szEnd++;
347 *szEnd = 0;
348 strcat(szEnd,szData);
349
350
351 pFile = fopen(szTemp,"rb");
352 if (!pFile)
353 {
354 // convert the string to lower case
355 for (unsigned int i = 0;;++i)
356 {
357 if ('\0' == szTemp[i])break;
358 szTemp[i] = (char)tolower((unsigned char)szTemp[i]);
359 }
360
361 if(TryLongerPath(szTemp,p_szString))return 1;
362 *szEnd = 0;
363
364 // search common sub directories
365 strcat(szEnd,"tex\\");
366 strcat(szEnd,szData);
367
368 pFile = fopen(szTemp,"rb");
369 if (!pFile)
370 {
371 if(TryLongerPath(szTemp,p_szString))return 1;
372
373 *szEnd = 0;
374
375 strcat(szEnd,"textures\\");
376 strcat(szEnd,szData);
377
378 pFile = fopen(szTemp,"rb");
379 if (!pFile)
380 {
381 if(TryLongerPath(szTemp, p_szString))return 1;
382 }
383
384 // patch by mark sibly to look for textures files in the asset's base directory.
385 const char *path=pcpy.data;
386 const char *p=strrchr( path,'/' );
387 if( !p ) p=strrchr( path,'\\' );
388 if( p ){
389 char *q=strrchr( tmp2,'/' );
390 if( !q ) q=strrchr( tmp2,'\\' );
391 if( q ){
392 strcpy( q+1,p+1 );
393 if((pFile=fopen( tmp2,"r" )) != nullptr){
394 fclose( pFile );
395 strcpy(p_szString->data,tmp2);
396 p_szString->length = static_cast<ai_uint32>(strlen(tmp2));
397 return 1;
398 }
399 }
400 }
401 return 0;
402 }
403 }
404 fclose(pFile);
405
406 // copy the result string back to the aiStr
407 const size_t len = strlen(szTemp);
408 size_t len2 = len+1;
409 len2 = len2 > MAXLEN ? MAXLEN : len2;
410 memcpy(p_szString->data, szTemp, len2);
411 p_szString->length = static_cast<ai_uint32>(len);
412 }
413 return 1;
414 }
415 //-------------------------------------------------------------------------------
LoadTexture(IDirect3DTexture9 ** p_ppiOut,aiString * szPath)416 int CMaterialManager::LoadTexture(IDirect3DTexture9** p_ppiOut,aiString* szPath)
417 {
418 ai_assert(nullptr != p_ppiOut);
419 ai_assert(nullptr != szPath);
420
421 *p_ppiOut = nullptr;
422
423 const std::string s = szPath->data;
424 TextureCache::iterator ff;
425 if ((ff = sCachedTextures.find(s)) != sCachedTextures.end()) {
426 *p_ppiOut = (*ff).second;
427 (*p_ppiOut)->AddRef();
428 return 1;
429 }
430
431 // first get a valid path to the texture
432 if( 5 == FindValidPath(szPath))
433 {
434 // embedded file. Find its index
435 unsigned int iIndex = atoi(szPath->data+1);
436 if (iIndex < g_pcAsset->pcScene->mNumTextures)
437 {
438 if (0 == g_pcAsset->pcScene->mTextures[iIndex]->mHeight)
439 {
440 // it is an embedded file ... don't need the file format hint,
441 // simply let D3DX load the file
442 D3DXIMAGE_INFO info;
443 if (FAILED(D3DXCreateTextureFromFileInMemoryEx(g_piDevice,
444 g_pcAsset->pcScene->mTextures[iIndex]->pcData,
445 g_pcAsset->pcScene->mTextures[iIndex]->mWidth,
446 D3DX_DEFAULT,
447 D3DX_DEFAULT,
448 1,
449 D3DUSAGE_AUTOGENMIPMAP,
450 D3DFMT_UNKNOWN,
451 D3DPOOL_MANAGED,
452 D3DX_DEFAULT,
453 D3DX_DEFAULT,
454 0,
455 &info,
456 nullptr,
457 p_ppiOut)))
458 {
459 std::string sz = "[ERROR] Unable to load embedded texture (#1): ";
460 sz.append(szPath->data);
461 CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
462
463 this->SetDefaultTexture(p_ppiOut);
464 return 1;
465 }
466 }
467 else
468 {
469 // fill a new texture ...
470 if(FAILED(g_piDevice->CreateTexture(
471 g_pcAsset->pcScene->mTextures[iIndex]->mWidth,
472 g_pcAsset->pcScene->mTextures[iIndex]->mHeight,
473 0,D3DUSAGE_AUTOGENMIPMAP,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,p_ppiOut,nullptr)))
474 {
475 std::string sz = "[ERROR] Unable to load embedded texture (#2): ";
476 sz.append(szPath->data);
477 CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
478
479 this->SetDefaultTexture(p_ppiOut);
480 return 1;
481 }
482
483 // now copy the data to it ... (assume non pow2 to be supported)
484 D3DLOCKED_RECT sLock;
485 (*p_ppiOut)->LockRect(0,&sLock,nullptr,0);
486
487 const aiTexel* pcData = g_pcAsset->pcScene->mTextures[iIndex]->pcData;
488
489 for (unsigned int y = 0; y < g_pcAsset->pcScene->mTextures[iIndex]->mHeight;++y)
490 {
491 memcpy(sLock.pBits,pcData,g_pcAsset->pcScene->mTextures[iIndex]->
492 mWidth *sizeof(aiTexel));
493 sLock.pBits = (char*)sLock.pBits + sLock.Pitch;
494 pcData += g_pcAsset->pcScene->mTextures[iIndex]->mWidth;
495 }
496 (*p_ppiOut)->UnlockRect(0);
497 (*p_ppiOut)->GenerateMipSubLevels();
498 }
499 sCachedTextures[s] = *p_ppiOut;
500 (*p_ppiOut)->AddRef();
501 return 1;
502 }
503 else
504 {
505 std::string sz = "[ERROR] Invalid index for embedded texture: ";
506 sz.append(szPath->data);
507 CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
508
509 SetDefaultTexture(p_ppiOut);
510 return 1;
511 }
512 }
513
514 // then call D3DX to load the texture
515 if (FAILED(D3DXCreateTextureFromFileEx(
516 g_piDevice,
517 szPath->data,
518 D3DX_DEFAULT,
519 D3DX_DEFAULT,
520 0,
521 0,
522 D3DFMT_A8R8G8B8,
523 D3DPOOL_MANAGED,
524 D3DX_DEFAULT,
525 D3DX_DEFAULT,
526 0,
527 nullptr,
528 nullptr,
529 p_ppiOut)))
530 {
531 // error ... use the default texture instead
532 std::string sz = "[ERROR] Unable to load texture: ";
533 sz.append(szPath->data);
534 CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
535
536 this->SetDefaultTexture(p_ppiOut);
537 }
538 sCachedTextures[s] = *p_ppiOut;
539 (*p_ppiOut)->AddRef();
540
541 return 1;
542 }
543 //-------------------------------------------------------------------------------
DeleteMaterial(AssetHelper::MeshHelper * pcIn)544 void CMaterialManager::DeleteMaterial(AssetHelper::MeshHelper* pcIn)
545 {
546 if (!pcIn || !pcIn->piEffect)return;
547 pcIn->piEffect->Release();
548
549 // release all textures associated with the material
550 if (pcIn->piDiffuseTexture)
551 {
552 pcIn->piDiffuseTexture->Release();
553 pcIn->piDiffuseTexture = nullptr;
554 }
555 if (pcIn->piSpecularTexture)
556 {
557 pcIn->piSpecularTexture->Release();
558 pcIn->piSpecularTexture = nullptr;
559 }
560 if (pcIn->piEmissiveTexture)
561 {
562 pcIn->piEmissiveTexture->Release();
563 pcIn->piEmissiveTexture = nullptr;
564 }
565 if (pcIn->piAmbientTexture)
566 {
567 pcIn->piAmbientTexture->Release();
568 pcIn->piAmbientTexture = nullptr;
569 }
570 if (pcIn->piOpacityTexture)
571 {
572 pcIn->piOpacityTexture->Release();
573 pcIn->piOpacityTexture = nullptr;
574 }
575 if (pcIn->piNormalTexture)
576 {
577 pcIn->piNormalTexture->Release();
578 pcIn->piNormalTexture = nullptr;
579 }
580 if (pcIn->piShininessTexture)
581 {
582 pcIn->piShininessTexture->Release();
583 pcIn->piShininessTexture = nullptr;
584 }
585 if (pcIn->piLightmapTexture)
586 {
587 pcIn->piLightmapTexture->Release();
588 pcIn->piLightmapTexture = nullptr;
589 }
590 pcIn->piEffect = nullptr;
591 }
592 //-------------------------------------------------------------------------------
HMtoNMIfNecessary(IDirect3DTexture9 * piTexture,IDirect3DTexture9 ** piTextureOut,bool bWasOriginallyHM)593 void CMaterialManager::HMtoNMIfNecessary(
594 IDirect3DTexture9* piTexture,
595 IDirect3DTexture9** piTextureOut,
596 bool bWasOriginallyHM)
597 {
598 ai_assert(nullptr != piTexture);
599 ai_assert(nullptr != piTextureOut);
600
601 bool bMustConvert = false;
602 uintptr_t iElement = 3;
603
604 *piTextureOut = piTexture;
605
606 // Lock the input texture and try to determine its type.
607 // Criteria:
608 // - If r,g,b channel are identical it MUST be a height map
609 // - If one of the rgb channels is used and the others are empty it
610 // must be a height map, too.
611 // - If the average color of the whole image is something inside the
612 // purple range we can be sure it is a normal map
613 //
614 // - Otherwise we assume it is a normal map
615 // To increase performance we take not every pixel
616
617 D3DLOCKED_RECT sRect;
618 D3DSURFACE_DESC sDesc;
619 piTexture->GetLevelDesc(0,&sDesc);
620 if (FAILED(piTexture->LockRect(0,&sRect,nullptr,D3DLOCK_READONLY)))
621 {
622 return;
623 }
624 const int iPitchDiff = (int)sRect.Pitch - (int)(sDesc.Width * 4);
625
626 struct SColor
627 {
628 union
629 {
630 struct {unsigned char b,g,r,a;} data;
631 char _array[4];
632 };
633 };
634 const SColor* pcData = (const SColor*)sRect.pBits;
635
636 union
637 {
638 const SColor* pcPointer;
639 const unsigned char* pcCharPointer;
640 };
641 pcPointer = pcData;
642
643 // 1. If r,g,b channel are identical it MUST be a height map
644 bool bIsEqual = true;
645 for (unsigned int y = 0; y < sDesc.Height;++y)
646 {
647 for (unsigned int x = 0; x < sDesc.Width;++x)
648 {
649 if (pcPointer->data.b != pcPointer->data.r || pcPointer->data.b != pcPointer->data.g)
650 {
651 bIsEqual = false;
652 break;
653 }
654 pcPointer++;
655 }
656 pcCharPointer += iPitchDiff;
657 }
658 if (bIsEqual)bMustConvert = true;
659 else
660 {
661 // 2. If one of the rgb channels is used and the others are empty it
662 // must be a height map, too.
663 pcPointer = pcData;
664 while (*pcCharPointer == 0)pcCharPointer++;
665
666 iElement = (uintptr_t)(pcCharPointer - (unsigned char*)pcData) % 4;
667 unsigned int aiIndex[3] = {0,1,2};
668 if (3 != iElement)aiIndex[iElement] = 3;
669
670 pcPointer = pcData;
671
672 bIsEqual = true;
673 if (3 != iElement)
674 {
675 for (unsigned int y = 0; y < sDesc.Height;++y)
676 {
677 for (unsigned int x = 0; x < sDesc.Width;++x)
678 {
679 for (unsigned int ii = 0; ii < 3;++ii)
680 {
681 // don't take the alpha channel into account.
682 // if the texture was stored n RGB888 format D3DX has
683 // converted it to ARGB8888 format with a fixed alpha channel
684 if (aiIndex[ii] != 3 && pcPointer->_array[aiIndex[ii]] != 0)
685 {
686 bIsEqual = false;
687 break;
688 }
689 }
690 pcPointer++;
691 }
692 pcCharPointer += iPitchDiff;
693 }
694 if (bIsEqual)bMustConvert = true;
695 else
696 {
697 // If the average color of the whole image is something inside the
698 // purple range we can be sure it is a normal map
699
700 // (calculate the average color line per line to prevent overflows!)
701 pcPointer = pcData;
702 aiColor3D clrColor;
703 for (unsigned int y = 0; y < sDesc.Height;++y)
704 {
705 aiColor3D clrColorLine;
706 for (unsigned int x = 0; x < sDesc.Width;++x)
707 {
708 clrColorLine.r += pcPointer->data.r;
709 clrColorLine.g += pcPointer->data.g;
710 clrColorLine.b += pcPointer->data.b;
711 pcPointer++;
712 }
713 clrColor.r += clrColorLine.r /= (float)sDesc.Width;
714 clrColor.g += clrColorLine.g /= (float)sDesc.Width;
715 clrColor.b += clrColorLine.b /= (float)sDesc.Width;
716 pcCharPointer += iPitchDiff;
717 }
718 clrColor.r /= (float)sDesc.Height;
719 clrColor.g /= (float)sDesc.Height;
720 clrColor.b /= (float)sDesc.Height;
721
722 if (!(clrColor.b > 215 &&
723 clrColor.r > 100 && clrColor.r < 140 &&
724 clrColor.g > 100 && clrColor.g < 140))
725 {
726 // Unable to detect. Believe the original value obtained from the loader
727 if (bWasOriginallyHM)
728 {
729 bMustConvert = true;
730 }
731 }
732 }
733 }
734 }
735
736 piTexture->UnlockRect(0);
737
738 // if the input data is assumed to be a height map we'll
739 // need to convert it NOW
740 if (bMustConvert)
741 {
742 D3DSURFACE_DESC sDesc2;
743 piTexture->GetLevelDesc(0, &sDesc2);
744
745 IDirect3DTexture9* piTempTexture;
746 if(FAILED(g_piDevice->CreateTexture(
747 sDesc2.Width,
748 sDesc2.Height,
749 piTexture->GetLevelCount(),
750 sDesc2.Usage,
751 sDesc2.Format,
752 sDesc2.Pool, &piTempTexture, nullptr)))
753 {
754 CLogDisplay::Instance().AddEntry(
755 "[ERROR] Unable to create normal map texture",
756 D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
757 return;
758 }
759
760 DWORD dwFlags;
761 if (3 == iElement)dwFlags = D3DX_CHANNEL_LUMINANCE;
762 else if (2 == iElement)dwFlags = D3DX_CHANNEL_RED;
763 else if (1 == iElement)dwFlags = D3DX_CHANNEL_GREEN;
764 else /*if (0 == iElement)*/dwFlags = D3DX_CHANNEL_BLUE;
765
766 if(FAILED(D3DXComputeNormalMap(piTempTexture,
767 piTexture,nullptr,0,dwFlags,1.0f)))
768 {
769 CLogDisplay::Instance().AddEntry(
770 "[ERROR] Unable to compute normal map from height map",
771 D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
772
773 piTempTexture->Release();
774 return;
775 }
776 *piTextureOut = piTempTexture;
777 piTexture->Release();
778 }
779 }
780 //-------------------------------------------------------------------------------
HasAlphaPixels(IDirect3DTexture9 * piTexture)781 bool CMaterialManager::HasAlphaPixels(IDirect3DTexture9* piTexture)
782 {
783 ai_assert(nullptr != piTexture);
784
785 D3DLOCKED_RECT sRect;
786 D3DSURFACE_DESC sDesc;
787 piTexture->GetLevelDesc(0,&sDesc);
788 if (FAILED(piTexture->LockRect(0,&sRect,nullptr,D3DLOCK_READONLY)))
789 {
790 return false;
791 }
792 const int iPitchDiff = (int)sRect.Pitch - (int)(sDesc.Width * 4);
793
794 struct SColor
795 {
796 unsigned char b,g,r,a;;
797 };
798 const SColor* pcData = (const SColor*)sRect.pBits;
799
800 union
801 {
802 const SColor* pcPointer;
803 const unsigned char* pcCharPointer;
804 };
805 pcPointer = pcData;
806 for (unsigned int y = 0; y < sDesc.Height;++y)
807 {
808 for (unsigned int x = 0; x < sDesc.Width;++x)
809 {
810 if (pcPointer->a != 0xFF)
811 {
812 piTexture->UnlockRect(0);
813 return true;
814 }
815 pcPointer++;
816 }
817 pcCharPointer += iPitchDiff;
818 }
819 piTexture->UnlockRect(0);
820 return false;
821 }
822 //-------------------------------------------------------------------------------
CreateMaterial(AssetHelper::MeshHelper * pcMesh,const aiMesh * pcSource)823 int CMaterialManager::CreateMaterial(
824 AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSource)
825 {
826 ai_assert(nullptr != pcMesh);
827 ai_assert(nullptr != pcSource);
828
829 ID3DXBuffer* piBuffer;
830
831 D3DXMACRO sMacro[64];
832
833 // extract all properties from the ASSIMP material structure
834 const aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[pcSource->mMaterialIndex];
835
836 //
837 // DIFFUSE COLOR --------------------------------------------------
838 //
839 if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_DIFFUSE,
840 (aiColor4D*)&pcMesh->vDiffuseColor))
841 {
842 pcMesh->vDiffuseColor.x = 1.0f;
843 pcMesh->vDiffuseColor.y = 1.0f;
844 pcMesh->vDiffuseColor.z = 1.0f;
845 pcMesh->vDiffuseColor.w = 1.0f;
846 }
847 //
848 // SPECULAR COLOR --------------------------------------------------
849 //
850 if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_SPECULAR,
851 (aiColor4D*)&pcMesh->vSpecularColor))
852 {
853 pcMesh->vSpecularColor.x = 1.0f;
854 pcMesh->vSpecularColor.y = 1.0f;
855 pcMesh->vSpecularColor.z = 1.0f;
856 pcMesh->vSpecularColor.w = 1.0f;
857 }
858 //
859 // AMBIENT COLOR --------------------------------------------------
860 //
861 if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_AMBIENT,
862 (aiColor4D*)&pcMesh->vAmbientColor))
863 {
864 pcMesh->vAmbientColor.x = 0.0f;
865 pcMesh->vAmbientColor.y = 0.0f;
866 pcMesh->vAmbientColor.z = 0.0f;
867 pcMesh->vAmbientColor.w = 1.0f;
868 }
869 //
870 // EMISSIVE COLOR -------------------------------------------------
871 //
872 if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_EMISSIVE,
873 (aiColor4D*)&pcMesh->vEmissiveColor))
874 {
875 pcMesh->vEmissiveColor.x = 0.0f;
876 pcMesh->vEmissiveColor.y = 0.0f;
877 pcMesh->vEmissiveColor.z = 0.0f;
878 pcMesh->vEmissiveColor.w = 1.0f;
879 }
880
881 //
882 // Opacity --------------------------------------------------------
883 //
884 if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_OPACITY,&pcMesh->fOpacity))
885 {
886 pcMesh->fOpacity = 1.0f;
887 }
888
889 //
890 // Shading Model --------------------------------------------------
891 //
892 bool bDefault = false;
893 if(AI_SUCCESS != aiGetMaterialInteger(pcMat,AI_MATKEY_SHADING_MODEL,(int*)&pcMesh->eShadingMode ))
894 {
895 bDefault = true;
896 pcMesh->eShadingMode = aiShadingMode_Gouraud;
897 }
898
899
900 //
901 // Shininess ------------------------------------------------------
902 //
903 if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_SHININESS,&pcMesh->fShininess))
904 {
905 // assume 15 as default shininess
906 pcMesh->fShininess = 15.0f;
907 }
908 else if (bDefault)pcMesh->eShadingMode = aiShadingMode_Phong;
909
910
911 //
912 // Shininess strength ------------------------------------------------------
913 //
914 if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_SHININESS_STRENGTH,&pcMesh->fSpecularStrength))
915 {
916 // assume 1.0 as default shininess strength
917 pcMesh->fSpecularStrength = 1.0f;
918 }
919
920 aiString szPath;
921
922 aiTextureMapMode mapU(aiTextureMapMode_Wrap),mapV(aiTextureMapMode_Wrap);
923
924 bool bib =false;
925 if (pcSource->mTextureCoords[0])
926 {
927
928 //
929 // DIFFUSE TEXTURE ------------------------------------------------
930 //
931 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath))
932 {
933 LoadTexture(&pcMesh->piDiffuseTexture,&szPath);
934
935 aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0),(int*)&mapU);
936 aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0),(int*)&mapV);
937 }
938
939 //
940 // SPECULAR TEXTURE ------------------------------------------------
941 //
942 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0),&szPath))
943 {
944 LoadTexture(&pcMesh->piSpecularTexture,&szPath);
945 }
946
947 //
948 // OPACITY TEXTURE ------------------------------------------------
949 //
950 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0),&szPath))
951 {
952 LoadTexture(&pcMesh->piOpacityTexture,&szPath);
953 }
954 else
955 {
956 int flags = 0;
957 aiGetMaterialInteger(pcMat,AI_MATKEY_TEXFLAGS_DIFFUSE(0),&flags);
958
959 // try to find out whether the diffuse texture has any
960 // non-opaque pixels. If we find a few, use it as opacity texture
961 if (pcMesh->piDiffuseTexture && !(flags & aiTextureFlags_IgnoreAlpha) && HasAlphaPixels(pcMesh->piDiffuseTexture))
962 {
963 int iVal;
964
965 // NOTE: This special value is set by the tree view if the user
966 // manually removes the alpha texture from the view ...
967 if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",0,0,&iVal))
968 {
969 pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture;
970 pcMesh->piOpacityTexture->AddRef();
971 }
972 }
973 }
974
975 //
976 // AMBIENT TEXTURE ------------------------------------------------
977 //
978 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0),&szPath))
979 {
980 LoadTexture(&pcMesh->piAmbientTexture,&szPath);
981 }
982
983 //
984 // EMISSIVE TEXTURE ------------------------------------------------
985 //
986 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0),&szPath))
987 {
988 LoadTexture(&pcMesh->piEmissiveTexture,&szPath);
989 }
990
991 //
992 // Shininess TEXTURE ------------------------------------------------
993 //
994 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SHININESS(0),&szPath))
995 {
996 LoadTexture(&pcMesh->piShininessTexture,&szPath);
997 }
998
999 //
1000 // Lightmap TEXTURE ------------------------------------------------
1001 //
1002 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_LIGHTMAP(0),&szPath))
1003 {
1004 LoadTexture(&pcMesh->piLightmapTexture,&szPath);
1005 }
1006
1007
1008 //
1009 // NORMAL/HEIGHT MAP ------------------------------------------------
1010 //
1011 bool bHM = false;
1012 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0),&szPath))
1013 {
1014 LoadTexture(&pcMesh->piNormalTexture,&szPath);
1015 }
1016 else
1017 {
1018 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_HEIGHT(0),&szPath))
1019 {
1020 LoadTexture(&pcMesh->piNormalTexture,&szPath);
1021 }
1022 else bib = true;
1023 bHM = true;
1024 }
1025
1026 // normal/height maps are sometimes mixed up. Try to detect the type
1027 // of the texture automatically
1028 if (pcMesh->piNormalTexture)
1029 {
1030 HMtoNMIfNecessary(pcMesh->piNormalTexture, &pcMesh->piNormalTexture,bHM);
1031 }
1032 }
1033
1034 // check whether a global background texture is contained
1035 // in this material. Some loaders set this value ...
1036 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_GLOBAL_BACKGROUND_IMAGE,&szPath))
1037 {
1038 CBackgroundPainter::Instance().SetTextureBG(szPath.data);
1039 }
1040
1041 // BUGFIX: If the shininess is 0.0f disable phong lighting
1042 // This is a workaround for some meshes in the DX SDK (e.g. tiny.x)
1043 // FIX: Added this check to the x-loader, but the line remains to
1044 // catch other loader doing the same ...
1045 if (0.0f == pcMesh->fShininess){
1046 pcMesh->eShadingMode = aiShadingMode_Gouraud;
1047 }
1048
1049 int two_sided = 0;
1050 aiGetMaterialInteger(pcMat,AI_MATKEY_TWOSIDED,&two_sided);
1051 pcMesh->twosided = (two_sided != 0);
1052
1053 // check whether we have already a material using the same
1054 // shader. This will decrease loading time rapidly ...
1055 for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
1056 {
1057 if (g_pcAsset->pcScene->mMeshes[i] == pcSource)
1058 {
1059 break;
1060 }
1061 AssetHelper::MeshHelper* pc = g_pcAsset->apcMeshes[i];
1062
1063 if ((pcMesh->piDiffuseTexture != nullptr ? true : false) !=
1064 (pc->piDiffuseTexture != nullptr ? true : false))
1065 continue;
1066 if ((pcMesh->piSpecularTexture != nullptr ? true : false) !=
1067 (pc->piSpecularTexture != nullptr ? true : false))
1068 continue;
1069 if ((pcMesh->piAmbientTexture != nullptr ? true : false) !=
1070 (pc->piAmbientTexture != nullptr ? true : false))
1071 continue;
1072 if ((pcMesh->piEmissiveTexture != nullptr ? true : false) !=
1073 (pc->piEmissiveTexture != nullptr ? true : false))
1074 continue;
1075 if ((pcMesh->piNormalTexture != nullptr ? true : false) !=
1076 (pc->piNormalTexture != nullptr ? true : false))
1077 continue;
1078 if ((pcMesh->piOpacityTexture != nullptr ? true : false) !=
1079 (pc->piOpacityTexture != nullptr ? true : false))
1080 continue;
1081 if ((pcMesh->piShininessTexture != nullptr ? true : false) !=
1082 (pc->piShininessTexture != nullptr ? true : false))
1083 continue;
1084 if ((pcMesh->piLightmapTexture != nullptr ? true : false) !=
1085 (pc->piLightmapTexture != nullptr ? true : false))
1086 continue;
1087 if ((pcMesh->eShadingMode != aiShadingMode_Gouraud ? true : false) !=
1088 (pc->eShadingMode != aiShadingMode_Gouraud ? true : false))
1089 continue;
1090
1091 if ((pcMesh->fOpacity != 1.0f ? true : false) != (pc->fOpacity != 1.0f ? true : false))
1092 continue;
1093
1094 if (pcSource->HasBones() != g_pcAsset->pcScene->mMeshes[i]->HasBones())
1095 continue;
1096
1097 // we can reuse this material
1098 if (pc->piEffect)
1099 {
1100 pcMesh->piEffect = pc->piEffect;
1101 pc->bSharedFX = pcMesh->bSharedFX = true;
1102 pcMesh->piEffect->AddRef();
1103 return 2;
1104 }
1105 }
1106 m_iShaderCount++;
1107
1108 // build macros for the HLSL compiler
1109 unsigned int iCurrent = 0;
1110 if (pcMesh->piDiffuseTexture)
1111 {
1112 sMacro[iCurrent].Name = "AV_DIFFUSE_TEXTURE";
1113 sMacro[iCurrent].Definition = "1";
1114 ++iCurrent;
1115
1116 if (mapU == aiTextureMapMode_Wrap)
1117 sMacro[iCurrent].Name = "AV_WRAPU";
1118 else if (mapU == aiTextureMapMode_Mirror)
1119 sMacro[iCurrent].Name = "AV_MIRRORU";
1120 else // if (mapU == aiTextureMapMode_Clamp)
1121 sMacro[iCurrent].Name = "AV_CLAMPU";
1122
1123 sMacro[iCurrent].Definition = "1";
1124 ++iCurrent;
1125
1126
1127 if (mapV == aiTextureMapMode_Wrap)
1128 sMacro[iCurrent].Name = "AV_WRAPV";
1129 else if (mapV == aiTextureMapMode_Mirror)
1130 sMacro[iCurrent].Name = "AV_MIRRORV";
1131 else // if (mapV == aiTextureMapMode_Clamp)
1132 sMacro[iCurrent].Name = "AV_CLAMPV";
1133
1134 sMacro[iCurrent].Definition = "1";
1135 ++iCurrent;
1136 }
1137 if (pcMesh->piSpecularTexture)
1138 {
1139 sMacro[iCurrent].Name = "AV_SPECULAR_TEXTURE";
1140 sMacro[iCurrent].Definition = "1";
1141 ++iCurrent;
1142 }
1143 if (pcMesh->piAmbientTexture)
1144 {
1145 sMacro[iCurrent].Name = "AV_AMBIENT_TEXTURE";
1146 sMacro[iCurrent].Definition = "1";
1147 ++iCurrent;
1148 }
1149 if (pcMesh->piEmissiveTexture)
1150 {
1151 sMacro[iCurrent].Name = "AV_EMISSIVE_TEXTURE";
1152 sMacro[iCurrent].Definition = "1";
1153 ++iCurrent;
1154 }
1155 char buff[32];
1156 if (pcMesh->piLightmapTexture)
1157 {
1158 sMacro[iCurrent].Name = "AV_LIGHTMAP_TEXTURE";
1159 sMacro[iCurrent].Definition = "1";
1160 ++iCurrent;
1161
1162 int idx;
1163 if(AI_SUCCESS == aiGetMaterialInteger(pcMat,AI_MATKEY_UVWSRC_LIGHTMAP(0),&idx) && idx >= 1 && pcSource->mTextureCoords[idx]) {
1164 sMacro[iCurrent].Name = "AV_TWO_UV";
1165 sMacro[iCurrent].Definition = "1";
1166 ++iCurrent;
1167
1168 sMacro[iCurrent].Definition = "IN.TexCoord1";
1169 }
1170 else sMacro[iCurrent].Definition = "IN.TexCoord0";
1171 sMacro[iCurrent].Name = "AV_LIGHTMAP_TEXTURE_UV_COORD";
1172
1173 ++iCurrent;float f= 1.f;
1174 aiGetMaterialFloat(pcMat,AI_MATKEY_TEXBLEND_LIGHTMAP(0),&f);
1175 sprintf(buff,"%f",f);
1176
1177 sMacro[iCurrent].Name = "LM_STRENGTH";
1178 sMacro[iCurrent].Definition = buff;
1179 ++iCurrent;
1180 }
1181 if (pcMesh->piNormalTexture && !bib)
1182 {
1183 sMacro[iCurrent].Name = "AV_NORMAL_TEXTURE";
1184 sMacro[iCurrent].Definition = "1";
1185 ++iCurrent;
1186 }
1187 if (pcMesh->piOpacityTexture)
1188 {
1189 sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE";
1190 sMacro[iCurrent].Definition = "1";
1191 ++iCurrent;
1192
1193 if (pcMesh->piOpacityTexture == pcMesh->piDiffuseTexture)
1194 {
1195 sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE_REGISTER_MASK";
1196 sMacro[iCurrent].Definition = "a";
1197 ++iCurrent;
1198 }
1199 else
1200 {
1201 sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE_REGISTER_MASK";
1202 sMacro[iCurrent].Definition = "r";
1203 ++iCurrent;
1204 }
1205 }
1206
1207 if (pcMesh->eShadingMode != aiShadingMode_Gouraud && !g_sOptions.bNoSpecular)
1208 {
1209 sMacro[iCurrent].Name = "AV_SPECULAR_COMPONENT";
1210 sMacro[iCurrent].Definition = "1";
1211 ++iCurrent;
1212
1213 if (pcMesh->piShininessTexture)
1214 {
1215 sMacro[iCurrent].Name = "AV_SHININESS_TEXTURE";
1216 sMacro[iCurrent].Definition = "1";
1217 ++iCurrent;
1218 }
1219 }
1220 if (1.0f != pcMesh->fOpacity)
1221 {
1222 sMacro[iCurrent].Name = "AV_OPACITY";
1223 sMacro[iCurrent].Definition = "1";
1224 ++iCurrent;
1225 }
1226
1227 if( pcSource->HasBones())
1228 {
1229 sMacro[iCurrent].Name = "AV_SKINNING";
1230 sMacro[iCurrent].Definition = "1";
1231 ++iCurrent;
1232 }
1233
1234 // If a cubemap is active, we'll need to lookup it for calculating
1235 // a physically correct reflection
1236 if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
1237 {
1238 sMacro[iCurrent].Name = "AV_SKYBOX_LOOKUP";
1239 sMacro[iCurrent].Definition = "1";
1240 ++iCurrent;
1241 }
1242 sMacro[iCurrent].Name = nullptr;
1243 sMacro[iCurrent].Definition = nullptr;
1244
1245 // compile the shader
1246 if(FAILED( D3DXCreateEffect(g_piDevice,
1247 g_szMaterialShader.c_str(),(UINT)g_szMaterialShader.length(),
1248 (const D3DXMACRO*)sMacro,nullptr,0,nullptr,&pcMesh->piEffect,&piBuffer)))
1249 {
1250 // failed to compile the shader
1251 if( piBuffer)
1252 {
1253 MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK);
1254 piBuffer->Release();
1255 }
1256 // use the default material instead
1257 if (g_piDefaultEffect)
1258 {
1259 pcMesh->piEffect = g_piDefaultEffect;
1260 g_piDefaultEffect->AddRef();
1261 }
1262
1263 // get the name of the material and use it in the log message
1264 if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szPath) &&
1265 '\0' != szPath.data[0])
1266 {
1267 std::string sz = "[ERROR] Unable to load material: ";
1268 sz.append(szPath.data);
1269 CLogDisplay::Instance().AddEntry(sz);
1270 }
1271 else
1272 {
1273 CLogDisplay::Instance().AddEntry("Unable to load material: UNNAMED");
1274 }
1275 return 0;
1276 } else
1277 {
1278 // use Fixed Function effect when working with shaderless cards
1279 if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
1280 pcMesh->piEffect->SetTechnique( "MaterialFX_FF");
1281 }
1282
1283 if( piBuffer) piBuffer->Release();
1284
1285
1286 // now commit all constants to the shader
1287 //
1288 // This is not necessary for shared shader. Shader constants for
1289 // shared shaders are automatically recommited before the shader
1290 // is being used for a particular mesh
1291
1292 if (1.0f != pcMesh->fOpacity)
1293 pcMesh->piEffect->SetFloat("TRANSPARENCY",pcMesh->fOpacity);
1294 if (pcMesh->eShadingMode != aiShadingMode_Gouraud && !g_sOptions.bNoSpecular)
1295 {
1296 pcMesh->piEffect->SetFloat("SPECULARITY",pcMesh->fShininess);
1297 pcMesh->piEffect->SetFloat("SPECULAR_STRENGTH",pcMesh->fSpecularStrength);
1298 }
1299
1300 pcMesh->piEffect->SetVector("DIFFUSE_COLOR",&pcMesh->vDiffuseColor);
1301 pcMesh->piEffect->SetVector("SPECULAR_COLOR",&pcMesh->vSpecularColor);
1302 pcMesh->piEffect->SetVector("AMBIENT_COLOR",&pcMesh->vAmbientColor);
1303 pcMesh->piEffect->SetVector("EMISSIVE_COLOR",&pcMesh->vEmissiveColor);
1304
1305 if (pcMesh->piDiffuseTexture)
1306 pcMesh->piEffect->SetTexture("DIFFUSE_TEXTURE",pcMesh->piDiffuseTexture);
1307 if (pcMesh->piOpacityTexture)
1308 pcMesh->piEffect->SetTexture("OPACITY_TEXTURE",pcMesh->piOpacityTexture);
1309 if (pcMesh->piSpecularTexture)
1310 pcMesh->piEffect->SetTexture("SPECULAR_TEXTURE",pcMesh->piSpecularTexture);
1311 if (pcMesh->piAmbientTexture)
1312 pcMesh->piEffect->SetTexture("AMBIENT_TEXTURE",pcMesh->piAmbientTexture);
1313 if (pcMesh->piEmissiveTexture)
1314 pcMesh->piEffect->SetTexture("EMISSIVE_TEXTURE",pcMesh->piEmissiveTexture);
1315 if (pcMesh->piNormalTexture)
1316 pcMesh->piEffect->SetTexture("NORMAL_TEXTURE",pcMesh->piNormalTexture);
1317 if (pcMesh->piShininessTexture)
1318 pcMesh->piEffect->SetTexture("SHININESS_TEXTURE",pcMesh->piShininessTexture);
1319 if (pcMesh->piLightmapTexture)
1320 pcMesh->piEffect->SetTexture("LIGHTMAP_TEXTURE",pcMesh->piLightmapTexture);
1321
1322 if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode()){
1323 pcMesh->piEffect->SetTexture("lw_tex_envmap",CBackgroundPainter::Instance().GetTexture());
1324 }
1325
1326 return 1;
1327 }
1328 //-------------------------------------------------------------------------------
SetupMaterial(AssetHelper::MeshHelper * pcMesh,const aiMatrix4x4 & pcProj,const aiMatrix4x4 & aiMe,const aiMatrix4x4 & pcCam,const aiVector3D & vPos)1329 int CMaterialManager::SetupMaterial (
1330 AssetHelper::MeshHelper* pcMesh,
1331 const aiMatrix4x4& pcProj,
1332 const aiMatrix4x4& aiMe,
1333 const aiMatrix4x4& pcCam,
1334 const aiVector3D& vPos)
1335 {
1336 ai_assert(nullptr != pcMesh);
1337 if (!pcMesh->piEffect)return 0;
1338
1339 ID3DXEffect* piEnd = pcMesh->piEffect;
1340
1341 piEnd->SetMatrix("WorldViewProjection",
1342 (const D3DXMATRIX*)&pcProj);
1343
1344 piEnd->SetMatrix("World",(const D3DXMATRIX*)&aiMe);
1345 piEnd->SetMatrix("WorldInverseTranspose",
1346 (const D3DXMATRIX*)&pcCam);
1347
1348 D3DXVECTOR4 apcVec[5];
1349 memset(apcVec,0,sizeof(apcVec));
1350 apcVec[0].x = g_avLightDirs[0].x;
1351 apcVec[0].y = g_avLightDirs[0].y;
1352 apcVec[0].z = g_avLightDirs[0].z;
1353 apcVec[0].w = 0.0f;
1354 apcVec[1].x = g_avLightDirs[0].x * -1.0f;
1355 apcVec[1].y = g_avLightDirs[0].y * -1.0f;
1356 apcVec[1].z = g_avLightDirs[0].z * -1.0f;
1357 apcVec[1].w = 0.0f;
1358 D3DXVec4Normalize(&apcVec[0],&apcVec[0]);
1359 D3DXVec4Normalize(&apcVec[1],&apcVec[1]);
1360 piEnd->SetVectorArray("afLightDir",apcVec,5);
1361
1362 apcVec[0].x = ((g_avLightColors[0] >> 16) & 0xFF) / 255.0f;
1363 apcVec[0].y = ((g_avLightColors[0] >> 8) & 0xFF) / 255.0f;
1364 apcVec[0].z = ((g_avLightColors[0]) & 0xFF) / 255.0f;
1365 apcVec[0].w = 1.0f;
1366
1367 if( g_sOptions.b3Lights)
1368 {
1369 apcVec[1].x = ((g_avLightColors[1] >> 16) & 0xFF) / 255.0f;
1370 apcVec[1].y = ((g_avLightColors[1] >> 8) & 0xFF) / 255.0f;
1371 apcVec[1].z = ((g_avLightColors[1]) & 0xFF) / 255.0f;
1372 apcVec[1].w = 0.0f;
1373 } else
1374 {
1375 apcVec[1].x = 0.0f;
1376 apcVec[1].y = 0.0f;
1377 apcVec[1].z = 0.0f;
1378 apcVec[1].w = 0.0f;
1379 }
1380
1381 apcVec[0] *= g_fLightIntensity;
1382 apcVec[1] *= g_fLightIntensity;
1383 piEnd->SetVectorArray("afLightColor",apcVec,5);
1384
1385 apcVec[0].x = ((g_avLightColors[2] >> 16) & 0xFF) / 255.0f;
1386 apcVec[0].y = ((g_avLightColors[2] >> 8) & 0xFF) / 255.0f;
1387 apcVec[0].z = ((g_avLightColors[2]) & 0xFF) / 255.0f;
1388 apcVec[0].w = 1.0f;
1389
1390 apcVec[1].x = ((g_avLightColors[2] >> 16) & 0xFF) / 255.0f;
1391 apcVec[1].y = ((g_avLightColors[2] >> 8) & 0xFF) / 255.0f;
1392 apcVec[1].z = ((g_avLightColors[2]) & 0xFF) / 255.0f;
1393 apcVec[1].w = 0.0f;
1394
1395 // FIX: light intensity doesn't apply to ambient color
1396 //apcVec[0] *= g_fLightIntensity;
1397 //apcVec[1] *= g_fLightIntensity;
1398 piEnd->SetVectorArray("afLightColorAmbient",apcVec,5);
1399
1400
1401 apcVec[0].x = vPos.x;
1402 apcVec[0].y = vPos.y;
1403 apcVec[0].z = vPos.z;
1404 piEnd->SetVector( "vCameraPos",&apcVec[0]);
1405
1406 // if the effect instance is shared by multiple materials we need to
1407 // recommit its whole state once per frame ...
1408 if (pcMesh->bSharedFX)
1409 {
1410 // now commit all constants to the shader
1411 if (1.0f != pcMesh->fOpacity)
1412 pcMesh->piEffect->SetFloat("TRANSPARENCY",pcMesh->fOpacity);
1413 if (pcMesh->eShadingMode != aiShadingMode_Gouraud)
1414 {
1415 pcMesh->piEffect->SetFloat("SPECULARITY",pcMesh->fShininess);
1416 pcMesh->piEffect->SetFloat("SPECULAR_STRENGTH",pcMesh->fSpecularStrength);
1417 }
1418
1419 pcMesh->piEffect->SetVector("DIFFUSE_COLOR",&pcMesh->vDiffuseColor);
1420 pcMesh->piEffect->SetVector("SPECULAR_COLOR",&pcMesh->vSpecularColor);
1421 pcMesh->piEffect->SetVector("AMBIENT_COLOR",&pcMesh->vAmbientColor);
1422 pcMesh->piEffect->SetVector("EMISSIVE_COLOR",&pcMesh->vEmissiveColor);
1423
1424 if (pcMesh->piOpacityTexture)
1425 pcMesh->piEffect->SetTexture("OPACITY_TEXTURE",pcMesh->piOpacityTexture);
1426 if (pcMesh->piDiffuseTexture)
1427 pcMesh->piEffect->SetTexture("DIFFUSE_TEXTURE",pcMesh->piDiffuseTexture);
1428 if (pcMesh->piSpecularTexture)
1429 pcMesh->piEffect->SetTexture("SPECULAR_TEXTURE",pcMesh->piSpecularTexture);
1430 if (pcMesh->piAmbientTexture)
1431 pcMesh->piEffect->SetTexture("AMBIENT_TEXTURE",pcMesh->piAmbientTexture);
1432 if (pcMesh->piEmissiveTexture)
1433 pcMesh->piEffect->SetTexture("EMISSIVE_TEXTURE",pcMesh->piEmissiveTexture);
1434 if (pcMesh->piNormalTexture)
1435 pcMesh->piEffect->SetTexture("NORMAL_TEXTURE",pcMesh->piNormalTexture);
1436 if (pcMesh->piShininessTexture)
1437 pcMesh->piEffect->SetTexture("SHININESS_TEXTURE",pcMesh->piShininessTexture);
1438 if (pcMesh->piLightmapTexture)
1439 pcMesh->piEffect->SetTexture("LIGHTMAP_TEXTURE",pcMesh->piLightmapTexture);
1440
1441 if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
1442 {
1443 piEnd->SetTexture("lw_tex_envmap",CBackgroundPainter::Instance().GetTexture());
1444 }
1445 }
1446
1447 // disable culling, if necessary
1448 if (pcMesh->twosided && g_sOptions.bCulling) {
1449 g_piDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
1450 }
1451
1452 // setup the correct shader technique to be used for drawing
1453 if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
1454 {
1455 g_piDefaultEffect->SetTechnique( "MaterialFXSpecular_FF");
1456 } else
1457 if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(3,0) || g_sOptions.bLowQuality)
1458 {
1459 if (g_sOptions.b3Lights)
1460 piEnd->SetTechnique("MaterialFXSpecular_PS20_D2");
1461 else piEnd->SetTechnique("MaterialFXSpecular_PS20_D1");
1462 }
1463 else
1464 {
1465 if (g_sOptions.b3Lights)
1466 piEnd->SetTechnique("MaterialFXSpecular_D2");
1467 else piEnd->SetTechnique("MaterialFXSpecular_D1");
1468 }
1469
1470 // activate the effect
1471 UINT dwPasses = 0;
1472 piEnd->Begin(&dwPasses,0);
1473 piEnd->BeginPass(0);
1474 return 1;
1475 }
1476 //-------------------------------------------------------------------------------
EndMaterial(AssetHelper::MeshHelper * pcMesh)1477 int CMaterialManager::EndMaterial (AssetHelper::MeshHelper* pcMesh)
1478 {
1479 ai_assert(nullptr != pcMesh);
1480 if (!pcMesh->piEffect)return 0;
1481
1482 // end the effect
1483 pcMesh->piEffect->EndPass();
1484 pcMesh->piEffect->End();
1485
1486 // re-enable culling if necessary
1487 if (pcMesh->twosided && g_sOptions.bCulling) {
1488 g_piDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
1489 }
1490
1491 return 1;
1492 }
1493
1494 } // end namespace AssimpView
1495