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