sfx3DWorld.cpp

Engine/source/T3D/sfx/sfx3DWorld.cpp

More...

Public Variables

The singleton instance of SFX3DWorld, if there is one.

Detailed Description

Public Variables

SFX3DWorld * gSFX3DWorld 

The singleton instance of SFX3DWorld, if there is one.

 MODULE_END 
 MODULE_INIT 
 MODULE_SHUTDOWN 
  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "T3D/sfx/sfx3DWorld.h"
 25#include "T3D/portal.h"
 26#include "T3D/shapeBase.h"
 27#include "ts/tsShapeInstance.h"
 28#include "sfx/sfxSystem.h"
 29#include "math/mBox.h"
 30#include "core/module.h"
 31#include "T3D/gameBase/gameConnection.h"
 32
 33
 34//#define DEBUG_SPEW
 35
 36
 37MODULE_BEGIN( SFX3D )
 38
 39   MODULE_INIT_AFTER( Scene )
 40   MODULE_SHUTDOWN_BEFORE( Scene )
 41   
 42   MODULE_INIT
 43   {
 44      if( !Con::getBoolVariable( "$SFX::noSFXWorld", false ) )
 45         gSFX3DWorld = new SFX3DWorld;
 46   }
 47   
 48   MODULE_SHUTDOWN
 49   {
 50      if( gSFX3DWorld )
 51         SAFE_DELETE( gSFX3DWorld );
 52   }
 53
 54MODULE_END;
 55
 56
 57SFX3DWorld* gSFX3DWorld;
 58
 59
 60//=============================================================================
 61//    SFX3DObject.
 62//=============================================================================
 63
 64//-----------------------------------------------------------------------------
 65
 66SFX3DObject::SFX3DObject( SFX3DWorld* world, SceneObject* object )
 67   : Parent( world, object )
 68{
 69   if( mObject->isOccludingSound() )
 70      setFlags( SFXObjectOccluder );
 71   if( dynamic_cast< Portal* >( mObject ) )
 72      setFlags( SFXObjectPortal );
 73   if( object->getSoundAmbience() )
 74      setFlags( SFXObjectZone );
 75}
 76
 77//-----------------------------------------------------------------------------
 78
 79void SFX3DObject::getEarTransform( MatrixF& transform ) const
 80{
 81   // If it's not a ShapeBase, just use the object transform.   
 82   ShapeBase* shape = dynamic_cast< ShapeBase* >( mObject );
 83   if ( !shape )
 84   {
 85      transform = mObject->getTransform();
 86      return;
 87   }
 88
 89   // It it's ShapeBase, use the earNode transform if one was defined.
 90   // Otherwise, use the camera transform.
 91   TSShapeInstance* shapeInstance = shape->getShapeInstance();
 92   if ( !shapeInstance )
 93   {
 94      // Just in case.
 95      GameConnection* connection = dynamic_cast<GameConnection *>(NetConnection::getConnectionToServer());
 96      if ( !connection || !connection->getControlCameraTransform( 0.0f, &transform ) )
 97         transform = mObject->getTransform();
 98      return;
 99   }
100
101   ShapeBaseData* datablock = dynamic_cast< ShapeBaseData* >( shape->getDataBlock() );
102   AssertFatal( datablock, "SFX3DObject::getEarTransform() - shape without ShapeBaseData datablock!" );
103   
104   // Get the transform for the ear node.
105       
106   const S32 earNode = datablock->earNode;
107
108   if ( earNode != -1 && earNode != datablock->eyeNode )
109   {
110      transform = shape->getTransform();
111      transform *= shapeInstance->mNodeTransforms[ earNode ];
112   }
113   else
114   {
115      GameConnection* connection = dynamic_cast<GameConnection *>(NetConnection::getConnectionToServer());
116      if ( !connection || !connection->getControlCameraTransform( 0.0f, &transform ) )
117         transform = mObject->getTransform();
118   }
119}
120
121//-----------------------------------------------------------------------------
122
123void SFX3DObject::getReferenceCenter( F32 position[ 3 ] ) const
124{
125   MatrixF transform;
126   getEarTransform( transform );
127   Point3F pos = transform.getPosition();
128   
129   AssertFatal( TypeTraits< F32 >::MIN <= pos.x && pos.x <= TypeTraits< F32 >::MAX,
130      "SFX3DObject::getReferenceCenter - invalid float in reference center X position" );
131   AssertFatal( TypeTraits< F32 >::MIN <= pos.y && pos.y <= TypeTraits< F32 >::MAX,
132      "SFX3DObject::getReferenceCenter - invalid float in reference center Y position" );
133   AssertFatal( TypeTraits< F32 >::MIN <= pos.z && pos.z <= TypeTraits< F32 >::MAX,
134      "SFX3DObject::getReferenceCenter - invalid float in reference center Z position" );
135   
136   dMemcpy( position, &pos.x, sizeof( F32 ) * 3 );
137}
138
139//-----------------------------------------------------------------------------
140
141void SFX3DObject::getBounds( F32 minBounds[ 3 ], F32 maxBounds[ 3 ] ) const
142{
143   getRealBounds( minBounds, maxBounds );
144}
145
146//-----------------------------------------------------------------------------
147
148void SFX3DObject::getRealBounds( F32 minBounds[ 3 ], F32 maxBounds[ 3 ] ) const
149{
150   const Box3F& worldBox = mObject->getWorldBox();
151   dMemcpy( minBounds, &worldBox.minExtents.x, sizeof( F32 ) * 3 );
152   dMemcpy( maxBounds, &worldBox.maxExtents.x, sizeof( F32 ) * 3 );
153}
154
155//-----------------------------------------------------------------------------
156
157SFXAmbience* SFX3DObject::getAmbience() const
158{
159   return mObject->getSoundAmbience();
160}
161
162//-----------------------------------------------------------------------------
163
164bool SFX3DObject::containsPoint( const F32 point[ 3 ] ) const
165{
166   return mObject->containsPoint( *( reinterpret_cast< const Point3F* >( &point[ 0 ] ) ) );
167}
168
169//-----------------------------------------------------------------------------
170
171String SFX3DObject::describeSelf() const
172{
173   return mObject->describeSelf();
174}
175
176//=============================================================================
177//    SFX3DWorld.
178//=============================================================================
179
180//-----------------------------------------------------------------------------
181
182SFX3DWorld::SFX3DWorld()
183   : Parent( true, TYPEMASK )
184{
185}
186
187//-----------------------------------------------------------------------------
188
189bool SFX3DWorld::_isTrackableObject( SceneObject* object ) const
190{
191   if( !Parent::_isTrackableObject( object ) )
192      return false;
193      
194   // We are only interested in occluders, zones, and portals.
195      
196   if( object->isOccludingSound() )
197      return true;
198   else if( object->getSoundAmbience() )
199      return true;
200   else if( dynamic_cast< Portal* >( object ) )
201      return true;
202      
203   return false;
204}
205
206//-----------------------------------------------------------------------------
207
208void SFX3DWorld::update()
209{
210   mSFXWorld.update();
211}
212
213//-----------------------------------------------------------------------------
214
215void SFX3DWorld::registerObject( SceneObject* object )
216{
217   if( !_isTrackableObject( object ) )
218      return;
219      
220   // Construct a new scene object link.
221      
222   SFX3DObject* sfxObject = mChunker.alloc();
223   constructInPlace( sfxObject, this, object );
224   
225   // Register it with the SFX world.
226   
227   #ifdef DEBUG_SPEW
228   Platform::outputDebugString( "[SFX3DWorld] Registering %i:%s as 0x%x",
229      object->getId(), object->getClassName(), sfxObject );
230   #endif
231   
232   mSFXWorld.registerObject( sfxObject );
233}
234
235//-----------------------------------------------------------------------------
236
237void SFX3DWorld::unregisterObject( SceneObject* object )
238{
239   SFX3DObject* sfxObject = dynamic_cast< SFX3DObject* >( SFX3DObject::getLinkForTracker( this, object ) );
240   if( !sfxObject )
241      return;
242      
243   #ifdef DEBUG_SPEW
244   Platform::outputDebugString( "[SFX3DWorld] Unregistering %i:%s (was 0x%x)",
245      object->getId(), object->getClassName(), sfxObject );
246   #endif
247
248   // Remove the object from the SFX world.
249      
250   if( sfxObject->isListener() )
251      mSFXWorld.setReferenceObject( NULL );
252   else
253      mSFXWorld.unregisterObject( sfxObject );
254   
255   // Destroy the scene object link.
256   
257   destructInPlace( sfxObject );
258   mChunker.free( sfxObject );
259}
260
261//-----------------------------------------------------------------------------
262
263void SFX3DWorld::updateObject( SceneObjectLink* object )
264{
265   SFX3DObject* sfxObject = dynamic_cast< SFX3DObject* >( object );
266   AssertFatal( sfxObject, "SFX3DWorld::updateObject - invalid object type" );
267   
268   mSFXWorld.updateObject( sfxObject );
269   
270   // If this is the listener object, update its
271   // properties on the SFX system.
272   
273   if( sfxObject->isListener() )
274   {
275      SFXListenerProperties listener;
276      sfxObject->getEarTransform( listener.getTransform() );
277      listener.getVelocity() = sfxObject->getObject()->getVelocity();
278      
279      SFX->setListener( 0, listener );
280   }
281}
282
283//-----------------------------------------------------------------------------
284
285SceneObject* SFX3DWorld::getListener() const
286{
287   SFX3DObject* object = mSFXWorld.getReferenceObject();
288   if( !object )
289      return NULL;
290      
291   return object->getObject();
292}
293
294//-----------------------------------------------------------------------------
295
296void SFX3DWorld::setListener( SceneObject* object )
297{
298   SFX3DObject* oldListener = mSFXWorld.getReferenceObject();
299
300   // If it's the same object as our current listener,
301   // return.
302
303   if( oldListener && oldListener->getObject() == object )
304      return;
305
306   // Create a SFX3DObject for the given SceneObject.
307
308   SFX3DObject* sfxObject = NULL;
309   if( object )
310   {
311      AssertFatal( !dynamic_cast< SFX3DObject* >( SFX3DObject::getLinkForTracker( this, object ) ),
312         "SFX3DWorld::setListener - listener objects must not be registered for tracking" );
313
314      sfxObject = mChunker.alloc();
315      constructInPlace( sfxObject, this, object );
316      sfxObject->setFlags( SFXObjectListener );
317   }
318
319#ifdef DEBUG_SPEW
320   if( object )
321      Platform::outputDebugString( "[SFX3DWorld] Listener is now %i:%s (%s)",
322      object->getId(), object->getClassName(), object->getName() );
323   else
324      Platform::outputDebugString( "[SFX3DWorld] Unsetting listener" );
325#endif
326
327   // Make this object the center of our SFX world.
328
329   mSFXWorld.setReferenceObject( sfxObject );
330
331   // Remove the tracking links from the old listener so we
332   // don't see further updates on it.
333
334   if( oldListener )
335   {
336      destructInPlace( oldListener );
337      mChunker.free( oldListener );
338   }
339}
340
341//-----------------------------------------------------------------------------
342
343void SFX3DWorld::notifyChanged( SceneObject* object )
344{
345   SFX3DObject* sfxObject = dynamic_cast< SFX3DObject* >( SFX3DObject::getLinkForTracker( this, object ) );
346
347   if( !sfxObject && _isTrackableObject( object ) )
348      registerObject( object );
349   else if( sfxObject && !_isTrackableObject( object ) )
350      unregisterObject( object );
351   else if( sfxObject )
352      mSFXWorld.notifyChanged( sfxObject );
353}
354
355//-----------------------------------------------------------------------------
356
357void SFX3DWorld::debugDump()
358{
359   mSFXWorld.debugDump();
360}
361