home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / directx / dxf / samples / multimedia / demos / donuts3d / donuts.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  103.8 KB  |  2,998 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Donuts.cpp
  3. //
  4. // Desc: DirectInput semantic mapper version of Donuts3D game
  5. //
  6. // Copyright (C) 1995-2000 Microsoft Corporation. All Rights Reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <windows.h>
  10. #include <windowsx.h>
  11. #include <basetsd.h>
  12. #include <cguid.h>
  13. #include <tchar.h>
  14. #include <mmsystem.h>
  15. #include <stdio.h>
  16. #include <math.h>
  17. #include <D3DX8.h>
  18. #include "D3DFile.h"
  19. #include "D3DFont.h"
  20. #include "D3DUtil.h"
  21. #include "DIUtil.h"
  22. #include "DMUtil.h"
  23. #include "DXUtil.h"
  24. #include "resource.h"
  25. #include "donuts.h"
  26. #include "gamemenu.h"
  27.  
  28.  
  29.  
  30.  
  31. //-----------------------------------------------------------------------------
  32. // Custom Direct3D vertex types
  33. //-----------------------------------------------------------------------------
  34. struct SCREENVERTEX
  35. {
  36.     D3DXVECTOR4 p;
  37.     DWORD       color;
  38. };
  39.  
  40. struct SPRITEVERTEX
  41. {
  42.     D3DXVECTOR3 p;
  43.     DWORD       color;
  44.     FLOAT       tu, tv;
  45. };
  46.  
  47. struct MODELVERTEX
  48. {
  49.     D3DXVECTOR3 p;
  50.     D3DXVECTOR3 n;
  51.     FLOAT       tu, tv;
  52. };
  53.  
  54. #define D3DFVF_SCREENVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
  55. #define D3DFVF_SPRITEVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  56. #define D3DFVF_MODELVERTEX  (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  57.  
  58.  
  59.  
  60.  
  61. //-----------------------------------------------------------------------------
  62. // Application globals
  63. //-----------------------------------------------------------------------------
  64. TCHAR*               g_strAppName     = _T("Donuts3D");
  65. GUID                 g_AppGuid        = { 0x451F8CCC, 0xA7E9, 0x4DF4, 0x9A, 0x6B,
  66.                                           0xF4, 0xA7,0xC7, 0x06, 0xF3, 0x33 };
  67.  
  68. HWND                 g_hWndMain;               // Main window
  69. DWORD                g_dwScreenWidth  = 800;   // Dimensions for fullscreen modes
  70. DWORD                g_dwScreenHeight = 600;
  71. D3DDISPLAYMODE       g_DesktopMode;
  72. D3DFORMAT            g_d3dfmtFullscreen;       // Pixel format for fullscreen modes
  73. D3DFORMAT            g_d3dfmtTexture;          // Pixel format for textures
  74. BOOL                 g_bFullScreen    = FALSE; // Whether app is fullscreen (or windowed)
  75. BOOL                 g_bIsActive;              // Whether app is active
  76. BOOL                 g_bDisplayReady  = FALSE; // Whether display class is initialized
  77. BOOL                 g_bMouseVisible  = TRUE;  // Whether mouse is visible
  78. HBITMAP              g_hSplashBitmap  = NULL;  // Bitmap for splash screen
  79.  
  80. DWORD                g_dwAppState;              // Current state the app is in
  81. DWORD                g_dwLevel        = 0;      // Current game level
  82. DWORD                g_dwScore        = 0;      // Current game score
  83.  
  84. // Player view mode
  85. #define NUMVIEWMODES 3
  86. CD3DCamera           g_Camera;                       // Camera used for 3D scene
  87. DWORD                g_dwViewMode           = 0;     // Which view mode is being used
  88. FLOAT                g_fViewTransition      = 0.0f;  // Amount used to transittion views
  89. BOOL                 g_bAnimatingViewChange = FALSE; // Whether view is transitioning
  90. BOOL                 g_bFirstPersonView     = TRUE;  // Whether view is first-person
  91.  
  92. // Bullet mode
  93. FLOAT                g_fBulletRechargeTime  = 0.0f;  // Recharge time for firing bullets
  94. DWORD                g_dwBulletType         = 0L;    // Current bullet type
  95.  
  96. // Display list and player ship
  97. DisplayObject*       g_pDisplayList = NULL;          // Global display list
  98. CShip*               g_pShip        = NULL;          // Player's display object
  99.  
  100. // DirectDraw/Direct3D objects
  101. LPDIRECT3DDEVICE8       g_pd3dDevice        = NULL;  // Class to handle D3D device
  102. D3DPRESENT_PARAMETERS   g_d3dpp;
  103. LPDIRECT3DSURFACE8      g_pConfigSurface    = NULL;  // Surface for config'ing DInput devices
  104. LPDIRECT3DVERTEXBUFFER8 g_pViewportVB       = NULL;
  105. LPDIRECT3DVERTEXBUFFER8 g_pSpriteVB         = NULL;
  106.  
  107. // Support for the ship model
  108. CD3DMesh*            g_pShipFileObject   = NULL;      // Geometry model of player's ship
  109. DWORD                g_dwNumShipTypes    = 10L;
  110. DWORD                g_dwCurrentShipType = 0L;
  111. TCHAR*               g_strShipFiles[]    = { _T("Concept Plane 3.x"), _T("Spaceship 2.x"), _T("Shusui.x"),
  112.                                              _T("Space Station 7.x"), _T("Spaceship 8.x"), _T("Orbiter.x"),
  113.                                              _T("Spaceship 13.x"),    _T("Spaceship 5.x"), _T("Star Sail.x"), 
  114.                                              _T("Heli.x"), };
  115. TCHAR*               g_strShipNames[]    = { _T("Concept Plane"), _T("Green Machine"),  _T("Purple Prowler"),
  116.                                              _T("Drone Clone"),   _T("Canyon Fighter"), _T("Roundabout"),
  117.                                              _T("Tie-X7"),        _T("Gunner"),         _T("Star Sail"), 
  118.                                              _T("Helicopter"), };
  119.  
  120. // DirectMusic objects
  121. CMusicManager*       g_pMusicManager        = NULL;  // Class to manage DMusic objects
  122. CMusicSegment*       g_pBeginLevelSound     = NULL;  // Sounds for the app
  123. CMusicSegment*       g_pEngineIdleSound     = NULL;
  124. CMusicSegment*       g_pEngineRevSound      = NULL;
  125. CMusicSegment*       g_pShieldBuzzSound     = NULL;
  126. CMusicSegment*       g_pShipExplodeSound    = NULL;
  127. CMusicSegment*       g_pFireBulletSound     = NULL;
  128. CMusicSegment*       g_pShipBounceSound     = NULL;
  129. CMusicSegment*       g_pDonutExplodeSound   = NULL;
  130. CMusicSegment*       g_pPyramidExplodeSound = NULL;
  131. CMusicSegment*       g_pCubeExplodeSound    = NULL;
  132. CMusicSegment*       g_pSphereExplodeSound  = NULL;
  133.  
  134. // Game objects
  135. LPDIRECT3DTEXTURE8   g_pGameTexture1 = NULL; // Texture with game object animations
  136. LPDIRECT3DTEXTURE8   g_pGameTexture2 = NULL; // Texture with game object animations
  137. CD3DMesh*            g_pTerrain        = NULL;    // Geometry model of terrain
  138. CD3DFont*            g_pGameFont       = NULL;    // Font for displaying score, etc.
  139. CD3DFont*            g_pMenuFont       = NULL;    // Font for displaying in-game menus
  140.  
  141.  
  142. // Menu objects
  143. CMenuItem*           g_pMainMenu       = NULL;    // Menu class for in-game menus
  144. CMenuItem*           g_pQuitMenu       = NULL;
  145. CMenuItem*           g_pCurrentMenu    = NULL;
  146.  
  147. // Defines for the in-game menu
  148. #define MENU_MAIN           1
  149. #define MENU_SOUND          2
  150. #define MENU_VIDEO          3
  151. #define MENU_INPUT          4
  152. #define MENU_VIEWDEVICES    5
  153. #define MENU_CONFIGDEVICES  6
  154. #define MENU_WINDOWED       7
  155. #define MENU_640x480        8
  156. #define MENU_800x600        9
  157. #define MENU_1024x768      10
  158. #define MENU_BACK          11
  159. #define MENU_SOUNDON       12
  160. #define MENU_SOUNDOFF      13
  161. #define MENU_QUIT          14
  162.  
  163.  
  164. // DirectInput objects
  165. CInputDeviceManager* g_pInputDeviceManager = NULL; // Class for managing DInput devices
  166. DIACTIONFORMAT       g_diafGame;                   // Action format for game play
  167. DIACTIONFORMAT       g_diafBrowser;                // Action format for menu navigation
  168.  
  169. // Game input variables
  170. FLOAT                g_fBank           = 0.0f;
  171. FLOAT                g_fThrust         = 0.0f;
  172. BOOL                 g_bFiringWeapons  = FALSE;
  173. BOOL                 g_bChangeView     = FALSE;
  174. BOOL                 g_bPaused         = FALSE;
  175.  
  176. // Menu input variables
  177. BOOL                 g_bMenuLeft       = FALSE;
  178. BOOL                 g_bMenuRight      = FALSE;
  179. BOOL                 g_bMenuUp         = FALSE;
  180. BOOL                 g_bMenuDown       = FALSE;
  181. BOOL                 g_bMenuSelect     = FALSE;
  182. BOOL                 g_bMenuQuit       = FALSE;
  183.  
  184.  
  185. //-----------------------------------------------------------------------------
  186. // Game actions (using DInput semantic mapper). The definitions here are kind
  187. // of the whole point of this sample. The game uses these actions to map
  188. // physical input like, "the user pressed the 'W' key", to a more useable
  189. // constant for the game, like "if( dwInput == INPUT_CHANGEWEAPONS )...".
  190. //-----------------------------------------------------------------------------
  191.  
  192.  
  193. // Input semantics used by this game
  194. enum INPUT_SEMANTICS
  195. {
  196.     // Gameplay semantics
  197.     INPUT_AXIS_LR=1,     INPUT_AXIS_UD,       INPUT_AXIS_SHIPTYPE,
  198.     INPUT_MOUSE_LR,      INPUT_MOUSE_UD,      INPUT_MOUSE_SHIPTYPE,
  199.     INPUT_TURNLEFT,      INPUT_TURNRIGHT,     INPUT_FORWARDTHRUST,
  200.     INPUT_REVERSETHRUST, INPUT_FIREWEAPONS,   INPUT_CHANGESHIPTYPE,
  201.     INPUT_CHANGEVIEW,    INPUT_CHANGEWEAPONS, INPUT_DISPLAYGAMEMENU,
  202.     INPUT_QUITGAME,      INPUT_START,
  203.  
  204.     // Menu semantics
  205.     INPUT_MENU_LR,       INPUT_MENU_UD,       INPUT_MENU_WHEEL,
  206.     INPUT_MENU_UP,       INPUT_MENU_DOWN,     INPUT_MENU_LEFT,
  207.     INPUT_MENU_RIGHT,    INPUT_MENU_SELECT,   INPUT_MENU_QUIT,
  208. };
  209.  
  210. // Game actions used by this game.
  211. DIACTION g_rgGameAction[] =
  212. {
  213.     { INPUT_AXIS_LR,         DIAXIS_SPACESIM_LATERAL,   0, TEXT("Turn"), },
  214.     { INPUT_AXIS_UD,         DIAXIS_SPACESIM_MOVE,      0, TEXT("Move"), },
  215.     { INPUT_FIREWEAPONS,     DIBUTTON_SPACESIM_FIRE,    0, TEXT("Fire weapons"), },
  216.     { INPUT_CHANGEVIEW,      DIBUTTON_SPACESIM_VIEW,    0, TEXT("Change view"), },
  217.     { INPUT_CHANGEWEAPONS,   DIBUTTON_SPACESIM_WEAPONS, 0, TEXT("Change weapons"), },
  218.     { INPUT_CHANGESHIPTYPE,  DIBUTTON_SPACESIM_LOWER,    0, TEXT("Change ship type"), },
  219.     { INPUT_DISPLAYGAMEMENU, DIBUTTON_SPACESIM_DEVICE,    0, TEXT("Display game menu"), },
  220.     { INPUT_START,           DIBUTTON_SPACESIM_MENU,  0, TEXT("Start/pause"), },
  221.  
  222.     { INPUT_TURNLEFT,        DIKEYBOARD_LEFT,    0, TEXT("Turn left"), },
  223.     { INPUT_TURNRIGHT,       DIKEYBOARD_RIGHT,   0, TEXT("Turn right"), },
  224.     { INPUT_FORWARDTHRUST,   DIKEYBOARD_UP,      0, TEXT("Forward thrust"), },
  225.     { INPUT_REVERSETHRUST,   DIKEYBOARD_DOWN,    0, TEXT("Reverse thrust"), },
  226.     { INPUT_FIREWEAPONS,     DIKEYBOARD_SPACE,   0, TEXT("Fire weapons"), },
  227.     { INPUT_CHANGESHIPTYPE,  DIKEYBOARD_A,       0, TEXT("Change ship type"), },
  228.     { INPUT_CHANGEVIEW,      DIKEYBOARD_V,       0, TEXT("Change view"), },
  229.     { INPUT_CHANGEWEAPONS,   DIKEYBOARD_W,       0, TEXT("Change weapons"), },
  230.     { INPUT_DISPLAYGAMEMENU, DIKEYBOARD_F1,      DIA_APPFIXED, TEXT("Display game menu"), },
  231.     { INPUT_START,           DIKEYBOARD_PAUSE,   0, TEXT("Start/pause"), },
  232.     { INPUT_QUITGAME,        DIKEYBOARD_ESCAPE,  DIA_APPFIXED, TEXT("Quit game"), },
  233.  
  234.     { INPUT_MOUSE_LR,        DIMOUSE_XAXIS,      0, TEXT("Turn"), },
  235.     { INPUT_MOUSE_UD,        DIMOUSE_YAXIS,      0, TEXT("Move"), },
  236.     { INPUT_MOUSE_SHIPTYPE,  DIMOUSE_WHEEL,      0, TEXT("Change ship type"), },
  237.     { INPUT_FIREWEAPONS,     DIMOUSE_BUTTON0,    0, TEXT("Fire weapons"), },
  238.     { INPUT_CHANGEWEAPONS,   DIMOUSE_BUTTON1,    0, TEXT("Change weapons"), },
  239. };
  240.  
  241. // Game actions used by this game.
  242. DIACTION g_rgBrowserAction[] =
  243. {
  244.     { INPUT_MENU_LR,         DIAXIS_BROWSER_LATERAL,    0, TEXT("Left/right"), },
  245.     { INPUT_MENU_UD,         DIAXIS_BROWSER_MOVE,       0, TEXT("Up/down"), },
  246.     { INPUT_MENU_SELECT,     DIBUTTON_BROWSER_SELECT,   0, TEXT("Select"), },
  247.     { INPUT_MENU_UP,         DIBUTTON_BROWSER_PREVIOUS, 0, TEXT("Up"), },
  248.     { INPUT_MENU_DOWN,       DIBUTTON_BROWSER_NEXT,     0, TEXT("Down"), },
  249.     { INPUT_MENU_QUIT,       DIBUTTON_BROWSER_DEVICE,   0, TEXT("Quit menu"), },
  250.  
  251.     { INPUT_MENU_LEFT,       DIKEYBOARD_LEFT,        0, TEXT("Left"), },
  252.     { INPUT_MENU_RIGHT,      DIKEYBOARD_RIGHT,       0, TEXT("Right"), },
  253.     { INPUT_MENU_UP,         DIKEYBOARD_UP,          0, TEXT("Up"), },
  254.     { INPUT_MENU_DOWN,       DIKEYBOARD_DOWN,        0, TEXT("Down"), },
  255.     { INPUT_MENU_SELECT,     DIKEYBOARD_SPACE,       0, TEXT("Select"), },
  256.     { INPUT_MENU_SELECT,     DIKEYBOARD_RETURN,      0, TEXT("Select"), },
  257.     { INPUT_MENU_SELECT,     DIKEYBOARD_NUMPADENTER, 0, TEXT("Select"), },
  258.     { INPUT_MENU_QUIT,       DIKEYBOARD_ESCAPE,      0, TEXT("Quit menu"), },
  259.  
  260.     { INPUT_MENU_WHEEL,      DIMOUSE_WHEEL,      0, TEXT("Up/down"), },
  261.     { INPUT_MENU_SELECT,     DIMOUSE_BUTTON0,    0, TEXT("Select"), },
  262. };
  263.  
  264. // Number of actions
  265. #define NUMBER_OF_GAMEACTIONS    (sizeof(g_rgGameAction)/sizeof(DIACTION))
  266. #define NUMBER_OF_BROWSERACTIONS (sizeof(g_rgBrowserAction)/sizeof(DIACTION))
  267.  
  268.  
  269.  
  270.  
  271. //-----------------------------------------------------------------------------
  272. // Inline helper functions
  273. //-----------------------------------------------------------------------------
  274.  
  275. // Simple function to define "hilliness" for terrain
  276. inline FLOAT HeightField( FLOAT x, FLOAT z )
  277. {
  278.     return (cosf(x/2.0f+0.2f)*cosf(z/1.5f-0.2f)+1.0f) - 2.0f;
  279. }
  280.  
  281. // Simple function for generating random numbers
  282. inline FLOAT rnd( FLOAT low, FLOAT high )
  283. {
  284.     return low + ( high - low ) * ( (FLOAT)rand() ) / RAND_MAX;
  285. }
  286.  
  287. // Convenient macros for playing sounds
  288. inline VOID PlaySound( CMusicSegment* pSound )
  289. {
  290.         if( pSound ) pSound->Play( DMUS_SEGF_SECONDARY );
  291. }
  292.  
  293. inline VOID StopSound( CMusicSegment* pSound )
  294. {
  295.         if( pSound ) pSound->Stop();
  296. }
  297.  
  298.  
  299.  
  300.  
  301. //-----------------------------------------------------------------------------
  302. // Name: WinMain()
  303. // Desc: Application entry point
  304. //-----------------------------------------------------------------------------
  305. int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
  306. {
  307.     // Register the window class
  308.     WNDCLASS wndClass = { CS_DBLCLKS, WndProc, 0, 0, hInstance,
  309.                           LoadIcon( hInstance, MAKEINTRESOURCE(DONUTS_ICON) ),
  310.                           LoadCursor( NULL, IDC_ARROW ),
  311.                           (HBRUSH)GetStockObject( BLACK_BRUSH ),
  312.                           NULL, TEXT("DonutsClass") };
  313.     RegisterClass( &wndClass );
  314.  
  315.     // Create our main window
  316.     g_hWndMain = CreateWindowEx( 0, TEXT("DonutsClass"), TEXT("Donuts"),
  317.                                  WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU,
  318.                                  0, 0, 640, 480, NULL, NULL,
  319.                                  hInstance, NULL );
  320.     if( NULL == g_hWndMain )
  321.         return FALSE;
  322.     UpdateWindow( g_hWndMain );
  323.  
  324.         // Create the game objects (display objects, sounds, input devices,
  325.         // menus, etc.)
  326.     if( FAILED( CreateGameObjects( g_hWndMain ) ) )
  327.     {
  328.         DestroyWindow( g_hWndMain );
  329.         return FALSE;
  330.     }
  331.  
  332.     // Load keyboard accelerators
  333.     HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  334.  
  335.     // Now we're ready to recieve and process Windows messages.
  336.     BOOL bGotMsg;
  337.     MSG  msg;
  338.     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
  339.  
  340.     while( WM_QUIT != msg.message  )
  341.     {
  342.         // Use PeekMessage() if the app is active, so we can use idle time to
  343.         // render the scene. Else, use GetMessage() to avoid eating CPU time.
  344.         if( g_bIsActive )
  345.             bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
  346.         else
  347.             bGotMsg = GetMessage( &msg, NULL, 0U, 0U );
  348.  
  349.         if( bGotMsg )
  350.         {
  351.             // Translate and dispatch the message
  352.             TranslateMessage( &msg );
  353.             DispatchMessage( &msg );
  354.         }
  355.         else
  356.         {
  357.             // Render a frame during idle time (no messages are waiting)
  358.             if( g_bDisplayReady )
  359.             {
  360.                 FrameMove();
  361.                 RenderFrame();
  362.             }
  363.         }
  364.     }
  365.  
  366.     return (int)msg.wParam;
  367. }
  368.  
  369.  
  370.  
  371.  
  372. //-----------------------------------------------------------------------------
  373. // Name: WndProc()
  374. // Desc: Callback for all Windows messages
  375. //-----------------------------------------------------------------------------
  376. LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  377. {
  378.     switch( msg )
  379.     {
  380.         case WM_ACTIVATEAPP:
  381.             g_bIsActive = (BOOL)wParam;
  382.  
  383.             if( g_bIsActive )
  384.             {
  385.                 g_bMouseVisible   = FALSE;
  386.                 DXUtil_Timer( TIMER_START );
  387.             }
  388.             else
  389.             {
  390.                 g_bMouseVisible = TRUE;
  391.                 DXUtil_Timer( TIMER_STOP );
  392.             }
  393.             break;
  394.  
  395.         case WM_GETMINMAXINFO:
  396.             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 320;
  397.             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 200;
  398.             break;
  399.  
  400.         case WM_SETCURSOR:
  401.             if( !g_bMouseVisible && g_dwAppState!=APPSTATE_DISPLAYSPLASH )
  402.                 SetCursor( NULL );
  403.             else
  404.                 SetCursor( LoadCursor( NULL, IDC_ARROW ) );
  405.             return TRUE;
  406.  
  407.         case WM_SYSCOMMAND:
  408.             // Prevent moving/sizing and power loss
  409.             switch( wParam )
  410.             {
  411.                 case SC_MOVE:
  412.                 case SC_SIZE:
  413.                 case SC_MAXIMIZE:
  414.                 case SC_KEYMENU:
  415.                 case SC_MONITORPOWER:
  416.                         return 1;
  417.             }
  418.             break;
  419.  
  420.                 case WM_SYSKEYDOWN:
  421.             // Handle Alt+Enter to do mode-switching
  422.             if( VK_RETURN == wParam )
  423.             {
  424.                 SwitchDisplayModes( !g_bFullScreen, g_dwScreenWidth,
  425.                                     g_dwScreenHeight );
  426.             }
  427.             break;
  428.  
  429.         case WM_KEYDOWN:
  430.             // Move from splash screen when user presses a key
  431.             if( g_dwAppState == APPSTATE_DISPLAYSPLASH )
  432.             {
  433.                 if( wParam==VK_ESCAPE )
  434.                 {
  435.                     // Escape keys exits the app
  436.                     PostMessage( hWnd, WM_CLOSE, 0, 0 );
  437.                     g_bDisplayReady = FALSE;
  438.                 }
  439.                 else
  440.                 {
  441.                     // Get rid of splash bitmap
  442.                     DeleteObject( g_hSplashBitmap );
  443.  
  444.                     // Advance to the first level
  445.                     g_dwAppState = APPSTATE_BEGINLEVELSCREEN;
  446.                     DXUtil_Timer( TIMER_START );
  447.                     AdvanceLevel();
  448.                 }
  449.             }
  450.             return 0;
  451.  
  452.         case WM_PAINT:
  453.             if( g_dwAppState == APPSTATE_DISPLAYSPLASH )
  454.             {
  455.                 BITMAP bmp;
  456.                 RECT rc;
  457.                 GetClientRect( g_hWndMain, &rc );
  458.  
  459.                 // Display the splash bitmap in the window
  460.                 HDC hDCWindow = GetDC( g_hWndMain );
  461.                 HDC hDCImage  = CreateCompatibleDC( NULL );
  462.                 SelectObject( hDCImage, g_hSplashBitmap );
  463.                 GetObject( g_hSplashBitmap, sizeof(bmp), &bmp );
  464.                 StretchBlt( hDCWindow, 0, 0, rc.right, rc.bottom,
  465.                             hDCImage, 0, 0,
  466.                             bmp.bmWidth, bmp.bmHeight, SRCCOPY );
  467.                 DeleteDC( hDCImage );
  468.                 ReleaseDC( g_hWndMain, hDCWindow );
  469.             }
  470.             else
  471.             {
  472.                 if( g_bDisplayReady )
  473.                 {
  474.                     DrawDisplayList();
  475.                     ShowFrame();
  476.                 }
  477.             }
  478.             break;
  479.  
  480.         case WM_DESTROY:
  481.             DestroyGameObjects();
  482.             PostQuitMessage( 0 );
  483.             g_bDisplayReady = FALSE;
  484.             break;
  485.     }
  486.  
  487.     return DefWindowProc( hWnd, msg, wParam, lParam );
  488. }
  489.  
  490.  
  491.  
  492.  
  493. //-----------------------------------------------------------------------------
  494. // Name: CreateGameObjects()
  495. // Desc:
  496. //-----------------------------------------------------------------------------
  497. HRESULT CreateGameObjects( HWND hWnd )
  498. {
  499.     HRESULT hr;
  500.  
  501.     // Initialize the DirectInput stuff
  502.     if( FAILED( hr = CreateInputObjects( hWnd ) ) )
  503.         return hr;
  504.  
  505.     // Initialize the DirectSound stuff. Note: if this call fails, we can
  506.         // continue with no sound.
  507.     CreateSoundObjects( hWnd );
  508.  
  509.     // Create the display objects
  510.     if( FAILED( hr = CreateDisplayObjects( hWnd ) ) )
  511.         return hr;
  512.  
  513.     // Add a ship to the displaylist
  514.     g_pShip = new CShip( D3DXVECTOR3(0.0f,0.0f,0.0f) );
  515.     g_pDisplayList = g_pShip;
  516.  
  517.     // Construct the game menus
  518.     ConstructMenus();
  519.  
  520.     // Initial program state is to display the splash screen
  521.     g_dwAppState = APPSTATE_LOADSPLASH;
  522.  
  523.     return S_OK;
  524. }
  525.  
  526.  
  527.  
  528.  
  529. //-----------------------------------------------------------------------------
  530. // Name: DestroyGameObjects()
  531. // Desc:
  532. //-----------------------------------------------------------------------------
  533. VOID DestroyGameObjects()
  534. {
  535.     DestroyDisplayObjects();
  536.     DestroySoundObjects();
  537.     DestroyInputObjects();
  538.     DestroyMenus();
  539. }
  540.  
  541.  
  542.  
  543.  
  544. //-----------------------------------------------------------------------------
  545. // Name: AdvanceLevel()
  546. // Desc:
  547. //-----------------------------------------------------------------------------
  548. VOID AdvanceLevel()
  549. {
  550.     // Up the level
  551.     g_dwLevel++;
  552.  
  553.     srand( timeGetTime() );
  554.  
  555.     // Clear any stray objects (anything but the ship) out of the display list
  556.     while( g_pShip->pNext )
  557.     {
  558.         DeleteFromList( g_pShip->pNext );
  559.     }
  560.  
  561.     // Create donuts for the new level
  562.     for( WORD i=0; i<(2*g_dwLevel+3); i++ )
  563.     {
  564.         D3DVECTOR vPosition = 3.0f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  565.         D3DVECTOR vVelocity = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  566.  
  567.         AddToList( new CDonut( vPosition, vVelocity ) );
  568.     }
  569.  
  570.     // Delay for 2 seconds before displaying ship
  571.     g_pShip->vPos       = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  572.     g_pShip->vVel       = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  573.     g_pShip->bVisible   = FALSE;
  574.     g_pShip->bExploded  = FALSE;
  575.     g_pShip->fShowDelay = 2.0f;
  576.  
  577.     // Clear out iput states
  578.     g_fBank          = 0.0f;
  579.     g_fThrust        = 0.0f;
  580.     g_bFiringWeapons = FALSE;
  581.  
  582.     // Stop engine sounds
  583.     StopSound( g_pEngineIdleSound );
  584.     StopSound( g_pEngineRevSound );
  585. }
  586.  
  587.  
  588.  
  589.  
  590. //-----------------------------------------------------------------------------
  591. // Name: DisplayObject()
  592. // Desc:
  593. //-----------------------------------------------------------------------------
  594. DisplayObject::DisplayObject( DWORD type, D3DVECTOR p, D3DVECTOR v )
  595. {
  596.     // Set object attributes
  597.     pNext    = NULL;
  598.     pPrev    = NULL;
  599.     bVisible = TRUE;
  600.     dwType   = type;
  601.     vPos     = p;
  602.     vVel     = v;
  603. }
  604.  
  605.  
  606.  
  607.  
  608. //-----------------------------------------------------------------------------
  609. // Name: C3DSprite()
  610. // Desc:
  611. //-----------------------------------------------------------------------------
  612. C3DSprite::C3DSprite( DWORD type, D3DVECTOR p, D3DVECTOR v )
  613.           :DisplayObject( type, p, v )
  614. {
  615.     dwColor = 0xffffffff;
  616. }
  617.  
  618.  
  619.  
  620.  
  621. //-----------------------------------------------------------------------------
  622. // Name: CDonut()
  623. // Desc:
  624. //-----------------------------------------------------------------------------
  625. CDonut::CDonut( D3DVECTOR p, D3DVECTOR v )
  626.        :C3DSprite( OBJ_DONUT, p, v )
  627. {
  628.     // Set object attributes
  629.     dwTextureWidth   = DONUT_WIDTH;
  630.     dwTextureHeight  = DONUT_HEIGHT;
  631.     dwTextureOffsetX = 0;
  632.     dwTextureOffsetY = 0;
  633.  
  634.     fSize           = dwTextureWidth / 256.0f;
  635.     vVel            += 0.5f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  636.  
  637.     delay           = rnd( 3.0f, 12.0f );
  638.     dwFramesPerLine = 8;
  639.     frame           = rnd( 0.0f, 30.0f );
  640.     fMaxFrame       = NUM_DONUT_FRAMES;
  641. }
  642.  
  643.  
  644.  
  645.  
  646. //-----------------------------------------------------------------------------
  647. // Name: CPyramid()
  648. // Desc:
  649. //-----------------------------------------------------------------------------
  650. CPyramid::CPyramid( D3DVECTOR p, D3DVECTOR v )
  651.          :C3DSprite( OBJ_PYRAMID, p, v )
  652. {
  653.     // Set object attributes
  654.     dwTextureWidth   = PYRAMID_WIDTH;
  655.     dwTextureHeight  = PYRAMID_HEIGHT;
  656.     dwTextureOffsetX = 0;
  657.     dwTextureOffsetY = 0;
  658.  
  659.     fSize           = dwTextureWidth / 256.0f;
  660.     vVel            += 0.5f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  661.  
  662.     delay           = rnd( 12.0f, 40.0f );
  663.     dwFramesPerLine = 8;
  664.     frame           = rnd( 0.0f, 30.0f );
  665.     fMaxFrame       = NUM_PYRAMID_FRAMES;
  666.  
  667. }
  668.  
  669.  
  670.  
  671.  
  672. //-----------------------------------------------------------------------------
  673. // Name: CSphere()
  674. // Desc:
  675. //-----------------------------------------------------------------------------
  676. CSphere::CSphere( D3DVECTOR p, D3DVECTOR v )
  677.         :C3DSprite( OBJ_SPHERE, p, v )
  678. {
  679.     // Set object attributes
  680.     dwTextureWidth   = SPHERE_WIDTH;
  681.     dwTextureHeight  = SPHERE_HEIGHT;
  682.     dwTextureOffsetX = 0;
  683.     dwTextureOffsetY = 128;
  684.  
  685.     fSize           = dwTextureWidth / 256.0f;
  686.     vVel            += 0.5f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  687.  
  688.     delay           = rnd( 60.0f, 80.0f );
  689.     dwFramesPerLine = 16;
  690.     frame           = rnd( 0.0f, 30.0f );
  691.     fMaxFrame       = NUM_SPHERE_FRAMES;
  692. }
  693.  
  694.  
  695.  
  696.  
  697.  
  698. //-----------------------------------------------------------------------------
  699. // Name: CCube()
  700. // Desc:
  701. //-----------------------------------------------------------------------------
  702. CCube::CCube( D3DVECTOR p, D3DVECTOR v )
  703.       :C3DSprite( OBJ_CUBE, p, v )
  704. {
  705.     // Set object attributes
  706.     dwTextureWidth   = CUBE_WIDTH;
  707.     dwTextureHeight  = CUBE_HEIGHT;
  708.     dwTextureOffsetX = 0;
  709.     dwTextureOffsetY = 176;
  710.  
  711.     fSize           = dwTextureWidth / 256.0f;
  712.     vVel            += 0.5f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  713.  
  714.     delay           = rnd( 32.0f, 80.0f );
  715.     dwFramesPerLine = 16;
  716.     frame           = rnd( 0.0f, 30.0f );
  717.     fMaxFrame       = NUM_CUBE_FRAMES;
  718. }
  719.  
  720.  
  721.  
  722.  
  723. //-----------------------------------------------------------------------------
  724. // Name: CCloud()
  725. // Desc:
  726. //-----------------------------------------------------------------------------
  727. CCloud::CCloud( D3DVECTOR p, D3DVECTOR v )
  728.        :C3DSprite( OBJ_CLOUD, p, v )
  729. {
  730.     // Set object attributes
  731.     dwTextureWidth   = CLOUD_WIDTH;
  732.     dwTextureHeight  = CLOUD_WIDTH;
  733.     dwTextureOffsetX = 224;
  734.     dwTextureOffsetY = 224;
  735.  
  736.     fSize           = dwTextureWidth / 256.0f;
  737.     delay           = rnd( 1.0f, 3.0f );
  738.     dwFramesPerLine = 1;
  739.     frame           = 0.0f;
  740.     fMaxFrame       = 1;
  741. }
  742.  
  743.  
  744.  
  745.  
  746. //-----------------------------------------------------------------------------
  747. // Name: CBullet()
  748. // Desc:
  749. //-----------------------------------------------------------------------------
  750. CBullet::CBullet( D3DVECTOR p, D3DVECTOR v, DWORD dwCType )
  751.         :C3DSprite( OBJ_BULLET, p, v )
  752. {
  753.     // Set object attributes
  754.     dwTextureWidth   = CLOUD_WIDTH;
  755.     dwTextureHeight  = CLOUD_HEIGHT;
  756.     dwTextureOffsetX = 224;
  757.     dwTextureOffsetY = 224;
  758.  
  759.     if( dwCType == 0 )
  760.         dwColor = 0xff2020ff;
  761.     if( dwCType == 1 )
  762.         dwColor = 0xff208020;
  763.     if( dwCType == 2 )
  764.         dwColor = 0xff208080;
  765.     if( dwCType == 3 )
  766.         dwColor = 0xff802020;
  767.  
  768.     fSize           = 4 / 256.0f;
  769.     fMaxFrame       = NUM_BULLET_FRAMES;
  770.  
  771.     delay           = 1000.0f;
  772.     dwFramesPerLine = 1;
  773.     frame           = 0.0f;
  774. }
  775.  
  776.  
  777.  
  778.  
  779. //-----------------------------------------------------------------------------
  780. // Name: CShip()
  781. // Desc:
  782. //-----------------------------------------------------------------------------
  783. CShip::CShip( D3DVECTOR p )
  784.       :DisplayObject( OBJ_SHIP, p, D3DXVECTOR3(0,0,0) )
  785. {
  786.     fSize           = 10.0f / 256.0f;
  787.     bExploded       = FALSE;
  788.     fShowDelay      = 0.0f;
  789.  
  790.     fRoll           = 0.0f;
  791.     fAngle          = 0.0f;
  792. }
  793.  
  794.  
  795.  
  796.  
  797. //-----------------------------------------------------------------------------
  798. // Name: AddToList()
  799. // Desc:
  800. //-----------------------------------------------------------------------------
  801. VOID AddToList( DisplayObject* pObject )
  802. {
  803.     pObject->pNext = g_pDisplayList->pNext;
  804.     pObject->pPrev = g_pDisplayList;
  805.  
  806.     if( g_pDisplayList->pNext )
  807.         g_pDisplayList->pNext->pPrev = pObject;
  808.     g_pDisplayList->pNext = pObject;
  809. }
  810.  
  811.  
  812.  
  813.  
  814. //-----------------------------------------------------------------------------
  815. // Name: IsDisplayListEmpty()
  816. // Desc:
  817. //-----------------------------------------------------------------------------
  818. BOOL IsDisplayListEmpty()
  819. {
  820.     DisplayObject* pObject = g_pDisplayList->pNext;
  821.  
  822.     while( pObject )
  823.     {
  824.         if( pObject->dwType != OBJ_BULLET )
  825.             return FALSE;
  826.  
  827.         pObject = pObject->pNext;
  828.     }
  829.  
  830.     return TRUE;
  831. }
  832.  
  833.  
  834.  
  835.  
  836. //-----------------------------------------------------------------------------
  837. // Name: LoadTerrainModel()
  838. // Desc: Loads the 3D geometry for the terrain
  839. //-----------------------------------------------------------------------------
  840. HRESULT LoadTerrainModel()
  841. {
  842.     LPDIRECT3DVERTEXBUFFER8 pVB;
  843.     DWORD        dwNumVertices;
  844.     MODELVERTEX* pVertices;
  845.  
  846.     // Delete old object
  847.     SAFE_DELETE( g_pTerrain );
  848.  
  849.     // Create new object
  850.     g_pTerrain = new CD3DMesh();
  851.     if( FAILED( g_pTerrain->Create( g_pd3dDevice, _T("SeaFloor.x") ) ) )
  852.         return E_FAIL;
  853.  
  854.     // Set the FVF to a reasonable type
  855.     g_pTerrain->SetFVF( g_pd3dDevice, D3DFVF_MODELVERTEX );
  856.  
  857.     // Gain access to the model's vertices
  858.     g_pTerrain->GetSysMemMesh()->GetVertexBuffer( &pVB );
  859.     dwNumVertices = g_pTerrain->GetSysMemMesh()->GetNumVertices();
  860.     pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
  861.  
  862.     for( DWORD i=0; i<dwNumVertices; i++ )
  863.     {
  864.         pVertices[i].p.x *= 0.1f;
  865.         pVertices[i].p.z *= 0.1f;
  866.         pVertices[i].p.y = HeightField( pVertices[i].p.x, pVertices[i].p.z );
  867.     }
  868.  
  869.     // Done with the vertex buffer
  870.     pVB->Unlock();
  871.     pVB->Release();
  872.  
  873.     return S_OK;
  874. }
  875.  
  876.  
  877.  
  878.  
  879. //-----------------------------------------------------------------------------
  880. // Name: LoadShipModel()
  881. // Desc: Loads the 3D geometry for the player's ship
  882. //-----------------------------------------------------------------------------
  883. HRESULT LoadShipModel()
  884. {
  885.     LPDIRECT3DVERTEXBUFFER8 pVB;
  886.     DWORD        dwNumVertices;
  887.     MODELVERTEX* pVertices;
  888.     D3DXVECTOR3  vCenter;
  889.     FLOAT        fRadius;
  890.  
  891.     // Delete old object
  892.     SAFE_DELETE( g_pShipFileObject );
  893.  
  894.     // Create new object
  895.     g_pShipFileObject = new CD3DMesh();
  896.     if( FAILED( g_pShipFileObject->Create( g_pd3dDevice,
  897.                                            g_strShipFiles[g_dwCurrentShipType] ) ) )
  898.         return E_FAIL;
  899.  
  900.     // Set the FVF to a reasonable type
  901.     g_pShipFileObject->SetFVF( g_pd3dDevice, D3DFVF_MODELVERTEX );
  902.  
  903.     // Gain access to the model's vertices
  904.     g_pShipFileObject->GetSysMemMesh()->GetVertexBuffer( &pVB );
  905.     dwNumVertices = g_pShipFileObject->GetSysMemMesh()->GetNumVertices();
  906.     pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
  907.  
  908.     // Scale the new object to a standard size  
  909.     D3DXComputeBoundingSphere( pVertices, dwNumVertices,
  910.                                D3DFVF_MODELVERTEX, &vCenter, &fRadius );
  911.     for( DWORD i=0; i<dwNumVertices; i++ )
  912.     {
  913.         pVertices[i].p /= 12*fRadius;
  914.     }
  915.  
  916.     // Done with the vertex buffer
  917.     pVB->Unlock();
  918.     pVB->Release();
  919.  
  920.     return S_OK;
  921. }
  922.  
  923.  
  924.  
  925.  
  926. //-----------------------------------------------------------------------------
  927. // Name: SwitchModel()
  928. // Desc:
  929. //-----------------------------------------------------------------------------
  930. HRESULT SwitchModel()
  931. {
  932.     // Select next model
  933.     g_dwCurrentShipType++;
  934.     if( g_dwCurrentShipType >= g_dwNumShipTypes )
  935.         g_dwCurrentShipType = 0L;
  936.  
  937.     // Create new object
  938.     if( SUCCEEDED( LoadShipModel() ) )
  939.     {
  940.         // Initialize the new object's device dependent objects
  941.         if( SUCCEEDED( g_pShipFileObject->RestoreDeviceObjects( g_pd3dDevice ) ) )
  942.             return S_OK;
  943.     }
  944.  
  945.     // Return with a fatal error
  946.     PostMessage( g_hWndMain, WM_CLOSE, 0, 0 );
  947.     return E_FAIL;
  948. }
  949.  
  950.  
  951.  
  952.  
  953. //-----------------------------------------------------------------------------
  954. // Name: FrameMove()
  955. // Desc:
  956. //-----------------------------------------------------------------------------
  957. HRESULT FrameMove()
  958. {
  959.     switch( g_dwAppState )
  960.     {
  961.         case APPSTATE_LOADSPLASH:
  962.             // Set the app state to displaying splash
  963.             g_dwAppState = APPSTATE_DISPLAYSPLASH;
  964.  
  965.             // Draw the splash bitmap
  966.             g_hSplashBitmap = (HBITMAP)LoadImage( GetModuleHandle( NULL ),
  967.                                                   TEXT("SPLASH"), IMAGE_BITMAP,
  968.                                                   0, 0, LR_CREATEDIBSECTION );
  969.             SendMessage( g_hWndMain, WM_PAINT, 0, 0 );
  970.             break;
  971.  
  972.         case APPSTATE_ACTIVE:
  973.             UpdateDisplayList();
  974.             CheckForHits();
  975.  
  976.             if( IsDisplayListEmpty() )
  977.             {
  978.                 AdvanceLevel();
  979.                 g_dwAppState = APPSTATE_BEGINLEVELSCREEN;
  980.             }
  981.             break;
  982.  
  983.         case APPSTATE_BEGINLEVELSCREEN:
  984.             PlaySound( g_pBeginLevelSound );
  985.             DXUtil_Timer( TIMER_RESET );
  986.             g_dwAppState = APPSTATE_DISPLAYLEVELSCREEN;
  987.             break;
  988.  
  989.         case APPSTATE_DISPLAYLEVELSCREEN:
  990.             // Only show the Level intro screen for 3 seconds
  991.  
  992.             if( DXUtil_Timer( TIMER_GETAPPTIME ) > 3.0f )
  993.             {
  994.                 g_dwAppState = APPSTATE_ACTIVE;
  995.             }
  996.             break;
  997.     }
  998.  
  999.     return S_OK;
  1000. }
  1001.  
  1002.  
  1003.  
  1004.  
  1005. //-----------------------------------------------------------------------------
  1006. // Name: RenderFrame()
  1007. // Desc:
  1008. //-----------------------------------------------------------------------------
  1009. HRESULT RenderFrame()
  1010. {
  1011.     // Test cooperative level
  1012.     HRESULT hr;
  1013.  
  1014.     // Test the cooperative level to see if it's okay to render
  1015.     if( FAILED( hr = g_pd3dDevice->TestCooperativeLevel() ) )
  1016.     {
  1017.         // If the device was lost, do not render until we get it back
  1018.         if( D3DERR_DEVICELOST == hr )
  1019.             return S_OK;
  1020.  
  1021.         // Check if the device needs to be resized.
  1022.         if( D3DERR_DEVICENOTRESET == hr )
  1023.         {
  1024.             g_bDisplayReady = FALSE;
  1025.  
  1026.             InvalidateDisplayObjects();
  1027.  
  1028.             // Resize the device
  1029.             if( SUCCEEDED( g_pd3dDevice->Reset( &g_d3dpp ) ) )
  1030.             {
  1031.                 // Initialize the app's device-dependent objects
  1032.                 if( SUCCEEDED( RestoreDisplayObjects() ) )
  1033.                 {
  1034.                     g_bDisplayReady = TRUE;
  1035.                     return S_OK;
  1036.                 }
  1037.             }
  1038.  
  1039.             PostMessage( g_hWndMain, WM_CLOSE, 0, 0 );
  1040.         }
  1041.         return hr;
  1042.     }
  1043.  
  1044.     // Render the scene based on current state of the app
  1045.     switch( g_dwAppState )
  1046.     {
  1047.         case APPSTATE_LOADSPLASH:
  1048.             // Nothing to render while loading the splash screen
  1049.             break;
  1050.  
  1051.         case APPSTATE_DISPLAYSPLASH:
  1052.             // Rendering of the splash screen is handled by WM_PAINT
  1053.             break;
  1054.  
  1055.         case APPSTATE_BEGINLEVELSCREEN:
  1056.             // Nothing to render while starting sound to advance a level
  1057.             break;
  1058.  
  1059.         case APPSTATE_DISPLAYLEVELSCREEN:
  1060.             DisplayLevelIntroScreen( g_dwLevel );
  1061.             ShowFrame();
  1062.             break;
  1063.  
  1064.         case APPSTATE_ACTIVE:
  1065.             DrawDisplayList();
  1066.             ShowFrame();
  1067.             break;
  1068.     }
  1069.  
  1070.     return S_OK;
  1071. }
  1072.  
  1073.  
  1074.  
  1075.  
  1076. //-----------------------------------------------------------------------------
  1077. // Name: DarkenScene()
  1078. // Desc:
  1079. //-----------------------------------------------------------------------------
  1080. VOID DarkenScene( FLOAT fAmount )
  1081. {
  1082.     if( g_pd3dDevice==NULL )
  1083.         return;
  1084.  
  1085.     // Setup a dark square to cover the scene
  1086.     DWORD dwAlpha = (fAmount<1.0f) ? ((DWORD)(255*fAmount))<<24L : 0xff000000;
  1087.     SCREENVERTEX* v;
  1088.     g_pViewportVB->Lock( 0, 0, (BYTE**)&v, 0 );
  1089.     v[0].color = v[1].color = v[2].color = v[3].color = dwAlpha;
  1090.     g_pViewportVB->Unlock();
  1091.  
  1092.     // Set renderstates
  1093.     g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  1094.     g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
  1095.     g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  1096.     g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,   FALSE );
  1097.     g_pd3dDevice->SetTexture( 0, NULL );
  1098.  
  1099.     // Draw a big, gray square
  1100.     g_pd3dDevice->SetVertexShader( D3DFVF_SCREENVERTEX );
  1101.     g_pd3dDevice->SetStreamSource( 0, g_pViewportVB, sizeof(SCREENVERTEX) );
  1102.     g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,0, 2 );
  1103.  
  1104.     // Restore states
  1105.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  1106.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  1107.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  1108.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  1109.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  1110.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
  1111. }
  1112.  
  1113.  
  1114.  
  1115.  
  1116. //-----------------------------------------------------------------------------
  1117. // Name:
  1118. // Desc:
  1119. //-----------------------------------------------------------------------------
  1120. VOID RenderFieryText( CD3DFont* pFont, TCHAR* strText )
  1121. {
  1122.     if( NULL==pFont || NULL==strText )
  1123.         return;
  1124.  
  1125.     // Render the fiery portion of the text
  1126.     for( DWORD i=0; i<20; i++ )
  1127.     {
  1128.         FLOAT x = -0.5f;
  1129.         FLOAT y =  1.8f;
  1130.  
  1131.         FLOAT v1 = rnd(0.0f, 1.0f);
  1132.         FLOAT red1 = v1*v1*v1;
  1133.         FLOAT grn1 = v1*v1;
  1134.         FLOAT blu1 = v1;
  1135.  
  1136.  
  1137.         FLOAT a1 = rnd(0.0f, 2*D3DX_PI);
  1138.         FLOAT r1 = v1 * 0.05f;
  1139.  
  1140.         x += r1*sinf(a1);
  1141.         y += r1*cosf(a1);
  1142.  
  1143.         if( cosf(a1) < 0.0f )
  1144.             y -= 2*r1*cosf(a1)*cosf(a1);
  1145.  
  1146.         DWORD r = (CHAR)((1.0f-red1)*256.0f);
  1147.         DWORD g = (CHAR)((1.0f-grn1)*256.0f);
  1148.         DWORD b = (CHAR)((1.0f-blu1)*256.0f);
  1149.         DWORD a = (CHAR)255;
  1150.         DWORD dwColor = (a<<24) + (r<<16) + (g<<8) + b;
  1151.  
  1152.         g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ONE );
  1153.         g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  1154.  
  1155.         pFont->DrawTextScaled( x, y, 0.9f, 0.25f, 0.25f, dwColor, strText, D3DFONT_FILTERED );
  1156.     }
  1157.  
  1158.     // Render the plain, black portion of the text
  1159.     g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
  1160.     g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  1161.     FLOAT x = -0.5f;
  1162.     FLOAT y =  1.8f;
  1163.     pFont->DrawTextScaled( x, y, 0.9f, 0.25f, 0.25f, 0xff000000, strText, D3DFONT_FILTERED );
  1164. }
  1165.  
  1166.  
  1167.  
  1168.  
  1169. //-----------------------------------------------------------------------------
  1170. // Name: DisplayLevelIntroScreen()
  1171. // Desc:
  1172. //-----------------------------------------------------------------------------
  1173. VOID DisplayLevelIntroScreen( DWORD dwLevel )
  1174. {
  1175.     if( g_pd3dDevice==NULL )
  1176.         return;
  1177.  
  1178.     // Begin the scene
  1179.     if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
  1180.     {
  1181.         // Erase the screen
  1182.         g_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0L, 1.0f, 0L );
  1183.  
  1184.         TCHAR strLevel[80];
  1185.         _stprintf( strLevel, _T("Level %ld"), dwLevel );
  1186.         RenderFieryText( g_pGameFont, strLevel );
  1187.  
  1188.         DarkenScene( 1.0f - sinf(D3DX_PI*DXUtil_Timer( TIMER_GETAPPTIME )/3.0f) );
  1189.  
  1190.         // End the scene
  1191.         g_pd3dDevice->EndScene();
  1192.     }
  1193. }
  1194.  
  1195.  
  1196.  
  1197.  
  1198. //-----------------------------------------------------------------------------
  1199. // Name: UpdateDisplayList()
  1200. // Desc:
  1201. //-----------------------------------------------------------------------------
  1202. VOID UpdateDisplayList()
  1203. {
  1204.     DisplayObject* pObject;
  1205.  
  1206.         // Get the time lapsed since the last frame
  1207.         static FLOAT fLastTime = 0.0f;
  1208.     FLOAT fTimeLapsed = DXUtil_Timer( TIMER_GETAPPTIME ) - fLastTime;
  1209.         if( fTimeLapsed <= 0.0f )
  1210.                 fTimeLapsed = 0.01f;
  1211.         fLastTime = DXUtil_Timer( TIMER_GETAPPTIME );
  1212.  
  1213.     // Read input from the joystick/keyboard/etc
  1214.     GetInput();
  1215.  
  1216.     // Check for game menu condition
  1217.     if( g_pCurrentMenu )
  1218.     {
  1219.         UpdateMenus();
  1220.         return;
  1221.     }
  1222.  
  1223.     if( g_bPaused )
  1224.         return;
  1225.  
  1226.     if( g_pShip->fShowDelay > 0.0f )
  1227.     {
  1228.         g_pShip->fShowDelay -= fTimeLapsed;
  1229.  
  1230.         if( g_pShip->fShowDelay <= 0.0f )
  1231.         {
  1232.             g_pShip->vVel       = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  1233.             g_pShip->fShowDelay = 0.0f;
  1234.             g_pShip->bVisible   = TRUE;
  1235.             g_pShip->bExploded  = FALSE;
  1236.         }
  1237.     }
  1238.  
  1239.     // Update the ship
  1240.     if( g_pShip->bVisible )
  1241.     {
  1242.         g_pShip->vPos += g_pShip->vVel * fTimeLapsed;
  1243.     }
  1244.  
  1245.     // Apply banking motion
  1246.     g_pShip->fRoll += g_fBank * 1.0f * fTimeLapsed;
  1247.     if( g_pShip->fRoll > 0.5f )
  1248.         g_pShip->fRoll = 0.5f;
  1249.     if( g_pShip->fRoll < -0.5f )
  1250.         g_pShip->fRoll = -0.5f;
  1251.  
  1252.     g_pShip->fAngle += 5 * g_pShip->fRoll * fTimeLapsed;
  1253.  
  1254.     if( g_fBank < 0.2f && g_fBank > -0.2f )
  1255.     {
  1256.         g_pShip->fRoll *= 0.95f;
  1257.     }
  1258.  
  1259.     // Slow the ship down
  1260.     g_pShip->vVel.x *= 0.97f;
  1261.     g_pShip->vVel.y *= 0.97f;
  1262.  
  1263.     // Apply thrust
  1264.     g_pShip->vVel.x +=  sinf( g_pShip->fAngle ) * g_fThrust * 5.0f * fTimeLapsed;
  1265.     g_pShip->vVel.y += -cosf( g_pShip->fAngle ) * g_fThrust * 5.0f * fTimeLapsed;
  1266.  
  1267.     // Play thrusting sounds
  1268.     {
  1269.         static bPlayingEngineRevSound = FALSE;
  1270.  
  1271.         if( g_fThrust > 0.5f )
  1272.         {
  1273.             if( FALSE == bPlayingEngineRevSound )
  1274.             {
  1275.                 bPlayingEngineRevSound = TRUE;
  1276.             }
  1277.         }
  1278.         else
  1279.         {
  1280.             if( TRUE == bPlayingEngineRevSound )
  1281.             {
  1282.                 StopSound( g_pEngineRevSound );
  1283.                 bPlayingEngineRevSound = FALSE;
  1284.             }
  1285.         }
  1286.     }
  1287.  
  1288.     g_fBulletRechargeTime -= fTimeLapsed;
  1289.  
  1290.      // Fire a bullet
  1291.     if( g_bFiringWeapons && g_fBulletRechargeTime <= 0.0f )
  1292.     {
  1293.         // Ship must be visible and have no shields on to fire
  1294.         if( g_pShip->bVisible )
  1295.         {
  1296.             // Bullets cost one score point
  1297.             if( g_dwScore )
  1298.                 g_dwScore--;
  1299.  
  1300.             // Play the "fire" effects
  1301.             PlaySound( g_pFireBulletSound );
  1302.  
  1303.             // Add a bullet to the display list
  1304.             if( g_dwBulletType == 0 )
  1305.             {
  1306.                 D3DXVECTOR3 vDir = D3DXVECTOR3( sinf( g_pShip->fAngle ), -cosf( g_pShip->fAngle ), 0.0f );
  1307.  
  1308.                 AddToList( new CBullet( g_pShip->vPos, g_pShip->vVel + 2*vDir, 0 ) );
  1309.                 g_fBulletRechargeTime = 0.05f;
  1310.             }
  1311.             else if( g_dwBulletType == 1 )
  1312.             {
  1313.                 D3DXVECTOR3 vOffset = 0.02f * D3DXVECTOR3( cosf(g_pShip->fAngle), sinf(g_pShip->fAngle), 0.0f );
  1314.                 D3DXVECTOR3 vDir = D3DXVECTOR3( sinf( g_pShip->fAngle ), -cosf( g_pShip->fAngle ), 0.0f );
  1315.  
  1316.                 AddToList( new CBullet( g_pShip->vPos + vOffset, g_pShip->vVel + 2*vDir, 1 ) );
  1317.                 AddToList( new CBullet( g_pShip->vPos - vOffset, g_pShip->vVel + 2*vDir, 1 ) );
  1318.                 g_fBulletRechargeTime = 0.10f;
  1319.             }
  1320.             else if( g_dwBulletType == 2 )
  1321.             {
  1322.                 FLOAT fBulletAngle = g_pShip->fAngle + 0.2f*rnd();
  1323.                 D3DXVECTOR3 vDir = D3DXVECTOR3( sinf(fBulletAngle), -cosf(fBulletAngle), 0.0f );
  1324.  
  1325.                 AddToList( new CBullet( g_pShip->vPos, g_pShip->vVel + 2*vDir, 2 ) );
  1326.                 g_fBulletRechargeTime = 0.01f;
  1327.             }
  1328.             else
  1329.             {
  1330.                 for( DWORD i=0; i<50; i++ )
  1331.                 {
  1332.                     FLOAT fBulletAngle = g_pShip->fAngle + D3DX_PI*rnd();
  1333.                     D3DXVECTOR3 vDir = D3DXVECTOR3( sinf(fBulletAngle), -cosf(fBulletAngle), 0.0f );
  1334.  
  1335.                     AddToList( new CBullet( g_pShip->vPos, 2*vDir, 3 ) );
  1336.                 }
  1337.  
  1338.                 g_fBulletRechargeTime = 1.0f;
  1339.             }
  1340.         }
  1341.     }
  1342.  
  1343.     // Keep ship in bounds
  1344.     if( g_pShip->vPos.x < -5.0f || g_pShip->vPos.x > +5.0f ||
  1345.         g_pShip->vPos.y < -5.0f || g_pShip->vPos.y > +5.0f )
  1346.     {
  1347.          D3DXVec3Normalize( &g_pShip->vVel, &g_pShip->vPos );
  1348.          g_pShip->vVel.x *= -1.0f;
  1349.          g_pShip->vVel.y *= -1.0f;
  1350.          g_pShip->vVel.z *= -1.0f;
  1351.     }
  1352.  
  1353.     // Finally, move all objects on the screen
  1354.     for( pObject = g_pDisplayList; pObject; pObject = pObject->pNext )
  1355.     {
  1356.         // The ship is moved by the code above
  1357.         if( pObject->dwType == OBJ_SHIP )
  1358.             continue;
  1359.  
  1360.         C3DSprite* pSprite = (C3DSprite*)pObject;
  1361.  
  1362.         // Update the position and animation frame
  1363.         pSprite->vPos  += pSprite->vVel * fTimeLapsed;
  1364.         pSprite->frame += pSprite->delay * fTimeLapsed;
  1365.  
  1366.         // If this is an "expired" cloud, removed it from list
  1367.         if( pObject->dwType == OBJ_CLOUD )
  1368.         {
  1369.             if( pSprite->frame >= pSprite->fMaxFrame )
  1370.             {
  1371.                 DisplayObject* pVictim = pObject;
  1372.                 pObject = pObject->pPrev;
  1373.                 DeleteFromList( pVictim );
  1374.             }
  1375.         }
  1376.         else if( pObject->dwType == OBJ_BULLET )
  1377.         {
  1378.             // Remove bullets when they leave the scene
  1379.             if( pObject->vPos.x < -6.0f || pObject->vPos.x > +6.0f ||
  1380.                 pObject->vPos.y < -6.0f || pObject->vPos.y > +6.0f )
  1381.             {
  1382.                 DisplayObject* pVictim = pObject;
  1383.                 pObject = pObject->pPrev;
  1384.                 DeleteFromList( pVictim );
  1385.             }
  1386.         }
  1387.         else if( pObject->dwType != OBJ_CLOUD )
  1388.         {
  1389.             // Keep object in bounds in X
  1390.             if( pObject->vPos.x < -4.0f || pObject->vPos.x > +4.0f )
  1391.             {
  1392.                 if( pObject->vPos.x < -4.0f ) pObject->vPos.x = -4.0f;
  1393.                 if( pObject->vPos.x > +4.0f ) pObject->vPos.x = +4.0f;
  1394.                 pObject->vVel.x = -pObject->vVel.x;
  1395.             }
  1396.  
  1397.             // Keep object in bounds in Y
  1398.             if( pObject->vPos.y < -4.0f || pObject->vPos.y > +4.0f )
  1399.             {
  1400.                 if( pObject->vPos.y < -4.0f ) pObject->vPos.y = -4.0f;
  1401.                 if( pObject->vPos.y > +4.0f ) pObject->vPos.y = +4.0f;
  1402.                 pObject->vVel.y = -pObject->vVel.y;
  1403.             }
  1404.  
  1405.             // Keep animation frame in bounds
  1406.             if( pSprite->frame < 0.0f )
  1407.                 pSprite->frame += pSprite->fMaxFrame;
  1408.             if( pSprite->frame >= pSprite->fMaxFrame )
  1409.                 pSprite->frame -= pSprite->fMaxFrame;
  1410.         }
  1411.     }
  1412.  
  1413.     D3DXVECTOR3 vEyePt[NUMVIEWMODES];
  1414.     D3DXVECTOR3 vLookatPt[NUMVIEWMODES];
  1415.     D3DXVECTOR3 vUpVec[NUMVIEWMODES];
  1416.  
  1417.     // Update the view
  1418.     if( g_bChangeView )
  1419.     {
  1420.         g_bAnimatingViewChange = TRUE;
  1421.         g_bChangeView = FALSE;
  1422.     }
  1423.  
  1424.     if( g_bAnimatingViewChange )
  1425.     {
  1426.         g_fViewTransition += fTimeLapsed;
  1427.  
  1428.         if( g_fViewTransition >= 1.0f )
  1429.         {
  1430.             g_dwViewMode++;
  1431.             if( g_dwViewMode >= NUMVIEWMODES )
  1432.                 g_dwViewMode = 0;
  1433.  
  1434.             g_fViewTransition      = 0.0f;
  1435.             g_bAnimatingViewChange = FALSE;
  1436.         }
  1437.     }
  1438.  
  1439.     FLOAT fX =  g_pShip->vPos.x;
  1440.     FLOAT fZ = -g_pShip->vPos.y;
  1441.     FLOAT fY = 0.1f + HeightField( fX, fZ );
  1442.  
  1443.     // View mode 0 (third person)
  1444.     vEyePt[0]      = D3DXVECTOR3( fX-sinf(g_pShip->fAngle)/2, fY+0.2f, fZ-cosf(g_pShip->fAngle)/2 );
  1445.     vLookatPt[0]   = D3DXVECTOR3( fX+sinf(g_pShip->fAngle)/2, fY, fZ+cosf(g_pShip->fAngle)/2 );
  1446.     vUpVec[0]      = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  1447.  
  1448.     // View mode 1 (first person)
  1449.     FLOAT fX2 = fX+sinf(g_pShip->fAngle);
  1450.     FLOAT fZ2 = fZ+cosf(g_pShip->fAngle);
  1451.     FLOAT fY2 = 0.1f + HeightField( fX2, fZ2 );
  1452.     vEyePt[1]    = D3DXVECTOR3( fX, fY+0.1f, fZ );
  1453.     vLookatPt[1] = D3DXVECTOR3( fX2, fY2+0.1f, fZ2 );
  1454.     vUpVec[1]    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  1455.  
  1456.     // View mode 2 (top down view)
  1457.     vEyePt[2]    = D3DXVECTOR3( fX+1.5f, fY+1.5f, fZ+1.5f );
  1458.     vLookatPt[2] = D3DXVECTOR3( fX, fY, fZ );
  1459.     vUpVec[2]    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  1460.  
  1461.     DWORD start = g_dwViewMode;
  1462.     DWORD end   = ( start < (NUMVIEWMODES-1) ) ? g_dwViewMode+1: 0;
  1463.  
  1464.     if( start == 1 && g_fViewTransition<0.2f)
  1465.         g_bFirstPersonView = TRUE;
  1466.     else
  1467.         g_bFirstPersonView = FALSE;
  1468.  
  1469.     D3DXVECTOR3 vEyePt0    = (1.0f-g_fViewTransition)*vEyePt[start]    + g_fViewTransition*vEyePt[end];
  1470.     D3DXVECTOR3 vLookatPt0 = (1.0f-g_fViewTransition)*vLookatPt[start] + g_fViewTransition*vLookatPt[end];
  1471.     D3DXVECTOR3 vUpVec0    = (1.0f-g_fViewTransition)*vUpVec[start]    + g_fViewTransition*vUpVec[end];
  1472.  
  1473.     // Shake screen if ship exploded
  1474.     if( g_pShip->bExploded == TRUE )
  1475.         vEyePt0 += D3DXVECTOR3( rnd(), rnd(), rnd() ) * g_pShip->fShowDelay / 50.0f;
  1476.  
  1477.     g_Camera.SetViewParams( vEyePt0, vLookatPt0, vUpVec0 );
  1478. }
  1479.  
  1480.  
  1481.  
  1482.  
  1483. //-----------------------------------------------------------------------------
  1484. // Name: CheckForHits()
  1485. // Desc:
  1486. //-----------------------------------------------------------------------------
  1487. VOID CheckForHits()
  1488. {
  1489.     DisplayObject* pObject;
  1490.     DisplayObject* pBullet;
  1491.  
  1492.     for( pBullet = g_pDisplayList; pBullet; pBullet = pBullet->pNext )
  1493.     {
  1494.         BOOL bBulletHit = FALSE;
  1495.  
  1496.         // Only bullet objects and the ship (if shieleds are on) can hit
  1497.         // other objects. Skip all others.
  1498.         if( (pBullet->dwType != OBJ_BULLET) && (pBullet->dwType != OBJ_SHIP) )
  1499.             continue;
  1500.  
  1501.         for( pObject = g_pDisplayList->pNext; pObject; pObject = pObject->pNext )
  1502.         {
  1503.             // Only trying to hit explodable targets
  1504.             if( ( pObject->dwType != OBJ_DONUT ) &&
  1505.                 ( pObject->dwType != OBJ_PYRAMID ) &&
  1506.                 ( pObject->dwType != OBJ_SPHERE ) &&
  1507.                 ( pObject->dwType != OBJ_CUBE ) )
  1508.                 continue;
  1509.  
  1510.             // Check if bullet is in radius of object
  1511.             FLOAT fDistance = D3DXVec3Length( &(pBullet->vPos - pObject->vPos) );
  1512.  
  1513.             if( fDistance < (pObject->fSize+pBullet->fSize) )
  1514.             {
  1515.                 // The object was hit
  1516.                 switch( pObject->dwType )
  1517.                 {
  1518.                     case OBJ_DONUT:
  1519.                         PlaySound( g_pDonutExplodeSound );
  1520.                         AddToList( new CPyramid( pObject->vPos, pObject->vVel ) );
  1521.                         AddToList( new CPyramid( pObject->vPos, pObject->vVel ) );
  1522.                         AddToList( new CPyramid( pObject->vPos, pObject->vVel ) );
  1523.                         AddToList( new CPyramid( pObject->vPos, pObject->vVel ) );
  1524.                         g_dwScore += 10;
  1525.                         break;
  1526.  
  1527.                     case OBJ_PYRAMID:
  1528.                         PlaySound( g_pPyramidExplodeSound );
  1529.                         AddToList( new CCube( pObject->vPos, pObject->vVel ) );
  1530.                         AddToList( new CCube( pObject->vPos, pObject->vVel ) );
  1531.                         AddToList( new CCube( pObject->vPos, pObject->vVel ) );
  1532.                         AddToList( new CCube( pObject->vPos, pObject->vVel ) );
  1533.                         g_dwScore += 20;
  1534.                         break;
  1535.  
  1536.                     case OBJ_CUBE:
  1537.                         PlaySound( g_pCubeExplodeSound );
  1538.                         AddToList( new CSphere( pObject->vPos, pObject->vVel ) );
  1539.                         g_dwScore += 40;
  1540.                         break;
  1541.  
  1542.                     case OBJ_SPHERE:
  1543.                         PlaySound( g_pSphereExplodeSound );
  1544.                         g_dwScore += 20;
  1545.                         break;
  1546.                 }
  1547.  
  1548.                 // Add explosion effects to scene
  1549.                 for( DWORD c=0; c<4; c++ )
  1550.                     AddToList( new CCloud( pObject->vPos, 0.05f*D3DXVECTOR3(rnd(),rnd(),0.0f) ) );
  1551.  
  1552.                 // Remove the victim from the scene
  1553.                 DisplayObject* pVictim = pObject;
  1554.                 pObject = pObject->pPrev;
  1555.                 DeleteFromList( pVictim );
  1556.  
  1557.                 bBulletHit = TRUE;
  1558.             }
  1559.  
  1560.             if( bBulletHit )
  1561.             {
  1562.                 if( pBullet->dwType == OBJ_SHIP )
  1563.                 {
  1564.                     bBulletHit = FALSE;
  1565.  
  1566.                     if( g_pShip->bVisible )
  1567.                     {
  1568.                         // Ship has exploded
  1569.                         PlaySound( g_pShipExplodeSound );
  1570.  
  1571.                         if( g_dwScore < 150 )
  1572.                             g_dwScore = 0;
  1573.                         else
  1574.                             g_dwScore -= 150;
  1575.  
  1576.                         // Add explosion debris to scene
  1577.                         for( DWORD sphere=0; sphere<4; sphere++ )
  1578.                             AddToList( new CSphere( g_pShip->vPos, pObject->vVel ) );
  1579.  
  1580.                         for( DWORD bullet=0; bullet<20; bullet++ )
  1581.                         {
  1582.                             FLOAT     angle     = D3DX_PI * rnd();
  1583.                             D3DVECTOR vDir      = D3DXVECTOR3(cosf(angle),sinf(angle),0.0f);
  1584.                             AddToList( new CBullet( g_pShip->vPos, 500.0f*vDir, 0 ) );
  1585.                         }
  1586.  
  1587.                         for( DWORD cloud=0; cloud<100; cloud++ )
  1588.                         {
  1589.                             FLOAT     magnitude = 1.0f + 0.1f*rnd();
  1590.                             FLOAT     angle     = D3DX_PI * rnd();
  1591.                             D3DVECTOR vDir      = D3DXVECTOR3(cosf(angle),sinf(angle),0.0f);
  1592.  
  1593.                             AddToList( new CCloud( g_pShip->vPos, magnitude*vDir ) );
  1594.                         }
  1595.  
  1596.                         // Clear out ship params
  1597.                         g_pShip->vVel.x = 0.0f;
  1598.                         g_pShip->vVel.y = 0.0f;
  1599.                         g_fThrust       = 0.0f;
  1600.                         g_fBank         = 0.0f;
  1601.  
  1602.                         // Delay for 2 seconds before displaying ship
  1603.                         g_pShip->fShowDelay = 2.0f;
  1604.                         g_pShip->bVisible   = FALSE;
  1605.                         g_pShip->bExploded  = TRUE;
  1606.                     }
  1607.                 }
  1608.  
  1609.                 break;
  1610.             }
  1611.         }
  1612.  
  1613.         if( bBulletHit )
  1614.         {
  1615.             DisplayObject* pLastBullet = pBullet;
  1616.             pBullet = pBullet->pPrev;
  1617.             DeleteFromList( pLastBullet );
  1618.         }
  1619.     }
  1620. }
  1621.  
  1622.  
  1623.  
  1624.  
  1625. //-----------------------------------------------------------------------------
  1626. // Name: DrawDisplayList()
  1627. // Desc:
  1628. //-----------------------------------------------------------------------------
  1629. VOID DrawDisplayList()
  1630. {
  1631.     TCHAR strBuffer[80];
  1632.  
  1633.     // Set the world matrix
  1634.     D3DXMATRIX matWorld;
  1635.     D3DXMatrixIdentity( &matWorld );
  1636.     g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  1637.  
  1638.     // Set the app view matrix for normal viewing
  1639.     g_pd3dDevice->SetTransform( D3DTS_VIEW, &g_Camera.GetViewMatrix() );
  1640.  
  1641.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  1642.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  1643.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  1644.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  1645.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
  1646.     g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  1647.     g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
  1648.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  1649.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  1650.     g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  1651.     g_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, FALSE );
  1652.     g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1653.     g_pd3dDevice->SetRenderState( D3DRS_LIGHTING,     TRUE );
  1654.     g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x33333333 );
  1655.  
  1656.     // Begin the scene
  1657.     if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
  1658.     {
  1659.         // Clear the display
  1660.         g_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0L, 1.0f, 0L );
  1661.  
  1662.         // Draw the terrain
  1663.         g_pTerrain->Render( g_pd3dDevice );
  1664.  
  1665.         // Render the ship
  1666.         if( g_pShip->bVisible && g_bFirstPersonView == FALSE )
  1667.         {
  1668.             // Point of ship, on terrain
  1669.             D3DXVECTOR3 vShipPt;
  1670.             vShipPt.x =  g_pShip->vPos.x;
  1671.             vShipPt.z = -g_pShip->vPos.y;
  1672.             vShipPt.y = 0.1f + HeightField( vShipPt.x, vShipPt.z );
  1673.  
  1674.             // Point ahead of ship, on terrain
  1675.             D3DXVECTOR3 vForwardPt;
  1676.             vForwardPt.x = vShipPt.x+sinf(g_pShip->fAngle);
  1677.             vForwardPt.z = vShipPt.z+cosf(g_pShip->fAngle);
  1678.             vForwardPt.y = 0.1f + HeightField( vForwardPt.x, vForwardPt.z );
  1679.  
  1680.             // Point to side of ship, on terrain
  1681.             D3DXVECTOR3 vSidePt;
  1682.             vSidePt.x = vShipPt.x+sinf(g_pShip->fAngle + D3DX_PI/2.0f);
  1683.             vSidePt.z = vShipPt.z+cosf(g_pShip->fAngle + D3DX_PI/2.0f);
  1684.             vSidePt.y = 0.1f + HeightField( vSidePt.x, vSidePt.z );
  1685.  
  1686.             // Compute vectors of the ship's orientation
  1687.             D3DXVECTOR3 vForwardDir = vForwardPt - vShipPt;
  1688.             D3DXVECTOR3 vSideDir    = vSidePt - vShipPt;
  1689.             D3DXVECTOR3 vNormalDir;
  1690.             D3DXVec3Cross( &vNormalDir, &vForwardDir, &vSideDir );
  1691.  
  1692.             // Construct matrix to orient ship
  1693.             D3DXMATRIX matWorld, matLookAt, matRotateZ;
  1694.             D3DXMatrixRotationZ( &matRotateZ, g_pShip->fRoll );
  1695.             D3DXMatrixLookAtLH( &matLookAt, &vShipPt, &(vShipPt-vForwardDir), &vNormalDir );
  1696.             D3DXMatrixInverse( &matLookAt, NULL, &matLookAt );
  1697.             D3DXMatrixIdentity( &matWorld );
  1698.             D3DXMatrixMultiply( &matWorld, &matWorld, &matRotateZ );
  1699.             D3DXMatrixMultiply( &matWorld, &matWorld, &matLookAt );
  1700.  
  1701.             // Set renderstates for rendering the ship
  1702.             g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  1703.             g_pd3dDevice->SetRenderState( D3DRS_LIGHTING,           TRUE );
  1704.             g_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS,   TRUE );
  1705.             g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   FALSE );
  1706.             g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,    FALSE );
  1707.  
  1708.             // Render the ship - opaque parts
  1709.             g_pShipFileObject->Render( g_pd3dDevice, TRUE, FALSE );
  1710.  
  1711.             // Render the ship - transparent parts
  1712.             g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE );
  1713.             g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  1714.             g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,     D3DBLEND_ONE );
  1715.             g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,    D3DBLEND_ONE );
  1716.             g_pShipFileObject->Render( g_pd3dDevice, FALSE, TRUE );
  1717.             g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  1718.         }
  1719.  
  1720.         // Remaining objects don't need lighting
  1721.         g_pd3dDevice->SetRenderState( D3DRS_LIGHTING,           FALSE );
  1722.  
  1723.         // Enable alpha blending and testing
  1724.         g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  1725.         g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
  1726.         g_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
  1727.         g_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
  1728.  
  1729.         // Display all visible objects in the display list
  1730.         for( DisplayObject* pObject = g_pDisplayList; pObject; pObject = pObject->pNext )
  1731.         {
  1732.             if( !pObject->bVisible )
  1733.                 continue;
  1734.             if( pObject->dwType == OBJ_SHIP )
  1735.                 continue;
  1736.             if( pObject->dwType == OBJ_BULLET )
  1737.                 continue;
  1738.  
  1739.             // This is really a 3D sprite
  1740.             C3DSprite* pSprite = (C3DSprite*)pObject;
  1741.  
  1742.             FLOAT fX =  pObject->vPos.x;
  1743.             FLOAT fZ = -pObject->vPos.y;
  1744.             FLOAT fY =  HeightField( fX, fZ );
  1745.  
  1746.             FLOAT x1 = -pObject->fSize;
  1747.             FLOAT x2 =  pObject->fSize;
  1748.             FLOAT y1 = -pObject->fSize;
  1749.             FLOAT y2 =  pObject->fSize;
  1750.  
  1751.             FLOAT u1 = (FLOAT)(pSprite->dwTextureOffsetX + pSprite->dwTextureWidth *(((int)pSprite->frame)%pSprite->dwFramesPerLine));
  1752.             FLOAT v1 = (FLOAT)(pSprite->dwTextureOffsetY + pSprite->dwTextureHeight*(((int)pSprite->frame)/pSprite->dwFramesPerLine));
  1753.  
  1754.             FLOAT tu1 = u1 / (256.0f-1.0f);
  1755.             FLOAT tv1 = v1 / (256.0f-1.0f);
  1756.             FLOAT tu2 = (u1 + pSprite->dwTextureWidth -1) / (256.0f-1.0f);
  1757.             FLOAT tv2 = (v1 + pSprite->dwTextureHeight-1) / (256.0f-1.0f);
  1758.  
  1759.             // Set the game texture
  1760.             switch( pObject->dwType )
  1761.             {
  1762.                 case OBJ_DONUT:
  1763.                 case OBJ_CUBE:
  1764.                 case OBJ_SPHERE:
  1765.                     g_pd3dDevice->SetTexture( 0, g_pGameTexture1 );
  1766.                     break;
  1767.                 case OBJ_PYRAMID:
  1768.                 case OBJ_CLOUD:
  1769.                     g_pd3dDevice->SetTexture( 0, g_pGameTexture2 );
  1770.                     break;
  1771.             }
  1772.  
  1773.             // Translate the billboard into place
  1774.             D3DXMATRIX mat = g_Camera.GetBillboardMatrix();
  1775.             mat._41 = fX;
  1776.             mat._42 = fY;
  1777.             mat._43 = fZ;
  1778.             g_pd3dDevice->SetTransform( D3DTS_WORLD, &mat );
  1779.  
  1780.             DWORD dwColor = pSprite->dwColor;
  1781.  
  1782.             g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
  1783.             g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  1784.             g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1785.             g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  1786.  
  1787.             if( pObject->dwType == OBJ_CLOUD )
  1788.             {
  1789.                 DWORD red = 255-(int)(pSprite->frame*255.0f);
  1790.                 DWORD grn = 255-(int)(pSprite->frame*511.0f);
  1791.                 DWORD blu = 255-(int)(pSprite->frame*1023.0f);
  1792.                 if( grn > 255 ) grn = 0;
  1793.                 if( blu > 255 ) blu = 0;
  1794.                 dwColor = 0xff000000 + (red<<16) + (grn<<8) + blu;
  1795.  
  1796.                 g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ONE );
  1797.                 g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  1798.                 g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1799.                 g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  1800.             }
  1801.  
  1802.             FLOAT h = 300.0f*pObject->vPos.z + 0.1f;
  1803.  
  1804.             SPRITEVERTEX* v;
  1805.             g_pSpriteVB->Lock( 0, 0, (BYTE**)&v, 0 );
  1806.             v[0].p = D3DXVECTOR3(x1,y1+h,0); v[0].color=dwColor; v[0].tu=tu1; v[0].tv=tv2;
  1807.             v[1].p = D3DXVECTOR3(x1,y2+h,0); v[1].color=dwColor; v[1].tu=tu1; v[1].tv=tv1;
  1808.             v[2].p = D3DXVECTOR3(x2,y1+h,0); v[2].color=dwColor; v[2].tu=tu2; v[2].tv=tv2;
  1809.             v[3].p = D3DXVECTOR3(x2,y2+h,0); v[3].color=dwColor; v[3].tu=tu2; v[3].tv=tv1;
  1810.             g_pSpriteVB->Unlock();
  1811.  
  1812.             // Render the billboarded sprite
  1813.             g_pd3dDevice->SetVertexShader( D3DFVF_SPRITEVERTEX );
  1814.             g_pd3dDevice->SetStreamSource( 0, g_pSpriteVB, sizeof(SPRITEVERTEX) );
  1815.             g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
  1816.         }
  1817.  
  1818.         // Display all bullets
  1819.         for( pObject = g_pDisplayList; pObject; pObject = pObject->pNext )
  1820.         {
  1821.             if( pObject->dwType != OBJ_BULLET )
  1822.                 continue;
  1823.  
  1824.             // This is really a 3D sprite
  1825.             C3DSprite* pSprite = (C3DSprite*)pObject;
  1826.  
  1827.             FLOAT u1 = (FLOAT)(pSprite->dwTextureOffsetX + pSprite->dwTextureWidth *(((int)pSprite->frame)%pSprite->dwFramesPerLine));
  1828.             FLOAT v1 = (FLOAT)(pSprite->dwTextureOffsetY + pSprite->dwTextureHeight*(((int)pSprite->frame)/pSprite->dwFramesPerLine));
  1829.             u1 = (FLOAT)(pSprite->dwTextureOffsetX);
  1830.             v1 = (FLOAT)(pSprite->dwTextureOffsetY);
  1831.  
  1832.             FLOAT tu1 = u1 / (256.0f-1.0f);
  1833.             FLOAT tv1 = v1 / (256.0f-1.0f);
  1834.             FLOAT tu2 = (u1 + pSprite->dwTextureWidth -1) / (256.0f-1.0f);
  1835.             FLOAT tv2 = (v1 + pSprite->dwTextureHeight-1) / (256.0f-1.0f);
  1836.  
  1837.             // Set render states
  1838.             g_pd3dDevice->SetTexture( 0, g_pGameTexture2 );
  1839.             g_pd3dDevice->SetVertexShader( D3DFVF_SPRITEVERTEX );
  1840.             g_pd3dDevice->SetStreamSource( 0, g_pSpriteVB, sizeof(SPRITEVERTEX) );
  1841.             g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,     D3DBLEND_ONE );
  1842.             g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,    D3DBLEND_ONE );
  1843.             g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1844.             g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  1845.  
  1846.             FLOAT x1 = -0.01f;
  1847.             FLOAT x2 =  0.01f;
  1848.             FLOAT y1 = -0.01f;
  1849.             FLOAT y2 =  0.01f;
  1850.  
  1851.             DWORD dwColor = pSprite->dwColor;
  1852.  
  1853.             for( DWORD a=0; a<6; a++ )
  1854.             {
  1855.                 FLOAT fX =  pObject->vPos.x - a*a*0.0005f*pObject->vVel.x;
  1856.                 FLOAT fZ = -pObject->vPos.y + a*a*0.0005f*pObject->vVel.y;
  1857.                 FLOAT fY =  HeightField( fX, fZ );
  1858.  
  1859.                 // Translate the billboard into place
  1860.                 D3DXMATRIX mat = g_Camera.GetBillboardMatrix();
  1861.                 mat._41 = fX;
  1862.                 mat._42 = fY;
  1863.                 mat._43 = fZ;
  1864.                 g_pd3dDevice->SetTransform( D3DTS_WORLD, &mat );
  1865.  
  1866.                 FLOAT h = 300.0f*pObject->vPos.z + 0.1f;
  1867.  
  1868.                 SPRITEVERTEX* v;
  1869.                 g_pSpriteVB->Lock( 0, 0, (BYTE**)&v, 0 );
  1870.                 v[0].p = D3DXVECTOR3(x1,y1+h,0); v[0].color=dwColor; v[0].tu=tu1; v[0].tv=tv2;
  1871.                 v[1].p = D3DXVECTOR3(x1,y2+h,0); v[1].color=dwColor; v[1].tu=tu1; v[1].tv=tv1;
  1872.                 v[2].p = D3DXVECTOR3(x2,y1+h,0); v[2].color=dwColor; v[2].tu=tu2; v[2].tv=tv2;
  1873.                 v[3].p = D3DXVECTOR3(x2,y2+h,0); v[3].color=dwColor; v[3].tu=tu2; v[3].tv=tv1;
  1874.                 g_pSpriteVB->Unlock();
  1875.  
  1876.                 // Render the billboarded sprite
  1877.                 g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
  1878.             }
  1879.         }
  1880.  
  1881.         // Restore state
  1882.         g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1883.         g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  1884.  
  1885.         // Display score
  1886.         _stprintf( strBuffer, _T("Score: %08ld"), g_dwScore );
  1887.         g_pGameFont->DrawTextScaled( -1.0f, 1.0f, 0.9f, 0.05f, 0.05f,
  1888.                                      0xffffff00, strBuffer, D3DFONT_FILTERED );
  1889.  
  1890.         // Display ship type
  1891.         _stprintf( strBuffer, _T("Ship: %s"), g_strShipNames[g_dwCurrentShipType] );
  1892.         g_pGameFont->DrawTextScaled( 0.0f, 1.0f, 0.9f, 0.05f, 0.05f,
  1893.                                      0xffffff00, strBuffer, D3DFONT_FILTERED );
  1894.  
  1895.         // Display weapon type
  1896.         TCHAR* strWeapon;
  1897.         if( g_dwBulletType == 0 )      strWeapon = _T("Weapon: Blaster");
  1898.         else if( g_dwBulletType == 1 ) strWeapon = _T("Weapon: Double blaster");
  1899.         else if( g_dwBulletType == 2 ) strWeapon = _T("Weapon: Spray gun");
  1900.         else                           strWeapon = _T("Weapon: Proximity killer");
  1901.         g_pGameFont->DrawTextScaled( 0.0f, 1.1f, 0.9f, 0.05f, 0.05f,
  1902.                                      0xffffff00, strWeapon, D3DFONT_FILTERED );
  1903.  
  1904.         // Render "Paused" text if game is paused
  1905.         if( g_bPaused && g_pGameFont )
  1906.         {
  1907.             DarkenScene( 0.5f );
  1908.             RenderFieryText( g_pMenuFont, _T("Paused") );
  1909.         }
  1910.  
  1911.         if( g_pShip->fShowDelay > 0.0f )
  1912.             DarkenScene( g_pShip->fShowDelay/2.0f );
  1913.  
  1914.         // Render game menu
  1915.         if( g_pCurrentMenu )
  1916.         {
  1917.             DarkenScene( 0.5f );
  1918.             g_pCurrentMenu->Render( g_pd3dDevice, g_pMenuFont );
  1919.         }
  1920.  
  1921.         g_pd3dDevice->EndScene();
  1922.     }
  1923. }
  1924.  
  1925.  
  1926.  
  1927.  
  1928. //-----------------------------------------------------------------------------
  1929. // Name: DeleteFromList()
  1930. // Desc:
  1931. //-----------------------------------------------------------------------------
  1932. VOID DeleteFromList( DisplayObject* pObject )
  1933. {
  1934.     if( pObject->pNext )
  1935.         pObject->pNext->pPrev = pObject->pPrev;
  1936.     if( pObject->pPrev )
  1937.         pObject->pPrev->pNext = pObject->pNext;
  1938.     delete( pObject );
  1939. }
  1940.  
  1941.  
  1942.  
  1943.  
  1944. //-----------------------------------------------------------------------------
  1945. // Name:
  1946. // Desc:
  1947. //-----------------------------------------------------------------------------
  1948. VOID ConstructMenus()
  1949. {
  1950.     // Build video sub menu
  1951.     CMenuItem* pVideoSubMenu = new CMenuItem( _T("Video Menu"), MENU_VIDEO );
  1952.     pVideoSubMenu->Add( new CMenuItem( _T("Windowed"), MENU_WINDOWED ) );
  1953.     pVideoSubMenu->Add( new CMenuItem( _T("640x480"),  MENU_640x480 ) );
  1954.     pVideoSubMenu->Add( new CMenuItem( _T("800x600"),  MENU_800x600 ) );
  1955.     pVideoSubMenu->Add( new CMenuItem( _T("1024x768"), MENU_1024x768 ) );
  1956.     pVideoSubMenu->Add( new CMenuItem( _T("Back"),     MENU_BACK ) );
  1957.  
  1958.     // Build sound menu
  1959.     CMenuItem* pSoundSubMenu = new CMenuItem( _T("Sound Menu"), MENU_SOUND );
  1960.     pSoundSubMenu->Add( new CMenuItem( _T("Sound On"),  MENU_SOUNDON ) );
  1961.     pSoundSubMenu->Add( new CMenuItem( _T("Sound Off"), MENU_SOUNDOFF ) );
  1962.     pSoundSubMenu->Add( new CMenuItem( _T("Back"),      MENU_BACK ) );
  1963.  
  1964.     // Build input menu
  1965.     CMenuItem* pInputSubMenu = new CMenuItem( _T("Input Menu"), MENU_INPUT );
  1966.     pInputSubMenu->Add( new CMenuItem( _T("View Devices"),   MENU_VIEWDEVICES ) );
  1967.     pInputSubMenu->Add( new CMenuItem( _T("Config Devices"), MENU_CONFIGDEVICES ) );
  1968.     pInputSubMenu->Add( new CMenuItem( _T("Back"),           MENU_BACK ) );
  1969.  
  1970.     // Build main menu
  1971.     g_pMainMenu = new CMenuItem( _T("Main Menu"),  MENU_MAIN );
  1972.     g_pMainMenu->Add( pVideoSubMenu );
  1973.     g_pMainMenu->Add( pSoundSubMenu );
  1974.     g_pMainMenu->Add( pInputSubMenu );
  1975.     g_pMainMenu->Add( new CMenuItem( _T("Back to Game"), MENU_BACK ) );
  1976.  
  1977.     // Build "quit game?" menu
  1978.     g_pQuitMenu = new CMenuItem( _T("Quit Game?"),  MENU_MAIN );
  1979.     g_pQuitMenu->Add( new CMenuItem( _T("Yes"),     MENU_QUIT ) );
  1980.     g_pQuitMenu->Add( new CMenuItem( _T("No"),      MENU_BACK ) );
  1981.  
  1982.     return;
  1983. }
  1984.  
  1985.  
  1986.  
  1987.  
  1988. //-----------------------------------------------------------------------------
  1989. // Name:
  1990. // Desc:
  1991. //-----------------------------------------------------------------------------
  1992. VOID DestroyMenus()
  1993. {
  1994.     SAFE_DELETE( g_pQuitMenu );
  1995.     SAFE_DELETE( g_pMainMenu );
  1996. }
  1997.  
  1998.  
  1999.  
  2000.  
  2001. //-----------------------------------------------------------------------------
  2002. // Name: UpdateMenus()
  2003. // Desc:
  2004. //-----------------------------------------------------------------------------
  2005. VOID UpdateMenus()
  2006. {
  2007.     if( g_pCurrentMenu == NULL )
  2008.         return;
  2009.  
  2010.     // Keep track of current selected menu, to check later for changes
  2011.     DWORD dwCurrentSelectedMenu = g_pCurrentMenu->dwSelectedMenu;
  2012.  
  2013.     // Check for menu up/down input
  2014.     if( g_bMenuUp )
  2015.     {
  2016.         if( g_pCurrentMenu->dwSelectedMenu > 0 )
  2017.             g_pCurrentMenu->dwSelectedMenu--;
  2018.     }
  2019.     else if( g_bMenuDown )
  2020.     {
  2021.         if( (g_pCurrentMenu->dwSelectedMenu+1) < g_pCurrentMenu->dwNumChildren )
  2022.             g_pCurrentMenu->dwSelectedMenu++;
  2023.     }
  2024.  
  2025.     // The the current menu changed, play a sound
  2026.     if( dwCurrentSelectedMenu != g_pCurrentMenu->dwSelectedMenu )
  2027.         PlaySound( g_pSphereExplodeSound );
  2028.  
  2029.     if( g_bMenuSelect )
  2030.     {
  2031.         PlaySound( g_pSphereExplodeSound );
  2032.  
  2033.         DWORD dwID = g_pCurrentMenu->pChild[g_pCurrentMenu->dwSelectedMenu]->dwID;
  2034.  
  2035.         switch( dwID )
  2036.         {
  2037.             case MENU_BACK:
  2038.                 g_pCurrentMenu = g_pCurrentMenu->pParent;
  2039.                 break;
  2040.  
  2041.             case MENU_VIDEO:
  2042.             case MENU_SOUND:
  2043.             case MENU_INPUT:
  2044.                 g_pCurrentMenu = g_pCurrentMenu->pChild[g_pCurrentMenu->dwSelectedMenu];
  2045.                 break;
  2046.  
  2047.             case MENU_WINDOWED:
  2048.                 SwitchDisplayModes( FALSE, 0L, 0L );
  2049.                 g_pCurrentMenu = NULL;
  2050.                 break;
  2051.  
  2052.             case MENU_640x480:
  2053.                 SwitchDisplayModes( TRUE, 640, 480 );
  2054.                 g_pCurrentMenu = NULL;
  2055.                 break;
  2056.  
  2057.             case MENU_800x600:
  2058.                 SwitchDisplayModes( TRUE, 800, 600 );
  2059.                 g_pCurrentMenu = NULL;
  2060.                 break;
  2061.  
  2062.             case MENU_1024x768:
  2063.                 SwitchDisplayModes( TRUE, 1024, 768 );
  2064.                 g_pCurrentMenu = NULL;
  2065.                 break;
  2066.  
  2067.             case MENU_SOUNDON:
  2068.                 if( g_pMusicManager == NULL )
  2069.                     CreateSoundObjects( g_hWndMain );
  2070.                 g_pCurrentMenu = NULL;
  2071.                 break;
  2072.  
  2073.             case MENU_SOUNDOFF:
  2074.                 if( g_pMusicManager )
  2075.                     DestroySoundObjects();
  2076.                 g_pCurrentMenu = NULL;
  2077.                 break;
  2078.  
  2079.             case MENU_VIEWDEVICES:
  2080.                 // Put action format to game play actions
  2081.                 g_pInputDeviceManager->SetActionFormat( g_diafGame, TRUE );
  2082.  
  2083.                 g_bMouseVisible = TRUE;
  2084.  
  2085.                 // Configure the devices (with view capability only)
  2086.                 if( g_bFullScreen )
  2087.                     g_pInputDeviceManager->ConfigureDevices( g_hWndMain,
  2088.                                                              g_pConfigSurface,
  2089.                                                              (VOID*)ConfigureInputDevicesCB,
  2090.                                                              DICD_DEFAULT );
  2091.                 else
  2092.                     g_pInputDeviceManager->ConfigureDevices( g_hWndMain, NULL, NULL,
  2093.                                                              DICD_DEFAULT );
  2094.                 g_bMouseVisible = FALSE;
  2095.  
  2096.                 g_pCurrentMenu = NULL;
  2097.                 break;
  2098.  
  2099.             case MENU_CONFIGDEVICES:
  2100.                 // Put action format to game play actions
  2101.                 g_pInputDeviceManager->SetActionFormat( g_diafGame, TRUE );
  2102.  
  2103.                 g_bMouseVisible = TRUE;
  2104.  
  2105.                 // Configure the devices (with edit capability)
  2106.                 if( g_bFullScreen )
  2107.                     g_pInputDeviceManager->ConfigureDevices( g_hWndMain,
  2108.                                                              g_pConfigSurface,
  2109.                                                              (VOID*)ConfigureInputDevicesCB,
  2110.                                                              DICD_EDIT );
  2111.                 else
  2112.                     g_pInputDeviceManager->ConfigureDevices( g_hWndMain, NULL, NULL,
  2113.                                                              DICD_EDIT );
  2114.                 g_bMouseVisible = FALSE;
  2115.  
  2116.                 g_pCurrentMenu = NULL;
  2117.                 break;
  2118.  
  2119.             case MENU_QUIT:
  2120.                 PostMessage( g_hWndMain, WM_CLOSE, 0, 0 );
  2121.                 g_pCurrentMenu = NULL;
  2122.                 break;
  2123.         }
  2124.     }
  2125.  
  2126.     // Check if the menu system is being exitted
  2127.     if( g_bMenuQuit )
  2128.         g_pCurrentMenu = NULL;
  2129.  
  2130.     // If the menu is going away, go back to game play actions
  2131.     if( g_pCurrentMenu == NULL )
  2132.         g_pInputDeviceManager->SetActionFormat( g_diafGame, TRUE );
  2133.  
  2134.     // Clear menu inputs
  2135.     g_bMenuUp     = FALSE;
  2136.     g_bMenuDown   = FALSE;
  2137.     g_bMenuSelect = FALSE;
  2138.     g_bMenuQuit   = FALSE;
  2139. }
  2140.  
  2141.  
  2142.  
  2143.  
  2144. //-----------------------------------------------------------------------------
  2145. // Display support code (using Direct3D functionality from D3DUtil.h)
  2146. //-----------------------------------------------------------------------------
  2147.  
  2148.  
  2149.  
  2150.  
  2151. //-----------------------------------------------------------------------------
  2152. // Name: CreateDisplayObjects()
  2153. // Desc:
  2154. //-----------------------------------------------------------------------------
  2155. HRESULT CreateDisplayObjects( HWND hWnd )
  2156. {
  2157.     HRESULT hr, hr1, hr2;
  2158.  
  2159.     // Construct a new display
  2160.     LPDIRECT3D8 pD3D = Direct3DCreate8( D3D_SDK_VERSION );
  2161.     if( NULL == pD3D )
  2162.     {
  2163.         CleanupAndDisplayError( DONUTS3DERR_NODIRECT3D );
  2164.         return E_FAIL;
  2165.     }
  2166.  
  2167.     // Get the current desktop format
  2168.     pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &g_DesktopMode );
  2169.  
  2170.     const D3DFORMAT fmtFullscreenArray[] = 
  2171.     {
  2172.         D3DFMT_R5G6B5,
  2173.         D3DFMT_X1R5G5B5,
  2174.         D3DFMT_A1R5G5B5,
  2175.         D3DFMT_X8R8G8B8,
  2176.         D3DFMT_A8R8G8B8,
  2177.     };
  2178.     const INT numFullscreenFmts = sizeof(fmtFullscreenArray) / sizeof(fmtFullscreenArray[0]);
  2179.     INT iFmt;
  2180.  
  2181.     // Find a pixel format that will be good for fullscreen back buffers
  2182.     for( iFmt = 0; iFmt < numFullscreenFmts; iFmt++ )
  2183.     {
  2184.         if( SUCCEEDED( pD3D->CheckDeviceType( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
  2185.             fmtFullscreenArray[iFmt], fmtFullscreenArray[iFmt], FALSE ) ) )
  2186.         {
  2187.             g_d3dfmtFullscreen = fmtFullscreenArray[iFmt];
  2188.             break;
  2189.         }
  2190.     }
  2191.  
  2192.     const D3DFORMAT fmtTextureArray[] = 
  2193.     {
  2194.         D3DFMT_A1R5G5B5,
  2195.         D3DFMT_A4R4G4B4,
  2196.         D3DFMT_A8R8G8B8,
  2197.     };
  2198.     const INT numTextureFmts = sizeof(fmtTextureArray) / sizeof(fmtTextureArray[0]);
  2199.  
  2200.     // Find a format that is supported as a texture map for the current mode
  2201.     for( iFmt = 0; iFmt < numTextureFmts; iFmt++ )
  2202.     {
  2203.         if( SUCCEEDED( pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
  2204.             g_DesktopMode.Format, 0, D3DRTYPE_TEXTURE, fmtTextureArray[iFmt] ) ) )
  2205.         {
  2206.             g_d3dfmtTexture = fmtTextureArray[iFmt];
  2207.             break;
  2208.         }
  2209.     }
  2210.  
  2211.     // Set up presentation parameters for the display
  2212.     ZeroMemory( &g_d3dpp, sizeof(g_d3dpp) );
  2213.     g_d3dpp.Windowed         = !g_bFullScreen;
  2214.     g_d3dpp.BackBufferCount  = 1;
  2215.     g_d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
  2216.     g_d3dpp.EnableAutoDepthStencil = TRUE;
  2217.     g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
  2218.     if( g_bFullScreen )
  2219.     {
  2220.         g_d3dpp.hDeviceWindow    = hWnd;
  2221.         g_d3dpp.BackBufferWidth  = g_dwScreenWidth;
  2222.         g_d3dpp.BackBufferHeight = g_dwScreenHeight;
  2223.         g_d3dpp.BackBufferFormat = g_d3dfmtFullscreen;
  2224.     }
  2225.     else
  2226.     {
  2227.         g_d3dpp.BackBufferFormat = g_DesktopMode.Format;
  2228.     }
  2229.  
  2230.     // Create the device
  2231.     hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
  2232.                              D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  2233.                              &g_d3dpp, &g_pd3dDevice );
  2234.     pD3D->Release();
  2235.     if( FAILED(hr) )
  2236.     {
  2237.         CleanupAndDisplayError( DONUTS3DERR_NOD3DDEVICE );
  2238.         return E_FAIL;
  2239.     }
  2240.  
  2241.     // Create some game fonts
  2242.     g_pGameFont = new CD3DFont( _T("Tahoma"), 30, 0L );
  2243.     g_pGameFont->InitDeviceObjects( g_pd3dDevice );
  2244.  
  2245.     g_pMenuFont = new CD3DFont( _T("Impact"), 48, 0L );
  2246.     g_pMenuFont->InitDeviceObjects( g_pd3dDevice );
  2247.  
  2248.     // Find the media files (textures and geometry models) for the game
  2249.     TCHAR strGameTexture1[512];
  2250.     TCHAR strGameTexture2[512];
  2251.     hr1 = DXUtil_FindMediaFile( strGameTexture1, _T("Donuts1.bmp") );
  2252.     hr2 = DXUtil_FindMediaFile( strGameTexture2, _T("Donuts2.bmp") );
  2253.  
  2254.     if( FAILED(hr1) || FAILED(hr2) )
  2255.     {
  2256.         CleanupAndDisplayError( DONUTS3DERR_NOTEXTURES );
  2257.         return E_FAIL;
  2258.     }
  2259.  
  2260.     // Load the game textures
  2261.     if( FAILED( D3DUtil_CreateTexture( g_pd3dDevice, strGameTexture1,
  2262.                                        &g_pGameTexture1, g_d3dfmtTexture ) ) ||
  2263.         FAILED( D3DUtil_CreateTexture( g_pd3dDevice, strGameTexture2,
  2264.                                        &g_pGameTexture2, g_d3dfmtTexture ) ) )
  2265.     {
  2266.         CleanupAndDisplayError( DONUTS3DERR_NOTEXTURES );
  2267.         return E_FAIL;
  2268.     }
  2269.  
  2270.     D3DUtil_SetColorKey( g_pGameTexture1, 0x00000000 );
  2271.     D3DUtil_SetColorKey( g_pGameTexture2, 0x00000000 );
  2272.  
  2273.     // Load the geometry models
  2274.     hr1 = LoadShipModel();
  2275.     hr2 = LoadTerrainModel();
  2276.  
  2277.     if( FAILED(hr1) || FAILED(hr2) )
  2278.     {
  2279.         CleanupAndDisplayError( DONUTS3DERR_NOGEOMETRY );
  2280.         return E_FAIL;
  2281.     }
  2282.  
  2283.     // Create a viewport covering sqaure
  2284.     if( FAILED( g_pd3dDevice->CreateVertexBuffer( 4*sizeof(SCREENVERTEX),
  2285.                                        D3DUSAGE_WRITEONLY, D3DFVF_SCREENVERTEX,
  2286.                                        D3DPOOL_MANAGED, &g_pViewportVB ) ) )
  2287.     {
  2288.         CleanupAndDisplayError( DONUTS3DERR_NO3DRESOURCES );
  2289.         return E_FAIL;
  2290.     }
  2291.  
  2292.     // Create a sqaure for rendering the sprites
  2293.     if( FAILED( g_pd3dDevice->CreateVertexBuffer( 4*sizeof(SPRITEVERTEX),
  2294.                                        D3DUSAGE_WRITEONLY, D3DFVF_SPRITEVERTEX,
  2295.                                        D3DPOOL_MANAGED, &g_pSpriteVB ) ) )
  2296.     {
  2297.         CleanupAndDisplayError( DONUTS3DERR_NO3DRESOURCES );
  2298.         return E_FAIL;
  2299.     }
  2300.  
  2301.     // Now that all the display objects are created, "restore" them (create
  2302.     // local mem objects and set state)
  2303.     if( FAILED( RestoreDisplayObjects() ) )
  2304.                 return E_FAIL;
  2305.  
  2306.         // The display is now ready
  2307.         g_bDisplayReady = TRUE;
  2308.         return S_OK;
  2309. }
  2310.  
  2311.  
  2312.  
  2313.  
  2314. //-----------------------------------------------------------------------------
  2315. // Name: RestoreDisplayObjects()
  2316. // Desc:
  2317. //-----------------------------------------------------------------------------
  2318. HRESULT RestoreDisplayObjects()
  2319. {
  2320.     HRESULT hr;
  2321.     HWND hWnd = g_hWndMain;
  2322.  
  2323.     if( FALSE == g_bFullScreen )
  2324.     {
  2325.         // If we are still a WS_POPUP window we should convert to a normal app
  2326.         // window so we look like a windows app.
  2327.         DWORD dwStyle  = GetWindowStyle( hWnd );
  2328.         dwStyle &= ~WS_POPUP;
  2329.         dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
  2330.         SetWindowLong( hWnd, GWL_STYLE, dwStyle );
  2331.  
  2332.         // Aet window size
  2333.         RECT rc;
  2334.         SetRect( &rc, 0, 0, 640, 480 );
  2335.  
  2336.         AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
  2337.                             GetWindowExStyle(hWnd) );
  2338.  
  2339.         SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
  2340.                       SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
  2341.  
  2342.         SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  2343.                       SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
  2344.  
  2345.         //  Make sure our window does not hang outside of the work area
  2346.         RECT rcWork;
  2347.         SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
  2348.         GetWindowRect( hWnd, &rc );
  2349.         if( rc.left < rcWork.left ) rc.left = rcWork.left;
  2350.         if( rc.top  < rcWork.top )  rc.top  = rcWork.top;
  2351.         SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
  2352.                       SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
  2353.     }
  2354.  
  2355.     // Create the device-dependent objects for the file-based mesh objects
  2356.     g_pShipFileObject->RestoreDeviceObjects( g_pd3dDevice );
  2357.     g_pTerrain->RestoreDeviceObjects( g_pd3dDevice );
  2358.     g_pGameFont->RestoreDeviceObjects();
  2359.     g_pMenuFont->RestoreDeviceObjects();
  2360.  
  2361.     // Get viewport dimensions
  2362.     D3DVIEWPORT8 vp;
  2363.     g_pd3dDevice->GetViewport(&vp);
  2364.     FLOAT sx = (FLOAT)vp.Width;
  2365.     FLOAT sy = (FLOAT)vp.Height;
  2366.  
  2367.     // Setup dimensions for the viewport covering sqaure
  2368.     SCREENVERTEX* v;
  2369.     g_pViewportVB->Lock( 0, 0, (BYTE**)&v, 0 );
  2370.     v[0].p = D3DXVECTOR4( 0,sy,0.0f,1.0f);
  2371.     v[1].p = D3DXVECTOR4( 0, 0,0.0f,1.0f);
  2372.     v[2].p = D3DXVECTOR4(sx,sy,0.0f,1.0f);
  2373.     v[3].p = D3DXVECTOR4(sx, 0,0.0f,1.0f);
  2374.     g_pViewportVB->Unlock();
  2375.  
  2376.     // Create a surface for confguring DInput devices
  2377.     hr = g_pd3dDevice->CreateImageSurface( 640, 480, g_d3dfmtFullscreen, &g_pConfigSurface );
  2378.     if( FAILED(hr) )
  2379.     {
  2380.         CleanupAndDisplayError( DONUTS3DERR_NO3DRESOURCES );
  2381.         return E_FAIL;
  2382.     }
  2383.  
  2384.     // Set up the camera
  2385.     g_Camera.SetViewParams( D3DXVECTOR3(0.0f,0.0f,0.0f), D3DXVECTOR3(0.0f,0.0f,1.0f),
  2386.                             D3DXVECTOR3(0.0f,1.0f,0.0f) );
  2387.     g_Camera.SetProjParams( D3DX_PI/4, 1.0f, 0.1f, 100.0f );
  2388.  
  2389.     // Set up default matrices (using the CD3DCamera class)
  2390.     g_pd3dDevice->SetTransform( D3DTS_VIEW,       &g_Camera.GetViewMatrix() );
  2391.     g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &g_Camera.GetProjMatrix() );
  2392.  
  2393.     // Setup a material
  2394.     D3DMATERIAL8 mtrl;
  2395.     D3DUtil_InitMaterial( mtrl, 1.0f, 1.0f, 1.0f );
  2396.     g_pd3dDevice->SetMaterial( &mtrl );
  2397.  
  2398.     // Set up lighting states
  2399.     D3DLIGHT8 light;
  2400.     D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, 1.0f, -1.0f, 1.0f );
  2401.     g_pd3dDevice->SetLight( 0, &light );
  2402.     g_pd3dDevice->LightEnable( 0, TRUE );
  2403.  
  2404.     g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  2405.     g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x33333333 );
  2406.  
  2407.     // Set miscellaneous render states
  2408.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  2409.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  2410.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  2411.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
  2412.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
  2413.     g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  2414.  
  2415.     return S_OK;
  2416. }
  2417.  
  2418.  
  2419.  
  2420.  
  2421. //-----------------------------------------------------------------------------
  2422. // Name: InvalidateDisplayObjects()
  2423. // Desc:
  2424. //-----------------------------------------------------------------------------
  2425. HRESULT InvalidateDisplayObjects()
  2426. {
  2427.     g_pShipFileObject->InvalidateDeviceObjects();
  2428.     g_pTerrain->InvalidateDeviceObjects();
  2429.     g_pGameFont->InvalidateDeviceObjects();
  2430.     g_pMenuFont->InvalidateDeviceObjects();
  2431.  
  2432.     SAFE_RELEASE( g_pConfigSurface );
  2433.  
  2434.     return S_OK;
  2435. }
  2436.  
  2437.  
  2438.  
  2439. //-----------------------------------------------------------------------------
  2440. // Name: DestroyDisplayObjects()
  2441. // Desc:
  2442. //-----------------------------------------------------------------------------
  2443. HRESULT DestroyDisplayObjects()
  2444. {
  2445.     DisplayObject* pDO;
  2446.     while( g_pDisplayList != NULL )
  2447.     {
  2448.         pDO = g_pDisplayList;
  2449.         g_pDisplayList = g_pDisplayList->pNext;
  2450.         delete pDO;
  2451.         if( g_pDisplayList != NULL)
  2452.             g_pDisplayList->pPrev = NULL;
  2453.     }
  2454.     
  2455.     SAFE_RELEASE( g_pGameTexture1 );
  2456.     SAFE_RELEASE( g_pGameTexture2 );
  2457.  
  2458.     SAFE_DELETE( g_pGameFont );
  2459.     SAFE_DELETE( g_pMenuFont );
  2460.  
  2461.     SAFE_RELEASE( g_pConfigSurface );
  2462.  
  2463.     if( g_pShipFileObject != NULL )
  2464.         g_pShipFileObject->Destroy();
  2465.     if( g_pTerrain != NULL )
  2466.         g_pTerrain->Destroy();
  2467.  
  2468.     SAFE_DELETE( g_pTerrain );
  2469.     SAFE_DELETE( g_pShipFileObject );
  2470.  
  2471.     SAFE_RELEASE( g_pViewportVB );
  2472.     SAFE_RELEASE( g_pSpriteVB );
  2473.     SAFE_RELEASE( g_pd3dDevice );
  2474.  
  2475.     return S_OK;
  2476. }
  2477.  
  2478.  
  2479.  
  2480.  
  2481. //-----------------------------------------------------------------------------
  2482. // Name: SwitchDisplayModes()
  2483. // Desc:
  2484. //-----------------------------------------------------------------------------
  2485. HRESULT SwitchDisplayModes( BOOL bFullScreen, DWORD dwWidth, DWORD dwHeight )
  2486. {
  2487.     HRESULT hr;
  2488.  
  2489.     if( FALSE==g_bIsActive || FALSE==g_bDisplayReady )
  2490.         return S_OK;
  2491.  
  2492.     // Check to see if a change was actually requested
  2493.     if( bFullScreen )
  2494.     {
  2495.         if( g_dwScreenWidth==dwWidth && g_dwScreenHeight==dwHeight &&
  2496.             g_bFullScreen==bFullScreen )
  2497.             return S_OK;
  2498.     }
  2499.     else
  2500.     {
  2501.         if( g_bFullScreen == FALSE )
  2502.             return S_OK;
  2503.     }
  2504.  
  2505.     // Invalidate the old display objects
  2506.     g_bDisplayReady = FALSE;
  2507.     InvalidateDisplayObjects();
  2508.  
  2509.     // Set up the new presentation paramters
  2510.     if( bFullScreen )
  2511.     {
  2512.         g_d3dpp.Windowed         = FALSE;
  2513.         g_d3dpp.hDeviceWindow    = g_hWndMain;
  2514.         g_d3dpp.BackBufferWidth  = g_dwScreenWidth  = dwWidth;
  2515.         g_d3dpp.BackBufferHeight = g_dwScreenHeight = dwHeight;
  2516.         g_d3dpp.BackBufferFormat = g_d3dfmtFullscreen;
  2517.     }
  2518.     else
  2519.     {
  2520.         g_d3dpp.Windowed         = TRUE;
  2521.         g_d3dpp.hDeviceWindow    = NULL;
  2522.         g_d3dpp.BackBufferWidth  = 0L;
  2523.         g_d3dpp.BackBufferHeight = 0L;
  2524.  
  2525.         g_d3dpp.BackBufferFormat = g_DesktopMode.Format;
  2526.     }
  2527.  
  2528.     // Reset the device
  2529.     if( SUCCEEDED( hr = g_pd3dDevice->Reset( &g_d3dpp ) ) )
  2530.     {
  2531.         g_bFullScreen   = bFullScreen;
  2532.         if( SUCCEEDED( hr = RestoreDisplayObjects() ) )
  2533.         {
  2534.             g_bDisplayReady = TRUE;
  2535.             return S_OK;
  2536.         }
  2537.     }
  2538.  
  2539.     // If we get here, a fatal error occurred
  2540.     PostMessage( g_hWndMain, WM_CLOSE, 0, 0 );
  2541.     return E_FAIL;
  2542. }
  2543.  
  2544.  
  2545.  
  2546.  
  2547. //-----------------------------------------------------------------------------
  2548. // Name: ShowFrame()
  2549. // Desc:
  2550. //-----------------------------------------------------------------------------
  2551. VOID ShowFrame()
  2552. {
  2553.     if( NULL == g_pd3dDevice )
  2554.         return;
  2555.  
  2556.     // Present the backbuffer contents to the front buffer
  2557.     g_pd3dDevice->Present( 0, 0, 0, 0 );
  2558. }
  2559.  
  2560.  
  2561.  
  2562.  
  2563. //-----------------------------------------------------------------------------
  2564. // Sound support code (using DMusic functionality from DMUtil.h)
  2565. //-----------------------------------------------------------------------------
  2566.  
  2567.  
  2568.  
  2569.  
  2570. //-----------------------------------------------------------------------------
  2571. // Name: CreateSoundObjects()
  2572. // Desc:
  2573. //-----------------------------------------------------------------------------
  2574. HRESULT CreateSoundObjects( HWND hWnd )
  2575. {
  2576.     // Create the music manager class, used to create the sounds
  2577.     g_pMusicManager = new CMusicManager();
  2578.     if( FAILED( g_pMusicManager->Initialize( hWnd ) ) )
  2579.         return E_FAIL;
  2580.  
  2581.     // Instruct the music manager where to find the files
  2582.     g_pMusicManager->SetSearchDirectory( DXUtil_GetDXSDKMediaPath() );
  2583.  
  2584.     // Create the sounds
  2585.     g_pMusicManager->CreateSegmentFromResource( &g_pBeginLevelSound,     _T("BEGINLEVEL"), _T("WAV") );
  2586.     g_pMusicManager->CreateSegmentFromResource( &g_pEngineIdleSound,     _T("ENGINEIDLE") , _T("WAV"));
  2587.     g_pMusicManager->CreateSegmentFromResource( &g_pEngineRevSound,      _T("ENGINEREV") , _T("WAV"));
  2588.     g_pMusicManager->CreateSegmentFromResource( &g_pShieldBuzzSound,     _T("SHIELDBUZZ") , _T("WAV"));
  2589.     g_pMusicManager->CreateSegmentFromResource( &g_pShipExplodeSound,    _T("SHIPEXPLODE") , _T("WAV"));
  2590.     g_pMusicManager->CreateSegmentFromResource( &g_pFireBulletSound,     _T("GUNFIRE") , _T("WAV"));
  2591.     g_pMusicManager->CreateSegmentFromResource( &g_pShipBounceSound,     _T("SHIPBOUNCE") , _T("WAV"));
  2592.     g_pMusicManager->CreateSegmentFromResource( &g_pDonutExplodeSound,   _T("DONUTEXPLODE") , _T("WAV"));
  2593.     g_pMusicManager->CreateSegmentFromResource( &g_pPyramidExplodeSound, _T("PYRAMIDEXPLODE") , _T("WAV"));
  2594.     g_pMusicManager->CreateSegmentFromResource( &g_pCubeExplodeSound,    _T("CUBEEXPLODE") , _T("WAV"));
  2595.     g_pMusicManager->CreateSegmentFromResource( &g_pSphereExplodeSound,  _T("SPHEREEXPLODE") , _T("WAV"));
  2596.  
  2597.     return S_OK;
  2598. }
  2599.  
  2600.  
  2601.  
  2602.  
  2603. //-----------------------------------------------------------------------------
  2604. // Name: DestroySoundObjects()
  2605. // Desc:
  2606. //-----------------------------------------------------------------------------
  2607. VOID DestroySoundObjects()
  2608. {
  2609.     SAFE_DELETE( g_pBeginLevelSound );
  2610.     SAFE_DELETE( g_pEngineIdleSound );
  2611.     SAFE_DELETE( g_pEngineRevSound );
  2612.     SAFE_DELETE( g_pShieldBuzzSound );
  2613.     SAFE_DELETE( g_pShipExplodeSound );
  2614.     SAFE_DELETE( g_pFireBulletSound );
  2615.     SAFE_DELETE( g_pShipBounceSound );
  2616.     SAFE_DELETE( g_pDonutExplodeSound );
  2617.     SAFE_DELETE( g_pPyramidExplodeSound );
  2618.     SAFE_DELETE( g_pCubeExplodeSound );
  2619.     SAFE_DELETE( g_pSphereExplodeSound );
  2620.  
  2621.     SAFE_DELETE( g_pMusicManager );
  2622. }
  2623.  
  2624.  
  2625.  
  2626.  
  2627. //-----------------------------------------------------------------------------
  2628. // Input support code (using DInput functionality from DIUtil.h)
  2629. //-----------------------------------------------------------------------------
  2630.  
  2631.  
  2632.  
  2633. //-----------------------------------------------------------------------------
  2634. // Name: CreateInputObjects()
  2635. // Desc:
  2636. //-----------------------------------------------------------------------------
  2637. HRESULT CreateInputObjects( HWND hWnd )
  2638. {
  2639.     HRESULT hr;
  2640.  
  2641.     // Setup action format for the acutal gameplay
  2642.     ZeroMemory( &g_diafGame, sizeof(DIACTIONFORMAT) );
  2643.     g_diafGame.dwSize          = sizeof(DIACTIONFORMAT);
  2644.     g_diafGame.dwActionSize    = sizeof(DIACTION);
  2645.     g_diafGame.dwDataSize      = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
  2646.     g_diafGame.guidActionMap   = g_AppGuid;
  2647.     g_diafGame.dwGenre         = DIVIRTUAL_SPACESIM;
  2648.     g_diafGame.dwNumActions    = NUMBER_OF_GAMEACTIONS;
  2649.     g_diafGame.rgoAction       = g_rgGameAction;
  2650.     g_diafGame.lAxisMin        = -10;
  2651.     g_diafGame.lAxisMax        = 10;
  2652.     g_diafGame.dwBufferSize    = 16;
  2653.     _tcscpy( g_diafGame.tszActionMap, _T("Donuts3D New") );
  2654.  
  2655.     // Setup action format for the in-game menus
  2656.     ZeroMemory( &g_diafBrowser, sizeof(DIACTIONFORMAT) );
  2657.     g_diafBrowser.dwSize          = sizeof(DIACTIONFORMAT);
  2658.     g_diafBrowser.dwActionSize    = sizeof(DIACTION);
  2659.     g_diafBrowser.dwDataSize      = NUMBER_OF_BROWSERACTIONS * sizeof(DWORD);
  2660.     g_diafBrowser.guidActionMap   = g_AppGuid;
  2661.     g_diafBrowser.dwGenre         = DIVIRTUAL_BROWSER_CONTROL;
  2662.     g_diafBrowser.dwNumActions    = NUMBER_OF_BROWSERACTIONS;
  2663.     g_diafBrowser.rgoAction       = g_rgBrowserAction;
  2664.     g_diafBrowser.lAxisMin        = -10;
  2665.     g_diafBrowser.lAxisMax        = 10;
  2666.     g_diafBrowser.dwBufferSize    = 16;
  2667.     _tcscpy( g_diafBrowser.tszActionMap, _T("Donuts New") );
  2668.  
  2669.     // Create a new input device manager
  2670.     g_pInputDeviceManager = new CInputDeviceManager();
  2671.  
  2672.     if( FAILED( hr = g_pInputDeviceManager->Create( hWnd, NULL, g_diafGame ) ) )
  2673.     {
  2674.         CleanupAndDisplayError( DONUTS3DERR_NOINPUT );
  2675.         return E_FAIL;
  2676.     }
  2677.  
  2678.     return S_OK;
  2679. }
  2680.  
  2681.  
  2682.  
  2683.  
  2684. //-----------------------------------------------------------------------------
  2685. // Name: DestroyInputObjects()
  2686. // Desc:
  2687. //-----------------------------------------------------------------------------
  2688. VOID DestroyInputObjects()
  2689. {
  2690.     // Delete input device manager
  2691.     SAFE_DELETE( g_pInputDeviceManager );
  2692. }
  2693.  
  2694.  
  2695.  
  2696.  
  2697. //-----------------------------------------------------------------------------
  2698. // Name: ConfigureInputDevicesCB()
  2699. // Desc: Callback function for configuring input devices. This function is
  2700. //       called in fullscreen modes, so that the input device configuration
  2701. //       window can update the screen.
  2702. //-----------------------------------------------------------------------------
  2703. BOOL CALLBACK ConfigureInputDevicesCB( IUnknown* pUnknown, VOID* pUserData )
  2704. {
  2705.     if( g_dwAppState != APPSTATE_ACTIVE )
  2706.         return TRUE;
  2707.  
  2708.     // Get access to the surface
  2709.     LPDIRECT3DSURFACE8 pConfigSurface;
  2710.     if( FAILED( pUnknown->QueryInterface( IID_IDirect3DSurface8,
  2711.                                           (VOID**)&pConfigSurface ) ) )
  2712.         return TRUE;
  2713.  
  2714.     // Draw the scene, with the config surface blitted on top
  2715.     DrawDisplayList();
  2716.  
  2717.     RECT  rcSrc;
  2718.     SetRect( &rcSrc, 0, 0, 640, 480 );
  2719.  
  2720.     POINT ptDst;
  2721.     ptDst.x = (g_dwScreenWidth-640)/2;
  2722.     ptDst.y = (g_dwScreenHeight-480)/2;
  2723.  
  2724.     LPDIRECT3DSURFACE8 pBackBuffer;
  2725.     g_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  2726.     g_pd3dDevice->CopyRects( pConfigSurface, &rcSrc, 1, pBackBuffer, &ptDst );
  2727.     pBackBuffer->Release();
  2728.  
  2729.     ShowFrame();
  2730.  
  2731.     // Release the surface
  2732.     pConfigSurface->Release();
  2733.  
  2734.     return TRUE;
  2735. }
  2736.  
  2737.  
  2738.  
  2739.  
  2740. //-----------------------------------------------------------------------------
  2741. // Name: GetInput()
  2742. // Desc: Processes data from the input device.  Uses GetDeviceState().
  2743. //-----------------------------------------------------------------------------
  2744. VOID GetInput()
  2745. {
  2746.     // Buffers for accumulating data from input devices
  2747.     static FLOAT fLeftThrust[10]    = {0};
  2748.     static FLOAT fRightThrust[10]   = {0};
  2749.     static FLOAT fForwardThrust[10] = {0};
  2750.     static FLOAT fReverseThrust[10] = {0};
  2751.  
  2752.     // Get access to the list of semantically-mapped input devices
  2753.     LPDIRECTINPUTDEVICE8* pdidDevices;
  2754.     DWORD                 dwNumDevices;
  2755.     g_pInputDeviceManager->GetDevices( &pdidDevices, &dwNumDevices );
  2756.  
  2757.     // Loop through all devices and check game input
  2758.     for( DWORD i=0; i<dwNumDevices; i++ )
  2759.     {
  2760.         DIDEVICEOBJECTDATA rgdod[10];
  2761.         DWORD   dwItems = 10;
  2762.         HRESULT hr;
  2763.  
  2764.         hr = pdidDevices[i]->Acquire();
  2765.         hr = pdidDevices[i]->Poll();
  2766.         hr = pdidDevices[i]->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  2767.                                            rgdod, &dwItems, 0 );
  2768.         if( FAILED(hr) )
  2769.             continue;
  2770.  
  2771.         // Get the sematics codes for the game menu
  2772.         for( DWORD j=0; j<dwItems; j++ )
  2773.         {
  2774.             BOOL  bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
  2775.             FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
  2776.             FLOAT fAxisState   = (FLOAT)((int)rgdod[j].dwData)/10.0f;
  2777.  
  2778.             switch( rgdod[j].uAppData )
  2779.             {
  2780.                 // Handle semantics for the game menu
  2781.                 case INPUT_MENU_LR:     // There are no nieghboring menus so ignore this one
  2782.                     break;
  2783.  
  2784.                 case INPUT_MENU_UD:
  2785.                 {
  2786.                     // The axis goes between -1 and 1.  We need to set g_bMenuDown or g_bMenuUp
  2787.                     // only one time.
  2788.                     static BOOL s_bOneTimeUD = FALSE;
  2789.  
  2790.                     if( fabs(fAxisState) < 0.2 )
  2791.                     {
  2792.                         s_bOneTimeUD = FALSE;
  2793.                     }
  2794.                     else
  2795.                     {
  2796.                         if ( !s_bOneTimeUD )
  2797.                         {
  2798.                             if( fAxisState > 0.0f )
  2799.                                 g_bMenuDown = TRUE;
  2800.                             else
  2801.                                 g_bMenuUp = TRUE;
  2802.  
  2803.                             s_bOneTimeUD = TRUE;
  2804.                         }
  2805.                     }
  2806.  
  2807.                     break;
  2808.                 }
  2809.  
  2810.                 case INPUT_MENU_UP:     g_bMenuUp     |= bButtonState; break;
  2811.                 case INPUT_MENU_DOWN:   g_bMenuDown   |= bButtonState; break;
  2812.                 case INPUT_MENU_LEFT:   g_bMenuLeft   |= bButtonState; break;
  2813.                 case INPUT_MENU_RIGHT:  g_bMenuRight  |= bButtonState; break;
  2814.                 case INPUT_MENU_SELECT: g_bMenuSelect |= bButtonState; break;
  2815.                 case INPUT_MENU_QUIT:   g_bMenuQuit   |= bButtonState; break;
  2816.  
  2817.                 case INPUT_MENU_WHEEL:
  2818.                     if( fAxisState > 0.0f )
  2819.                         g_bMenuUp = TRUE;
  2820.                     else
  2821.                         g_bMenuDown = TRUE;
  2822.                     break;
  2823.  
  2824.                 // Handle semantics for normal game play
  2825.                 case INPUT_AXIS_LR:
  2826.                 case INPUT_MOUSE_LR:
  2827.                     fLeftThrust[i]  = 0.0f;
  2828.                     fRightThrust[i] = 0.0f;
  2829.                     if( fAxisState > 0.0f )
  2830.                         fRightThrust[i] = +fAxisState;
  2831.                     else
  2832.                         fLeftThrust[i]  = -fAxisState;
  2833.                     break;
  2834.                 case INPUT_AXIS_UD:
  2835.                 case INPUT_MOUSE_UD:
  2836.                     fForwardThrust[i] = 0.0f;
  2837.                     fReverseThrust[i] = 0.0f;
  2838.                     if( fAxisState > 0.0f )
  2839.                         fReverseThrust[i] = +fAxisState;
  2840.                     else
  2841.                         fForwardThrust[i] = -fAxisState;
  2842.                     break;
  2843.  
  2844.                 // User wants to change ship type
  2845.                 case INPUT_AXIS_SHIPTYPE:
  2846.                 case INPUT_MOUSE_SHIPTYPE:
  2847.                     SwitchModel();
  2848.                     break;
  2849.  
  2850.                 case INPUT_TURNLEFT:      fLeftThrust[i]    = fButtonState; break;
  2851.                 case INPUT_TURNRIGHT:     fRightThrust[i]   = fButtonState; break;
  2852.                 case INPUT_FORWARDTHRUST: fForwardThrust[i] = fButtonState; break;
  2853.                 case INPUT_REVERSETHRUST: fReverseThrust[i] = fButtonState; break;
  2854.  
  2855.                 case INPUT_FIREWEAPONS:   g_bFiringWeapons  = bButtonState; break;
  2856.                 case INPUT_CHANGEVIEW:    g_bChangeView     = bButtonState; break;
  2857.  
  2858.                 // User wants to change weapons
  2859.                 case INPUT_CHANGEWEAPONS:
  2860.                     if( bButtonState )
  2861.                     {
  2862.                         if( ++g_dwBulletType > 3 )
  2863.                             g_dwBulletType = 0L;
  2864.                     }
  2865.                     break;
  2866.  
  2867.                 // User wants to change ship type
  2868.                 case INPUT_CHANGESHIPTYPE:
  2869.                     if( bButtonState )
  2870.                         SwitchModel();
  2871.                     break;
  2872.  
  2873.                 case INPUT_START:
  2874.                     if( bButtonState )
  2875.                         g_bPaused = !g_bPaused;
  2876.                     break;
  2877.  
  2878.                 case INPUT_DISPLAYGAMEMENU:
  2879.                     if( bButtonState )
  2880.                     {
  2881.                         PlaySound( g_pSphereExplodeSound );
  2882.                         g_pCurrentMenu = g_pMainMenu;
  2883.                         g_pInputDeviceManager->SetActionFormat( g_diafBrowser, FALSE );
  2884.                     }
  2885.                     break;
  2886.  
  2887.                 case INPUT_QUITGAME:
  2888.                     if( bButtonState )
  2889.                     {
  2890.                         PlaySound( g_pSphereExplodeSound );
  2891.                         g_pCurrentMenu = g_pQuitMenu;
  2892.                         g_pInputDeviceManager->SetActionFormat( g_diafBrowser, FALSE );
  2893.                     }
  2894.                     break;
  2895.             }
  2896.         }
  2897.     }
  2898.  
  2899.     if( g_pShip->bVisible  )
  2900.     {
  2901.         // Accumulate thrust inputs
  2902.         g_fBank   = 0.0f;
  2903.         g_fThrust = 0.0f;
  2904.  
  2905.         for( DWORD i=0; i<dwNumDevices; i++ )
  2906.         {
  2907.             if( fRightThrust[i] > 0.4f )   g_fBank   += fRightThrust[i];
  2908.             if( fLeftThrust[i] > 0.4f )    g_fBank   -= fLeftThrust[i];
  2909.  
  2910.             if( fForwardThrust[i] > 0.4f ) g_fThrust += fForwardThrust[i];
  2911.             if( fReverseThrust[i] > 0.4f ) g_fThrust -= fReverseThrust[i];
  2912.         }
  2913.     }
  2914.     else
  2915.     {
  2916.         // If the ship is not visible, zero out appropriate inputs
  2917.         g_fBank           = 0.0f;
  2918.         g_fThrust         = 0.0f;
  2919.         g_bFiringWeapons  = FALSE;
  2920.         g_bChangeView     = FALSE;
  2921.     }
  2922. }
  2923.  
  2924.  
  2925.  
  2926.  
  2927. //-----------------------------------------------------------------------------
  2928. // Error handling
  2929. //-----------------------------------------------------------------------------
  2930.  
  2931.  
  2932.  
  2933.  
  2934. //-----------------------------------------------------------------------------
  2935. // Name: CleanupAndDisplayError()
  2936. // Desc:
  2937. //-----------------------------------------------------------------------------
  2938. VOID CleanupAndDisplayError( DWORD dwError )
  2939. {
  2940.     TCHAR* strDbgOut;
  2941.     TCHAR* strMsgBox;
  2942.  
  2943.     // Cleanup the app
  2944.     DestroyGameObjects();
  2945.  
  2946.     // Make the cursor visible
  2947.     SetCursor( LoadCursor( NULL, IDC_ARROW ) );
  2948.     g_bMouseVisible = TRUE;
  2949.  
  2950.     // Get the appropriate error strings
  2951.     switch( dwError )
  2952.     {
  2953.         case DONUTS3DERR_NODIRECT3D:
  2954.             strDbgOut = _T("Could not create Direct3D\n");
  2955.             strMsgBox = _T("Could not create Direct3D.\n\n")
  2956.                         _T("Please make sure you have the latest DirectX\n")
  2957.                         _T(".dlls installed on your system.");
  2958.             break;
  2959.         case DONUTS3DERR_NOD3DDEVICE:
  2960.             strDbgOut = _T("Could not create a Direct3D device\n");
  2961.             strMsgBox = _T("Could not create a Direct3D device. Your\n")
  2962.                         _T("graphics accelerator is not sufficient to\n")
  2963.                         _T("run this demo, or your desktop is using\n")
  2964.                         _T("a color format that cannot be accelerated by\n")
  2965.                         _T("your graphics card (try 16-bit mode).");
  2966.             break;
  2967.         case DONUTS3DERR_NOTEXTURES:
  2968.             strDbgOut = _T("Could not load textures\n");
  2969.             strMsgBox = _T("Couldn't load game textures.\n\n")
  2970.                         _T("Either your graphics hardware does not have\n")
  2971.                         _T("sufficient resources, or the DirectX SDK was\n")
  2972.                         _T("not properly installed.");
  2973.             break;
  2974.         case DONUTS3DERR_NOGEOMETRY:
  2975.             strDbgOut = _T("Could not load .x models\n");
  2976.             strMsgBox = _T("Couldn't load game geometry.\n\n")
  2977.                         _T("Either your graphics hardware does not have\n")
  2978.                         _T("sufficient resources, or the DirectX SDK was\n")
  2979.                         _T("not properly installed.");
  2980.             break;
  2981.         case DONUTS3DERR_NO3DRESOURCES:
  2982.             strDbgOut = _T("Couldn't load create a d3d object\n");
  2983.             strMsgBox = _T("Couldn't create display objects.\n")
  2984.                         _T("Yourr graphics hardware does not have\n")
  2985.                         _T("sufficient resources to run this app.");
  2986.             break;
  2987.         case DONUTS3DERR_NOINPUT:
  2988.             strDbgOut = _T("Could not create input objects\n");
  2989.             strMsgBox = _T("Could not create input objects.");
  2990.             break;
  2991.     }
  2992.  
  2993.     // Output the error strings
  2994.     OutputDebugString( strDbgOut );
  2995.     MessageBox( g_hWndMain, strMsgBox, _T("Donuts3D"), MB_OK );
  2996. }
  2997.  
  2998.