0001: //-----------------------------------------------------------------------------
0002: // File: D3DUtil.cpp
0003: //
0004: // Desc: Shortcut macros and functions for using DX objects
0005: //-----------------------------------------------------------------------------
0006: #define STRICT
0007: #include <tchar.h>
0008: #include <stdio.h>
0009: #include "D3DUtil.h"
0010: #include "DXUtil.h"
0011: #include "D3DX8.h"
0012: 
0013: 
0014: 
0015: 
0016: //-----------------------------------------------------------------------------
0017: // Name: D3DUtil_InitMaterial()
0018: // Desc: Initializes a D3DMATERIAL8 structure, setting the diffuse and ambient
0019: //       colors. It does not set emissive or specular colors.
0020: //-----------------------------------------------------------------------------
0021: VOID D3DUtil_InitMaterial( D3DMATERIAL8& mtrl, FLOAT r, FLOAT g, FLOAT b,
0022:                            FLOAT a )
0023: {
0024:     ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );
0025:     mtrl.Diffuse.r = mtrl.Ambient.r = r;
0026:     mtrl.Diffuse.g = mtrl.Ambient.g = g;
0027:     mtrl.Diffuse.b = mtrl.Ambient.b = b;
0028:     mtrl.Diffuse.a = mtrl.Ambient.a = a;
0029: }
0030: 
0031: 
0032: 
0033: 
0034: //-----------------------------------------------------------------------------
0035: // Name: D3DUtil_InitLight()
0036: // Desc: Initializes a D3DLIGHT structure, setting the light position. The
0037: //       diffuse color is set to white; specular and ambient are left as black.
0038: //-----------------------------------------------------------------------------
0039: VOID D3DUtil_InitLight( D3DLIGHT8& light, D3DLIGHTTYPE ltType,
0040:                         FLOAT x, FLOAT y, FLOAT z )
0041: {
0042:     ZeroMemory( &light, sizeof(D3DLIGHT8) );
0043:     light.Type        = ltType;
0044:     light.Diffuse.r   = 1.0f;
0045:     light.Diffuse.g   = 1.0f;
0046:     light.Diffuse.b   = 1.0f;
0047:     D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &D3DXVECTOR3(x, y, z) );
0048:     light.Position.x   = x;
0049:     light.Position.y   = y;
0050:     light.Position.z   = z;
0051:     light.Range        = 1000.0f;
0052: }
0053: 
0054: 
0055: 
0056: 
0057: //-----------------------------------------------------------------------------
0058: // Name: D3DUtil_CreateTexture()
0059: // Desc: Helper function to create a texture. It checks the root path first,
0060: //       then tries the DXSDK media path (as specified in the system registry).
0061: //-----------------------------------------------------------------------------
0062: HRESULT D3DUtil_CreateTexture( LPDIRECT3DDEVICE8 pd3dDevice, TCHAR* strTexture,
0063:                                LPDIRECT3DTEXTURE8* ppTexture, D3DFORMAT d3dFormat )
0064: {
0065:     // Get the path to the texture
0066:     TCHAR strPath[MAX_PATH];
0067:     DXUtil_FindMediaFile( strPath, strTexture );
0068: 
0069:     // Create the texture using D3DX
0070:     return D3DXCreateTextureFromFileEx( pd3dDevice, strPath, 
0071:                 D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, d3dFormat, 
0072:                 D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 
0073:                 D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 0, NULL, NULL, ppTexture );
0074: }
0075: 
0076: 
0077: 
0078: 
0079: //-----------------------------------------------------------------------------
0080: // Name: D3DUtil_SetColorKey()
0081: // Desc: Changes all texels matching the colorkey to transparent, black.
0082: //-----------------------------------------------------------------------------
0083: HRESULT D3DUtil_SetColorKey( LPDIRECT3DTEXTURE8 pTexture, DWORD dwColorKey )
0084: {
0085:     // Get colorkey's red, green, and blue components
0086:     DWORD r = ((dwColorKey&0x00ff0000)>>16);
0087:     DWORD g = ((dwColorKey&0x0000ff00)>>8);
0088:     DWORD b = ((dwColorKey&0x000000ff)>>0);
0089: 
0090:     // Put the colorkey in the texture's native format
0091:     D3DSURFACE_DESC d3dsd;
0092:     pTexture->GetLevelDesc( 0, &d3dsd );
0093:     if( d3dsd.Format == D3DFMT_A4R4G4B4 )
0094:         dwColorKey = 0xf000 + ((r>>4)<<8) + ((g>>4)<<4) + (b>>4);
0095:     else if( d3dsd.Format == D3DFMT_A1R5G5B5 )
0096:         dwColorKey = 0x8000 + ((r>>3)<<10) + ((g>>3)<<5) + (b>>3);
0097:     else if( d3dsd.Format != D3DFMT_A8R8G8B8 )
0098:         return E_FAIL;
0099: 
0100:     // Lock the texture
0101:     D3DLOCKED_RECT  d3dlr;
0102:     if( FAILED( pTexture->LockRect( 0, &d3dlr, 0, 0 ) ) )
0103:         return E_FAIL;
0104: 
0105:     // Scan through each pixel, looking for the colorkey to replace
0106:     for( DWORD y=0; y<d3dsd.Height; y++ )
0107:     {
0108:         for( DWORD x=0; x<d3dsd.Width; x++ )
0109:         {
0110:             if( d3dsd.Format==D3DFMT_A8R8G8B8 )
0111:             {
0112:                 // Handle 32-bit formats
0113:                 if( ((DWORD*)d3dlr.pBits)[d3dsd.Width*y+x] == dwColorKey )
0114:                     ((DWORD*)d3dlr.pBits)[d3dsd.Width*y+x] = 0x00000000;
0115:             }
0116:             else
0117:             {
0118:                 // Handle 16-bit formats
0119:                 if( ((WORD*)d3dlr.pBits)[d3dsd.Width*y+x] == dwColorKey )
0120:                     ((WORD*)d3dlr.pBits)[d3dsd.Width*y+x] = 0x0000;
0121:             }
0122:         }
0123:     }
0124: 
0125:     // Unlock the texture and return OK.
0126:     pTexture->UnlockRect(0);
0127:     return S_OK;
0128: }
0129: 
0130: 
0131: 
0132: 
0133: //-----------------------------------------------------------------------------
0134: // Name: D3DUtil_CreateVertexShader()
0135: // Desc: Assembles and creates a file-based vertex shader
0136: //-----------------------------------------------------------------------------
0137: HRESULT D3DUtil_CreateVertexShader( LPDIRECT3DDEVICE8 pd3dDevice, 
0138:                                     TCHAR* strFilename, DWORD* pdwVertexDecl,
0139:                                     DWORD* pdwVertexShader )
0140: {
0141:     LPD3DXBUFFER pCode;
0142:     TCHAR        strPath[MAX_PATH];
0143:     HRESULT      hr;
0144: 
0145:     // Get the path to the vertex shader file
0146:     DXUtil_FindMediaFile( strPath, strFilename );
0147: 
0148:     // Assemble the vertex shader file
0149:     if( FAILED( hr = D3DXAssembleShaderFromFile( strPath, 0, NULL, &pCode, NULL ) ) )
0150:         return hr;
0151: 
0152:     // Create the vertex shader
0153:     hr = pd3dDevice->CreateVertexShader( pdwVertexDecl, 
0154:                                          (DWORD*)pCode->GetBufferPointer(),
0155:                                          pdwVertexShader, 0 );
0156:     pCode->Release();
0157:     return hr;
0158: }
0159: 
0160: 
0161: 
0162: 
0163: //-----------------------------------------------------------------------------
0164: // Name: D3DUtil_GetCubeMapViewMatrix()
0165: // Desc: Returns a view matrix for rendering to a face of a cubemap.
0166: //-----------------------------------------------------------------------------
0167: D3DXMATRIX D3DUtil_GetCubeMapViewMatrix( DWORD dwFace )
0168: {
0169:     D3DXVECTOR3 vEyePt   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
0170:     D3DXVECTOR3 vLookDir;
0171:     D3DXVECTOR3 vUpDir;
0172: 
0173:     switch( dwFace )
0174:     {
0175:         case D3DCUBEMAP_FACE_POSITIVE_X:
0176:             vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
0177:             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
0178:             break;
0179:         case D3DCUBEMAP_FACE_NEGATIVE_X:
0180:             vLookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f );
0181:             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
0182:             break;
0183:         case D3DCUBEMAP_FACE_POSITIVE_Y:
0184:             vLookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
0185:             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
0186:             break;
0187:         case D3DCUBEMAP_FACE_NEGATIVE_Y:
0188:             vLookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f );
0189:             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
0190:             break;
0191:         case D3DCUBEMAP_FACE_POSITIVE_Z:
0192:             vLookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
0193:             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
0194:             break;
0195:         case D3DCUBEMAP_FACE_NEGATIVE_Z:
0196:             vLookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
0197:             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
0198:             break;
0199:     }
0200: 
0201:     // Set the view transform for this cubemap surface
0202:     D3DXMATRIX matView;
0203:     D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookDir, &vUpDir );
0204:     return matView;
0205: }
0206: 
0207: 
0208: 
0209: 
0210: //-----------------------------------------------------------------------------
0211: // Name: D3DUtil_GetRotationFromCursor()
0212: // Desc: Returns a quaternion for the rotation implied by the window's cursor
0213: //       position.
0214: //-----------------------------------------------------------------------------
0215: D3DXQUATERNION D3DUtil_GetRotationFromCursor( HWND hWnd,
0216:                                               FLOAT fTrackBallRadius )
0217: {
0218:     POINT pt;
0219:     RECT  rc;
0220:     GetCursorPos( &pt );
0221:     GetClientRect( hWnd, &rc );
0222:     ScreenToClient( hWnd, &pt );
0223:     FLOAT sx = ( ( ( 2.0f * pt.x ) / (rc.right-rc.left) ) - 1 );
0224:     FLOAT sy = ( ( ( 2.0f * pt.y ) / (rc.bottom-rc.top) ) - 1 );
0225:     FLOAT sz;
0226: 
0227:     if( sx == 0.0f && sy == 0.0f )
0228:         return D3DXQUATERNION( 0.0f, 0.0f, 0.0f, 1.0f );
0229: 
0230:     FLOAT d1 = 0.0f;
0231:     FLOAT d2 = sqrtf( sx*sx + sy*sy );
0232: 
0233:     if( d2 < fTrackBallRadius * 0.70710678118654752440 ) // Inside sphere
0234:         sz = sqrtf( fTrackBallRadius*fTrackBallRadius - d2*d2 );
0235:     else                                                 // On hyperbola
0236:         sz = (fTrackBallRadius*fTrackBallRadius) / (2.0f*d2);
0237: 
0238:     // Get two points on trackball's sphere
0239:     D3DXVECTOR3 p1( sx, sy, sz );
0240:     D3DXVECTOR3 p2( 0.0f, 0.0f, fTrackBallRadius );
0241: 
0242:     // Get axis of rotation, which is cross product of p1 and p2
0243:     D3DXVECTOR3 vAxis;
0244:     D3DXVec3Cross( &vAxis, &p1, &p2);
0245: 
0246:     // Calculate angle for the rotation about that axis
0247:     FLOAT t = D3DXVec3Length( &(p2-p1) ) / ( 2.0f*fTrackBallRadius );
0248:     if( t > +1.0f) t = +1.0f;
0249:     if( t < -1.0f) t = -1.0f;
0250:     FLOAT fAngle = 2.0f * asinf( t );
0251: 
0252:     // Convert axis to quaternion
0253:     D3DXQUATERNION quat;
0254:     D3DXQuaternionRotationAxis( &quat, &vAxis, fAngle );
0255:     return quat;
0256: }
0257: 
0258: 
0259: 
0260: 
0261: //-----------------------------------------------------------------------------
0262: // Name: D3DUtil_SetDeviceCursor
0263: // Desc: Gives the D3D device a cursor with image and hotspot from hCursor.
0264: //-----------------------------------------------------------------------------
0265: HRESULT D3DUtil_SetDeviceCursor( LPDIRECT3DDEVICE8 pd3dDevice, HCURSOR hCursor,
0266:                                  BOOL bAddWatermark )
0267: {
0268:     HRESULT hr = E_FAIL;
0269:     ICONINFO iconinfo;
0270:     BOOL bBWCursor;
0271:     LPDIRECT3DSURFACE8 pCursorBitmap = NULL;
0272:     HDC hdcColor = NULL;
0273:     HDC hdcMask = NULL;
0274:     HDC hdcScreen = NULL;
0275:     BITMAP bm;
0276:     DWORD dwWidth;
0277:     DWORD dwHeightSrc;
0278:     DWORD dwHeightDest;
0279:     COLORREF crColor;
0280:     COLORREF crMask;
0281:     UINT x;
0282:     UINT y;
0283:     BITMAPINFO bmi;
0284:     COLORREF* pcrArrayColor = NULL;
0285:     COLORREF* pcrArrayMask = NULL;
0286:     DWORD* pBitmap;
0287:     HGDIOBJ hgdiobjOld;
0288: 
0289:     ZeroMemory( &iconinfo, sizeof(iconinfo) );
0290:     if( !GetIconInfo( hCursor, &iconinfo ) )
0291:         goto End;
0292: 
0293:     if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm))
0294:         goto End;
0295:     dwWidth = bm.bmWidth;
0296:     dwHeightSrc = bm.bmHeight;
0297: 
0298:     if( iconinfo.hbmColor == NULL )
0299:     {
0300:         bBWCursor = TRUE;
0301:         dwHeightDest = dwHeightSrc / 2;
0302:     }
0303:     else 
0304:     {
0305:         bBWCursor = FALSE;
0306:         dwHeightDest = dwHeightSrc;
0307:     }
0308: 
0309:     // Create a surface for the fullscreen cursor
0310:     if( FAILED( hr = pd3dDevice->CreateImageSurface( dwWidth, dwHeightDest, 
0311:         D3DFMT_A8R8G8B8, &pCursorBitmap ) ) )
0312:     {
0313:         goto End;
0314:     }
0315: 
0316:     pcrArrayMask = new DWORD[dwWidth * dwHeightSrc];
0317: 
0318:     ZeroMemory(&bmi, sizeof(bmi));
0319:     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
0320:     bmi.bmiHeader.biWidth = dwWidth;
0321:     bmi.bmiHeader.biHeight = dwHeightSrc;
0322:     bmi.bmiHeader.biPlanes = 1;
0323:     bmi.bmiHeader.biBitCount = 32;
0324:     bmi.bmiHeader.biCompression = BI_RGB;
0325: 
0326:     hdcScreen = GetDC( NULL );
0327:     hdcMask = CreateCompatibleDC( hdcScreen );
0328:     if( hdcMask == NULL )
0329:     {
0330:         hr = E_FAIL;
0331:         goto End;
0332:     }
0333:     hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask);
0334:     GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc, 
0335:         pcrArrayMask, &bmi, DIB_RGB_COLORS);
0336:     SelectObject(hdcMask, hgdiobjOld);
0337: 
0338:     if (!bBWCursor)
0339:     {
0340:         pcrArrayColor = new DWORD[dwWidth * dwHeightDest];
0341:         hdcColor = CreateCompatibleDC( GetDC( NULL ) );
0342:         if( hdcColor == NULL )
0343:         {
0344:             hr = E_FAIL;
0345:             goto End;
0346:         }
0347:         SelectObject(hdcColor, iconinfo.hbmColor);
0348:         GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest, 
0349:             pcrArrayColor, &bmi, DIB_RGB_COLORS);
0350:     }
0351: 
0352:     // Transfer cursor image into the surface
0353:     D3DLOCKED_RECT lr;
0354:     pCursorBitmap->LockRect( &lr, NULL, 0 );
0355:     pBitmap = (DWORD*)lr.pBits;
0356:     for( y = 0; y < dwHeightDest; y++ )
0357:     {
0358:         for( x = 0; x < dwWidth; x++ )
0359:         {
0360:             if (bBWCursor)
0361:             {
0362:                 crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
0363:                 crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x];
0364:             }
0365:             else
0366:             {
0367:                 crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x];
0368:                 crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
0369:             }
0370:             if (crMask == 0)
0371:                 pBitmap[dwWidth*y + x] = 0xff000000 | crColor;
0372:             else
0373:                 pBitmap[dwWidth*y + x] = 0x00000000;
0374: 
0375:             // It may be helpful to make the D3D cursor look slightly 
0376:             // different from the Windows cursor so you can distinguish 
0377:             // between the two when developing/testing code.  When
0378:             // bAddWatermark is TRUE, the following code adds some
0379:             // small grey "D3D" characters to the upper-left corner of
0380:             // the D3D cursor image.
0381:             if( bAddWatermark && x < 12 && y < 5 )
0382:             {
0383:                 // 11.. 11.. 11.. .... CCC0
0384:                 // 1.1. ..1. 1.1. .... A2A0
0385:                 // 1.1. .1.. 1.1. .... A4A0
0386:                 // 1.1. ..1. 1.1. .... A2A0
0387:                 // 11.. 11.. 11.. .... CCC0
0388: 
0389:                 const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 };
0390:                 if( wMask[y] & (1 << (15 - x)) )
0391:                 {
0392:                     pBitmap[dwWidth*y + x] |= 0xff808080;
0393:                 }
0394:             }
0395:         }
0396:     }
0397:     pCursorBitmap->UnlockRect();
0398: 
0399:     // Set the device cursor
0400:     if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot, 
0401:         iconinfo.yHotspot, pCursorBitmap ) ) )
0402:     {
0403:         goto End;
0404:     }
0405: 
0406:     hr = S_OK;
0407: 
0408: End:
0409:     if( iconinfo.hbmMask != NULL )
0410:         DeleteObject( iconinfo.hbmMask );
0411:     if( iconinfo.hbmColor != NULL )
0412:         DeleteObject( iconinfo.hbmColor );
0413:     if( hdcScreen != NULL )
0414:         ReleaseDC( NULL, hdcScreen );
0415:     if( hdcColor != NULL )
0416:         DeleteDC( hdcColor );
0417:     if( hdcMask != NULL )
0418:         DeleteDC( hdcMask );
0419:     SAFE_DELETE_ARRAY( pcrArrayColor );
0420:     SAFE_DELETE_ARRAY( pcrArrayMask );
0421:     SAFE_RELEASE( pCursorBitmap );
0422:     return hr;
0423: }
0424: 
0425: 
0426: 
0427: 
0428: //-----------------------------------------------------------------------------
0429: // Name: D3DXQuaternionUnitAxisToUnitAxis2
0430: // Desc: Axis to axis quaternion double angle (no normalization)
0431: //       Takes two points on unit sphere an angle THETA apart, returns
0432: //       quaternion that represents a rotation around cross product by 2*THETA.
0433: //-----------------------------------------------------------------------------
0434: inline D3DXQUATERNION* WINAPI D3DXQuaternionUnitAxisToUnitAxis2
0435: ( D3DXQUATERNION *pOut, const D3DXVECTOR3 *pvFrom, const D3DXVECTOR3 *pvTo)
0436: {
0437:     D3DXVECTOR3 vAxis;
0438:     D3DXVec3Cross(&vAxis, pvFrom, pvTo);    // proportional to sin(theta)
0439:     pOut->x = vAxis.x;
0440:     pOut->y = vAxis.y;
0441:     pOut->z = vAxis.z;
0442:     pOut->w = D3DXVec3Dot( pvFrom, pvTo );
0443:     return pOut;
0444: }
0445: 
0446: 
0447: 
0448: 
0449: //-----------------------------------------------------------------------------
0450: // Name: D3DXQuaternionAxisToAxis
0451: // Desc: Axis to axis quaternion 
0452: //       Takes two points on unit sphere an angle THETA apart, returns
0453: //       quaternion that represents a rotation around cross product by theta.
0454: //-----------------------------------------------------------------------------
0455: inline D3DXQUATERNION* WINAPI D3DXQuaternionAxisToAxis
0456: ( D3DXQUATERNION *pOut, const D3DXVECTOR3 *pvFrom, const D3DXVECTOR3 *pvTo)
0457: {
0458:     D3DXVECTOR3 vA, vB;
0459:     D3DXVec3Normalize(&vA, pvFrom);
0460:     D3DXVec3Normalize(&vB, pvTo);
0461:     D3DXVECTOR3 vHalf(vA + vB);
0462:     D3DXVec3Normalize(&vHalf, &vHalf);
0463:     return D3DXQuaternionUnitAxisToUnitAxis2(pOut, &vA, &vHalf);
0464: }
0465: 
0466: 
0467: 
0468: 
0469: //-----------------------------------------------------------------------------
0470: // Name:
0471: // Desc:
0472: //-----------------------------------------------------------------------------
0473: CD3DArcBall::CD3DArcBall()
0474: {
0475:     D3DXQuaternionIdentity( &m_qDown );
0476:     D3DXQuaternionIdentity( &m_qNow );
0477:     D3DXMatrixIdentity( &m_matRotation );
0478:     D3DXMatrixIdentity( &m_matRotationDelta );
0479:     D3DXMatrixIdentity( &m_matTranslation );
0480:     D3DXMatrixIdentity( &m_matTranslationDelta );
0481:     m_bDrag = FALSE;
0482:     m_fRadiusTranslation = 1.0f;
0483:     m_bRightHanded = FALSE;
0484: }
0485: 
0486: 
0487: 
0488: 
0489: //-----------------------------------------------------------------------------
0490: // Name:
0491: // Desc:
0492: //-----------------------------------------------------------------------------
0493: VOID CD3DArcBall::SetWindow( int iWidth, int iHeight, float fRadius )
0494: {
0495:     // Set ArcBall info
0496:     m_iWidth  = iWidth;
0497:     m_iHeight = iHeight;
0498:     m_fRadius = fRadius;
0499: }
0500: 
0501: 
0502: 
0503: 
0504: //-----------------------------------------------------------------------------
0505: // Name:
0506: // Desc:
0507: //-----------------------------------------------------------------------------
0508: D3DXVECTOR3 CD3DArcBall::ScreenToVector( int sx, int sy )
0509: {
0510:     // Scale to screen
0511:     FLOAT x   = -(sx - m_iWidth/2)  / (m_fRadius*m_iWidth/2);
0512:     FLOAT y   =  (sy - m_iHeight/2) / (m_fRadius*m_iHeight/2);
0513: 
0514:     if( m_bRightHanded )
0515:     {
0516:         x = -x;
0517:         y = -y;
0518:     }
0519: 
0520:     FLOAT z   = 0.0f;
0521:     FLOAT mag = x*x + y*y;
0522: 
0523:     if( mag > 1.0f )
0524:     {
0525:         FLOAT scale = 1.0f/sqrtf(mag);
0526:         x *= scale;
0527:         y *= scale;
0528:     }
0529:     else
0530:         z = sqrtf( 1.0f - mag );
0531: 
0532:     // Return vector
0533:     return D3DXVECTOR3( x, y, z );
0534: }
0535: 
0536: 
0537: 
0538: 
0539: //-----------------------------------------------------------------------------
0540: // Name:
0541: // Desc:
0542: //-----------------------------------------------------------------------------
0543: VOID CD3DArcBall::SetRadius( FLOAT fRadius )
0544: {
0545:     m_fRadiusTranslation = fRadius;
0546: }
0547: 
0548: 
0549: 
0550: 
0551: //-----------------------------------------------------------------------------
0552: // Name:
0553: // Desc:
0554: //-----------------------------------------------------------------------------
0555: LRESULT CD3DArcBall::HandleMouseMessages( HWND hWnd, UINT uMsg, WPARAM wParam,
0556:                                           LPARAM lParam )
0557: {
0558:     static int         iCurMouseX;      // Saved mouse position
0559:     static int         iCurMouseY;
0560:     static D3DXVECTOR3 s_vDown;         // Button down vector
0561: 
0562:     // Current mouse position
0563:     int iMouseX = LOWORD(lParam);
0564:     int iMouseY = HIWORD(lParam);
0565: 
0566:     switch( uMsg )
0567:     {
0568:         case WM_RBUTTONDOWN:
0569:         case WM_MBUTTONDOWN:
0570:             // Store off the position of the cursor when the button is pressed
0571:             iCurMouseX = iMouseX;
0572:             iCurMouseY = iMouseY;
0573:             return TRUE;
0574: 
0575:         case WM_LBUTTONDOWN:
0576:             // Start drag mode
0577:             m_bDrag = TRUE;
0578:             s_vDown = ScreenToVector( iMouseX, iMouseY );
0579:             m_qDown = m_qNow;
0580:             return TRUE;
0581: 
0582:         case WM_LBUTTONUP:
0583:             // End drag mode
0584:             m_bDrag = FALSE;
0585:             return TRUE;
0586: 
0587:         case WM_MOUSEMOVE:
0588:             // Drag object
0589:             if( MK_LBUTTON&wParam )
0590:             {
0591:                 if( m_bDrag )
0592:                 {
0593:                     // recompute m_qNow
0594:                     D3DXVECTOR3 vCur = ScreenToVector( iMouseX, iMouseY );
0595:                     D3DXQUATERNION qAxisToAxis;
0596:                     D3DXQuaternionAxisToAxis(&qAxisToAxis, &s_vDown, &vCur);
0597:                     m_qNow = m_qDown;
0598:                     m_qNow *= qAxisToAxis;
0599:                     D3DXMatrixRotationQuaternion(&m_matRotationDelta, &qAxisToAxis);
0600:                 }
0601:                 else
0602:                     D3DXMatrixIdentity(&m_matRotationDelta);
0603:                 D3DXMatrixRotationQuaternion(&m_matRotation, &m_qNow);
0604:                 m_bDrag = TRUE;
0605:             }
0606:             else if( (MK_RBUTTON&wParam) || (MK_MBUTTON&wParam) )
0607:             {
0608:                 // Normalize based on size of window and bounding sphere radius
0609:                 FLOAT fDeltaX = ( iCurMouseX-iMouseX ) * m_fRadiusTranslation / m_iWidth;
0610:                 FLOAT fDeltaY = ( iCurMouseY-iMouseY ) * m_fRadiusTranslation / m_iHeight;
0611: 
0612:                 if( wParam & MK_RBUTTON )
0613:                 {
0614:                     D3DXMatrixTranslation( &m_matTranslationDelta, -2*fDeltaX, 2*fDeltaY, 0.0f );
0615:                     D3DXMatrixMultiply( &m_matTranslation, &m_matTranslation, &m_matTranslationDelta );
0616:                 }
0617:                 else  // wParam & MK_MBUTTON
0618:                 {
0619:                     D3DXMatrixTranslation( &m_matTranslationDelta, 0.0f, 0.0f, 5*fDeltaY );
0620:                     D3DXMatrixMultiply( &m_matTranslation, &m_matTranslation, &m_matTranslationDelta );
0621:                 }
0622: 
0623:                 // Store mouse coordinate
0624:                 iCurMouseX = iMouseX;
0625:                 iCurMouseY = iMouseY;
0626:             }
0627:             return TRUE;
0628:     }
0629: 
0630:     return FALSE;
0631: }
0632: 
0633: 
0634: 
0635: 
0636: //-----------------------------------------------------------------------------
0637: // Name:
0638: // Desc:
0639: //-----------------------------------------------------------------------------
0640: CD3DCamera::CD3DCamera()
0641: {
0642:     // Set attributes for the view matrix
0643:     SetViewParams( D3DXVECTOR3(0.0f,0.0f,0.0f), D3DXVECTOR3(0.0f,0.0f,1.0f),
0644:                    D3DXVECTOR3(0.0f,1.0f,0.0f) );
0645: 
0646:     // Set attributes for the projection matrix
0647:     SetProjParams( D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
0648: }
0649: 
0650: 
0651: 
0652: 
0653: //-----------------------------------------------------------------------------
0654: // Name:
0655: // Desc:
0656: //-----------------------------------------------------------------------------
0657: VOID CD3DCamera::SetViewParams( D3DXVECTOR3 &vEyePt, D3DXVECTOR3& vLookatPt,
0658:                                 D3DXVECTOR3& vUpVec )
0659: {
0660:     // Set attributes for the view matrix
0661:     m_vEyePt    = vEyePt;
0662:     m_vLookatPt = vLookatPt;
0663:     m_vUpVec    = vUpVec;
0664:     D3DXVec3Normalize( &m_vView, &(m_vLookatPt - m_vEyePt) );
0665:     D3DXVec3Cross( &m_vCross, &m_vView, &m_vUpVec );
0666: 
0667:     D3DXMatrixLookAtLH( &m_matView, &m_vEyePt, &m_vLookatPt, &m_vUpVec );
0668:     D3DXMatrixInverse( &m_matBillboard, NULL, &m_matView );
0669:     m_matBillboard._41 = 0.0f;
0670:     m_matBillboard._42 = 0.0f;
0671:     m_matBillboard._43 = 0.0f;
0672: }
0673: 
0674: 
0675: 
0676: 
0677: //-----------------------------------------------------------------------------
0678: // Name:
0679: // Desc:
0680: //-----------------------------------------------------------------------------
0681: VOID CD3DCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
0682:                                 FLOAT fFarPlane )
0683: {
0684:     // Set attributes for the projection matrix
0685:     m_fFOV        = fFOV;
0686:     m_fAspect     = fAspect;
0687:     m_fNearPlane  = fNearPlane;
0688:     m_fFarPlane   = fFarPlane;
0689: 
0690:     D3DXMatrixPerspectiveFovLH( &m_matProj, fFOV, fAspect, fNearPlane, fFarPlane );
0691: }
0692: