home *** CD-ROM | disk | FTP | other *** search
/ Game Audio Programming / GameAudioProgramming.iso / Extras / Sensaura / SDK1.0 / data1.cab / Example_Files / DS3DDemo / Source / dxworld.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-13  |  29.1 KB  |  984 lines

  1. /*
  2.     Company:            Sensaura
  3.     Copyright:          (C) 1999
  4.  
  5.     Software Project:    Sensaura DirectSound3D Demo
  6.     File Name:            dxworld.cpp
  7.     File Description:    Source file for implementation of DirectXWorld class.  This is the overall
  8.                         control class for all our DirectX world.
  9.     Author:                Adam Philp
  10.     File Version:        1.02.000
  11.     Last Update:        10-FEB-99
  12.  
  13.     Target Compiler:    Microsoft Visual C++ Version 5.0
  14. */
  15.  
  16. ///////////////////////    Included files ////////////////////////////////////////////////////////////
  17.  
  18. #include <windows.h>
  19.  
  20. #include "dxworld.h"                    // DirectXWorld class declaration
  21. #include "dxwldobj.h"                    // Classes for 3D objects
  22. #include "sensaura.h"                    // Sensaura-specific DirectSound functions
  23. #include "directx.h"                    // DirectX error handling functions and macros
  24. #include "resource.h"                    // Wave audio resources for DirectSound buffers
  25.  
  26. #include "debug.h"                        
  27.  
  28. ///////////////////////    Constants /////////////////////////////////////////////////////////////////
  29.  
  30. const D3DVALUE MAX_SPEED        = D3DVAL(25.0);
  31. const D3DVALUE MAX_TURN            = D3DVAL(1.0);
  32. const D3DVALUE SPEED_STEP        = D3DVAL(1.0);
  33. const D3DVALUE TURN_STEP        = D3DVAL(0.1);
  34. const D3DVALUE ROLLOFF_FACTOR    = D3DVAL(0.2);
  35. const D3DVALUE DOPPLER_FACTOR    = D3DVAL(2.0);
  36. const D3DVALUE MAX_DISTANCE        = D3DVAL(200.0);
  37. const D3DVALUE BACK_DISTANCE    = D3DVAL(500.0);
  38. const D3DVALUE FLOOR_Y            = D3DVAL(-2.0);
  39. const D3DVALUE CAMERA_X            = D3DVAL(0);
  40. const D3DVALUE CAMERA_Y            = D3DVAL(0);
  41. const D3DVALUE CAMERA_Z            = D3DVAL(-MAX_DISTANCE/4);
  42. const D3DVALUE MAX_CAMERA_X        = D3DVAL(MAX_DISTANCE/2);
  43. const D3DVALUE MAX_CAMERA_Y        = D3DVAL(10.0);
  44. const D3DVALUE MAX_CAMERA_Z        = D3DVAL(MAX_DISTANCE/2);
  45.  
  46. const int NUM_SAUCER_WAVS        = 3;    // Number of different wav resources available available
  47. const int NUM_METEOR_WAVS        = 3;    // for each type of 3D object in the game
  48. const int NUM_EXPLOSIONS        = 20;
  49. const int ID_EXPLOSION_SAUCER    = ID_EXPLOSION+ID_SAUCER;
  50. const int ID_EXPLOSION_METEOR    = ID_EXPLOSION+ID_METEOR;
  51.  
  52. /////////////////////// DirectXWorld class implementation /////////////////////////////////////////
  53.  
  54. DirectXWorld::DirectXWorld(HINSTANCE hInstance)
  55. :Direct3DRMObject(BACK_DISTANCE), DirectSound3DObject(hInstance)
  56. {
  57.     m_hInstance = hInstance;
  58.  
  59.     m_pCamera = NULL;
  60.     m_pView = NULL;
  61.     m_FrameRate = 0;            
  62.  
  63.     m_pSaucerBuilder = NULL;            // Initialize all pointers to NULL
  64.     m_pMeteorBuilder = NULL;
  65.     m_pBulletBuilder = NULL;
  66.     m_pExplosionBuilder = NULL;
  67.     m_pGlobeBuilder = NULL;
  68.  
  69.     LoadDirectXObjects();                // Pre-load DirectX geometry files
  70. }
  71.  
  72. DirectXWorld::~DirectXWorld()
  73. {
  74.     DestroyObjects();
  75.     ReleaseDirectXObjects();            // Free DirectX geometry files
  76. }
  77.  
  78. /*
  79.     Function:        Create
  80.     Description:    Set up the DirectX base classes which are required to make up our world work, 
  81.                     then create the objects which are world contains at startup.
  82.     Parameters:        hwnd - handle of window to which to attach Direct3DRM and DirectSound object
  83.                     hinst - application instance handle
  84.     Return value:    true if all objects were successfully created, false otherwise
  85. */
  86.  
  87. bool DirectXWorld::Create(HWND hwnd)
  88. {                                        // Check that parameters passed are OK
  89.     if(hwnd == NULL || m_hInstance == NULL || !DirectXOK())
  90.         return false;
  91.                                         // Set up windowed Direct3DRM, DirectSound, DirectInput
  92.     if(!Direct3DRMObject::Create(hwnd))    
  93.         return false;
  94.     if (!DirectSound3DObject::Create(hwnd))
  95.         return false;
  96.     if (!DirectInputObject::Create(hwnd, m_hInstance))
  97.         return false;
  98.  
  99.     if(!CreateViewer())                    // Set up camera, viewport and listener
  100.         return false;
  101.     if(!CreateLights())                    // Need some light in our world
  102.         return false;
  103.     if(!CreateEnvironment())            // Set up static objects
  104.         return false;
  105.     m_bFirstUpdate = true;
  106.  
  107.     return Reset();                        // Set world variables to startup conditions
  108. }
  109.  
  110. /*
  111.     Function:        Update
  112.     Description:    Update the 3D objects and the viewer.  This is the function called by the 
  113.                     application once the world has been created.  The application basically calls
  114.                     this function as often as it can until termination.
  115.     Return value:    true if all objects were successfully updated, false otherwise
  116. */
  117.  
  118. bool DirectXWorld::Update()
  119. {
  120.     D3DVALUE delta = UpdateTime();
  121.                                         // It's important to update the Direct3D scene first as 
  122.     if(!UpdateScene(delta))                // this takes the lion's share of processor time and must    
  123.         return false;                    // be called at least once before objects are created
  124.     if(!DirectInputObject::Update(&m_dwFlags))
  125.         return false;
  126.     if(!UpdateInput())
  127.         return false;
  128.  
  129.     if(m_bFirstUpdate)
  130.         if(!CreateObjects())            // Create the objects which exist at the beginning of the
  131.             return false;                // world
  132.  
  133.     if(!UpdateObjects(delta))
  134.         return false;
  135.     if(!UpdateViewer(delta))
  136.         return false;
  137.  
  138.     m_bFirstUpdate = false;
  139.  
  140.     return true;
  141. }
  142.  
  143. /*
  144.     Function:        Resize
  145.     Description:    Rebuild the windowed Direct3DRM object and the viewport when the user resizes 
  146.                     the    application window
  147.     Parameters:        cx - the width of the resized window
  148.                     cy - the height of the resized window
  149.     Return value:    true if all objects were successfully updated, false otherwise
  150. */
  151.  
  152. bool DirectXWorld::Resize(int cx, int cy)
  153. {
  154.     long lVolume;
  155.  
  156.     TRY_DS(m_pPrimary->GetVolume(&lVolume))    // Mute primary buffer whilst rebuilding device
  157.     TRY_DS(m_pPrimary->SetVolume(DSBVOLUME_MIN))
  158.  
  159.     RELEASE(m_pView)                    // Destroy the old viewport
  160.                                         // Rebuild the Direct3DRM device
  161.     if(!Direct3DRMObject::Resize(cx, cy))
  162.         return false;
  163.                                         // Rebuild the viewport
  164.     TRY_D3DRM(m_pD3DRM->CreateViewport(m_pDevice, m_pCamera, 0, 0, cx, cy, &m_pView))
  165.     TRY_D3DRM(m_pView->SetBack(m_BackDistance))
  166.     TRY_DS(m_pPrimary->SetVolume(lVolume))    // Unmute primary buffer
  167.  
  168.     return true;
  169.  
  170. DS_ERROR:
  171. D3DRM_ERROR:
  172.     RELEASE(m_pView)
  173.     return false;
  174. }
  175.  
  176. /*
  177.     Function:        SetDirectSound
  178.     Description:    Cycle through the supplied list of 3D objects and recreate their attached
  179.                     sound buffers to reflect the change in our DirectSound type
  180.     Return value:    true if all objects were successfully updated, false otherwise
  181. */
  182.  
  183. bool DirectXWorld::SetDirectSound(DIRECTSOUND3DTYPE type)
  184. {
  185.     LPD3DRMNODE    pNode;
  186.     LPCSTR pSound;
  187.                                         // Set the DirectSound type
  188.     if(!DirectSound3DObject::SetDirectSound(type))
  189.         return false;
  190.  
  191.     pNode = m_Objects.m_pHead;            // Cycle through the 3D object list
  192.     while(pNode)
  193.     {
  194.         pSound = pNode->pObject->GetSound();
  195.         if(pSound)
  196.         {
  197.             pNode->pObject->DetachSound();
  198.             pNode->pObject->AttachSound(pSound);
  199.         }
  200.         pNode = pNode->pNext;
  201.     }
  202.     
  203.     return true;
  204. }
  205.  
  206. /*
  207.     Function:        SetSpeakerConfig
  208.     Description:    Set the DirectSound speaker configuration
  209.     Parameters:        dwConfig - the DirectSound speaker configuration
  210.     Return value:    true if speaker configuration was successfully updated, false otherwise
  211. */
  212.  
  213. bool DirectXWorld::SetSpeakerConfig(DWORD dwConfig)
  214. {
  215.     TRY_DS(m_pDS->SetSpeakerConfig(dwConfig))
  216.     return true;
  217.  
  218. DS_ERROR:
  219.     return false;
  220. }
  221.  
  222. bool DirectXWorld::CreateObject(DWORD dwId)
  223. {
  224.     switch(dwId)
  225.     {
  226.     case ID_GLOBE:
  227.         return CreateGlobe();
  228.  
  229.     default:
  230.         return false;
  231.     }
  232. }
  233.  
  234. void DirectXWorld::DestroyObject(DWORD dwId)
  235. {
  236.     LPD3DRMNODE pNode = m_Objects.First(dwId);
  237.     if(pNode)
  238.     {
  239.         delete pNode->pObject;
  240.         m_Objects.Remove(pNode);
  241.     }
  242. }
  243.  
  244. /////////////////////// DirectXWorld private member functions /////////////////////////////////////
  245.  
  246. /*
  247.     Function:        LoadDirectXObjects
  248.     Description:    Create mesh builders for the 3D objects in our world
  249.     Return value:    true if all objects were successfully loaded, false otherwise
  250. */
  251.  
  252. bool DirectXWorld::LoadDirectXObjects()
  253. {
  254.     ASSERT(!m_pSaucerBuilder);
  255.     ASSERT(!m_pMeteorBuilder);
  256.     ASSERT(!m_pBulletBuilder);
  257.     ASSERT(!m_pExplosionBuilder);
  258.  
  259.     TRY_D3DRM(m_pD3DRM->CreateMeshBuilder(&m_pSaucerBuilder))
  260.     TRY_D3DRM(m_pSaucerBuilder->Load(".\\Objects\\saucer.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL))
  261.     TRY_D3DRM(m_pSaucerBuilder->SetQuality(m_Quality))
  262.     TRY_D3DRM(m_pD3DRM->CreateMeshBuilder(&m_pMeteorBuilder))
  263.     TRY_D3DRM(m_pMeteorBuilder->Load(".\\Objects\\meteor.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL))
  264.     TRY_D3DRM(m_pMeteorBuilder->SetQuality(m_Quality))
  265.     TRY_D3DRM(m_pMeteorBuilder->Scale(D3DVAL(0.5), D3DVAL(0.5), D3DVAL(0.5)))
  266.     TRY_D3DRM(m_pD3DRM->CreateMeshBuilder(&m_pBulletBuilder))
  267.     TRY_D3DRM(m_pBulletBuilder->Load(".\\Objects\\bullet.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL))
  268.     TRY_D3DRM(m_pBulletBuilder->SetQuality(m_Quality))
  269.     TRY_D3DRM(m_pBulletBuilder->Scale(D3DVAL(0.2), D3DVAL(0.2), D3DVAL(0.2)))
  270.     TRY_D3DRM(m_pD3DRM->CreateMeshBuilder(&m_pExplosionBuilder))
  271.     TRY_D3DRM(m_pExplosionBuilder->Load(".\\Objects\\star.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL))
  272.     TRY_D3DRM(m_pExplosionBuilder->SetQuality(m_Quality))
  273.     TRY_D3DRM(m_pExplosionBuilder->Scale(D3DVAL(0.1), D3DVAL(0.1), D3DVAL(0.1)))
  274.     return true;
  275.  
  276. D3DRM_ERROR:
  277.     ReleaseDirectXObjects();
  278.     return false;
  279. }
  280.  
  281. /*
  282.     Function:        ReleaseDirectXObjects
  283.     Description:    Free all 3D object data
  284. */
  285.  
  286. void DirectXWorld::ReleaseDirectXObjects()
  287. {
  288.     RELEASE(m_pSaucerBuilder)
  289.     RELEASE(m_pMeteorBuilder)
  290.     RELEASE(m_pBulletBuilder)
  291.     RELEASE(m_pExplosionBuilder)
  292.     RELEASE(m_pGlobeBuilder)
  293. }
  294.  
  295. /*
  296.     Function:        CreateViewer
  297.     Description:    Create Direct3DRM camera and viewport to allow us to see our 3D world.  Set
  298.                     DirectSound3D listener position to camera position.
  299.     Return value:    true if viewer was successfully created, false otherwise
  300. */
  301.  
  302. bool DirectXWorld::CreateViewer()
  303. {
  304.     D3DVECTOR position, front, top;
  305.  
  306.     ASSERT(m_pScene);
  307.     ASSERT(!m_pCamera);
  308.  
  309.     if(!m_pListener)
  310.         return false;
  311.                                         // Create camera and viewport
  312.     TRY_D3DRM(m_pD3DRM->CreateFrame(m_pScene, &m_pCamera))
  313.     TRY_D3DRM(m_pD3DRM->CreateViewport(m_pDevice, m_pCamera,
  314.                                        0, 0, m_pDevice->GetWidth(), m_pDevice->GetHeight(),
  315.                                        &m_pView))
  316.     TRY_D3DRM (m_pView->SetBack(m_BackDistance))
  317.                                         // Set listener position and orientation
  318.     TRY_D3DRM(m_pCamera->GetPosition(m_pScene, &position))
  319.     TRY_D3DRM(m_pCamera->GetOrientation(m_pScene, &front, &top))
  320.     TRY_DS(m_pListener->SetPosition(position.x, position.y, position.z, DS3D_DEFERRED))
  321.     TRY_DS(m_pListener->SetOrientation(front.x, front.y, front.z,
  322.                                         top.x, top.y, top.z, DS3D_DEFERRED))
  323.     TRY_DS(m_pListener->SetRolloffFactor(ROLLOFF_FACTOR, DS3D_DEFERRED))
  324.     TRY_DS(m_pListener->SetDopplerFactor(DOPPLER_FACTOR, DS3D_DEFERRED))
  325.     TRY_DS(m_pListener->CommitDeferredSettings())
  326.     return true;
  327.  
  328. DS_ERROR:
  329. D3DRM_ERROR:
  330.     RELEASE(m_pCamera)
  331.     RELEASE(m_pView)
  332.     return false;
  333. }
  334.  
  335. /*
  336.     Function:        CreateLights
  337.     Description:    Create Direct3DRM light objects to allow us to see our 3D world.
  338.     Return value:    true if all lights were successfully created, false otherwise
  339. */
  340.  
  341. bool DirectXWorld::CreateLights()
  342. {
  343.     LPDIRECT3DRMLIGHT pLight = NULL;
  344.     bool bCreated = false;
  345.     // Create a light for the camera to illuminate objects as we approach them
  346.     TRY_D3DRM(m_pD3DRM->CreateLightRGB(D3DRMLIGHT_SPOT, 1, 1, 1, &pLight))
  347.     TRY_D3DRM(pLight->SetLinearAttenuation(D3DVAL(0.3)))
  348.     TRY_D3DRM(pLight->SetUmbra(1))
  349.     TRY_D3DRM(pLight->SetPenumbra(2))
  350.     TRY_D3DRM(m_pCamera->AddLight(pLight))
  351.     RELEASE(pLight)
  352.     // Create ambient light source to illuminate everything
  353.     TRY_D3DRM(m_pD3DRM->CreateLightRGB(D3DRMLIGHT_AMBIENT, 
  354.                                        D3DVAL(0.5), D3DVAL(0.5), D3DVAL(0.5), 
  355.                                        &pLight))
  356.      TRY_D3DRM(m_pScene->AddLight(pLight))
  357.     bCreated = true;
  358.  
  359. D3DRM_ERROR:
  360.     RELEASE(pLight)
  361.     return bCreated;
  362. }
  363.  
  364. /*
  365.     Function:        CreateEnvironment
  366.     Description:    Create the objects which are there but which we don't interact with - floor,
  367.                     walls, sky or whatever
  368.     Return value:    true if all object were successfully created, false otherwise
  369. */
  370.  
  371. bool DirectXWorld::CreateEnvironment()
  372. {
  373.     return true;
  374. }
  375.  
  376. /*
  377.     Function:        CreateObjects
  378.     Description:    Create the 3D objects which we want when our world starts.
  379.     Return value:    true if all object were successfully created, false otherwise
  380. */
  381.  
  382. bool DirectXWorld::CreateObjects()
  383. {
  384.     if(!CreateGlobe())
  385.         return false;
  386.     if(!CreateSaucer())                    // Start off with one flying saucer ...
  387.         return false;
  388.     return CreateMeteor();                // ... and one meteor
  389. }
  390.  
  391. /*
  392.     Function:        Reset
  393.     Description:    Set all world parameters to their initial values.
  394.     Return value:    true if all objects were successfully reset, false otherwise
  395. */
  396.  
  397. bool DirectXWorld::Reset()
  398. {
  399.     m_dwFlags = 0;                        // Set camera position and velocity to zero
  400.     m_YVelocity = 0;
  401.     m_ZVelocity = 0;
  402.     m_XTurnVelocity = 0;
  403.  
  404.     TRY_D3DRM(m_pCamera->SetPosition(m_pScene, CAMERA_X, CAMERA_Y, CAMERA_Z))
  405.     TRY_D3DRM(m_pCamera->SetOrientation(m_pScene, 0, 0, 1, 0, 1, 0))
  406.     TRY_D3DRM(m_pCamera->SetVelocity(m_pScene, 0, 0, 0, FALSE))
  407.  
  408.     m_dwTime = timeGetTime();
  409.     return true;                    
  410.  
  411. D3DRM_ERROR:
  412.     return false;
  413. }
  414.  
  415. /*
  416.     Function:        DestroyObjects
  417.     Description:    Destroy all the 3D objects in our world.
  418. */
  419.  
  420. void DirectXWorld::DestroyObjects()
  421. {
  422.     while(m_Objects.m_pHead)            // m_Objects maintains a list of all 3D objects
  423.     {
  424.         delete m_Objects.m_pHead->pObject;
  425.         m_Objects.RemoveHead();
  426.     }
  427. }
  428.  
  429. /*
  430.     Function:        CreateGlobe
  431.     Description:    Create a new globe object.
  432. */
  433.  
  434. bool DirectXWorld::CreateGlobe()
  435. {
  436.     LPD3DRMOBJECT pObject;                // Create globe builder here because it is modified 
  437.                                         // by the D3DRMGlobeObject class
  438.     TRY_D3DRM(m_pD3DRM->CreateMeshBuilder(&m_pGlobeBuilder))
  439.     TRY_D3DRM(m_pGlobeBuilder->Load(".\\Objects\\sphere.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL))
  440.     TRY_D3DRM(m_pGlobeBuilder->SetQuality(m_Quality))
  441.  
  442.     pObject = new D3DRMGlobeObject(this, &m_pGlobeBuilder, D3DRMOBJECT_SOUNDLOOPING, 0);
  443.     if(!pObject)
  444.         return false;
  445.     if(!pObject->AttachSound(MAKEINTRESOURCE(IDR_WAVE_GLOBE)))
  446.     {
  447.         delete pObject;
  448.         return false;
  449.     }
  450.     m_Objects.Insert(pObject);            // Add it to our object list
  451.                                         // Set its initial position, speed etc.
  452.     return true;
  453.  
  454. D3DRM_ERROR:
  455.     RELEASE(m_pGlobeBuilder)
  456.     return false;
  457. }
  458.  
  459. /*
  460.     Function:        CreateSaucer
  461.     Description:    Create a new flying saucer object.
  462.     Return value:    true if the object was successfully created, false otherwise
  463. */
  464.  
  465. bool DirectXWorld::CreateSaucer()
  466. {
  467.     LPD3DRMOBJECT pObject;
  468.     static int nSaucer = 0;
  469.                                         // Create the object
  470.     pObject = new D3DRMSaucerObject(this, m_pSaucerBuilder,    D3DRMOBJECT_SOUNDLOOPING, 0);
  471.     if(!pObject)
  472.         return false;
  473.     if(!pObject->AttachSound(MAKEINTRESOURCE(IDR_WAVE_SAUCER1+nSaucer)))
  474.     {
  475.         delete pObject;
  476.         return false;
  477.     }
  478.     nSaucer = (nSaucer+1)%NUM_SAUCER_WAVS;
  479.     m_Objects.Insert(pObject);            // Add it to our object list
  480.                                         // Set its initial position, speed etc.
  481.     return true;
  482. }
  483.  
  484. /*
  485.     Function:        CreateMeteor
  486.     Description:    Create a new meteor object.
  487.     Return value:    true if the object was successfully created, false otherwise
  488. */
  489.  
  490. bool DirectXWorld::CreateMeteor()
  491. {
  492.     LPD3DRMOBJECT pObject;
  493.     static int nMeteor = 0;
  494.  
  495.     pObject = new D3DRMMeteorObject(this, m_pMeteorBuilder, D3DRMOBJECT_SOUNDLOOPING, 0);
  496.     if(!pObject)
  497.         return false;
  498.     if(!pObject->AttachSound(MAKEINTRESOURCE(IDR_WAVE_METEOR1+nMeteor)))
  499.     {
  500.         delete pObject;
  501.         return false;
  502.     }
  503.     nMeteor = (nMeteor+1)%NUM_METEOR_WAVS;
  504.     m_Objects.Insert(pObject);
  505.     return true;
  506. }
  507.  
  508. /*
  509.     Function:        CreateExplosion
  510.     Description:    Create an explosion made up of several stars objects.  One star has the 
  511.                     explosion sound    attached to it.
  512.     Parameters:        position - pointer to vector containing position at which to create explosion
  513.                     dwId - id of the object which was blown up in order to create this explosion
  514.     Return value:    true if the object was successfully created, false otherwise
  515. */
  516.  
  517. bool DirectXWorld::CreateExplosion(LPD3DVECTOR position, DWORD dwId)
  518. {
  519.     LPD3DRMOBJECT    pObject;
  520.     int                i;
  521.                                         // Create the star with the attached sound
  522.     pObject = new D3DRMExplosionObject(this, dwId, m_pExplosionBuilder, position, 
  523.                                        D3DRMOBJECT_KILLWITHSOUND, 0);
  524.     if (!pObject)
  525.         return false;
  526.     if(!pObject->AttachSound(MAKEINTRESOURCE(IDR_WAVE_EXPLOSION)))
  527.     {
  528.         delete pObject;
  529.         return false;
  530.     }
  531.     m_Objects.Insert(pObject);            // Add it to our object list
  532.     
  533.     for(i = 1; i < NUM_EXPLOSIONS; i++) // Create other star objects
  534.     {                                    
  535.         pObject = new D3DRMExplosionObject(this, dwId+i, m_pExplosionBuilder, position, 0, 0);
  536.         if(!pObject)
  537.             return false;
  538.         m_Objects.Insert(pObject);        // Add them to object list
  539.     }
  540.     return true;
  541. }
  542.  
  543. /*
  544.     Function:        DestroyExplosion
  545.     Description:    Destroy and remove from the object list all explosion objects with the supplied
  546.                     id value
  547.     Return value:    true if the object was successfully created, false otherwise
  548. */
  549.  
  550. void DirectXWorld::DestroyExplosion(DWORD dwId)
  551. {
  552.     LPD3DRMNODE pNode = m_Objects.m_pHead;
  553.  
  554.     while(pNode)
  555.     {
  556.         if(pNode->pObject->GetID() >= dwId && pNode->pObject->GetID() < dwId+NUM_EXPLOSIONS)
  557.             pNode->pObject->Kill();
  558.         pNode = pNode->pNext;
  559.     }
  560. }
  561.  
  562. /*
  563.     Function:        UpdateTime
  564.     Description:    Update the world time.  Calculate how much time has elapsed since the last 
  565.                     update and calculate the frame rate.  Use the frame rate to calculate how much
  566.                     to advance the game so as to make game speed independent of PC speed
  567.     Return value:    Amount indicating how much to advance the Direct3D scene, objects etc.
  568. */
  569.  
  570. D3DVALUE DirectXWorld::UpdateTime()
  571. {
  572.     DWORD dwNewTime = timeGetTime();
  573.     m_FrameRate = 1000/(D3DVAL(dwNewTime-m_dwTime));
  574.     m_dwTime = dwNewTime;
  575.     return D3DVAL(1.0)/m_FrameRate;
  576. }
  577.  
  578. /*
  579.     Function:        UpdateScene
  580.     Description:    Update and render our Direct3DRM world
  581.     Parameters:        delta - the time in seconds since the last call to UpdateScene
  582.     Return value:    true if everything successfully updated, false otherwise
  583. */
  584.  
  585. bool DirectXWorld::UpdateScene(D3DVALUE delta)
  586. {
  587.     TRY_D3DRM(m_pScene->Move(delta))
  588.     TRY_D3DRM(m_pView->Clear())
  589.     TRY_D3DRM(m_pView->Render(m_pScene))
  590.     TRY_D3DRM(m_pDevice->Update())
  591.                                         // Calculate the frame rate so that the speed of the game
  592.     return true;
  593.  
  594. D3DRM_ERROR:
  595.     return false;
  596. }
  597.  
  598. /*
  599.     Function:        UpdateInput
  600.     Description:    Respond to input from the user
  601.     Return value:    true successfully updated, false otherwise
  602. */
  603.  
  604. bool DirectXWorld::UpdateInput()
  605. {
  606.     if(m_dwFlags & KF_SPACE)            // Fire a bullet        
  607.         Fire();
  608.     if(m_dwFlags & KF_UPARROW)            // Accelerate forward
  609.         MoveZ(SPEED_STEP);
  610.     else if(m_dwFlags & KF_DOWNARROW)    // Accelerate backwards
  611.         MoveZ(-SPEED_STEP);
  612.     else                                // No forward/backward key pressed
  613.         m_ZVelocity = m_ZVelocity >= SPEED_STEP ? m_ZVelocity-SPEED_STEP :
  614.                       m_ZVelocity <= -SPEED_STEP ? m_ZVelocity+SPEED_STEP : 0;
  615.  
  616.     if(m_dwFlags & KF_PAGEUP)            // Accelerate up
  617.         MoveY(SPEED_STEP);
  618.     else
  619.     if(m_dwFlags & KF_PAGEDOWN)            // Accelerate down
  620.         MoveY(-SPEED_STEP);
  621.     else                                // No up/down key pressed
  622.         m_YVelocity = m_YVelocity >= SPEED_STEP ? m_YVelocity-SPEED_STEP :
  623.                       m_YVelocity <= -SPEED_STEP ? m_YVelocity+SPEED_STEP : 0;
  624.  
  625.     if(m_dwFlags & KF_RIGHTARROW)        // Accelerate left turn
  626.         TurnX(TURN_STEP);
  627.     else if(m_dwFlags & KF_LEFTARROW)    // Accelerate right turn
  628.         TurnX(-TURN_STEP);
  629.     else                                // No left/right turn key pressed
  630.         m_XTurnVelocity = m_XTurnVelocity >= TURN_STEP ? m_XTurnVelocity-TURN_STEP :
  631.                           m_XTurnVelocity <= -TURN_STEP ? m_XTurnVelocity+TURN_STEP : 0;
  632.     return true;
  633. }
  634.  
  635. /*
  636.     Function:        UpdateObjects
  637.     Description:    Update the status of all the objects in our object list.  This function
  638.                     controls the progress of all objects that currently exist in our 3D world.
  639.     Parameters:        delta - the time in seconds since the last call to UpdateObjects
  640.     Return value:    true if all objects were successfully updated, false otherwise
  641. */
  642.  
  643. bool DirectXWorld::UpdateObjects(D3DVALUE delta)
  644. {
  645.     if(!DestroyDeadObjects())
  646.         return false;
  647.     if(!CheckCollisions(delta))
  648.         return false;
  649.     if(!MoveObjects(delta))
  650.         return false;
  651.  
  652.     return true;
  653. }
  654.  
  655. /*
  656.     Function:        DestroyDeadObjects
  657.     Description:    Remove all dead objects from the object list
  658.     Return value:    true if all objects were successfully removed, false otherwise
  659. */
  660.  
  661. bool DirectXWorld::DestroyDeadObjects()
  662. {
  663.     LPD3DRMNODE    pNode = m_Objects.m_pHead;
  664.     DWORD dwId;
  665.     bool bSaucer = false;
  666.     bool bMeteor = false;
  667.  
  668.     while(pNode)                        // Cycle through our object list
  669.     {
  670.         if(pNode->pObject->IsDead())    // Remove dead object from list
  671.         {                                // What kind of object is it
  672.             dwId = pNode->pObject->GetID();
  673.             if(dwId == ID_EXPLOSION_SAUCER)
  674.                 bSaucer = true;            // Explosion from flying saucer
  675.             if(dwId == ID_EXPLOSION_METEOR)
  676.                 bMeteor = true;            // Explosion from meteor
  677.  
  678.             delete pNode->pObject;
  679.             pNode = m_Objects.Remove(pNode);
  680.         }
  681.         else
  682.             pNode = pNode->pNext;        // Get next object in our list
  683.     }
  684.                                         // Finished cycling through our object list
  685.     if(bSaucer)                            // Did a saucer explosion end?
  686.     {        
  687.         DestroyExplosion(ID_EXPLOSION_SAUCER);
  688.         CreateSaucer();                    // Create a new flying saucer
  689.     }
  690.     if(bMeteor)                            // Did a meteor explosion end?
  691.     {
  692.         DestroyExplosion(ID_EXPLOSION_METEOR);
  693.         CreateMeteor();                    // Create a new meteor
  694.     }
  695.     return true;
  696. }
  697.  
  698. /*
  699.     Function:        CheckCollisions
  700.     Description:    Check whether any objects have collided with each other and take appropriate
  701.                     action depending on the object type
  702.     Parameters:        delta - the time in seconds since the last call to CheckCollisions
  703.     Return value:    true if all objects were successfully checked, false otherwise
  704. */
  705.  
  706. bool DirectXWorld::CheckCollisions(D3DVALUE delta)
  707. {
  708.     LPD3DRMOBJECT    pObject;
  709.     LPD3DRMNODE        pNode = m_Objects.m_pHead;
  710.     DWORD            dwId;
  711.     bool            bHitCamera;
  712.     LPD3DRMNODE        pHitObject;
  713.  
  714.     while(pNode)                        // Cycle through our object list
  715.     {
  716.         pObject = pNode->pObject;        // Get the 3D object
  717.         dwId = pObject->GetID();        // Get the type of 3D object
  718.                                         // Determine whether the object hit us
  719.         bHitCamera = HitCamera(pObject, delta);    
  720.         pHitObject = HitObject(pObject, delta);
  721.  
  722.         switch(dwId)                    // What happens to an object in the event of a collision
  723.         {                                // depends on what it is ...                    
  724.         case ID_GLOBE:
  725.             break;
  726.  
  727.         case ID_SAUCER:
  728.         case ID_METEOR:
  729.             break;
  730.  
  731.         case ID_BULLET:
  732.             if(pHitObject)                // Ooh, our bullet hit something
  733.             {
  734.                 DWORD dwHitId = pHitObject->pObject->GetID();
  735.                 if(dwHitId == ID_SAUCER || dwHitId == ID_METEOR)
  736.                 {
  737.                     D3DVECTOR p;
  738.  
  739.                     pHitObject->pObject->m_pFrame->GetPosition(m_pScene, &p);
  740.                     pHitObject->pObject->Kill();
  741.                     pObject->Kill();
  742.                     if(!CreateExplosion(&p, dwHitId))
  743.                         return false;
  744.                 }
  745.             }
  746.             break;
  747.         }
  748.         pNode = pNode->pNext;            // Get next object in our list
  749.     }
  750.     return true;
  751. }
  752.  
  753. /*
  754.     Function:        MoveObjects
  755.     Description:    Update the positions and velocities of all the objects in our object list
  756.     Parameters:        delta - the time in seconds since the last call to MoveObjects
  757.     Return value:    true if all objects were successfully moved, false otherwise
  758. */
  759.  
  760. bool DirectXWorld::MoveObjects(D3DVALUE delta)
  761. {
  762.     LPD3DRMOBJECT    pObject;
  763.     LPD3DRMNODE        pNode = m_Objects.m_pHead;
  764.  
  765.     while(pNode)                        // Cycle through our object list
  766.     {
  767.         pObject = pNode->pObject;        // Get the 3D object
  768.         pObject->Update(delta);            // Update the 3D object's position, velocity etc.
  769.         pNode = pNode->pNext;            // Get next object in our list
  770.     }
  771.     return true;
  772. }
  773.  
  774. /*
  775. bool DirectXWorld::UpdateObjects(D3DVALUE delta)
  776. {
  777.     LPD3DRMOBJECT    pObject;
  778.     LPD3DRMNODE        pNode = m_Objects.m_pHead;
  779.     bool            bDead;
  780.     DWORD            dwId, dwIdExplosion = 0;
  781.  
  782.  
  783.     while(pNode)                        // Cycle through our object list
  784.     {
  785.         pObject = pNode->pObject;        // Get the 3D object
  786.         pObject->Update(delta);            // Update the 3D object's position, velocity etc.
  787.         dwId = pObject->GetID();        // Get the type of 3D object
  788.         bDead = pObject->IsDead();        // Should the object be destroyed?
  789. //        switch(dwId)                    // What happens to an object depends on what it is ...                    
  790.         {
  791.         }
  792.         if(bDead)
  793.         {                                // Remove this object from the list and destroy it
  794.             delete pNode->pObject;
  795.             pNode = m_Objects.Remove(pNode);
  796.         }
  797.         else
  798.             pNode = pNode->pNext;        // Get next object in our list
  799.     }
  800.     return true;
  801. }*/
  802.  
  803. /*
  804.     Function:        UpdateViewer
  805.     Description:    Update the status of our view of the world.  This function moves the camera and
  806.                     the listener and responds to user actions.
  807.     Parameters:        delta - the time in seconds since the last call to UpdateViewer
  808.     Return value:    true if everything successfully updated, false otherwise
  809. */
  810.  
  811. bool DirectXWorld::UpdateViewer(D3DVALUE delta)
  812. {
  813.     D3DVECTOR p, v;
  814.     D3DVECTOR front, up, right;
  815.                                         // Get the camera position and orientation
  816.     TRY_D3DRM(m_pCamera->GetPosition(m_pScene, &p))
  817.     TRY_D3DRM(m_pCamera->GetOrientation(m_pScene, &front, &up))
  818.     D3DRMVectorCrossProduct(&right, &up, &front);
  819.                                         // Update the camera velocity
  820.     v.x = m_ZVelocity*front.x+m_YVelocity*up.x;
  821.     v.y = m_ZVelocity*front.y+m_YVelocity*up.y;
  822.     v.z = m_ZVelocity*front.z+m_YVelocity*up.z;
  823.                                         // We've reached the edge of our 3D world
  824.     if((p.x > MAX_CAMERA_X && v.x > 0) || (p.x < -MAX_CAMERA_X && v.x < 0) ||
  825.         (p.z > MAX_CAMERA_Z && v.z > 0) || (p.z < -MAX_CAMERA_Z && v.z < 0))
  826.     {                                    // Dead stop in horizontal plane
  827.         v.x = 0;
  828.         v.z = 0;
  829.         m_ZVelocity = 0;
  830.     }        
  831.     if((p.y > MAX_CAMERA_Y && v.y > 0) || (p.y < -MAX_CAMERA_Y && v.y < 0))
  832.     {                                    // Dead stop in vertical plane
  833.         v.y = 0;
  834.         m_YVelocity = 0;
  835.     }
  836.                                         
  837.     TRY_D3DRM(m_pCamera->SetVelocity(m_pScene, v.x, v.y, v.z, FALSE))
  838.     TRY_D3DRM(m_pCamera->SetRotation(m_pScene, up.x, up.y, up.z, m_XTurnVelocity))
  839.                                         
  840.     if(m_pListener)                        // Update the 3D listener object to match the camera
  841.     {
  842.         TRY_DS(m_pListener->SetPosition(p.x, p.y, p.z, DS3D_DEFERRED))
  843.         TRY_DS(m_pListener->SetVelocity(m_ZVelocity*front.x+m_YVelocity*up.x, 
  844.                                         m_ZVelocity*front.y+m_YVelocity*up.y, 
  845.                                         m_ZVelocity*front.z+m_ZVelocity*up.z, 
  846.                                         DS3D_DEFERRED))
  847.         TRY_DS(m_pListener->SetOrientation(front.x, front.y, front.z, 
  848.                                            up.x, up.y, up.z, DS3D_DEFERRED))
  849.         TRY_DS(m_pListener->CommitDeferredSettings())
  850.     }
  851.     return true;
  852.  
  853. DS_ERROR:
  854. D3DRM_ERROR:
  855.     return false;
  856. }
  857.  
  858. /*
  859.     Function:        MoveY
  860.     Description:    Update the viewer's vertical velocity
  861.     Parameters:        step - amount by which to change velocity
  862. */
  863.  
  864. void DirectXWorld::MoveY(D3DVALUE step)
  865. {
  866.     m_YVelocity += step;
  867.     if(m_YVelocity > MAX_SPEED)            // Limit vertical velocity to +/-MAX_SPEED
  868.         m_YVelocity = MAX_SPEED;
  869.     else
  870.     if(m_YVelocity < -MAX_SPEED)
  871.         m_YVelocity = -MAX_SPEED;    
  872. }
  873.  
  874. /*
  875.     Function:        MoveZ
  876.     Description:    Update the viewer's forward velocity
  877.     Parameters:        step - amount by which to change velocity
  878. */
  879.  
  880. void DirectXWorld::MoveZ(D3DVALUE step)
  881. {
  882.     m_ZVelocity += step;
  883.     if(m_ZVelocity > MAX_SPEED)            // Limit forward velocity to +/-MAX_SPEED
  884.         m_ZVelocity = MAX_SPEED;
  885.     else
  886.     if(m_ZVelocity < -MAX_SPEED)
  887.         m_ZVelocity = -MAX_SPEED;    
  888. }
  889.  
  890. /*
  891.     Function:        MoveZ
  892.     Description:    Update the viewer's left/right turn rate
  893.     Parameters:        step - amount by which to change turn rate
  894. */
  895.  
  896. void DirectXWorld::TurnX(D3DVALUE step)
  897. {
  898.     m_XTurnVelocity += step;
  899.     if(m_XTurnVelocity > MAX_TURN)        // Limit turn rate to +/-MAX_TURN
  900.         m_XTurnVelocity = MAX_TURN;
  901.     else
  902.     if(m_XTurnVelocity < -MAX_TURN)
  903.         m_XTurnVelocity = -MAX_TURN;    
  904. }
  905.  
  906. /*
  907.     Function:        Fire
  908.     Description:    Create a new bullet object
  909.     Return value:    true if bullet successfully created, false otherwise
  910. */
  911.  
  912. bool DirectXWorld::Fire()
  913. {
  914.     LPD3DRMOBJECT pObject;
  915.     static DWORD dwLastTime = 0;
  916.  
  917.     if(timeGetTime() < dwLastTime+500)        // Time required for bullet sound buffer to become
  918.         return false;                        // available again
  919.  
  920.     pObject = new D3DRMBulletObject(this, m_pBulletBuilder, 
  921.                                     D3DRMOBJECT_MORTAL|D3DRMOBJECT_DONTMOVESOUND, 1500);
  922.     if(!pObject)
  923.         return false;
  924.     if(!pObject->AttachSound(MAKEINTRESOURCE(IDR_WAVE_BULLET)))
  925.     {
  926.         delete pObject;
  927.         return false;
  928.     }
  929.     dwLastTime = timeGetTime();
  930.     m_Objects.Insert(pObject);
  931.     return true;
  932. }
  933.  
  934. /*
  935.     Function:        HitCamera
  936.     Description:    Determine whether the supplied object has collided with the camera.  If it has,
  937.                     reverse the camera's velocity
  938.     Parameters:        pObject - pointer to the object to check
  939.                     delta - time of travel for the object
  940.     Return value:    true if the object did collide with the camera, false otherwise
  941. */
  942.  
  943. bool DirectXWorld::HitCamera(LPD3DRMOBJECT pObject, D3DVALUE delta)
  944. {
  945.     D3DVECTOR p, v;
  946.                                     
  947.     if(pObject->Collided(m_pCamera, delta)) 
  948.     {                                    // Reverse velocity of camera as if bouncing off object
  949.         TRY_D3DRM(m_pCamera->GetPosition(pObject->m_pFrame, &p))
  950.         TRY_D3DRM(m_pCamera->GetVelocity(pObject->m_pFrame, &v, FALSE))
  951.         TRY_D3DRM(m_pCamera->SetVelocity(pObject->m_pFrame, -v.x, -v.y, -v.z, FALSE))
  952.         m_ZVelocity = -m_ZVelocity;
  953.         return true;
  954.     }
  955. D3DRM_ERROR:
  956.     return false;
  957. }
  958.  
  959. /*
  960.     Function:        HitObject
  961.     Description:    Determine whether the supplied object has collided with another object in our
  962.                     world
  963.     Parameters:        pObject - pointer to the object to check
  964.                     delta - time of travel for the object
  965.     Return value:    Pointer to the object with which the supplied object collided or NULL
  966. */
  967.  
  968. LPD3DRMNODE DirectXWorld::HitObject(LPD3DRMOBJECT pObject, D3DVALUE delta)
  969. {
  970.     LPD3DRMNODE    pNode;
  971.  
  972.     pNode = m_Objects.m_pHead;
  973.     while(pNode)                        // Cycle through our object list
  974.     {
  975.         if(pNode->pObject != pObject)    // Don't check whether object hit itself
  976.         {                                
  977.             if(pNode->pObject->Collided(pObject->m_pFrame, delta)) 
  978.                 break;                    // We hit something
  979.         }
  980.         pNode = pNode->pNext;
  981.     }
  982.     return pNode;
  983. }
  984.