1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2015, 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 "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 {
56     float x,y,z;
57     float u,v,w;
58 };
59 
60 
61 // ------------------------------------------------------------------------------
62 /** \brief Vertices for the skybox
63 */
64 // ------------------------------------------------------------------------------
65 SkyBoxVertex g_cubeVertices_indexed[] =
66 {
67     { -1.0f, 1.0f, -1.0f,   -1.0f,1.0f,-1.0f },     // 0
68     { 1.0f, 1.0f,  -1.0f,   1.0f,1.0f,-1.0f },      // 1
69     { -1.0f, -1.0f, -1.0f,  -1.0f,-1.0f,-1.0f },    // 2
70     { 1.0f,-1.0f,-1.0f,      1.0f,-1.0f,-1.0f },    // 3
71     {-1.0f, 1.0f, 1.0f,     -1.0f,1.0f,1.0f },      // 4
72     {-1.0f,-1.0f, 1.0f,     -1.0f,-1.0f,1.0f },     // 5
73     { 1.0f, 1.0f, 1.0f,     1.0f,1.0f,1.0f },       // 6
74     { 1.0f,-1.0f, 1.0f,     1.0f,-1.0f,1.0f }       // 7
75 };
76 
77 
78 // ------------------------------------------------------------------------------
79 /** \brief Indices for the skybox
80 */
81 // ------------------------------------------------------------------------------
82 unsigned short g_cubeIndices[] =
83 {
84     0, 1, 2, 3, 2, 1,4, 5, 6,
85     7, 6, 5, 4, 6,  0, 1, 6, 0,
86     5, 2, 7,3, 2, 7, 1, 6, 3,
87     7, 3, 6, 0, 2, 4, 5, 4, 2,
88 };
89 
90 CBackgroundPainter CBackgroundPainter::s_cInstance;
91 
92 //-------------------------------------------------------------------------------
SetColor(D3DCOLOR p_clrNew)93 void CBackgroundPainter::SetColor (D3DCOLOR p_clrNew)
94 {
95     if (TEXTURE_CUBE == eMode)
96         RemoveSBDeps();
97 
98     clrColor = p_clrNew;
99     eMode = SIMPLE_COLOR;
100 
101     if (pcTexture)
102     {
103         pcTexture->Release();
104         pcTexture = NULL;
105     }
106 }
107 //-------------------------------------------------------------------------------
RemoveSBDeps()108 void CBackgroundPainter::RemoveSBDeps()
109 {
110     MODE e = eMode;
111     eMode = SIMPLE_COLOR;
112     if (g_pcAsset && g_pcAsset->pcScene)
113     {
114         for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
115         {
116             if (aiShadingMode_Gouraud != g_pcAsset->apcMeshes[i]->eShadingMode)
117             {
118                 CMaterialManager::Instance().DeleteMaterial(g_pcAsset->apcMeshes[i]);
119                 CMaterialManager::Instance().CreateMaterial(
120                     g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]);
121             }
122         }
123     }
124     eMode = e;
125 }
126 //-------------------------------------------------------------------------------
ResetSB()127 void CBackgroundPainter::ResetSB()
128 {
129     mMatrix = aiMatrix4x4();
130 }
131 //-------------------------------------------------------------------------------
SetCubeMapBG(const char * p_szPath)132 void CBackgroundPainter::SetCubeMapBG (const char* p_szPath)
133 {
134     bool bHad = false;
135     if (pcTexture)
136     {
137         pcTexture->Release();
138         pcTexture = NULL;
139         if(TEXTURE_CUBE ==eMode)bHad = true;
140     }
141 
142     eMode = TEXTURE_CUBE;
143 
144     szPath = std::string( p_szPath );
145 
146     // ARRRGHH... ugly. TODO: Rewrite this!
147     aiString sz;
148     sz.Set(szPath);
149     CMaterialManager::Instance().FindValidPath(&sz);
150     szPath = std::string( sz.data );
151 
152     // now recreate all native resources
153     RecreateNativeResource();
154 
155     if (SIMPLE_COLOR != this->eMode)
156     {
157         // this influences all material with specular components
158         if (!bHad)
159         {
160             if (g_pcAsset && g_pcAsset->pcScene)
161             {
162                 for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
163                 {
164                     if (aiShadingMode_Phong == g_pcAsset->apcMeshes[i]->eShadingMode)
165                     {
166                         CMaterialManager::Instance().DeleteMaterial(g_pcAsset->apcMeshes[i]);
167                         CMaterialManager::Instance().CreateMaterial(
168                             g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]);
169                     }
170                 }
171             }
172         }
173         else
174         {
175             if (g_pcAsset && g_pcAsset->pcScene)
176             {
177                 for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
178                 {
179                     if (aiShadingMode_Phong == g_pcAsset->apcMeshes[i]->eShadingMode)
180                     {
181                         g_pcAsset->apcMeshes[i]->piEffect->SetTexture(
182                             "lw_tex_envmap",CBackgroundPainter::Instance().GetTexture());
183                     }
184                 }
185             }
186         }
187     }
188 }
189 //-------------------------------------------------------------------------------
RotateSB(const aiMatrix4x4 * pm)190 void CBackgroundPainter::RotateSB(const aiMatrix4x4* pm)
191 {
192     this->mMatrix = mMatrix * (*pm);
193 }
194 //-------------------------------------------------------------------------------
SetTextureBG(const char * p_szPath)195 void CBackgroundPainter::SetTextureBG (const char* p_szPath)
196 {
197     if (TEXTURE_CUBE == this->eMode)this->RemoveSBDeps();
198 
199     if (pcTexture)
200     {
201         pcTexture->Release();
202         pcTexture = NULL;
203     }
204 
205     eMode = TEXTURE_2D;
206     szPath = std::string( p_szPath );
207 
208     // ARRRGHH... ugly. TODO: Rewrite this!
209     aiString sz;
210     sz.Set(szPath);
211     CMaterialManager::Instance().FindValidPath(&sz);
212     szPath = std::string( sz.data );
213 
214     // now recreate all native resources
215     RecreateNativeResource();
216 }
217 //-------------------------------------------------------------------------------
OnPreRender()218 void CBackgroundPainter::OnPreRender()
219 {
220     if (SIMPLE_COLOR != eMode)
221     {
222         // clear the z-buffer only (in wireframe mode we must also clear
223         // the color buffer )
224         if (g_sOptions.eDrawMode == RenderOptions::WIREFRAME)
225         {
226             g_piDevice->Clear(0,NULL,D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET,
227                 D3DCOLOR_ARGB(0xff,100,100,100),1.0f,0);
228         }
229         else
230         {
231             g_piDevice->Clear(0,NULL,D3DCLEAR_ZBUFFER,0,1.0f,0);
232         }
233 
234         if (TEXTURE_2D == eMode)
235         {
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             {
243                 float x,y,z,w,u,v;
244             };
245 
246             UINT dw;
247             this->piSkyBoxEffect->Begin(&dw,0);
248             this->piSkyBoxEffect->BeginPass(0);
249 
250             SVertex as[4];
251             as[1].x = 0.0f;
252             as[1].y = 0.0f;
253             as[1].z = 0.2f;
254             as[1].w = 1.0f;
255             as[1].u = 0.0f;
256             as[1].v = 0.0f;
257 
258             as[3].x = (float)sRect.right;
259             as[3].y = 0.0f;
260             as[3].z = 0.2f;
261             as[3].w = 1.0f;
262             as[3].u = 1.0f;
263             as[3].v = 0.0f;
264 
265             as[0].x = 0.0f;
266             as[0].y = (float)sRect.bottom;
267             as[0].z = 0.2f;
268             as[0].w = 1.0f;
269             as[0].u = 0.0f;
270             as[0].v = 1.0f;
271 
272             as[2].x = (float)sRect.right;
273             as[2].y = (float)sRect.bottom;
274             as[2].z = 0.2f;
275             as[2].w = 1.0f;
276             as[2].u = 1.0f;
277             as[2].v = 1.0f;
278 
279             as[0].x -= 0.5f;as[1].x -= 0.5f;as[2].x -= 0.5f;as[3].x -= 0.5f;
280             as[0].y -= 0.5f;as[1].y -= 0.5f;as[2].y -= 0.5f;as[3].y -= 0.5f;
281 
282             DWORD dw2;g_piDevice->GetFVF(&dw2);
283             g_piDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
284 
285             g_piDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,
286                 &as,sizeof(SVertex));
287 
288             piSkyBoxEffect->EndPass();
289             piSkyBoxEffect->End();
290 
291             g_piDevice->SetFVF(dw2);
292         }
293         return;
294     }
295     // clear both the render target and the z-buffer
296     g_piDevice->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
297         clrColor,1.0f,0);
298 }
299 //-------------------------------------------------------------------------------
OnPostRender()300 void CBackgroundPainter::OnPostRender()
301 {
302     if (TEXTURE_CUBE == eMode)
303     {
304         aiMatrix4x4 pcProj;
305         GetProjectionMatrix(pcProj);
306 
307         aiMatrix4x4 pcCam;
308         aiVector3D vPos = GetCameraMatrix(pcCam);
309 
310         aiMatrix4x4 aiMe;
311         aiMe[3][0] = vPos.x;
312         aiMe[3][1] = vPos.y;
313         aiMe[3][2] = vPos.z;
314         aiMe = mMatrix * aiMe;
315 
316         pcProj = (aiMe * pcCam) * pcProj;
317 
318         piSkyBoxEffect->SetMatrix("WorldViewProjection",
319             (const D3DXMATRIX*)&pcProj);
320 
321         UINT dwPasses;
322         piSkyBoxEffect->Begin(&dwPasses,0);
323         piSkyBoxEffect->BeginPass(0);
324 
325         DWORD dw2;
326         g_piDevice->GetFVF(&dw2);
327         g_piDevice->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0));
328 
329         g_piDevice->DrawIndexedPrimitiveUP(
330             D3DPT_TRIANGLELIST,0,8,12,g_cubeIndices,D3DFMT_INDEX16,
331             g_cubeVertices_indexed,sizeof(SkyBoxVertex));
332 
333         g_piDevice->SetFVF(dw2);
334 
335         piSkyBoxEffect->EndPass();
336         piSkyBoxEffect->End();
337     }
338 }
339 //-------------------------------------------------------------------------------
ReleaseNativeResource()340 void CBackgroundPainter::ReleaseNativeResource()
341 {
342     if ( piSkyBoxEffect)
343     {
344         piSkyBoxEffect->Release();
345         piSkyBoxEffect = NULL;
346     }
347     if (pcTexture)
348     {
349         pcTexture->Release();
350         pcTexture = NULL;
351     }
352 }
353 //-------------------------------------------------------------------------------
RecreateNativeResource()354 void CBackgroundPainter::RecreateNativeResource()
355 {
356     if (SIMPLE_COLOR == eMode)return;
357     if (TEXTURE_CUBE == eMode)
358     {
359 
360         // many skyboxes are 16bit FP format which isn't supported
361         // with bilinear filtering on older cards
362         D3DFORMAT eFmt = D3DFMT_UNKNOWN;
363         if(FAILED(g_piD3D->CheckDeviceFormat(0,D3DDEVTYPE_HAL,
364             D3DFMT_X8R8G8B8,D3DUSAGE_QUERY_FILTER,D3DRTYPE_CUBETEXTURE,D3DFMT_A16B16G16R16F)))
365         {
366             eFmt = D3DFMT_A8R8G8B8;
367         }
368 
369         if (FAILED(D3DXCreateCubeTextureFromFileEx(
370             g_piDevice,
371             szPath.c_str(),
372             D3DX_DEFAULT,
373             0,
374             0,
375             eFmt,
376             D3DPOOL_MANAGED,
377             D3DX_DEFAULT,
378             D3DX_DEFAULT,
379             0,
380             NULL,
381             NULL,
382             (IDirect3DCubeTexture9**)&pcTexture)))
383         {
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         }
397         else CLogDisplay::Instance().AddEntry("[OK] The skybox has been imported successfully",
398             D3DCOLOR_ARGB(0xFF,0,0xFF,0));
399     }
400     else
401     {
402         if (FAILED(D3DXCreateTextureFromFileEx(
403             g_piDevice,
404             szPath.c_str(),
405             D3DX_DEFAULT,
406             D3DX_DEFAULT,
407             0,
408             0,
409             D3DFMT_A8R8G8B8,
410             D3DPOOL_MANAGED,
411             D3DX_DEFAULT,
412             D3DX_DEFAULT,
413             0,
414             NULL,
415             NULL,
416             (IDirect3DTexture9**)&pcTexture)))
417         {
418             const char* szEnd = strrchr(szPath.c_str(),'\\');
419             if (!szEnd)szEnd = strrchr(szPath.c_str(),'/');
420             if (!szEnd)szEnd = szPath.c_str()-1;
421 
422             char szTemp[1024];
423 			ai_snprintf(szTemp,1024,"[ERROR] Unable to load background texture %s",szEnd+1);
424 
425             CLogDisplay::Instance().AddEntry(szTemp,
426                 D3DCOLOR_ARGB(0xFF,0xFF,0,0));
427 
428             eMode = SIMPLE_COLOR;
429             return;
430         }
431         else CLogDisplay::Instance().AddEntry("[OK] The background texture has been imported successfully",
432             D3DCOLOR_ARGB(0xFF,0,0xFF,0));
433     }
434     if (!piSkyBoxEffect)
435     {
436         ID3DXBuffer* piBuffer = NULL;
437         if(FAILED( D3DXCreateEffect(
438             g_piDevice,
439             g_szSkyboxShader.c_str(),
440             (UINT)g_szSkyboxShader.length(),
441             NULL,
442             NULL,
443             AI_SHADER_COMPILE_FLAGS,
444             NULL,
445             &piSkyBoxEffect,&piBuffer)))
446         {
447             // failed to compile the shader
448             if( piBuffer) {
449                 MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK);
450                 piBuffer->Release();
451             }
452 
453             CLogDisplay::Instance().AddEntry("[ERROR] Unable to compile skybox shader",
454                 D3DCOLOR_ARGB(0xFF,0xFF,0,0));
455             eMode = SIMPLE_COLOR;
456             return ;
457         }
458     }
459     // commit the correct textures to the shader
460     if (TEXTURE_CUBE == eMode)
461     {
462         piSkyBoxEffect->SetTexture("lw_tex_envmap",pcTexture);
463         piSkyBoxEffect->SetTechnique("RenderSkyBox");
464     }
465     else if (TEXTURE_2D == eMode)
466     {
467         piSkyBoxEffect->SetTexture("TEXTURE_2D",pcTexture);
468         piSkyBoxEffect->SetTechnique("RenderImage2D");
469     }
470 }
471 };