sfxFMODProject.cpp
Engine/source/sfx/fmod/sfxFMODProject.cpp
Public Functions
ConsoleDocClass(SFXFMODProject , "@brief An FMOD Designer project loaded into <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Torque.\n\n</a>" "@section SFXFMODProject_resources <a href="/coding/class/classresource/">Resource</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Loading\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SFXFMOD\n</a>" "@ingroup Datablocks" )
Detailed Description
Public Functions
ConsoleDocClass(SFXFMODProject , "@brief An FMOD Designer project loaded into <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Torque.\n\n</a>" "@section SFXFMODProject_resources <a href="/coding/class/classresource/">Resource</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Loading\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SFXFMOD\n</a>" "@ingroup Datablocks" )
IMPLEMENT_CO_DATABLOCK_V1(SFXFMODProject )
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 "sfx/fmod/sfxFMODProject.h" 25#include "sfx/fmod/sfxFMODDevice.h" 26#include "sfx/fmod/sfxFMODEvent.h" 27#include "sfx/fmod/sfxFMODEventGroup.h" 28#include "sfx/sfxDescription.h" 29#include "core/stringTable.h" 30#include "core/volume.h" 31#include "core/util/path.h" 32#include "core/stream/fileStream.h" 33#include "core/stream/bitStream.h" 34#include "core/util/safeDelete.h" 35 36 37IMPLEMENT_CO_DATABLOCK_V1( SFXFMODProject ); 38 39 40ConsoleDocClass( SFXFMODProject, 41 "@brief An FMOD Designer project loaded into Torque.\n\n" 42 43 "@section SFXFMODProject_resources Resource Loading\n\n" 44 45 "@ingroup SFXFMOD\n" 46 "@ingroup Datablocks" 47); 48 49 50//----------------------------------------------------------------------------- 51 52SFXFMODProject::SFXFMODProject() 53 : mHandle( NULL ), 54 mRootGroups( NULL ) 55{ 56 VECTOR_SET_ASSOCIATION( mGroups ); 57 VECTOR_SET_ASSOCIATION( mEvents ); 58 59 SFX->getEventSignal().notify( this, &SFXFMODProject::_onSystemEvent ); 60} 61 62//----------------------------------------------------------------------------- 63 64SFXFMODProject::~SFXFMODProject() 65{ 66 AssertFatal( mGroups.empty(), "SFXFMODProject::~SFXFMODProject - project still has groups attached" ); 67 AssertFatal( mEvents.empty(), "SFXFMODProject::~SFXFMODProject - project still has events attached" ); 68 69 if( SFX ) 70 SFX->getEventSignal().remove( this, &SFXFMODProject::_onSystemEvent ); 71} 72 73//----------------------------------------------------------------------------- 74 75void SFXFMODProject::initPersistFields() 76{ 77 addGroup( "FMOD" ); 78 79 addField( "fileName", TypeStringFilename, Offset( mFileName, SFXFMODProject ), "The compiled .fev file from FMOD Designer." ); 80 addField( "mediaPath", TypeStringFilename, Offset( mMediaPath, SFXFMODProject ), "Path to the media files; if unset, defaults to project directory." ); 81 82 endGroup( "FMOD" ); 83 84 Parent::initPersistFields(); 85} 86 87//----------------------------------------------------------------------------- 88 89bool SFXFMODProject::onAdd() 90{ 91 if( !Parent::onAdd() ) 92 return false; 93 94 // If this is a non-networked datablock, load the 95 // project data now. 96 97 if( isClientOnly() && !_load() ) 98 return false; 99 100 return true; 101} 102 103//----------------------------------------------------------------------------- 104 105void SFXFMODProject::onRemove() 106{ 107 Parent::onRemove(); 108 109 _clear(); 110} 111 112//----------------------------------------------------------------------------- 113 114bool SFXFMODProject::preload( bool server, String& errorStr ) 115{ 116 if( !Parent::preload( server, errorStr ) ) 117 return false; 118 119 if( server ) 120 { 121 if( mFileName.isEmpty() ) 122 { 123 errorStr = String::ToString( "SFXFMODProject::preload - no filename set on %i (%s)", 124 getId(), getName() ); 125 return false; 126 } 127 128 if( mGroups.empty() || mEvents.empty() ) 129 _load(); 130 131 release(); 132 } 133 134 return true; 135} 136 137//----------------------------------------------------------------------------- 138 139void SFXFMODProject::packData( BitStream* stream ) 140{ 141 Parent::packData( stream ); 142 143 stream->write( mFileName ); 144 stream->write( mMediaPath ); 145} 146 147//----------------------------------------------------------------------------- 148 149void SFXFMODProject::unpackData( BitStream* stream ) 150{ 151 Parent::unpackData( stream ); 152 153 stream->read( &mFileName ); 154 stream->read( &mMediaPath ); 155} 156 157//----------------------------------------------------------------------------- 158 159void SFXFMODProject::_onSystemEvent( SFXSystemEventType event ) 160{ 161 switch( event ) 162 { 163 case SFXSystemEvent_DestroyDevice: 164 165 // If the FMOD device is being destroyed, 166 // release all our data. 167 168 if( SFXFMODDevice::instance() ) 169 release(); 170 171 break; 172 173 default: 174 break; 175 } 176} 177 178//----------------------------------------------------------------------------- 179 180void SFXFMODProject::_clear() 181{ 182 release(); 183 184 for( U32 i = 0; i < mGroups.size(); ++ i ) 185 if( !mGroups[ i ]->isRemoved() ) 186 mGroups[ i ]->deleteObject(); 187 188 mGroups.clear(); 189 mEvents.clear(); 190 191 mRootGroups = NULL; 192} 193 194//----------------------------------------------------------------------------- 195 196bool SFXFMODProject::_load() 197{ 198 const Torque::Path eventScriptFileName = mFileName + ".cs"; 199 const Torque::Path eventScriptFileNameDSO = eventScriptFileName + ".dso"; 200 const bool eventScriptFileExists = Torque::FS::IsFile( eventScriptFileName ); 201 const bool eventScriptFileDSOExists = Torque::FS::IsFile( eventScriptFileNameDSO ); 202 203 // Check if we need to (re-)generate the event script file. 204 205 bool needToGenerateEventScriptFile = false; 206 if( ( !eventScriptFileExists && !eventScriptFileDSOExists ) 207 || ( Torque::FS::CompareModifiedTimes( mFileName, eventScriptFileName ) > 0 208 || Torque::FS::CompareModifiedTimes( mFileName, eventScriptFileNameDSO ) > 0 ) ) 209 needToGenerateEventScriptFile = true; 210 211 // If we need to generate, check if we can. 212 213 SFXFMODDevice* fmodDevice = SFXFMODDevice::instance(); 214 if( needToGenerateEventScriptFile && !fmodDevice ) 215 { 216 // If we have neither FMOD nor the event scripts (even if outdated), 217 // there's nothing we can do. 218 219 if( !eventScriptFileExists && !eventScriptFileDSOExists ) 220 { 221 Con::errorf( "SFXFMODProject::_load() - event script for '%s' does not exist and device is not FMOD; load this project under FMOD first", 222 mFileName.c_str() ); 223 return false; 224 } 225 226 // Use the oudated versions. 227 228 Con::warnf( "SFXMODProject::_load() - event script for '%s' is outdated and device is not FMOD; event data may not match .fev contents", 229 mFileName.c_str() ); 230 needToGenerateEventScriptFile = false; 231 } 232 233 // If we don't need to regenerate, try executing the event script now. 234 235 if( !needToGenerateEventScriptFile ) 236 { 237 if( ( eventScriptFileExists || eventScriptFileDSOExists ) 238 && !Con::evaluatef( "exec( \"%s\" );", eventScriptFileName.getFullPath().c_str() ) ) 239 { 240 Con::errorf( "SFXFMODProject::_load() - failed to execute event script for '%s'%s", 241 mFileName.c_str(), 242 fmodDevice != NULL ? "; trying to regenerate" : "" 243 ); 244 245 if( !fmodDevice ) 246 return false; 247 248 needToGenerateEventScriptFile = true; 249 } 250 else 251 Con::printf( "SFXFMODProject - %s: Loaded event script", getName() ); 252 } 253 254 // If we need to generate the event script file, 255 // load the FMOD project now and then emit the file. 256 257 if( needToGenerateEventScriptFile ) 258 { 259 // Try to load the project. 260 261 acquire(); 262 263 if( !mHandle ) 264 return false; 265 266 // Get the project info. 267 268 FMOD_EVENT_PROJECTINFO info; 269 270 int numEvents; 271 int numGroups; 272 273 SFXFMODDevice::smFunc->FMOD_EventProject_GetInfo( mHandle, &info ); 274 SFXFMODDevice::smFunc->FMOD_EventProject_GetNumEvents( mHandle, &numEvents ); 275 SFXFMODDevice::smFunc->FMOD_EventProject_GetNumGroups( mHandle, &numGroups ); 276 277 Con::printf( "SFXFMODProject - %s: Loading '%s' from '%s' (index: %i, events: %i, groups: %i)", 278 getName(), info.name, mFileName.c_str(), info.index, numEvents, numGroups ); 279 280 // Load the root groups. 281 282 for( U32 i = 0; i < numGroups; ++ i ) 283 { 284 FMOD_EVENTGROUP* group; 285 if( SFXFMODDevice::smFunc->FMOD_EventProject_GetGroupByIndex( mHandle, i, true, &group ) == FMOD_OK ) 286 { 287 SFXFMODEventGroup* object = new SFXFMODEventGroup( this, group ); 288 289 object->mSibling = mRootGroups; 290 mRootGroups = object; 291 292 String qualifiedName = FMODEventPathToTorqueName( object->getQualifiedName() ); 293 294 if( !isClientOnly() ) 295 object->assignId(); 296 297 object->registerObject( String::ToString( "%s_%s", getName(), qualifiedName.c_str() ) ); 298 if( isClientOnly() ) 299 Sim::getRootGroup()->addObject( object ); 300 301 object->_load(); 302 } 303 } 304 305 // Create the event script file. 306 307 FileStream stream; 308 if( !stream.open( eventScriptFileName.getFullPath(), Torque::FS::File::Write ) ) 309 { 310 Con::errorf( "SFXFMODProject::_load - could not create event script file for '%s'", mFileName.c_str() ); 311 return true; // Don't treat as failure. 312 } 313 314 // Write a header. 315 316 stream.writeText( String::ToString( "// This file has been auto-generated from '%s'\n", mFileName.c_str() ) ); 317 stream.writeText( "// Do not edit this file manually and do not move it away from the Designer file.\n\n" ); 318 319 // Write the group objects. 320 321 for( U32 i = 0; i < mGroups.size(); ++ i ) 322 { 323 mGroups[ i ]->write( stream, 0 ); 324 stream.writeText( "\n" ); 325 } 326 327 // Write the event objects along with their 328 // SFXDescriptions. 329 330 for( U32 i = 0; i < mEvents.size(); ++ i ) 331 { 332 mEvents[ i ]->getDescription()->write( stream, 0 ); 333 mEvents[ i ]->write( stream, 0 ); 334 stream.writeText( "\n" ); 335 } 336 337 Con::printf( "SFXFMODProject - %s: Generated event script '%s'", getName(), eventScriptFileName.getFullPath().c_str() ); 338 } 339 340 return true; 341} 342 343//----------------------------------------------------------------------------- 344 345void SFXFMODProject::acquire( bool recursive ) 346{ 347 // Load the project file. 348 349 if( !mHandle ) 350 { 351 FMOD_RESULT result = SFXFMODDevice::smFunc->FMOD_EventSystem_Load( 352 SFXFMODDevice::smEventSystem, 353 mFileName.c_str(), 354 ( FMOD_EVENT_LOADINFO* ) 0, 355 &mHandle 356 ); 357 358 if( result != FMOD_OK ) 359 { 360 Con::errorf( "SFXFMODProject::acquire - could not load '%s' (%s)", 361 mFileName.c_str(), FMODResultToString( result ).c_str() ); 362 mHandle = NULL; 363 return; 364 } 365 366 Con::printf( "SFXFMODProject - %s: Opened project '%s'", getName(), mFileName.c_str() ); 367 368 // Set the media path. 369 370 String mediaPath; 371 if( !mMediaPath.isEmpty() ) 372 { 373 mediaPath = mMediaPath; 374 if( mediaPath[ mediaPath.length() - 1 ] != '/' ) 375 mediaPath += '/'; 376 } 377 else 378 { 379 // Set to project directory. 380 381 Torque::Path path = mFileName; 382 if( path.getRoot().isEmpty() ) 383 path.setRoot( "game" ); 384 path.setFileName( "" ); 385 path.setExtension( "" ); 386 387 mediaPath = path.getFullPath() + '/'; 388 } 389 390 SFXFMODDevice::smFunc->FMOD_EventSystem_SetMediaPath( 391 SFXFMODDevice::smEventSystem, 392 mediaPath.c_str() 393 ); 394 } 395 396 // Acquire the root groups. 397 398 if( recursive ) 399 for( SFXFMODEventGroup* group = mRootGroups; group != NULL; group = group->mSibling ) 400 group->acquire( true ); 401 402 SFXFMODDevice::instance()->updateMemUsageStats(); 403} 404 405//----------------------------------------------------------------------------- 406 407void SFXFMODProject::release() 408{ 409 if( !mHandle ) 410 return; 411 412 Con::printf( "SFXFMODProject - %s: Closing project '%s'", 413 getName(), mFileName.c_str() ); 414 415 // Clear media path. 416 417 SFXFMODDevice::smFunc->FMOD_EventSystem_SetMediaPath( 418 SFXFMODDevice::smEventSystem, "" ); 419 420 // Release the root groups. 421 422 for( SFXFMODEventGroup* group = mRootGroups; group != NULL; group = group->mSibling ) 423 group->release(); 424 425 // Release the project. 426 427 SFXFMODDevice::smFunc->FMOD_EventProject_Release( mHandle ); 428 mHandle = NULL; 429 430 SFXFMODDevice::instance()->updateMemUsageStats(); 431} 432 433//----------------------------------------------------------------------------- 434 435void SFXFMODProject::_addEvent( SFXFMODEvent* event ) 436{ 437 mEvents.push_back( event ); 438} 439 440//----------------------------------------------------------------------------- 441 442void SFXFMODProject::_addGroup( SFXFMODEventGroup* group ) 443{ 444 mGroups.push_back( group ); 445} 446 447//----------------------------------------------------------------------------- 448 449void SFXFMODProject::_removeEvent( SFXFMODEvent* event ) 450{ 451 for( U32 i = 0; i < mEvents.size(); ++ i ) 452 if( mEvents[ i ] == event ) 453 { 454 mEvents.erase( i ); 455 break; 456 } 457} 458 459//----------------------------------------------------------------------------- 460 461void SFXFMODProject::_removeGroup( SFXFMODEventGroup* group ) 462{ 463 // Remove from group array. 464 465 for( U32 i = 0; i < mGroups.size(); ++ i ) 466 if( mGroups[ i ] == group ) 467 { 468 mGroups.erase( i ); 469 break;; 470 } 471 472 // Unlink if it's a root group. 473 474 if( !group->mParent ) 475 { 476 if( group == mRootGroups ) 477 { 478 mRootGroups = group->mSibling; 479 group->mSibling = NULL; 480 } 481 else 482 { 483 SFXFMODEventGroup* p = mRootGroups; 484 while( p && p->mSibling != group ) 485 p = p->mSibling; 486 487 if( p ) 488 { 489 p->mSibling = group->mSibling; 490 group->mSibling = NULL; 491 } 492 } 493 } 494} 495