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