1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2021, assimp team
7 
8 All rights reserved.
9 
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13 
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17 
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22 
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27 
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41 
42 #include "assimp_view.h"
43 #include <assimp/StringUtils.h>
44 
45 namespace AssimpView {
46 
47 extern std::string g_szSkyboxShader;
48 
49 // From: U3D build 1256 (src\kernel\graphic\scenegraph\SkyBox.cpp)
50 // ------------------------------------------------------------------------------
51 /** \brief Vertex structure for the skybox
52 */
53 // ------------------------------------------------------------------------------
54 struct SkyBoxVertex {
55     float x, y, z;
56     float u, v, w;
57 };
58 
59 // ------------------------------------------------------------------------------
60 /** \brief Vertices for the skybox
61 */
62 // ------------------------------------------------------------------------------
63 SkyBoxVertex g_cubeVertices_indexed[] = {
64     { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f }, // 0
65     { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f }, // 1
66     { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f }, // 2
67     { 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f }, // 3
68     { -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }, // 4
69     { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f }, // 5
70     { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }, // 6
71     { 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f } // 7
72 };
73 
74 // ------------------------------------------------------------------------------
75 /** \brief Indices for the skybox
76 */
77 // ------------------------------------------------------------------------------
78 unsigned short g_cubeIndices[] = {
79     0,
80     1,
81     2,
82     3,
83     2,
84     1,
85     4,
86     5,
87     6,
88     7,
89     6,
90     5,
91     4,
92     6,
93     0,
94     1,
95     6,
96     0,
97     5,
98     2,
99     7,
100     3,
101     2,
102     7,
103     1,
104     6,
105     3,
106     7,
107     3,
108     6,
109     0,
110     2,
111     4,
112     5,
113     4,
114     2,
115 };
116 
117 CBackgroundPainter CBackgroundPainter::s_cInstance;
118 
119 //-------------------------------------------------------------------------------
SetColor(D3DCOLOR p_clrNew)120 void CBackgroundPainter::SetColor(D3DCOLOR p_clrNew) {
121     if (TEXTURE_CUBE == eMode) {
122         RemoveSBDeps();
123     }
124 
125     clrColor = p_clrNew;
126     eMode = SIMPLE_COLOR;
127 
128     if (pcTexture) {
129         pcTexture->Release();
130         pcTexture = nullptr;
131     }
132 }
133 //-------------------------------------------------------------------------------
RemoveSBDeps()134 void CBackgroundPainter::RemoveSBDeps() {
135     MODE e = eMode;
136     eMode = SIMPLE_COLOR;
137     if (g_pcAsset && g_pcAsset->pcScene) {
138         for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
139             if (aiShadingMode_Gouraud != g_pcAsset->apcMeshes[i]->eShadingMode) {
140                 CMaterialManager::Instance().DeleteMaterial(g_pcAsset->apcMeshes[i]);
141                 CMaterialManager::Instance().CreateMaterial(
142                         g_pcAsset->apcMeshes[i], g_pcAsset->pcScene->mMeshes[i]);
143             }
144         }
145     }
146     eMode = e;
147 }
148 //-------------------------------------------------------------------------------
ResetSB()149 void CBackgroundPainter::ResetSB() {
150     mMatrix = aiMatrix4x4();
151 }
152 //-------------------------------------------------------------------------------
SetCubeMapBG(const char * p_szPath)153 void CBackgroundPainter::SetCubeMapBG(const char *p_szPath) {
154     bool bHad = false;
155     if (pcTexture) {
156         pcTexture->Release();
157         pcTexture = nullptr;
158         if (TEXTURE_CUBE == eMode) bHad = true;
159     }
160 
161     eMode = TEXTURE_CUBE;
162 
163     szPath = std::string(p_szPath);
164 
165     // ARRRGHH... ugly. TODO: Rewrite this!
166     aiString sz;
167     sz.Set(szPath);
168     CMaterialManager::Instance().FindValidPath(&sz);
169     szPath = std::string(sz.data);
170 
171     // now recreate all native resources
172     RecreateNativeResource();
173 
174     if (SIMPLE_COLOR != this->eMode) {
175         // this influences all material with specular components
176         if (!bHad) {
177             if (g_pcAsset && g_pcAsset->pcScene) {
178                 for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
179                     if (aiShadingMode_Phong == g_pcAsset->apcMeshes[i]->eShadingMode) {
180                         CMaterialManager::Instance().DeleteMaterial(g_pcAsset->apcMeshes[i]);
181                         CMaterialManager::Instance().CreateMaterial(
182                                 g_pcAsset->apcMeshes[i], g_pcAsset->pcScene->mMeshes[i]);
183                     }
184                 }
185             }
186         } else {
187             if (g_pcAsset && g_pcAsset->pcScene) {
188                 for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
189                     if (aiShadingMode_Phong == g_pcAsset->apcMeshes[i]->eShadingMode) {
190                         g_pcAsset->apcMeshes[i]->piEffect->SetTexture(
191                                 "lw_tex_envmap", CBackgroundPainter::Instance().GetTexture());
192                     }
193                 }
194             }
195         }
196     }
197 }
198 //-------------------------------------------------------------------------------
RotateSB(const aiMatrix4x4 * pm)199 void CBackgroundPainter::RotateSB(const aiMatrix4x4 *pm) {
200     this->mMatrix = mMatrix * (*pm);
201 }
202 //-------------------------------------------------------------------------------
SetTextureBG(const char * p_szPath)203 void CBackgroundPainter::SetTextureBG(const char *p_szPath) {
204     if (TEXTURE_CUBE == this->eMode) this->RemoveSBDeps();
205 
206     if (pcTexture) {
207         pcTexture->Release();
208         pcTexture = nullptr;
209     }
210 
211     eMode = TEXTURE_2D;
212     szPath = std::string(p_szPath);
213 
214     // ARRRGHH... ugly. TODO: Rewrite this!
215     aiString sz;
216     sz.Set(szPath);
217     CMaterialManager::Instance().FindValidPath(&sz);
218     szPath = std::string(sz.data);
219 
220     // now recreate all native resources
221     RecreateNativeResource();
222 }
223 //-------------------------------------------------------------------------------
OnPreRender()224 void CBackgroundPainter::OnPreRender() {
225     if (SIMPLE_COLOR != eMode) {
226         // clear the z-buffer only (in wireframe mode we must also clear
227         // the color buffer )
228         if (g_sOptions.eDrawMode == RenderOptions::WIREFRAME) {
229             g_piDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET,
230                     D3DCOLOR_ARGB(0xff, 100, 100, 100), 1.0f, 0);
231         } else {
232             g_piDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
233         }
234 
235         if (TEXTURE_2D == eMode) {
236             RECT sRect;
237             GetWindowRect(GetDlgItem(g_hDlg, IDC_RT), &sRect);
238             sRect.right -= sRect.left;
239             sRect.bottom -= sRect.top;
240 
241             struct SVertex {
242                 float x, y, z, w, u, v;
243             };
244 
245             UINT dw;
246             this->piSkyBoxEffect->Begin(&dw, 0);
247             this->piSkyBoxEffect->BeginPass(0);
248 
249             SVertex as[4];
250             as[1].x = 0.0f;
251             as[1].y = 0.0f;
252             as[1].z = 0.2f;
253             as[1].w = 1.0f;
254             as[1].u = 0.0f;
255             as[1].v = 0.0f;
256 
257             as[3].x = (float)sRect.right;
258             as[3].y = 0.0f;
259             as[3].z = 0.2f;
260             as[3].w = 1.0f;
261             as[3].u = 1.0f;
262             as[3].v = 0.0f;
263 
264             as[0].x = 0.0f;
265             as[0].y = (float)sRect.bottom;
266             as[0].z = 0.2f;
267             as[0].w = 1.0f;
268             as[0].u = 0.0f;
269             as[0].v = 1.0f;
270 
271             as[2].x = (float)sRect.right;
272             as[2].y = (float)sRect.bottom;
273             as[2].z = 0.2f;
274             as[2].w = 1.0f;
275             as[2].u = 1.0f;
276             as[2].v = 1.0f;
277 
278             as[0].x -= 0.5f;
279             as[1].x -= 0.5f;
280             as[2].x -= 0.5f;
281             as[3].x -= 0.5f;
282             as[0].y -= 0.5f;
283             as[1].y -= 0.5f;
284             as[2].y -= 0.5f;
285             as[3].y -= 0.5f;
286 
287             DWORD dw2;
288             g_piDevice->GetFVF(&dw2);
289             g_piDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
290 
291             g_piDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2,
292                     &as, sizeof(SVertex));
293 
294             piSkyBoxEffect->EndPass();
295             piSkyBoxEffect->End();
296 
297             g_piDevice->SetFVF(dw2);
298         }
299         return;
300     }
301     // clear both the render target and the z-buffer
302     g_piDevice->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
303             clrColor, 1.0f, 0);
304 }
305 //-------------------------------------------------------------------------------
OnPostRender()306 void CBackgroundPainter::OnPostRender() {
307     if (TEXTURE_CUBE == eMode) {
308         aiMatrix4x4 pcProj;
309         GetProjectionMatrix(pcProj);
310 
311         aiMatrix4x4 pcCam;
312         aiVector3D vPos = GetCameraMatrix(pcCam);
313 
314         aiMatrix4x4 aiMe;
315         aiMe[3][0] = vPos.x;
316         aiMe[3][1] = vPos.y;
317         aiMe[3][2] = vPos.z;
318         aiMe = mMatrix * aiMe;
319 
320         pcProj = (aiMe * pcCam) * pcProj;
321 
322         piSkyBoxEffect->SetMatrix("WorldViewProjection",
323                 (const D3DXMATRIX *)&pcProj);
324 
325         UINT dwPasses;
326         piSkyBoxEffect->Begin(&dwPasses, 0);
327         piSkyBoxEffect->BeginPass(0);
328 
329         DWORD dw2;
330         g_piDevice->GetFVF(&dw2);
331         g_piDevice->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0));
332 
333         g_piDevice->DrawIndexedPrimitiveUP(
334                 D3DPT_TRIANGLELIST, 0, 8, 12, g_cubeIndices, D3DFMT_INDEX16,
335                 g_cubeVertices_indexed, sizeof(SkyBoxVertex));
336 
337         g_piDevice->SetFVF(dw2);
338 
339         piSkyBoxEffect->EndPass();
340         piSkyBoxEffect->End();
341     }
342 }
343 //-------------------------------------------------------------------------------
ReleaseNativeResource()344 void CBackgroundPainter::ReleaseNativeResource() {
345     if (piSkyBoxEffect) {
346         piSkyBoxEffect->Release();
347         piSkyBoxEffect = nullptr;
348     }
349     if (pcTexture) {
350         pcTexture->Release();
351         pcTexture = nullptr;
352     }
353 }
354 //-------------------------------------------------------------------------------
RecreateNativeResource()355 void CBackgroundPainter::RecreateNativeResource() {
356     if (SIMPLE_COLOR == eMode) {
357         return;
358     }
359 
360     if (TEXTURE_CUBE == eMode) {
361 
362         // many skyboxes are 16bit FP format which isn't supported
363         // with bilinear filtering on older cards
364         D3DFORMAT eFmt = D3DFMT_UNKNOWN;
365         if (FAILED(g_piD3D->CheckDeviceFormat(0, D3DDEVTYPE_HAL,
366                     D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F))) {
367             eFmt = D3DFMT_A8R8G8B8;
368         }
369 
370         if (FAILED(D3DXCreateCubeTextureFromFileEx(
371                     g_piDevice,
372                     szPath.c_str(),
373                     D3DX_DEFAULT,
374                     0,
375                     0,
376                     eFmt,
377                     D3DPOOL_MANAGED,
378                     D3DX_DEFAULT,
379                     D3DX_DEFAULT,
380                     0,
381                     nullptr,
382                     nullptr,
383                     (IDirect3DCubeTexture9 **)&pcTexture))) {
384             const char *szEnd = strrchr(szPath.c_str(), '\\');
385             if (!szEnd) szEnd = strrchr(szPath.c_str(), '/');
386             if (!szEnd) szEnd = szPath.c_str() - 1;
387 
388             char szTemp[1024];
389             ai_snprintf(szTemp, 1024, "[ERROR] Unable to load background cubemap %s", szEnd + 1);
390 
391             CLogDisplay::Instance().AddEntry(szTemp,
392                     D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
393 
394             eMode = SIMPLE_COLOR;
395             return;
396         } else
397             CLogDisplay::Instance().AddEntry("[OK] The skybox has been imported successfully",
398                     D3DCOLOR_ARGB(0xFF, 0, 0xFF, 0));
399     } else {
400         if (FAILED(D3DXCreateTextureFromFileEx(
401                     g_piDevice,
402                     szPath.c_str(),
403                     D3DX_DEFAULT,
404                     D3DX_DEFAULT,
405                     0,
406                     0,
407                     D3DFMT_A8R8G8B8,
408                     D3DPOOL_MANAGED,
409                     D3DX_DEFAULT,
410                     D3DX_DEFAULT,
411                     0,
412                     nullptr,
413                     nullptr,
414                     (IDirect3DTexture9 **)&pcTexture))) {
415             const char *szEnd = strrchr(szPath.c_str(), '\\');
416             if (!szEnd) szEnd = strrchr(szPath.c_str(), '/');
417             if (!szEnd) szEnd = szPath.c_str() - 1;
418 
419             char szTemp[1024];
420             ai_snprintf(szTemp, 1024, "[ERROR] Unable to load background texture %s", szEnd + 1);
421 
422             CLogDisplay::Instance().AddEntry(szTemp,
423                     D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
424 
425             eMode = SIMPLE_COLOR;
426             return;
427         } else
428             CLogDisplay::Instance().AddEntry("[OK] The background texture has been imported successfully",
429                     D3DCOLOR_ARGB(0xFF, 0, 0xFF, 0));
430     }
431     if (!piSkyBoxEffect) {
432         ID3DXBuffer *piBuffer = nullptr;
433         if (FAILED(D3DXCreateEffect(
434                     g_piDevice,
435                     g_szSkyboxShader.c_str(),
436                     (UINT)g_szSkyboxShader.length(),
437                     nullptr,
438                     nullptr,
439                     AI_SHADER_COMPILE_FLAGS,
440                     nullptr,
441                     &piSkyBoxEffect, &piBuffer))) {
442             // failed to compile the shader
443             if (piBuffer) {
444                 MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK);
445                 piBuffer->Release();
446             }
447 
448             CLogDisplay::Instance().AddEntry("[ERROR] Unable to compile skybox shader",
449                     D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
450             eMode = SIMPLE_COLOR;
451             return;
452         }
453     }
454     // commit the correct textures to the shader
455     if (TEXTURE_CUBE == eMode) {
456         piSkyBoxEffect->SetTexture("lw_tex_envmap", pcTexture);
457         piSkyBoxEffect->SetTechnique("RenderSkyBox");
458     } else if (TEXTURE_2D == eMode) {
459         piSkyBoxEffect->SetTexture("TEXTURE_2D", pcTexture);
460         piSkyBoxEffect->SetTechnique("RenderImage2D");
461     }
462 }
463 }; // namespace AssimpView
464