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 
43 #include "assimp_view.h"
44 #include "StringUtils.h"
45 #include <map>
46 
47 using namespace std;
48 
49 namespace AssimpView {
50 
51 extern std::string g_szNormalsShader;
52 extern std::string g_szDefaultShader;
53 extern std::string g_szPassThroughShader;
54 
55 //-------------------------------------------------------------------------------
56 HINSTANCE g_hInstance				= NULL;
57 HWND g_hDlg							= NULL;
58 IDirect3D9* g_piD3D					= NULL;
59 IDirect3DDevice9* g_piDevice		= NULL;
60 IDirect3DVertexDeclaration9* gDefaultVertexDecl = NULL;
61 double g_fFPS						= 0.0f;
62 char g_szFileName[MAX_PATH];
63 ID3DXEffect* g_piDefaultEffect		= NULL;
64 ID3DXEffect* g_piNormalsEffect		= NULL;
65 ID3DXEffect* g_piPassThroughEffect	= NULL;
66 ID3DXEffect* g_piPatternEffect		= NULL;
67 bool g_bMousePressed				= false;
68 bool g_bMousePressedR				= false;
69 bool g_bMousePressedM				= false;
70 bool g_bMousePressedBoth			= false;
71 float g_fElpasedTime				= 0.0f;
72 D3DCAPS9 g_sCaps;
73 bool g_bLoadingFinished				= false;
74 HANDLE g_hThreadHandle				= NULL;
75 float g_fWheelPos					= -10.0f;
76 bool g_bLoadingCanceled				= false;
77 IDirect3DTexture9* g_pcTexture		= NULL;
78 bool g_bPlay						= false;
79 double g_dCurrent = 0.;
80 
81 // default pp steps
82 unsigned int ppsteps = aiProcess_CalcTangentSpace | // calculate tangents and bitangents if possible
83         aiProcess_JoinIdenticalVertices    | // join identical vertices/ optimize indexing
84         aiProcess_ValidateDataStructure    | // perform a full validation of the loader's output
85         aiProcess_ImproveCacheLocality     | // improve the cache locality of the output vertices
86         aiProcess_RemoveRedundantMaterials | // remove redundant materials
87         aiProcess_FindDegenerates          | // remove degenerated polygons from the import
88         aiProcess_FindInvalidData          | // detect invalid model data, such as invalid normal vectors
89         aiProcess_GenUVCoords              | // convert spherical, cylindrical, box and planar mapping to proper UVs
90         aiProcess_TransformUVCoords        | // preprocess UV transformations (scaling, translation ...)
91         aiProcess_FindInstances            | // search for instanced meshes and remove them by references to one master
92         aiProcess_LimitBoneWeights         | // limit bone weights to 4 per vertex
93         aiProcess_OptimizeMeshes		   | // join small meshes, if possible;
94         aiProcess_SplitByBoneCount         | // split meshes with too many bones. Necessary for our (limited) hardware skinning shader
95         0;
96 
97 unsigned int ppstepsdefault = ppsteps;
98 
99 bool nopointslines = false;
100 
101 extern bool g_bWasFlipped			/*= false*/;
102 
103 aiMatrix4x4 g_mWorld;
104 aiMatrix4x4 g_mWorldRotate;
105 aiVector3D g_vRotateSpeed			= aiVector3D(0.5f,0.5f,0.5f);
106 
107 // NOTE: The second light direction is now computed from the first
108 aiVector3D g_avLightDirs[1] =
109 {	aiVector3D(-0.5f,0.6f,0.2f)  };
110 
111 D3DCOLOR g_avLightColors[3] =
112 {
113     D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0xFF),
114     D3DCOLOR_ARGB(0xFF,0xFF,0x00,0x00),
115     D3DCOLOR_ARGB(0xFF,0x05,0x05,0x05),
116 };
117 
118 POINT g_mousePos;
119 POINT g_LastmousePos;
120 bool g_bFPSView						= false;
121 bool g_bInvert						= false;
122 EClickPos g_eClick					= EClickPos_Circle;
123 unsigned int g_iCurrentColor		= 0;
124 
125 float g_fLightIntensity				= 1.0f;
126 float g_fLightColor					= 1.0f;
127 
128 RenderOptions g_sOptions;
129 Camera g_sCamera;
130 AssetHelper *g_pcAsset				= NULL;
131 
132 //
133 // Contains the mask image for the HUD
134 // (used to determine the position of a click)
135 //
136 unsigned char* g_szImageMask		= NULL;
137 
138 float g_fLoadTime = 0.0f;
139 
140 
141 //-------------------------------------------------------------------------------
142 // Entry point for the loader thread
143 // The laoder thread loads the asset while the progress dialog displays the
144 // smart progress bar
145 //-------------------------------------------------------------------------------
LoadThreadProc(LPVOID lpParameter)146 DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
147 {
148     UNREFERENCED_PARAMETER(lpParameter);
149 
150     // get current time
151     double fCur = (double)timeGetTime();
152 
153     aiPropertyStore* props = aiCreatePropertyStore();
154     aiSetImportPropertyInteger(props,AI_CONFIG_IMPORT_TER_MAKE_UVS,1);
155     aiSetImportPropertyFloat(props,AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,g_smoothAngle);
156     aiSetImportPropertyInteger(props,AI_CONFIG_PP_SBP_REMOVE,nopointslines ? aiPrimitiveType_LINE | aiPrimitiveType_POINT : 0 );
157 
158     aiSetImportPropertyInteger(props,AI_CONFIG_GLOB_MEASURE_TIME,1);
159     //aiSetImportPropertyInteger(props,AI_CONFIG_PP_PTV_KEEP_HIERARCHY,1);
160 
161     // Call ASSIMPs C-API to load the file
162     g_pcAsset->pcScene = (aiScene*)aiImportFileExWithProperties(g_szFileName,
163 
164         ppsteps | /* configurable pp steps */
165         aiProcess_GenSmoothNormals		   | // generate smooth normal vectors if not existing
166         aiProcess_SplitLargeMeshes         | // split large, unrenderable meshes into submeshes
167         aiProcess_Triangulate			   | // triangulate polygons with more than 3 edges
168         aiProcess_ConvertToLeftHanded	   | // convert everything to D3D left handed space
169         aiProcess_SortByPType              | // make 'clean' meshes which consist of a single typ of primitives
170         0,
171         NULL,
172         props);
173 
174     aiReleasePropertyStore(props);
175 
176     // get the end time of zje operation, calculate delta t
177     double fEnd = (double)timeGetTime();
178     g_fLoadTime = (float)((fEnd - fCur) / 1000);
179 //	char szTemp[128];
180     g_bLoadingFinished = true;
181 
182     // check whether the loading process has failed ...
183     if (NULL == g_pcAsset->pcScene)
184     {
185         CLogDisplay::Instance().AddEntry("[ERROR] Unable to load this asset:",
186             D3DCOLOR_ARGB(0xFF,0xFF,0,0));
187 
188         // print ASSIMPs error string to the log display
189         CLogDisplay::Instance().AddEntry(aiGetErrorString(),
190             D3DCOLOR_ARGB(0xFF,0xFF,0,0));
191         return 1;
192     }
193 
194     return 0;
195 }
196 
197 //-------------------------------------------------------------------------------
198 // load the current asset
199 // THe path to the asset is specified in the global path variable
200 //-------------------------------------------------------------------------------
LoadAsset(void)201 int LoadAsset(void)
202 {
203     // set the world and world rotation matrices to the identuty
204     g_mWorldRotate = aiMatrix4x4();
205     g_mWorld = aiMatrix4x4();
206 
207 //	char szTemp[MAX_PATH+64];
208 //	sprintf(szTemp,"Starting to load %s",g_szFileName);
209     CLogWindow::Instance().WriteLine(
210         "----------------------------------------------------------------------------");
211 //	CLogWindow::Instance().WriteLine(szTemp);
212 //	CLogWindow::Instance().WriteLine(
213 //		"----------------------------------------------------------------------------");
214     CLogWindow::Instance().SetAutoUpdate(false);
215 
216     // create a helper thread to load the asset
217     DWORD dwID;
218     g_bLoadingCanceled = false;
219     g_pcAsset = new AssetHelper();
220     g_hThreadHandle = CreateThread(NULL,0,&LoadThreadProc,NULL,0,&dwID);
221 
222     if (!g_hThreadHandle)
223     {
224         CLogDisplay::Instance().AddEntry(
225             "[ERROR] Unable to create helper thread for loading",
226             D3DCOLOR_ARGB(0xFF,0xFF,0,0));
227         return 0;
228     }
229 
230     // show the progress bar dialog
231     DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_LOADDIALOG),
232         g_hDlg,&ProgressMessageProc);
233 
234     // update the log window
235     CLogWindow::Instance().SetAutoUpdate(true);
236     CLogWindow::Instance().Update();
237 
238     // now we should have loaded the asset. Check this ...
239     g_bLoadingFinished = false;
240     if (!g_pcAsset || !g_pcAsset->pcScene)
241     {
242         if (g_pcAsset)
243         {
244             delete g_pcAsset;
245             g_pcAsset = NULL;
246         }
247         return 0;
248     }
249 
250     // allocate a new MeshHelper array and build a new instance
251     // for each mesh in the original asset
252     g_pcAsset->apcMeshes = new AssetHelper::MeshHelper*[g_pcAsset->pcScene->mNumMeshes]();
253     for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
254         g_pcAsset->apcMeshes[i] = new AssetHelper::MeshHelper();
255 
256 
257     // create animator
258     g_pcAsset->mAnimator = new SceneAnimator( g_pcAsset->pcScene);
259 
260     // build a new caption string for the viewer
261 	static const size_t Size = MAX_PATH + 10;
262 	char szOut[Size];
263     ai_snprintf(szOut, Size,AI_VIEW_CAPTION_BASE " [%s]",g_szFileName);
264     SetWindowText(g_hDlg,szOut);
265 
266     // scale the asset vertices to fit into the viewer window
267     ScaleAsset();
268 
269     // reset the camera view to the default position
270     g_sCamera.vPos = aiVector3D(0.0f,0.0f,-10.0f);
271     g_sCamera.vLookAt = aiVector3D(0.0f,0.0f,1.0f);
272     g_sCamera.vUp = aiVector3D(0.0f,1.0f,0.0f);
273     g_sCamera.vRight = aiVector3D(0.0f,1.0f,0.0f);
274 
275     // build native D3D vertex/index buffers, textures, materials
276     if( 1 != CreateAssetData())
277         return 0;
278 
279     if (!g_pcAsset->pcScene->HasAnimations()) {
280         EnableWindow(GetDlgItem(g_hDlg,IDC_PLAY),FALSE);
281         EnableWindow(GetDlgItem(g_hDlg,IDC_SLIDERANIM),FALSE);
282     }
283     else {
284         EnableWindow(GetDlgItem(g_hDlg,IDC_PLAY),TRUE);
285         EnableWindow(GetDlgItem(g_hDlg,IDC_SLIDERANIM),TRUE);
286     }
287 
288     CLogDisplay::Instance().AddEntry("[OK] The asset has been loaded successfully");
289     CDisplay::Instance().FillDisplayList();
290     CDisplay::Instance().FillAnimList();
291 
292     CDisplay::Instance().FillDefaultStatistics();
293 
294     // render the scene once
295     CDisplay::Instance().OnRender();
296 
297     g_pcAsset->iNormalSet = AssetHelper::ORIGINAL;
298     g_bWasFlipped = false;
299     return 1;
300 }
301 
302 
303 //-------------------------------------------------------------------------------
304 // Delete the loaded asset
305 // The function does nothing is no asset is loaded
306 //-------------------------------------------------------------------------------
DeleteAsset(void)307 int DeleteAsset(void)
308 {
309     if (!g_pcAsset)return 0;
310 
311     // don't anymore know why this was necessary ...
312     CDisplay::Instance().OnRender();
313 
314     // delete everything
315     DeleteAssetData();
316     for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
317     {
318         delete g_pcAsset->apcMeshes[i];
319     }
320     aiReleaseImport(g_pcAsset->pcScene);
321     delete[] g_pcAsset->apcMeshes;
322     delete g_pcAsset->mAnimator;
323     delete g_pcAsset;
324     g_pcAsset = NULL;
325 
326     // reset the caption of the viewer window
327     SetWindowText(g_hDlg,AI_VIEW_CAPTION_BASE);
328 
329     // clear UI
330     CDisplay::Instance().ClearAnimList();
331     CDisplay::Instance().ClearDisplayList();
332 
333     CMaterialManager::Instance().Reset();
334     UpdateWindow(g_hDlg);
335     return 1;
336 }
337 
338 
339 //-------------------------------------------------------------------------------
340 // Calculate the boundaries of a given node and all of its children
341 // The boundaries are in Worldspace (AABB)
342 // piNode Input node
343 // p_avOut Receives the min/max boundaries. Must point to 2 vec3s
344 // piMatrix Transformation matrix of the graph at this position
345 //-------------------------------------------------------------------------------
CalculateBounds(aiNode * piNode,aiVector3D * p_avOut,const aiMatrix4x4 & piMatrix)346 int CalculateBounds(aiNode* piNode, aiVector3D* p_avOut,
347     const aiMatrix4x4& piMatrix)
348 {
349     ai_assert(NULL != piNode);
350     ai_assert(NULL != p_avOut);
351 
352     aiMatrix4x4 mTemp = piNode->mTransformation;
353     mTemp.Transpose();
354     aiMatrix4x4 aiMe = mTemp * piMatrix;
355 
356     for (unsigned int i = 0; i < piNode->mNumMeshes;++i)
357     {
358         for( unsigned int a = 0; a < g_pcAsset->pcScene->mMeshes[
359             piNode->mMeshes[i]]->mNumVertices;++a)
360         {
361             aiVector3D pc =g_pcAsset->pcScene->mMeshes[piNode->mMeshes[i]]->mVertices[a];
362 
363             aiVector3D pc1;
364             D3DXVec3TransformCoord((D3DXVECTOR3*)&pc1,(D3DXVECTOR3*)&pc,
365                 (D3DXMATRIX*)&aiMe);
366 
367             p_avOut[0].x = min( p_avOut[0].x, pc1.x);
368             p_avOut[0].y = min( p_avOut[0].y, pc1.y);
369             p_avOut[0].z = min( p_avOut[0].z, pc1.z);
370             p_avOut[1].x = max( p_avOut[1].x, pc1.x);
371             p_avOut[1].y = max( p_avOut[1].y, pc1.y);
372             p_avOut[1].z = max( p_avOut[1].z, pc1.z);
373         }
374     }
375     for (unsigned int i = 0; i < piNode->mNumChildren;++i)
376     {
377         CalculateBounds( piNode->mChildren[i], p_avOut, aiMe );
378     }
379     return 1;
380 }
381 //-------------------------------------------------------------------------------
382 // Scale the asset that it fits perfectly into the viewer window
383 // The function calculates the boundaries of the mesh and modifies the
384 // global world transformation matrix according to the aset AABB
385 //-------------------------------------------------------------------------------
ScaleAsset(void)386 int ScaleAsset(void)
387 {
388     aiVector3D aiVecs[2] = {aiVector3D( 1e10f, 1e10f, 1e10f),
389         aiVector3D( -1e10f, -1e10f, -1e10f) };
390 
391     if (g_pcAsset->pcScene->mRootNode)
392     {
393         aiMatrix4x4 m;
394         CalculateBounds(g_pcAsset->pcScene->mRootNode,aiVecs,m);
395     }
396 
397     aiVector3D vDelta = aiVecs[1]-aiVecs[0];
398     aiVector3D vHalf =  aiVecs[0] + (vDelta / 2.0f);
399     float fScale = 10.0f / vDelta.Length();
400 
401     g_mWorld =  aiMatrix4x4(
402         1.0f,0.0f,0.0f,0.0f,
403         0.0f,1.0f,0.0f,0.0f,
404         0.0f,0.0f,1.0f,0.0f,
405         -vHalf.x,-vHalf.y,-vHalf.z,1.0f) *
406         aiMatrix4x4(
407         fScale,0.0f,0.0f,0.0f,
408         0.0f,fScale,0.0f,0.0f,
409         0.0f,0.0f,fScale,0.0f,
410         0.0f,0.0f,0.0f,1.0f);
411     return 1;
412 }
413 
414 //-------------------------------------------------------------------------------
415 // Generate a vertex buffer which holds the normals of the asset as
416 // a list of unconnected lines
417 // pcMesh Input mesh
418 // pcSource Source mesh from ASSIMP
419 //-------------------------------------------------------------------------------
GenerateNormalsAsLineList(AssetHelper::MeshHelper * pcMesh,const aiMesh * pcSource)420 int GenerateNormalsAsLineList(AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSource)
421 {
422     ai_assert(NULL != pcMesh);
423     ai_assert(NULL != pcSource);
424 
425     if (!pcSource->mNormals)return 0;
426 
427     // create vertex buffer
428     if(FAILED( g_piDevice->CreateVertexBuffer(sizeof(AssetHelper::LineVertex) *
429         pcSource->mNumVertices * 2,
430         D3DUSAGE_WRITEONLY,
431         AssetHelper::LineVertex::GetFVF(),
432         D3DPOOL_DEFAULT, &pcMesh->piVBNormals,NULL)))
433     {
434         CLogDisplay::Instance().AddEntry("Failed to create vertex buffer for the normal list",
435             D3DCOLOR_ARGB(0xFF,0xFF,0,0));
436         return 2;
437     }
438 
439     // now fill the vertex buffer with data
440     AssetHelper::LineVertex* pbData2;
441     pcMesh->piVBNormals->Lock(0,0,(void**)&pbData2,0);
442     for (unsigned int x = 0; x < pcSource->mNumVertices;++x)
443     {
444         pbData2->vPosition = pcSource->mVertices[x];
445 
446         ++pbData2;
447 
448         aiVector3D vNormal = pcSource->mNormals[x];
449         vNormal.Normalize();
450 
451         // scalo with the inverse of the world scaling to make sure
452         // the normals have equal length in each case
453         // TODO: Check whether this works in every case, I don't think so
454         vNormal.x /= g_mWorld.a1*4;
455         vNormal.y /= g_mWorld.b2*4;
456         vNormal.z /= g_mWorld.c3*4;
457 
458         pbData2->vPosition = pcSource->mVertices[x] + vNormal;
459 
460         ++pbData2;
461     }
462     pcMesh->piVBNormals->Unlock();
463     return 1;
464 }
465 
466 //-------------------------------------------------------------------------------
467 // Create the native D3D representation of the asset: vertex buffers,
468 // index buffers, materials ...
469 //-------------------------------------------------------------------------------
CreateAssetData()470 int CreateAssetData()
471 {
472     if (!g_pcAsset)return 0;
473 
474     // reset all subsystems
475     CMaterialManager::Instance().Reset();
476     CDisplay::Instance().Reset();
477 
478     for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
479     {
480         const aiMesh* mesh = g_pcAsset->pcScene->mMeshes[i];
481 
482         // create the material for the mesh
483         if (!g_pcAsset->apcMeshes[i]->piEffect)	{
484             CMaterialManager::Instance().CreateMaterial(
485                 g_pcAsset->apcMeshes[i],mesh);
486         }
487 
488         // create vertex buffer
489         if(FAILED( g_piDevice->CreateVertexBuffer(sizeof(AssetHelper::Vertex) *
490             mesh->mNumVertices,
491             D3DUSAGE_WRITEONLY,
492             0,
493             D3DPOOL_DEFAULT, &g_pcAsset->apcMeshes[i]->piVB,NULL)))	{
494             MessageBox(g_hDlg,"Failed to create vertex buffer",
495                 "ASSIMP Viewer Utility",MB_OK);
496             return 2;
497         }
498 
499         DWORD dwUsage = 0;
500         if (g_pcAsset->apcMeshes[i]->piOpacityTexture || 1.0f != g_pcAsset->apcMeshes[i]->fOpacity)
501             dwUsage |= D3DUSAGE_DYNAMIC;
502 
503         unsigned int nidx;
504         switch (mesh->mPrimitiveTypes) {
505             case aiPrimitiveType_POINT:
506                 nidx = 1;break;
507             case aiPrimitiveType_LINE:
508                 nidx = 2;break;
509             case aiPrimitiveType_TRIANGLE:
510                 nidx = 3;break;
511             default: ai_assert(false);
512         };
513 
514         // check whether we can use 16 bit indices
515         if (mesh->mNumFaces * 3 >= 65536)	{
516             // create 32 bit index buffer
517             if(FAILED( g_piDevice->CreateIndexBuffer( 4 *
518                 mesh->mNumFaces * nidx,
519                 D3DUSAGE_WRITEONLY | dwUsage,
520                 D3DFMT_INDEX32,
521                 D3DPOOL_DEFAULT,
522                 &g_pcAsset->apcMeshes[i]->piIB,
523                 NULL)))
524             {
525                 MessageBox(g_hDlg,"Failed to create 32 Bit index buffer",
526                     "ASSIMP Viewer Utility",MB_OK);
527                 return 2;
528             }
529 
530             // now fill the index buffer
531             unsigned int* pbData;
532             g_pcAsset->apcMeshes[i]->piIB->Lock(0,0,(void**)&pbData,0);
533             for (unsigned int x = 0; x < mesh->mNumFaces;++x)
534             {
535                 for (unsigned int a = 0; a < nidx;++a)
536                 {
537                     *pbData++ = mesh->mFaces[x].mIndices[a];
538                 }
539             }
540         }
541         else	{
542             // create 16 bit index buffer
543             if(FAILED( g_piDevice->CreateIndexBuffer( 2 *
544                 mesh->mNumFaces * nidx,
545                 D3DUSAGE_WRITEONLY | dwUsage,
546                 D3DFMT_INDEX16,
547                 D3DPOOL_DEFAULT,
548                 &g_pcAsset->apcMeshes[i]->piIB,
549                 NULL)))
550             {
551                 MessageBox(g_hDlg,"Failed to create 16 Bit index buffer",
552                     "ASSIMP Viewer Utility",MB_OK);
553                 return 2;
554             }
555 
556             // now fill the index buffer
557             uint16_t* pbData;
558             g_pcAsset->apcMeshes[i]->piIB->Lock(0,0,(void**)&pbData,0);
559             for (unsigned int x = 0; x < mesh->mNumFaces;++x)
560             {
561                 for (unsigned int a = 0; a < nidx;++a)
562                 {
563                     *pbData++ = (uint16_t)mesh->mFaces[x].mIndices[a];
564                 }
565             }
566         }
567         g_pcAsset->apcMeshes[i]->piIB->Unlock();
568 
569         // collect weights on all vertices. Quick and careless
570         std::vector<std::vector<aiVertexWeight> > weightsPerVertex( mesh->mNumVertices);
571         for( unsigned int a = 0; a < mesh->mNumBones; a++)	{
572             const aiBone* bone = mesh->mBones[a];
573             for( unsigned int b = 0; b < bone->mNumWeights; b++)
574                 weightsPerVertex[bone->mWeights[b].mVertexId].push_back( aiVertexWeight( a, bone->mWeights[b].mWeight));
575         }
576 
577         // now fill the vertex buffer
578         AssetHelper::Vertex* pbData2;
579         g_pcAsset->apcMeshes[i]->piVB->Lock(0,0,(void**)&pbData2,0);
580         for (unsigned int x = 0; x < mesh->mNumVertices;++x)
581         {
582             pbData2->vPosition = mesh->mVertices[x];
583 
584             if (NULL == mesh->mNormals)
585                 pbData2->vNormal = aiVector3D(0.0f,0.0f,0.0f);
586             else pbData2->vNormal = mesh->mNormals[x];
587 
588             if (NULL == mesh->mTangents)	{
589                 pbData2->vTangent = aiVector3D(0.0f,0.0f,0.0f);
590                 pbData2->vBitangent = aiVector3D(0.0f,0.0f,0.0f);
591             }
592             else	{
593                 pbData2->vTangent = mesh->mTangents[x];
594                 pbData2->vBitangent = mesh->mBitangents[x];
595             }
596 
597             if (mesh->HasVertexColors( 0))	{
598                 pbData2->dColorDiffuse = D3DCOLOR_ARGB(
599                     ((unsigned char)max( min( mesh->mColors[0][x].a * 255.0f, 255.0f),0.0f)),
600                     ((unsigned char)max( min( mesh->mColors[0][x].r * 255.0f, 255.0f),0.0f)),
601                     ((unsigned char)max( min( mesh->mColors[0][x].g * 255.0f, 255.0f),0.0f)),
602                     ((unsigned char)max( min( mesh->mColors[0][x].b * 255.0f, 255.0f),0.0f)));
603             }
604             else pbData2->dColorDiffuse = D3DCOLOR_ARGB(0xFF,0xff,0xff,0xff);
605 
606             // ignore a third texture coordinate component
607             if (mesh->HasTextureCoords( 0))	{
608                 pbData2->vTextureUV = aiVector2D(
609                     mesh->mTextureCoords[0][x].x,
610                     mesh->mTextureCoords[0][x].y);
611             }
612             else pbData2->vTextureUV = aiVector2D(0.5f,0.5f);
613 
614             if (mesh->HasTextureCoords( 1))	{
615                 pbData2->vTextureUV2 = aiVector2D(
616                     mesh->mTextureCoords[1][x].x,
617                     mesh->mTextureCoords[1][x].y);
618             }
619             else pbData2->vTextureUV2 = aiVector2D(0.5f,0.5f);
620 
621             // Bone indices and weights
622             if( mesh->HasBones())	{
623                 unsigned char boneIndices[4] = { 0, 0, 0, 0 };
624                 unsigned char boneWeights[4] = { 0, 0, 0, 0 };
625                 ai_assert( weightsPerVertex[x].size() <= 4);
626                 for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++)
627                 {
628                     boneIndices[a] = weightsPerVertex[x][a].mVertexId;
629                     boneWeights[a] = (unsigned char) (weightsPerVertex[x][a].mWeight * 255.0f);
630                 }
631 
632                 memcpy( pbData2->mBoneIndices, boneIndices, sizeof( boneIndices));
633                 memcpy( pbData2->mBoneWeights, boneWeights, sizeof( boneWeights));
634             } else
635             {
636                 memset( pbData2->mBoneIndices, 0, sizeof( pbData2->mBoneIndices));
637                 memset( pbData2->mBoneWeights, 0, sizeof( pbData2->mBoneWeights));
638             }
639 
640             ++pbData2;
641         }
642         g_pcAsset->apcMeshes[i]->piVB->Unlock();
643 
644         // now generate the second vertex buffer, holding all normals
645         if (!g_pcAsset->apcMeshes[i]->piVBNormals)	{
646             GenerateNormalsAsLineList(g_pcAsset->apcMeshes[i],mesh);
647         }
648     }
649     return 1;
650 }
651 
652 //-------------------------------------------------------------------------------
653 // Delete all effects, textures, vertex buffers ... associated with
654 // an asset
655 //-------------------------------------------------------------------------------
DeleteAssetData(bool bNoMaterials)656 int DeleteAssetData(bool bNoMaterials)
657 {
658     if (!g_pcAsset)return 0;
659 
660     // TODO: Move this to a proper destructor
661     for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
662     {
663         if(g_pcAsset->apcMeshes[i]->piVB)
664         {
665             g_pcAsset->apcMeshes[i]->piVB->Release();
666             g_pcAsset->apcMeshes[i]->piVB = NULL;
667         }
668         if(g_pcAsset->apcMeshes[i]->piVBNormals)
669         {
670             g_pcAsset->apcMeshes[i]->piVBNormals->Release();
671             g_pcAsset->apcMeshes[i]->piVBNormals = NULL;
672         }
673         if(g_pcAsset->apcMeshes[i]->piIB)
674         {
675             g_pcAsset->apcMeshes[i]->piIB->Release();
676             g_pcAsset->apcMeshes[i]->piIB = NULL;
677         }
678 
679         // TODO ... unfixed memory leak
680         // delete storage eventually allocated to hold a copy
681         // of the original vertex normals
682         //if (g_pcAsset->apcMeshes[i]->pvOriginalNormals)
683         //{
684         //	delete[] g_pcAsset->apcMeshes[i]->pvOriginalNormals;
685         //}
686 
687         if (!bNoMaterials)
688         {
689             if(g_pcAsset->apcMeshes[i]->piEffect)
690             {
691                 g_pcAsset->apcMeshes[i]->piEffect->Release();
692                 g_pcAsset->apcMeshes[i]->piEffect = NULL;
693             }
694             if(g_pcAsset->apcMeshes[i]->piDiffuseTexture)
695             {
696                 g_pcAsset->apcMeshes[i]->piDiffuseTexture->Release();
697                 g_pcAsset->apcMeshes[i]->piDiffuseTexture = NULL;
698             }
699             if(g_pcAsset->apcMeshes[i]->piNormalTexture)
700             {
701                 g_pcAsset->apcMeshes[i]->piNormalTexture->Release();
702                 g_pcAsset->apcMeshes[i]->piNormalTexture = NULL;
703             }
704             if(g_pcAsset->apcMeshes[i]->piSpecularTexture)
705             {
706                 g_pcAsset->apcMeshes[i]->piSpecularTexture->Release();
707                 g_pcAsset->apcMeshes[i]->piSpecularTexture = NULL;
708             }
709             if(g_pcAsset->apcMeshes[i]->piAmbientTexture)
710             {
711                 g_pcAsset->apcMeshes[i]->piAmbientTexture->Release();
712                 g_pcAsset->apcMeshes[i]->piAmbientTexture = NULL;
713             }
714             if(g_pcAsset->apcMeshes[i]->piEmissiveTexture)
715             {
716                 g_pcAsset->apcMeshes[i]->piEmissiveTexture->Release();
717                 g_pcAsset->apcMeshes[i]->piEmissiveTexture = NULL;
718             }
719             if(g_pcAsset->apcMeshes[i]->piOpacityTexture)
720             {
721                 g_pcAsset->apcMeshes[i]->piOpacityTexture->Release();
722                 g_pcAsset->apcMeshes[i]->piOpacityTexture = NULL;
723             }
724             if(g_pcAsset->apcMeshes[i]->piShininessTexture)
725             {
726                 g_pcAsset->apcMeshes[i]->piShininessTexture->Release();
727                 g_pcAsset->apcMeshes[i]->piShininessTexture = NULL;
728             }
729         }
730     }
731     return 1;
732 }
733 
734 
735 //-------------------------------------------------------------------------------
736 // Switch beetween zoom/rotate view and the standatd FPS view
737 // g_bFPSView specifies the view mode to setup
738 //-------------------------------------------------------------------------------
SetupFPSView()739 int SetupFPSView()
740 {
741     if (!g_bFPSView)
742     {
743         g_sCamera.vPos = aiVector3D(0.0f,0.0f,g_fWheelPos);
744         g_sCamera.vLookAt = aiVector3D(0.0f,0.0f,1.0f);
745         g_sCamera.vUp = aiVector3D(0.0f,1.0f,0.0f);
746         g_sCamera.vRight = aiVector3D(0.0f,1.0f,0.0f);
747     }
748     else
749     {
750         g_fWheelPos = g_sCamera.vPos.z;
751         g_sCamera.vPos = aiVector3D(0.0f,0.0f,-10.0f);
752         g_sCamera.vLookAt = aiVector3D(0.0f,0.0f,1.0f);
753         g_sCamera.vUp = aiVector3D(0.0f,1.0f,0.0f);
754         g_sCamera.vRight = aiVector3D(0.0f,1.0f,0.0f);
755     }
756     return 1;
757 }
758 
759 //-------------------------------------------------------------------------------
760 // Initialize the IDIrect3D interface
761 // Called by the WinMain
762 //-------------------------------------------------------------------------------
InitD3D(void)763 int InitD3D(void)
764 {
765     if (NULL == g_piD3D)
766     {
767         g_piD3D = Direct3DCreate9(D3D_SDK_VERSION);
768         if (NULL == g_piD3D)return 0;
769     }
770     return 1;
771 }
772 
773 
774 //-------------------------------------------------------------------------------
775 // Release the IDirect3D interface.
776 // NOTE: Assumes that the device has already been deleted
777 //-------------------------------------------------------------------------------
ShutdownD3D(void)778 int ShutdownD3D(void)
779 {
780     ShutdownDevice();
781     if (NULL != g_piD3D)
782     {
783         g_piD3D->Release();
784         g_piD3D = NULL;
785     }
786     return 1;
787 }
788 
789 
790 //-------------------------------------------------------------------------------
791 // Shutdown the D3D devie object and all resources associated with it
792 // NOTE: Assumes that the asset has already been deleted
793 //-------------------------------------------------------------------------------
ShutdownDevice(void)794 int ShutdownDevice(void)
795 {
796     // release other subsystems
797     CBackgroundPainter::Instance().ReleaseNativeResource();
798     CLogDisplay::Instance().ReleaseNativeResource();
799 
800     // release global shaders that have been allocazed
801     if (NULL != g_piDefaultEffect)
802     {
803         g_piDefaultEffect->Release();
804         g_piDefaultEffect = NULL;
805     }
806     if (NULL != g_piNormalsEffect)
807     {
808         g_piNormalsEffect->Release();
809         g_piNormalsEffect = NULL;
810     }
811     if (NULL != g_piPassThroughEffect)
812     {
813         g_piPassThroughEffect->Release();
814         g_piPassThroughEffect = NULL;
815     }
816     if (NULL != g_piPatternEffect)
817     {
818         g_piPatternEffect->Release();
819         g_piPatternEffect = NULL;
820     }
821     if (NULL != g_pcTexture)
822     {
823         g_pcTexture->Release();
824         g_pcTexture = NULL;
825     }
826 
827     if( NULL != gDefaultVertexDecl)
828     {
829         gDefaultVertexDecl->Release();
830         gDefaultVertexDecl = NULL;
831     }
832 
833     // delete the main D3D device object
834     if (NULL != g_piDevice)
835     {
836         g_piDevice->Release();
837         g_piDevice = NULL;
838     }
839 
840     // deleted the one channel image allocated to hold the HUD mask
841     delete[] g_szImageMask;
842     g_szImageMask = NULL;
843 
844     return 1;
845 }
846 
847 
848 //-------------------------------------------------------------------------------
849 //-------------------------------------------------------------------------------
CreateHUDTexture()850 int CreateHUDTexture()
851 {
852     // lock the memory resource ourselves
853     HRSRC res = FindResource(NULL,MAKEINTRESOURCE(IDR_HUD),RT_RCDATA);
854     HGLOBAL hg = LoadResource(NULL,res);
855     void* pData = LockResource(hg);
856 
857     if(FAILED(D3DXCreateTextureFromFileInMemoryEx(g_piDevice,
858         pData,SizeofResource(NULL,res),
859         D3DX_DEFAULT_NONPOW2,
860         D3DX_DEFAULT_NONPOW2,
861         1,
862         0,
863         D3DFMT_A8R8G8B8,
864         D3DPOOL_MANAGED,
865         D3DX_DEFAULT,
866         D3DX_DEFAULT,
867         0,
868         NULL,
869         NULL,
870         &g_pcTexture)))
871     {
872         CLogDisplay::Instance().AddEntry("[ERROR] Unable to load HUD texture",
873             D3DCOLOR_ARGB(0xFF,0xFF,0,0));
874 
875         g_pcTexture  = NULL;
876         g_szImageMask = NULL;
877 
878         FreeResource(hg);
879         return 0;
880     }
881 
882     FreeResource(hg);
883 
884     D3DSURFACE_DESC sDesc;
885     g_pcTexture->GetLevelDesc(0,&sDesc);
886 
887 
888     // lock the memory resource ourselves
889     res = FindResource(NULL,MAKEINTRESOURCE(IDR_HUDMASK),RT_RCDATA);
890     hg = LoadResource(NULL,res);
891     pData = LockResource(hg);
892 
893     IDirect3DTexture9* pcTex;
894     if(FAILED(D3DXCreateTextureFromFileInMemoryEx(g_piDevice,
895         pData,SizeofResource(NULL,res),
896         sDesc.Width,
897         sDesc.Height,
898         1,
899         0,
900         D3DFMT_L8,
901         D3DPOOL_MANAGED, // unnecessary
902         D3DX_DEFAULT,
903         D3DX_DEFAULT,
904         0,
905         NULL,
906         NULL,
907         &pcTex)))
908     {
909         CLogDisplay::Instance().AddEntry("[ERROR] Unable to load HUD mask texture",
910             D3DCOLOR_ARGB(0xFF,0xFF,0,0));
911         g_szImageMask = NULL;
912 
913         FreeResource(hg);
914         return 0;
915     }
916 
917     FreeResource(hg);
918 
919     // lock the texture and copy it to get a pointer
920     D3DLOCKED_RECT sRect;
921     pcTex->LockRect(0,&sRect,NULL,D3DLOCK_READONLY);
922 
923     unsigned char* szOut = new unsigned char[sDesc.Width * sDesc.Height];
924     unsigned char* _szOut = szOut;
925 
926     unsigned char* szCur = (unsigned char*) sRect.pBits;
927     for (unsigned int y = 0; y < sDesc.Height;++y)
928     {
929         memcpy(_szOut,szCur,sDesc.Width);
930 
931         szCur += sRect.Pitch;
932         _szOut += sDesc.Width;
933     }
934     pcTex->UnlockRect(0);
935     pcTex->Release();
936 
937     g_szImageMask = szOut;
938     return 1;
939 }
940 
941 //-------------------------------------------------------------------------------
942 //-------------------------------------------------------------------------------
CreateDevice(bool p_bMultiSample,bool p_bSuperSample,bool bHW)943 int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
944 {
945     D3DDEVTYPE eType = bHW ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF;
946 
947     // get the client rectangle of the window.
948     RECT sRect;
949     GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sRect);
950     sRect.right -= sRect.left;
951     sRect.bottom -= sRect.top;
952 
953     D3DPRESENT_PARAMETERS sParams;
954     memset(&sParams,0,sizeof(D3DPRESENT_PARAMETERS));
955 
956     // get the current display mode
957     D3DDISPLAYMODE sMode;
958     g_piD3D->GetAdapterDisplayMode(0,&sMode);
959 
960     // fill the presentation parameter structure
961     sParams.Windowed				= TRUE;
962     sParams.hDeviceWindow			= GetDlgItem( g_hDlg, IDC_RT );
963     sParams.EnableAutoDepthStencil	= TRUE;
964     sParams.PresentationInterval	= D3DPRESENT_INTERVAL_ONE;
965     sParams.BackBufferWidth			= (UINT)sRect.right;
966     sParams.BackBufferHeight		= (UINT)sRect.bottom;
967     sParams.SwapEffect				= D3DSWAPEFFECT_DISCARD;
968     sParams.BackBufferCount			= 1;
969 
970     // check whether we can use a D32 depth buffer format
971     if (SUCCEEDED ( g_piD3D->CheckDepthStencilMatch(0,eType,
972         D3DFMT_X8R8G8B8,D3DFMT_X8R8G8B8,D3DFMT_D32)))
973     {
974         sParams.AutoDepthStencilFormat = D3DFMT_D32;
975     }
976     else sParams.AutoDepthStencilFormat = D3DFMT_D24X8;
977 
978     // find the highest multisample type available on this device
979     D3DMULTISAMPLE_TYPE sMS = D3DMULTISAMPLE_2_SAMPLES;
980     D3DMULTISAMPLE_TYPE sMSOut = D3DMULTISAMPLE_NONE;
981     DWORD dwQuality = 0;
982     if (p_bMultiSample)
983     {
984         while ((D3DMULTISAMPLE_TYPE)(D3DMULTISAMPLE_16_SAMPLES + 1)  !=
985             (sMS = (D3DMULTISAMPLE_TYPE)(sMS + 1)))
986         {
987             if(SUCCEEDED( g_piD3D->CheckDeviceMultiSampleType(0,eType,
988                 sMode.Format,TRUE,sMS,&dwQuality)))
989             {
990                 sMSOut = sMS;
991             }
992         }
993         if (0 != dwQuality)dwQuality -= 1;
994 
995 
996         sParams.MultiSampleQuality = dwQuality;
997         sParams.MultiSampleType = sMSOut;
998     }
999 
1000     // preget the device capabilities. If the hardware vertex shader is too old, we prefer software vertex processing
1001     g_piD3D->GetDeviceCaps( 0, D3DDEVTYPE_HAL, &g_sCaps);
1002     DWORD creationFlags = D3DCREATE_MULTITHREADED;
1003     if( g_sCaps.VertexShaderVersion >= D3DVS_VERSION( 2, 0))
1004         creationFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
1005     else
1006         creationFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
1007 
1008     // create the D3D9 device object. with software-vertexprocessing if VS2.0 isn`t supported in hardware
1009     if(FAILED(g_piD3D->CreateDevice(0,eType, g_hDlg, creationFlags ,&sParams,&g_piDevice)))
1010     {
1011         // if hardware fails use software rendering instead
1012         if (bHW)return CreateDevice(p_bMultiSample,p_bSuperSample,false);
1013         return 0;
1014     }
1015 
1016     // create a vertex declaration to match the vertex
1017     D3DVERTEXELEMENT9* vdecl = AssetHelper::Vertex::GetDeclarationElements();
1018     if( FAILED( g_piDevice->CreateVertexDeclaration( vdecl, &gDefaultVertexDecl)))
1019     {
1020         MessageBox( g_hDlg, "Failed to create vertex declaration", "Init", MB_OK);
1021         return 0;
1022     }
1023     g_piDevice->SetVertexDeclaration( gDefaultVertexDecl);
1024 
1025     // get the capabilities of the device object
1026     g_piDevice->GetDeviceCaps(&g_sCaps);
1027     if(g_sCaps.PixelShaderVersion < D3DPS_VERSION(3,0))
1028     {
1029         EnableWindow(GetDlgItem(g_hDlg,IDC_LOWQUALITY),FALSE);
1030     }
1031 
1032     // compile the default material shader (gray gouraud/phong)
1033     ID3DXBuffer* piBuffer = NULL;
1034     if(FAILED( D3DXCreateEffect(g_piDevice,
1035         g_szDefaultShader.c_str(),
1036         (UINT)g_szDefaultShader.length(),
1037         NULL,
1038         NULL,
1039         AI_SHADER_COMPILE_FLAGS,
1040         NULL,
1041         &g_piDefaultEffect,&piBuffer)))
1042     {
1043         if( piBuffer)
1044         {
1045             MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK);
1046             piBuffer->Release();
1047         }
1048         return 0;
1049     }
1050     if( piBuffer)
1051     {
1052         piBuffer->Release();
1053         piBuffer = NULL;
1054     }
1055 
1056     // use Fixed Function effect when working with shaderless cards
1057     if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
1058         g_piDefaultEffect->SetTechnique( "DefaultFXSpecular_FF");
1059 
1060     // create the shader used to draw the HUD
1061     if(FAILED( D3DXCreateEffect(g_piDevice,
1062         g_szPassThroughShader.c_str(),(UINT)g_szPassThroughShader.length(),
1063         NULL,NULL,AI_SHADER_COMPILE_FLAGS,NULL,&g_piPassThroughEffect,&piBuffer)))
1064     {
1065         if( piBuffer)
1066         {
1067             MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK);
1068             piBuffer->Release();
1069         }
1070         return 0;
1071     }
1072     if( piBuffer)
1073     {
1074         piBuffer->Release();
1075         piBuffer = NULL;
1076     }
1077 
1078     // use Fixed Function effect when working with shaderless cards
1079     if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
1080         g_piPassThroughEffect->SetTechnique( "PassThrough_FF");
1081 
1082     // create the shader used to visualize normal vectors
1083     if(FAILED( D3DXCreateEffect(g_piDevice,
1084         g_szNormalsShader.c_str(),(UINT)g_szNormalsShader.length(),
1085         NULL,NULL,AI_SHADER_COMPILE_FLAGS,NULL,&g_piNormalsEffect, &piBuffer)))
1086     {
1087         if( piBuffer)
1088         {
1089             MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK);
1090             piBuffer->Release();
1091         }
1092         return 0;
1093     }
1094     if( piBuffer)
1095     {
1096         piBuffer->Release();
1097         piBuffer = NULL;
1098     }
1099 
1100     //MessageBox( g_hDlg, "Failed to create vertex declaration", "Init", MB_OK);
1101 
1102     // use Fixed Function effect when working with shaderless cards
1103     if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
1104         g_piNormalsEffect->SetTechnique( "RenderNormals_FF");
1105 
1106     g_piDevice->SetRenderState(D3DRS_DITHERENABLE,TRUE);
1107 
1108     // create the texture for the HUD
1109     CreateHUDTexture();
1110     CBackgroundPainter::Instance().RecreateNativeResource();
1111     CLogDisplay::Instance().RecreateNativeResource();
1112 
1113     g_piPassThroughEffect->SetTexture("TEXTURE_2D",g_pcTexture);
1114     return 1;
1115 }
1116 
1117 
1118 //-------------------------------------------------------------------------------
1119 //-------------------------------------------------------------------------------
CreateDevice(void)1120 int CreateDevice (void)
1121 {
1122     return CreateDevice(g_sOptions.bMultiSample,
1123         g_sOptions.bSuperSample);
1124 }
1125 
1126 
1127 //-------------------------------------------------------------------------------
1128 //-------------------------------------------------------------------------------
GetProjectionMatrix(aiMatrix4x4 & p_mOut)1129 int GetProjectionMatrix (aiMatrix4x4& p_mOut)
1130 {
1131     const float fFarPlane = 100.0f;
1132     const float fNearPlane = 0.1f;
1133     const float fFOV = (float)(45.0 * 0.0174532925);
1134 
1135     const float s = 1.0f / tanf(fFOV * 0.5f);
1136     const float Q = fFarPlane / (fFarPlane - fNearPlane);
1137 
1138     RECT sRect;
1139     GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sRect);
1140     sRect.right -= sRect.left;
1141     sRect.bottom -= sRect.top;
1142     const float fAspect = (float)sRect.right / (float)sRect.bottom;
1143 
1144     p_mOut = aiMatrix4x4(
1145         s / fAspect, 0.0f, 0.0f, 0.0f,
1146         0.0f, s, 0.0f, 0.0f,
1147         0.0f, 0.0f, Q, 1.0f,
1148         0.0f, 0.0f, -Q * fNearPlane, 0.0f);
1149     return 1;
1150 }
1151 
1152 
1153 //-------------------------------------------------------------------------------
1154 //-------------------------------------------------------------------------------
GetCameraMatrix(aiMatrix4x4 & p_mOut)1155 aiVector3D GetCameraMatrix (aiMatrix4x4& p_mOut)
1156 {
1157     D3DXMATRIX view;
1158     D3DXMatrixIdentity( &view );
1159 
1160     D3DXVec3Normalize( (D3DXVECTOR3*)&g_sCamera.vLookAt, (D3DXVECTOR3*)&g_sCamera.vLookAt );
1161     D3DXVec3Cross( (D3DXVECTOR3*)&g_sCamera.vRight, (D3DXVECTOR3*)&g_sCamera.vUp, (D3DXVECTOR3*)&g_sCamera.vLookAt );
1162     D3DXVec3Normalize( (D3DXVECTOR3*)&g_sCamera.vRight, (D3DXVECTOR3*)&g_sCamera.vRight );
1163     D3DXVec3Cross( (D3DXVECTOR3*)&g_sCamera.vUp, (D3DXVECTOR3*)&g_sCamera.vLookAt, (D3DXVECTOR3*)&g_sCamera.vRight );
1164     D3DXVec3Normalize( (D3DXVECTOR3*)&g_sCamera.vUp, (D3DXVECTOR3*)&g_sCamera.vUp );
1165 
1166     view._11 = g_sCamera.vRight.x;
1167     view._12 = g_sCamera.vUp.x;
1168     view._13 = g_sCamera.vLookAt.x;
1169     view._14 = 0.0f;
1170 
1171     view._21 = g_sCamera.vRight.y;
1172     view._22 = g_sCamera.vUp.y;
1173     view._23 = g_sCamera.vLookAt.y;
1174     view._24 = 0.0f;
1175 
1176     view._31 = g_sCamera.vRight.z;
1177     view._32 = g_sCamera.vUp.z;
1178     view._33 = g_sCamera.vLookAt.z;
1179     view._34 = 0.0f;
1180 
1181     view._41 = -D3DXVec3Dot( (D3DXVECTOR3*)&g_sCamera.vPos, (D3DXVECTOR3*)&g_sCamera.vRight );
1182     view._42 = -D3DXVec3Dot( (D3DXVECTOR3*)&g_sCamera.vPos, (D3DXVECTOR3*)&g_sCamera.vUp );
1183     view._43 = -D3DXVec3Dot( (D3DXVECTOR3*)&g_sCamera.vPos, (D3DXVECTOR3*)&g_sCamera.vLookAt );
1184     view._44 =  1.0f;
1185 
1186     memcpy(&p_mOut,&view,sizeof(aiMatrix4x4));
1187 
1188     return g_sCamera.vPos;
1189 }
1190 
1191 }
1192