Torque3D Documentation / _generateds / sfxFMODProject.cpp

sfxFMODProject.cpp

Engine/source/sfx/fmod/sfxFMODProject.cpp

More...

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