sfx3DWorld.cpp
Engine/source/T3D/sfx/sfx3DWorld.cpp
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