mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-14 16:14:38 +00:00
Merge branch 'Preview4_0' of https://github.com/TorqueGameEngines/Torque3D into UpdatedProjectImporter
This commit is contained in:
commit
1952820ef2
14 changed files with 657 additions and 312 deletions
|
|
@ -218,6 +218,9 @@ bool SoundAsset::loadSound()
|
||||||
{
|
{
|
||||||
Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile);
|
Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile);
|
||||||
mLoadedState = BadFileReference;
|
mLoadedState = BadFileReference;
|
||||||
|
mSFXProfile.setDescription(NULL);
|
||||||
|
mSFXProfile.setSoundFileName(StringTable->insert(StringTable->EmptyString()));
|
||||||
|
mSFXProfile.setPreload(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -257,7 +260,7 @@ StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
|
||||||
if (fileName == StringTable->EmptyString())
|
if (fileName == StringTable->EmptyString())
|
||||||
return StringTable->EmptyString();
|
return StringTable->EmptyString();
|
||||||
|
|
||||||
StringTableEntry materialAssetId = "";
|
StringTableEntry soundAssetId = StringTable->EmptyString();
|
||||||
|
|
||||||
AssetQuery query;
|
AssetQuery query;
|
||||||
U32 foundCount = AssetDatabase.findAssetType(&query, "SoundAsset");
|
U32 foundCount = AssetDatabase.findAssetType(&query, "SoundAsset");
|
||||||
|
|
@ -268,7 +271,7 @@ StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
|
||||||
SoundAsset* soundAsset = AssetDatabase.acquireAsset<SoundAsset>(query.mAssetList[i]);
|
SoundAsset* soundAsset = AssetDatabase.acquireAsset<SoundAsset>(query.mAssetList[i]);
|
||||||
if (soundAsset && soundAsset->getSoundPath() == fileName)
|
if (soundAsset && soundAsset->getSoundPath() == fileName)
|
||||||
{
|
{
|
||||||
materialAssetId = soundAsset->getAssetId();
|
soundAssetId = soundAsset->getAssetId();
|
||||||
AssetDatabase.releaseAsset(query.mAssetList[i]);
|
AssetDatabase.releaseAsset(query.mAssetList[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -276,7 +279,7 @@ StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return materialAssetId;
|
return soundAssetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 SoundAsset::getAssetById(StringTableEntry assetId, AssetPtr<SoundAsset>* soundAsset)
|
U32 SoundAsset::getAssetById(StringTableEntry assetId, AssetPtr<SoundAsset>* soundAsset)
|
||||||
|
|
@ -330,8 +333,8 @@ DefineEngineMethod(SoundAsset, getSoundPath, const char*, (), , "")
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineEngineMethod(SoundAsset, playSound, S32, (Point3F position), (Point3F::Zero),
|
DefineEngineMethod(SoundAsset, playSound, S32, (Point3F position), (Point3F::Zero),
|
||||||
"Gets the number of materials for this shape asset.\n"
|
"Plays the sound for this asset.\n"
|
||||||
"@return Material count.\n")
|
"@return (sound plays).\n")
|
||||||
{
|
{
|
||||||
if (object->getSfxProfile())
|
if (object->getSfxProfile())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -859,9 +859,6 @@ bool ExplosionData::preload(bool server, String &errorStr)
|
||||||
if (Parent::preload(server, errorStr) == false)
|
if (Parent::preload(server, errorStr) == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!server && !getSoundProfile())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if( !server )
|
if( !server )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -870,12 +867,18 @@ bool ExplosionData::preload(bool server, String &errorStr)
|
||||||
_setSound(getSound());
|
_setSound(getSound());
|
||||||
|
|
||||||
if (!getSoundProfile())
|
if (!getSoundProfile())
|
||||||
|
{
|
||||||
Con::errorf(ConsoleLogEntry::General, "SplashData::preload: Cant get an sfxProfile for splash.");
|
Con::errorf(ConsoleLogEntry::General, "SplashData::preload: Cant get an sfxProfile for splash.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!particleEmitter && particleEmitterId != 0)
|
if (!particleEmitter && particleEmitterId != 0)
|
||||||
if (Sim::findObject(particleEmitterId, particleEmitter) == false)
|
if (Sim::findObject(particleEmitterId, particleEmitter) == false)
|
||||||
|
{
|
||||||
Con::errorf(ConsoleLogEntry::General, "Error, unable to load particle emitter for explosion datablock");
|
Con::errorf(ConsoleLogEntry::General, "Error, unable to load particle emitter for explosion datablock");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExplosionShapeAsset.notNull()) {
|
if (mExplosionShapeAsset.notNull()) {
|
||||||
|
|
|
||||||
|
|
@ -1562,19 +1562,32 @@ void GameConnection::packetDropped(PacketNotify *note)
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
void GameConnection::play2D(SFXProfile* profile)
|
void GameConnection::play2D(StringTableEntry assetId)
|
||||||
{
|
{
|
||||||
postNetEvent(new Sim2DAudioEvent(profile));
|
if (AssetDatabase.isDeclaredAsset(assetId))
|
||||||
|
{
|
||||||
|
|
||||||
|
AssetPtr<SoundAsset> tempSoundAsset;
|
||||||
|
tempSoundAsset = assetId;
|
||||||
|
|
||||||
|
postNetEvent(new SimSoundAssetEvent(tempSoundAsset));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameConnection::play3D(SFXProfile* profile, const MatrixF *transform)
|
void GameConnection::play3D(StringTableEntry assetId, const MatrixF *transform)
|
||||||
{
|
{
|
||||||
if ( !transform )
|
if ( !transform )
|
||||||
play2D(profile);
|
play2D(assetId);
|
||||||
|
|
||||||
else if ( !mControlObject )
|
if (AssetDatabase.isDeclaredAsset(assetId))
|
||||||
postNetEvent(new Sim3DAudioEvent(profile,transform));
|
{
|
||||||
|
|
||||||
|
AssetPtr<SoundAsset> tempSoundAsset;
|
||||||
|
tempSoundAsset = assetId;
|
||||||
|
|
||||||
|
if (!mControlObject)
|
||||||
|
postNetEvent(new SimSoundAssetEvent(tempSoundAsset, transform));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Maybe improve this to account for the duration
|
// TODO: Maybe improve this to account for the duration
|
||||||
|
|
@ -1583,12 +1596,16 @@ void GameConnection::play3D(SFXProfile* profile, const MatrixF *transform)
|
||||||
|
|
||||||
// Only post the event if it's within audible range
|
// Only post the event if it's within audible range
|
||||||
// of the control object.
|
// of the control object.
|
||||||
|
tempSoundAsset->getSfxDescription();
|
||||||
Point3F ear, pos;
|
Point3F ear, pos;
|
||||||
transform->getColumn(3, &pos);
|
transform->getColumn(3, &pos);
|
||||||
mControlObject->getTransform().getColumn(3, &ear);
|
mControlObject->getTransform().getColumn(3, &ear);
|
||||||
if ((ear - pos).len() < profile->getDescription()->mMaxDistance)
|
if ((ear - pos).len() < tempSoundAsset->getSfxDescription()->mMaxDistance)
|
||||||
postNetEvent(new Sim3DAudioEvent(profile,transform));
|
postNetEvent(new SimSoundAssetEvent(tempSoundAsset, transform));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameConnection::doneScopingScene()
|
void GameConnection::doneScopingScene()
|
||||||
|
|
@ -2010,49 +2027,49 @@ DefineEngineMethod( GameConnection, isControlObjectRotDampedCamera, bool, (),,
|
||||||
return object->isControlObjectRotDampedCamera();
|
return object->isControlObjectRotDampedCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineEngineMethod( GameConnection, play2D, bool, (SFXProfile* profile),,
|
DefineEngineMethod( GameConnection, play2D, bool, (StringTableEntry assetId),,
|
||||||
"@brief Used on the server to play a 2D sound that is not attached to any object.\n\n"
|
"@brief Used on the server to play a 2D sound that is not attached to any object.\n\n"
|
||||||
|
|
||||||
"@param profile The SFXProfile that defines the sound to play.\n\n"
|
"@param assetID The SoundAsset ID that defines the sound to play.\n"
|
||||||
|
|
||||||
"@tsexample\n"
|
"@tsexample\n"
|
||||||
"function ServerPlay2D(%profile)\n"
|
"function ServerPlay2D(%assetId)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" // Play the given sound profile on every client.\n"
|
" // Play the given sound asset on every client.\n"
|
||||||
" // The sounds will be transmitted as an event, not attached to any object.\n"
|
" // The sounds will be transmitted as an event, not attached to any object.\n"
|
||||||
" for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
|
" for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
|
||||||
" ClientGroup.getObject(%idx).play2D(%profile);\n"
|
" ClientGroup.getObject(%idx).play2D(%assetId);\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"@endtsexample\n\n")
|
"@endtsexample\n\n")
|
||||||
{
|
{
|
||||||
if(!profile)
|
if(assetId == StringTable->EmptyString())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
object->play2D(profile);
|
object->play2D(assetId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineEngineMethod( GameConnection, play3D, bool, (SFXProfile* profile, TransformF location),,
|
DefineEngineMethod( GameConnection, play3D, bool, (StringTableEntry assetId, TransformF location),,
|
||||||
"@brief Used on the server to play a 3D sound that is not attached to any object.\n\n"
|
"@brief Used on the server to play a 3D sound that is not attached to any object.\n\n"
|
||||||
|
|
||||||
"@param profile The SFXProfile that defines the sound to play.\n"
|
"@param assetID The SoundAsset ID that defines the sound to play.\n"
|
||||||
"@param location The position and orientation of the 3D sound given in the form of \"x y z ax ay az aa\".\n\n"
|
"@param location The position and orientation of the 3D sound given in the form of \"x y z ax ay az aa\".\n\n"
|
||||||
|
|
||||||
"@tsexample\n"
|
"@tsexample\n"
|
||||||
"function ServerPlay3D(%profile,%transform)\n"
|
"function ServerPlay3D(%assetId,%transform)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" // Play the given sound profile at the given position on every client\n"
|
" // Play the given sound asset at the given position on every client\n"
|
||||||
" // The sound will be transmitted as an event, not attached to any object.\n"
|
" // The sound will be transmitted as an event, not attached to any object.\n"
|
||||||
" for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
|
" for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
|
||||||
" ClientGroup.getObject(%idx).play3D(%profile,%transform);\n"
|
" ClientGroup.getObject(%idx).play3D(%assetID,%transform);\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"@endtsexample\n\n")
|
"@endtsexample\n\n")
|
||||||
{
|
{
|
||||||
if(!profile)
|
if(assetId == StringTable->EmptyString())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MatrixF mat = location.getMatrix();
|
MatrixF mat = location.getMatrix();
|
||||||
object->play3D(profile,&mat);
|
object->play3D(assetId,&mat);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -352,8 +352,8 @@ public:
|
||||||
/// @name Sound
|
/// @name Sound
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
void play2D(SFXProfile *profile);
|
void play2D(StringTableEntry assetId);
|
||||||
void play3D(SFXProfile *profile, const MatrixF *transform);
|
void play3D(StringTableEntry assetId, const MatrixF *transform);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @name Misc.
|
/// @name Misc.
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
IMPLEMENT_CO_CLIENTEVENT_V1(SimDataBlockEvent);
|
IMPLEMENT_CO_CLIENTEVENT_V1(SimDataBlockEvent);
|
||||||
|
IMPLEMENT_CO_CLIENTEVENT_V1(SimSoundAssetEvent);
|
||||||
IMPLEMENT_CO_CLIENTEVENT_V1(Sim2DAudioEvent);
|
IMPLEMENT_CO_CLIENTEVENT_V1(Sim2DAudioEvent);
|
||||||
IMPLEMENT_CO_CLIENTEVENT_V1(Sim3DAudioEvent);
|
IMPLEMENT_CO_CLIENTEVENT_V1(Sim3DAudioEvent);
|
||||||
IMPLEMENT_CO_CLIENTEVENT_V1(SetMissionCRCEvent);
|
IMPLEMENT_CO_CLIENTEVENT_V1(SetMissionCRCEvent);
|
||||||
|
|
@ -293,6 +294,104 @@ void SimDataBlockEvent::process(NetConnection *cptr)
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static F32 SoundPosAccuracy = 0.5;
|
||||||
|
static S32 SoundRotBits = 8;
|
||||||
|
|
||||||
|
SimSoundAssetEvent::SimSoundAssetEvent(AssetPtr<SoundAsset> asset, const MatrixF* mat)
|
||||||
|
{
|
||||||
|
// cant get here unless the asset is declared.
|
||||||
|
mAsset = asset;
|
||||||
|
|
||||||
|
if (mat)
|
||||||
|
mTransform = *mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimSoundAssetEvent::pack(NetConnection* con, BitStream* stream)
|
||||||
|
{
|
||||||
|
NetStringHandle assetIdStr = mAsset->getAssetId();
|
||||||
|
con->packNetStringHandleU(stream, assetIdStr);
|
||||||
|
|
||||||
|
// only stream if this is a 3d sound asset.
|
||||||
|
if (mAsset->is3D())
|
||||||
|
{
|
||||||
|
SFXDescription* ad = mAsset->getSfxDescription();
|
||||||
|
if (stream->writeFlag(ad->mConeInsideAngle || ad->mConeOutsideAngle))
|
||||||
|
{
|
||||||
|
QuatF q(mTransform);
|
||||||
|
q.normalize();
|
||||||
|
|
||||||
|
// LH - we can get a valid quat that's very slightly over 1 in and so
|
||||||
|
// this fails (barely) check against zero. So use some error-
|
||||||
|
AssertFatal((1.0 - ((q.x * q.x) + (q.y * q.y) + (q.z * q.z))) >= (0.0 - 0.001),
|
||||||
|
"QuatF::normalize() is broken in Sim3DAudioEvent");
|
||||||
|
|
||||||
|
stream->writeSignedFloat(q.x, SoundRotBits);
|
||||||
|
stream->writeSignedFloat(q.y, SoundRotBits);
|
||||||
|
stream->writeSignedFloat(q.z, SoundRotBits);
|
||||||
|
stream->writeFlag(q.w < 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3F pos;
|
||||||
|
mTransform.getColumn(3, &pos);
|
||||||
|
stream->writeCompressedPoint(pos, SoundPosAccuracy);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimSoundAssetEvent::write(NetConnection* con, BitStream* stream)
|
||||||
|
{
|
||||||
|
// Just do the normal pack...
|
||||||
|
pack(con, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimSoundAssetEvent::unpack(NetConnection* con, BitStream* stream)
|
||||||
|
{
|
||||||
|
|
||||||
|
StringTableEntry temp = StringTable->insert(con->unpackNetStringHandleU(stream).getString());
|
||||||
|
if (AssetDatabase.isDeclaredAsset(temp))
|
||||||
|
{
|
||||||
|
AssetPtr<SoundAsset> tempSoundAsset;
|
||||||
|
tempSoundAsset = temp;
|
||||||
|
|
||||||
|
mAsset = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAsset->is3D())
|
||||||
|
{
|
||||||
|
if (stream->readFlag()) {
|
||||||
|
QuatF q;
|
||||||
|
q.x = stream->readSignedFloat(SoundRotBits);
|
||||||
|
q.y = stream->readSignedFloat(SoundRotBits);
|
||||||
|
q.z = stream->readSignedFloat(SoundRotBits);
|
||||||
|
F32 value = ((q.x * q.x) + (q.y * q.y) + (q.z * q.z));
|
||||||
|
// #ifdef __linux
|
||||||
|
// Hmm, this should never happen, but it does...
|
||||||
|
if (value > 1.f)
|
||||||
|
value = 1.f;
|
||||||
|
// #endif
|
||||||
|
q.w = mSqrt(1.f - value);
|
||||||
|
if (stream->readFlag())
|
||||||
|
q.w = -q.w;
|
||||||
|
q.setMatrix(&mTransform);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mTransform.identity();
|
||||||
|
|
||||||
|
Point3F pos;
|
||||||
|
stream->readCompressedPoint(&pos, SoundPosAccuracy);
|
||||||
|
mTransform.setColumn(3, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimSoundAssetEvent::process(NetConnection* con)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (mAsset->is3D())
|
||||||
|
SFX->playOnce(mAsset->getSfxProfile(), &mTransform);
|
||||||
|
else
|
||||||
|
SFX->playOnce(mAsset->getSfxProfile());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Sim2DAudioEvent::Sim2DAudioEvent(SFXProfile *profile)
|
Sim2DAudioEvent::Sim2DAudioEvent(SFXProfile *profile)
|
||||||
{
|
{
|
||||||
|
|
@ -321,11 +420,6 @@ void Sim2DAudioEvent::process(NetConnection *)
|
||||||
SFX->playOnce( mProfile );
|
SFX->playOnce( mProfile );
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static F32 SoundPosAccuracy = 0.5;
|
|
||||||
static S32 SoundRotBits = 8;
|
|
||||||
|
|
||||||
Sim3DAudioEvent::Sim3DAudioEvent(SFXProfile *profile,const MatrixF* mat)
|
Sim3DAudioEvent::Sim3DAudioEvent(SFXProfile *profile,const MatrixF* mat)
|
||||||
{
|
{
|
||||||
mProfile = profile;
|
mProfile = profile;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@
|
||||||
#include "core/stream/bitStream.h"
|
#include "core/stream/bitStream.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "T3D/assets/SoundAsset.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class QuitEvent : public SimEvent
|
class QuitEvent : public SimEvent
|
||||||
{
|
{
|
||||||
|
|
@ -102,6 +105,23 @@ class SimDataBlockEvent : public NetEvent
|
||||||
DECLARE_CATEGORY( "Game Networking" );
|
DECLARE_CATEGORY( "Game Networking" );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SimSoundAssetEvent : public NetEvent
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
AssetPtr<SoundAsset> mAsset;
|
||||||
|
MatrixF mTransform;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef NetEvent Parent;
|
||||||
|
|
||||||
|
SimSoundAssetEvent(AssetPtr<SoundAsset> asset = NULL, const MatrixF* mat = NULL);
|
||||||
|
void pack(NetConnection*, BitStream* bstream);
|
||||||
|
void write(NetConnection*, BitStream* bstream);
|
||||||
|
void unpack(NetConnection*, BitStream* bstream);
|
||||||
|
void process(NetConnection*);
|
||||||
|
DECLARE_CONOBJECT(SimSoundAssetEvent);
|
||||||
|
};
|
||||||
|
|
||||||
class Sim2DAudioEvent: public NetEvent
|
class Sim2DAudioEvent: public NetEvent
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -1009,7 +1009,7 @@ ShapeBase::ShapeBase()
|
||||||
|
|
||||||
for (i = 0; i < MaxSoundThreads; i++) {
|
for (i = 0; i < MaxSoundThreads; i++) {
|
||||||
mSoundThread[i].play = false;
|
mSoundThread[i].play = false;
|
||||||
mSoundThread[i].profile = 0;
|
mSoundThread[i].asset = 0;
|
||||||
mSoundThread[i].sound = 0;
|
mSoundThread[i].sound = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2233,24 +2233,30 @@ void ShapeBase::applyImpulse(const Point3F&,const VectorF&)
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
void ShapeBase::playAudio(U32 slot,SFXTrack* profile)
|
void ShapeBase::playAudio(U32 slot, StringTableEntry assetId)
|
||||||
{
|
{
|
||||||
AssertFatal( slot < MaxSoundThreads, "ShapeBase::playAudio() bad slot index" );
|
AssertFatal( slot < MaxSoundThreads, "ShapeBase::playAudio() bad slot index" );
|
||||||
Sound& st = mSoundThread[slot];
|
if (AssetDatabase.isDeclaredAsset(assetId))
|
||||||
if( profile && ( !st.play || st.profile != profile ) )
|
{
|
||||||
|
AssetPtr<SoundAsset> tempSoundAsset;
|
||||||
|
tempSoundAsset = assetId;
|
||||||
|
|
||||||
|
SoundThread& st = mSoundThread[slot];
|
||||||
|
if (tempSoundAsset && (!st.play || st.asset != tempSoundAsset))
|
||||||
{
|
{
|
||||||
setMaskBits(SoundMaskN << slot);
|
setMaskBits(SoundMaskN << slot);
|
||||||
st.play = true;
|
st.play = true;
|
||||||
st.profile = profile;
|
st.asset = tempSoundAsset;
|
||||||
updateAudioState(st);
|
updateAudioState(st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ShapeBase::stopAudio(U32 slot)
|
void ShapeBase::stopAudio(U32 slot)
|
||||||
{
|
{
|
||||||
AssertFatal( slot < MaxSoundThreads, "ShapeBase::stopAudio() bad slot index" );
|
AssertFatal( slot < MaxSoundThreads, "ShapeBase::stopAudio() bad slot index" );
|
||||||
|
|
||||||
Sound& st = mSoundThread[slot];
|
SoundThread& st = mSoundThread[slot];
|
||||||
if ( st.play )
|
if ( st.play )
|
||||||
{
|
{
|
||||||
st.play = false;
|
st.play = false;
|
||||||
|
|
@ -2263,7 +2269,7 @@ void ShapeBase::updateServerAudio()
|
||||||
{
|
{
|
||||||
// Timeout non-looping sounds
|
// Timeout non-looping sounds
|
||||||
for (S32 i = 0; i < MaxSoundThreads; i++) {
|
for (S32 i = 0; i < MaxSoundThreads; i++) {
|
||||||
Sound& st = mSoundThread[i];
|
SoundThread& st = mSoundThread[i];
|
||||||
if (st.play && st.timeout && st.timeout < Sim::getCurrentTime()) {
|
if (st.play && st.timeout && st.timeout < Sim::getCurrentTime()) {
|
||||||
clearMaskBits(SoundMaskN << i);
|
clearMaskBits(SoundMaskN << i);
|
||||||
st.play = false;
|
st.play = false;
|
||||||
|
|
@ -2271,17 +2277,18 @@ void ShapeBase::updateServerAudio()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBase::updateAudioState(Sound& st)
|
void ShapeBase::updateAudioState(SoundThread& st)
|
||||||
{
|
{
|
||||||
SFX_DELETE( st.sound );
|
SFX_DELETE( st.sound );
|
||||||
|
|
||||||
if ( st.play && st.profile )
|
if ( st.play && st.asset )
|
||||||
{
|
{
|
||||||
if ( isGhost() )
|
if ( isGhost() )
|
||||||
{
|
{
|
||||||
if ( Sim::findObject( SimObjectId((uintptr_t)st.profile), st.profile ) )
|
// if asset is valid, play
|
||||||
|
if (st.asset->isAssetValid() )
|
||||||
{
|
{
|
||||||
st.sound = SFX->createSource( st.profile, &getTransform() );
|
st.sound = SFX->createSource( st.asset->getSfxProfile() , &getTransform() );
|
||||||
if ( st.sound )
|
if ( st.sound )
|
||||||
st.sound->play();
|
st.sound->play();
|
||||||
}
|
}
|
||||||
|
|
@ -2292,12 +2299,17 @@ void ShapeBase::updateAudioState(Sound& st)
|
||||||
{
|
{
|
||||||
// Non-looping sounds timeout on the server
|
// Non-looping sounds timeout on the server
|
||||||
st.timeout = 0;
|
st.timeout = 0;
|
||||||
if ( !st.profile->getDescription()->mIsLooping )
|
if ( !st.asset->getSfxDescription()->mIsLooping )
|
||||||
st.timeout = Sim::getCurrentTime() + sAudioTimeout;
|
st.timeout = Sim::getCurrentTime() + sAudioTimeout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// st.sound was not stopped before. If this causes issues remove.
|
||||||
st.play = false;
|
st.play = false;
|
||||||
|
if (st.sound)
|
||||||
|
st.sound->stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBase::updateAudioPos()
|
void ShapeBase::updateAudioPos()
|
||||||
|
|
@ -3122,11 +3134,13 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||||
|
|
||||||
if (stream->writeFlag(mask & SoundMask)) {
|
if (stream->writeFlag(mask & SoundMask)) {
|
||||||
for (S32 i = 0; i < MaxSoundThreads; i++) {
|
for (S32 i = 0; i < MaxSoundThreads; i++) {
|
||||||
Sound& st = mSoundThread[i];
|
SoundThread& st = mSoundThread[i];
|
||||||
if (stream->writeFlag(mask & (SoundMaskN << i)))
|
if (stream->writeFlag(mask & (SoundMaskN << i)))
|
||||||
if (stream->writeFlag(st.play))
|
if (stream->writeFlag(st.play))
|
||||||
stream->writeRangedU32(st.profile->getId(),DataBlockObjectIdFirst,
|
{
|
||||||
DataBlockObjectIdLast);
|
NetStringHandle assetIdStr = st.asset->getAssetId();
|
||||||
|
con->packNetStringHandleU(stream, assetIdStr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3242,12 +3256,18 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
{
|
{
|
||||||
if ( stream->readFlag() )
|
if ( stream->readFlag() )
|
||||||
{
|
{
|
||||||
Sound& st = mSoundThread[i];
|
SoundThread& st = mSoundThread[i];
|
||||||
st.play = stream->readFlag();
|
st.play = stream->readFlag();
|
||||||
if ( st.play )
|
if ( st.play )
|
||||||
{
|
{
|
||||||
st.profile = (SFXTrack*)(uintptr_t)stream->readRangedU32( DataBlockObjectIdFirst,
|
StringTableEntry temp = StringTable->insert(con->unpackNetStringHandleU(stream).getString());
|
||||||
DataBlockObjectIdLast );
|
if (AssetDatabase.isDeclaredAsset(temp))
|
||||||
|
{
|
||||||
|
AssetPtr<SoundAsset> tempSoundAsset;
|
||||||
|
tempSoundAsset = temp;
|
||||||
|
|
||||||
|
st.asset = temp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isProperlyAdded() )
|
if ( isProperlyAdded() )
|
||||||
|
|
@ -3777,7 +3797,7 @@ DefineEngineMethod( ShapeBase, isHidden, bool, (),,
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
DefineEngineMethod( ShapeBase, playAudio, bool, ( S32 slot, SFXTrack* track ),,
|
DefineEngineMethod( ShapeBase, playAudio, bool, ( S32 slot, StringTableEntry assetId),,
|
||||||
"@brief Attach a sound to this shape and start playing it.\n\n"
|
"@brief Attach a sound to this shape and start playing it.\n\n"
|
||||||
|
|
||||||
"@param slot Audio slot index for the sound (valid range is 0 - 3)\n" // 3 = ShapeBase::MaxSoundThreads-1
|
"@param slot Audio slot index for the sound (valid range is 0 - 3)\n" // 3 = ShapeBase::MaxSoundThreads-1
|
||||||
|
|
@ -3786,8 +3806,8 @@ DefineEngineMethod( ShapeBase, playAudio, bool, ( S32 slot, SFXTrack* track ),,
|
||||||
|
|
||||||
"@see stopAudio()\n")
|
"@see stopAudio()\n")
|
||||||
{
|
{
|
||||||
if (track && slot >= 0 && slot < ShapeBase::MaxSoundThreads) {
|
if (assetId && slot >= 0 && slot < ShapeBase::MaxSoundThreads) {
|
||||||
object->playAudio(slot,track);
|
object->playAudio(slot, assetId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,7 @@ struct ShapeBaseImageData: public GameBaseData {
|
||||||
F32 emitterTime; ///<
|
F32 emitterTime; ///<
|
||||||
S32 emitterNode[MaxShapes]; ///< Node ID on the shape to emit from
|
S32 emitterNode[MaxShapes]; ///< Node ID on the shape to emit from
|
||||||
SoundAsset* sound;
|
SoundAsset* sound;
|
||||||
|
SFXTrack* soundTrack; ///<Holdover for special, non-asset cases like SFXPlaylists
|
||||||
};
|
};
|
||||||
/// @name State Data
|
/// @name State Data
|
||||||
/// Individual state data used to initialize struct array
|
/// Individual state data used to initialize struct array
|
||||||
|
|
@ -744,13 +745,13 @@ protected:
|
||||||
|
|
||||||
/// @name Scripted Sound
|
/// @name Scripted Sound
|
||||||
/// @{
|
/// @{
|
||||||
struct Sound {
|
struct SoundThread {
|
||||||
bool play; ///< Are we playing this sound?
|
bool play; ///< Are we playing this sound?
|
||||||
SimTime timeout; ///< Time until we stop playing this sound.
|
SimTime timeout; ///< Time until we stop playing this sound.
|
||||||
SFXTrack* profile; ///< Profile on server
|
AssetPtr<SoundAsset> asset; ///< Asset on server
|
||||||
SFXSource* sound; ///< Sound on client
|
SFXSource* sound; ///< Sound on client
|
||||||
};
|
};
|
||||||
Sound mSoundThread[MaxSoundThreads];
|
SoundThread mSoundThread[MaxSoundThreads];
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @name Scripted Animation Threads
|
/// @name Scripted Animation Threads
|
||||||
|
|
@ -1114,7 +1115,7 @@ protected:
|
||||||
|
|
||||||
/// Updates the audio state of the supplied sound
|
/// Updates the audio state of the supplied sound
|
||||||
/// @param st Sound
|
/// @param st Sound
|
||||||
void updateAudioState(Sound& st);
|
void updateAudioState(SoundThread& st);
|
||||||
|
|
||||||
/// Recalculates the spacial sound based on the current position of the object
|
/// Recalculates the spacial sound based on the current position of the object
|
||||||
/// emitting the sound.
|
/// emitting the sound.
|
||||||
|
|
@ -1328,9 +1329,7 @@ public:
|
||||||
|
|
||||||
/// Plays an audio sound from a mounted object
|
/// Plays an audio sound from a mounted object
|
||||||
/// @param slot Mount slot ID
|
/// @param slot Mount slot ID
|
||||||
/// @param track Audio track to play
|
void playAudio(U32 slot, StringTableEntry assetId);
|
||||||
void playAudio(U32 slot,SFXTrack* track);
|
|
||||||
void playAudio( U32 slot, SFXProfile* profile ) { playAudio( slot, ( SFXTrack* ) profile ); }
|
|
||||||
|
|
||||||
/// Stops audio from a mounted object
|
/// Stops audio from a mounted object
|
||||||
/// @param slot Mount slot ID
|
/// @param slot Mount slot ID
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ ShapeBaseImageData::StateData::StateData()
|
||||||
spin = IgnoreSpin;
|
spin = IgnoreSpin;
|
||||||
recoil = NoRecoil;
|
recoil = NoRecoil;
|
||||||
sound = NULL;
|
sound = NULL;
|
||||||
|
soundTrack = NULL;
|
||||||
emitter = NULL;
|
emitter = NULL;
|
||||||
shapeSequence = NULL;
|
shapeSequence = NULL;
|
||||||
shapeSequenceScale = true;
|
shapeSequenceScale = true;
|
||||||
|
|
@ -372,6 +373,19 @@ bool ShapeBaseImageData::onAdd()
|
||||||
|
|
||||||
//_setstateSound(getstateSound(i),i);
|
//_setstateSound(getstateSound(i),i);
|
||||||
s.sound = getstateSoundAsset(i);
|
s.sound = getstateSoundAsset(i);
|
||||||
|
if (s.sound == NULL && mstateSoundName[i] != StringTable->EmptyString())
|
||||||
|
{
|
||||||
|
//ok, so we've got some sort of special-case here like a fallback or SFXPlaylist. So do the hook-up now
|
||||||
|
SFXTrack* sndTrack;
|
||||||
|
if (!Sim::findObject(mstateSoundName[i], sndTrack))
|
||||||
|
{
|
||||||
|
Con::errorf("ShapeBaseImageData::onAdd() - attempted to find sound %s but failed!", mstateSoundName[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s.soundTrack = sndTrack;
|
||||||
|
}
|
||||||
|
}
|
||||||
s.script = stateScript[i];
|
s.script = stateScript[i];
|
||||||
s.emitter = stateEmitter[i];
|
s.emitter = stateEmitter[i];
|
||||||
s.emitterTime = stateEmitterTime[i];
|
s.emitterTime = stateEmitterTime[i];
|
||||||
|
|
@ -2771,11 +2785,19 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play sound
|
// Play sound
|
||||||
if( stateData.sound && isGhost() )
|
if (isGhost())
|
||||||
|
{
|
||||||
|
if (stateData.sound)
|
||||||
{
|
{
|
||||||
const Point3F& velocity = getVelocity();
|
const Point3F& velocity = getVelocity();
|
||||||
image.addSoundSource(SFX->createSource(stateData.sound->getSfxProfile(), &getRenderTransform(), &velocity));
|
image.addSoundSource(SFX->createSource(stateData.sound->getSfxProfile(), &getRenderTransform(), &velocity));
|
||||||
}
|
}
|
||||||
|
if (stateData.soundTrack)
|
||||||
|
{
|
||||||
|
const Point3F& velocity = getVelocity();
|
||||||
|
image.addSoundSource(SFX->createSource(stateData.soundTrack, &getRenderTransform(), &velocity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Play animation
|
// Play animation
|
||||||
updateAnimThread(imageSlot, imageShapeIndex, lastState);
|
updateAnimThread(imageSlot, imageShapeIndex, lastState);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,41 @@
|
||||||
|
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
|
|
||||||
|
VfsXMLPrinter::VfsXMLPrinter(FileStream& stream, bool compact, int depth)
|
||||||
|
: XMLPrinter(NULL, compact, depth),
|
||||||
|
m_Stream(stream)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VfsXMLPrinter::~VfsXMLPrinter()
|
||||||
|
{
|
||||||
|
m_Stream.flush();
|
||||||
|
m_Stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add VFS friendly implementations of output functions
|
||||||
|
|
||||||
|
void VfsXMLPrinter::Print(const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
|
||||||
|
m_Stream.writeFormattedBuffer(format, va);
|
||||||
|
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VfsXMLPrinter::Write(const char* data, size_t size)
|
||||||
|
{
|
||||||
|
m_Stream.write(size, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VfsXMLPrinter::Putc(char ch)
|
||||||
|
{
|
||||||
|
m_Stream.write(static_cast<U8>(ch));
|
||||||
|
}
|
||||||
|
|
||||||
bool VfsXMLDocument::LoadFile(const char* pFilename)
|
bool VfsXMLDocument::LoadFile(const char* pFilename)
|
||||||
{
|
{
|
||||||
// Expand the file-path.
|
// Expand the file-path.
|
||||||
|
|
@ -61,96 +96,6 @@ bool VfsXMLDocument::LoadFile(const char* pFilename)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VfsXMLDocument::SaveFile(const char* pFilename)
|
|
||||||
{
|
|
||||||
// Expand the file-name into the file-path buffer.
|
|
||||||
char filenameBuffer[1024];
|
|
||||||
Con::expandScriptFilename(filenameBuffer, sizeof(filenameBuffer), pFilename);
|
|
||||||
|
|
||||||
FileStream stream;
|
|
||||||
|
|
||||||
// File opened?
|
|
||||||
if (!stream.open(filenameBuffer, Torque::FS::File::Write))
|
|
||||||
{
|
|
||||||
// No, so warn.
|
|
||||||
Con::warnf("Taml::writeFile() - Could not open filename '%s' for write.", filenameBuffer);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ret = SaveFile(stream);
|
|
||||||
|
|
||||||
stream.close();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VfsXMLDocument::ClearError()
|
|
||||||
{
|
|
||||||
_errorID = tinyxml2::XML_SUCCESS;
|
|
||||||
_errorLineNum = 0;
|
|
||||||
_errorStr.Reset();
|
|
||||||
|
|
||||||
tinyxml2::XMLDocument::ClearError();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VfsXMLDocument::SetError(tinyxml2::XMLError error, int lineNum, const char* format, ...)
|
|
||||||
{
|
|
||||||
TIXMLASSERT(error >= 0 && error < tinyxml2::XML_ERROR_COUNT);
|
|
||||||
_errorID = error;
|
|
||||||
_errorLineNum = lineNum;
|
|
||||||
_errorStr.Reset();
|
|
||||||
|
|
||||||
const size_t BUFFER_SIZE = 1000;
|
|
||||||
char* buffer = new char[BUFFER_SIZE];
|
|
||||||
|
|
||||||
TIXMLASSERT(sizeof(error) <= sizeof(int));
|
|
||||||
dSprintf(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
|
|
||||||
|
|
||||||
if (format) {
|
|
||||||
size_t len = strlen(buffer);
|
|
||||||
dSprintf(buffer + len, BUFFER_SIZE - len, ": ");
|
|
||||||
len = strlen(buffer);
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
dSprintf(buffer + len, BUFFER_SIZE - len, format, va);
|
|
||||||
va_end(va);
|
|
||||||
}
|
|
||||||
_errorStr.SetStr(buffer);
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
VfsXMLPrinter::VfsXMLPrinter(FileStream& stream, bool compact, int depth)
|
|
||||||
: XMLPrinter(NULL, compact, depth),
|
|
||||||
m_Stream(stream)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VfsXMLPrinter::~VfsXMLPrinter()
|
|
||||||
{
|
|
||||||
m_Stream.flush();
|
|
||||||
m_Stream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VfsXMLPrinter::Print(const char* format, ...)
|
|
||||||
{
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
|
|
||||||
m_Stream.writeFormattedBuffer(format, va);
|
|
||||||
|
|
||||||
va_end(va);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VfsXMLPrinter::Write(const char* data, size_t size)
|
|
||||||
{
|
|
||||||
m_Stream.write(size, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VfsXMLPrinter::Putc(char ch)
|
|
||||||
{
|
|
||||||
m_Stream.write(static_cast<U8>(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VfsXMLDocument::LoadFile(FileStream& stream)
|
bool VfsXMLDocument::LoadFile(FileStream& stream)
|
||||||
{
|
{
|
||||||
// Delete the existing data:
|
// Delete the existing data:
|
||||||
|
|
@ -254,6 +199,173 @@ bool VfsXMLDocument::SaveFile(FileStream& stream)
|
||||||
// for *this* call.
|
// for *this* call.
|
||||||
ClearError();
|
ClearError();
|
||||||
VfsXMLPrinter printer(stream, false, 0);
|
VfsXMLPrinter printer(stream, false, 0);
|
||||||
Print(&printer);
|
PrettyXMLPrinter prettyPrinter(printer);
|
||||||
|
Print(&prettyPrinter);
|
||||||
return !Error();
|
return !Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VfsXMLDocument::SaveFile(const char* pFilename)
|
||||||
|
{
|
||||||
|
// Expand the file-name into the file-path buffer.
|
||||||
|
char filenameBuffer[1024];
|
||||||
|
Con::expandScriptFilename(filenameBuffer, sizeof(filenameBuffer), pFilename);
|
||||||
|
|
||||||
|
FileStream stream;
|
||||||
|
|
||||||
|
// File opened?
|
||||||
|
if (!stream.open(filenameBuffer, Torque::FS::File::Write))
|
||||||
|
{
|
||||||
|
// No, so warn.
|
||||||
|
Con::warnf("Taml::writeFile() - Could not open filename '%s' for write.", filenameBuffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = SaveFile(stream);
|
||||||
|
|
||||||
|
stream.close();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VfsXMLDocument::ClearError()
|
||||||
|
{
|
||||||
|
_errorID = tinyxml2::XML_SUCCESS;
|
||||||
|
_errorLineNum = 0;
|
||||||
|
_errorStr.Reset();
|
||||||
|
|
||||||
|
tinyxml2::XMLDocument::ClearError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VfsXMLDocument::SetError(tinyxml2::XMLError error, int lineNum, const char* format, ...)
|
||||||
|
{
|
||||||
|
TIXMLASSERT(error >= 0 && error < tinyxml2::XML_ERROR_COUNT);
|
||||||
|
_errorID = error;
|
||||||
|
_errorLineNum = lineNum;
|
||||||
|
_errorStr.Reset();
|
||||||
|
|
||||||
|
const size_t BUFFER_SIZE = 1000;
|
||||||
|
char* buffer = new char[BUFFER_SIZE];
|
||||||
|
|
||||||
|
TIXMLASSERT(sizeof(error) <= sizeof(int));
|
||||||
|
dSprintf(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
|
||||||
|
|
||||||
|
if (format) {
|
||||||
|
size_t len = strlen(buffer);
|
||||||
|
dSprintf(buffer + len, BUFFER_SIZE - len, ": ");
|
||||||
|
len = strlen(buffer);
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
dSprintf(buffer + len, BUFFER_SIZE - len, format, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
_errorStr.SetStr(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Overwrite Visitation of elements to add newlines before attributes
|
||||||
|
PrettyXMLPrinter::PrettyXMLPrinter(VfsXMLPrinter& innerPrinter, int depth)
|
||||||
|
: mInnerPrinter(innerPrinter),
|
||||||
|
mDepth(depth)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ENTITY_RANGE; ++i) {
|
||||||
|
mEntityFlag[i] = false;
|
||||||
|
mRestrictedEntityFlag[i] = false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < NUM_ENTITIES; ++i) {
|
||||||
|
const char entityValue = entities[i].value;
|
||||||
|
const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
|
||||||
|
TIXMLASSERT(flagIndex < ENTITY_RANGE);
|
||||||
|
mEntityFlag[flagIndex] = true;
|
||||||
|
}
|
||||||
|
mRestrictedEntityFlag[static_cast<unsigned char>('&')] = true;
|
||||||
|
mRestrictedEntityFlag[static_cast<unsigned char>('<')] = true;
|
||||||
|
mRestrictedEntityFlag[static_cast<unsigned char>('>')] = true; // not required, but consistency is nice
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrettyXMLPrinter::PrintString(const char* p, bool restricted)
|
||||||
|
{
|
||||||
|
// Look for runs of bytes between entities to print.
|
||||||
|
const char* q = p;
|
||||||
|
|
||||||
|
if (mProcessEntities) {
|
||||||
|
const bool* flag = restricted ? mRestrictedEntityFlag : mEntityFlag;
|
||||||
|
while (*q) {
|
||||||
|
TIXMLASSERT(p <= q);
|
||||||
|
// Remember, char is sometimes signed. (How many times has that bitten me?)
|
||||||
|
if (*q > 0 && *q < ENTITY_RANGE) {
|
||||||
|
// Check for entities. If one is found, flush
|
||||||
|
// the stream up until the entity, write the
|
||||||
|
// entity, and keep looking.
|
||||||
|
if (flag[static_cast<unsigned char>(*q)]) {
|
||||||
|
while (p < q) {
|
||||||
|
const size_t delta = q - p;
|
||||||
|
const int toPrint = (INT_MAX < delta) ? INT_MAX : static_cast<int>(delta);
|
||||||
|
mInnerPrinter.Write(p, toPrint);
|
||||||
|
p += toPrint;
|
||||||
|
}
|
||||||
|
bool entityPatternPrinted = false;
|
||||||
|
for (int i = 0; i < NUM_ENTITIES; ++i) {
|
||||||
|
if (entities[i].value == *q) {
|
||||||
|
mInnerPrinter.Putc('&');
|
||||||
|
mInnerPrinter.Write(entities[i].pattern, entities[i].length);
|
||||||
|
mInnerPrinter.Putc(';');
|
||||||
|
entityPatternPrinted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!entityPatternPrinted) {
|
||||||
|
// TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
|
||||||
|
TIXMLASSERT(false);
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++q;
|
||||||
|
TIXMLASSERT(p <= q);
|
||||||
|
}
|
||||||
|
// Flush the remaining string. This will be the entire
|
||||||
|
// string if an entity wasn't found.
|
||||||
|
if (p < q) {
|
||||||
|
const size_t delta = q - p;
|
||||||
|
const int toPrint = (INT_MAX < delta) ? INT_MAX : static_cast<int>(delta);
|
||||||
|
mInnerPrinter.Write(p, toPrint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mInnerPrinter.Write(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PrettyXMLPrinter::VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* attribute)
|
||||||
|
{
|
||||||
|
const tinyxml2::XMLElement* parentElem = 0;
|
||||||
|
if (element.Parent()) {
|
||||||
|
parentElem = element.Parent()->ToElement();
|
||||||
|
}
|
||||||
|
const bool compactMode = parentElem ? mInnerPrinter.CompactMode(*parentElem) : mInnerPrinter.CompactMode(element);
|
||||||
|
mInnerPrinter.OpenElement(element.Name(), compactMode);
|
||||||
|
mDepth++;
|
||||||
|
while (attribute) {
|
||||||
|
PushAttribute(attribute->Name(), attribute->Value(), compactMode);
|
||||||
|
attribute = attribute->Next();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrettyXMLPrinter::PushAttribute(const char* name, const char* value, bool compactMode)
|
||||||
|
{
|
||||||
|
if (compactMode)
|
||||||
|
{
|
||||||
|
mInnerPrinter.Putc(' ');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mInnerPrinter.Putc('\n');
|
||||||
|
mInnerPrinter.PrintSpace(mDepth);
|
||||||
|
}
|
||||||
|
mInnerPrinter.Write(name);
|
||||||
|
mInnerPrinter.Write("=\"");
|
||||||
|
PrintString(value, false);
|
||||||
|
mInnerPrinter.Putc('\"');
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,18 @@ public:
|
||||||
VfsXMLPrinter(FileStream& stream, bool compact = false, int depth = 0);
|
VfsXMLPrinter(FileStream& stream, bool compact = false, int depth = 0);
|
||||||
~VfsXMLPrinter() override;
|
~VfsXMLPrinter() override;
|
||||||
|
|
||||||
|
// Re-implement protected functionality in TinyXML2 library, and make it public
|
||||||
|
// (This is a bit dirty, but it's necessary for the PrettyXMLPrinter)
|
||||||
|
bool CompactMode(const tinyxml2::XMLElement& element) override { return tinyxml2::XMLPrinter::CompactMode(element); }
|
||||||
|
void PrintSpace(int depth) override { tinyxml2::XMLPrinter::PrintSpace(depth); }
|
||||||
|
inline void Write(const char* data) { Write(data, strlen(data)); }
|
||||||
|
|
||||||
|
// Add VFS friendly implementations of output functions
|
||||||
void Print(const char* format, ...) override;
|
void Print(const char* format, ...) override;
|
||||||
void Write(const char* data, size_t size) override;
|
void Write(const char* data, size_t size) override;
|
||||||
void Putc(char ch) override;
|
void Putc(char ch) override;
|
||||||
|
|
||||||
|
// Accept a virtual FileStream instead of a FILE pointer
|
||||||
FileStream& m_Stream;
|
FileStream& m_Stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -127,4 +136,103 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PrettyXMLPrinter : public tinyxml2::XMLPrinter
|
||||||
|
{
|
||||||
|
// Re-implement private functionality in TinyXML2
|
||||||
|
static const char LINE_FEED = static_cast<char>(0x0a); // all line endings are normalized to LF
|
||||||
|
static const char LF = LINE_FEED;
|
||||||
|
static const char CARRIAGE_RETURN = static_cast<char>(0x0d); // CR gets filtered out
|
||||||
|
static const char CR = CARRIAGE_RETURN;
|
||||||
|
static const char SINGLE_QUOTE = '\'';
|
||||||
|
static const char DOUBLE_QUOTE = '\"';
|
||||||
|
|
||||||
|
struct Entity
|
||||||
|
{
|
||||||
|
const char* pattern;
|
||||||
|
int length;
|
||||||
|
char value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int NUM_ENTITIES = 5;
|
||||||
|
static constexpr Entity entities[NUM_ENTITIES] = {
|
||||||
|
{"quot", 4, DOUBLE_QUOTE},
|
||||||
|
{"amp", 3, '&'},
|
||||||
|
{"apos", 4, SINGLE_QUOTE},
|
||||||
|
{"lt", 2, '<'},
|
||||||
|
{"gt", 2, '>'}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
PrettyXMLPrinter(VfsXMLPrinter& innerPrinter, int depth = 0);
|
||||||
|
|
||||||
|
/// Visit a document.
|
||||||
|
virtual bool VisitEnter(const tinyxml2::XMLDocument& doc)
|
||||||
|
{
|
||||||
|
mProcessEntities = doc.ProcessEntities();
|
||||||
|
return mInnerPrinter.VisitEnter(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visit a document.
|
||||||
|
virtual bool VisitExit(const tinyxml2::XMLDocument& doc)
|
||||||
|
{
|
||||||
|
return mInnerPrinter.VisitExit(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visit an element.
|
||||||
|
virtual bool VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* firstAttribute);
|
||||||
|
/// Visit an element.
|
||||||
|
virtual bool VisitExit(const tinyxml2::XMLElement& element)
|
||||||
|
{
|
||||||
|
mDepth--;
|
||||||
|
return mInnerPrinter.VisitExit(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visit a declaration.
|
||||||
|
virtual bool Visit(const tinyxml2::XMLDeclaration& declaration)
|
||||||
|
{
|
||||||
|
return mInnerPrinter.Visit(declaration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visit a text node.
|
||||||
|
virtual bool Visit(const tinyxml2::XMLText& text)
|
||||||
|
{
|
||||||
|
return mInnerPrinter.Visit(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visit a comment node.
|
||||||
|
virtual bool Visit(const tinyxml2::XMLComment& comment)
|
||||||
|
{
|
||||||
|
return mInnerPrinter.Visit(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visit an unknown node.
|
||||||
|
virtual bool Visit(const tinyxml2::XMLUnknown& unknown)
|
||||||
|
{
|
||||||
|
return mInnerPrinter.Visit(unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushAttribute(const char* name, const char* value, bool compactMode);
|
||||||
|
|
||||||
|
// Re-implement private functionality in TinyXML2 library, this is just a copy-paste job
|
||||||
|
void PrintString(const char*, bool restrictedEntitySet); // prints out, after detecting entities.
|
||||||
|
|
||||||
|
// The inner printer we are wrapping, we only support VfsXMLPrinter based classes because
|
||||||
|
// stock tinyxml printer is very closed
|
||||||
|
VfsXMLPrinter& mInnerPrinter;
|
||||||
|
|
||||||
|
// Track private fields that are necessary for private functionality in TinyXML2
|
||||||
|
int mDepth;
|
||||||
|
bool mProcessEntities;
|
||||||
|
bool mCompactMode;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ENTITY_RANGE = 64,
|
||||||
|
BUF_SIZE = 200
|
||||||
|
};
|
||||||
|
|
||||||
|
bool mEntityFlag[ENTITY_RANGE];
|
||||||
|
bool mRestrictedEntityFlag[ENTITY_RANGE];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif //_FSTINYXML_H_
|
#endif //_FSTINYXML_H_
|
||||||
|
|
|
||||||
|
|
@ -351,6 +351,9 @@ bool SFXPlayList::preload( bool server, String& errorStr )
|
||||||
if( !server )
|
if( !server )
|
||||||
{
|
{
|
||||||
for( U32 i = 0; i < NUM_SLOTS; ++ i )
|
for( U32 i = 0; i < NUM_SLOTS; ++ i )
|
||||||
|
{
|
||||||
|
StringTableEntry track = getTrack(i);
|
||||||
|
if (track != StringTable->EmptyString())
|
||||||
{
|
{
|
||||||
_setTrack(getTrack(i), i);
|
_setTrack(getTrack(i), i);
|
||||||
if (!getTrackProfile(i))
|
if (!getTrackProfile(i))
|
||||||
|
|
@ -363,6 +366,7 @@ bool SFXPlayList::preload( bool server, String& errorStr )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
#include "core/stream/bitStream.h"
|
#include "core/stream/bitStream.h"
|
||||||
#include "core/resourceManager.h"
|
#include "core/resourceManager.h"
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
|
#include "core/stream/fileStream.h"
|
||||||
|
|
||||||
using namespace Torque;
|
using namespace Torque;
|
||||||
|
|
||||||
|
|
@ -283,8 +284,13 @@ bool SFXProfile::_preloadBuffer()
|
||||||
|
|
||||||
Resource<SFXResource>& SFXProfile::getResource()
|
Resource<SFXResource>& SFXProfile::getResource()
|
||||||
{
|
{
|
||||||
if( !mResource && mFilename != StringTable->EmptyString())
|
char buf[1024];
|
||||||
|
FileName fullFilename = String(Platform::makeFullPathName(mFilename, buf, sizeof(buf)));
|
||||||
|
|
||||||
|
if (!mResource && SFXResource::exists(fullFilename))
|
||||||
mResource = SFXResource::load(mFilename);
|
mResource = SFXResource::load(mFilename);
|
||||||
|
else
|
||||||
|
mResource = NULL;
|
||||||
|
|
||||||
return mResource;
|
return mResource;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1581,133 +1581,70 @@ DefineEngineFunction( sfxPlay, S32, ( const char * trackName, const char * point
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static ConsoleDocFragment _sPlayOnce1(
|
static ConsoleDocFragment _sPlayOnce1(
|
||||||
"@brief Create a play-once source for the given @a track.\n\n"
|
"@brief Create a play-once source for the given @a asset.\n\n"
|
||||||
"Once playback has finished, the source will be automatically deleted in the next sound system update.\n"
|
"Once playback has finished, the source will be automatically deleted in the next sound system update.\n"
|
||||||
"@param track The sound datablock.\n"
|
"@param track The sound datablock.\n"
|
||||||
"@return A newly created temporary source in \"Playing\" state or 0 if the operation failed.\n\n"
|
"@return A newly created temporary source in \"Playing\" state or 0 if the operation failed.\n\n"
|
||||||
"@ref SFXSource_playonce\n\n"
|
"@ref SFXSource_playonce\n\n"
|
||||||
"@ingroup SFX",
|
"@ingroup SFX",
|
||||||
NULL,
|
NULL,
|
||||||
"SFXSource sfxPlayOnce( SFXTrack track );"
|
"SFXSource sfxPlayOnce( StringTableEntry assetID );"
|
||||||
);
|
);
|
||||||
static ConsoleDocFragment _sPlayOnce2(
|
static ConsoleDocFragment _sPlayOnce2(
|
||||||
"@brief Create a play-once source for the given given @a track and position the source's 3D sound at the given coordinates "
|
"@brief Create a play-once source for the given given @a asset and position the source's 3D sound at the given coordinates "
|
||||||
"only if the track's description is set up for 3D sound).\n\n"
|
"only if the asset is set up for 3D sound).\n\n"
|
||||||
"Once playback has finished, the source will be automatically deleted in the next sound system update.\n"
|
"Once playback has finished, the source will be automatically deleted in the next sound system update.\n"
|
||||||
"@param track The sound datablock.\n"
|
"@param assetId The sound asset.\n"
|
||||||
"@param x The X coordinate of the 3D sound position.\n"
|
"@param x The X coordinate of the 3D sound position.\n"
|
||||||
"@param y The Y coordinate of the 3D sound position.\n"
|
"@param y The Y coordinate of the 3D sound position.\n"
|
||||||
"@param z The Z coordinate of the 3D sound position.\n"
|
"@param z The Z coordinate of the 3D sound position.\n"
|
||||||
"@param fadeInTime If >=0, this overrides the SFXDescription::fadeInTime value on the track's description.\n"
|
"@param fadeInTime If >=0, this overrides the SFXDescription::fadeInTime value on the asset's definition.\n"
|
||||||
"@return A newly created temporary source in \"Playing\" state or 0 if the operation failed.\n\n"
|
"@return A newly created temporary source in \"Playing\" state or 0 if the operation failed.\n\n"
|
||||||
"@tsexample\n"
|
"@tsexample\n"
|
||||||
"// Immediately start playing the given track. Fade it in to full volume over 5 seconds.\n"
|
"// Immediately start playing the given asset. Fade it in to full volume over 5 seconds.\n"
|
||||||
"sfxPlayOnce( MusicTrack, 0, 0, 0, 5.f );\n"
|
"sfxPlayOnce( ExampleModule:MusicTrack, 0, 0, 0, 5.f );\n"
|
||||||
"@endtsexample\n\n"
|
"@endtsexample\n\n"
|
||||||
"@ref SFXSource_playonce\n\n"
|
"@ref SFXSource_playonce\n\n"
|
||||||
"@ingroup SFX",
|
"@ingroup SFX",
|
||||||
NULL,
|
NULL,
|
||||||
"SFXSource sfxPlayOnce( SFXTrack track, float x, float y, float z, float fadeInTime=-1 );"
|
"SFXSource sfxPlayOnce( StringTableEntry assetID, float x, float y, float z, float fadeInTime=-1 );"
|
||||||
);
|
|
||||||
static ConsoleDocFragment _sPlayOnce3(
|
|
||||||
"@brief Create a new temporary SFXProfile from the given @a description and @a filename, then create a play-once source "
|
|
||||||
"for it and start playback.\n\n"
|
|
||||||
"Once playback has finished, the source will be automatically deleted in the next sound system update. If not referenced "
|
|
||||||
"otherwise by then, the temporary SFXProfile will also be deleted.\n"
|
|
||||||
"@param description The description to use for playback.\n"
|
|
||||||
"@param filename Path to the sound file to play.\n"
|
|
||||||
"@return A newly created temporary source in \"Playing\" state or 0 if the operation failed.\n\n"
|
|
||||||
"@tsexample\n"
|
|
||||||
"// Play a sound effect file once.\n"
|
|
||||||
"sfxPlayOnce( AudioEffects, \"art/sound/weapons/Weapon_pickup\" );\n"
|
|
||||||
"@endtsexample\n\n"
|
|
||||||
"@ref SFXSource_playonce\n\n"
|
|
||||||
"@ingroup SFX",
|
|
||||||
NULL,
|
|
||||||
"SFXSource sfxPlayOnce( SFXDescription description, string filename );"
|
|
||||||
);
|
|
||||||
static ConsoleDocFragment _sPlayOnce4(
|
|
||||||
"@brief Create a new temporary SFXProfile from the given @a description and @a filename, then create a play-once source "
|
|
||||||
"for it and start playback. Position the source's 3D sound at the given coordinates (only if the description "
|
|
||||||
"is set up for 3D sound).\n\n"
|
|
||||||
"Once playback has finished, the source will be automatically deleted in the next sound system update. If not referenced "
|
|
||||||
"otherwise by then, the temporary SFXProfile will also be deleted.\n"
|
|
||||||
"@param description The description to use for playback.\n"
|
|
||||||
"@param filename Path to the sound file to play.\n"
|
|
||||||
"@param x The X coordinate of the 3D sound position.\n"
|
|
||||||
"@param y The Y coordinate of the 3D sound position.\n"
|
|
||||||
"@param z The Z coordinate of the 3D sound position.\n"
|
|
||||||
"@param fadeInTime If >=0, this overrides the SFXDescription::fadeInTime value on the track's description.\n"
|
|
||||||
"@return A newly created temporary source in \"Playing\" state or 0 if the operation failed.\n\n"
|
|
||||||
"@tsexample\n"
|
|
||||||
"// Play a sound effect file once using a 3D sound with a default falloff placed at the origin.\n"
|
|
||||||
"sfxPlayOnce( AudioDefault3D, \"art/sound/weapons/Weapon_pickup\", 0, 0, 0 );\n"
|
|
||||||
"@endtsexample\n\n"
|
|
||||||
"@ref SFXSource_playonce\n\n"
|
|
||||||
"@ingroup SFX",
|
|
||||||
NULL,
|
|
||||||
"SFXSource sfxPlayOnce( SFXDescription description, string filename, float x, float y, float z, float fadeInTime=-1 );"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
DefineEngineFunction( sfxPlayOnce, S32, ( const char * sfxType, const char * arg0, const char * arg1, const char * arg2, const char * arg3, const char* arg4 ), ("", "", "", "", "-1.0f"),
|
DefineEngineFunction( sfxPlayOnce, S32, (StringTableEntry assetId, const char* arg0, const char * arg1, const char * arg2, const char * arg3 ), (StringTable->EmptyString(), "", "", "", "-1.0f"),
|
||||||
"SFXSource sfxPlayOnce( ( SFXTrack track | SFXDescription description, string filename ) [, float x, float y, float z, float fadeInTime=-1 ] ) "
|
"SFXSource sfxPlayOnce( ( SFXTrack track | SFXDescription description, string filename ) [, float x, float y, float z, float fadeInTime=-1 ] ) "
|
||||||
"Create a new play-once source for the given profile or description+filename and start playback of the source.\n"
|
"Create a new play-once source for the given profile or description+filename and start playback of the source.\n"
|
||||||
"@hide" )
|
"@hide" )
|
||||||
{
|
{
|
||||||
SFXDescription* description = NULL;
|
SFXDescription* description = NULL;
|
||||||
SFXTrack* track = dynamic_cast< SFXTrack* >( Sim::findObject( sfxType ) );
|
if (assetId == StringTable->EmptyString())
|
||||||
if( !track )
|
|
||||||
{
|
{
|
||||||
description = dynamic_cast< SFXDescription* >( Sim::findObject( sfxType ) );
|
Con::errorf( "sfxPlayOnce - Must Define a sound asset");
|
||||||
if( !description )
|
|
||||||
{
|
|
||||||
Con::errorf( "sfxPlayOnce - Unable to locate sound track/description '%s'", sfxType );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SFXSource* source = NULL;
|
SFXSource* source = NULL;
|
||||||
if( track )
|
|
||||||
|
if (AssetDatabase.isDeclaredAsset(assetId))
|
||||||
{
|
{
|
||||||
// In this overloaded use, arg0..arg2 are x, y, z, and arg3 is the fadeInTime.
|
|
||||||
if (String::isEmpty(arg0))
|
AssetPtr<SoundAsset> tempSoundAsset;
|
||||||
|
tempSoundAsset = assetId;
|
||||||
|
|
||||||
|
if (String::isEmpty(arg0) || !tempSoundAsset->is3D())
|
||||||
{
|
{
|
||||||
source = SFX->playOnce( track );
|
source = SFX->playOnce(tempSoundAsset->getSfxProfile());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MatrixF transform;
|
MatrixF transform;
|
||||||
transform.set(EulerF(0, 0, 0), Point3F(dAtof(arg0), dAtof(arg1), dAtof(arg2)));
|
transform.set(EulerF(0, 0, 0), Point3F(dAtof(arg0), dAtof(arg1), dAtof(arg2)));
|
||||||
source = SFX->playOnce( track, &transform, NULL, dAtof( arg3 ) );
|
source = SFX->playOnce(tempSoundAsset->getSfxProfile(), &transform, NULL, dAtof(arg3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( description )
|
|
||||||
{
|
|
||||||
// In this overload, arg0 is the filename, arg1..arg3 are x, y, z, and arg4 is fadeInTime.
|
|
||||||
SFXProfile* tempProfile = new SFXProfile( description, StringTable->insert( arg0 ), true );
|
|
||||||
if( !tempProfile->registerObject() )
|
|
||||||
{
|
|
||||||
Con::errorf( "sfxPlayOnce - unable to create profile" );
|
|
||||||
delete tempProfile;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (String::isEmpty(arg1))
|
Con::errorf("sfxPlayOnce - Could not locate assetId '%s'", assetId);
|
||||||
source = SFX->playOnce( tempProfile );
|
return 0;
|
||||||
else
|
|
||||||
{
|
|
||||||
MatrixF transform;
|
|
||||||
transform.set( EulerF( 0, 0, 0 ), Point3F( dAtof( arg1 ), dAtof( arg2 ),dAtof( arg3 ) ) );
|
|
||||||
source = SFX->playOnce( tempProfile, &transform, NULL, dAtof( arg4 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set profile to auto-delete when SFXSource releases its reference.
|
|
||||||
// Also add to root group so the profile will get deleted when the
|
|
||||||
// Sim system is shut down before the SFXSource has played out.
|
|
||||||
|
|
||||||
tempProfile->setAutoDelete( true );
|
|
||||||
Sim::getRootGroup()->addObject( tempProfile );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !source )
|
if( !source )
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue