home *** CD-ROM | disk | FTP | other *** search
- /*
- Company: Sensaura
- Copyright: (C) 1999
-
- File Name: object3d.cpp
- File Description: Source file for implementation of base classes for D3DRM objects with
- sounds attached
- Author: Adam Philp
- File Version: 1.02.000
- Last Update: 11-FEB-99
-
- Target Compiler: Microsoft Visual C++ Version 5.0
- */
-
- /////////////////////// Included files ////////////////////////////////////////////////////////////
-
- #include <windows.h>
- #include <math.h>
-
- #include "object3d.h"
- #include "dxworld.h"
- #include "directx.h" // DirectX support functions and macros
- #include "debug.h"
-
- /////////////////////// Constants /////////////////////////////////////////////////////////////////
-
- const double M_PI = 3.14159265;
-
- /////////////////////// D3DRMObject class implementation //////////////////////////////////////////
-
- D3DRMObject::D3DRMObject(DirectXWorld* pWorld,
- DWORD id,
- LPDIRECT3DRMMESHBUILDER pBuilder,
- DWORD flags,
- DWORD lifetime,
- D3DRMCOLLISION collision)
- {
- m_Collision = collision; // Save collision shape
- m_pWorld = pWorld; // Save object properties
- m_dwId = id;
- m_dwFlags = flags;
- m_dwLifeTime = lifetime;
- m_dwAge = 0; // Object has just been born
- m_bKilled = false;
-
- m_pFrame = NULL; // Initialize data members
- m_pSound = NULL; // No sound attached to object initially
- m_pBuffer = NULL;
- m_p3dBuffer = NULL;
-
- TRY_D3DRM(m_pWorld->m_pD3DRM->CreateFrame(m_pWorld->m_pScene, &m_pFrame))
- TRY_D3DRM(pBuilder->GetBox(this))
- return;
-
- D3DRM_ERROR:
- RELEASE(m_pFrame)
- }
-
- D3DRMObject::~D3DRMObject()
- {
- if(!m_bKilled) // Kill object if necessary
- Kill();
- }
-
- /*
- Function: AttachSound
- Description: Create, position and play a DirectSound buffer for the object's attached sound
- Parameters: pSound - pointer to the sound's resource
- Returns: true if the buffer was successfully created, false otherwise
- */
-
- bool D3DRMObject::AttachSound(LPCTSTR pSound)
- {
- long lVolume;
-
- ASSERT(pSound);
- if(!pSound) // Don't bother if there's no sound attached to the object
- return false;
-
- RELEASE(m_p3dBuffer) // Destroy DirectSound buffer if we have one
- RELEASE(m_pBuffer)
-
- DWORD dwFlags = DSBCAPS_STATIC|DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME;
- // Do we want 3D sound? Is DirectSound3D support enabled?
- switch(m_pWorld->m_DirectSoundType)
- {
- case DIRECTSOUND3D_SENSAURA:
- case DIRECTSOUND3D_HARDWARE: // Request a hardware 3D buffer from DirectSound
- dwFlags |= DSBCAPS_CTRL3D|DSBCAPS_LOCHARDWARE;
- lVolume = 0; // 0dB attenuation
- break;
-
- case DIRECTSOUND3D_SOFTWARE: // Request a software 3D buffer from DirectSound
- dwFlags |= DSBCAPS_CTRL3D|DSBCAPS_LOCSOFTWARE;
- lVolume = -600; // 6dB attenuation
- break;
-
- default: // Request a 2D buffer from DirectSound
- dwFlags |= DSBCAPS_CTRLPAN;
- lVolume = -1500; // 15dB attenuation
- }
- // Create the DirectSound buffer
- m_pBuffer = CreateDSBufferFromResource(m_pWorld->m_pDS, dwFlags, pSound);
- if(m_pBuffer == NULL)
- return false;
-
- TRY_DS(m_pBuffer->SetVolume(lVolume))
-
- if(dwFlags & DSBCAPS_CTRL3D) // If we want 3D, then get a DirectSound3DBuffer interface
- TRY_DS(m_pBuffer->QueryInterface(IID_IDirectSound3DBuffer, (void**)&m_p3dBuffer))
-
- if(m_p3dBuffer) // Sound is 3D
- {
- if(!UpdateSound3D(DS3D_IMMEDIATE))
- goto DS_ERROR;
- }
- else // Sound is 2D
- if(!UpdateSound2D())
- goto DS_ERROR;
-
- TRY_DS(m_pBuffer->Play(0, 0, m_dwFlags & D3DRMOBJECT_SOUNDLOOPING ? DSBPLAY_LOOPING : 0))
-
- m_pSound = pSound;
-
- return true;
-
- DS_ERROR: // Oops ! we got an error
- RELEASE(m_p3dBuffer) // Release any objects which we might have created
- RELEASE(m_pBuffer)
- return false;
- }
-
- /*
- Function: DetachSound
- Description: Destroy the objects DirectSound buffer
- */
-
- void D3DRMObject::DetachSound()
- {
- RELEASE(m_p3dBuffer)
- RELEASE(m_pBuffer)
- m_pSound = NULL;
- }
-
- /*
- Function: Update
- Description: Update the object's position, velocity, sound etc
- Parameters: delta - time in seconds by which to advance the object's life
- Return value: true if successful, false otherwise
- */
-
- bool D3DRMObject::Update(D3DVALUE delta)
- {
- if(IsDead())
- return false; // It's a stiff, so it's not going anywhere
-
- m_dwAge += (DWORD)(delta*1000); // Advance the object's age
- if(IsMortal() && m_dwAge > m_dwLifeTime)
- { // Time to die !!
- Kill();
- return true;
- }
- return UpdateSound(DS3D_DEFERRED); // Move the object's sound
- }
-
- /*
- Function: Collided
- Description: Checks if object will collide with another object with the supplied parameters
- Parameters: pFrame - the frame of the other object
- delta - time period over which to check the paths of the two objects. The
- function determines whether the other object will will pass through our current
- position during this period. This allows the function to be called
- infrequently without worrying whether a collision will be missed because the
- other object has travelled too far.
- Return value: true if the objects collide, false otherwise
- */
-
- bool D3DRMObject::Collided(LPDIRECT3DRMFRAME pFrame, D3DVALUE delta)
- {
- D3DVECTOR p, v;
- D3DVALUE modulus;
- D3DVALUE collisionSize = GetCollisionSize();
- D3DVALUE step = 0;
- bool bCollided;
-
- if(collisionSize == 0) // We have no size, so we can't hit anything
- return false;
- if(m_bKilled) // Object is dead, so can't hit anything
- return false;
- if(pFrame == NULL) // Other object is dead or invalid
- return false;
-
- TRY_D3DRM(pFrame->GetPosition(m_pFrame, &p))
- TRY_D3DRM(pFrame->GetVelocity(m_pFrame, &v, FALSE))
- modulus = D3DRMVectorModulus(&v);
- // Calculate how many points along the object's path we must test so we don't miss a collision
- D3DRMVectorScale(&v, &v, delta*collisionSize/modulus);
- do
- {
-
- bCollided = CheckCollision(p); // Check each point along the path
- D3DRMVectorAdd(&p, &p, &v); // Get the next point on the path
- step += collisionSize;
- } // Stop at end of path or if we detect a collision
- while((step < modulus) && !bCollided);
-
- return bCollided;
-
- D3DRM_ERROR:
- return false;
- }
-
- /*
- Function: Kill
- Description: Destroys the DirectX visual and sound objects associated with this object
- */
-
- void D3DRMObject::Kill()
- {
- LPDIRECT3DRMVISUALARRAY pVisuals;
- LPDIRECT3DRMVISUAL pVisual;
-
- m_pFrame->GetVisuals(&pVisuals);
- for(DWORD i = 0; i < pVisuals->GetSize(); i++)
- { // Destroy the visuals
- pVisuals->GetElement(i, &pVisual);
- m_pFrame->DeleteVisual(pVisual);
- }
- RELEASE(m_pFrame)
-
- RELEASE(m_p3dBuffer) // Destroy the sound
- RELEASE(m_pBuffer)
- m_bKilled = true;
- }
-
- /*
- Function: UpdateSound
- Description: Move the sound to the object's current position
- Parameters: dwApply - DS3D_IMMEDIATE if the sound is to be moved now. DirectSound will
- immediately recalculate the 3D parameters for the sound.
- DS3D_DEFERRED to wait until the listener is moved
- Return value: true if successful, false otherwise
- */
-
- bool D3DRMObject::UpdateSound(DWORD dwApply)
- {
- DWORD dwStatus;
-
- if(!m_pFrame)
- return false; // Object is either dead or not created yet
- if(!m_pBuffer)
- return true; // No sound attached to object
- if(m_dwFlags & D3DRMOBJECT_DONTMOVESOUND)
- return true; // Sound does not move with object
- TRY_DS(m_pBuffer->GetStatus(&dwStatus))
- if(dwStatus == 0) // Sound has finished playing
- { // Does object's life depend on whether it makes a sound?
- if(m_dwFlags & D3DRMOBJECT_KILLWITHSOUND)
- Kill(); // Yes, so kill the object
- else
- {
- RELEASE(m_p3dBuffer) // No, so just destroy the sound buffer
- RELEASE(m_pBuffer)
- }
- return true;
- }
- if(m_p3dBuffer) // Sound is 3D
- return UpdateSound3D(dwApply);
- else // Sound is 2D
- return UpdateSound2D();
-
- DS_ERROR: // Oops !
- return false;
- }
-
- /*
- Function: UpdateSound3D
- Description: Move the 3D sound buffer to the object's current position
- Parameters: dwApply - DS3D_IMMEDIATE or DS3D_DEFERRED
- Returns: true if successful, false otherwise
- */
-
- bool D3DRMObject::UpdateSound3D(DWORD dwApply)
- {
- D3DVECTOR p, v;
-
- // Get the object's current position and velocity
- TRY_D3DRM(m_pFrame->GetPosition(m_pWorld->m_pScene, &p))
- TRY_D3DRM(m_pFrame->GetVelocity(m_pWorld->m_pScene, &v, FALSE))
- // Set the sound's position and velocity
- TRY_DS(m_p3dBuffer->SetPosition(p.x, p.y, p.z, DS3D_DEFERRED))
- TRY_DS(m_p3dBuffer->SetVelocity(v.x, v.y, v.z, dwApply))
- return true;
-
- D3DRM_ERROR: // Oops ! We got an error
- DS_ERROR:
- return false;
- }
-
- /*
- Function: UpdateSound2D
- Description: Pans the 2D sound buffer using the object's current position
- Returns: true if successful, false otherwise
- */
-
- bool D3DRMObject::UpdateSound2D()
- {
- D3DVECTOR p;
- double x, z, azimuth;
-
- // Get the object's current position relative to the camera
- TRY_D3DRM(m_pFrame->GetPosition(m_pWorld->m_pCamera, &p))
- // Calculate the volume of the sound using the object's distance
-
- D3DRMVectorNormalize(&p); // Calculate the horizontal angle of the object
- x = fabs(p.x);
- z = fabs(p.z);
- azimuth = atan(x/z)*180./M_PI;
- if(p.x < 0)
- azimuth = -azimuth;
-
- azimuth *= DSBPAN_RIGHT/90.0; // +90 is right, -90 is left, 0 or 180 is central
-
- TRY_DS(m_pBuffer->SetPan((long)azimuth))
- return true;
-
- D3DRM_ERROR:
- DS_ERROR:
- return false;
- }
-
- /////////////////////// D3DRMBoxObject class implementation ///////////////////////////////////////
-
- D3DRMBoxObject::D3DRMBoxObject(DirectXWorld* pWorld,
- DWORD id,
- LPDIRECT3DRMMESHBUILDER pBuilder,
- DWORD flags,
- DWORD lifetime)
- : D3DRMObject(pWorld, id, pBuilder, flags, lifetime, D3DRMCOLLISION_BOX)
- {}
-
- bool D3DRMBoxObject::CheckCollision(const D3DVECTOR& p)
- {
- return(min.x > p.x || max.x < p.x) ? false :
- (min.y > p.y || max.y < p.y) ? false :
- (min.z > p.z || max.z < p.z) ? false : true;
- }
-
- D3DVALUE D3DRMBoxObject::GetCollisionSize() const
- {
- D3DVALUE x = max.x-min.x;
- D3DVALUE y = max.y-min.y;
- D3DVALUE z = max.z-min.z;
- D3DVALUE size = x > y ? y : x;
- return size > z ? z : size;
- }
-
- /////////////////////// D3DRMSphereObject class implementation ////////////////////////////////////
-
- D3DRMSphereObject::D3DRMSphereObject(DirectXWorld* pWorld,
- DWORD id,
- LPDIRECT3DRMMESHBUILDER pBuilder,
- DWORD flags,
- DWORD lifetime)
- : D3DRMObject(pWorld, id, pBuilder, flags, lifetime, D3DRMCOLLISION_SPHERE)
- {}
-
- bool D3DRMSphereObject::CheckCollision(const D3DVECTOR& p)
- {
- D3DVECTOR pos = p;
- D3DVALUE m = D3DRMVectorModulus(&pos);
-
- return m > max.x-min.x ? false : true;
- }
-
- D3DVALUE D3DRMSphereObject::GetCollisionSize() const
- {
- return max.x-min.x;
- }
-
- /////////////////////// D3DRMObjectList class implementation //////////////////////////////////////
-
- D3DRMObjectList::D3DRMObjectList()
- {
- m_pHead = NULL;
- m_pTail = NULL;
- m_nObjects = 0;
- }
-
- D3DRMObjectList::~D3DRMObjectList()
- {
- while(m_pHead)
- RemoveHead();
- }
-
- LPD3DRMNODE D3DRMObjectList::Insert(LPD3DRMOBJECT pObject)
- {
- if(!m_pHead)
- return InsertHead(pObject);
-
- LPD3DRMNODE pNode = new D3DRMNODE;
- if(!pNode)
- return NULL;
- pNode->pObject = pObject;
- pNode->pNext = NULL;
- if(m_pTail)
- m_pTail->pNext = pNode;
- m_pTail = pNode;
- m_nObjects++;
- return pNode;
- }
-
- LPD3DRMNODE D3DRMObjectList::Remove(LPD3DRMNODE pNode)
- {
- LPD3DRMNODE pNext;
-
- if(m_pHead == pNode)
- return RemoveHead();
-
- LPD3DRMNODE pThis = m_pHead;
- while(pThis->pNext != m_pTail)
- {
- if(pThis->pNext == pNode)
- {
- pNext = pThis->pNext;
- pThis->pNext = pNext->pNext;
- delete pNext;
- m_nObjects--;
- if(m_nObjects == 0)
- m_pTail = NULL;
- return pThis->pNext;
- }
- pThis = pThis->pNext;
- }
- if(pThis->pNext == pNode)
- {
- m_pTail = pThis;
- delete pThis->pNext;
- pThis->pNext = NULL;
- m_nObjects--;
- if(m_nObjects == 0)
- m_pTail = NULL;
- return NULL;
- }
- return pNode;
- }
-
- LPD3DRMNODE D3DRMObjectList::RemoveHead()
- {
- LPD3DRMNODE pOldHead;
-
- pOldHead = m_pHead;
- m_pHead = m_pHead->pNext;
- delete pOldHead;
- m_nObjects--;
- if(m_nObjects == 0)
- m_pTail = NULL;
- return m_pHead;
- }
-
- LPD3DRMNODE D3DRMObjectList::InsertHead(LPD3DRMOBJECT pObject)
- {
- LPD3DRMNODE pNewHead = new D3DRMNODE;
- if(!pNewHead)
- return NULL;
-
- pNewHead->pObject = pObject;
- pNewHead->pNext = m_pHead;
- m_pHead = pNewHead;
- if(!m_pTail)
- m_pTail = pNewHead;
- m_nObjects++;
-
- return m_pHead;
- }
-
- LPD3DRMNODE D3DRMObjectList::First(DWORD dwId)
- {
- LPD3DRMNODE pNode = m_pHead;
-
- while(pNode && pNode->pObject->GetID() != dwId)
- pNode = pNode->pNext;
-
- return pNode;
- }
-
- LPD3DRMNODE D3DRMObjectList::Last(DWORD dwId)
- {
- LPD3DRMNODE pNode = m_pHead;
- LPD3DRMNODE pRetNode = NULL;
-
- while(pNode)
- {
- if(pNode->pObject->GetID() == dwId)
- pRetNode = pNode;
-
- pNode = pNode->pNext;
- }
-
- return pRetNode;
- }
-
-