1 //-----------------------------------------------------------------------------
2 // File: XBUtil.cpp
3 //
4 // Desc: Shortcut macros and helper functions for the XBox samples
5 //
6 // Hist: 11.01.00 - New for November XDK release
7 //       12.01.00 - Moved input code to XBInput.cpp
8 //       12.15.00 - Changes for December XDK release
9 //       02.19.00 - Changes for March XDK release
10 //
11 // Copyright (c) Microsoft Corporation. All rights reserved.
12 //-----------------------------------------------------------------------------
13 #include <xtl.h>
14 #include <xgraphics.h>
15 #include <tchar.h>
16 #include <cstdio>
17 #include <cassert>
18 #include "XBUtil.h"
19 
20 
21 
22 //-----------------------------------------------------------------------------
23 // Path to the XBox media files on the target machine
24 //-----------------------------------------------------------------------------
25 CHAR g_strMediaPath[512] = "D:\\Media\\";
26 
27 
28 
29 
30 //-----------------------------------------------------------------------------
31 // Name: XBUtil_SetMediaPath()
32 // Desc: Sets the path to media files
33 //-----------------------------------------------------------------------------
XBUtil_SetMediaPath(const CHAR * strPath)34 VOID XBUtil_SetMediaPath( const CHAR* strPath )
35 {
36     strcpy( g_strMediaPath, strPath );
37 }
38 
39 
40 
41 
42 //-----------------------------------------------------------------------------
43 // Name: XBUtil_FindMediaFile()
44 // Desc: Returns a valid path to a media file.
45 //-----------------------------------------------------------------------------
XBUtil_FindMediaFile(CHAR * strPath,const CHAR * strFilename)46 HRESULT XBUtil_FindMediaFile( CHAR* strPath, const CHAR* strFilename )
47 {
48     // Check for valid arguments
49     if( NULL==strFilename || NULL==strPath )
50     {
51         OUTPUT_DEBUG_STRING( "XBUtil_FindMediaFile(): Invalid arguments\n" );
52         return E_INVALIDARG;
53     }
54 
55     // Default path is the filename itself as a fully qualified path
56     strcpy( strPath, strFilename );
57 
58     // Check for the ':' character to see if the filename is a fully
59     // qualified path. If not, pre-pend the media directory
60     if( strFilename[1] != ':' )
61         sprintf( strPath, "%s%s", g_strMediaPath, strFilename );
62 
63     // Try to open the file
64     HANDLE hFile = CreateFile( strPath, GENERIC_READ, FILE_SHARE_READ, NULL,
65                                OPEN_EXISTING, 0, NULL );
66     if( INVALID_HANDLE_VALUE == hFile )
67     {
68         // Return error
69         CHAR strBuffer[80];
70         sprintf( strBuffer, "XBUtil_FindMediaFile(): Could not find file [%s]\n",
71                             strFilename );
72         OUTPUT_DEBUG_STRING( strBuffer );
73         return 0x82000004;
74     }
75 
76     // Found the file. Close the file and return
77     CloseHandle( hFile );
78 
79     return S_OK;
80 }
81 
82 
83 
84 
85 //-----------------------------------------------------------------------------
86 // Name: XBUtil_Timer()
87 // Desc: Performs timer operations. Use the following commands:
88 //          TIMER_RESET           - to reset the timer
89 //          TIMER_START           - to start the timer
90 //          TIMER_STOP            - to stop (or pause) the timer
91 //          TIMER_ADVANCE         - to advance the timer by 0.1 seconds
92 //          TIMER_GETABSOLUTETIME - to get the absolute system time
93 //          TIMER_GETAPPTIME      - to get the current time
94 //-----------------------------------------------------------------------------
XBUtil_Timer(TIMER_COMMAND command)95 FLOAT XBUtil_Timer( TIMER_COMMAND command )
96 {
97     static BOOL  m_bTimerInitialized = FALSE;
98     static FLOAT m_fSecsPerTick = 0.0f;
99     static FLOAT m_fBaseTime    = 0.0f;
100     static FLOAT m_fStopTime    = 0.0f;
101     FLOAT        fTime;
102 
103     // Initialize the timer
104     if( FALSE == m_bTimerInitialized )
105     {
106         m_bTimerInitialized = TRUE;
107 
108         // Use QueryPerformanceFrequency() to get frequency of timer.
109         LARGE_INTEGER qwTicksPerSec;
110         QueryPerformanceFrequency( &qwTicksPerSec );
111         m_fSecsPerTick = 1.0f / (FLOAT)qwTicksPerSec.QuadPart;
112     }
113 
114     // Get the current time using QueryPerformanceCounter() or timeGetTime()
115     LARGE_INTEGER qwTime;
116     QueryPerformanceCounter( &qwTime );
117     fTime = ((FLOAT)qwTime.QuadPart) * m_fSecsPerTick;
118 
119     // Reset the timer
120     if( command == TIMER_RESET )
121     {
122         m_fBaseTime = fTime;
123         return 0.0f;
124     }
125 
126     // Return the current time
127     if( command == TIMER_GETAPPTIME )
128         return fTime - m_fBaseTime;
129 
130     // Start the timer
131     if( command == TIMER_START )
132         m_fBaseTime += fTime - m_fStopTime;
133 
134     // Stop the timer
135     if( command == TIMER_STOP )
136         m_fStopTime = fTime;
137 
138     // Advance the timer by 1/10th second
139     if( command == TIMER_ADVANCE )
140         m_fBaseTime += fTime - ( m_fStopTime + 0.1f );
141 
142     // Retract the timer by 1/10th second
143     if( command == TIMER_RETRACT )
144         m_fBaseTime += fTime - ( m_fStopTime - 0.1f );
145 
146     return fTime;
147 }
148 
149 
150 
151 
152 //-----------------------------------------------------------------------------
153 // Name: XBUtil_InitMaterial()
154 // Desc: Initializes a D3DMATERIAL8 structure, setting the diffuse and ambient
155 //       colors. It does not set emissive or specular colors.
156 //-----------------------------------------------------------------------------
XBUtil_InitMaterial(D3DMATERIAL8 & mtrl,FLOAT r,FLOAT g,FLOAT b,FLOAT a)157 VOID XBUtil_InitMaterial( D3DMATERIAL8& mtrl, FLOAT r, FLOAT g, FLOAT b,
158                           FLOAT a )
159 {
160     ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );
161     mtrl.Diffuse.r = mtrl.Ambient.r = r;
162     mtrl.Diffuse.g = mtrl.Ambient.g = g;
163     mtrl.Diffuse.b = mtrl.Ambient.b = b;
164     mtrl.Diffuse.a = mtrl.Ambient.a = a;
165 }
166 
167 
168 
169 
170 //-----------------------------------------------------------------------------
171 // Name: XBUtil_InitLight()
172 // Desc: Initializes a D3DLIGHT structure, setting the light position. The
173 //       diffuse color is set to white, specular and ambient left as black.
174 //-----------------------------------------------------------------------------
XBUtil_InitLight(D3DLIGHT8 & light,D3DLIGHTTYPE ltType,FLOAT x,FLOAT y,FLOAT z)175 VOID XBUtil_InitLight( D3DLIGHT8& light, D3DLIGHTTYPE ltType,
176                        FLOAT x, FLOAT y, FLOAT z )
177 {
178     ZeroMemory( &light, sizeof(D3DLIGHT8) );
179     light.Type         = ltType;
180     light.Diffuse.r    = 1.0f;
181     light.Diffuse.g    = 1.0f;
182     light.Diffuse.b    = 1.0f;
183     light.Position     = D3DXVECTOR3(x,y,z);
184 
185     light.Position.x   = x;
186     light.Position.y   = y;
187     light.Position.z   = z;
188     D3DXVECTOR3 vSource(x,y,z);
189     D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vSource );
190     light.Range        = 1000.0f;
191 }
192 
193 
194 
195 
196 //-----------------------------------------------------------------------------
197 // Name: XBUtil_CreateTexture()
198 // Desc: Helper function to create a texture.
199 //-----------------------------------------------------------------------------
XBUtil_CreateTexture(LPDIRECT3DDEVICE8 pd3dDevice,const CHAR * strTexture,LPDIRECT3DTEXTURE8 * ppTexture,D3DFORMAT d3dFormat)200 HRESULT XBUtil_CreateTexture( LPDIRECT3DDEVICE8 pd3dDevice, const CHAR* strTexture,
201                               LPDIRECT3DTEXTURE8* ppTexture, D3DFORMAT d3dFormat )
202 {
203     HRESULT hr;
204 
205     // Find the media file
206     CHAR strTexturePath[512];
207     if( FAILED( hr = XBUtil_FindMediaFile( strTexturePath, strTexture ) ) )
208         return hr;
209 
210     // Create the texture using D3DX. Check the current directory
211     return D3DXCreateTextureFromFileEx( pd3dDevice, strTexturePath,
212                                         D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
213                                         0, d3dFormat, D3DPOOL_DEFAULT,
214                                         D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL,
215                                         ppTexture );
216 }
217 
218 
219 
220 
221 //-----------------------------------------------------------------------------
222 // Name: XBUtil_UnswizzleTexture2D()
223 // Desc: Unswizzles a 2D texture before it gets unlocked. Note: this operation
224 //       can be very slow.
225 //-----------------------------------------------------------------------------
XBUtil_UnswizzleTexture2D(D3DLOCKED_RECT * pLock,const D3DSURFACE_DESC * pDesc)226 VOID XBUtil_UnswizzleTexture2D( D3DLOCKED_RECT* pLock, const D3DSURFACE_DESC* pDesc )
227 {
228     DWORD dwPixelSize   = XGBytesPerPixelFromFormat( pDesc->Format );
229     DWORD dwTextureSize = pDesc->Width * pDesc->Height * dwPixelSize;
230 
231     BYTE* pSrcBits = new BYTE[ dwTextureSize ];
232     memcpy( pSrcBits, pLock->pBits, dwTextureSize );
233 
234     XGUnswizzleRect( pSrcBits, pDesc->Width, pDesc->Height, NULL, pLock->pBits,
235                      0, NULL, dwPixelSize );
236 
237     SAFE_DELETE_ARRAY( pSrcBits );
238 }
239 
240 
241 
242 
243 //-----------------------------------------------------------------------------
244 // Name: XBUtil_UnswizzleTexture3D()
245 // Desc: Unswizzles a 3D texture before it gets unlocked. Note: this operation
246 //       can be very slow.
247 //-----------------------------------------------------------------------------
XBUtil_UnswizzleTexture3D(D3DLOCKED_BOX * pLock,const D3DVOLUME_DESC * pDesc)248 VOID XBUtil_UnswizzleTexture3D( D3DLOCKED_BOX* pLock, const D3DVOLUME_DESC* pDesc )
249 {
250     DWORD dwPixelSize   = XGBytesPerPixelFromFormat( pDesc->Format );
251     DWORD dwTextureSize = pDesc->Width * pDesc->Height * pDesc->Depth * dwPixelSize;
252 
253     BYTE* pSrcBits = new BYTE[ dwTextureSize ];
254     memcpy( pSrcBits, pLock->pBits, dwTextureSize );
255 
256     XGUnswizzleBox( pSrcBits, pDesc->Width, pDesc->Height, pDesc->Depth, NULL, pLock->pBits,
257                     0, 0, NULL, dwPixelSize );
258 
259     SAFE_DELETE_ARRAY( pSrcBits );
260 }
261 
262 
263 
264 
265 //-----------------------------------------------------------------------------
266 // Name: XBUtil_SwizzleTexture2D()
267 // Desc: Swizzles a 2D texture before it gets unlocked. Note: this operation
268 //       can be very slow.
269 //-----------------------------------------------------------------------------
XBUtil_SwizzleTexture2D(D3DLOCKED_RECT * pLock,const D3DSURFACE_DESC * pDesc)270 VOID XBUtil_SwizzleTexture2D( D3DLOCKED_RECT* pLock, const D3DSURFACE_DESC* pDesc )
271 {
272     DWORD dwPixelSize   = XGBytesPerPixelFromFormat( pDesc->Format );
273     DWORD dwTextureSize = pDesc->Width * pDesc->Height * dwPixelSize;
274 
275     BYTE* pSrcBits = new BYTE[ dwTextureSize ];
276     memcpy( pSrcBits, pLock->pBits, dwTextureSize );
277 
278     XGSwizzleRect( pSrcBits, 0, NULL, pLock->pBits,
279                   pDesc->Width, pDesc->Height,
280                   NULL, dwPixelSize );
281 
282     SAFE_DELETE_ARRAY( pSrcBits );
283 }
284 
285 
286 
287 
288 //-----------------------------------------------------------------------------
289 // Name: XBUtil_SwizzleTexture3D()
290 // Desc: Swizzles a 3D texture before it gets unlocked. Note: this operation
291 //       can be very slow.
292 //-----------------------------------------------------------------------------
XBUtil_SwizzleTexture3D(D3DLOCKED_BOX * pLock,const D3DVOLUME_DESC * pDesc)293 VOID XBUtil_SwizzleTexture3D( D3DLOCKED_BOX* pLock, const D3DVOLUME_DESC* pDesc )
294 {
295     DWORD dwPixelSize   = XGBytesPerPixelFromFormat( pDesc->Format );
296     DWORD dwTextureSize = pDesc->Width * pDesc->Height * pDesc->Depth * dwPixelSize;
297 
298     BYTE* pSrcBits = new BYTE[ dwTextureSize ];
299     memcpy( pSrcBits, pLock->pBits, dwTextureSize );
300 
301     XGSwizzleBox( pSrcBits, 0, 0, NULL, pLock->pBits,
302                   pDesc->Width, pDesc->Height, pDesc->Depth,
303                   NULL, dwPixelSize );
304 
305     SAFE_DELETE_ARRAY( pSrcBits );
306 }
307 
308 
309 
310 
311 //-----------------------------------------------------------------------------
312 // Name: XBUtil_CreateVertexShader()
313 // Desc: Creates a file-based vertex shader
314 //-----------------------------------------------------------------------------
XBUtil_CreateVertexShader(LPDIRECT3DDEVICE8 pd3dDevice,const CHAR * strFilename,const DWORD * pdwVertexDecl,DWORD * pdwVertexShader)315 HRESULT XBUtil_CreateVertexShader( LPDIRECT3DDEVICE8 pd3dDevice,
316                                    const CHAR* strFilename,
317                                    const DWORD* pdwVertexDecl,
318                                    DWORD* pdwVertexShader )
319 {
320     HRESULT hr;
321 
322     // Find the media file
323     CHAR strShaderPath[512];
324     if( FAILED( hr = XBUtil_FindMediaFile( strShaderPath, strFilename ) ) )
325         return hr;
326 
327     // Open the vertex shader file
328     HANDLE hFile;
329     DWORD dwNumBytesRead;
330     hFile = CreateFile(strShaderPath, GENERIC_READ, FILE_SHARE_READ, NULL,
331                        OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
332     if(hFile == INVALID_HANDLE_VALUE)
333         return E_FAIL;
334 
335     // Allocate memory to read the vertex shader file
336     DWORD dwSize = GetFileSize(hFile, NULL);
337     BYTE* pData  = new BYTE[dwSize+4];
338     if( NULL == pData )
339         return E_FAIL;
340     ZeroMemory( pData, dwSize+4 );
341 
342     // Read the pre-compiled vertex shader microcode
343     ReadFile(hFile, pData, dwSize, &dwNumBytesRead, 0);
344 
345     // Create the vertex shader
346     hr = pd3dDevice->CreateVertexShader( pdwVertexDecl, (const DWORD*)pData,
347                                          pdwVertexShader, 0 );
348 
349     // Cleanup and return
350     CloseHandle(hFile);
351     delete [] pData;
352     return hr;
353 }
354 
355 
356 
357 
358 //-----------------------------------------------------------------------------
359 // Name: XBUtil_CreatePixelShader()
360 // Desc: Creates a file-based pixel shader
361 //-----------------------------------------------------------------------------
XBUtil_CreatePixelShader(LPDIRECT3DDEVICE8 pd3dDevice,const CHAR * strFilename,DWORD * pdwPixelShader)362 HRESULT XBUtil_CreatePixelShader( LPDIRECT3DDEVICE8 pd3dDevice,
363                                   const CHAR* strFilename, DWORD* pdwPixelShader )
364 {
365     HRESULT hr;
366 
367     // Find the media file
368     CHAR strShaderPath[512];
369     if( FAILED( hr = XBUtil_FindMediaFile( strShaderPath, strFilename ) ) )
370         return hr;
371 
372     // Open the pixel shader file
373     HANDLE hFile;
374     DWORD dwNumBytesRead;
375     hFile = CreateFile(strShaderPath, GENERIC_READ, FILE_SHARE_READ, NULL,
376                        OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
377     if(hFile == INVALID_HANDLE_VALUE)
378         return E_FAIL;
379 
380 
381     // Load the pre-compiled pixel shader microcode
382     D3DPIXELSHADERDEF_FILE psdf;
383 
384     ReadFile( hFile, &psdf, sizeof(D3DPIXELSHADERDEF_FILE), &dwNumBytesRead, NULL );
385 
386     // Make sure the pixel shader is valid
387     if( psdf.FileID != D3DPIXELSHADERDEF_FILE_ID )
388     {
389         OUTPUT_DEBUG_STRING( "XBUtil_CreatePixelShader(): Invalid pixel shader file\n" );
390         return E_FAIL;
391     }
392 
393     // Create the pixel shader
394     if( FAILED( hr = pd3dDevice->CreatePixelShader( &(psdf.Psd), pdwPixelShader ) ) )
395     {
396         OUTPUT_DEBUG_STRING( "XBUtil_CreatePixelShader(): Could not create pixel shader\n" );
397         return hr;
398     }
399 
400     // cleanup
401     CloseHandle( hFile );
402 
403     return S_OK;
404 }
405 
406 
407 
408 
409 //-----------------------------------------------------------------------------
410 // Name: XBUtil_GetCubeMapViewMatrix()
411 // Desc: Returns a view matrix for rendering to a face of a cubemap.
412 //-----------------------------------------------------------------------------
XBUtil_GetCubeMapViewMatrix(DWORD dwFace)413 D3DXMATRIX XBUtil_GetCubeMapViewMatrix( DWORD dwFace )
414 {
415     D3DXVECTOR3 vEyePt   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
416     D3DXVECTOR3 vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
417     D3DXVECTOR3 vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
418 
419     switch( dwFace )
420     {
421         case D3DCUBEMAP_FACE_POSITIVE_X:
422             vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
423             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
424             break;
425         case D3DCUBEMAP_FACE_NEGATIVE_X:
426             vLookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f );
427             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
428             break;
429         case D3DCUBEMAP_FACE_POSITIVE_Y:
430             vLookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
431             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
432             break;
433         case D3DCUBEMAP_FACE_NEGATIVE_Y:
434             vLookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f );
435             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
436             break;
437         case D3DCUBEMAP_FACE_POSITIVE_Z:
438             vLookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
439             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
440             break;
441         case D3DCUBEMAP_FACE_NEGATIVE_Z:
442             vLookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
443             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
444             break;
445     }
446 
447     // Set the view transform for this cubemap surface
448     D3DXMATRIX matView;
449     D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookDir, &vUpDir );
450     return matView;
451 }
452 
453 
454 
455 
456 //-----------------------------------------------------------------------------
457 // Name: XBUtil_CreateNormalizationCubeMap()
458 // Desc: Creates a cubemap and fills it with normalized RGBA vectors
459 //-----------------------------------------------------------------------------
XBUtil_CreateNormalizationCubeMap(LPDIRECT3DDEVICE8 pd3dDevice,DWORD dwSize,LPDIRECT3DCUBETEXTURE8 * ppCubeMap)460 HRESULT XBUtil_CreateNormalizationCubeMap( LPDIRECT3DDEVICE8 pd3dDevice,
461                                            DWORD dwSize,
462                                            LPDIRECT3DCUBETEXTURE8* ppCubeMap )
463 {
464     HRESULT hr;
465 
466     // Create the cube map
467     if( FAILED( hr = pd3dDevice->CreateCubeTexture( dwSize, 1, 0, D3DFMT_X8R8G8B8,
468                                                     D3DPOOL_DEFAULT, ppCubeMap ) ) )
469         return E_FAIL;
470 
471     // Allocate temp space for swizzling the cubemap surfaces
472     DWORD* pSourceBits = new DWORD[ dwSize * dwSize ];
473 
474     // Fill all six sides of the cubemap
475     for( DWORD i=0; i<6; i++ )
476     {
477         // Lock the i'th cubemap surface
478         LPDIRECT3DSURFACE8 pCubeMapFace;
479         (*ppCubeMap)->GetCubeMapSurface( (D3DCUBEMAP_FACES)i, 0, &pCubeMapFace );
480 
481         // Write the RGBA-encoded normals to the surface pixels
482         DWORD*      pPixel = pSourceBits;
483         D3DXVECTOR3 n;
484         FLOAT       w, h;
485 
486         for( DWORD y = 0; y < dwSize; y++ )
487         {
488             h  = (FLOAT)y / (FLOAT)(dwSize-1);  // 0 to 1
489             h  = ( h * 2.0f ) - 1.0f;           // -1 to 1
490 
491             for( DWORD x = 0; x < dwSize; x++ )
492             {
493                 w = (FLOAT)x / (FLOAT)(dwSize-1);   // 0 to 1
494                 w = ( w * 2.0f ) - 1.0f;            // -1 to 1
495 
496                 // Calc the normal for this texel
497                 switch( i )
498                 {
499                     case D3DCUBEMAP_FACE_POSITIVE_X:    // +x
500                         n.x = +1.0;
501                         n.y = -h;
502                         n.z = -w;
503                         break;
504 
505                     case D3DCUBEMAP_FACE_NEGATIVE_X:    // -x
506                         n.x = -1.0;
507                         n.y = -h;
508                         n.z = +w;
509                         break;
510 
511                     case D3DCUBEMAP_FACE_POSITIVE_Y:    // y
512                         n.x = +w;
513                         n.y = +1.0;
514                         n.z = +h;
515                         break;
516 
517                     case D3DCUBEMAP_FACE_NEGATIVE_Y:    // -y
518                         n.x = +w;
519                         n.y = -1.0;
520                         n.z = -h;
521                         break;
522 
523                     case D3DCUBEMAP_FACE_POSITIVE_Z:    // +z
524                         n.x = +w;
525                         n.y = -h;
526                         n.z = +1.0;
527                         break;
528 
529                     case D3DCUBEMAP_FACE_NEGATIVE_Z:    // -z
530                         n.x = -w;
531                         n.y = -h;
532                         n.z = -1.0;
533                         break;
534                 }
535 
536                 // Store the normal as an RGBA color
537                 D3DXVec3Normalize( &n, &n );
538                 *pPixel++ = XBUtil_VectorToRGBA( &n );
539             }
540         }
541 
542         // Swizzle the result into the cubemap face surface
543         D3DLOCKED_RECT lock;
544         pCubeMapFace->LockRect( &lock, 0, 0L );
545         XGSwizzleRect( pSourceBits, 0, NULL, lock.pBits, dwSize, dwSize,
546                        NULL, sizeof(DWORD) );
547         pCubeMapFace->UnlockRect();
548 
549         // Release the cubemap face
550         pCubeMapFace->Release();
551     }
552 
553     // Free temp space
554     SAFE_DELETE_ARRAY( pSourceBits );
555 
556     return S_OK;
557 }
558 
559 
560 
561 
562 //-----------------------------------------------------------------------------
563 // Name: XBUtil_DumpSurface()
564 // Desc: Writes the contents of a surface (32-bit only) to a .tga file. This
565 //       could be a backbuffer, texture, or any other 32-bit surface.
566 //-----------------------------------------------------------------------------
XBUtil_DumpSurface(LPDIRECT3DSURFACE8 pSurface,const CHAR * strFileName,BOOL bSurfaceIsTiled)567 HRESULT XBUtil_DumpSurface( LPDIRECT3DSURFACE8 pSurface, const CHAR* strFileName,
568                             BOOL bSurfaceIsTiled )
569 {
570     // Get the surface description. Make sure it's a 32-bit format
571     D3DSURFACE_DESC desc;
572     pSurface->GetDesc( &desc );
573     if( desc.Size != ( desc.Width * desc.Height * sizeof(DWORD) ) )
574         return E_NOTIMPL;
575 
576     // Lock the surface
577     D3DLOCKED_RECT lock;
578     if( FAILED( pSurface->LockRect( &lock, 0, bSurfaceIsTiled ? D3DLOCK_TILED : 0 ) ) )
579         return E_FAIL;
580 
581     // Allocate memory for storing the surface bits
582     VOID* pBits = (VOID*)new DWORD[desc.Width*desc.Height];
583 
584     // Unswizzle the bits, if necessary
585     if( XGIsSwizzledFormat( desc.Format ) )
586         XGUnswizzleRect( lock.pBits, desc.Width, desc.Height, NULL,
587                          pBits, lock.Pitch, NULL, sizeof(DWORD) );
588     else
589         memcpy( pBits, lock.pBits, desc.Size );
590 
591     // Unlock the surface
592     pSurface->UnlockRect();
593 
594     // Setup the TGA file header
595     struct TargaHeader
596     {
597         BYTE IDLength;
598         BYTE ColormapType;
599         BYTE ImageType;
600         BYTE ColormapSpecification[5];
601         WORD XOrigin;
602         WORD YOrigin;
603         WORD ImageWidth;
604         WORD ImageHeight;
605         BYTE PixelDepth;
606         BYTE ImageDescriptor;
607     } tgaHeader;
608 
609     ZeroMemory( &tgaHeader, sizeof(tgaHeader) );
610     tgaHeader.IDLength        = 0;
611     tgaHeader.ImageType       = 2;
612     tgaHeader.ImageWidth      = (WORD)desc.Width;
613     tgaHeader.ImageHeight     = (WORD)desc.Height;
614     tgaHeader.PixelDepth      = 32;
615     tgaHeader.ImageDescriptor = 0x28;
616 
617     // Create a new file
618     FILE* file = fopen( strFileName, "wb" );
619     if( NULL == file )
620     {
621         pSurface->UnlockRect();
622         return E_FAIL;
623     }
624 
625     // Write the Targa header and the surface pixels to the file
626     fwrite( &tgaHeader, sizeof(TargaHeader), 1, file );
627     fwrite( pBits, sizeof(BYTE), desc.Size, file );
628     fclose( file );
629 
630     // Cleanup and return
631     delete[] pBits;
632 
633     return S_OK;
634 }
635 
636 
637 
638 
639 //-----------------------------------------------------------------------------
640 // Name: XBUtil_EvaluateHermite()
641 // Desc: Evaluate a cubic parametric equation. Returns the point at u on a
642 //       Hermite curve.
643 //-----------------------------------------------------------------------------
XBUtil_EvaluateHermite(const D3DXVECTOR3 & p0,const D3DXVECTOR3 & p1,const D3DXVECTOR3 & v0,const D3DXVECTOR3 & v1,FLOAT u)644 D3DXVECTOR3 XBUtil_EvaluateHermite( const D3DXVECTOR3& p0, const D3DXVECTOR3& p1,
645                                     const D3DXVECTOR3& v0, const D3DXVECTOR3& v1,
646                                     FLOAT u )
647 {
648     // Generate coeffecients from the two end points and two tangents
649     D3DXVECTOR3 a =  2*p0 - 2*p1 +   v0 + v1; // a = 2p0 - 2p1 +  v0 + v1
650     D3DXVECTOR3 b = -3*p0 + 3*p1 - 2*v0 - v1; // b =-3p0 + 3p1 - 2v0 + v1
651     D3DXVECTOR3 c =                  v0;      // c = v0
652     D3DXVECTOR3 d =    p0;                    // d = p0
653 
654     // Evaluate the equation at u, where:
655     //    f(u) = au^3 + bu^2 + cu + d
656     return ( ( a * u + b ) * u + c ) * u + d;
657 }
658 
659 
660 
661 
662 //-----------------------------------------------------------------------------
663 // Name: XBUtil_EvaluateCatmullRom()
664 // Desc: Evaluate a cubic parametric equation. Returns the point at u on a
665 //       Catmull-Rom curve.
666 //-----------------------------------------------------------------------------
XBUtil_EvaluateCatmullRom(const D3DXVECTOR3 & p1,const D3DXVECTOR3 & p2,const D3DXVECTOR3 & p3,const D3DXVECTOR3 & p4,FLOAT u)667 D3DXVECTOR3 XBUtil_EvaluateCatmullRom( const D3DXVECTOR3& p1, const D3DXVECTOR3& p2,
668                                        const D3DXVECTOR3& p3, const D3DXVECTOR3& p4,
669                                        FLOAT u )
670 {
671     // Generate coefficients from four spline points
672     D3DXVECTOR3 a =   -p1 + 3*p2 - 3*p3 + p4;
673     D3DXVECTOR3 b =  2*p1 - 5*p2 + 4*p3 - p4;
674     D3DXVECTOR3 c =   -p1        +   p3;
675     D3DXVECTOR3 d =         2*p2;
676 
677     // Evaluate the equation at u, where:
678     //    f(u) = 0.5 * ( au^3 + bu^2 + cu + d )
679     return 0.5f * ( ( ( a * u + b ) * u + c ) * u + d );
680 }
681 
682 
683 
684 
685 //-----------------------------------------------------------------------------
686 // Name: XBUtil_GetSplinePoint()
687 // Desc: Returns a point on a spline. The spline is defined by an array of
688 //       points, and the point and tangent returned are located at position t
689 //       on the spline, where 0 < t < dwNumSpinePts.
690 //-----------------------------------------------------------------------------
XBUtil_GetSplinePoint(const D3DXVECTOR3 * pSpline,DWORD dwNumSpinePts,FLOAT t,D3DXVECTOR3 * pvPoint,D3DXVECTOR3 * pvTangent)691 VOID XBUtil_GetSplinePoint( const D3DXVECTOR3* pSpline, DWORD dwNumSpinePts,
692                             FLOAT t, D3DXVECTOR3* pvPoint, D3DXVECTOR3* pvTangent )
693 {
694     DWORD p0 = ( t > 1.0 ) ? (DWORD)floorf(t)-1 : dwNumSpinePts-1;
695     DWORD p1 = ( p0 < dwNumSpinePts-1 ) ? p0 + 1 : 0;
696     DWORD p2 = ( p1 < dwNumSpinePts-1 ) ? p1 + 1 : 0;
697     DWORD p3 = ( p2 < dwNumSpinePts-1 ) ? p2 + 1 : 0;
698     FLOAT u  = t - floorf(t);
699 
700     if( pvPoint )
701         (*pvPoint) = XBUtil_EvaluateCatmullRom( pSpline[p0], pSpline[p1],
702                                                 pSpline[p2], pSpline[p3], u );
703 
704     if( pvTangent )
705         (*pvTangent) = 0.5f * ( (1-u) * ( pSpline[p2] - pSpline[p0] ) +
706                                   (u) * ( pSpline[p3] - pSpline[p1] ) );
707 }
708 
709 
710 
711 
712 //-----------------------------------------------------------------------------
713 // Name: XBUtil_RenderSpline()
714 // Desc: For debugging purposes, visually renders a spline.
715 //-----------------------------------------------------------------------------
XBUtil_RenderSpline(LPDIRECT3DDEVICE8 pd3dDevice,const D3DXVECTOR3 * pSpline,DWORD dwNumSplinePts,DWORD dwColor,BOOL bRenderAxes)716 VOID XBUtil_RenderSpline( LPDIRECT3DDEVICE8 pd3dDevice, const D3DXVECTOR3* pSpline,
717                           DWORD dwNumSplinePts, DWORD dwColor, BOOL bRenderAxes )
718 {
719     pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
720     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
721     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TFACTOR );
722     pd3dDevice->SetVertexShader( D3DFVF_XYZ );
723 
724     for( FLOAT u = 0; u < dwNumSplinePts; u += 1.0f )
725     {
726         D3DXVECTOR3 p[2];
727         D3DXVECTOR3 vTangent, vSide, vUp;
728 
729         XBUtil_GetSplinePoint( pSpline, dwNumSplinePts, u+0, &p[0], &vTangent );
730         XBUtil_GetSplinePoint( pSpline, dwNumSplinePts, u+1, &p[1], NULL );
731 
732         D3DXVec3Normalize( &vTangent, &vTangent );
733         D3DXVECTOR3 v1( 0, 1, 0 );
734         D3DXVec3Cross( &vSide, &v1, &vTangent );
735         D3DXVec3Cross( &vUp, &vTangent, &vSide );
736 
737         pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, dwColor );
738         pd3dDevice->DrawPrimitiveUP( D3DPT_LINELIST, 1, p, sizeof(D3DXVECTOR3) );
739 
740         if( bRenderAxes )
741         {
742             p[1] = p[0] + vTangent/4;
743             pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, 0xffff0000 );
744             pd3dDevice->DrawPrimitiveUP( D3DPT_LINELIST, 1, p, sizeof(D3DXVECTOR3) );
745 
746             p[1] = p[0] + vSide/4;
747             pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, 0xff00ff00 );
748             pd3dDevice->DrawPrimitiveUP( D3DPT_LINELIST, 1, p, sizeof(D3DXVECTOR3) );
749 
750             p[1] = p[0] + vUp/4;
751             pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, 0xffffffff );
752             pd3dDevice->DrawPrimitiveUP( D3DPT_LINELIST, 1, p, sizeof(D3DXVECTOR3) );
753         }
754     }
755 }
756 
757 
758 
759 
760 //-----------------------------------------------------------------------------
761 // Name: XBUtil_DeclaratorFromFVF()
762 // Desc: Create a vertex declaration from an FVF. Registers are assigned as
763 //       follows:
764 //          v0     = Vertex position
765 //          v1     = Vertex blend weights
766 //          v2     = Vertex normal
767 //          v3     = Vertex diffuse color
768 //          v4     = Vertex specular color
769 //       // v5     = Vertex fog (no FVF code)
770 //       // v6     = Vertex pointsize (no FVF code)
771 //       // v7     = Vertex back diffuse color (no FVF code)
772 //       // v8     = Vertex back specular color (no FVF code)
773 //          v9-v12 = Vertex texture coords
774 //-----------------------------------------------------------------------------
XBUtil_DeclaratorFromFVF(DWORD dwFVF,DWORD Declaration[MAX_FVF_DECL_SIZE])775 HRESULT XBUtil_DeclaratorFromFVF( DWORD dwFVF,
776                                   DWORD Declaration[MAX_FVF_DECL_SIZE] )
777 {
778     // Start the declaration
779     DWORD decl = 0;
780     Declaration[decl++] = D3DVSD_STREAM(0);
781 
782     // Handle position
783     DWORD dwPositionFVF = ( dwFVF & D3DFVF_POSITION_MASK );
784     if( dwPositionFVF == D3DFVF_XYZRHW ) Declaration[decl++] = D3DVSD_REG( 0, D3DVSDT_FLOAT4 );
785     else                                 Declaration[decl++] = D3DVSD_REG( 0, D3DVSDT_FLOAT3 );
786 
787     // Handle blend weights
788     if( dwPositionFVF == D3DFVF_XYZB1 )  Declaration[decl++] = D3DVSD_REG( 1, D3DVSDT_FLOAT1 );
789     if( dwPositionFVF == D3DFVF_XYZB2 )  Declaration[decl++] = D3DVSD_REG( 1, D3DVSDT_FLOAT2 );
790     if( dwPositionFVF == D3DFVF_XYZB3 )  Declaration[decl++] = D3DVSD_REG( 1, D3DVSDT_FLOAT3 );
791     if( dwPositionFVF == D3DFVF_XYZB4 )  Declaration[decl++] = D3DVSD_REG( 1, D3DVSDT_FLOAT4 );
792 
793     // Handle normal, diffuse, and specular
794     if( dwFVF & D3DFVF_NORMAL )          Declaration[decl++] = D3DVSD_REG( 2, D3DVSDT_FLOAT3 );
795     if( dwFVF & D3DFVF_DIFFUSE )         Declaration[decl++] = D3DVSD_REG( 3, D3DVSDT_D3DCOLOR );
796     if( dwFVF & D3DFVF_SPECULAR )        Declaration[decl++] = D3DVSD_REG( 4, D3DVSDT_D3DCOLOR );
797 
798     // Handle texture coordinates
799     DWORD dwNumTextures = (dwFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
800 
801     for( DWORD i=0; i<dwNumTextures; i++ )
802     {
803         DWORD dwTexCoordSize = ( dwFVF & (0x00030000<<(i*2)) );
804 
805         DWORD dwNumTexCoords = 0;
806         if( dwTexCoordSize == D3DFVF_TEXCOORDSIZE1(i) ) dwNumTexCoords = D3DVSDT_FLOAT1;
807         if( dwTexCoordSize == D3DFVF_TEXCOORDSIZE2(i) ) dwNumTexCoords = D3DVSDT_FLOAT2;
808         if( dwTexCoordSize == D3DFVF_TEXCOORDSIZE3(i) ) dwNumTexCoords = D3DVSDT_FLOAT3;
809         if( dwTexCoordSize == D3DFVF_TEXCOORDSIZE4(i) ) dwNumTexCoords = D3DVSDT_FLOAT4;
810 
811         Declaration[decl++] = D3DVSD_REG( 9 + i, dwNumTexCoords );
812     }
813 
814     // End the declarator
815     Declaration[decl++] = D3DVSD_END();
816 
817     return S_OK;
818 }
819 
820 
821 
822 
823 //-----------------------------------------------------------------------------
824 // Name: XBUtil_GetWide()
825 // Desc: Convert CHAR string to WCHAR string. dwMax includes the null byte.
826 //       Never copies more than dwMax-1 characters into strWide.
827 //          Ex: GetWide( "abc", strWide, 3 ) gives strWide = "ab"
828 //       Typical usage:
829 //          WCHAR strResult[MAX];
830 //          XBUtil_GetWide( strThin, strResult, MAX );
831 //-----------------------------------------------------------------------------
XBUtil_GetWide(const CHAR * strThin,WCHAR * strWide,DWORD dwMax)832 VOID XBUtil_GetWide( const CHAR* strThin, WCHAR* strWide, DWORD dwMax )
833 {
834     assert( strThin != NULL );
835     assert( strWide != NULL );
836 
837     // dwMax includes the null bytes, so must always be at least one.
838     // Furthermore, if dwMax is 0, MultiByteToWideChar doesn't do any
839     // conversion, but returns the number of chars it *would* convert.
840     assert( dwMax > 0 );
841 
842     // Determine how many characters we will convert. Can never be more
843     // than dwMax-1
844     INT nChars = lstrlenA( strThin );
845     if( nChars > INT(dwMax) - 1 )
846         nChars = INT(dwMax) - 1;
847 
848     // Perform the conversion
849     INT iWide = MultiByteToWideChar( CP_ACP, 0, strThin, nChars,
850                                      strWide, dwMax );
851     assert( nChars == iWide - 1 );
852     (VOID)iWide; // avoid compiler warning in release mode
853 }
854