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

  1. /*
  2.     Company:            Sensaura
  3.     Copyright:          (C) 1999
  4.  
  5.     File Name:            object3d.cpp
  6.     File Description:    Source file for implementation of base classes for D3DRM objects with 
  7.                         sounds attached
  8.     Author:                Adam Philp
  9.     File Version:        1.02.000
  10.     Last Update:        11-FEB-99
  11.  
  12.     Target Compiler:    Microsoft Visual C++ Version 5.0
  13. */
  14.  
  15. ///////////////////////    Included files ////////////////////////////////////////////////////////////
  16.  
  17. #include <windows.h>
  18. #include <math.h>
  19.  
  20. #include "object3d.h"
  21. #include "dxworld.h"
  22. #include "directx.h"                    // DirectX support functions and macros
  23. #include "debug.h"
  24.  
  25. ///////////////////////    Constants /////////////////////////////////////////////////////////////////
  26.  
  27. const double M_PI = 3.14159265;
  28.  
  29. /////////////////////// D3DRMObject class implementation //////////////////////////////////////////
  30.  
  31. D3DRMObject::D3DRMObject(DirectXWorld* pWorld,
  32.                          DWORD id,        
  33.                          LPDIRECT3DRMMESHBUILDER pBuilder,
  34.                          DWORD flags,    
  35.                          DWORD lifetime,
  36.                          D3DRMCOLLISION collision)    
  37. {
  38.     m_Collision = collision;            // Save collision shape
  39.     m_pWorld = pWorld;                    // Save object properties
  40.     m_dwId = id;                    
  41.     m_dwFlags = flags;
  42.     m_dwLifeTime = lifetime;
  43.     m_dwAge = 0;                        // Object has just been born
  44.     m_bKilled = false;
  45.     
  46.     m_pFrame = NULL;                    // Initialize data members
  47.     m_pSound = NULL;                    // No sound attached to object initially
  48.     m_pBuffer = NULL;
  49.     m_p3dBuffer = NULL;
  50.  
  51.     TRY_D3DRM(m_pWorld->m_pD3DRM->CreateFrame(m_pWorld->m_pScene, &m_pFrame))
  52.     TRY_D3DRM(pBuilder->GetBox(this))
  53.     return;
  54.  
  55. D3DRM_ERROR:
  56.     RELEASE(m_pFrame)
  57. }
  58.  
  59. D3DRMObject::~D3DRMObject()
  60. {
  61.     if(!m_bKilled)                        // Kill object if necessary 
  62.         Kill();
  63. }
  64.  
  65. /*
  66.     Function:        AttachSound
  67.     Description:    Create, position and play a DirectSound buffer for the object's attached sound
  68.     Parameters:        pSound - pointer to the sound's resource
  69.     Returns:        true if the buffer was successfully created, false otherwise
  70. */
  71.  
  72. bool D3DRMObject::AttachSound(LPCTSTR pSound)
  73. {
  74.     long lVolume;
  75.  
  76.     ASSERT(pSound);
  77.     if(!pSound)                            // Don't bother if there's no sound attached to the object
  78.         return false;
  79.  
  80.     RELEASE(m_p3dBuffer)                // Destroy DirectSound buffer if we have one
  81.     RELEASE(m_pBuffer)
  82.  
  83.     DWORD dwFlags = DSBCAPS_STATIC|DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME;
  84.     // Do we want 3D sound?  Is DirectSound3D support enabled?
  85.     switch(m_pWorld->m_DirectSoundType)
  86.     {
  87.     case DIRECTSOUND3D_SENSAURA:
  88.     case DIRECTSOUND3D_HARDWARE:        // Request a hardware 3D buffer from DirectSound
  89.         dwFlags |= DSBCAPS_CTRL3D|DSBCAPS_LOCHARDWARE;
  90.         lVolume = 0;                    // 0dB attenuation
  91.         break;
  92.  
  93.     case DIRECTSOUND3D_SOFTWARE:        // Request a software 3D buffer from DirectSound
  94.         dwFlags |= DSBCAPS_CTRL3D|DSBCAPS_LOCSOFTWARE;
  95.         lVolume = -600;                    // 6dB attenuation
  96.         break;
  97.  
  98.     default:                            // Request a 2D buffer from DirectSound
  99.         dwFlags |= DSBCAPS_CTRLPAN;
  100.         lVolume = -1500;                // 15dB attenuation
  101.     }
  102.                                         // Create the DirectSound buffer
  103.     m_pBuffer = CreateDSBufferFromResource(m_pWorld->m_pDS, dwFlags, pSound);
  104.     if(m_pBuffer == NULL)
  105.         return false;
  106.  
  107.     TRY_DS(m_pBuffer->SetVolume(lVolume))
  108.  
  109.     if(dwFlags & DSBCAPS_CTRL3D)        // If we want 3D, then get a DirectSound3DBuffer interface
  110.         TRY_DS(m_pBuffer->QueryInterface(IID_IDirectSound3DBuffer, (void**)&m_p3dBuffer))
  111.  
  112.     if(m_p3dBuffer)                     // Sound is 3D
  113.     {
  114.         if(!UpdateSound3D(DS3D_IMMEDIATE))    
  115.             goto DS_ERROR;
  116.     }
  117.     else                                // Sound is 2D
  118.         if(!UpdateSound2D())    
  119.             goto DS_ERROR;
  120.  
  121.     TRY_DS(m_pBuffer->Play(0, 0, m_dwFlags & D3DRMOBJECT_SOUNDLOOPING ? DSBPLAY_LOOPING : 0))
  122.  
  123.     m_pSound = pSound;
  124.  
  125.     return true;
  126.  
  127. DS_ERROR:                                // Oops ! we got an error
  128.     RELEASE(m_p3dBuffer)                // Release any objects which we might have created
  129.     RELEASE(m_pBuffer)
  130.     return false;
  131. }
  132.  
  133. /*
  134.     Function:        DetachSound
  135.     Description:    Destroy the objects DirectSound buffer
  136. */
  137.  
  138. void D3DRMObject::DetachSound()
  139. {
  140.     RELEASE(m_p3dBuffer)
  141.     RELEASE(m_pBuffer)
  142.     m_pSound = NULL;
  143. }
  144.  
  145. /*
  146.     Function:        Update
  147.     Description:    Update the object's position, velocity, sound etc
  148.     Parameters:        delta -    time in seconds by which to advance the object's life
  149.     Return value:    true if successful, false otherwise
  150. */
  151.  
  152. bool D3DRMObject::Update(D3DVALUE delta)
  153. {
  154.     if(IsDead())                        
  155.         return false;                    // It's a stiff, so it's not going anywhere
  156.  
  157.     m_dwAge += (DWORD)(delta*1000);        // Advance the object's age
  158.     if(IsMortal() && m_dwAge > m_dwLifeTime)
  159.     {                                    // Time to die !!
  160.         Kill();                            
  161.         return true;                    
  162.     }
  163.     return UpdateSound(DS3D_DEFERRED);    // Move the object's sound
  164. }
  165.  
  166. /*
  167.     Function:        Collided
  168.     Description:    Checks if object will collide with another object with the supplied parameters
  169.     Parameters:        pFrame - the frame of the other object
  170.                     delta -    time period over which to check the paths of the two objects.  The
  171.                     function determines whether the other object will will pass through our current 
  172.                     position during this period.  This allows the function to be called 
  173.                     infrequently without worrying whether a collision will be missed because the 
  174.                     other object has travelled too far.
  175.     Return value:    true if the objects collide, false otherwise
  176. */
  177.  
  178. bool D3DRMObject::Collided(LPDIRECT3DRMFRAME pFrame, D3DVALUE delta)
  179. {
  180.     D3DVECTOR    p, v;
  181.     D3DVALUE    modulus; 
  182.     D3DVALUE    collisionSize = GetCollisionSize();
  183.     D3DVALUE    step = 0;
  184.     bool        bCollided;
  185.  
  186.     if(collisionSize == 0)                // We have no size, so we can't hit anything
  187.         return false;
  188.     if(m_bKilled)                        // Object is dead, so can't hit anything
  189.         return false;
  190.     if(pFrame == NULL)                    // Other object is dead or invalid
  191.         return false;
  192.  
  193.     TRY_D3DRM(pFrame->GetPosition(m_pFrame, &p))
  194.     TRY_D3DRM(pFrame->GetVelocity(m_pFrame, &v, FALSE))
  195.     modulus = D3DRMVectorModulus(&v); 
  196.     // Calculate how many points along the object's path we must test so we don't miss a collision
  197.     D3DRMVectorScale(&v, &v, delta*collisionSize/modulus);
  198.     do 
  199.     {                        
  200.         
  201.         bCollided = CheckCollision(p);    // Check each point along the path
  202.         D3DRMVectorAdd(&p, &p, &v);        // Get the next point on the path
  203.         step += collisionSize;
  204.     }                                    // Stop at end of path or if we detect a collision
  205.     while((step < modulus) && !bCollided);
  206.  
  207.     return bCollided;
  208.  
  209. D3DRM_ERROR:
  210.     return false;
  211. }
  212.  
  213. /*
  214.     Function:        Kill
  215.     Description:    Destroys the DirectX visual and sound objects associated with this object
  216. */
  217.  
  218. void D3DRMObject::Kill()
  219. {
  220.     LPDIRECT3DRMVISUALARRAY    pVisuals;
  221.     LPDIRECT3DRMVISUAL        pVisual;
  222.  
  223.     m_pFrame->GetVisuals(&pVisuals);
  224.     for(DWORD i = 0; i < pVisuals->GetSize(); i++) 
  225.     {                                        // Destroy the visuals
  226.         pVisuals->GetElement(i, &pVisual);
  227.         m_pFrame->DeleteVisual(pVisual);
  228.     }
  229.     RELEASE(m_pFrame)
  230.     
  231.     RELEASE(m_p3dBuffer)                    // Destroy the sound
  232.     RELEASE(m_pBuffer)
  233.     m_bKilled = true;
  234. }
  235.  
  236. /*
  237.     Function:        UpdateSound
  238.     Description:    Move the sound to the object's current position
  239.     Parameters:        dwApply - DS3D_IMMEDIATE if the sound is to be moved now.  DirectSound will 
  240.                     immediately recalculate the 3D parameters for the sound.
  241.                     DS3D_DEFERRED to wait until the listener is moved
  242.     Return value:    true if successful, false otherwise
  243. */
  244.  
  245. bool D3DRMObject::UpdateSound(DWORD dwApply)
  246. {
  247.     DWORD dwStatus;
  248.  
  249.     if(!m_pFrame)
  250.         return false;                    // Object is either dead or not created yet
  251.     if(!m_pBuffer)
  252.         return true;                    // No sound attached to object    
  253.     if(m_dwFlags & D3DRMOBJECT_DONTMOVESOUND)
  254.         return true;                    // Sound does not move with object
  255.     TRY_DS(m_pBuffer->GetStatus(&dwStatus))
  256.     if(dwStatus == 0)                    // Sound has finished playing
  257.     {                                    // Does object's life depend on whether it makes a sound?
  258.         if(m_dwFlags & D3DRMOBJECT_KILLWITHSOUND)    
  259.             Kill();                        // Yes, so kill the object
  260.         else 
  261.         {                            
  262.             RELEASE(m_p3dBuffer)        // No, so just destroy the sound buffer
  263.             RELEASE(m_pBuffer)
  264.         }
  265.         return true;
  266.     }
  267.     if(m_p3dBuffer)                     // Sound is 3D
  268.         return UpdateSound3D(dwApply);
  269.     else                                // Sound is 2D
  270.         return UpdateSound2D();
  271.  
  272. DS_ERROR:                                // Oops !
  273.     return false;
  274. }
  275.  
  276. /*
  277.     Function:        UpdateSound3D
  278.     Description:    Move the 3D sound buffer to the object's current position
  279.     Parameters:        dwApply - DS3D_IMMEDIATE or DS3D_DEFERRED
  280.     Returns:        true if successful, false otherwise
  281. */
  282.  
  283. bool D3DRMObject::UpdateSound3D(DWORD dwApply)
  284. {
  285.     D3DVECTOR p, v;
  286.  
  287.     // Get the object's current position and velocity
  288.     TRY_D3DRM(m_pFrame->GetPosition(m_pWorld->m_pScene, &p))
  289.     TRY_D3DRM(m_pFrame->GetVelocity(m_pWorld->m_pScene, &v, FALSE))
  290.     // Set the sound's position and velocity
  291.     TRY_DS(m_p3dBuffer->SetPosition(p.x, p.y, p.z, DS3D_DEFERRED))
  292.     TRY_DS(m_p3dBuffer->SetVelocity(v.x, v.y, v.z, dwApply))
  293.     return true;
  294.         
  295. D3DRM_ERROR:                        // Oops ! We got an error
  296. DS_ERROR:
  297.     return false;
  298. }
  299.  
  300. /*
  301.     Function:        UpdateSound2D
  302.     Description:    Pans the 2D sound buffer using the object's current position
  303.     Returns:        true if successful, false otherwise
  304. */
  305.  
  306. bool D3DRMObject::UpdateSound2D()
  307. {
  308.     D3DVECTOR p;
  309.     double x, z, azimuth;
  310.  
  311.     // Get the object's current position relative to the camera
  312.     TRY_D3DRM(m_pFrame->GetPosition(m_pWorld->m_pCamera, &p))
  313.     //  Calculate the volume of the sound using the object's distance
  314.     
  315.     D3DRMVectorNormalize(&p);            // Calculate the horizontal angle of the object
  316.     x = fabs(p.x);
  317.     z = fabs(p.z);
  318.     azimuth = atan(x/z)*180./M_PI;
  319.     if(p.x < 0)
  320.         azimuth = -azimuth;
  321.     
  322.     azimuth *= DSBPAN_RIGHT/90.0;        // +90 is right, -90 is left, 0 or 180 is central    
  323.     
  324.     TRY_DS(m_pBuffer->SetPan((long)azimuth))
  325.     return true;
  326.  
  327. D3DRM_ERROR:
  328. DS_ERROR:
  329.     return false;
  330. }
  331.  
  332. /////////////////////// D3DRMBoxObject class implementation ///////////////////////////////////////
  333.  
  334. D3DRMBoxObject::D3DRMBoxObject(DirectXWorld* pWorld,
  335.                                DWORD id,
  336.                                LPDIRECT3DRMMESHBUILDER pBuilder,
  337.                                DWORD flags,
  338.                                DWORD lifetime)    
  339. : D3DRMObject(pWorld, id, pBuilder, flags,    lifetime, D3DRMCOLLISION_BOX)
  340. {}
  341.  
  342. bool D3DRMBoxObject::CheckCollision(const D3DVECTOR& p)
  343. {
  344.     return(min.x > p.x || max.x < p.x) ? false :
  345.           (min.y > p.y || max.y < p.y) ? false :
  346.           (min.z > p.z || max.z < p.z) ? false : true;
  347. }
  348.  
  349. D3DVALUE D3DRMBoxObject::GetCollisionSize() const
  350. {
  351.     D3DVALUE x = max.x-min.x;
  352.     D3DVALUE y = max.y-min.y;
  353.     D3DVALUE z = max.z-min.z;
  354.     D3DVALUE size = x > y ? y : x;
  355.     return size > z ? z : size;
  356. }
  357.  
  358. /////////////////////// D3DRMSphereObject class implementation ////////////////////////////////////
  359.  
  360. D3DRMSphereObject::D3DRMSphereObject(DirectXWorld* pWorld,
  361.                                      DWORD id,        
  362.                                      LPDIRECT3DRMMESHBUILDER pBuilder,
  363.                                      DWORD flags,
  364.                                      DWORD lifetime)
  365. : D3DRMObject(pWorld, id, pBuilder, flags, lifetime, D3DRMCOLLISION_SPHERE)
  366. {}
  367.  
  368. bool D3DRMSphereObject::CheckCollision(const D3DVECTOR& p)
  369. {
  370.     D3DVECTOR pos = p;
  371.     D3DVALUE m = D3DRMVectorModulus(&pos);
  372.  
  373.     return m > max.x-min.x ? false : true;
  374. }
  375.  
  376. D3DVALUE D3DRMSphereObject::GetCollisionSize() const
  377. {
  378.     return max.x-min.x;
  379. }
  380.  
  381. /////////////////////// D3DRMObjectList class implementation //////////////////////////////////////
  382.  
  383. D3DRMObjectList::D3DRMObjectList()
  384. {
  385.     m_pHead = NULL;
  386.     m_pTail = NULL;
  387.     m_nObjects = 0;
  388. }
  389.  
  390. D3DRMObjectList::~D3DRMObjectList()
  391. {
  392.     while(m_pHead)
  393.         RemoveHead();
  394. }
  395.  
  396. LPD3DRMNODE D3DRMObjectList::Insert(LPD3DRMOBJECT pObject)
  397. {
  398.     if(!m_pHead)
  399.         return InsertHead(pObject);
  400.  
  401.     LPD3DRMNODE pNode = new D3DRMNODE;
  402.     if(!pNode)
  403.         return NULL;
  404.     pNode->pObject = pObject;
  405.     pNode->pNext = NULL;
  406.     if(m_pTail)
  407.         m_pTail->pNext = pNode;
  408.     m_pTail = pNode;
  409.     m_nObjects++;
  410.     return pNode;
  411. }
  412.  
  413. LPD3DRMNODE D3DRMObjectList::Remove(LPD3DRMNODE pNode)
  414. {
  415.     LPD3DRMNODE pNext;
  416.  
  417.     if(m_pHead == pNode)
  418.         return RemoveHead();
  419.  
  420.     LPD3DRMNODE pThis = m_pHead;
  421.     while(pThis->pNext != m_pTail)
  422.     {
  423.         if(pThis->pNext == pNode)
  424.         {
  425.             pNext = pThis->pNext;
  426.             pThis->pNext = pNext->pNext;
  427.             delete pNext;
  428.             m_nObjects--;
  429.             if(m_nObjects == 0)
  430.                 m_pTail = NULL;
  431.             return pThis->pNext;
  432.         }
  433.         pThis = pThis->pNext;
  434.     }
  435.     if(pThis->pNext == pNode)
  436.     {
  437.         m_pTail = pThis;
  438.         delete pThis->pNext;
  439.         pThis->pNext = NULL;
  440.         m_nObjects--;
  441.         if(m_nObjects == 0)
  442.             m_pTail = NULL;
  443.         return NULL;
  444.     }
  445.     return pNode;
  446. }
  447.  
  448. LPD3DRMNODE D3DRMObjectList::RemoveHead()
  449. {
  450.     LPD3DRMNODE pOldHead;
  451.  
  452.     pOldHead = m_pHead;
  453.     m_pHead = m_pHead->pNext;
  454.     delete pOldHead;
  455.     m_nObjects--;
  456.     if(m_nObjects == 0)
  457.         m_pTail = NULL;
  458.     return m_pHead;
  459. }
  460.  
  461. LPD3DRMNODE D3DRMObjectList::InsertHead(LPD3DRMOBJECT pObject)
  462. {
  463.     LPD3DRMNODE pNewHead = new D3DRMNODE;
  464.     if(!pNewHead)
  465.         return NULL;
  466.  
  467.     pNewHead->pObject = pObject;
  468.     pNewHead->pNext = m_pHead;
  469.     m_pHead = pNewHead;
  470.     if(!m_pTail)
  471.         m_pTail = pNewHead;
  472.     m_nObjects++;
  473.  
  474.     return m_pHead;
  475. }
  476.  
  477. LPD3DRMNODE D3DRMObjectList::First(DWORD dwId)
  478. {
  479.     LPD3DRMNODE pNode = m_pHead;
  480.  
  481.     while(pNode && pNode->pObject->GetID() != dwId)
  482.         pNode = pNode->pNext;
  483.  
  484.     return pNode;
  485. }
  486.  
  487. LPD3DRMNODE D3DRMObjectList::Last(DWORD dwId)
  488. {
  489.     LPD3DRMNODE pNode = m_pHead;
  490.     LPD3DRMNODE pRetNode = NULL;
  491.  
  492.     while(pNode)
  493.     {
  494.         if(pNode->pObject->GetID() == dwId)
  495.             pRetNode = pNode;
  496.  
  497.         pNode = pNode->pNext;
  498.     }
  499.  
  500.     return pRetNode;
  501. }
  502.  
  503.