mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
351 lines
12 KiB
C++
351 lines
12 KiB
C++
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Copyright (c) 2012 GarageGames, LLC
|
||
|
|
//
|
||
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
|
// of this software and associated documentation files (the "Software"), to
|
||
|
|
// deal in the Software without restriction, including without limitation the
|
||
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||
|
|
// furnished to do so, subject to the following conditions:
|
||
|
|
//
|
||
|
|
// The above copyright notice and this permission notice shall be included in
|
||
|
|
// all copies or substantial portions of the Software.
|
||
|
|
//
|
||
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||
|
|
// IN THE SOFTWARE.
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
#include "sfx/sfxParameter.h"
|
||
|
|
#include "console/consoleTypes.h"
|
||
|
|
#include "console/engineAPI.h"
|
||
|
|
#include "console/simSet.h"
|
||
|
|
#include "math/mMathFn.h"
|
||
|
|
#include "math/mathTypes.h"
|
||
|
|
#include "math/mathIO.h"
|
||
|
|
#include "core/stream/bitStream.h"
|
||
|
|
#include "platform/typetraits.h"
|
||
|
|
|
||
|
|
|
||
|
|
IMPLEMENT_CONOBJECT( SFXParameter );
|
||
|
|
|
||
|
|
ConsoleDocClass( SFXParameter,
|
||
|
|
"@brief A sound channel value that can be bound to multiple sound sources.\n\n"
|
||
|
|
|
||
|
|
"Parameters are special objects that isolate a specific property that sound sources can have and allows to bind "
|
||
|
|
"this isolated instance to multiple sound sources such that when the value of the parameter changes, all sources "
|
||
|
|
"bound to the parameter will have their respective property changed.\n\n"
|
||
|
|
|
||
|
|
"Parameters are identified and referenced by their #internalName. This means that the SFXDescription::parameters and "
|
||
|
|
"SFXTrack::parameters fields should contain the #internalNames of the SFXParameter objects which should be attached to "
|
||
|
|
"the SFXSources when they are created. No two SFXParameters should have the same #internalName.\n\n"
|
||
|
|
|
||
|
|
"All SFXParameter instances are automatically made children of the SFXParameterGroup.\n\n"
|
||
|
|
|
||
|
|
"@note To simply control the volume and/or pitch levels of a group of sounds, it is easier and more efficient to use "
|
||
|
|
"a sound source group rather than SFXParameters (see @ref SFXSource_hierarchies). Simply create a SFXSource object representing the group, assign "
|
||
|
|
"SFXDescription::sourceGroup of the sounds appropriately, and then set the volume and/or pitch level of the group to "
|
||
|
|
"modulate the respective properties of all children.\n\n"
|
||
|
|
|
||
|
|
"@section SFXParameter_updates Parameter Updates\n"
|
||
|
|
|
||
|
|
"Parameters are periodically allowed to update their own values. This makes it possible to attach custom logic to a parameter "
|
||
|
|
"and have individual parameters synchronize their values autonomously. Use the onUpdate() callback to attach "
|
||
|
|
"script code to a parameter update.\n\n"
|
||
|
|
|
||
|
|
"@tsexample\n"
|
||
|
|
"new SFXParameter( EngineRPMLevel )\n"
|
||
|
|
"{\n"
|
||
|
|
" // Set the name by which this parameter is identified.\n"
|
||
|
|
" internalName = \"EngineRPMLevel\";\n"
|
||
|
|
"\n"
|
||
|
|
" // Let this parameter control the pitch of attached sources to simulate engine RPM ramping up and down.\n"
|
||
|
|
" channel = \"Pitch\";\n"
|
||
|
|
"\n"
|
||
|
|
" // Start out with unmodified pitch.\n"
|
||
|
|
" defaultValue = 1;\n"
|
||
|
|
"\n"
|
||
|
|
" // Add a texture description of what this parameter does.\n"
|
||
|
|
" description = \"Engine RPM Level\";\n"
|
||
|
|
"};\n"
|
||
|
|
"\n"
|
||
|
|
"// Create a description that automatically attaches the engine RPM parameter.\n"
|
||
|
|
"singleton SFXDescription( EngineRPMSound : AudioLoop2D )\n"
|
||
|
|
"{\n"
|
||
|
|
" parameters[ 0 ] = \"EngineRPMLevel\";\n"
|
||
|
|
"};\n"
|
||
|
|
"\n"
|
||
|
|
"// Create sound sources for the engine.\n"
|
||
|
|
"sfxCreateSource( EngineRPMSound, \"art/sound/engine/enginePrimary\" );\n"
|
||
|
|
"sfxCreateSource( EngineRPMSound, \"art/sound/engine/engineSecondary\" );\n"
|
||
|
|
"\n"
|
||
|
|
"// Setting the parameter value will now affect the pitch level of both sound sources.\n"
|
||
|
|
"EngineRPMLevel.value = 0.5;\n"
|
||
|
|
"EngineRPMLevel.value = 1.5;\n"
|
||
|
|
"@endtsexample\n\n"
|
||
|
|
|
||
|
|
"@ref SFX_interactive\n\n"
|
||
|
|
"@ingroup SFX"
|
||
|
|
);
|
||
|
|
|
||
|
|
|
||
|
|
IMPLEMENT_CALLBACK( SFXParameter, onUpdate, void, (), (),
|
||
|
|
"Called when the sound system triggers an update on the parameter.\n"
|
||
|
|
"This occurs periodically during system operation." );
|
||
|
|
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
SFXParameter::SFXParameter()
|
||
|
|
: mValue( 1.f ),
|
||
|
|
mRange( 0.f, 1.f ),
|
||
|
|
mChannel( SFXChannelVolume ),
|
||
|
|
mDefaultValue( 1.f )
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
SFXParameter::~SFXParameter()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void SFXParameter::initPersistFields()
|
||
|
|
{
|
||
|
|
addGroup( "Sound" );
|
||
|
|
|
||
|
|
addProtectedField( "value", TypeF32, Offset( mValue, SFXParameter ),
|
||
|
|
&SFXParameter::_setValue, &defaultProtectedGetFn,
|
||
|
|
"Current value of the audio parameter.\n"
|
||
|
|
"All attached sources are notified when this value changes." );
|
||
|
|
addProtectedField( "range", TypePoint2F, Offset( mRange, SFXParameter ),
|
||
|
|
&SFXParameter::_setRange, &defaultProtectedGetFn,
|
||
|
|
"Permitted range for #value.\n"
|
||
|
|
"Minimum and maximum allowed value for the parameter. Both inclusive.\n\n"
|
||
|
|
"For all but the User0-3 channels, this property is automatically set up by SFXParameter." );
|
||
|
|
addProtectedField( "channel", TYPEID< SFXChannel >(), Offset( mChannel, SFXParameter ),
|
||
|
|
&SFXParameter::_setChannel, &defaultProtectedGetFn,
|
||
|
|
"Channel that the parameter controls.\n"
|
||
|
|
"This controls which property of the sources it is attached to the parameter controls." );
|
||
|
|
addProtectedField( "defaultValue", TypeF32, Offset( mDefaultValue, SFXParameter ),
|
||
|
|
&SFXParameter::_setDefaultValue, &defaultProtectedGetFn,
|
||
|
|
"Value to which the parameter is initially set.\n"
|
||
|
|
"When the parameter is first added to the system, #value will be set to #defaultValue." );
|
||
|
|
addField( "description", TypeRealString,Offset( mDescription, SFXParameter ),
|
||
|
|
"Textual description of the parameter.\n"
|
||
|
|
"Primarily for use in the Audio Parameters dialog of the editor to allow for easier identification "
|
||
|
|
"of parameters." );
|
||
|
|
|
||
|
|
endGroup( "Sound" );
|
||
|
|
|
||
|
|
Parent::initPersistFields();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
bool SFXParameter::_setValue( void *object, const char *index, const char *data )
|
||
|
|
{
|
||
|
|
reinterpret_cast< SFXParameter* >( object )->setValue( dAtof( data ) );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
bool SFXParameter::_setRange( void *object, const char *index, const char *data )
|
||
|
|
{
|
||
|
|
Point2F range = EngineUnmarshallData< Point2F >()( data );
|
||
|
|
reinterpret_cast< SFXParameter* >( object )->setRange( range );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
bool SFXParameter::_setChannel( void *object, const char *index, const char *data )
|
||
|
|
{
|
||
|
|
SFXChannel channel = EngineUnmarshallData< SFXChannel >()( data );
|
||
|
|
reinterpret_cast< SFXParameter* >( object )->setChannel( channel );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
bool SFXParameter::_setDefaultValue( void *object, const char *index, const char *data )
|
||
|
|
{
|
||
|
|
reinterpret_cast< SFXParameter* >( object )->setDefaultValue( dAtof( data ) );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
bool SFXParameter::onAdd()
|
||
|
|
{
|
||
|
|
if( !Parent::onAdd() )
|
||
|
|
return false;
|
||
|
|
|
||
|
|
mValue = mDefaultValue;
|
||
|
|
|
||
|
|
// Make sure the parameter has a name.
|
||
|
|
|
||
|
|
if( !getInternalName() || !getInternalName()[ 0 ] )
|
||
|
|
{
|
||
|
|
Con::errorf( "SFXParameter::onAdd - %i (%s): parameter object does not have a name", getId(), getName() );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Make sure the parameter has a unique name.
|
||
|
|
|
||
|
|
if( find( getInternalName() ) )
|
||
|
|
{
|
||
|
|
Con::errorf( "SFXParameter::onAdd - %i (%s): a parameter called '%s' already exists", getId(), getName(), getInternalName() );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add us to the SFXParameter group.
|
||
|
|
|
||
|
|
Sim::getSFXParameterGroup()->addObject( this );
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void SFXParameter::onRemove()
|
||
|
|
{
|
||
|
|
mEventSignal.trigger( this, SFXParameterEvent_Deleted );
|
||
|
|
Parent::onRemove();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void SFXParameter::update()
|
||
|
|
{
|
||
|
|
onUpdate_callback();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void SFXParameter::reset()
|
||
|
|
{
|
||
|
|
setValue( mDefaultValue );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void SFXParameter::setValue( F32 value )
|
||
|
|
{
|
||
|
|
if( value == mValue )
|
||
|
|
return;
|
||
|
|
|
||
|
|
mValue = mClampF( value, mRange.x, mRange.y );
|
||
|
|
mEventSignal.trigger( this, SFXParameterEvent_ValueChanged );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void SFXParameter::setDefaultValue( F32 value )
|
||
|
|
{
|
||
|
|
mDefaultValue = mClampF( value, mRange.x, mRange.y );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void SFXParameter::setRange( const Point2F& range )
|
||
|
|
{
|
||
|
|
if( range == mRange )
|
||
|
|
return;
|
||
|
|
|
||
|
|
mRange = range;
|
||
|
|
|
||
|
|
F32 value = mClampF( mValue, mRange.x, mRange.y );
|
||
|
|
if( value != mValue )
|
||
|
|
setValue( value );
|
||
|
|
|
||
|
|
mDefaultValue = mClampF( mDefaultValue, mRange.x, mRange.y );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
void SFXParameter::setChannel( SFXChannel channel )
|
||
|
|
{
|
||
|
|
if( mChannel == channel )
|
||
|
|
return;
|
||
|
|
|
||
|
|
mChannel = channel;
|
||
|
|
|
||
|
|
F32 value = mValue;
|
||
|
|
switch( channel )
|
||
|
|
{
|
||
|
|
case SFXChannelVolume:
|
||
|
|
case SFXChannelConeOutsideVolume:
|
||
|
|
setRange( 0.f, 1.0f );
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SFXChannelConeInsideAngle:
|
||
|
|
case SFXChannelConeOutsideAngle:
|
||
|
|
setRange( 0.f, 360.f );
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SFXChannelPitch:
|
||
|
|
case SFXChannelMinDistance:
|
||
|
|
case SFXChannelMaxDistance:
|
||
|
|
case SFXChannelCursor:
|
||
|
|
setRange( 0.f, TypeTraits< F32 >::MAX );
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SFXChannelStatus:
|
||
|
|
setRange( F32( SFXStatusPlaying ), F32( SFXStatusStopped ) );
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
setRange( TypeTraits< F32 >::MIN, TypeTraits< F32 >::MAX );
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
// If the range setting did not result in the value already
|
||
|
|
// being changed, fire a value-change signal now so that sources
|
||
|
|
// can catch on to the new semantics. Unfortunately, we can't
|
||
|
|
// do something about the old semantic's value having been
|
||
|
|
// changed by us.
|
||
|
|
|
||
|
|
if( mValue == value )
|
||
|
|
mEventSignal.trigger( this, SFXParameterEvent_ValueChanged );
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
SFXParameter* SFXParameter::find( StringTableEntry name )
|
||
|
|
{
|
||
|
|
return dynamic_cast< SFXParameter* >(
|
||
|
|
Sim::getSFXParameterGroup()->findObjectByInternalName( name )
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
//=============================================================================
|
||
|
|
// Console Methods.
|
||
|
|
//=============================================================================
|
||
|
|
// MARK: ---- Console Methods ----
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
DefineEngineMethod( SFXParameter, getParameterName, String, (),,
|
||
|
|
"Get the name of the parameter.\n"
|
||
|
|
"@return The paramete name." )
|
||
|
|
{
|
||
|
|
return object->getInternalName();
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
DefineEngineMethod( SFXParameter, reset, void, (),,
|
||
|
|
"Reset the parameter's value to its default.\n"
|
||
|
|
"@see SFXParameter::defaultValue\n" )
|
||
|
|
{
|
||
|
|
object->reset();
|
||
|
|
}
|