Material.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975
  1. //-------------------------------------------------------------------------------
  2. /**
  3. * This program is distributed under the terms of the GNU Lesser General
  4. * Public License (LGPL).
  5. *
  6. * ASSIMP Viewer Utility
  7. *
  8. */
  9. //-------------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #include "assimp_view.h"
  12. namespace AssimpView {
  13. //
  14. // Specifies the number of different shaders generated for
  15. // the current asset. This number is incremented by CreateMaterial()
  16. // each time a shader isn't found in cache and needs to be created
  17. //
  18. unsigned int g_iShaderCount = 0 ;
  19. //-------------------------------------------------------------------------------
  20. // Compiler idependent stricmp() function.
  21. //
  22. // Used for case insensitive string comparison
  23. //-------------------------------------------------------------------------------
  24. inline int ASSIMP_stricmp(const char *s1, const char *s2)
  25. {
  26. const char *a1, *a2;
  27. a1 = s1;
  28. a2 = s2;
  29. while (true)
  30. {
  31. char c1 = (char)tolower(*a1);
  32. char c2 = (char)tolower(*a2);
  33. if ((0 == c1) && (0 == c2)) return 0;
  34. if (c1 < c2) return-1;
  35. if (c1 > c2) return 1;
  36. ++a1;
  37. ++a2;
  38. }
  39. }
  40. //-------------------------------------------------------------------------------
  41. // D3DX callback function to fill a texture with a checkers pattern
  42. //
  43. // This pattern is used to mark textures which could not be loaded
  44. //-------------------------------------------------------------------------------
  45. VOID WINAPI FillFunc(D3DXVECTOR4* pOut,
  46. CONST D3DXVECTOR2* pTexCoord,
  47. CONST D3DXVECTOR2* pTexelSize,
  48. LPVOID pData)
  49. {
  50. UNREFERENCED_PARAMETER(pData);
  51. UNREFERENCED_PARAMETER(pTexelSize);
  52. // generate a nice checker pattern (yellow/black)
  53. // size of a square: 32 * 32 px
  54. unsigned int iX = (unsigned int)(pTexCoord->x * 256.0f);
  55. unsigned int iY = (unsigned int)(pTexCoord->y * 256.0f);
  56. bool bBlack = false;
  57. if ((iX / 32) % 2 == 0)
  58. {
  59. if ((iY / 32) % 2 == 0)bBlack = true;
  60. }
  61. else
  62. {
  63. if ((iY / 32) % 2 != 0)bBlack = true;
  64. }
  65. pOut->w = 1.0f;
  66. if (bBlack)
  67. {
  68. pOut->x = pOut->y = pOut->z = 0.0f;
  69. }
  70. else
  71. {
  72. pOut->x = pOut->y = 1.0f;
  73. pOut->z = 0.0f;
  74. }
  75. return;
  76. }
  77. //-------------------------------------------------------------------------------
  78. // Setup the default texture for a texture channel
  79. //
  80. // Generates a default checker pattern for a texture
  81. //-------------------------------------------------------------------------------
  82. int SetDefaultTexture(IDirect3DTexture9** p_ppiOut)
  83. {
  84. if(FAILED(g_piDevice->CreateTexture(
  85. 256,
  86. 256,
  87. 0,
  88. 0,
  89. D3DFMT_A8R8G8B8,
  90. D3DPOOL_MANAGED,
  91. p_ppiOut,
  92. NULL)))
  93. {
  94. CLogDisplay::Instance().AddEntry("[ERROR] Unable to create default texture",
  95. D3DCOLOR_ARGB(0xFF,0xFF,0,0));
  96. }
  97. D3DXFillTexture(*p_ppiOut,&FillFunc,NULL);
  98. return 1;
  99. }
  100. //-------------------------------------------------------------------------------
  101. // find a valid path to a texture file
  102. //
  103. // Handle 8.3 syntax correctly, search the environment of the
  104. // executable and the asset for a texture with a name very similar to a given one
  105. //-------------------------------------------------------------------------------
  106. bool TryLongerPath(char* szTemp,aiString* p_szString)
  107. {
  108. char szTempB[MAX_PATH];
  109. strcpy(szTempB,szTemp);
  110. // go to the beginning of the file name
  111. char* szFile = strrchr(szTempB,'\\');
  112. if (!szFile)szFile = strrchr(szTempB,'/');
  113. char* szFile2 = szTemp + (szFile - szTempB)+1;
  114. szFile++;
  115. char* szExt = strrchr(szFile,'.')+1;
  116. *szFile = 0;
  117. strcat(szTempB,"*.*");
  118. const unsigned int iSize = (const unsigned int) ( szExt - 1 - szFile );
  119. HANDLE h;
  120. WIN32_FIND_DATA info;
  121. // build a list of files
  122. h = FindFirstFile(szTempB, &info);
  123. if (h != INVALID_HANDLE_VALUE)
  124. {
  125. do
  126. {
  127. if (!(strcmp(info.cFileName, ".") == 0 || strcmp(info.cFileName, "..") == 0))
  128. {
  129. char* szExtFound = strrchr(info.cFileName, '.')+1;
  130. if ((char*)0x1 != szExtFound)
  131. {
  132. if (0 == ASSIMP_stricmp(szExtFound,szExt))
  133. {
  134. const unsigned int iSizeFound = (const unsigned int) (
  135. szExtFound - 1 - info.cFileName);
  136. for (unsigned int i = 0; i < iSizeFound;++i)
  137. info.cFileName[i] = (CHAR)tolower(info.cFileName[i]);
  138. if (0 == memcmp(info.cFileName,szFile2, std::min(iSizeFound,iSize)))
  139. {
  140. // we have it. Build the full path ...
  141. char* sz = strrchr(szTempB,'*');
  142. *(sz-2) = 0x0;
  143. strcat(szTempB,info.cFileName);
  144. // copy the result string back to the aiString
  145. const size_t iLen = strlen(szTempB);
  146. size_t iLen2 = iLen+1;
  147. iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
  148. memcpy(p_szString->data,szTempB,iLen2);
  149. p_szString->length = iLen;
  150. return true;
  151. }
  152. }
  153. // check whether the 8.3 DOS name is matching
  154. if (0 == ASSIMP_stricmp(info.cAlternateFileName,p_szString->data))
  155. {
  156. strcat(szTempB,info.cAlternateFileName);
  157. // copy the result string back to the aiString
  158. const size_t iLen = strlen(szTempB);
  159. size_t iLen2 = iLen+1;
  160. iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
  161. memcpy(p_szString->data,szTempB,iLen2);
  162. p_szString->length = iLen;
  163. return true;
  164. }
  165. }
  166. }
  167. }
  168. while (FindNextFile(h, &info));
  169. FindClose(h);
  170. }
  171. return false;
  172. }
  173. //-------------------------------------------------------------------------------
  174. // find a valid path to a texture file
  175. //
  176. // Handle 8.3 syntax correctly, search the environment of the
  177. // executable and the asset for a texture with a name very similar to a given one
  178. //-------------------------------------------------------------------------------
  179. int FindValidPath(aiString* p_szString)
  180. {
  181. // first check whether we can directly load the file
  182. FILE* pFile = fopen(p_szString->data,"rb");
  183. if (pFile)fclose(pFile);
  184. else
  185. {
  186. // check whether we can use the directory of
  187. // the asset as relative base
  188. char szTemp[MAX_PATH*2];
  189. strcpy(szTemp, g_szFileName);
  190. char* szData = p_szString->data;
  191. if (*szData == '\\' || *szData == '/')++szData;
  192. char* szEnd = strrchr(szTemp,'\\');
  193. if (!szEnd)
  194. {
  195. szEnd = strrchr(szTemp,'/');
  196. if (!szEnd)szEnd = szTemp;
  197. }
  198. szEnd++;
  199. *szEnd = 0;
  200. strcat(szEnd,szData);
  201. pFile = fopen(szTemp,"rb");
  202. if (!pFile)
  203. {
  204. // convert the string to lower case
  205. for (unsigned int i = 0;;++i)
  206. {
  207. if ('\0' == szTemp[i])break;
  208. szTemp[i] = (char)tolower(szTemp[i]);
  209. }
  210. if(TryLongerPath(szTemp,p_szString))return 1;
  211. *szEnd = 0;
  212. // search common sub directories
  213. strcat(szEnd,"tex\\");
  214. strcat(szEnd,szData);
  215. pFile = fopen(szTemp,"rb");
  216. if (!pFile)
  217. {
  218. if(TryLongerPath(szTemp,p_szString))return 1;
  219. *szEnd = 0;
  220. strcat(szEnd,"textures\\");
  221. strcat(szEnd,szData);
  222. pFile = fopen(szTemp,"rb");
  223. if (!pFile)
  224. {
  225. if(TryLongerPath(szTemp, p_szString))return 1;
  226. // still unable to load ... however, don't spew
  227. // an error message here, simply let it and wait for
  228. // D3DXCreateTextureFromFileEx() to fail ;-)
  229. }
  230. return 0;
  231. }
  232. }
  233. fclose(pFile);
  234. // copy the result string back to the aiString
  235. const size_t iLen = strlen(szTemp);
  236. size_t iLen2 = iLen+1;
  237. iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
  238. memcpy(p_szString->data,szTemp,iLen2);
  239. p_szString->length = iLen;
  240. }
  241. return 1;
  242. }
  243. //-------------------------------------------------------------------------------
  244. // Load a texture into memory and create a native D3D texture resource
  245. //
  246. // The function tries to find a valid path for a texture
  247. //-------------------------------------------------------------------------------
  248. int LoadTexture(IDirect3DTexture9** p_ppiOut,aiString* szPath)
  249. {
  250. // first get a valid path to the texture
  251. FindValidPath(szPath);
  252. *p_ppiOut = NULL;
  253. // then call D3DX to load the texture
  254. if (FAILED(D3DXCreateTextureFromFileEx(
  255. g_piDevice,
  256. szPath->data,
  257. D3DX_DEFAULT,
  258. D3DX_DEFAULT,
  259. 0,
  260. 0,
  261. D3DFMT_A8R8G8B8,
  262. D3DPOOL_MANAGED,
  263. D3DX_DEFAULT,
  264. D3DX_DEFAULT,
  265. 0,
  266. NULL,
  267. NULL,
  268. p_ppiOut)))
  269. {
  270. // error ... use the default texture instead
  271. std::string sz = "[ERROR] Unable to load texture: ";
  272. sz.append(szPath->data);
  273. CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
  274. SetDefaultTexture(p_ppiOut);
  275. }
  276. return 1;
  277. }
  278. //-------------------------------------------------------------------------------
  279. // Delete all resources of a given material
  280. //
  281. // Must be called before CreateMaterial() to prevent memory leaking
  282. //-------------------------------------------------------------------------------
  283. void DeleteMaterial(AssetHelper::MeshHelper* pcIn)
  284. {
  285. if (!pcIn || !pcIn->piEffect)return;
  286. pcIn->piEffect->Release();
  287. // release all textures associated with the material
  288. if (pcIn->piDiffuseTexture)
  289. {
  290. pcIn->piDiffuseTexture->Release();
  291. pcIn->piDiffuseTexture = NULL;
  292. }
  293. if (pcIn->piSpecularTexture)
  294. {
  295. pcIn->piSpecularTexture->Release();
  296. pcIn->piSpecularTexture = NULL;
  297. }
  298. if (pcIn->piEmissiveTexture)
  299. {
  300. pcIn->piEmissiveTexture->Release();
  301. pcIn->piEmissiveTexture = NULL;
  302. }
  303. if (pcIn->piAmbientTexture)
  304. {
  305. pcIn->piAmbientTexture->Release();
  306. pcIn->piAmbientTexture = NULL;
  307. }
  308. if (pcIn->piOpacityTexture)
  309. {
  310. pcIn->piOpacityTexture->Release();
  311. pcIn->piOpacityTexture = NULL;
  312. }
  313. if (pcIn->piNormalTexture)
  314. {
  315. pcIn->piNormalTexture->Release();
  316. pcIn->piNormalTexture = NULL;
  317. }
  318. }
  319. //-------------------------------------------------------------------------------
  320. // Convert a height map to a normal map if necessary
  321. //
  322. // The function tries to detect the type of a texture automatically.
  323. // However, this wont work in every case.
  324. //-------------------------------------------------------------------------------
  325. void HMtoNMIfNecessary(IDirect3DTexture9* piTexture,IDirect3DTexture9** piTextureOut,
  326. bool bWasOriginallyHM = true)
  327. {
  328. bool bMustConvert = false;
  329. uintptr_t iElement = 3;
  330. *piTextureOut = piTexture;
  331. // Lock the input texture and try to determine its type.
  332. // Criterias:
  333. // - If r,g,b channel are identical it MUST be a height map
  334. // - If one of the rgb channels is used and the others are empty it
  335. // must be a height map, too.
  336. // - If the average color of the whole image is something inside the
  337. // purple range we can be sure it is a normal map
  338. //
  339. // - Otherwise we assume it is a normal map
  340. // To increase performance we take not every pixel
  341. D3DLOCKED_RECT sRect;
  342. D3DSURFACE_DESC sDesc;
  343. piTexture->GetLevelDesc(0,&sDesc);
  344. if (FAILED(piTexture->LockRect(0,&sRect,NULL,D3DLOCK_READONLY)))
  345. {
  346. return;
  347. }
  348. const int iPitchDiff = (int)sRect.Pitch - (int)(sDesc.Width * 4);
  349. struct SColor
  350. {
  351. union
  352. {
  353. struct {unsigned char b,g,r,a;};
  354. char _array[4];
  355. };
  356. };
  357. const SColor* pcData = (const SColor*)sRect.pBits;
  358. union
  359. {
  360. const SColor* pcPointer;
  361. const unsigned char* pcCharPointer;
  362. };
  363. pcPointer = pcData;
  364. // 1. If r,g,b channel are identical it MUST be a height map
  365. bool bIsEqual = true;
  366. for (unsigned int y = 0; y < sDesc.Height;++y)
  367. {
  368. for (unsigned int x = 0; x < sDesc.Width;++x)
  369. {
  370. if (pcPointer->b != pcPointer->r || pcPointer->b != pcPointer->g)
  371. {
  372. bIsEqual = false;
  373. break;
  374. }
  375. pcPointer++;
  376. }
  377. pcCharPointer += iPitchDiff;
  378. }
  379. if (bIsEqual)bMustConvert = true;
  380. else
  381. {
  382. // 2. If one of the rgb channels is used and the others are empty it
  383. // must be a height map, too.
  384. pcPointer = pcData;
  385. while (*pcCharPointer == 0)pcCharPointer++;
  386. iElement = (uintptr_t)(pcCharPointer - (unsigned char*)pcData) % 4;
  387. unsigned int aiIndex[3] = {0,1,2};
  388. if (3 != iElement)aiIndex[iElement] = 3;
  389. pcPointer = pcData;
  390. bIsEqual = true;
  391. if (3 != iElement)
  392. {
  393. for (unsigned int y = 0; y < sDesc.Height;++y)
  394. {
  395. for (unsigned int x = 0; x < sDesc.Width;++x)
  396. {
  397. for (unsigned int ii = 0; ii < 3;++ii)
  398. {
  399. // don't take the alpha channel into account.
  400. // if the texture was stored n RGB888 format D3DX has
  401. // converted it to ARGB8888 format with a fixed alpha channel
  402. if (aiIndex[ii] != 3 && pcPointer->_array[aiIndex[ii]] != 0)
  403. {
  404. bIsEqual = false;
  405. break;
  406. }
  407. }
  408. pcPointer++;
  409. }
  410. pcCharPointer += iPitchDiff;
  411. }
  412. if (bIsEqual)bMustConvert = true;
  413. else
  414. {
  415. // If the average color of the whole image is something inside the
  416. // purple range we can be sure it is a normal map
  417. // (calculate the average color line per line to prevent overflows!)
  418. pcPointer = pcData;
  419. aiColor3D clrColor;
  420. for (unsigned int y = 0; y < sDesc.Height;++y)
  421. {
  422. aiColor3D clrColorLine;
  423. for (unsigned int x = 0; x < sDesc.Width;++x)
  424. {
  425. clrColorLine.r += pcPointer->r;
  426. clrColorLine.g += pcPointer->g;
  427. clrColorLine.b += pcPointer->b;
  428. pcPointer++;
  429. }
  430. clrColor.r += clrColorLine.r /= (float)sDesc.Width;
  431. clrColor.g += clrColorLine.g /= (float)sDesc.Width;
  432. clrColor.b += clrColorLine.b /= (float)sDesc.Width;
  433. pcCharPointer += iPitchDiff;
  434. }
  435. clrColor.r /= (float)sDesc.Height;
  436. clrColor.g /= (float)sDesc.Height;
  437. clrColor.b /= (float)sDesc.Height;
  438. if (!(clrColor.b > 215 &&
  439. clrColor.r > 100 && clrColor.r < 140 &&
  440. clrColor.g > 100 && clrColor.g < 140))
  441. {
  442. // Unable to detect. Believe the original value obtained from the loader
  443. if (bWasOriginallyHM)
  444. {
  445. bMustConvert = true;
  446. }
  447. }
  448. }
  449. }
  450. }
  451. piTexture->UnlockRect(0);
  452. // if the input data is assumed to be a height map we'll
  453. // need to convert it NOW
  454. if (bMustConvert)
  455. {
  456. D3DSURFACE_DESC sDesc;
  457. piTexture->GetLevelDesc(0, &sDesc);
  458. IDirect3DTexture9* piTempTexture;
  459. if(FAILED(g_piDevice->CreateTexture(
  460. sDesc.Width,
  461. sDesc.Height,
  462. piTexture->GetLevelCount(),
  463. sDesc.Usage,
  464. sDesc.Format,
  465. sDesc.Pool, &piTempTexture, NULL)))
  466. {
  467. CLogDisplay::Instance().AddEntry(
  468. "[ERROR] Unable to create normal map texture",
  469. D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
  470. return;
  471. }
  472. DWORD dwFlags;
  473. if (3 == iElement)dwFlags = D3DX_CHANNEL_LUMINANCE;
  474. else if (2 == iElement)dwFlags = D3DX_CHANNEL_RED;
  475. else if (1 == iElement)dwFlags = D3DX_CHANNEL_GREEN;
  476. else /*if (0 == iElement)*/dwFlags = D3DX_CHANNEL_BLUE;
  477. if(FAILED(D3DXComputeNormalMap(piTempTexture,
  478. piTexture,NULL,0,dwFlags,1.0f)))
  479. {
  480. CLogDisplay::Instance().AddEntry(
  481. "[ERROR] Unable to compute normal map from height map",
  482. D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
  483. piTempTexture->Release();
  484. return;
  485. }
  486. *piTextureOut = piTempTexture;
  487. piTexture->Release();
  488. }
  489. }
  490. //-------------------------------------------------------------------------------
  491. // Search for non-opaque pixels in a texture
  492. //
  493. // A pixel is considered to be non-opaque if its alpha value s less than 255
  494. //-------------------------------------------------------------------------------
  495. bool HasAlphaPixels(IDirect3DTexture9* piTexture)
  496. {
  497. D3DLOCKED_RECT sRect;
  498. D3DSURFACE_DESC sDesc;
  499. piTexture->GetLevelDesc(0,&sDesc);
  500. if (FAILED(piTexture->LockRect(0,&sRect,NULL,D3DLOCK_READONLY)))
  501. {
  502. return false;
  503. }
  504. const int iPitchDiff = (int)sRect.Pitch - (int)(sDesc.Width * 4);
  505. struct SColor
  506. {
  507. unsigned char b,g,r,a;;
  508. };
  509. const SColor* pcData = (const SColor*)sRect.pBits;
  510. union
  511. {
  512. const SColor* pcPointer;
  513. const unsigned char* pcCharPointer;
  514. };
  515. pcPointer = pcData;
  516. for (unsigned int y = 0; y < sDesc.Height;++y)
  517. {
  518. for (unsigned int x = 0; x < sDesc.Width;++x)
  519. {
  520. if (pcPointer->a != 0xFF)
  521. {
  522. piTexture->UnlockRect(0);
  523. return true;
  524. }
  525. pcPointer++;
  526. }
  527. pcCharPointer += iPitchDiff;
  528. }
  529. piTexture->UnlockRect(0);
  530. return false;
  531. }
  532. //-------------------------------------------------------------------------------
  533. // Create the material for a mesh.
  534. //
  535. // The function checks whether an identical shader is already in use.
  536. // A shader is considered to be identical if it has the same input signature
  537. // and takes the same number of texture channels.
  538. //-------------------------------------------------------------------------------
  539. int CreateMaterial(AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSource)
  540. {
  541. ID3DXBuffer* piBuffer;
  542. D3DXMACRO sMacro[32];
  543. // extract all properties from the ASSIMP material structure
  544. const aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[pcSource->mMaterialIndex];
  545. //
  546. // DIFFUSE COLOR --------------------------------------------------
  547. //
  548. if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_DIFFUSE,
  549. (aiColor4D*)&pcMesh->vDiffuseColor))
  550. {
  551. pcMesh->vDiffuseColor.x = 1.0f;
  552. pcMesh->vDiffuseColor.y = 1.0f;
  553. pcMesh->vDiffuseColor.z = 1.0f;
  554. pcMesh->vDiffuseColor.w = 1.0f;
  555. }
  556. //
  557. // SPECULAR COLOR --------------------------------------------------
  558. //
  559. if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_SPECULAR,
  560. (aiColor4D*)&pcMesh->vSpecularColor))
  561. {
  562. pcMesh->vSpecularColor.x = 1.0f;
  563. pcMesh->vSpecularColor.y = 1.0f;
  564. pcMesh->vSpecularColor.z = 1.0f;
  565. pcMesh->vSpecularColor.w = 1.0f;
  566. }
  567. //
  568. // AMBIENT COLOR --------------------------------------------------
  569. //
  570. if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_AMBIENT,
  571. (aiColor4D*)&pcMesh->vAmbientColor))
  572. {
  573. pcMesh->vAmbientColor.x = 0.0f;
  574. pcMesh->vAmbientColor.y = 0.0f;
  575. pcMesh->vAmbientColor.z = 0.0f;
  576. pcMesh->vAmbientColor.w = 1.0f;
  577. }
  578. //
  579. // EMISSIVE COLOR -------------------------------------------------
  580. //
  581. if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_EMISSIVE,
  582. (aiColor4D*)&pcMesh->vEmissiveColor))
  583. {
  584. pcMesh->vEmissiveColor.x = 0.0f;
  585. pcMesh->vEmissiveColor.y = 0.0f;
  586. pcMesh->vEmissiveColor.z = 0.0f;
  587. pcMesh->vEmissiveColor.w = 1.0f;
  588. }
  589. //
  590. // Opacity --------------------------------------------------------
  591. //
  592. if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_OPACITY,&pcMesh->fOpacity))
  593. {
  594. pcMesh->fOpacity = 1.0f;
  595. }
  596. //
  597. // Shading Model --------------------------------------------------
  598. //
  599. bool bDefault = false;
  600. if(AI_SUCCESS != aiGetMaterialInteger(pcMat,AI_MATKEY_SHADING_MODEL,(int*)&pcMesh->eShadingMode ))
  601. {
  602. bDefault = true;
  603. pcMesh->eShadingMode = aiShadingMode_Gouraud;
  604. }
  605. //
  606. // Shininess ------------------------------------------------------
  607. //
  608. if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_SHININESS,&pcMesh->fShininess))
  609. {
  610. // assume 15 as default shininess
  611. pcMesh->fShininess = 15.0f;
  612. }
  613. else if (bDefault)pcMesh->eShadingMode = aiShadingMode_Phong;
  614. aiString szPath;
  615. //
  616. // DIFFUSE TEXTURE ------------------------------------------------
  617. //
  618. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath))
  619. {
  620. LoadTexture(&pcMesh->piDiffuseTexture,&szPath);
  621. }
  622. //
  623. // SPECULAR TEXTURE ------------------------------------------------
  624. //
  625. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0),&szPath))
  626. {
  627. LoadTexture(&pcMesh->piSpecularTexture,&szPath);
  628. }
  629. //
  630. // OPACITY TEXTURE ------------------------------------------------
  631. //
  632. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0),&szPath))
  633. {
  634. LoadTexture(&pcMesh->piOpacityTexture,&szPath);
  635. }
  636. else
  637. {
  638. // try to find out whether the diffuse texture has any
  639. // non-opaque pixels. If we find a few use it as opacity texture
  640. if (pcMesh->piDiffuseTexture && HasAlphaPixels(pcMesh->piDiffuseTexture))
  641. {
  642. pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture;
  643. pcMesh->piOpacityTexture->AddRef();
  644. }
  645. }
  646. //
  647. // AMBIENT TEXTURE ------------------------------------------------
  648. //
  649. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0),&szPath))
  650. {
  651. LoadTexture(&pcMesh->piAmbientTexture,&szPath);
  652. }
  653. //
  654. // EMISSIVE TEXTURE ------------------------------------------------
  655. //
  656. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0),&szPath))
  657. {
  658. LoadTexture(&pcMesh->piEmissiveTexture,&szPath);
  659. }
  660. //
  661. // NORMAL/HEIGHT MAP ------------------------------------------------
  662. //
  663. bool bHM = false;
  664. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0),&szPath))
  665. {
  666. LoadTexture(&pcMesh->piNormalTexture,&szPath);
  667. }
  668. else
  669. {
  670. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_BUMP(0),&szPath))
  671. {
  672. LoadTexture(&pcMesh->piNormalTexture,&szPath);
  673. }
  674. bHM = true;
  675. }
  676. // normal/height maps are sometimes mixed up. Try to detect the type
  677. // of the texture automatically
  678. if (pcMesh->piNormalTexture)
  679. {
  680. HMtoNMIfNecessary(pcMesh->piNormalTexture, &pcMesh->piNormalTexture,bHM);
  681. }
  682. // check whether a global background texture is contained
  683. // in this material. Some loaders set this value ...
  684. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_GLOBAL_BACKGROUND_IMAGE,&szPath))
  685. {
  686. CBackgroundPainter::Instance().SetTextureBG(szPath.data);
  687. }
  688. // BUGFIX: If the shininess is 0.0f disable phong lighting
  689. // This is a workaround for some meshes in the DX SDK (e.g. tiny.x)
  690. if (0.0f == pcMesh->fShininess)
  691. {
  692. pcMesh->eShadingMode = aiShadingMode_Gouraud;
  693. }
  694. // check whether we have already a material using the same
  695. // shader. This will decrease loading time rapidly ...
  696. for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
  697. {
  698. if (g_pcAsset->pcScene->mMeshes[i] == pcSource)
  699. {
  700. break;
  701. }
  702. AssetHelper::MeshHelper* pc = g_pcAsset->apcMeshes[i];
  703. if ((pcMesh->piDiffuseTexture != NULL ? true : false) !=
  704. (pc->piDiffuseTexture != NULL ? true : false))
  705. continue;
  706. if ((pcMesh->piSpecularTexture != NULL ? true : false) !=
  707. (pc->piSpecularTexture != NULL ? true : false))
  708. continue;
  709. if ((pcMesh->piAmbientTexture != NULL ? true : false) !=
  710. (pc->piAmbientTexture != NULL ? true : false))
  711. continue;
  712. if ((pcMesh->piEmissiveTexture != NULL ? true : false) !=
  713. (pc->piEmissiveTexture != NULL ? true : false))
  714. continue;
  715. if ((pcMesh->piNormalTexture != NULL ? true : false) !=
  716. (pc->piNormalTexture != NULL ? true : false))
  717. continue;
  718. if ((pcMesh->piOpacityTexture != NULL ? true : false) !=
  719. (pc->piOpacityTexture != NULL ? true : false))
  720. continue;
  721. if ((pcMesh->eShadingMode != aiShadingMode_Gouraud ? true : false) !=
  722. (pc->eShadingMode != aiShadingMode_Gouraud ? true : false))
  723. continue;
  724. if ((pcMesh->fOpacity != 1.0f ? true : false) != (pc->fOpacity != 1.0f ? true : false))
  725. continue;
  726. // we can reuse this material
  727. if (pc->piEffect)
  728. {
  729. pcMesh->piEffect = pc->piEffect;
  730. pc->bSharedFX = pcMesh->bSharedFX = true;
  731. pcMesh->piEffect->AddRef();
  732. return 2;
  733. }
  734. }
  735. g_iShaderCount++;
  736. // build macros for the HLSL compiler
  737. unsigned int iCurrent = 0;
  738. if (pcMesh->piDiffuseTexture)
  739. {
  740. sMacro[iCurrent].Name = "AV_DIFFUSE_TEXTURE";
  741. sMacro[iCurrent].Definition = "1";
  742. ++iCurrent;
  743. }
  744. if (pcMesh->piSpecularTexture)
  745. {
  746. sMacro[iCurrent].Name = "AV_SPECULAR_TEXTURE";
  747. sMacro[iCurrent].Definition = "1";
  748. ++iCurrent;
  749. }
  750. if (pcMesh->piAmbientTexture)
  751. {
  752. sMacro[iCurrent].Name = "AV_AMBIENT_TEXTURE";
  753. sMacro[iCurrent].Definition = "1";
  754. ++iCurrent;
  755. }
  756. if (pcMesh->piEmissiveTexture)
  757. {
  758. sMacro[iCurrent].Name = "AV_EMISSIVE_TEXTURE";
  759. sMacro[iCurrent].Definition = "1";
  760. ++iCurrent;
  761. }
  762. if (pcMesh->piNormalTexture)
  763. {
  764. sMacro[iCurrent].Name = "AV_NORMAL_TEXTURE";
  765. sMacro[iCurrent].Definition = "1";
  766. ++iCurrent;
  767. }
  768. if (pcMesh->piOpacityTexture)
  769. {
  770. sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE";
  771. sMacro[iCurrent].Definition = "1";
  772. ++iCurrent;
  773. if (pcMesh->piOpacityTexture == pcMesh->piDiffuseTexture)
  774. {
  775. sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE_REGISTER_MASK";
  776. sMacro[iCurrent].Definition = "a";
  777. ++iCurrent;
  778. }
  779. else
  780. {
  781. sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE_REGISTER_MASK";
  782. sMacro[iCurrent].Definition = "r";
  783. ++iCurrent;
  784. }
  785. }
  786. if (pcMesh->eShadingMode != aiShadingMode_Gouraud && !g_sOptions.bNoSpecular)
  787. {
  788. sMacro[iCurrent].Name = "AV_SPECULAR_COMPONENT";
  789. sMacro[iCurrent].Definition = "1";
  790. ++iCurrent;
  791. }
  792. if (1.0f != pcMesh->fOpacity)
  793. {
  794. sMacro[iCurrent].Name = "AV_OPACITY";
  795. sMacro[iCurrent].Definition = "1";
  796. ++iCurrent;
  797. }
  798. // If a cubemap is active, we'll need to lookup it for calculating
  799. // a physically correct reflection
  800. if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
  801. {
  802. sMacro[iCurrent].Name = "AV_SKYBOX_LOOKUP";
  803. sMacro[iCurrent].Definition = "1";
  804. ++iCurrent;
  805. }
  806. sMacro[iCurrent].Name = NULL;
  807. sMacro[iCurrent].Definition = NULL;
  808. // compile the shader
  809. if(FAILED( D3DXCreateEffect(g_piDevice,
  810. g_szMaterialShader.c_str(),(UINT)g_szMaterialShader.length(),
  811. (const D3DXMACRO*)sMacro,NULL,0,NULL,&pcMesh->piEffect,&piBuffer)))
  812. {
  813. // failed to compile the shader
  814. if( piBuffer)
  815. {
  816. MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK);
  817. piBuffer->Release();
  818. }
  819. // use the default material instead
  820. if (g_piDefaultEffect)
  821. {
  822. pcMesh->piEffect = g_piDefaultEffect;
  823. g_piDefaultEffect->AddRef();
  824. }
  825. // get the name of the material and use it in the log message
  826. if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szPath) &&
  827. '\0' != szPath.data[0])
  828. {
  829. std::string sz = "[ERROR] Unable to load material: ";
  830. sz.append(szPath.data);
  831. CLogDisplay::Instance().AddEntry(sz);
  832. }
  833. else
  834. {
  835. CLogDisplay::Instance().AddEntry("Unable to load material: UNNAMED");
  836. }
  837. return 0;
  838. }
  839. if( piBuffer) piBuffer->Release();
  840. // now commit all constants to the shader
  841. //
  842. // This is not necessary for shared shader. Shader constants for
  843. // shared shaders are automatically recommited before the shader
  844. // is being used for a particular mesh
  845. if (1.0f != pcMesh->fOpacity)
  846. pcMesh->piEffect->SetFloat("TRANSPARENCY",pcMesh->fOpacity);
  847. if (pcMesh->eShadingMode != aiShadingMode_Gouraud && !g_sOptions.bNoSpecular)
  848. pcMesh->piEffect->SetFloat("SPECULARITY",pcMesh->fShininess);
  849. pcMesh->piEffect->SetVector("DIFFUSE_COLOR",&pcMesh->vDiffuseColor);
  850. pcMesh->piEffect->SetVector("SPECULAR_COLOR",&pcMesh->vSpecularColor);
  851. pcMesh->piEffect->SetVector("AMBIENT_COLOR",&pcMesh->vAmbientColor);
  852. pcMesh->piEffect->SetVector("EMISSIVE_COLOR",&pcMesh->vEmissiveColor);
  853. if (pcMesh->piDiffuseTexture)
  854. pcMesh->piEffect->SetTexture("DIFFUSE_TEXTURE",pcMesh->piDiffuseTexture);
  855. if (pcMesh->piOpacityTexture)
  856. pcMesh->piEffect->SetTexture("OPACITY_TEXTURE",pcMesh->piOpacityTexture);
  857. if (pcMesh->piSpecularTexture)
  858. pcMesh->piEffect->SetTexture("SPECULAR_TEXTURE",pcMesh->piSpecularTexture);
  859. if (pcMesh->piAmbientTexture)
  860. pcMesh->piEffect->SetTexture("AMBIENT_TEXTURE",pcMesh->piAmbientTexture);
  861. if (pcMesh->piEmissiveTexture)
  862. pcMesh->piEffect->SetTexture("EMISSIVE_TEXTURE",pcMesh->piEmissiveTexture);
  863. if (pcMesh->piNormalTexture)
  864. pcMesh->piEffect->SetTexture("NORMAL_TEXTURE",pcMesh->piNormalTexture);
  865. if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
  866. {
  867. pcMesh->piEffect->SetTexture("lw_tex_envmap",CBackgroundPainter::Instance().GetTexture());
  868. }
  869. return 1;
  870. }
  871. };