mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-29 16:25:42 +00:00
Merge pull request #2056 from Bloodknight/afx_merge_main
Afx merge main
This commit is contained in:
commit
35d649b57e
301 changed files with 59625 additions and 1480 deletions
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/aiPlayer.h"
|
#include "T3D/aiPlayer.h"
|
||||||
|
|
||||||
|
|
@ -97,6 +102,9 @@ AIPlayer::AIPlayer()
|
||||||
mMoveSlowdown = true;
|
mMoveSlowdown = true;
|
||||||
mMoveState = ModeStop;
|
mMoveState = ModeStop;
|
||||||
|
|
||||||
|
// This new member saves the movement state of the AI so that
|
||||||
|
// it can be restored after a substituted animation is finished.
|
||||||
|
mMoveState_saved = -1;
|
||||||
mAimObject = 0;
|
mAimObject = 0;
|
||||||
mAimLocationSet = false;
|
mAimLocationSet = false;
|
||||||
mTargetInLOS = false;
|
mTargetInLOS = false;
|
||||||
|
|
@ -547,23 +555,27 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
||||||
mMoveState = ModeMove;
|
mMoveState = ModeMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMoveStuckTestCountdown > 0)
|
// Don't check for ai stuckness if animation during
|
||||||
--mMoveStuckTestCountdown;
|
// an anim-clip effect override.
|
||||||
else
|
if (mDamageState == Enabled && !(anim_clip_flags & ANIM_OVERRIDDEN) && !isAnimationLocked()) {
|
||||||
{
|
if (mMoveStuckTestCountdown > 0)
|
||||||
// We should check to see if we are stuck...
|
--mMoveStuckTestCountdown;
|
||||||
F32 locationDelta = (location - mLastLocation).len();
|
else
|
||||||
|
{
|
||||||
|
// We should check to see if we are stuck...
|
||||||
|
F32 locationDelta = (location - mLastLocation).len();
|
||||||
if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled)
|
if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled)
|
||||||
{
|
{
|
||||||
// If we are slowing down, then it's likely that our location delta will be less than
|
// If we are slowing down, then it's likely that our location delta will be less than
|
||||||
// our move stuck tolerance. Because we can be both slowing and stuck
|
// our move stuck tolerance. Because we can be both slowing and stuck
|
||||||
// we should TRY to check if we've moved. This could use better detection.
|
// we should TRY to check if we've moved. This could use better detection.
|
||||||
if ( mMoveState != ModeSlowing || locationDelta == 0 )
|
if ( mMoveState != ModeSlowing || locationDelta == 0 )
|
||||||
{
|
{
|
||||||
mMoveState = ModeStuck;
|
mMoveState = ModeStuck;
|
||||||
onStuck();
|
onStuck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -626,6 +638,7 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
||||||
}
|
}
|
||||||
#endif // TORQUE_NAVIGATION_ENABLED
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
|
|
||||||
|
if (!(anim_clip_flags & ANIM_OVERRIDDEN) && !isAnimationLocked())
|
||||||
mLastLocation = location;
|
mLastLocation = location;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1415,6 +1428,47 @@ DefineEngineMethod( AIPlayer, clearMoveTriggers, void, ( ),,
|
||||||
object->clearMoveTriggers();
|
object->clearMoveTriggers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These changes coordinate with anim-clip mods to parent class, Player.
|
||||||
|
|
||||||
|
// New method, restartMove(), restores the AIPlayer to its normal move-state
|
||||||
|
// following animation overrides from AFX. The tag argument is used to match
|
||||||
|
// the latest override and prevents interruption of overlapping animation
|
||||||
|
// overrides. See related anim-clip changes in Player.[h,cc].
|
||||||
|
void AIPlayer::restartMove(U32 tag)
|
||||||
|
{
|
||||||
|
if (tag != 0 && tag == last_anim_tag)
|
||||||
|
{
|
||||||
|
if (mMoveState_saved != -1)
|
||||||
|
{
|
||||||
|
mMoveState = (MoveState) mMoveState_saved;
|
||||||
|
mMoveState_saved = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_death_anim = ((anim_clip_flags & IS_DEATH_ANIM) != 0);
|
||||||
|
|
||||||
|
last_anim_tag = 0;
|
||||||
|
anim_clip_flags &= ~(ANIM_OVERRIDDEN | IS_DEATH_ANIM);
|
||||||
|
|
||||||
|
if (mDamageState != Enabled)
|
||||||
|
{
|
||||||
|
if (!is_death_anim)
|
||||||
|
{
|
||||||
|
// this is a bit hardwired and desperate,
|
||||||
|
// but if he's dead he needs to look like it.
|
||||||
|
setActionThread("death10", false, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New method, saveMoveState(), stores the current movement state
|
||||||
|
// so that it can be restored when restartMove() is called.
|
||||||
|
void AIPlayer::saveMoveState()
|
||||||
|
{
|
||||||
|
if (mMoveState_saved == -1)
|
||||||
|
mMoveState_saved = (S32) mMoveState;
|
||||||
|
}
|
||||||
|
|
||||||
F32 AIPlayer::getTargetDistance(GameBase* target, bool _checkEnabled)
|
F32 AIPlayer::getTargetDistance(GameBase* target, bool _checkEnabled)
|
||||||
{
|
{
|
||||||
if (!isServerObject()) return false;
|
if (!isServerObject()) return false;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _AIPLAYER_H_
|
#ifndef _AIPLAYER_H_
|
||||||
#define _AIPLAYER_H_
|
#define _AIPLAYER_H_
|
||||||
|
|
||||||
|
|
@ -225,6 +230,18 @@ public:
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
#endif // TORQUE_NAVIGATION_ENABLED
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
|
// New method, restartMove(), restores the AIPlayer to its normal move-state
|
||||||
|
// following animation overrides from AFX. The tag argument is used to match
|
||||||
|
// the latest override and prevents interruption of overlapping animation
|
||||||
|
// overrides.
|
||||||
|
// New method, saveMoveState(), stores the current movement state
|
||||||
|
// so that it can be restored when restartMove() is called.
|
||||||
|
// See related anim-clip changes in Player.[h,cc].
|
||||||
|
private:
|
||||||
|
S32 mMoveState_saved;
|
||||||
|
public:
|
||||||
|
void restartMove(U32 tag);
|
||||||
|
void saveMoveState();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _CAMERA_H_
|
#ifndef _CAMERA_H_
|
||||||
#define _CAMERA_H_
|
#define _CAMERA_H_
|
||||||
|
|
||||||
|
|
@ -246,6 +251,8 @@ class Camera: public ShapeBase
|
||||||
DECLARE_CONOBJECT( Camera );
|
DECLARE_CONOBJECT( Camera );
|
||||||
DECLARE_CATEGORY( "Game" );
|
DECLARE_CATEGORY( "Game" );
|
||||||
DECLARE_DESCRIPTION( "Represents a position, direction and field of view to render a scene from." );
|
DECLARE_DESCRIPTION( "Represents a position, direction and field of view to render a scene from." );
|
||||||
|
static F32 getMovementSpeed() { return smMovementSpeed; }
|
||||||
|
bool isCamera() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Camera::CameraMotionMode CameraMotionMode;
|
typedef Camera::CameraMotionMode CameraMotionMode;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/containerQuery.h"
|
#include "T3D/containerQuery.h"
|
||||||
|
|
||||||
|
|
@ -91,7 +96,9 @@ void physicalZoneFind(SceneObject* obj, void *key)
|
||||||
|
|
||||||
if (pz->isActive()) {
|
if (pz->isActive()) {
|
||||||
info->gravityScale *= pz->getGravityMod();
|
info->gravityScale *= pz->getGravityMod();
|
||||||
info->appliedForce += pz->getForce();
|
Point3F center;
|
||||||
|
info->box.getCenter(¢er);
|
||||||
|
info->appliedForce += pz->getForce(¢er);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/debris.h"
|
#include "T3D/debris.h"
|
||||||
|
|
||||||
|
|
@ -113,6 +118,85 @@ DebrisData::DebrisData()
|
||||||
ignoreWater = true;
|
ignoreWater = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#define TRACK_DEBRIS_DATA_CLONES
|
||||||
|
|
||||||
|
#ifdef TRACK_DEBRIS_DATA_CLONES
|
||||||
|
static int debris_data_clones = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DebrisData::DebrisData(const DebrisData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
#ifdef TRACK_DEBRIS_DATA_CLONES
|
||||||
|
debris_data_clones++;
|
||||||
|
if (debris_data_clones == 1)
|
||||||
|
Con::errorf("DebrisData -- Clones are on the loose!");
|
||||||
|
#endif
|
||||||
|
velocity = other.velocity;
|
||||||
|
velocityVariance = other.velocityVariance;
|
||||||
|
friction = other.friction;
|
||||||
|
elasticity = other.elasticity;
|
||||||
|
lifetime = other.lifetime;
|
||||||
|
lifetimeVariance = other.lifetimeVariance;
|
||||||
|
numBounces = other.numBounces;
|
||||||
|
bounceVariance = other.bounceVariance;
|
||||||
|
minSpinSpeed = other.minSpinSpeed;
|
||||||
|
maxSpinSpeed = other.maxSpinSpeed;
|
||||||
|
explodeOnMaxBounce = other.explodeOnMaxBounce;
|
||||||
|
staticOnMaxBounce = other.staticOnMaxBounce;
|
||||||
|
snapOnMaxBounce = other.snapOnMaxBounce;
|
||||||
|
fade = other.fade;
|
||||||
|
useRadiusMass = other.useRadiusMass;
|
||||||
|
baseRadius = other.baseRadius;
|
||||||
|
gravModifier = other.gravModifier;
|
||||||
|
terminalVelocity = other.terminalVelocity;
|
||||||
|
ignoreWater = other.ignoreWater;
|
||||||
|
shapeName = other.shapeName;
|
||||||
|
shape = other.shape; // -- TSShape loaded using shapeName
|
||||||
|
textureName = other.textureName;
|
||||||
|
explosionId = other.explosionId; // -- for pack/unpack of explosion ptr
|
||||||
|
explosion = other.explosion;
|
||||||
|
dMemcpy( emitterList, other.emitterList, sizeof( emitterList ) );
|
||||||
|
dMemcpy( emitterIDList, other.emitterIDList, sizeof( emitterIDList ) ); // -- for pack/unpack of emitterList ptrs
|
||||||
|
}
|
||||||
|
|
||||||
|
DebrisData::~DebrisData()
|
||||||
|
{
|
||||||
|
if (!isTempClone())
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef TRACK_DEBRIS_DATA_CLONES
|
||||||
|
if (debris_data_clones > 0)
|
||||||
|
{
|
||||||
|
debris_data_clones--;
|
||||||
|
if (debris_data_clones == 0)
|
||||||
|
Con::errorf("DebrisData -- Clones eliminated!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Con::errorf("DebrisData -- Too many clones deleted!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DebrisData* DebrisData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index)
|
||||||
|
{
|
||||||
|
if (!owner || getSubstitutionCount() == 0)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
DebrisData* sub_debris_db = new DebrisData(*this, true);
|
||||||
|
performSubstitutions(sub_debris_db, owner, index);
|
||||||
|
|
||||||
|
return sub_debris_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebrisData::onPerformSubstitutions()
|
||||||
|
{
|
||||||
|
if( shapeName && shapeName[0] != '\0')
|
||||||
|
{
|
||||||
|
shape = ResourceManager::get().load(shapeName);
|
||||||
|
if( bool(shape) == false )
|
||||||
|
Con::errorf("DebrisData::onPerformSubstitutions(): failed to load shape \"%s\"", shapeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DebrisData::onAdd()
|
bool DebrisData::onAdd()
|
||||||
{
|
{
|
||||||
if(!Parent::onAdd())
|
if(!Parent::onAdd())
|
||||||
|
|
@ -269,6 +353,9 @@ void DebrisData::initPersistFields()
|
||||||
addField("ignoreWater", TypeBool, Offset(ignoreWater, DebrisData), "If true, this debris object will not collide with water, acting as if the water is not there.");
|
addField("ignoreWater", TypeBool, Offset(ignoreWater, DebrisData), "If true, this debris object will not collide with water, acting as if the water is not there.");
|
||||||
endGroup("Behavior");
|
endGroup("Behavior");
|
||||||
|
|
||||||
|
// disallow some field substitutions
|
||||||
|
onlyKeepClearSubstitutions("emitters"); // subs resolving to "~~", or "~0" are OK
|
||||||
|
onlyKeepClearSubstitutions("explosion");
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -451,6 +538,8 @@ Debris::Debris()
|
||||||
|
|
||||||
// Only allocated client side.
|
// Only allocated client side.
|
||||||
mNetFlags.set( IsGhost );
|
mNetFlags.set( IsGhost );
|
||||||
|
ss_object = 0;
|
||||||
|
ss_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debris::~Debris()
|
Debris::~Debris()
|
||||||
|
|
@ -466,6 +555,12 @@ Debris::~Debris()
|
||||||
delete mPart;
|
delete mPart;
|
||||||
mPart = NULL;
|
mPart = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mDataBlock && mDataBlock->isTempClone())
|
||||||
|
{
|
||||||
|
delete mDataBlock;
|
||||||
|
mDataBlock = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debris::initPersistFields()
|
void Debris::initPersistFields()
|
||||||
|
|
@ -495,6 +590,8 @@ bool Debris::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||||
if( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
|
if( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (mDataBlock->isTempClone())
|
||||||
|
return true;
|
||||||
scriptOnNewDataBlock();
|
scriptOnNewDataBlock();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
@ -519,7 +616,7 @@ bool Debris::onAdd()
|
||||||
if( mDataBlock->emitterList[i] != NULL )
|
if( mDataBlock->emitterList[i] != NULL )
|
||||||
{
|
{
|
||||||
ParticleEmitter * pEmitter = new ParticleEmitter;
|
ParticleEmitter * pEmitter = new ParticleEmitter;
|
||||||
pEmitter->onNewDataBlock( mDataBlock->emitterList[i], false );
|
pEmitter->onNewDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index), false);
|
||||||
if( !pEmitter->registerObject() )
|
if( !pEmitter->registerObject() )
|
||||||
{
|
{
|
||||||
Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
|
Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
|
||||||
|
|
@ -537,7 +634,8 @@ bool Debris::onAdd()
|
||||||
{
|
{
|
||||||
sizeList[0] = mSize * 0.5;
|
sizeList[0] = mSize * 0.5;
|
||||||
sizeList[1] = mSize;
|
sizeList[1] = mSize;
|
||||||
sizeList[2] = mSize * 1.5;
|
for (U32 i = 2; i < ParticleData::PDC_NUM_KEYS; i++)
|
||||||
|
sizeList[i] = mSize * 1.5;
|
||||||
|
|
||||||
mEmitterList[0]->setSizes( sizeList );
|
mEmitterList[0]->setSizes( sizeList );
|
||||||
}
|
}
|
||||||
|
|
@ -546,7 +644,8 @@ bool Debris::onAdd()
|
||||||
{
|
{
|
||||||
sizeList[0] = 0.0;
|
sizeList[0] = 0.0;
|
||||||
sizeList[1] = mSize * 0.5;
|
sizeList[1] = mSize * 0.5;
|
||||||
sizeList[2] = mSize;
|
for (U32 i = 2; i < ParticleData::PDC_NUM_KEYS; i++)
|
||||||
|
sizeList[i] = mSize;
|
||||||
|
|
||||||
mEmitterList[1]->setSizes( sizeList );
|
mEmitterList[1]->setSizes( sizeList );
|
||||||
}
|
}
|
||||||
|
|
@ -798,7 +897,8 @@ void Debris::explode()
|
||||||
Point3F explosionPos = getPosition();
|
Point3F explosionPos = getPosition();
|
||||||
|
|
||||||
Explosion* pExplosion = new Explosion;
|
Explosion* pExplosion = new Explosion;
|
||||||
pExplosion->onNewDataBlock(mDataBlock->explosion, false);
|
pExplosion->setSubstitutionData(ss_object, ss_index);
|
||||||
|
pExplosion->onNewDataBlock(mDataBlock->explosion->cloneAndPerformSubstitutions(ss_object, ss_index), false);
|
||||||
|
|
||||||
MatrixF trans( true );
|
MatrixF trans( true );
|
||||||
trans.setPosition( getPosition() );
|
trans.setPosition( getPosition() );
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _DEBRIS_H_
|
#ifndef _DEBRIS_H_
|
||||||
#define _DEBRIS_H_
|
#define _DEBRIS_H_
|
||||||
|
|
||||||
|
|
@ -97,6 +102,12 @@ struct DebrisData : public GameBaseData
|
||||||
|
|
||||||
DECLARE_CONOBJECT(DebrisData);
|
DECLARE_CONOBJECT(DebrisData);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ DebrisData(const DebrisData&, bool = false);
|
||||||
|
/*D*/ ~DebrisData();
|
||||||
|
DebrisData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0);
|
||||||
|
virtual void onPerformSubstitutions();
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
|
|
@ -165,6 +176,11 @@ public:
|
||||||
|
|
||||||
DECLARE_CONOBJECT(Debris);
|
DECLARE_CONOBJECT(Debris);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SimObject* ss_object;
|
||||||
|
S32 ss_index;
|
||||||
|
public:
|
||||||
|
void setSubstitutionData(SimObject* obj, S32 idx=0) { ss_object = obj; ss_index = idx; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/fx/explosion.h"
|
#include "T3D/fx/explosion.h"
|
||||||
|
|
||||||
|
|
@ -50,6 +55,8 @@
|
||||||
#include "renderInstance/renderPassManager.h"
|
#include "renderInstance/renderPassManager.h"
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
|
|
||||||
|
#include "sfx/sfxProfile.h"
|
||||||
|
|
||||||
IMPLEMENT_CONOBJECT(Explosion);
|
IMPLEMENT_CONOBJECT(Explosion);
|
||||||
|
|
||||||
ConsoleDocClass( Explosion,
|
ConsoleDocClass( Explosion,
|
||||||
|
|
@ -281,6 +288,105 @@ ExplosionData::ExplosionData()
|
||||||
lightNormalOffset = 0.1f;
|
lightNormalOffset = 0.1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#define TRACK_EXPLOSION_DATA_CLONES
|
||||||
|
|
||||||
|
#ifdef TRACK_EXPLOSION_DATA_CLONES
|
||||||
|
static int explosion_data_clones = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ExplosionData::ExplosionData(const ExplosionData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
#ifdef TRACK_EXPLOSION_DATA_CLONES
|
||||||
|
explosion_data_clones++;
|
||||||
|
if (explosion_data_clones == 1)
|
||||||
|
Con::errorf("ExplosionData -- Clones are on the loose!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dtsFileName = other.dtsFileName;
|
||||||
|
faceViewer = other.faceViewer;
|
||||||
|
particleDensity = other.particleDensity;
|
||||||
|
particleRadius = other.particleRadius;
|
||||||
|
soundProfile = other.soundProfile;
|
||||||
|
particleEmitter = other.particleEmitter;
|
||||||
|
particleEmitterId = other.particleEmitterId; // -- for pack/unpack of particleEmitter ptr
|
||||||
|
explosionScale = other.explosionScale;
|
||||||
|
playSpeed = other.playSpeed;
|
||||||
|
explosionShape = other.explosionShape; // -- TSShape loaded using dtsFileName
|
||||||
|
explosionAnimation = other.explosionAnimation; // -- from explosionShape sequence "ambient"
|
||||||
|
dMemcpy( emitterList, other.emitterList, sizeof( emitterList ) );
|
||||||
|
dMemcpy( emitterIDList, other.emitterIDList, sizeof( emitterIDList ) ); // -- for pack/unpack of emitterList ptrs
|
||||||
|
dMemcpy( debrisList, other.debrisList, sizeof( debrisList ) );
|
||||||
|
dMemcpy( debrisIDList, other.debrisIDList, sizeof( debrisIDList ) ); // -- for pack/unpack of debrisList ptrs
|
||||||
|
debrisThetaMin = other.debrisThetaMin;
|
||||||
|
debrisThetaMax = other.debrisThetaMax;
|
||||||
|
debrisPhiMin = other.debrisPhiMin;
|
||||||
|
debrisPhiMax = other.debrisPhiMax;
|
||||||
|
debrisNum = other.debrisNum;
|
||||||
|
debrisNumVariance = other.debrisNumVariance;
|
||||||
|
debrisVelocity = other.debrisVelocity;
|
||||||
|
debrisVelocityVariance = other.debrisVelocityVariance;
|
||||||
|
dMemcpy( explosionList, other.explosionList, sizeof( explosionList ) );
|
||||||
|
dMemcpy( explosionIDList, other.explosionIDList, sizeof( explosionIDList ) ); // -- for pack/unpack of explosionList ptrs
|
||||||
|
delayMS = other.delayMS;
|
||||||
|
delayVariance = other.delayVariance;
|
||||||
|
lifetimeMS = other.lifetimeMS;
|
||||||
|
lifetimeVariance = other.lifetimeVariance;
|
||||||
|
offset = other.offset;
|
||||||
|
dMemcpy( sizes, other.times, sizeof( sizes ) );
|
||||||
|
dMemcpy( times, other.times, sizeof( times ) );
|
||||||
|
shakeCamera = other.shakeCamera;
|
||||||
|
camShakeFreq = other.camShakeFreq;
|
||||||
|
camShakeAmp = other.camShakeAmp;
|
||||||
|
camShakeDuration = other.camShakeDuration;
|
||||||
|
camShakeRadius = other.camShakeRadius;
|
||||||
|
camShakeFalloff = other.camShakeFalloff;
|
||||||
|
lightStartRadius = other.lightStartRadius;
|
||||||
|
lightEndRadius = other.lightEndRadius;
|
||||||
|
lightStartColor = other.lightStartColor;
|
||||||
|
lightEndColor = other.lightEndColor;
|
||||||
|
lightStartBrightness = other.lightStartBrightness;
|
||||||
|
lightEndBrightness = other.lightEndBrightness;
|
||||||
|
lightNormalOffset = other.lightNormalOffset;
|
||||||
|
// Note - Explosion calls mDataBlock->getName() in warning messages but
|
||||||
|
// that should be safe.
|
||||||
|
}
|
||||||
|
|
||||||
|
ExplosionData::~ExplosionData()
|
||||||
|
{
|
||||||
|
if (!isTempClone())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (soundProfile && soundProfile->isTempClone())
|
||||||
|
{
|
||||||
|
delete soundProfile;
|
||||||
|
soundProfile = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// particleEmitter, emitterList[*], debrisList[*], explosionList[*] will delete themselves
|
||||||
|
|
||||||
|
#ifdef TRACK_EXPLOSION_DATA_CLONES
|
||||||
|
if (explosion_data_clones > 0)
|
||||||
|
{
|
||||||
|
explosion_data_clones--;
|
||||||
|
if (explosion_data_clones == 0)
|
||||||
|
Con::errorf("ExplosionData -- Clones eliminated!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Con::errorf("ExplosionData -- Too many clones deleted!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ExplosionData* ExplosionData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index)
|
||||||
|
{
|
||||||
|
if (!owner || getSubstitutionCount() == 0)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
ExplosionData* sub_explosion_db = new ExplosionData(*this, true);
|
||||||
|
performSubstitutions(sub_explosion_db, owner, index);
|
||||||
|
|
||||||
|
return sub_explosion_db;
|
||||||
|
}
|
||||||
|
|
||||||
void ExplosionData::initPersistFields()
|
void ExplosionData::initPersistFields()
|
||||||
{
|
{
|
||||||
addField( "explosionShape", TypeShapeFilename, Offset(dtsFileName, ExplosionData),
|
addField( "explosionShape", TypeShapeFilename, Offset(dtsFileName, ExplosionData),
|
||||||
|
|
@ -412,6 +518,12 @@ void ExplosionData::initPersistFields()
|
||||||
"Distance (in the explosion normal direction) of the PointLight position "
|
"Distance (in the explosion normal direction) of the PointLight position "
|
||||||
"from the explosion center." );
|
"from the explosion center." );
|
||||||
|
|
||||||
|
// disallow some field substitutions
|
||||||
|
onlyKeepClearSubstitutions("debris"); // subs resolving to "~~", or "~0" are OK
|
||||||
|
onlyKeepClearSubstitutions("emitter");
|
||||||
|
onlyKeepClearSubstitutions("particleEmitter");
|
||||||
|
onlyKeepClearSubstitutions("soundProfile");
|
||||||
|
onlyKeepClearSubstitutions("subExplosion");
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -808,6 +920,10 @@ Explosion::Explosion()
|
||||||
mLight = LIGHTMGR->createLightInfo();
|
mLight = LIGHTMGR->createLightInfo();
|
||||||
|
|
||||||
mNetFlags.set( IsGhost );
|
mNetFlags.set( IsGhost );
|
||||||
|
ss_object = 0;
|
||||||
|
ss_index = 0;
|
||||||
|
mDataBlock = 0;
|
||||||
|
soundProfile_clone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Explosion::~Explosion()
|
Explosion::~Explosion()
|
||||||
|
|
@ -820,6 +936,18 @@ Explosion::~Explosion()
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_DELETE(mLight);
|
SAFE_DELETE(mLight);
|
||||||
|
|
||||||
|
if (soundProfile_clone)
|
||||||
|
{
|
||||||
|
delete soundProfile_clone;
|
||||||
|
soundProfile_clone = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDataBlock && mDataBlock->isTempClone())
|
||||||
|
{
|
||||||
|
delete mDataBlock;
|
||||||
|
mDataBlock = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -978,6 +1106,8 @@ bool Explosion::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||||
if (!mDataBlock || !Parent::onNewDataBlock( dptr, reload ))
|
if (!mDataBlock || !Parent::onNewDataBlock( dptr, reload ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (mDataBlock->isTempClone())
|
||||||
|
return true;
|
||||||
scriptOnNewDataBlock();
|
scriptOnNewDataBlock();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1190,7 +1320,8 @@ void Explosion::launchDebris( Point3F &axis )
|
||||||
launchDir *= debrisVel;
|
launchDir *= debrisVel;
|
||||||
|
|
||||||
Debris *debris = new Debris;
|
Debris *debris = new Debris;
|
||||||
debris->setDataBlock( mDataBlock->debrisList[0] );
|
debris->setSubstitutionData(ss_object, ss_index);
|
||||||
|
debris->setDataBlock(mDataBlock->debrisList[0]->cloneAndPerformSubstitutions(ss_object, ss_index));
|
||||||
debris->setTransform( getTransform() );
|
debris->setTransform( getTransform() );
|
||||||
debris->init( pos, launchDir );
|
debris->init( pos, launchDir );
|
||||||
|
|
||||||
|
|
@ -1218,7 +1349,8 @@ void Explosion::spawnSubExplosions()
|
||||||
{
|
{
|
||||||
MatrixF trans = getTransform();
|
MatrixF trans = getTransform();
|
||||||
Explosion* pExplosion = new Explosion;
|
Explosion* pExplosion = new Explosion;
|
||||||
pExplosion->setDataBlock( mDataBlock->explosionList[i] );
|
pExplosion->setSubstitutionData(ss_object, ss_index);
|
||||||
|
pExplosion->setDataBlock(mDataBlock->explosionList[i]->cloneAndPerformSubstitutions(ss_object, ss_index));
|
||||||
pExplosion->setTransform( trans );
|
pExplosion->setTransform( trans );
|
||||||
pExplosion->setInitialState( trans.getPosition(), mInitialNormal, 1);
|
pExplosion->setInitialState( trans.getPosition(), mInitialNormal, 1);
|
||||||
if (!pExplosion->registerObject())
|
if (!pExplosion->registerObject())
|
||||||
|
|
@ -1256,12 +1388,18 @@ bool Explosion::explode()
|
||||||
resetWorldBox();
|
resetWorldBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDataBlock->soundProfile)
|
SFXProfile* sound_prof = dynamic_cast<SFXProfile*>(mDataBlock->soundProfile);
|
||||||
SFX->playOnce( mDataBlock->soundProfile, &getTransform() );
|
if (sound_prof)
|
||||||
|
{
|
||||||
|
soundProfile_clone = sound_prof->cloneAndPerformSubstitutions(ss_object, ss_index);
|
||||||
|
SFX->playOnce( soundProfile_clone, &getTransform() );
|
||||||
|
if (!soundProfile_clone->isTempClone())
|
||||||
|
soundProfile_clone = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (mDataBlock->particleEmitter) {
|
if (mDataBlock->particleEmitter) {
|
||||||
mMainEmitter = new ParticleEmitter;
|
mMainEmitter = new ParticleEmitter;
|
||||||
mMainEmitter->setDataBlock(mDataBlock->particleEmitter);
|
mMainEmitter->setDataBlock(mDataBlock->particleEmitter->cloneAndPerformSubstitutions(ss_object, ss_index));
|
||||||
mMainEmitter->registerObject();
|
mMainEmitter->registerObject();
|
||||||
|
|
||||||
mMainEmitter->emitParticles(getPosition(), mInitialNormal, mDataBlock->particleRadius,
|
mMainEmitter->emitParticles(getPosition(), mInitialNormal, mDataBlock->particleRadius,
|
||||||
|
|
@ -1273,7 +1411,7 @@ bool Explosion::explode()
|
||||||
if( mDataBlock->emitterList[i] != NULL )
|
if( mDataBlock->emitterList[i] != NULL )
|
||||||
{
|
{
|
||||||
ParticleEmitter * pEmitter = new ParticleEmitter;
|
ParticleEmitter * pEmitter = new ParticleEmitter;
|
||||||
pEmitter->setDataBlock( mDataBlock->emitterList[i] );
|
pEmitter->setDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index));
|
||||||
if( !pEmitter->registerObject() )
|
if( !pEmitter->registerObject() )
|
||||||
{
|
{
|
||||||
Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
|
Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _EXPLOSION_H_
|
#ifndef _EXPLOSION_H_
|
||||||
#define _EXPLOSION_H_
|
#define _EXPLOSION_H_
|
||||||
|
|
||||||
|
|
@ -42,6 +47,7 @@ class TSThread;
|
||||||
class SFXTrack;
|
class SFXTrack;
|
||||||
struct DebrisData;
|
struct DebrisData;
|
||||||
|
|
||||||
|
class SFXProfile;
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
class ExplosionData : public GameBaseData {
|
class ExplosionData : public GameBaseData {
|
||||||
public:
|
public:
|
||||||
|
|
@ -126,6 +132,11 @@ class ExplosionData : public GameBaseData {
|
||||||
static void initPersistFields();
|
static void initPersistFields();
|
||||||
virtual void packData(BitStream* stream);
|
virtual void packData(BitStream* stream);
|
||||||
virtual void unpackData(BitStream* stream);
|
virtual void unpackData(BitStream* stream);
|
||||||
|
public:
|
||||||
|
/*C*/ ExplosionData(const ExplosionData&, bool = false);
|
||||||
|
/*D*/ ~ExplosionData();
|
||||||
|
ExplosionData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0);
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -188,6 +199,12 @@ class Explosion : public GameBase, public ISceneLight
|
||||||
|
|
||||||
DECLARE_CONOBJECT(Explosion);
|
DECLARE_CONOBJECT(Explosion);
|
||||||
static void initPersistFields();
|
static void initPersistFields();
|
||||||
|
private:
|
||||||
|
SimObject* ss_object;
|
||||||
|
S32 ss_index;
|
||||||
|
SFXProfile* soundProfile_clone;
|
||||||
|
public:
|
||||||
|
void setSubstitutionData(SimObject* obj, S32 idx=0) { ss_object = obj; ss_index = idx; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _H_EXPLOSION
|
#endif // _H_EXPLOSION
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,11 @@
|
||||||
// POTENTIAL TODO LIST:
|
// POTENTIAL TODO LIST:
|
||||||
// TODO: Clamp item alpha to fog alpha
|
// TODO: Clamp item alpha to fog alpha
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/fx/fxFoliageReplicator.h"
|
#include "T3D/fx/fxFoliageReplicator.h"
|
||||||
|
|
||||||
|
|
@ -402,6 +407,9 @@ void fxFoliageReplicator::initPersistFields()
|
||||||
addField( "AllowedTerrainSlope", TypeS32, Offset( mFieldData.mAllowedTerrainSlope, fxFoliageReplicator ), "Maximum surface angle allowed for foliage instances." );
|
addField( "AllowedTerrainSlope", TypeS32, Offset( mFieldData.mAllowedTerrainSlope, fxFoliageReplicator ), "Maximum surface angle allowed for foliage instances." );
|
||||||
endGroup( "Restrictions" ); // MM: Added Group Footer.
|
endGroup( "Restrictions" ); // MM: Added Group Footer.
|
||||||
|
|
||||||
|
addGroup( "AFX" );
|
||||||
|
addField( "AmbientModulationBias", TypeF32, Offset( mFieldData.mAmbientModulationBias,fxFoliageReplicator ), "Multiplier controling amount foliage is modulated by sun's ambient." );
|
||||||
|
endGroup( "AFX" );
|
||||||
// Initialise parents' persistent fields.
|
// Initialise parents' persistent fields.
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
@ -1564,7 +1572,12 @@ void fxFoliageReplicator::renderObject(ObjectRenderInst *ri, SceneRenderState *s
|
||||||
mFoliageShaderConsts->setSafe(mFoliageShaderGroundAlphaSC, Point4F(mFieldData.mGroundAlpha, mFieldData.mGroundAlpha, mFieldData.mGroundAlpha, mFieldData.mGroundAlpha));
|
mFoliageShaderConsts->setSafe(mFoliageShaderGroundAlphaSC, Point4F(mFieldData.mGroundAlpha, mFieldData.mGroundAlpha, mFieldData.mGroundAlpha, mFieldData.mGroundAlpha));
|
||||||
|
|
||||||
if (mFoliageShaderAmbientColorSC->isValid())
|
if (mFoliageShaderAmbientColorSC->isValid())
|
||||||
mFoliageShaderConsts->set(mFoliageShaderAmbientColorSC, state->getAmbientLightColor());
|
{
|
||||||
|
LinearColorF ambient = state->getAmbientLightColor();
|
||||||
|
LinearColorF ambient_inv(1.0f-ambient.red, 1.0f-ambient.green, 1.0f-ambient.blue, 0.0f);
|
||||||
|
ambient += ambient_inv*(1.0f - mFieldData.mAmbientModulationBias);
|
||||||
|
mFoliageShaderConsts->set(mFoliageShaderAmbientColorSC, ambient);
|
||||||
|
}
|
||||||
|
|
||||||
GFX->setShaderConstBuffer(mFoliageShaderConsts);
|
GFX->setShaderConstBuffer(mFoliageShaderConsts);
|
||||||
|
|
||||||
|
|
@ -1705,6 +1718,7 @@ U32 fxFoliageReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * s
|
||||||
stream->writeFlag(mFieldData.mShowPlacementArea); // Show Placement Area Flag.
|
stream->writeFlag(mFieldData.mShowPlacementArea); // Show Placement Area Flag.
|
||||||
stream->write(mFieldData.mPlacementBandHeight); // Placement Area Height.
|
stream->write(mFieldData.mPlacementBandHeight); // Placement Area Height.
|
||||||
stream->write(mFieldData.mPlaceAreaColour); // Placement Area Colour.
|
stream->write(mFieldData.mPlaceAreaColour); // Placement Area Colour.
|
||||||
|
stream->write(mFieldData.mAmbientModulationBias);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Were done ...
|
// Were done ...
|
||||||
|
|
@ -1782,6 +1796,7 @@ void fxFoliageReplicator::unpackUpdate(NetConnection * con, BitStream * stream)
|
||||||
stream->read(&mFieldData.mPlacementBandHeight); // Placement Area Height.
|
stream->read(&mFieldData.mPlacementBandHeight); // Placement Area Height.
|
||||||
stream->read(&mFieldData.mPlaceAreaColour);
|
stream->read(&mFieldData.mPlaceAreaColour);
|
||||||
|
|
||||||
|
stream->read(&mFieldData.mAmbientModulationBias);
|
||||||
// Calculate Fade-In/Out Gradients.
|
// Calculate Fade-In/Out Gradients.
|
||||||
mFadeInGradient = 1.0f / mFieldData.mFadeInRegion;
|
mFadeInGradient = 1.0f / mFieldData.mFadeInRegion;
|
||||||
mFadeOutGradient = 1.0f / mFieldData.mFadeOutRegion;
|
mFadeOutGradient = 1.0f / mFieldData.mFadeOutRegion;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _FOLIAGEREPLICATOR_H_
|
#ifndef _FOLIAGEREPLICATOR_H_
|
||||||
#define _FOLIAGEREPLICATOR_H_
|
#define _FOLIAGEREPLICATOR_H_
|
||||||
|
|
||||||
|
|
@ -319,6 +324,7 @@ public:
|
||||||
U32 mPlacementBandHeight;
|
U32 mPlacementBandHeight;
|
||||||
LinearColorF mPlaceAreaColour;
|
LinearColorF mPlaceAreaColour;
|
||||||
|
|
||||||
|
F32 mAmbientModulationBias;
|
||||||
tagFieldData()
|
tagFieldData()
|
||||||
{
|
{
|
||||||
// Set Defaults.
|
// Set Defaults.
|
||||||
|
|
@ -377,6 +383,7 @@ public:
|
||||||
mShowPlacementArea = true;
|
mShowPlacementArea = true;
|
||||||
mPlacementBandHeight = 25;
|
mPlacementBandHeight = 25;
|
||||||
mPlaceAreaColour .set(0.4f, 0, 0.8f);
|
mPlaceAreaColour .set(0.4f, 0, 0.8f);
|
||||||
|
mAmbientModulationBias = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
} mFieldData;
|
} mFieldData;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,12 @@
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "particle.h"
|
#include "particle.h"
|
||||||
#include "console/consoleTypes.h"
|
#include "console/consoleTypes.h"
|
||||||
#include "console/typeValidators.h"
|
#include "console/typeValidators.h"
|
||||||
|
|
@ -72,6 +78,8 @@ static const F32 sgDefaultSpinSpeed = 1.f;
|
||||||
static const F32 sgDefaultSpinRandomMin = 0.f;
|
static const F32 sgDefaultSpinRandomMin = 0.f;
|
||||||
static const F32 sgDefaultSpinRandomMax = 0.f;
|
static const F32 sgDefaultSpinRandomMax = 0.f;
|
||||||
|
|
||||||
|
static const F32 sgDefaultSpinBias = 1.0f;
|
||||||
|
static const F32 sgDefaultSizeBias = 1.0f;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Constructor
|
// Constructor
|
||||||
|
|
@ -102,9 +110,9 @@ ParticleData::ParticleData()
|
||||||
}
|
}
|
||||||
|
|
||||||
times[0] = 0.0f;
|
times[0] = 0.0f;
|
||||||
times[1] = 0.33f;
|
times[1] = 1.0f;
|
||||||
times[2] = 0.66f;
|
for (i = 2; i < PDC_NUM_KEYS; i++)
|
||||||
times[3] = 1.0f;
|
times[i] = -1.0f;
|
||||||
|
|
||||||
texCoords[0].set(0.0,0.0); // texture coords at 4 corners
|
texCoords[0].set(0.0,0.0); // texture coords at 4 corners
|
||||||
texCoords[1].set(0.0,1.0); // of particle quad
|
texCoords[1].set(0.0,1.0); // of particle quad
|
||||||
|
|
@ -115,18 +123,20 @@ ParticleData::ParticleData()
|
||||||
animTexUVs = NULL; // array of tile vertex UVs
|
animTexUVs = NULL; // array of tile vertex UVs
|
||||||
textureName = NULL; // texture filename
|
textureName = NULL; // texture filename
|
||||||
textureHandle = NULL; // loaded texture handle
|
textureHandle = NULL; // loaded texture handle
|
||||||
|
textureExtName = NULL;
|
||||||
|
textureExtHandle = NULL;
|
||||||
|
constrain_pos = false;
|
||||||
|
start_angle = 0.0f;
|
||||||
|
angle_variance = 0.0f;
|
||||||
|
sizeBias = sgDefaultSizeBias;
|
||||||
|
spinBias = sgDefaultSpinBias;
|
||||||
|
randomizeSpinDir = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Destructor
|
// Destructor
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
ParticleData::~ParticleData()
|
|
||||||
{
|
|
||||||
if (animTexUVs)
|
|
||||||
{
|
|
||||||
delete [] animTexUVs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FRangeValidator dragCoefFValidator(0.f, 5.f);
|
FRangeValidator dragCoefFValidator(0.f, 5.f);
|
||||||
FRangeValidator gravCoefFValidator(-10.f, 10.f);
|
FRangeValidator gravCoefFValidator(-10.f, 10.f);
|
||||||
|
|
@ -214,6 +224,15 @@ void ParticleData::initPersistFields()
|
||||||
"@brief Time keys used with the colors and sizes keyframes.\n\n"
|
"@brief Time keys used with the colors and sizes keyframes.\n\n"
|
||||||
"Values are from 0.0 (particle creation) to 1.0 (end of lifespace)." );
|
"Values are from 0.0 (particle creation) to 1.0 (end of lifespace)." );
|
||||||
|
|
||||||
|
addGroup("AFX");
|
||||||
|
addField("textureExtName", TypeFilename, Offset(textureExtName, ParticleData));
|
||||||
|
addField("constrainPos", TypeBool, Offset(constrain_pos, ParticleData));
|
||||||
|
addField("angle", TypeF32, Offset(start_angle, ParticleData));
|
||||||
|
addField("angleVariance", TypeF32, Offset(angle_variance, ParticleData));
|
||||||
|
addField("sizeBias", TypeF32, Offset(sizeBias, ParticleData));
|
||||||
|
addField("spinBias", TypeF32, Offset(spinBias, ParticleData));
|
||||||
|
addField("randomizeSpinDir", TypeBool, Offset(randomizeSpinDir, ParticleData));
|
||||||
|
endGroup("AFX");
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,18 +262,22 @@ void ParticleData::packData(BitStream* stream)
|
||||||
stream->writeInt((S32)(spinRandomMin + 1000), 11);
|
stream->writeInt((S32)(spinRandomMin + 1000), 11);
|
||||||
stream->writeInt((S32)(spinRandomMax + 1000), 11);
|
stream->writeInt((S32)(spinRandomMax + 1000), 11);
|
||||||
}
|
}
|
||||||
|
if(stream->writeFlag(spinBias != sgDefaultSpinBias))
|
||||||
|
stream->write(spinBias);
|
||||||
|
stream->writeFlag(randomizeSpinDir);
|
||||||
stream->writeFlag(useInvAlpha);
|
stream->writeFlag(useInvAlpha);
|
||||||
|
|
||||||
S32 i, count;
|
S32 i, count;
|
||||||
|
|
||||||
// see how many frames there are:
|
// see how many frames there are:
|
||||||
for(count = 0; count < 3; count++)
|
for(count = 0; count < ParticleData::PDC_NUM_KEYS-1; count++)
|
||||||
if(times[count] >= 1)
|
if(times[count] >= 1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
stream->writeInt(count-1, 2);
|
// An extra bit is needed for 8 keys.
|
||||||
|
stream->writeInt(count-1, 3);
|
||||||
|
|
||||||
for( i=0; i<count; i++ )
|
for( i=0; i<count; i++ )
|
||||||
{
|
{
|
||||||
|
|
@ -262,7 +285,8 @@ void ParticleData::packData(BitStream* stream)
|
||||||
stream->writeFloat( colors[i].green, 7);
|
stream->writeFloat( colors[i].green, 7);
|
||||||
stream->writeFloat( colors[i].blue, 7);
|
stream->writeFloat( colors[i].blue, 7);
|
||||||
stream->writeFloat( colors[i].alpha, 7);
|
stream->writeFloat( colors[i].alpha, 7);
|
||||||
stream->writeFloat( sizes[i]/MaxParticleSize, 14);
|
// AFX bits raised from 14 to 16 to allow larger sizes
|
||||||
|
stream->writeFloat( sizes[i]/MaxParticleSize, 16);
|
||||||
stream->writeFloat( times[i], 8);
|
stream->writeFloat( times[i], 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,6 +303,13 @@ void ParticleData::packData(BitStream* stream)
|
||||||
mathWrite(*stream, animTexTiling);
|
mathWrite(*stream, animTexTiling);
|
||||||
stream->writeInt(framesPerSec, 8);
|
stream->writeInt(framesPerSec, 8);
|
||||||
}
|
}
|
||||||
|
if (stream->writeFlag(textureExtName && textureExtName[0]))
|
||||||
|
stream->writeString(textureExtName);
|
||||||
|
stream->writeFlag(constrain_pos);
|
||||||
|
stream->writeFloat(start_angle/360.0f, 11);
|
||||||
|
stream->writeFloat(angle_variance/180.0f, 10);
|
||||||
|
if(stream->writeFlag(sizeBias != sgDefaultSizeBias))
|
||||||
|
stream->write(sizeBias);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -322,17 +353,24 @@ void ParticleData::unpackData(BitStream* stream)
|
||||||
spinRandomMax = sgDefaultSpinRandomMax;
|
spinRandomMax = sgDefaultSpinRandomMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(stream->readFlag())
|
||||||
|
stream->read(&spinBias);
|
||||||
|
else
|
||||||
|
spinBias = sgDefaultSpinBias;
|
||||||
|
randomizeSpinDir = stream->readFlag();
|
||||||
useInvAlpha = stream->readFlag();
|
useInvAlpha = stream->readFlag();
|
||||||
|
|
||||||
S32 i;
|
S32 i;
|
||||||
S32 count = stream->readInt(2) + 1;
|
// An extra bit is needed for 8 keys.
|
||||||
|
S32 count = stream->readInt(3) + 1;
|
||||||
for(i = 0;i < count; i++)
|
for(i = 0;i < count; i++)
|
||||||
{
|
{
|
||||||
colors[i].red = stream->readFloat(7);
|
colors[i].red = stream->readFloat(7);
|
||||||
colors[i].green = stream->readFloat(7);
|
colors[i].green = stream->readFloat(7);
|
||||||
colors[i].blue = stream->readFloat(7);
|
colors[i].blue = stream->readFloat(7);
|
||||||
colors[i].alpha = stream->readFloat(7);
|
colors[i].alpha = stream->readFloat(7);
|
||||||
sizes[i] = stream->readFloat(14) * MaxParticleSize;
|
// AFX bits raised from 14 to 16 to allow larger sizes
|
||||||
|
sizes[i] = stream->readFloat(16) * MaxParticleSize;
|
||||||
times[i] = stream->readFloat(8);
|
times[i] = stream->readFloat(8);
|
||||||
}
|
}
|
||||||
textureName = (stream->readFlag()) ? stream->readSTString() : 0;
|
textureName = (stream->readFlag()) ? stream->readSTString() : 0;
|
||||||
|
|
@ -346,6 +384,14 @@ void ParticleData::unpackData(BitStream* stream)
|
||||||
mathRead(*stream, &animTexTiling);
|
mathRead(*stream, &animTexTiling);
|
||||||
framesPerSec = stream->readInt(8);
|
framesPerSec = stream->readInt(8);
|
||||||
}
|
}
|
||||||
|
textureExtName = (stream->readFlag()) ? stream->readSTString() : 0;
|
||||||
|
constrain_pos = stream->readFlag();
|
||||||
|
start_angle = 360.0f*stream->readFloat(11);
|
||||||
|
angle_variance = 180.0f*stream->readFloat(10);
|
||||||
|
if(stream->readFlag())
|
||||||
|
stream->read(&sizeBias);
|
||||||
|
else
|
||||||
|
sizeBias = sgDefaultSizeBias;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParticleData::protectedSetSizes( void *object, const char *index, const char *data)
|
bool ParticleData::protectedSetSizes( void *object, const char *index, const char *data)
|
||||||
|
|
@ -427,11 +473,33 @@ bool ParticleData::onAdd()
|
||||||
}
|
}
|
||||||
|
|
||||||
times[0] = 0.0f;
|
times[0] = 0.0f;
|
||||||
for (U32 i = 1; i < 4; i++) {
|
for (U32 i = 1; i < PDC_NUM_KEYS; i++)
|
||||||
if (times[i] < times[i-1]) {
|
{
|
||||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) times[%d] < times[%d]", getName(), i, i-1);
|
if (times[i] < 0.0f)
|
||||||
times[i] = times[i-1];
|
break;
|
||||||
}
|
if (times[i] < times[i-1])
|
||||||
|
{
|
||||||
|
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) times[%d] < times[%d]", getName(), i, i-1);
|
||||||
|
times[i] = times[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
times[0] = 0.0f;
|
||||||
|
|
||||||
|
U32 last_idx = 0;
|
||||||
|
for (U32 i = 1; i < PDC_NUM_KEYS; i++)
|
||||||
|
{
|
||||||
|
if (times[i] < 0.0f)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
last_idx = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (U32 i = last_idx+1; i < PDC_NUM_KEYS; i++)
|
||||||
|
{
|
||||||
|
times[i] = times[last_idx];
|
||||||
|
colors[i] = colors[last_idx];
|
||||||
|
sizes[i] = sizes[last_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we validate parameters
|
// Here we validate parameters
|
||||||
|
|
@ -470,6 +538,10 @@ bool ParticleData::onAdd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_angle = mFmod(start_angle, 360.0f);
|
||||||
|
if (start_angle < 0.0f)
|
||||||
|
start_angle += 360.0f;
|
||||||
|
angle_variance = mClampF(angle_variance, -180.0f, 180.0f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,6 +567,15 @@ bool ParticleData::preload(bool server, String &errorStr)
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (textureExtName && textureExtName[0])
|
||||||
|
{
|
||||||
|
textureExtHandle = GFXTexHandle(textureExtName, &GFXStaticTextureSRGBProfile, avar("%s() - textureExtHandle (line %d)", __FUNCTION__, __LINE__));
|
||||||
|
if (!textureExtHandle)
|
||||||
|
{
|
||||||
|
errorStr = String::ToString("Missing particle texture: %s", textureName);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (animateTexture)
|
if (animateTexture)
|
||||||
{
|
{
|
||||||
|
|
@ -606,6 +687,11 @@ void ParticleData::initializeParticle(Particle* init, const Point3F& inheritVelo
|
||||||
|
|
||||||
// assign spin amount
|
// assign spin amount
|
||||||
init->spinSpeed = spinSpeed * gRandGen.randF( spinRandomMin, spinRandomMax );
|
init->spinSpeed = spinSpeed * gRandGen.randF( spinRandomMin, spinRandomMax );
|
||||||
|
// apply spin bias
|
||||||
|
init->spinSpeed *= spinBias;
|
||||||
|
// randomize spin direction
|
||||||
|
if (randomizeSpinDir && (gRandGen.randI( 0, 1 ) == 1))
|
||||||
|
init->spinSpeed = -init->spinSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParticleData::reload(char errorBuffer[256])
|
bool ParticleData::reload(char errorBuffer[256])
|
||||||
|
|
@ -653,3 +739,78 @@ DefineEngineMethod(ParticleData, reload, void, (),,
|
||||||
char errorBuffer[256];
|
char errorBuffer[256];
|
||||||
object->reload(errorBuffer);
|
object->reload(errorBuffer);
|
||||||
}
|
}
|
||||||
|
//#define TRACK_PARTICLE_DATA_CLONES
|
||||||
|
|
||||||
|
#ifdef TRACK_PARTICLE_DATA_CLONES
|
||||||
|
static int particle_data_clones = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ParticleData::ParticleData(const ParticleData& other, bool temp_clone) : SimDataBlock(other, temp_clone)
|
||||||
|
{
|
||||||
|
#ifdef TRACK_PARTICLE_DATA_CLONES
|
||||||
|
particle_data_clones++;
|
||||||
|
if (particle_data_clones == 1)
|
||||||
|
Con::errorf("ParticleData -- Clones are on the loose!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dragCoefficient = other.dragCoefficient;
|
||||||
|
windCoefficient = other.windCoefficient;
|
||||||
|
gravityCoefficient = other.gravityCoefficient;
|
||||||
|
inheritedVelFactor = other.inheritedVelFactor;
|
||||||
|
constantAcceleration = other.constantAcceleration;
|
||||||
|
lifetimeMS = other.lifetimeMS;
|
||||||
|
lifetimeVarianceMS = other.lifetimeVarianceMS;
|
||||||
|
spinSpeed = other.spinSpeed;
|
||||||
|
spinRandomMin = other.spinRandomMin;
|
||||||
|
spinRandomMax = other.spinRandomMax;
|
||||||
|
useInvAlpha = other.useInvAlpha;
|
||||||
|
animateTexture = other.animateTexture;
|
||||||
|
numFrames = other.numFrames; // -- calc from other fields
|
||||||
|
framesPerSec = other.framesPerSec;
|
||||||
|
dMemcpy( colors, other.colors, sizeof( colors ) );
|
||||||
|
dMemcpy( sizes, other.sizes, sizeof( sizes ) );
|
||||||
|
dMemcpy( times, other.times, sizeof( times ) );
|
||||||
|
animTexUVs = other.animTexUVs; // -- calc from other fields
|
||||||
|
dMemcpy( texCoords, other.texCoords, sizeof( texCoords ) );
|
||||||
|
animTexTiling = other.animTexTiling;
|
||||||
|
animTexFramesString = other.animTexFramesString;
|
||||||
|
animTexFrames = other.animTexFrames; // -- parsed from animTexFramesString
|
||||||
|
textureName = other.textureName;
|
||||||
|
textureHandle = other.textureHandle;
|
||||||
|
spinBias = other.spinBias;
|
||||||
|
randomizeSpinDir = other.randomizeSpinDir;
|
||||||
|
textureExtName = other.textureExtName;
|
||||||
|
textureExtHandle = other.textureExtHandle;
|
||||||
|
constrain_pos = other.constrain_pos;
|
||||||
|
start_angle = other.start_angle;
|
||||||
|
angle_variance = other.angle_variance;
|
||||||
|
sizeBias = other.sizeBias;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleData::~ParticleData()
|
||||||
|
{
|
||||||
|
if (animTexUVs)
|
||||||
|
{
|
||||||
|
delete [] animTexUVs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isTempClone())
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef TRACK_PARTICLE_DATA_CLONES
|
||||||
|
if (particle_data_clones > 0)
|
||||||
|
{
|
||||||
|
particle_data_clones--;
|
||||||
|
if (particle_data_clones == 0)
|
||||||
|
Con::errorf("ParticleData -- Clones eliminated!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Con::errorf("ParticleData -- Too many clones deleted!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParticleData::onPerformSubstitutions()
|
||||||
|
{
|
||||||
|
char errorBuffer[256];
|
||||||
|
reload(errorBuffer);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _PARTICLE_H_
|
#ifndef _PARTICLE_H_
|
||||||
#define _PARTICLE_H_
|
#define _PARTICLE_H_
|
||||||
|
|
||||||
|
|
@ -44,7 +49,9 @@ class ParticleData : public SimDataBlock
|
||||||
public:
|
public:
|
||||||
enum PDConst
|
enum PDConst
|
||||||
{
|
{
|
||||||
PDC_NUM_KEYS = 4,
|
// This increase the keyframes from 4 to 8. Especially useful for premult-alpha blended particles
|
||||||
|
// for which 4 keyframes is often not enough.
|
||||||
|
PDC_NUM_KEYS = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
F32 dragCoefficient;
|
F32 dragCoefficient;
|
||||||
|
|
@ -97,6 +104,23 @@ class ParticleData : public SimDataBlock
|
||||||
static void initPersistFields();
|
static void initPersistFields();
|
||||||
|
|
||||||
bool reload(char errorBuffer[256]);
|
bool reload(char errorBuffer[256]);
|
||||||
|
public:
|
||||||
|
/*C*/ ParticleData(const ParticleData&, bool = false);
|
||||||
|
virtual void onPerformSubstitutions();
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
protected:
|
||||||
|
F32 spinBias;
|
||||||
|
bool randomizeSpinDir;
|
||||||
|
StringTableEntry textureExtName;
|
||||||
|
public:
|
||||||
|
GFXTexHandle textureExtHandle;
|
||||||
|
bool constrain_pos;
|
||||||
|
F32 start_angle;
|
||||||
|
F32 angle_variance;
|
||||||
|
F32 sizeBias;
|
||||||
|
public:
|
||||||
|
bool loadParameters();
|
||||||
|
bool reload(String &errorStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
@ -123,6 +147,10 @@ struct Particle
|
||||||
|
|
||||||
F32 spinSpeed;
|
F32 spinSpeed;
|
||||||
Particle * next;
|
Particle * next;
|
||||||
|
Point3F pos_local;
|
||||||
|
F32 t_last;
|
||||||
|
Point3F radial_v; // radial vector for concentric effects
|
||||||
|
// note -- for non-oriented particles, we use orientDir.x to store the billboard start angle.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/fx/particleEmitter.h"
|
#include "T3D/fx/particleEmitter.h"
|
||||||
|
|
||||||
|
|
@ -38,6 +43,10 @@
|
||||||
#include "lighting/lightInfo.h"
|
#include "lighting/lightInfo.h"
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
#include "afx/util/afxParticlePool.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
Point3F ParticleEmitter::mWindVelocity( 0.0, 0.0, 0.0 );
|
Point3F ParticleEmitter::mWindVelocity( 0.0, 0.0, 0.0 );
|
||||||
const F32 ParticleEmitter::AgedSpinToRadians = (1.0f/1000.0f) * (1.0f/360.0f) * M_PI_F * 2.0f;
|
const F32 ParticleEmitter::AgedSpinToRadians = (1.0f/1000.0f) * (1.0f/360.0f) * M_PI_F * 2.0f;
|
||||||
|
|
||||||
|
|
@ -149,6 +158,21 @@ ParticleEmitterData::ParticleEmitterData()
|
||||||
|
|
||||||
alignParticles = false;
|
alignParticles = false;
|
||||||
alignDirection = Point3F(0.0f, 1.0f, 0.0f);
|
alignDirection = Point3F(0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
|
ejectionInvert = false;
|
||||||
|
fade_color = false;
|
||||||
|
fade_alpha = false;
|
||||||
|
fade_size = false;
|
||||||
|
parts_per_eject = 1;
|
||||||
|
use_emitter_xfm = false;
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
pool_datablock = 0;
|
||||||
|
pool_index = 0;
|
||||||
|
pool_depth_fade = false;
|
||||||
|
pool_radial_fade = false;
|
||||||
|
do_pool_id_convert = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -293,6 +317,26 @@ void ParticleEmitterData::initPersistFields()
|
||||||
|
|
||||||
endGroup( "ParticleEmitterData" );
|
endGroup( "ParticleEmitterData" );
|
||||||
|
|
||||||
|
addGroup("AFX");
|
||||||
|
addField("ejectionInvert", TypeBool, Offset(ejectionInvert, ParticleEmitterData));
|
||||||
|
addField("fadeColor", TypeBool, Offset(fade_color, ParticleEmitterData));
|
||||||
|
addField("fadeAlpha", TypeBool, Offset(fade_alpha, ParticleEmitterData));
|
||||||
|
addField("fadeSize", TypeBool, Offset(fade_size, ParticleEmitterData));
|
||||||
|
// useEmitterTransform currently does not work in TGEA or T3D
|
||||||
|
addField("useEmitterTransform", TypeBool, Offset(use_emitter_xfm, ParticleEmitterData));
|
||||||
|
endGroup("AFX");
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
addGroup("AFX Pooled Particles");
|
||||||
|
addField("poolData", TYPEID<afxParticlePoolData>(), Offset(pool_datablock, ParticleEmitterData));
|
||||||
|
addField("poolIndex", TypeS32, Offset(pool_index, ParticleEmitterData));
|
||||||
|
addField("poolDepthFade", TypeBool, Offset(pool_depth_fade, ParticleEmitterData));
|
||||||
|
addField("poolRadialFade", TypeBool, Offset(pool_radial_fade, ParticleEmitterData));
|
||||||
|
endGroup("AFX Pooled Particles");
|
||||||
|
#endif
|
||||||
|
// disallow some field substitutions
|
||||||
|
disableFieldSubstitutions("particles");
|
||||||
|
onlyKeepClearSubstitutions("poolData"); // subs resolving to "~~", or "~0" are OK
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -358,6 +402,22 @@ void ParticleEmitterData::packData(BitStream* stream)
|
||||||
stream->writeFlag(renderReflection);
|
stream->writeFlag(renderReflection);
|
||||||
stream->writeFlag(glow);
|
stream->writeFlag(glow);
|
||||||
stream->writeInt( blendStyle, 4 );
|
stream->writeInt( blendStyle, 4 );
|
||||||
|
|
||||||
|
stream->writeFlag(ejectionInvert);
|
||||||
|
stream->writeFlag(fade_color);
|
||||||
|
stream->writeFlag(fade_alpha);
|
||||||
|
stream->writeFlag(fade_size);
|
||||||
|
stream->writeFlag(use_emitter_xfm);
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (stream->writeFlag(pool_datablock))
|
||||||
|
{
|
||||||
|
stream->writeRangedU32(packed ? SimObjectId((uintptr_t)pool_datablock) : pool_datablock->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
stream->write(pool_index);
|
||||||
|
stream->writeFlag(pool_depth_fade);
|
||||||
|
stream->writeFlag(pool_radial_fade);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -421,6 +481,22 @@ void ParticleEmitterData::unpackData(BitStream* stream)
|
||||||
renderReflection = stream->readFlag();
|
renderReflection = stream->readFlag();
|
||||||
glow = stream->readFlag();
|
glow = stream->readFlag();
|
||||||
blendStyle = stream->readInt( 4 );
|
blendStyle = stream->readInt( 4 );
|
||||||
|
ejectionInvert = stream->readFlag();
|
||||||
|
fade_color = stream->readFlag();
|
||||||
|
fade_alpha = stream->readFlag();
|
||||||
|
fade_size = stream->readFlag();
|
||||||
|
use_emitter_xfm = stream->readFlag();
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (stream->readFlag())
|
||||||
|
{
|
||||||
|
pool_datablock = (afxParticlePoolData*)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
stream->read(&pool_index);
|
||||||
|
pool_depth_fade = stream->readFlag();
|
||||||
|
pool_radial_fade = stream->readFlag();
|
||||||
|
do_pool_id_convert = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -600,6 +676,22 @@ bool ParticleEmitterData::preload(bool server, String &errorStr)
|
||||||
|
|
||||||
if (!server)
|
if (!server)
|
||||||
{
|
{
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (do_pool_id_convert)
|
||||||
|
{
|
||||||
|
SimObjectId db_id = (SimObjectId)(uintptr_t)pool_datablock;
|
||||||
|
if (db_id != 0)
|
||||||
|
{
|
||||||
|
// try to convert id to pointer
|
||||||
|
if (!Sim::findObject(db_id, pool_datablock))
|
||||||
|
{
|
||||||
|
Con::errorf("ParticleEmitterData::reload() -- bad datablockId: 0x%x (poolData)", db_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_pool_id_convert = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// load emitter texture if specified
|
// load emitter texture if specified
|
||||||
if (textureName && textureName[0])
|
if (textureName && textureName[0])
|
||||||
{
|
{
|
||||||
|
|
@ -669,6 +761,8 @@ void ParticleEmitterData::allocPrimBuffer( S32 overrideSize )
|
||||||
|
|
||||||
partListInitSize = maxPartLife / (ejectionPeriodMS - periodVarianceMS);
|
partListInitSize = maxPartLife / (ejectionPeriodMS - periodVarianceMS);
|
||||||
partListInitSize += 8; // add 8 as "fudge factor" to make sure it doesn't realloc if it goes over by 1
|
partListInitSize += 8; // add 8 as "fudge factor" to make sure it doesn't realloc if it goes over by 1
|
||||||
|
if (parts_per_eject > 1)
|
||||||
|
partListInitSize *= parts_per_eject;
|
||||||
|
|
||||||
// if override size is specified, then the emitter overran its buffer and needs a larger allocation
|
// if override size is specified, then the emitter overran its buffer and needs a larger allocation
|
||||||
if( overrideSize != -1 )
|
if( overrideSize != -1 )
|
||||||
|
|
@ -705,6 +799,134 @@ void ParticleEmitterData::allocPrimBuffer( S32 overrideSize )
|
||||||
delete [] indices;
|
delete [] indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#define TRACK_PARTICLE_EMITTER_DATA_CLONES
|
||||||
|
|
||||||
|
#ifdef TRACK_PARTICLE_EMITTER_DATA_CLONES
|
||||||
|
static int emitter_data_clones = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ParticleEmitterData::ParticleEmitterData(const ParticleEmitterData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
#ifdef TRACK_PARTICLE_EMITTER_DATA_CLONES
|
||||||
|
emitter_data_clones++;
|
||||||
|
if (emitter_data_clones == 1)
|
||||||
|
Con::errorf("ParticleEmitterData -- Clones are on the loose!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ejectionPeriodMS = other.ejectionPeriodMS;
|
||||||
|
periodVarianceMS = other.periodVarianceMS;
|
||||||
|
ejectionVelocity = other.ejectionVelocity;
|
||||||
|
velocityVariance = other.velocityVariance;
|
||||||
|
ejectionOffset = other.ejectionOffset;
|
||||||
|
ejectionOffsetVariance = other.ejectionOffsetVariance;
|
||||||
|
thetaMin = other.thetaMin;
|
||||||
|
thetaMax = other.thetaMax;
|
||||||
|
phiReferenceVel = other.phiReferenceVel;
|
||||||
|
phiVariance = other.phiVariance;
|
||||||
|
softnessDistance = other.softnessDistance;
|
||||||
|
ambientFactor = other.ambientFactor;
|
||||||
|
lifetimeMS = other.lifetimeMS;
|
||||||
|
lifetimeVarianceMS = other.lifetimeVarianceMS;
|
||||||
|
overrideAdvance = other.overrideAdvance;
|
||||||
|
orientParticles = other.orientParticles;
|
||||||
|
orientOnVelocity = other.orientOnVelocity;
|
||||||
|
useEmitterSizes = other.useEmitterSizes;
|
||||||
|
useEmitterColors = other.useEmitterColors;
|
||||||
|
alignParticles = other.alignParticles;
|
||||||
|
alignDirection = other.alignDirection;
|
||||||
|
particleString = other.particleString;
|
||||||
|
particleDataBlocks = other.particleDataBlocks; // -- derived from particleString
|
||||||
|
dataBlockIds = other.dataBlockIds; // -- derived from particleString
|
||||||
|
partListInitSize = other.partListInitSize; // -- approx calc from other fields
|
||||||
|
primBuff = other.primBuff;
|
||||||
|
blendStyle = other.blendStyle;
|
||||||
|
sortParticles = other.sortParticles;
|
||||||
|
reverseOrder = other.reverseOrder;
|
||||||
|
textureName = other.textureName;
|
||||||
|
textureHandle = other.textureHandle; // -- TextureHandle loads using textureName
|
||||||
|
highResOnly = other.highResOnly;
|
||||||
|
renderReflection = other.renderReflection;
|
||||||
|
fade_color = other.fade_color;
|
||||||
|
fade_size = other.fade_size;
|
||||||
|
fade_alpha = other.fade_alpha;
|
||||||
|
ejectionInvert = other.ejectionInvert;
|
||||||
|
parts_per_eject = other.parts_per_eject; // -- set to 1 (used by subclasses)
|
||||||
|
use_emitter_xfm = other.use_emitter_xfm;
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
pool_datablock = other.pool_datablock;
|
||||||
|
pool_index = other.pool_index;
|
||||||
|
pool_depth_fade = other.pool_depth_fade;
|
||||||
|
pool_radial_fade = other.pool_radial_fade;
|
||||||
|
do_pool_id_convert = other.do_pool_id_convert; // -- flags pool id conversion need
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleEmitterData::~ParticleEmitterData()
|
||||||
|
{
|
||||||
|
if (!isTempClone())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (S32 i = 0; i < particleDataBlocks.size(); i++)
|
||||||
|
{
|
||||||
|
if (particleDataBlocks[i] && particleDataBlocks[i]->isTempClone())
|
||||||
|
{
|
||||||
|
delete particleDataBlocks[i];
|
||||||
|
particleDataBlocks[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRACK_PARTICLE_EMITTER_DATA_CLONES
|
||||||
|
if (emitter_data_clones > 0)
|
||||||
|
{
|
||||||
|
emitter_data_clones--;
|
||||||
|
if (emitter_data_clones == 0)
|
||||||
|
Con::errorf("ParticleEmitterData -- Clones eliminated!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Con::errorf("ParticleEmitterData -- Too many clones deleted!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleEmitterData* ParticleEmitterData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index)
|
||||||
|
{
|
||||||
|
if (!owner)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
bool clone_parts_db = false;
|
||||||
|
|
||||||
|
// note -- this could be checked when the particle blocks are evaluated
|
||||||
|
for (S32 i = 0; i < this->particleDataBlocks.size(); i++)
|
||||||
|
{
|
||||||
|
if (this->particleDataBlocks[i] && (this->particleDataBlocks[i]->getSubstitutionCount() > 0))
|
||||||
|
{
|
||||||
|
clone_parts_db = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleEmitterData* sub_emitter_db = this;
|
||||||
|
|
||||||
|
if (this->getSubstitutionCount() > 0 || clone_parts_db)
|
||||||
|
{
|
||||||
|
sub_emitter_db = new ParticleEmitterData(*this, true);
|
||||||
|
performSubstitutions(sub_emitter_db, owner, index);
|
||||||
|
|
||||||
|
if (clone_parts_db)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < sub_emitter_db->particleDataBlocks.size(); i++)
|
||||||
|
{
|
||||||
|
if (sub_emitter_db->particleDataBlocks[i] && (sub_emitter_db->particleDataBlocks[i]->getSubstitutionCount() > 0))
|
||||||
|
{
|
||||||
|
ParticleData* orig_db = sub_emitter_db->particleDataBlocks[i];
|
||||||
|
sub_emitter_db->particleDataBlocks[i] = new ParticleData(*orig_db, true);
|
||||||
|
orig_db->performSubstitutions(sub_emitter_db->particleDataBlocks[i], owner, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sub_emitter_db;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// ParticleEmitter
|
// ParticleEmitter
|
||||||
|
|
@ -736,6 +958,16 @@ ParticleEmitter::ParticleEmitter()
|
||||||
|
|
||||||
// ParticleEmitter should be allocated on the client only.
|
// ParticleEmitter should be allocated on the client only.
|
||||||
mNetFlags.set( IsGhost );
|
mNetFlags.set( IsGhost );
|
||||||
|
fade_amt = 1.0f;
|
||||||
|
forced_bbox = false;
|
||||||
|
db_temp_clone = false;
|
||||||
|
pos_pe.set(0,0,0);
|
||||||
|
sort_priority = 0;
|
||||||
|
mDataBlock = 0;
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
pool = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -747,6 +979,19 @@ ParticleEmitter::~ParticleEmitter()
|
||||||
{
|
{
|
||||||
delete [] part_store[i];
|
delete [] part_store[i];
|
||||||
}
|
}
|
||||||
|
if (db_temp_clone && mDataBlock && mDataBlock->isTempClone())
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < mDataBlock->particleDataBlocks.size(); i++)
|
||||||
|
{
|
||||||
|
if (mDataBlock->particleDataBlocks[i] && mDataBlock->particleDataBlocks[i]->isTempClone())
|
||||||
|
{
|
||||||
|
delete mDataBlock->particleDataBlocks[i];
|
||||||
|
mDataBlock->particleDataBlocks[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete mDataBlock;
|
||||||
|
mDataBlock = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -771,6 +1016,11 @@ bool ParticleEmitter::onAdd()
|
||||||
mObjBox.maxExtents = Point3F(radius, radius, radius);
|
mObjBox.maxExtents = Point3F(radius, radius, radius);
|
||||||
resetWorldBox();
|
resetWorldBox();
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
pool->addParticleEmitter(this);
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -780,6 +1030,14 @@ bool ParticleEmitter::onAdd()
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::onRemove()
|
void ParticleEmitter::onRemove()
|
||||||
{
|
{
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
{
|
||||||
|
pool->removeParticleEmitter(this);
|
||||||
|
pool = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
removeFromScene();
|
removeFromScene();
|
||||||
Parent::onRemove();
|
Parent::onRemove();
|
||||||
}
|
}
|
||||||
|
|
@ -825,6 +1083,11 @@ bool ParticleEmitter::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||||
part_list_head.next = NULL;
|
part_list_head.next = NULL;
|
||||||
n_parts = 0;
|
n_parts = 0;
|
||||||
}
|
}
|
||||||
|
if (mDataBlock->isTempClone())
|
||||||
|
{
|
||||||
|
db_temp_clone = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
scriptOnNewDataBlock();
|
scriptOnNewDataBlock();
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -861,6 +1124,11 @@ LinearColorF ParticleEmitter::getCollectiveColor()
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
||||||
{
|
{
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if( state->isReflectPass() && !getDataBlock()->renderReflection )
|
if( state->isReflectPass() && !getDataBlock()->renderReflection )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -889,6 +1157,7 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
||||||
ri->translucentSort = true;
|
ri->translucentSort = true;
|
||||||
ri->type = RenderPassManager::RIT_Particle;
|
ri->type = RenderPassManager::RIT_Particle;
|
||||||
ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint( camPos );
|
ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint( camPos );
|
||||||
|
ri->defaultKey = (-sort_priority*100);
|
||||||
|
|
||||||
// Draw the system offscreen unless the highResOnly flag is set on the datablock
|
// Draw the system offscreen unless the highResOnly flag is set on the datablock
|
||||||
ri->systemState = ( getDataBlock()->highResOnly ? PSS_AwaitingHighResDraw : PSS_AwaitingOffscreenDraw );
|
ri->systemState = ( getDataBlock()->highResOnly ? PSS_AwaitingHighResDraw : PSS_AwaitingOffscreenDraw );
|
||||||
|
|
@ -992,6 +1261,7 @@ void ParticleEmitter::emitParticles(const Point3F& point,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos_pe = point;
|
||||||
Point3F realStart;
|
Point3F realStart;
|
||||||
if( useLastPosition && mHasLastPosition )
|
if( useLastPosition && mHasLastPosition )
|
||||||
realStart = mLastPosition;
|
realStart = mLastPosition;
|
||||||
|
|
@ -1059,7 +1329,8 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
||||||
// Create particle at the correct position
|
// Create particle at the correct position
|
||||||
Point3F pos;
|
Point3F pos;
|
||||||
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
||||||
addParticle(pos, axis, velocity, axisx);
|
addParticle(pos, axis, velocity, axisx, numMilliseconds-currTime);
|
||||||
|
|
||||||
particlesAdded = true;
|
particlesAdded = true;
|
||||||
mNextParticleTime = 0;
|
mNextParticleTime = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1089,7 +1360,7 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
||||||
// Create particle at the correct position
|
// Create particle at the correct position
|
||||||
Point3F pos;
|
Point3F pos;
|
||||||
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
||||||
addParticle(pos, axis, velocity, axisx);
|
addParticle(pos, axis, velocity, axisx, numMilliseconds-currTime);
|
||||||
particlesAdded = true;
|
particlesAdded = true;
|
||||||
|
|
||||||
// This override-advance code is restored in order to correctly adjust
|
// This override-advance code is restored in order to correctly adjust
|
||||||
|
|
@ -1114,17 +1385,27 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
||||||
{
|
{
|
||||||
if (advanceMS != 0)
|
if (advanceMS != 0)
|
||||||
{
|
{
|
||||||
F32 t = F32(advanceMS) / 1000.0;
|
F32 t = F32(advanceMS) / 1000.0;
|
||||||
|
|
||||||
Point3F a = last_part->acc;
|
Point3F a = last_part->acc;
|
||||||
a -= last_part->vel * last_part->dataBlock->dragCoefficient;
|
a -= last_part->vel * last_part->dataBlock->dragCoefficient;
|
||||||
a -= mWindVelocity * last_part->dataBlock->windCoefficient;
|
a -= mWindVelocity * last_part->dataBlock->windCoefficient;
|
||||||
a += Point3F(0.0f, 0.0f, -9.81f) * last_part->dataBlock->gravityCoefficient;
|
//a += Point3F(0.0f, 0.0f, -9.81f) * last_part->dataBlock->gravityCoefficient;
|
||||||
|
a.z += -9.81f*last_part->dataBlock->gravityCoefficient; // as long as gravity is a constant, this is faster
|
||||||
|
|
||||||
last_part->vel += a * t;
|
last_part->vel += a * t;
|
||||||
last_part->pos += last_part->vel * t;
|
//last_part->pos += last_part->vel * t;
|
||||||
|
last_part->pos_local += last_part->vel * t;
|
||||||
|
|
||||||
updateKeyData( last_part );
|
// AFX -- allow subclasses to adjust the particle params here
|
||||||
|
sub_particleUpdate(last_part);
|
||||||
|
|
||||||
|
if (last_part->dataBlock->constrain_pos)
|
||||||
|
last_part->pos = last_part->pos_local + this->pos_pe;
|
||||||
|
else
|
||||||
|
last_part->pos = last_part->pos_local;
|
||||||
|
|
||||||
|
updateKeyData( last_part );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1196,7 +1477,7 @@ void ParticleEmitter::emitParticles(const Point3F& rCenter,
|
||||||
axis.normalize();
|
axis.normalize();
|
||||||
pos += rCenter;
|
pos += rCenter;
|
||||||
|
|
||||||
addParticle(pos, axis, velocity, axisz);
|
addParticle(pos, axis, velocity, axisz, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set world bounding box
|
// Set world bounding box
|
||||||
|
|
@ -1219,6 +1500,8 @@ void ParticleEmitter::emitParticles(const Point3F& rCenter,
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::updateBBox()
|
void ParticleEmitter::updateBBox()
|
||||||
{
|
{
|
||||||
|
if (forced_bbox)
|
||||||
|
return;
|
||||||
Point3F minPt(1e10, 1e10, 1e10);
|
Point3F minPt(1e10, 1e10, 1e10);
|
||||||
Point3F maxPt(-1e10, -1e10, -1e10);
|
Point3F maxPt(-1e10, -1e10, -1e10);
|
||||||
|
|
||||||
|
|
@ -1239,15 +1522,18 @@ void ParticleEmitter::updateBBox()
|
||||||
boxScale.y = getMax(boxScale.y, 1.0f);
|
boxScale.y = getMax(boxScale.y, 1.0f);
|
||||||
boxScale.z = getMax(boxScale.z, 1.0f);
|
boxScale.z = getMax(boxScale.z, 1.0f);
|
||||||
mBBObjToWorld.scale(boxScale);
|
mBBObjToWorld.scale(boxScale);
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
pool->updatePoolBBox(this);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// addParticle
|
// addParticle
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::addParticle(const Point3F& pos,
|
void ParticleEmitter::addParticle(const Point3F& pos, const Point3F& axis, const Point3F& vel,
|
||||||
const Point3F& axis,
|
const Point3F& axisx, const U32 age_offset)
|
||||||
const Point3F& vel,
|
|
||||||
const Point3F& axisx)
|
|
||||||
{
|
{
|
||||||
n_parts++;
|
n_parts++;
|
||||||
if (n_parts > n_part_capacity || n_parts > mDataBlock->partListInitSize)
|
if (n_parts > n_part_capacity || n_parts > mDataBlock->partListInitSize)
|
||||||
|
|
@ -1269,6 +1555,16 @@ void ParticleEmitter::addParticle(const Point3F& pos,
|
||||||
pNew->next = part_list_head.next;
|
pNew->next = part_list_head.next;
|
||||||
part_list_head.next = pNew;
|
part_list_head.next = pNew;
|
||||||
|
|
||||||
|
// for earlier access to constrain_pos, the ParticleData datablock is chosen here instead
|
||||||
|
// of later in the method.
|
||||||
|
U32 dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size();
|
||||||
|
ParticleData* part_db = mDataBlock->particleDataBlocks[dBlockIndex];
|
||||||
|
// set start position to world or local space
|
||||||
|
Point3F pos_start;
|
||||||
|
if (part_db->constrain_pos)
|
||||||
|
pos_start.set(0,0,0);
|
||||||
|
else
|
||||||
|
pos_start = pos;
|
||||||
Point3F ejectionAxis = axis;
|
Point3F ejectionAxis = axis;
|
||||||
F32 theta = (mDataBlock->thetaMax - mDataBlock->thetaMin) * gRandGen.randF() +
|
F32 theta = (mDataBlock->thetaMax - mDataBlock->thetaMin) * gRandGen.randF() +
|
||||||
mDataBlock->thetaMin;
|
mDataBlock->thetaMin;
|
||||||
|
|
@ -1290,14 +1586,17 @@ void ParticleEmitter::addParticle(const Point3F& pos,
|
||||||
F32 initialVel = mDataBlock->ejectionVelocity;
|
F32 initialVel = mDataBlock->ejectionVelocity;
|
||||||
initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
|
initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
|
||||||
|
|
||||||
pNew->pos = pos + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
|
pNew->pos = pos_start + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
|
||||||
pNew->vel = ejectionAxis * initialVel;
|
pNew->pos_local = pNew->pos;
|
||||||
pNew->orientDir = ejectionAxis;
|
pNew->vel = mDataBlock->ejectionInvert ? ejectionAxis * -initialVel : ejectionAxis * initialVel;
|
||||||
|
if (mDataBlock->orientParticles)
|
||||||
|
pNew->orientDir = ejectionAxis;
|
||||||
|
else
|
||||||
|
// note -- for non-oriented particles, we use orientDir.x to store the billboard start angle.
|
||||||
|
pNew->orientDir.x = mDegToRad(part_db->start_angle + part_db->angle_variance*2.0f*gRandGen.randF() - part_db->angle_variance);
|
||||||
pNew->acc.set(0, 0, 0);
|
pNew->acc.set(0, 0, 0);
|
||||||
pNew->currentAge = 0;
|
pNew->currentAge = age_offset;
|
||||||
|
pNew->t_last = 0.0f;
|
||||||
// Choose a new particle datablack randomly from the list
|
|
||||||
U32 dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size();
|
|
||||||
mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel);
|
mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel);
|
||||||
updateKeyData( pNew );
|
updateKeyData( pNew );
|
||||||
|
|
||||||
|
|
@ -1379,8 +1678,10 @@ void ParticleEmitter::updateKeyData( Particle *part )
|
||||||
if( part->totalLifetime < 1 )
|
if( part->totalLifetime < 1 )
|
||||||
part->totalLifetime = 1;
|
part->totalLifetime = 1;
|
||||||
|
|
||||||
F32 t = F32(part->currentAge) / F32(part->totalLifetime);
|
if (part->currentAge > part->totalLifetime)
|
||||||
AssertFatal(t <= 1.0f, "Out out bounds filter function for particle.");
|
part->currentAge = part->totalLifetime;
|
||||||
|
F32 t = (F32)part->currentAge / (F32)part->totalLifetime;
|
||||||
|
|
||||||
|
|
||||||
for( U32 i = 1; i < ParticleData::PDC_NUM_KEYS; i++ )
|
for( U32 i = 1; i < ParticleData::PDC_NUM_KEYS; i++ )
|
||||||
{
|
{
|
||||||
|
|
@ -1412,7 +1713,25 @@ void ParticleEmitter::updateKeyData( Particle *part )
|
||||||
{
|
{
|
||||||
part->size = (part->dataBlock->sizes[i-1] * (1.0 - firstPart)) +
|
part->size = (part->dataBlock->sizes[i-1] * (1.0 - firstPart)) +
|
||||||
(part->dataBlock->sizes[i] * firstPart);
|
(part->dataBlock->sizes[i] * firstPart);
|
||||||
|
part->size *= part->dataBlock->sizeBias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mDataBlock->fade_color)
|
||||||
|
{
|
||||||
|
if (mDataBlock->fade_alpha)
|
||||||
|
part->color *= fade_amt;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
part->color.red *= fade_amt;
|
||||||
|
part->color.green *= fade_amt;
|
||||||
|
part->color.blue *= fade_amt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mDataBlock->fade_alpha)
|
||||||
|
part->color.alpha *= fade_amt;
|
||||||
|
|
||||||
|
if (mDataBlock->fade_size)
|
||||||
|
part->size *= fade_amt;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1424,19 +1743,25 @@ void ParticleEmitter::updateKeyData( Particle *part )
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::update( U32 ms )
|
void ParticleEmitter::update( U32 ms )
|
||||||
{
|
{
|
||||||
// TODO: Prefetch
|
F32 t = F32(ms)/1000.0f; // AFX -- moved outside loop, no need to recalculate this for every particle
|
||||||
|
|
||||||
for (Particle* part = part_list_head.next; part != NULL; part = part->next)
|
for (Particle* part = part_list_head.next; part != NULL; part = part->next)
|
||||||
{
|
{
|
||||||
F32 t = F32(ms) / 1000.0;
|
|
||||||
|
|
||||||
Point3F a = part->acc;
|
Point3F a = part->acc;
|
||||||
a -= part->vel * part->dataBlock->dragCoefficient;
|
a -= part->vel * part->dataBlock->dragCoefficient;
|
||||||
a -= mWindVelocity * part->dataBlock->windCoefficient;
|
a -= mWindVelocity * part->dataBlock->windCoefficient;
|
||||||
a += Point3F(0.0f, 0.0f, -9.81f) * part->dataBlock->gravityCoefficient;
|
a.z += -9.81f*part->dataBlock->gravityCoefficient; // AFX -- as long as gravity is a constant, this is faster
|
||||||
|
|
||||||
part->vel += a * t;
|
part->vel += a * t;
|
||||||
part->pos += part->vel * t;
|
part->pos_local += part->vel * t;
|
||||||
|
|
||||||
|
// AFX -- allow subclasses to adjust the particle params here
|
||||||
|
sub_particleUpdate(part);
|
||||||
|
|
||||||
|
if (part->dataBlock->constrain_pos)
|
||||||
|
part->pos = part->pos_local + this->pos_pe;
|
||||||
|
else
|
||||||
|
part->pos = part->pos_local;
|
||||||
|
|
||||||
updateKeyData( part );
|
updateKeyData( part );
|
||||||
}
|
}
|
||||||
|
|
@ -1999,3 +2324,43 @@ DefineEngineMethod(ParticleEmitterData, reload, void,(),,
|
||||||
{
|
{
|
||||||
object->reload();
|
object->reload();
|
||||||
}
|
}
|
||||||
|
void ParticleEmitter::emitParticlesExt(const MatrixF& xfm, const Point3F& point,
|
||||||
|
const Point3F& velocity, const U32 numMilliseconds)
|
||||||
|
{
|
||||||
|
if (mDataBlock->use_emitter_xfm)
|
||||||
|
{
|
||||||
|
Point3F zero_point(0.0f, 0.0f, 0.0f);
|
||||||
|
this->pos_pe = zero_point;
|
||||||
|
this->setTransform(xfm);
|
||||||
|
Point3F axis(0.0,0.0,1.0);
|
||||||
|
xfm.mulV(axis);
|
||||||
|
emitParticles(zero_point, true, axis, velocity, numMilliseconds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->pos_pe = point;
|
||||||
|
Point3F axis(0.0,0.0,1.0);
|
||||||
|
xfm.mulV(axis);
|
||||||
|
emitParticles(point, true, axis, velocity, numMilliseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParticleEmitter::setForcedObjBox(Box3F& box)
|
||||||
|
{
|
||||||
|
mObjBox = box;
|
||||||
|
forced_bbox = true;
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
pool->updatePoolBBox(this);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParticleEmitter::setSortPriority(S8 priority)
|
||||||
|
{
|
||||||
|
sort_priority = (priority == 0) ? 1 : priority;
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
pool->setSortPriority(sort_priority);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _H_PARTICLE_EMITTER
|
#ifndef _H_PARTICLE_EMITTER
|
||||||
#define _H_PARTICLE_EMITTER
|
#define _H_PARTICLE_EMITTER
|
||||||
|
|
||||||
|
|
@ -42,6 +47,12 @@
|
||||||
class RenderPassManager;
|
class RenderPassManager;
|
||||||
class ParticleData;
|
class ParticleData;
|
||||||
|
|
||||||
|
#define AFX_CAP_PARTICLE_POOLS
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
class afxParticlePoolData;
|
||||||
|
class afxParticlePool;
|
||||||
|
#endif
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// Particle Emitter Data
|
// Particle Emitter Data
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
@ -113,6 +124,26 @@ class ParticleEmitterData : public GameBaseData
|
||||||
bool glow; ///< Renders this emitter into the glow buffer.
|
bool glow; ///< Renders this emitter into the glow buffer.
|
||||||
|
|
||||||
bool reload();
|
bool reload();
|
||||||
|
public:
|
||||||
|
bool fade_color;
|
||||||
|
bool fade_size;
|
||||||
|
bool fade_alpha;
|
||||||
|
bool ejectionInvert;
|
||||||
|
U8 parts_per_eject;
|
||||||
|
bool use_emitter_xfm;
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
public:
|
||||||
|
afxParticlePoolData* pool_datablock;
|
||||||
|
U32 pool_index;
|
||||||
|
bool pool_depth_fade;
|
||||||
|
bool pool_radial_fade;
|
||||||
|
bool do_pool_id_convert;
|
||||||
|
#endif
|
||||||
|
public:
|
||||||
|
/*C*/ ParticleEmitterData(const ParticleEmitterData&, bool = false);
|
||||||
|
/*D*/ ~ParticleEmitterData();
|
||||||
|
virtual ParticleEmitterData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0);
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
@ -121,6 +152,9 @@ class ParticleEmitterData : public GameBaseData
|
||||||
class ParticleEmitter : public GameBase
|
class ParticleEmitter : public GameBase
|
||||||
{
|
{
|
||||||
typedef GameBase Parent;
|
typedef GameBase Parent;
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
friend class afxParticlePool;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -190,7 +224,7 @@ class ParticleEmitter : public GameBase
|
||||||
/// @param axis
|
/// @param axis
|
||||||
/// @param vel Initial velocity
|
/// @param vel Initial velocity
|
||||||
/// @param axisx
|
/// @param axisx
|
||||||
void addParticle(const Point3F &pos, const Point3F &axis, const Point3F &vel, const Point3F &axisx);
|
void addParticle(const Point3F &pos, const Point3F &axis, const Point3F &vel, const Point3F &axisx, const U32 age_offset);
|
||||||
|
|
||||||
|
|
||||||
inline void setupBillboard( Particle *part,
|
inline void setupBillboard( Particle *part,
|
||||||
|
|
@ -227,7 +261,12 @@ class ParticleEmitter : public GameBase
|
||||||
// PEngine interface
|
// PEngine interface
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
// AFX subclasses to ParticleEmitter require access to some members and methods of
|
||||||
|
// ParticleEmitter which are normally declared with private scope. In this section,
|
||||||
|
// protected and private scope statements have been inserted inline with the original
|
||||||
|
// code to expose the necessary members and methods.
|
||||||
void update( U32 ms );
|
void update( U32 ms );
|
||||||
|
protected:
|
||||||
inline void updateKeyData( Particle *part );
|
inline void updateKeyData( Particle *part );
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -239,25 +278,30 @@ class ParticleEmitter : public GameBase
|
||||||
|
|
||||||
ParticleEmitterData* mDataBlock;
|
ParticleEmitterData* mDataBlock;
|
||||||
|
|
||||||
|
protected:
|
||||||
U32 mInternalClock;
|
U32 mInternalClock;
|
||||||
|
|
||||||
U32 mNextParticleTime;
|
U32 mNextParticleTime;
|
||||||
|
|
||||||
Point3F mLastPosition;
|
Point3F mLastPosition;
|
||||||
bool mHasLastPosition;
|
bool mHasLastPosition;
|
||||||
|
private:
|
||||||
MatrixF mBBObjToWorld;
|
MatrixF mBBObjToWorld;
|
||||||
|
|
||||||
bool mDeleteWhenEmpty;
|
bool mDeleteWhenEmpty;
|
||||||
bool mDeleteOnTick;
|
bool mDeleteOnTick;
|
||||||
|
|
||||||
|
protected:
|
||||||
S32 mLifetimeMS;
|
S32 mLifetimeMS;
|
||||||
S32 mElapsedTimeMS;
|
S32 mElapsedTimeMS;
|
||||||
|
|
||||||
|
private:
|
||||||
F32 sizes[ ParticleData::PDC_NUM_KEYS ];
|
F32 sizes[ ParticleData::PDC_NUM_KEYS ];
|
||||||
LinearColorF colors[ ParticleData::PDC_NUM_KEYS ];
|
LinearColorF colors[ ParticleData::PDC_NUM_KEYS ];
|
||||||
|
|
||||||
GFXVertexBufferHandle<ParticleVertexType> mVertBuff;
|
GFXVertexBufferHandle<ParticleVertexType> mVertBuff;
|
||||||
|
|
||||||
|
protected:
|
||||||
// These members are for implementing a link-list of the active emitter
|
// These members are for implementing a link-list of the active emitter
|
||||||
// particles. Member part_store contains blocks of particles that can be
|
// particles. Member part_store contains blocks of particles that can be
|
||||||
// chained in a link-list. Usually the first part_store block is large
|
// chained in a link-list. Usually the first part_store block is large
|
||||||
|
|
@ -268,8 +312,28 @@ class ParticleEmitter : public GameBase
|
||||||
Particle part_list_head;
|
Particle part_list_head;
|
||||||
S32 n_part_capacity;
|
S32 n_part_capacity;
|
||||||
S32 n_parts;
|
S32 n_parts;
|
||||||
|
private:
|
||||||
S32 mCurBuffSize;
|
S32 mCurBuffSize;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
F32 fade_amt;
|
||||||
|
bool forced_bbox;
|
||||||
|
bool db_temp_clone;
|
||||||
|
Point3F pos_pe;
|
||||||
|
S8 sort_priority;
|
||||||
|
virtual void sub_particleUpdate(Particle*) { }
|
||||||
|
public:
|
||||||
|
virtual void emitParticlesExt(const MatrixF& xfm, const Point3F& point, const Point3F& velocity, const U32 numMilliseconds);
|
||||||
|
void setFadeAmount(F32 amt) { fade_amt = amt; }
|
||||||
|
void setForcedObjBox(Box3F& box);
|
||||||
|
void setSortPriority(S8 priority);
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
protected:
|
||||||
|
afxParticlePool* pool;
|
||||||
|
public:
|
||||||
|
void clearPool() { pool = 0; }
|
||||||
|
void setPool(afxParticlePool* p) { pool = p; }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _H_PARTICLE_EMITTER
|
#endif // _H_PARTICLE_EMITTER
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/gameBase/gameBase.h"
|
#include "T3D/gameBase/gameBase.h"
|
||||||
#include "console/consoleTypes.h"
|
#include "console/consoleTypes.h"
|
||||||
|
|
@ -36,6 +41,7 @@
|
||||||
#include "T3D/aiConnection.h"
|
#include "T3D/aiConnection.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "afx/arcaneFX.h"
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Ghost update relative priority values
|
// Ghost update relative priority values
|
||||||
|
|
||||||
|
|
@ -122,6 +128,12 @@ GameBaseData::GameBaseData()
|
||||||
category = "";
|
category = "";
|
||||||
packed = false;
|
packed = false;
|
||||||
}
|
}
|
||||||
|
GameBaseData::GameBaseData(const GameBaseData& other, bool temp_clone) : SimDataBlock(other, temp_clone)
|
||||||
|
{
|
||||||
|
packed = other.packed;
|
||||||
|
category = other.category;
|
||||||
|
//mReloadSignal = other.mReloadSignal; // DO NOT copy the mReloadSignal member.
|
||||||
|
}
|
||||||
|
|
||||||
void GameBaseData::inspectPostApply()
|
void GameBaseData::inspectPostApply()
|
||||||
{
|
{
|
||||||
|
|
@ -244,6 +256,8 @@ GameBase::GameBase()
|
||||||
|
|
||||||
GameBase::~GameBase()
|
GameBase::~GameBase()
|
||||||
{
|
{
|
||||||
|
if (scope_registered)
|
||||||
|
arcaneFX::unregisterScopedObject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -256,8 +270,16 @@ bool GameBase::onAdd()
|
||||||
|
|
||||||
// Datablock must be initialized on the server.
|
// Datablock must be initialized on the server.
|
||||||
// Client datablock are initialized by the initial update.
|
// Client datablock are initialized by the initial update.
|
||||||
if ( isServerObject() && mDataBlock && !onNewDataBlock( mDataBlock, false ) )
|
if (isClientObject())
|
||||||
return false;
|
{
|
||||||
|
if (scope_id > 0 && !scope_registered)
|
||||||
|
arcaneFX::registerScopedObject(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( mDataBlock && !onNewDataBlock( mDataBlock, false ) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
setProcessTick( true );
|
setProcessTick( true );
|
||||||
|
|
||||||
|
|
@ -266,6 +288,8 @@ bool GameBase::onAdd()
|
||||||
|
|
||||||
void GameBase::onRemove()
|
void GameBase::onRemove()
|
||||||
{
|
{
|
||||||
|
if (scope_registered)
|
||||||
|
arcaneFX::unregisterScopedObject(this);
|
||||||
// EDITOR FEATURE: Remove us from the reload signal of our datablock.
|
// EDITOR FEATURE: Remove us from the reload signal of our datablock.
|
||||||
if ( mDataBlock )
|
if ( mDataBlock )
|
||||||
mDataBlock->mReloadSignal.remove( this, &GameBase::_onDatablockModified );
|
mDataBlock->mReloadSignal.remove( this, &GameBase::_onDatablockModified );
|
||||||
|
|
@ -290,6 +314,9 @@ bool GameBase::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||||
|
|
||||||
if ( !mDataBlock )
|
if ( !mDataBlock )
|
||||||
return false;
|
return false;
|
||||||
|
// Don't set mask when new datablock is a temp-clone.
|
||||||
|
if (mDataBlock->isTempClone())
|
||||||
|
return true;
|
||||||
|
|
||||||
setMaskBits(DataBlockMask);
|
setMaskBits(DataBlockMask);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -543,6 +570,11 @@ U32 GameBase::packUpdate( NetConnection *connection, U32 mask, BitStream *stream
|
||||||
stream->writeFlag(mIsAiControlled);
|
stream->writeFlag(mIsAiControlled);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (stream->writeFlag(mask & ScopeIdMask))
|
||||||
|
{
|
||||||
|
if (stream->writeFlag(scope_refs > 0))
|
||||||
|
stream->writeInt(scope_id, SCOPE_ID_BITS);
|
||||||
|
}
|
||||||
return retMask;
|
return retMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -581,6 +613,11 @@ void GameBase::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
mTicksSinceLastMove = 0;
|
mTicksSinceLastMove = 0;
|
||||||
mIsAiControlled = stream->readFlag();
|
mIsAiControlled = stream->readFlag();
|
||||||
#endif
|
#endif
|
||||||
|
if (stream->readFlag())
|
||||||
|
{
|
||||||
|
scope_id = (stream->readFlag()) ? (U16) stream->readInt(SCOPE_ID_BITS) : 0;
|
||||||
|
scope_refs = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBase::onMount( SceneObject *obj, S32 node )
|
void GameBase::onMount( SceneObject *obj, S32 node )
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _GAMEBASE_H_
|
#ifndef _GAMEBASE_H_
|
||||||
#define _GAMEBASE_H_
|
#define _GAMEBASE_H_
|
||||||
|
|
||||||
|
|
@ -113,6 +118,8 @@ public:
|
||||||
DECLARE_CALLBACK( void, onMount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) );
|
DECLARE_CALLBACK( void, onMount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) );
|
||||||
DECLARE_CALLBACK( void, onUnmount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) );
|
DECLARE_CALLBACK( void, onUnmount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) );
|
||||||
/// @}
|
/// @}
|
||||||
|
public:
|
||||||
|
GameBaseData(const GameBaseData&, bool = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
@ -229,7 +236,8 @@ public:
|
||||||
enum GameBaseMasks {
|
enum GameBaseMasks {
|
||||||
DataBlockMask = Parent::NextFreeMask << 0,
|
DataBlockMask = Parent::NextFreeMask << 0,
|
||||||
ExtendedInfoMask = Parent::NextFreeMask << 1,
|
ExtendedInfoMask = Parent::NextFreeMask << 1,
|
||||||
NextFreeMask = Parent::NextFreeMask << 2
|
ScopeIdMask = Parent::NextFreeMask << 2,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
// net flags added by game base
|
// net flags added by game base
|
||||||
|
|
@ -453,6 +461,8 @@ private:
|
||||||
/// within this callback.
|
/// within this callback.
|
||||||
///
|
///
|
||||||
void _onDatablockModified();
|
void _onDatablockModified();
|
||||||
|
protected:
|
||||||
|
void onScopeIdChange() { setMaskBits(ScopeIdMask); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/gameBase/gameConnection.h"
|
#include "T3D/gameBase/gameConnection.h"
|
||||||
|
|
||||||
|
|
@ -52,6 +57,11 @@
|
||||||
#include "T3D/gameBase/std/stdMoveList.h"
|
#include "T3D/gameBase/std/stdMoveList.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
#include "core/stream/fileStream.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "afx/arcaneFX.h"
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
#define MAX_MOVE_PACKET_SENDS 4
|
#define MAX_MOVE_PACKET_SENDS 4
|
||||||
|
|
||||||
|
|
@ -173,9 +183,26 @@ IMPLEMENT_CALLBACK( GameConnection, onFlash, void, (bool state), (state),
|
||||||
"either is on or both are off. Typically this is used to enable the flash postFx.\n\n"
|
"either is on or both are off. Typically this is used to enable the flash postFx.\n\n"
|
||||||
"@param state Set to true if either the damage flash or white out conditions are active.\n\n");
|
"@param state Set to true if either the damage flash or white out conditions are active.\n\n");
|
||||||
|
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
StringTableEntry GameConnection::server_cache_filename = "";
|
||||||
|
StringTableEntry GameConnection::client_cache_filename = "";
|
||||||
|
bool GameConnection::server_cache_on = false;
|
||||||
|
bool GameConnection::client_cache_on = false;
|
||||||
|
#endif
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
GameConnection::GameConnection()
|
GameConnection::GameConnection()
|
||||||
{
|
{
|
||||||
|
mRolloverObj = NULL;
|
||||||
|
mPreSelectedObj = NULL;
|
||||||
|
mSelectedObj = NULL;
|
||||||
|
mChangedSelectedObj = false;
|
||||||
|
mPreSelectTimestamp = 0;
|
||||||
|
zoned_in = false;
|
||||||
|
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
client_db_stream = new InfiniteBitStream;
|
||||||
|
server_cache_CRC = 0xffffffff;
|
||||||
|
#endif
|
||||||
mLagging = false;
|
mLagging = false;
|
||||||
mControlObject = NULL;
|
mControlObject = NULL;
|
||||||
mCameraObject = NULL;
|
mCameraObject = NULL;
|
||||||
|
|
@ -246,6 +273,10 @@ GameConnection::~GameConnection()
|
||||||
dFree(mConnectArgv[i]);
|
dFree(mConnectArgv[i]);
|
||||||
dFree(mJoinPassword);
|
dFree(mJoinPassword);
|
||||||
delete mMoveList;
|
delete mMoveList;
|
||||||
|
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
delete client_db_stream;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
@ -1144,6 +1175,17 @@ void GameConnection::readPacket(BitStream *bstream)
|
||||||
{
|
{
|
||||||
mMoveList->clientReadMovePacket(bstream);
|
mMoveList->clientReadMovePacket(bstream);
|
||||||
|
|
||||||
|
// selected object - do we have a change in status?
|
||||||
|
if (bstream->readFlag())
|
||||||
|
{
|
||||||
|
if (bstream->readFlag())
|
||||||
|
{
|
||||||
|
S32 gIndex = bstream->readInt(NetConnection::GhostIdBitSize);
|
||||||
|
setSelectedObj(static_cast<SceneObject*>(resolveGhost(gIndex)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
setSelectedObj(NULL);
|
||||||
|
}
|
||||||
bool hadFlash = mDamageFlash > 0 || mWhiteOut > 0;
|
bool hadFlash = mDamageFlash > 0 || mWhiteOut > 0;
|
||||||
mDamageFlash = 0;
|
mDamageFlash = 0;
|
||||||
mWhiteOut = 0;
|
mWhiteOut = 0;
|
||||||
|
|
@ -1387,6 +1429,35 @@ void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
|
||||||
// all the damage flash & white out
|
// all the damage flash & white out
|
||||||
|
|
||||||
S32 gIndex = -1;
|
S32 gIndex = -1;
|
||||||
|
if (mChangedSelectedObj)
|
||||||
|
{
|
||||||
|
S32 gidx;
|
||||||
|
// send NULL player
|
||||||
|
if ((mSelectedObj == NULL) || mSelectedObj.isNull())
|
||||||
|
{
|
||||||
|
bstream->writeFlag(true);
|
||||||
|
bstream->writeFlag(false);
|
||||||
|
mChangedSelectedObj = false;
|
||||||
|
}
|
||||||
|
// send ghost-idx
|
||||||
|
else if ((gidx = getGhostIndex(mSelectedObj)) != -1)
|
||||||
|
{
|
||||||
|
Con::printf("SEND OBJECT SELECTION");
|
||||||
|
bstream->writeFlag(true);
|
||||||
|
bstream->writeFlag(true);
|
||||||
|
bstream->writeInt(gidx, NetConnection::GhostIdBitSize);
|
||||||
|
mChangedSelectedObj = false;
|
||||||
|
}
|
||||||
|
// not fully changed yet
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bstream->writeFlag(false);
|
||||||
|
mChangedSelectedObj = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bstream->writeFlag(false);
|
||||||
|
|
||||||
if (!mControlObject.isNull())
|
if (!mControlObject.isNull())
|
||||||
{
|
{
|
||||||
gIndex = getGhostIndex(mControlObject);
|
gIndex = getGhostIndex(mControlObject);
|
||||||
|
|
@ -1608,6 +1679,14 @@ void GameConnection::preloadNextDataBlock(bool hadNewFiles)
|
||||||
sendConnectionMessage(DataBlocksDownloadDone, mDataBlockSequence);
|
sendConnectionMessage(DataBlocksDownloadDone, mDataBlockSequence);
|
||||||
|
|
||||||
// gResourceManager->setMissingFileLogging(false);
|
// gResourceManager->setMissingFileLogging(false);
|
||||||
|
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
// This should be the last of the datablocks. An argument of false
|
||||||
|
// indicates that this is a client save.
|
||||||
|
if (clientCacheEnabled())
|
||||||
|
saveDatablockCache(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mFilesWereDownloaded = hadNewFiles;
|
mFilesWereDownloaded = hadNewFiles;
|
||||||
|
|
@ -1771,7 +1850,11 @@ DefineEngineMethod( GameConnection, transmitDataBlocks, void, (S32 sequence),,
|
||||||
const U32 iCount = pGroup->size();
|
const U32 iCount = pGroup->size();
|
||||||
|
|
||||||
// If this is the local client...
|
// If this is the local client...
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
if (GameConnection::getLocalClientConnection() == object && !GameConnection::serverCacheEnabled())
|
||||||
|
#else
|
||||||
if (GameConnection::getLocalClientConnection() == object)
|
if (GameConnection::getLocalClientConnection() == object)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
// Set up a pointer to the datablock.
|
// Set up a pointer to the datablock.
|
||||||
SimDataBlock* pDataBlock = 0;
|
SimDataBlock* pDataBlock = 0;
|
||||||
|
|
@ -2166,6 +2249,13 @@ void GameConnection::consoleInit()
|
||||||
"@ingroup Networking\n");
|
"@ingroup Networking\n");
|
||||||
|
|
||||||
// Con::addVariable("specialFog", TypeBool, &SceneGraph::useSpecial);
|
// Con::addVariable("specialFog", TypeBool, &SceneGraph::useSpecial);
|
||||||
|
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
Con::addVariable("$Pref::Server::DatablockCacheFilename", TypeString, &server_cache_filename);
|
||||||
|
Con::addVariable("$pref::Client::DatablockCacheFilename", TypeString, &client_cache_filename);
|
||||||
|
Con::addVariable("$Pref::Server::EnableDatablockCache", TypeBool, &server_cache_on);
|
||||||
|
Con::addVariable("$pref::Client::EnableDatablockCache", TypeBool, &client_cache_on);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineEngineMethod( GameConnection, startRecording, void, (const char* fileName),,
|
DefineEngineMethod( GameConnection, startRecording, void, (const char* fileName),,
|
||||||
|
|
@ -2360,4 +2450,522 @@ DefineEngineMethod( GameConnection, getVisibleGhostDistance, F32, (),,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return object->getVisibleGhostDistance();
|
return object->getVisibleGhostDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The object selection code here is, in part, based, on functionality described
|
||||||
|
// in the following resource:
|
||||||
|
// Object Selection in Torque by Dave Myers
|
||||||
|
// http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7335
|
||||||
|
|
||||||
|
ConsoleMethod(GameConnection, setSelectedObj, bool, 3, 4, "(object, [propagate_to_client])")
|
||||||
|
{
|
||||||
|
SceneObject* pending_selection;
|
||||||
|
if (!Sim::findObject(argv[2], pending_selection))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool propagate_to_client = (argc > 3) ? dAtob(argv[3]) : false;
|
||||||
|
object->setSelectedObj(pending_selection, propagate_to_client);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(GameConnection, getSelectedObj, S32, 2, 2, "()")
|
||||||
|
{
|
||||||
|
SimObject* selected = object->getSelectedObj();
|
||||||
|
return (selected) ? selected->getId(): -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(GameConnection, clearSelectedObj, void, 2, 3, "([propagate_to_client])")
|
||||||
|
{
|
||||||
|
bool propagate_to_client = (argc > 2) ? dAtob(argv[2]) : false;
|
||||||
|
object->setSelectedObj(NULL, propagate_to_client);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(GameConnection, setPreSelectedObjFromRollover, void, 2, 2, "()")
|
||||||
|
{
|
||||||
|
object->setPreSelectedObjFromRollover();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(GameConnection, clearPreSelectedObj, void, 2, 2, "()")
|
||||||
|
{
|
||||||
|
object->clearPreSelectedObj();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(GameConnection, setSelectedObjFromPreSelected, void, 2, 2, "()")
|
||||||
|
{
|
||||||
|
object->setSelectedObjFromPreSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameConnection::setSelectedObj(SceneObject* so, bool propagate_to_client)
|
||||||
|
{
|
||||||
|
if (!isConnectionToServer())
|
||||||
|
{
|
||||||
|
// clear previously selected object
|
||||||
|
if (mSelectedObj)
|
||||||
|
clearNotify(mSelectedObj);
|
||||||
|
|
||||||
|
// save new selection
|
||||||
|
mSelectedObj = so;
|
||||||
|
|
||||||
|
// mark selected object
|
||||||
|
if (mSelectedObj)
|
||||||
|
deleteNotify(mSelectedObj);
|
||||||
|
|
||||||
|
// mark selection dirty
|
||||||
|
if (propagate_to_client)
|
||||||
|
mChangedSelectedObj = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear previously selected object
|
||||||
|
if (mSelectedObj)
|
||||||
|
{
|
||||||
|
mSelectedObj->setSelectionFlags(mSelectedObj->getSelectionFlags() & ~SceneObject::SELECTED);
|
||||||
|
clearNotify(mSelectedObj);
|
||||||
|
Con::executef(this, "onObjectDeselected", mSelectedObj->getIdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// save new selection
|
||||||
|
mSelectedObj = so;
|
||||||
|
|
||||||
|
// mark selected object
|
||||||
|
if (mSelectedObj)
|
||||||
|
{
|
||||||
|
mSelectedObj->setSelectionFlags(mSelectedObj->getSelectionFlags() | SceneObject::SELECTED);
|
||||||
|
deleteNotify(mSelectedObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark selection dirty
|
||||||
|
//mChangedSelectedObj = true;
|
||||||
|
|
||||||
|
// notify appropriate script of the change
|
||||||
|
if (mSelectedObj)
|
||||||
|
Con::executef(this, "onObjectSelected", mSelectedObj->getIdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameConnection::setRolloverObj(SceneObject* so)
|
||||||
|
{
|
||||||
|
// save new selection
|
||||||
|
mRolloverObj = so;
|
||||||
|
|
||||||
|
// notify appropriate script of the change
|
||||||
|
Con::executef(this, "onObjectRollover", (mRolloverObj) ? mRolloverObj->getIdString() : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameConnection::setPreSelectedObjFromRollover()
|
||||||
|
{
|
||||||
|
mPreSelectedObj = mRolloverObj;
|
||||||
|
mPreSelectTimestamp = Platform::getRealMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameConnection::clearPreSelectedObj()
|
||||||
|
{
|
||||||
|
mPreSelectedObj = 0;
|
||||||
|
mPreSelectTimestamp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameConnection::setSelectedObjFromPreSelected()
|
||||||
|
{
|
||||||
|
U32 now = Platform::getRealMilliseconds();
|
||||||
|
if (now - mPreSelectTimestamp < arcaneFX::sTargetSelectionTimeoutMS)
|
||||||
|
setSelectedObj(mPreSelectedObj);
|
||||||
|
mPreSelectedObj = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameConnection::onDeleteNotify(SimObject* obj)
|
||||||
|
{
|
||||||
|
if (obj == mSelectedObj)
|
||||||
|
setSelectedObj(NULL);
|
||||||
|
|
||||||
|
Parent::onDeleteNotify(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
|
||||||
|
void GameConnection::tempDisableStringBuffering(BitStream* bs) const
|
||||||
|
{
|
||||||
|
bs->setStringBuffer(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameConnection::restoreStringBuffering(BitStream* bs) const
|
||||||
|
{
|
||||||
|
bs->clearStringBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// rewind to stream postion and then move raw bytes into client_db_stream
|
||||||
|
// for caching purposes.
|
||||||
|
void GameConnection::repackClientDatablock(BitStream* bstream, S32 start_pos)
|
||||||
|
{
|
||||||
|
static U8 bit_buffer[Net::MaxPacketDataSize];
|
||||||
|
|
||||||
|
if (!clientCacheEnabled() || !client_db_stream)
|
||||||
|
return;
|
||||||
|
|
||||||
|
S32 cur_pos = bstream->getCurPos();
|
||||||
|
S32 n_bits = cur_pos - start_pos;
|
||||||
|
if (n_bits <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bstream->setCurPos(start_pos);
|
||||||
|
bstream->readBits(n_bits, bit_buffer);
|
||||||
|
bstream->setCurPos(cur_pos);
|
||||||
|
|
||||||
|
//S32 start_pos2 = client_db_stream->getCurPos();
|
||||||
|
client_db_stream->writeBits(n_bits, bit_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CLIENT_CACHE_VERSION_CODE 47241113
|
||||||
|
|
||||||
|
void GameConnection::saveDatablockCache(bool on_server)
|
||||||
|
{
|
||||||
|
InfiniteBitStream bit_stream;
|
||||||
|
BitStream* bstream = 0;
|
||||||
|
|
||||||
|
if (on_server)
|
||||||
|
{
|
||||||
|
SimDataBlockGroup *g = Sim::getDataBlockGroup();
|
||||||
|
|
||||||
|
// find the first one we haven't sent:
|
||||||
|
U32 i, groupCount = g->size();
|
||||||
|
S32 key = this->getDataBlockModifiedKey();
|
||||||
|
for (i = 0; i < groupCount; i++)
|
||||||
|
if (((SimDataBlock*)(*g)[i])->getModifiedKey() > key)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// nothing to save
|
||||||
|
if (i == groupCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bstream = &bit_stream;
|
||||||
|
|
||||||
|
for (;i < groupCount; i++)
|
||||||
|
{
|
||||||
|
SimDataBlock* obj = (SimDataBlock*)(*g)[i];
|
||||||
|
GameConnection* gc = this;
|
||||||
|
NetConnection* conn = this;
|
||||||
|
SimObjectId id = obj->getId();
|
||||||
|
|
||||||
|
if (bstream->writeFlag(gc->getDataBlockModifiedKey() < obj->getModifiedKey())) // A - flag
|
||||||
|
{
|
||||||
|
if (obj->getModifiedKey() > gc->getMaxDataBlockModifiedKey())
|
||||||
|
gc->setMaxDataBlockModifiedKey(obj->getModifiedKey());
|
||||||
|
|
||||||
|
bstream->writeInt(id - DataBlockObjectIdFirst,DataBlockObjectIdBitSize); // B - int
|
||||||
|
|
||||||
|
S32 classId = obj->getClassId(conn->getNetClassGroup());
|
||||||
|
bstream->writeClassId(classId, NetClassTypeDataBlock, conn->getNetClassGroup()); // C - id
|
||||||
|
bstream->writeInt(i, DataBlockObjectIdBitSize); // D - int
|
||||||
|
bstream->writeInt(groupCount, DataBlockObjectIdBitSize + 1); // E - int
|
||||||
|
obj->packData(bstream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bstream = client_db_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bstream->getPosition() <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// zero out any leftover bits short of an even byte count
|
||||||
|
U32 n_leftover_bits = (bstream->getPosition()*8) - bstream->getCurPos();
|
||||||
|
if (n_leftover_bits >= 0 && n_leftover_bits <= 8)
|
||||||
|
{
|
||||||
|
// note - an unusual problem regarding setCurPos() results when there
|
||||||
|
// are no leftover bytes. Adding a buffer byte in this case avoids the problem.
|
||||||
|
if (n_leftover_bits == 0)
|
||||||
|
n_leftover_bits = 8;
|
||||||
|
U8 bzero = 0;
|
||||||
|
bstream->writeBits(n_leftover_bits, &bzero);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is where we actually save the file
|
||||||
|
const char* filename = (on_server) ? server_cache_filename : client_cache_filename;
|
||||||
|
if (filename && filename[0] != '\0')
|
||||||
|
{
|
||||||
|
FileStream* f_stream;
|
||||||
|
if((f_stream = FileStream::createAndOpen(filename, Torque::FS::File::Write )) == NULL)
|
||||||
|
{
|
||||||
|
Con::printf("Failed to open file '%s'.", filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 save_sz = bstream->getPosition();
|
||||||
|
|
||||||
|
if (!on_server)
|
||||||
|
{
|
||||||
|
f_stream->write((U32)CLIENT_CACHE_VERSION_CODE);
|
||||||
|
f_stream->write(save_sz);
|
||||||
|
f_stream->write(server_cache_CRC);
|
||||||
|
f_stream->write((U32)CLIENT_CACHE_VERSION_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
f_stream->write(save_sz, bstream->getBuffer());
|
||||||
|
|
||||||
|
// zero out any leftover bytes short of a 4-byte multiple
|
||||||
|
while ((save_sz % 4) != 0)
|
||||||
|
{
|
||||||
|
f_stream->write((U8)0);
|
||||||
|
save_sz++;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete f_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!on_server)
|
||||||
|
client_db_stream->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool afx_saved_db_cache = false;
|
||||||
|
static U32 afx_saved_db_cache_CRC = 0xffffffff;
|
||||||
|
|
||||||
|
void GameConnection::resetDatablockCache()
|
||||||
|
{
|
||||||
|
afx_saved_db_cache = false;
|
||||||
|
afx_saved_db_cache_CRC = 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(resetDatablockCache, void, 1, 1, "resetDatablockCache()")
|
||||||
|
{
|
||||||
|
GameConnection::resetDatablockCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(isDatablockCacheSaved, bool, 1, 1, "resetDatablockCache()")
|
||||||
|
{
|
||||||
|
return afx_saved_db_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(getDatablockCacheCRC, S32, 1, 1, "getDatablockCacheCRC()")
|
||||||
|
{
|
||||||
|
return (S32)afx_saved_db_cache_CRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(extractDatablockCacheCRC, S32, 2, 2, "extractDatablockCacheCRC(filename)")
|
||||||
|
{
|
||||||
|
FileStream f_stream;
|
||||||
|
const char* fileName = argv[1];
|
||||||
|
if(!f_stream.open(fileName, Torque::FS::File::Read))
|
||||||
|
{
|
||||||
|
Con::errorf("Failed to open file '%s'.", fileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 stream_sz = f_stream.getStreamSize();
|
||||||
|
if (stream_sz < 4*32)
|
||||||
|
{
|
||||||
|
Con::errorf("File '%s' is not a valid datablock cache.", fileName);
|
||||||
|
f_stream.close();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 pre_code; f_stream.read(&pre_code);
|
||||||
|
U32 save_sz; f_stream.read(&save_sz);
|
||||||
|
U32 crc_code; f_stream.read(&crc_code);
|
||||||
|
U32 post_code; f_stream.read(&post_code);
|
||||||
|
|
||||||
|
f_stream.close();
|
||||||
|
|
||||||
|
if (pre_code != post_code)
|
||||||
|
{
|
||||||
|
Con::errorf("File '%s' is not a valid datablock cache.", fileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pre_code != (U32)CLIENT_CACHE_VERSION_CODE)
|
||||||
|
{
|
||||||
|
Con::errorf("Version of datablock cache file '%s' does not match version of running software.", fileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (S32)crc_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(setDatablockCacheCRC, void, 2, 2, "setDatablockCacheCRC(crc)")
|
||||||
|
{
|
||||||
|
GameConnection *conn = GameConnection::getConnectionToServer();
|
||||||
|
if(!conn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
U32 crc_u = (U32)dAtoi(argv[1]);
|
||||||
|
conn->setServerCacheCRC(crc_u);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod( GameConnection, saveDatablockCache, void, 2, 2, "saveDatablockCache()")
|
||||||
|
{
|
||||||
|
if (GameConnection::serverCacheEnabled() && !afx_saved_db_cache)
|
||||||
|
{
|
||||||
|
// Save the datablocks to a cache file. An argument
|
||||||
|
// of true indicates that this is a server save.
|
||||||
|
object->saveDatablockCache(true);
|
||||||
|
afx_saved_db_cache = true;
|
||||||
|
afx_saved_db_cache_CRC = 0xffffffff;
|
||||||
|
|
||||||
|
static char filename_buffer[1024];
|
||||||
|
String filename(Torque::Path::CleanSeparators(object->serverCacheFilename()));
|
||||||
|
Con::expandScriptFilename(filename_buffer, sizeof(filename_buffer), filename.c_str());
|
||||||
|
Torque::Path givenPath(Torque::Path::CompressPath(filename_buffer));
|
||||||
|
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(givenPath);
|
||||||
|
if ( fileRef == NULL )
|
||||||
|
Con::errorf("saveDatablockCache() failed to get CRC for file '%s'.", filename.c_str());
|
||||||
|
else
|
||||||
|
afx_saved_db_cache_CRC = (S32)fileRef->getChecksum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod( GameConnection, loadDatablockCache, void, 2, 2, "loadDatablockCache()")
|
||||||
|
{
|
||||||
|
if (GameConnection::clientCacheEnabled())
|
||||||
|
{
|
||||||
|
object->loadDatablockCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod( GameConnection, loadDatablockCache_Begin, bool, 2, 2, "loadDatablockCache_Begin()")
|
||||||
|
{
|
||||||
|
if (GameConnection::clientCacheEnabled())
|
||||||
|
{
|
||||||
|
return object->loadDatablockCache_Begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod( GameConnection, loadDatablockCache_Continue, bool, 2, 2, "loadDatablockCache_Continue()")
|
||||||
|
{
|
||||||
|
if (GameConnection::clientCacheEnabled())
|
||||||
|
{
|
||||||
|
return object->loadDatablockCache_Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* afx_db_load_buf = 0;
|
||||||
|
static U32 afx_db_load_buf_sz = 0;
|
||||||
|
static BitStream* afx_db_load_bstream = 0;
|
||||||
|
|
||||||
|
void GameConnection::loadDatablockCache()
|
||||||
|
{
|
||||||
|
if (!loadDatablockCache_Begin())
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (loadDatablockCache_Continue())
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameConnection::loadDatablockCache_Begin()
|
||||||
|
{
|
||||||
|
if (!client_cache_filename || client_cache_filename[0] == '\0')
|
||||||
|
{
|
||||||
|
Con::errorf("No filename was specified for the client datablock cache.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open cache file
|
||||||
|
FileStream f_stream;
|
||||||
|
if(!f_stream.open(client_cache_filename, Torque::FS::File::Read))
|
||||||
|
{
|
||||||
|
Con::errorf("Failed to open file '%s'.", client_cache_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get file size
|
||||||
|
U32 stream_sz = f_stream.getStreamSize();
|
||||||
|
if (stream_sz <= 4*4)
|
||||||
|
{
|
||||||
|
Con::errorf("File '%s' is too small to be a valid datablock cache.", client_cache_filename);
|
||||||
|
f_stream.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load header data
|
||||||
|
U32 pre_code; f_stream.read(&pre_code);
|
||||||
|
U32 save_sz; f_stream.read(&save_sz);
|
||||||
|
U32 crc_code; f_stream.read(&crc_code);
|
||||||
|
U32 post_code; f_stream.read(&post_code);
|
||||||
|
|
||||||
|
// validate header info
|
||||||
|
if (pre_code != post_code)
|
||||||
|
{
|
||||||
|
Con::errorf("File '%s' is not a valid datablock cache.", client_cache_filename);
|
||||||
|
f_stream.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pre_code != (U32)CLIENT_CACHE_VERSION_CODE)
|
||||||
|
{
|
||||||
|
Con::errorf("Version of datablock cache file '%s' does not match version of running software.", client_cache_filename);
|
||||||
|
f_stream.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocated the in-memory buffer
|
||||||
|
afx_db_load_buf_sz = stream_sz - (4*4);
|
||||||
|
afx_db_load_buf = new char[afx_db_load_buf_sz];
|
||||||
|
|
||||||
|
// load data from file into memory
|
||||||
|
if (!f_stream.read(stream_sz, afx_db_load_buf))
|
||||||
|
{
|
||||||
|
Con::errorf("Failed to read data from file '%s'.", client_cache_filename);
|
||||||
|
f_stream.close();
|
||||||
|
delete [] afx_db_load_buf;
|
||||||
|
afx_db_load_buf = 0;
|
||||||
|
afx_db_load_buf_sz = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// close file
|
||||||
|
f_stream.close();
|
||||||
|
|
||||||
|
// At this point we have the whole cache in memory
|
||||||
|
|
||||||
|
// create a bitstream from the in-memory buffer
|
||||||
|
afx_db_load_bstream = new BitStream(afx_db_load_buf, afx_db_load_buf_sz);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameConnection::loadDatablockCache_Continue()
|
||||||
|
{
|
||||||
|
if (!afx_db_load_bstream)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// prevent repacking of datablocks during load
|
||||||
|
BitStream* save_client_db_stream = client_db_stream;
|
||||||
|
client_db_stream = 0;
|
||||||
|
|
||||||
|
bool all_finished = false;
|
||||||
|
|
||||||
|
// loop through at most 16 datablocks
|
||||||
|
BitStream *bstream = afx_db_load_bstream;
|
||||||
|
for (S32 i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
S32 save_pos = bstream->getCurPos();
|
||||||
|
if (!bstream->readFlag())
|
||||||
|
{
|
||||||
|
all_finished = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bstream->setCurPos(save_pos);
|
||||||
|
SimDataBlockEvent evt;
|
||||||
|
evt.unpack(this, bstream);
|
||||||
|
evt.process(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
client_db_stream = save_client_db_stream;
|
||||||
|
|
||||||
|
if (all_finished)
|
||||||
|
{
|
||||||
|
delete afx_db_load_bstream;
|
||||||
|
afx_db_load_bstream = 0;
|
||||||
|
delete [] afx_db_load_buf;
|
||||||
|
afx_db_load_buf = 0;
|
||||||
|
afx_db_load_buf_sz = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _GAMECONNECTION_H_
|
#ifndef _GAMECONNECTION_H_
|
||||||
#define _GAMECONNECTION_H_
|
#define _GAMECONNECTION_H_
|
||||||
|
|
||||||
|
|
@ -55,6 +60,14 @@ class MoveList;
|
||||||
struct Move;
|
struct Move;
|
||||||
struct AuthInfo;
|
struct AuthInfo;
|
||||||
|
|
||||||
|
// To disable datablock caching, remove or comment out the AFX_CAP_DATABLOCK_CACHE define below.
|
||||||
|
// Also, at a minimum, the following script preferences should be set to false:
|
||||||
|
// $pref::Client::EnableDatablockCache = false; (in arcane.fx/client/defaults.cs)
|
||||||
|
// $Pref::Server::EnableDatablockCache = false; (in arcane.fx/server/defaults.cs)
|
||||||
|
// Alternatively, all script code marked with "DATABLOCK CACHE CODE" can be removed or
|
||||||
|
// commented out.
|
||||||
|
//
|
||||||
|
#define AFX_CAP_DATABLOCK_CACHE
|
||||||
const F32 MinCameraFov = 1.f; ///< min camera FOV
|
const F32 MinCameraFov = 1.f; ///< min camera FOV
|
||||||
const F32 MaxCameraFov = 179.f; ///< max camera FOV
|
const F32 MaxCameraFov = 179.f; ///< max camera FOV
|
||||||
|
|
||||||
|
|
@ -372,6 +385,61 @@ protected:
|
||||||
DECLARE_CALLBACK( void, setLagIcon, (bool state) );
|
DECLARE_CALLBACK( void, setLagIcon, (bool state) );
|
||||||
DECLARE_CALLBACK( void, onDataBlocksDone, (U32 sequence) );
|
DECLARE_CALLBACK( void, onDataBlocksDone, (U32 sequence) );
|
||||||
DECLARE_CALLBACK( void, onFlash, (bool state) );
|
DECLARE_CALLBACK( void, onFlash, (bool state) );
|
||||||
|
|
||||||
|
// GameConnection is modified to keep track of object selections which are used in
|
||||||
|
// spell targeting. This code stores the current object selection as well as the
|
||||||
|
// current rollover object beneath the cursor. The rollover object is treated as a
|
||||||
|
// pending object selection and actual object selection is usually made by promoting
|
||||||
|
// the rollover object to the current object selection.
|
||||||
|
private:
|
||||||
|
SimObjectPtr<SceneObject> mRolloverObj;
|
||||||
|
SimObjectPtr<SceneObject> mPreSelectedObj;
|
||||||
|
SimObjectPtr<SceneObject> mSelectedObj;
|
||||||
|
bool mChangedSelectedObj;
|
||||||
|
U32 mPreSelectTimestamp;
|
||||||
|
protected:
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
public:
|
||||||
|
void setRolloverObj(SceneObject*);
|
||||||
|
SceneObject* getRolloverObj() { return mRolloverObj; }
|
||||||
|
void setSelectedObj(SceneObject*, bool propagate_to_client=false);
|
||||||
|
SceneObject* getSelectedObj() { return mSelectedObj; }
|
||||||
|
void setPreSelectedObjFromRollover();
|
||||||
|
void clearPreSelectedObj();
|
||||||
|
void setSelectedObjFromPreSelected();
|
||||||
|
// Flag is added to indicate when a client is fully connected or "zoned-in".
|
||||||
|
// This information determines when AFX will startup active effects on a newly
|
||||||
|
// added client.
|
||||||
|
private:
|
||||||
|
bool zoned_in;
|
||||||
|
public:
|
||||||
|
bool isZonedIn() const { return zoned_in; }
|
||||||
|
void setZonedIn() { zoned_in = true; }
|
||||||
|
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
private:
|
||||||
|
static StringTableEntry server_cache_filename;
|
||||||
|
static StringTableEntry client_cache_filename;
|
||||||
|
static bool server_cache_on;
|
||||||
|
static bool client_cache_on;
|
||||||
|
BitStream* client_db_stream;
|
||||||
|
U32 server_cache_CRC;
|
||||||
|
public:
|
||||||
|
void repackClientDatablock(BitStream*, S32 start_pos);
|
||||||
|
void saveDatablockCache(bool on_server);
|
||||||
|
void loadDatablockCache();
|
||||||
|
bool loadDatablockCache_Begin();
|
||||||
|
bool loadDatablockCache_Continue();
|
||||||
|
void tempDisableStringBuffering(BitStream* bs) const;
|
||||||
|
void restoreStringBuffering(BitStream* bs) const;
|
||||||
|
void setServerCacheCRC(U32 crc) { server_cache_CRC = crc; }
|
||||||
|
|
||||||
|
static void resetDatablockCache();
|
||||||
|
static bool serverCacheEnabled() { return server_cache_on; }
|
||||||
|
static bool clientCacheEnabled() { return client_cache_on; }
|
||||||
|
static const char* serverCacheFilename() { return server_cache_filename; }
|
||||||
|
static const char* clientCacheFilename() { return client_cache_filename; }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "core/dnet.h"
|
#include "core/dnet.h"
|
||||||
#include "core/stream/bitStream.h"
|
#include "core/stream/bitStream.h"
|
||||||
|
|
@ -136,6 +141,9 @@ void SimDataBlockEvent::notifyDelivered(NetConnection *conn, bool )
|
||||||
|
|
||||||
void SimDataBlockEvent::pack(NetConnection *conn, BitStream *bstream)
|
void SimDataBlockEvent::pack(NetConnection *conn, BitStream *bstream)
|
||||||
{
|
{
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
((GameConnection *)conn)->tempDisableStringBuffering(bstream);
|
||||||
|
#endif
|
||||||
SimDataBlock* obj;
|
SimDataBlock* obj;
|
||||||
Sim::findObject(id,obj);
|
Sim::findObject(id,obj);
|
||||||
GameConnection *gc = (GameConnection *) conn;
|
GameConnection *gc = (GameConnection *) conn;
|
||||||
|
|
@ -157,10 +165,18 @@ void SimDataBlockEvent::pack(NetConnection *conn, BitStream *bstream)
|
||||||
bstream->writeInt(classId ^ DebugChecksum, 32);
|
bstream->writeInt(classId ^ DebugChecksum, 32);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
((GameConnection *)conn)->restoreStringBuffering(bstream);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimDataBlockEvent::unpack(NetConnection *cptr, BitStream *bstream)
|
void SimDataBlockEvent::unpack(NetConnection *cptr, BitStream *bstream)
|
||||||
{
|
{
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
// stash the stream position prior to unpacking
|
||||||
|
S32 start_pos = bstream->getCurPos();
|
||||||
|
((GameConnection *)cptr)->tempDisableStringBuffering(bstream);
|
||||||
|
#endif
|
||||||
if(bstream->readFlag())
|
if(bstream->readFlag())
|
||||||
{
|
{
|
||||||
mProcess = true;
|
mProcess = true;
|
||||||
|
|
@ -215,6 +231,11 @@ void SimDataBlockEvent::unpack(NetConnection *cptr, BitStream *bstream)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#ifdef AFX_CAP_DATABLOCK_CACHE
|
||||||
|
// rewind to stream position and then process raw bytes for caching
|
||||||
|
((GameConnection *)cptr)->repackClientDatablock(bstream, start_pos);
|
||||||
|
((GameConnection *)cptr)->restoreStringBuffering(bstream);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimDataBlockEvent::write(NetConnection *cptr, BitStream *bstream)
|
void SimDataBlockEvent::write(NetConnection *cptr, BitStream *bstream)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/gameBase/processList.h"
|
#include "T3D/gameBase/processList.h"
|
||||||
|
|
||||||
|
|
@ -284,5 +289,20 @@ void ProcessList::advanceObjects()
|
||||||
PROFILE_END();
|
PROFILE_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProcessObject* ProcessList::findNearestToEnd(Vector<ProcessObject*>& objs) const
|
||||||
|
{
|
||||||
|
if (objs.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (ProcessObject* obj = mHead.mProcessLink.prev; obj != &mHead; obj = obj->mProcessLink.prev)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < objs.size(); i++)
|
||||||
|
{
|
||||||
|
if (obj == objs[i])
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _PROCESSLIST_H_
|
#ifndef _PROCESSLIST_H_
|
||||||
#define _PROCESSLIST_H_
|
#define _PROCESSLIST_H_
|
||||||
|
|
||||||
|
|
@ -188,6 +193,9 @@ protected:
|
||||||
|
|
||||||
PreTickSignal mPreTick;
|
PreTickSignal mPreTick;
|
||||||
PostTickSignal mPostTick;
|
PostTickSignal mPostTick;
|
||||||
|
// JTF: still needed?
|
||||||
|
public:
|
||||||
|
ProcessObject* findNearestToEnd(Vector<ProcessObject*>& objs) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _PROCESSLIST_H_
|
#endif // _PROCESSLIST_H_
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/groundPlane.h"
|
#include "T3D/groundPlane.h"
|
||||||
|
|
||||||
|
|
@ -40,6 +45,7 @@
|
||||||
#include "T3D/physics/physicsBody.h"
|
#include "T3D/physics/physicsBody.h"
|
||||||
#include "T3D/physics/physicsCollision.h"
|
#include "T3D/physics/physicsCollision.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxZodiacMgr.h"
|
||||||
|
|
||||||
/// Minimum square size allowed. This is a cheap way to limit the amount
|
/// Minimum square size allowed. This is a cheap way to limit the amount
|
||||||
/// of geometry possibly generated by the GroundPlane (vertex buffers have a
|
/// of geometry possibly generated by the GroundPlane (vertex buffers have a
|
||||||
|
|
@ -77,6 +83,7 @@ GroundPlane::GroundPlane()
|
||||||
mNetFlags.set( Ghostable | ScopeAlways );
|
mNetFlags.set( Ghostable | ScopeAlways );
|
||||||
|
|
||||||
mConvexList = new Convex;
|
mConvexList = new Convex;
|
||||||
|
mTypeMask |= TerrainLikeObjectType;
|
||||||
}
|
}
|
||||||
|
|
||||||
GroundPlane::~GroundPlane()
|
GroundPlane::~GroundPlane()
|
||||||
|
|
@ -356,6 +363,7 @@ void GroundPlane::prepRenderImage( SceneRenderState* state )
|
||||||
if( mVertexBuffer.isNull() )
|
if( mVertexBuffer.isNull() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
afxZodiacMgr::renderGroundPlaneZodiacs(state, this);
|
||||||
// Add a render instance.
|
// Add a render instance.
|
||||||
|
|
||||||
RenderPassManager* pass = state->getRenderPass();
|
RenderPassManager* pass = state->getRenderPass();
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/lightBase.h"
|
#include "T3D/lightBase.h"
|
||||||
|
|
||||||
|
|
@ -73,6 +78,7 @@ LightBase::LightBase()
|
||||||
mLight = LightManager::createLightInfo();
|
mLight = LightManager::createLightInfo();
|
||||||
|
|
||||||
mFlareState.clear();
|
mFlareState.clear();
|
||||||
|
mLocalRenderViz = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LightBase::~LightBase()
|
LightBase::~LightBase()
|
||||||
|
|
@ -206,7 +212,7 @@ void LightBase::prepRenderImage( SceneRenderState *state )
|
||||||
|
|
||||||
// If the light is selected or light visualization
|
// If the light is selected or light visualization
|
||||||
// is enabled then register the callback.
|
// is enabled then register the callback.
|
||||||
if ( smRenderViz || isSelectedInEditor )
|
if ( mLocalRenderViz || smRenderViz || isSelectedInEditor )
|
||||||
{
|
{
|
||||||
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||||
ri->renderDelegate.bind( this, &LightBase::_onRenderViz );
|
ri->renderDelegate.bind( this, &LightBase::_onRenderViz );
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _LIGHTBASE_H_
|
#ifndef _LIGHTBASE_H_
|
||||||
#define _LIGHTBASE_H_
|
#define _LIGHTBASE_H_
|
||||||
|
|
||||||
|
|
@ -132,6 +137,8 @@ public:
|
||||||
virtual void pauseAnimation( void );
|
virtual void pauseAnimation( void );
|
||||||
virtual void playAnimation( void );
|
virtual void playAnimation( void );
|
||||||
virtual void playAnimation( LightAnimData *animData );
|
virtual void playAnimation( LightAnimData *animData );
|
||||||
|
protected:
|
||||||
|
bool mLocalRenderViz;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _LIGHTBASE_H_
|
#endif // _LIGHTBASE_H_
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,19 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _OBJECTTYPES_H_
|
#ifndef _OBJECTTYPES_H_
|
||||||
#define _OBJECTTYPES_H_
|
#define _OBJECTTYPES_H_
|
||||||
|
|
||||||
#include "platform/types.h"
|
#include "platform/types.h"
|
||||||
|
|
||||||
|
// Uncomment the AFX_CAP_AFXMODEL_TYPE define below to enable a type flag
|
||||||
|
// for afxModel objects.
|
||||||
|
//#define AFX_CAP_AFXMODEL_TYPE
|
||||||
/// Types used for SceneObject type masks (SceneObject::mTypeMask)
|
/// Types used for SceneObject type masks (SceneObject::mTypeMask)
|
||||||
///
|
///
|
||||||
/// @note If a new object type is added, don't forget to add it to
|
/// @note If a new object type is added, don't forget to add it to
|
||||||
|
|
@ -149,6 +157,11 @@ enum SceneObjectTypes
|
||||||
|
|
||||||
EntityObjectType = BIT(23),
|
EntityObjectType = BIT(23),
|
||||||
/// @}
|
/// @}
|
||||||
|
InteriorLikeObjectType = BIT(24),
|
||||||
|
TerrainLikeObjectType = BIT(25),
|
||||||
|
#if defined(AFX_CAP_AFXMODEL_TYPE)
|
||||||
|
afxModelObjectType = BIT(26)
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SceneObjectTypeMasks : U32
|
enum SceneObjectTypeMasks : U32
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "T3D/physicalZone.h"
|
#include "T3D/physicalZone.h"
|
||||||
#include "core/stream/bitStream.h"
|
#include "core/stream/bitStream.h"
|
||||||
#include "collision/boxConvex.h"
|
#include "collision/boxConvex.h"
|
||||||
|
|
@ -33,6 +38,8 @@
|
||||||
#include "gfx/gfxDrawUtil.h"
|
#include "gfx/gfxDrawUtil.h"
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
|
|
||||||
|
//#include "console/engineTypes.h"
|
||||||
|
#include "sim/netConnection.h"
|
||||||
IMPLEMENT_CO_NETOBJECT_V1(PhysicalZone);
|
IMPLEMENT_CO_NETOBJECT_V1(PhysicalZone);
|
||||||
|
|
||||||
ConsoleDocClass( PhysicalZone,
|
ConsoleDocClass( PhysicalZone,
|
||||||
|
|
@ -103,6 +110,10 @@ PhysicalZone::PhysicalZone()
|
||||||
|
|
||||||
mConvexList = new Convex;
|
mConvexList = new Convex;
|
||||||
mActive = true;
|
mActive = true;
|
||||||
|
force_type = VECTOR;
|
||||||
|
force_mag = 0.0f;
|
||||||
|
orient_force = false;
|
||||||
|
fade_amt = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicalZone::~PhysicalZone()
|
PhysicalZone::~PhysicalZone()
|
||||||
|
|
@ -111,6 +122,16 @@ PhysicalZone::~PhysicalZone()
|
||||||
mConvexList = NULL;
|
mConvexList = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ImplementEnumType( PhysicalZone_ForceType, "Possible physical zone force types.\n" "@ingroup PhysicalZone\n\n" )
|
||||||
|
{ PhysicalZone::VECTOR, "vector", "..." },
|
||||||
|
{ PhysicalZone::SPHERICAL, "spherical", "..." },
|
||||||
|
{ PhysicalZone::CYLINDRICAL, "cylindrical", "..." },
|
||||||
|
// aliases
|
||||||
|
{ PhysicalZone::SPHERICAL, "sphere", "..." },
|
||||||
|
{ PhysicalZone::CYLINDRICAL, "cylinder", "..." },
|
||||||
|
EndImplementEnumType;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
void PhysicalZone::consoleInit()
|
void PhysicalZone::consoleInit()
|
||||||
{
|
{
|
||||||
|
|
@ -129,6 +150,10 @@ void PhysicalZone::initPersistFields()
|
||||||
"point followed by three vectors representing the edges extending from the corner." );
|
"point followed by three vectors representing the edges extending from the corner." );
|
||||||
endGroup("Misc");
|
endGroup("Misc");
|
||||||
|
|
||||||
|
addGroup("AFX");
|
||||||
|
addField("forceType", TYPEID<PhysicalZone::ForceType>(), Offset(force_type, PhysicalZone));
|
||||||
|
addField("orientForce", TypeBool, Offset(orient_force, PhysicalZone));
|
||||||
|
endGroup("AFX");
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,6 +183,19 @@ bool PhysicalZone::onAdd()
|
||||||
Polyhedron temp = mPolyhedron;
|
Polyhedron temp = mPolyhedron;
|
||||||
setPolyhedron(temp);
|
setPolyhedron(temp);
|
||||||
|
|
||||||
|
switch (force_type)
|
||||||
|
{
|
||||||
|
case SPHERICAL:
|
||||||
|
force_mag = mAppliedForce.magnitudeSafe();
|
||||||
|
break;
|
||||||
|
case CYLINDRICAL:
|
||||||
|
{
|
||||||
|
Point3F force_vec = mAppliedForce;
|
||||||
|
force_vec.z = 0.0;
|
||||||
|
force_mag = force_vec.magnitudeSafe();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
addToScene();
|
addToScene();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -191,7 +229,7 @@ void PhysicalZone::setTransform(const MatrixF & mat)
|
||||||
mClippedList.setBaseTransform(base);
|
mClippedList.setBaseTransform(base);
|
||||||
|
|
||||||
if (isServerObject())
|
if (isServerObject())
|
||||||
setMaskBits(InitialUpdateMask);
|
setMaskBits(MoveMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -242,12 +280,8 @@ U32 PhysicalZone::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
||||||
U32 i;
|
U32 i;
|
||||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||||
|
|
||||||
if (stream->writeFlag((mask & InitialUpdateMask) != 0)) {
|
if (stream->writeFlag(mask & PolyhedronMask))
|
||||||
// Note that we don't really care about efficiency here, since this is an
|
{
|
||||||
// edit-only ghost...
|
|
||||||
mathWrite(*stream, mObjToWorld);
|
|
||||||
mathWrite(*stream, mObjScale);
|
|
||||||
|
|
||||||
// Write the polyhedron
|
// Write the polyhedron
|
||||||
stream->write(mPolyhedron.pointList.size());
|
stream->write(mPolyhedron.pointList.size());
|
||||||
for (i = 0; i < mPolyhedron.pointList.size(); i++)
|
for (i = 0; i < mPolyhedron.pointList.size(); i++)
|
||||||
|
|
@ -266,32 +300,44 @@ U32 PhysicalZone::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
||||||
stream->write(rEdge.vertex[0]);
|
stream->write(rEdge.vertex[0]);
|
||||||
stream->write(rEdge.vertex[1]);
|
stream->write(rEdge.vertex[1]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->writeFlag(mask & MoveMask))
|
||||||
|
{
|
||||||
|
stream->writeAffineTransform(mObjToWorld);
|
||||||
|
mathWrite(*stream, mObjScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->writeFlag(mask & SettingsMask))
|
||||||
|
{
|
||||||
stream->write(mVelocityMod);
|
stream->write(mVelocityMod);
|
||||||
stream->write(mGravityMod);
|
stream->write(mGravityMod);
|
||||||
mathWrite(*stream, mAppliedForce);
|
mathWrite(*stream, mAppliedForce);
|
||||||
stream->writeFlag(mActive);
|
stream->writeInt(force_type, FORCE_TYPE_BITS);
|
||||||
} else {
|
stream->writeFlag(orient_force);
|
||||||
stream->writeFlag(mActive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retMask;
|
if (stream->writeFlag(mask & FadeMask))
|
||||||
|
{
|
||||||
|
U8 fade_byte = (U8)(fade_amt*255.0f);
|
||||||
|
stream->write(fade_byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->writeFlag(mActive);
|
||||||
|
|
||||||
|
return retMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicalZone::unpackUpdate(NetConnection* con, BitStream* stream)
|
void PhysicalZone::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||||
{
|
{
|
||||||
Parent::unpackUpdate(con, stream);
|
Parent::unpackUpdate(con, stream);
|
||||||
|
|
||||||
if (stream->readFlag()) {
|
bool new_ph = false;
|
||||||
|
if (stream->readFlag()) // PolyhedronMask
|
||||||
|
{
|
||||||
U32 i, size;
|
U32 i, size;
|
||||||
MatrixF temp;
|
|
||||||
Point3F tempScale;
|
|
||||||
Polyhedron tempPH;
|
Polyhedron tempPH;
|
||||||
|
|
||||||
// Transform
|
|
||||||
mathRead(*stream, &temp);
|
|
||||||
mathRead(*stream, &tempScale);
|
|
||||||
|
|
||||||
// Read the polyhedron
|
// Read the polyhedron
|
||||||
stream->read(&size);
|
stream->read(&size);
|
||||||
tempPH.pointList.setSize(size);
|
tempPH.pointList.setSize(size);
|
||||||
|
|
@ -314,17 +360,46 @@ void PhysicalZone::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||||
stream->read(&rEdge.vertex[1]);
|
stream->read(&rEdge.vertex[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPolyhedron(tempPH);
|
||||||
|
new_ph = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->readFlag()) // MoveMask
|
||||||
|
{
|
||||||
|
MatrixF temp;
|
||||||
|
stream->readAffineTransform(&temp);
|
||||||
|
|
||||||
|
Point3F tempScale;
|
||||||
|
mathRead(*stream, &tempScale);
|
||||||
|
|
||||||
|
//if (!new_ph)
|
||||||
|
//{
|
||||||
|
// Polyhedron rPolyhedron = mPolyhedron;
|
||||||
|
// setPolyhedron(rPolyhedron);
|
||||||
|
//}
|
||||||
|
setScale(tempScale);
|
||||||
|
setTransform(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->readFlag()) //SettingsMask
|
||||||
|
{
|
||||||
stream->read(&mVelocityMod);
|
stream->read(&mVelocityMod);
|
||||||
stream->read(&mGravityMod);
|
stream->read(&mGravityMod);
|
||||||
mathRead(*stream, &mAppliedForce);
|
mathRead(*stream, &mAppliedForce);
|
||||||
|
force_type = stream->readInt(FORCE_TYPE_BITS); // AFX
|
||||||
setPolyhedron(tempPH);
|
orient_force = stream->readFlag(); // AFX
|
||||||
setScale(tempScale);
|
|
||||||
setTransform(temp);
|
|
||||||
mActive = stream->readFlag();
|
|
||||||
} else {
|
|
||||||
mActive = stream->readFlag();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stream->readFlag()) //FadeMask
|
||||||
|
{
|
||||||
|
U8 fade_byte;
|
||||||
|
stream->read(&fade_byte);
|
||||||
|
fade_amt = ((F32)fade_byte)/255.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fade_amt = 1.0f;
|
||||||
|
|
||||||
|
mActive = stream->readFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -443,3 +518,104 @@ void PhysicalZone::deactivate()
|
||||||
mActive = false;
|
mActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhysicalZone::onStaticModified(const char* slotName, const char*newValue)
|
||||||
|
{
|
||||||
|
if (dStricmp(slotName, "appliedForce") == 0 || dStricmp(slotName, "forceType") == 0)
|
||||||
|
{
|
||||||
|
switch (force_type)
|
||||||
|
{
|
||||||
|
case SPHERICAL:
|
||||||
|
force_mag = mAppliedForce.magnitudeSafe();
|
||||||
|
break;
|
||||||
|
case CYLINDRICAL:
|
||||||
|
{
|
||||||
|
Point3F force_vec = mAppliedForce;
|
||||||
|
force_vec.z = 0.0;
|
||||||
|
force_mag = force_vec.magnitudeSafe();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point3F& PhysicalZone::getForce(const Point3F* center) const
|
||||||
|
{
|
||||||
|
static Point3F force_vec;
|
||||||
|
|
||||||
|
if (force_type == VECTOR)
|
||||||
|
{
|
||||||
|
if (orient_force)
|
||||||
|
{
|
||||||
|
getTransform().mulV(mAppliedForce, &force_vec);
|
||||||
|
force_vec *= fade_amt;
|
||||||
|
return force_vec;
|
||||||
|
}
|
||||||
|
force_vec = mAppliedForce;
|
||||||
|
force_vec *= fade_amt;
|
||||||
|
return force_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!center)
|
||||||
|
{
|
||||||
|
force_vec.zero();
|
||||||
|
return force_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_type == SPHERICAL)
|
||||||
|
{
|
||||||
|
force_vec = *center - getPosition();
|
||||||
|
force_vec.normalizeSafe();
|
||||||
|
force_vec *= force_mag*fade_amt;
|
||||||
|
return force_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orient_force)
|
||||||
|
{
|
||||||
|
force_vec = *center - getPosition();
|
||||||
|
getWorldTransform().mulV(force_vec);
|
||||||
|
force_vec.z = 0.0f;
|
||||||
|
force_vec.normalizeSafe();
|
||||||
|
force_vec *= force_mag;
|
||||||
|
force_vec.z = mAppliedForce.z;
|
||||||
|
getTransform().mulV(force_vec);
|
||||||
|
force_vec *= fade_amt;
|
||||||
|
return force_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
force_vec = *center - getPosition();
|
||||||
|
force_vec.z = 0.0f;
|
||||||
|
force_vec.normalizeSafe();
|
||||||
|
force_vec *= force_mag;
|
||||||
|
force_vec *= fade_amt;
|
||||||
|
return force_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PhysicalZone::isExcludedObject(SceneObject* obj) const
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < excluded_objects.size(); i++)
|
||||||
|
if (excluded_objects[i] == obj)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicalZone::registerExcludedObject(SceneObject* obj)
|
||||||
|
{
|
||||||
|
if (isExcludedObject(obj))
|
||||||
|
return;
|
||||||
|
|
||||||
|
excluded_objects.push_back(obj);
|
||||||
|
setMaskBits(FadeMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicalZone::unregisterExcludedObject(SceneObject* obj)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < excluded_objects.size(); i++)
|
||||||
|
if (excluded_objects[i] == obj)
|
||||||
|
{
|
||||||
|
excluded_objects.erase(i);
|
||||||
|
setMaskBits(FadeMask);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _H_PHYSICALZONE
|
#ifndef _H_PHYSICALZONE
|
||||||
#define _H_PHYSICALZONE
|
#define _H_PHYSICALZONE
|
||||||
|
|
||||||
|
|
@ -40,9 +45,14 @@ class PhysicalZone : public SceneObject
|
||||||
{
|
{
|
||||||
typedef SceneObject Parent;
|
typedef SceneObject Parent;
|
||||||
|
|
||||||
enum UpdateMasks {
|
enum UpdateMasks {
|
||||||
ActiveMask = Parent::NextFreeMask << 0,
|
ActiveMask = Parent::NextFreeMask << 0,
|
||||||
NextFreeMask = Parent::NextFreeMask << 1
|
SettingsMask = Parent::NextFreeMask << 1,
|
||||||
|
FadeMask = Parent::NextFreeMask << 2,
|
||||||
|
PolyhedronMask = Parent::NextFreeMask << 3,
|
||||||
|
MoveMask = Parent::NextFreeMask << 4,
|
||||||
|
ExclusionMask = Parent::NextFreeMask << 5,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 6
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -83,7 +93,10 @@ class PhysicalZone : public SceneObject
|
||||||
|
|
||||||
inline F32 getVelocityMod() const { return mVelocityMod; }
|
inline F32 getVelocityMod() const { return mVelocityMod; }
|
||||||
inline F32 getGravityMod() const { return mGravityMod; }
|
inline F32 getGravityMod() const { return mGravityMod; }
|
||||||
inline const Point3F& getForce() const { return mAppliedForce; }
|
// the scene object is now passed in to getForce() where
|
||||||
|
// it is needed to calculate the applied force when the
|
||||||
|
// force is radial.
|
||||||
|
const Point3F& getForce(const Point3F* center=0) const;
|
||||||
|
|
||||||
void setPolyhedron(const Polyhedron&);
|
void setPolyhedron(const Polyhedron&);
|
||||||
bool testObject(SceneObject*);
|
bool testObject(SceneObject*);
|
||||||
|
|
@ -96,7 +109,25 @@ class PhysicalZone : public SceneObject
|
||||||
void deactivate();
|
void deactivate();
|
||||||
inline bool isActive() const { return mActive; }
|
inline bool isActive() const { return mActive; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class afxPhysicalZoneData;
|
||||||
|
friend class afxEA_PhysicalZone;
|
||||||
|
Vector<SceneObject*> excluded_objects;
|
||||||
|
S32 force_type;
|
||||||
|
F32 force_mag;
|
||||||
|
bool orient_force;
|
||||||
|
F32 fade_amt;
|
||||||
|
void setFadeAmount(F32 amt) { fade_amt = amt; if (fade_amt < 1.0f) setMaskBits(FadeMask); }
|
||||||
|
public:
|
||||||
|
enum ForceType { VECTOR, SPHERICAL, CYLINDRICAL };
|
||||||
|
enum { FORCE_TYPE_BITS = 2 };
|
||||||
|
virtual void onStaticModified(const char* slotName, const char*newValue = NULL);
|
||||||
|
bool isExcludedObject(SceneObject*) const;
|
||||||
|
void registerExcludedObject(SceneObject*);
|
||||||
|
void unregisterExcludedObject(SceneObject*);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef PhysicalZone::ForceType PhysicalZone_ForceType;
|
||||||
|
DefineEnumType( PhysicalZone_ForceType );
|
||||||
#endif // _H_PHYSICALZONE
|
#endif // _H_PHYSICALZONE
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,10 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/player.h"
|
#include "T3D/player.h"
|
||||||
|
|
||||||
|
|
@ -1656,6 +1660,8 @@ Player::Player()
|
||||||
mLastAbsoluteYaw = 0.0f;
|
mLastAbsoluteYaw = 0.0f;
|
||||||
mLastAbsolutePitch = 0.0f;
|
mLastAbsolutePitch = 0.0f;
|
||||||
mLastAbsoluteRoll = 0.0f;
|
mLastAbsoluteRoll = 0.0f;
|
||||||
|
|
||||||
|
afx_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::~Player()
|
Player::~Player()
|
||||||
|
|
@ -2070,6 +2076,32 @@ void Player::processTick(const Move* move)
|
||||||
}
|
}
|
||||||
|
|
||||||
Parent::processTick(move);
|
Parent::processTick(move);
|
||||||
|
// Check for state changes in the standard move triggers and
|
||||||
|
// set bits for any triggers that switched on this tick in
|
||||||
|
// the fx_s_triggers mask. Flag any changes to be packed to
|
||||||
|
// clients.
|
||||||
|
if (isServerObject())
|
||||||
|
{
|
||||||
|
fx_s_triggers = 0;
|
||||||
|
if (move)
|
||||||
|
{
|
||||||
|
U8 on_bits = 0;
|
||||||
|
for (S32 i = 0; i < MaxTriggerKeys; i++)
|
||||||
|
if (move->trigger[i])
|
||||||
|
on_bits |= BIT(i);
|
||||||
|
|
||||||
|
if (on_bits != move_trigger_states)
|
||||||
|
{
|
||||||
|
U8 switched_on_bits = (on_bits & ~move_trigger_states);
|
||||||
|
if (switched_on_bits)
|
||||||
|
{
|
||||||
|
fx_s_triggers |= (U32)switched_on_bits;
|
||||||
|
setMaskBits(TriggerMask);
|
||||||
|
}
|
||||||
|
move_trigger_states = on_bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Warp to catch up to server
|
// Warp to catch up to server
|
||||||
if (delta.warpTicks > 0) {
|
if (delta.warpTicks > 0) {
|
||||||
delta.warpTicks--;
|
delta.warpTicks--;
|
||||||
|
|
@ -2085,7 +2117,10 @@ void Player::processTick(const Move* move)
|
||||||
else if (delta.rot.z > M_PI_F)
|
else if (delta.rot.z > M_PI_F)
|
||||||
delta.rot.z -= M_2PI_F;
|
delta.rot.z -= M_2PI_F;
|
||||||
|
|
||||||
setPosition(delta.pos,delta.rot);
|
if (!ignore_updates)
|
||||||
|
{
|
||||||
|
setPosition(delta.pos,delta.rot);
|
||||||
|
}
|
||||||
updateDeathOffsets();
|
updateDeathOffsets();
|
||||||
updateLookAnimation();
|
updateLookAnimation();
|
||||||
|
|
||||||
|
|
@ -2183,7 +2218,8 @@ void Player::interpolateTick(F32 dt)
|
||||||
Point3F pos = delta.pos + delta.posVec * dt;
|
Point3F pos = delta.pos + delta.posVec * dt;
|
||||||
Point3F rot = delta.rot + delta.rotVec * dt;
|
Point3F rot = delta.rot + delta.rotVec * dt;
|
||||||
|
|
||||||
setRenderPosition(pos,rot,dt);
|
if (!ignore_updates)
|
||||||
|
setRenderPosition(pos,rot,dt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// apply camera effects - is this the best place? - bramage
|
// apply camera effects - is this the best place? - bramage
|
||||||
|
|
@ -2208,6 +2244,9 @@ void Player::advanceTime(F32 dt)
|
||||||
{
|
{
|
||||||
// Client side animations
|
// Client side animations
|
||||||
Parent::advanceTime(dt);
|
Parent::advanceTime(dt);
|
||||||
|
// Increment timer for triggering idle events.
|
||||||
|
if (idle_timer >= 0.0f)
|
||||||
|
idle_timer += dt;
|
||||||
updateActionThread();
|
updateActionThread();
|
||||||
updateAnimation(dt);
|
updateAnimation(dt);
|
||||||
updateSplash();
|
updateSplash();
|
||||||
|
|
@ -2498,6 +2537,30 @@ AngAxisF gPlayerMoveRot;
|
||||||
|
|
||||||
void Player::updateMove(const Move* move)
|
void Player::updateMove(const Move* move)
|
||||||
{
|
{
|
||||||
|
struct Move my_move;
|
||||||
|
if (override_movement && movement_op < 3)
|
||||||
|
{
|
||||||
|
my_move = *move;
|
||||||
|
switch (movement_op)
|
||||||
|
{
|
||||||
|
case 0: // add
|
||||||
|
my_move.x += movement_data.x;
|
||||||
|
my_move.y += movement_data.y;
|
||||||
|
my_move.z += movement_data.z;
|
||||||
|
break;
|
||||||
|
case 1: // mult
|
||||||
|
my_move.x *= movement_data.x;
|
||||||
|
my_move.y *= movement_data.y;
|
||||||
|
my_move.z *= movement_data.z;
|
||||||
|
break;
|
||||||
|
case 2: // replace
|
||||||
|
my_move.x = movement_data.x;
|
||||||
|
my_move.y = movement_data.y;
|
||||||
|
my_move.z = movement_data.z;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
move = &my_move;
|
||||||
|
}
|
||||||
delta.move = *move;
|
delta.move = *move;
|
||||||
|
|
||||||
#ifdef TORQUE_OPENVR
|
#ifdef TORQUE_OPENVR
|
||||||
|
|
@ -2740,7 +2803,12 @@ void Player::updateMove(const Move* move)
|
||||||
// Desired move direction & speed
|
// Desired move direction & speed
|
||||||
VectorF moveVec;
|
VectorF moveVec;
|
||||||
F32 moveSpeed;
|
F32 moveSpeed;
|
||||||
if ((mState == MoveState || (mState == RecoverState && mDataBlock->recoverRunForceScale > 0.0f)) && mDamageState == Enabled)
|
// If BLOCK_USER_CONTROL is set in anim_clip_flags, the user won't be able to
|
||||||
|
// resume control over the player character. This generally happens for
|
||||||
|
// short periods of time synchronized with script driven animation at places
|
||||||
|
// where it makes sense that user motion is prohibited, such as when the
|
||||||
|
// player is lifted off the ground or knocked down.
|
||||||
|
if ((mState == MoveState || (mState == RecoverState && mDataBlock->recoverRunForceScale > 0.0f)) && mDamageState == Enabled && !isAnimationLocked())
|
||||||
{
|
{
|
||||||
zRot.getColumn(0,&moveVec);
|
zRot.getColumn(0,&moveVec);
|
||||||
moveVec *= (move->x * (mPose == SprintPose ? mDataBlock->sprintStrafeScale : 1.0f));
|
moveVec *= (move->x * (mPose == SprintPose ? mDataBlock->sprintStrafeScale : 1.0f));
|
||||||
|
|
@ -2799,6 +2867,9 @@ void Player::updateMove(const Move* move)
|
||||||
moveSpeed = 0.0f;
|
moveSpeed = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply speed bias here.
|
||||||
|
speed_bias = speed_bias + (speed_bias_goal - speed_bias)*0.1f;
|
||||||
|
moveSpeed *= speed_bias;
|
||||||
// Acceleration due to gravity
|
// Acceleration due to gravity
|
||||||
VectorF acc(0.0f, 0.0f, mGravity * mGravityMod * TickSec);
|
VectorF acc(0.0f, 0.0f, mGravity * mGravityMod * TickSec);
|
||||||
|
|
||||||
|
|
@ -3025,7 +3096,9 @@ void Player::updateMove(const Move* move)
|
||||||
mContactTimer++;
|
mContactTimer++;
|
||||||
|
|
||||||
// Acceleration from Jumping
|
// Acceleration from Jumping
|
||||||
if (move->trigger[sJumpTrigger] && canJump())// !isMounted() &&
|
// While BLOCK_USER_CONTROL is set in anim_clip_flags, the user won't be able to
|
||||||
|
// make the player character jump.
|
||||||
|
if (move->trigger[sJumpTrigger] && canJump() && !isAnimationLocked())
|
||||||
{
|
{
|
||||||
// Scale the jump impulse base on maxJumpSpeed
|
// Scale the jump impulse base on maxJumpSpeed
|
||||||
F32 zSpeedScale = mVelocity.z;
|
F32 zSpeedScale = mVelocity.z;
|
||||||
|
|
@ -3076,6 +3149,9 @@ void Player::updateMove(const Move* move)
|
||||||
setActionThread( seq, true, false, true );
|
setActionThread( seq, true, false, true );
|
||||||
|
|
||||||
mJumpSurfaceLastContact = JumpSkipContactsMax;
|
mJumpSurfaceLastContact = JumpSkipContactsMax;
|
||||||
|
// Flag the jump event trigger.
|
||||||
|
fx_s_triggers |= PLAYER_JUMP_S_TRIGGER;
|
||||||
|
setMaskBits(TriggerMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -3493,6 +3569,19 @@ void Player::updateDamageState()
|
||||||
|
|
||||||
void Player::updateLookAnimation(F32 dt)
|
void Player::updateLookAnimation(F32 dt)
|
||||||
{
|
{
|
||||||
|
// If the preference setting overrideLookAnimation is true, the player's
|
||||||
|
// arm and head no longer animate according to the view direction. They
|
||||||
|
// are instead given fixed positions.
|
||||||
|
if (overrideLookAnimation)
|
||||||
|
{
|
||||||
|
if (mArmAnimation.thread)
|
||||||
|
mShapeInstance->setPos(mArmAnimation.thread, armLookOverridePos);
|
||||||
|
if (mHeadVThread)
|
||||||
|
mShapeInstance->setPos(mHeadVThread, headVLookOverridePos);
|
||||||
|
if (mHeadHThread)
|
||||||
|
mShapeInstance->setPos(mHeadHThread, headHLookOverridePos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Calculate our interpolated head position.
|
// Calculate our interpolated head position.
|
||||||
Point3F renderHead = delta.head + delta.headVec * dt;
|
Point3F renderHead = delta.head + delta.headVec * dt;
|
||||||
|
|
||||||
|
|
@ -3533,6 +3622,8 @@ void Player::updateLookAnimation(F32 dt)
|
||||||
|
|
||||||
bool Player::inDeathAnim()
|
bool Player::inDeathAnim()
|
||||||
{
|
{
|
||||||
|
if ((anim_clip_flags & ANIM_OVERRIDDEN) != 0 && (anim_clip_flags & IS_DEATH_ANIM) == 0)
|
||||||
|
return false;
|
||||||
if (mActionAnimation.thread && mActionAnimation.action >= 0)
|
if (mActionAnimation.thread && mActionAnimation.action >= 0)
|
||||||
if (mActionAnimation.action < mDataBlock->actionCount)
|
if (mActionAnimation.action < mDataBlock->actionCount)
|
||||||
return mDataBlock->actionList[mActionAnimation.action].death;
|
return mDataBlock->actionList[mActionAnimation.action].death;
|
||||||
|
|
@ -3742,6 +3833,8 @@ bool Player::setArmThread(U32 action)
|
||||||
|
|
||||||
bool Player::setActionThread(const char* sequence,bool hold,bool wait,bool fsp)
|
bool Player::setActionThread(const char* sequence,bool hold,bool wait,bool fsp)
|
||||||
{
|
{
|
||||||
|
if (anim_clip_flags & ANIM_OVERRIDDEN)
|
||||||
|
return false;
|
||||||
for (U32 i = 1; i < mDataBlock->actionCount; i++)
|
for (U32 i = 1; i < mDataBlock->actionCount; i++)
|
||||||
{
|
{
|
||||||
PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
|
PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
|
||||||
|
|
@ -3766,6 +3859,11 @@ void Player::setActionThread(U32 action,bool forward,bool hold,bool wait,bool fs
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isClientObject())
|
||||||
|
{
|
||||||
|
mark_idle = (action == PlayerData::RootAnim);
|
||||||
|
idle_timer = (mark_idle) ? 0.0f : -1.0f;
|
||||||
|
}
|
||||||
PlayerData::ActionAnimation &anim = mDataBlock->actionList[action];
|
PlayerData::ActionAnimation &anim = mDataBlock->actionList[action];
|
||||||
if (anim.sequence != -1)
|
if (anim.sequence != -1)
|
||||||
{
|
{
|
||||||
|
|
@ -3858,7 +3956,8 @@ void Player::updateActionThread()
|
||||||
offset = mDataBlock->decalOffset * getScale().x;
|
offset = mDataBlock->decalOffset * getScale().x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( triggeredLeft || triggeredRight )
|
process_client_triggers(triggeredLeft, triggeredRight);
|
||||||
|
if ((triggeredLeft || triggeredRight) && !noFootfallFX)
|
||||||
{
|
{
|
||||||
Point3F rot, pos;
|
Point3F rot, pos;
|
||||||
RayInfo rInfo;
|
RayInfo rInfo;
|
||||||
|
|
@ -3875,7 +3974,7 @@ void Player::updateActionThread()
|
||||||
// Put footprints on surface, if appropriate for material.
|
// Put footprints on surface, if appropriate for material.
|
||||||
|
|
||||||
if( material && material->mShowFootprints
|
if( material && material->mShowFootprints
|
||||||
&& mDataBlock->decalData )
|
&& mDataBlock->decalData && !footfallDecalOverride )
|
||||||
{
|
{
|
||||||
Point3F normal;
|
Point3F normal;
|
||||||
Point3F tangent;
|
Point3F tangent;
|
||||||
|
|
@ -3886,8 +3985,8 @@ void Player::updateActionThread()
|
||||||
|
|
||||||
// Emit footpuffs.
|
// Emit footpuffs.
|
||||||
|
|
||||||
if( rInfo.t <= 0.5 && mWaterCoverage == 0.0
|
if (!footfallDustOverride && rInfo.t <= 0.5f && mWaterCoverage == 0.0f
|
||||||
&& material && material->mShowDust )
|
&& material && material->mShowDust )
|
||||||
{
|
{
|
||||||
// New emitter every time for visibility reasons
|
// New emitter every time for visibility reasons
|
||||||
ParticleEmitter * emitter = new ParticleEmitter;
|
ParticleEmitter * emitter = new ParticleEmitter;
|
||||||
|
|
@ -3920,6 +4019,7 @@ void Player::updateActionThread()
|
||||||
|
|
||||||
// Play footstep sound.
|
// Play footstep sound.
|
||||||
|
|
||||||
|
if (footfallSoundOverride <= 0)
|
||||||
playFootstepSound( triggeredLeft, material, rInfo.object );
|
playFootstepSound( triggeredLeft, material, rInfo.object );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3941,8 +4041,10 @@ void Player::updateActionThread()
|
||||||
pickActionAnimation();
|
pickActionAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prevent scaling of AFX picked actions
|
||||||
if ( (mActionAnimation.action != PlayerData::LandAnim) &&
|
if ( (mActionAnimation.action != PlayerData::LandAnim) &&
|
||||||
(mActionAnimation.action != PlayerData::NullAnimation) )
|
(mActionAnimation.action != PlayerData::NullAnimation) &&
|
||||||
|
!(anim_clip_flags & ANIM_OVERRIDDEN))
|
||||||
{
|
{
|
||||||
// Update action animation time scale to match ground velocity
|
// Update action animation time scale to match ground velocity
|
||||||
PlayerData::ActionAnimation &anim =
|
PlayerData::ActionAnimation &anim =
|
||||||
|
|
@ -4560,6 +4662,10 @@ void Player::updateAnimation(F32 dt)
|
||||||
if (mImageStateThread)
|
if (mImageStateThread)
|
||||||
mShapeInstance->advanceTime(dt,mImageStateThread);
|
mShapeInstance->advanceTime(dt,mImageStateThread);
|
||||||
|
|
||||||
|
// update any active blend clips
|
||||||
|
if (isGhost())
|
||||||
|
for (S32 i = 0; i < blend_clips.size(); i++)
|
||||||
|
mShapeInstance->advanceTime(dt, blend_clips[i].thread);
|
||||||
// If we are the client's player on this machine, then we need
|
// If we are the client's player on this machine, then we need
|
||||||
// to make sure the transforms are up to date as they are used
|
// to make sure the transforms are up to date as they are used
|
||||||
// to setup the camera.
|
// to setup the camera.
|
||||||
|
|
@ -4573,6 +4679,11 @@ void Player::updateAnimation(F32 dt)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
updateAnimationTree(false);
|
updateAnimationTree(false);
|
||||||
|
// This addition forces recently visible players to animate their
|
||||||
|
// skeleton now rather than in pre-render so that constrained effects
|
||||||
|
// get up-to-date node transforms.
|
||||||
|
if (didRenderLastRender())
|
||||||
|
mShapeInstance->animate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4878,6 +4989,11 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol )
|
||||||
// we can use it to do impacts
|
// we can use it to do impacts
|
||||||
// and query collision.
|
// and query collision.
|
||||||
*outCol = *collision;
|
*outCol = *collision;
|
||||||
|
if (isServerObject() && bd > 6.8f && collision->normal.z > 0.7f)
|
||||||
|
{
|
||||||
|
fx_s_triggers |= PLAYER_LANDING_S_TRIGGER;
|
||||||
|
setMaskBits(TriggerMask);
|
||||||
|
}
|
||||||
|
|
||||||
// Subtract out velocity
|
// Subtract out velocity
|
||||||
VectorF dv = collision->normal * (bd + sNormalElasticity);
|
VectorF dv = collision->normal * (bd + sNormalElasticity);
|
||||||
|
|
@ -5879,7 +5995,12 @@ void Player::applyImpulse(const Point3F&,const VectorF& vec)
|
||||||
|
|
||||||
bool Player::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
|
bool Player::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
|
||||||
{
|
{
|
||||||
if (getDamageState() != Enabled)
|
// In standard Torque there's a rather brute force culling of all
|
||||||
|
// non-enabled players (corpses) from the ray cast. But, to
|
||||||
|
// demonstrate a resurrection spell, we need corpses to be
|
||||||
|
// selectable, so this code change allows consideration of corpses
|
||||||
|
// in the ray cast if corpsesHiddenFromRayCast is set to false.
|
||||||
|
if (sCorpsesHiddenFromRayCast && getDamageState() != Enabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Collide against bounding box. Need at least this for the editor.
|
// Collide against bounding box. Need at least this for the editor.
|
||||||
|
|
@ -6146,7 +6267,8 @@ void Player::readPacketData(GameConnection *connection, BitStream *stream)
|
||||||
stream->read(&mHead.z);
|
stream->read(&mHead.z);
|
||||||
stream->read(&rot.z);
|
stream->read(&rot.z);
|
||||||
rot.x = rot.y = 0;
|
rot.x = rot.y = 0;
|
||||||
setPosition(pos,rot);
|
if (!ignore_updates)
|
||||||
|
setPosition(pos,rot);
|
||||||
delta.head = mHead;
|
delta.head = mHead;
|
||||||
delta.rot = rot;
|
delta.rot = rot;
|
||||||
|
|
||||||
|
|
@ -6188,6 +6310,7 @@ U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||||
mArmAnimation.action != mDataBlock->lookAction))) {
|
mArmAnimation.action != mDataBlock->lookAction))) {
|
||||||
stream->writeInt(mArmAnimation.action,PlayerData::ActionAnimBits);
|
stream->writeInt(mArmAnimation.action,PlayerData::ActionAnimBits);
|
||||||
}
|
}
|
||||||
|
retMask = afx_packUpdate(con, mask, stream, retMask);
|
||||||
|
|
||||||
// The rest of the data is part of the control object packet update.
|
// The rest of the data is part of the control object packet update.
|
||||||
// If we're controlled by this client, we don't need to send it.
|
// If we're controlled by this client, we don't need to send it.
|
||||||
|
|
@ -6292,6 +6415,7 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
mArmAnimation.action = action;
|
mArmAnimation.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afx_unpackUpdate(con, stream);
|
||||||
// Done if controlled by client ( and not initial update )
|
// Done if controlled by client ( and not initial update )
|
||||||
if(stream->readFlag())
|
if(stream->readFlag())
|
||||||
return;
|
return;
|
||||||
|
|
@ -6391,7 +6515,8 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
}
|
}
|
||||||
delta.pos = pos;
|
delta.pos = pos;
|
||||||
delta.rot = rot;
|
delta.rot = rot;
|
||||||
setPosition(pos,rot);
|
if (!ignore_updates)
|
||||||
|
setPosition(pos,rot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -6403,7 +6528,8 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
delta.rotVec.set(0.0f, 0.0f, 0.0f);
|
delta.rotVec.set(0.0f, 0.0f, 0.0f);
|
||||||
delta.warpTicks = 0;
|
delta.warpTicks = 0;
|
||||||
delta.dt = 0.0f;
|
delta.dt = 0.0f;
|
||||||
setPosition(pos,rot);
|
if (!ignore_updates)
|
||||||
|
setPosition(pos,rot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
F32 energy = stream->readFloat(EnergyLevelBits) * mDataBlock->maxEnergy;
|
F32 energy = stream->readFloat(EnergyLevelBits) * mDataBlock->maxEnergy;
|
||||||
|
|
@ -6819,6 +6945,7 @@ void Player::consoleInit()
|
||||||
Con::addVariable("$player::extendedMoveHeadPosRotIndex", TypeS32, &smExtendedMoveHeadPosRotIndex,
|
Con::addVariable("$player::extendedMoveHeadPosRotIndex", TypeS32, &smExtendedMoveHeadPosRotIndex,
|
||||||
"@brief The ExtendedMove position/rotation index used for head movements.\n\n"
|
"@brief The ExtendedMove position/rotation index used for head movements.\n\n"
|
||||||
"@ingroup GameObjects\n");
|
"@ingroup GameObjects\n");
|
||||||
|
afx_consoleInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
@ -6863,6 +6990,8 @@ void Player::calcClassRenderData()
|
||||||
|
|
||||||
void Player::playFootstepSound( bool triggeredLeft, Material* contactMaterial, SceneObject* contactObject )
|
void Player::playFootstepSound( bool triggeredLeft, Material* contactMaterial, SceneObject* contactObject )
|
||||||
{
|
{
|
||||||
|
if (footfallSoundOverride > 0)
|
||||||
|
return;
|
||||||
MatrixF footMat = getTransform();
|
MatrixF footMat = getTransform();
|
||||||
if( mWaterCoverage > 0.0 )
|
if( mWaterCoverage > 0.0 )
|
||||||
{
|
{
|
||||||
|
|
@ -7172,6 +7301,340 @@ void Player::renderConvex( ObjectRenderInst *ri, SceneRenderState *state, BaseMa
|
||||||
GFX->leaveDebugEvent();
|
GFX->leaveDebugEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool Player::sCorpsesHiddenFromRayCast = true; // this default matches stock Torque behavior.
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Player::afx_consoleInit()
|
||||||
|
{
|
||||||
|
Con::addVariable("pref::Player::corpsesHiddenFromRayCast", TypeBool, &sCorpsesHiddenFromRayCast);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::afx_init()
|
||||||
|
{
|
||||||
|
overrideLookAnimation = false;
|
||||||
|
armLookOverridePos = 0.5f;
|
||||||
|
headVLookOverridePos = 0.5f;
|
||||||
|
headHLookOverridePos = 0.5f;
|
||||||
|
ignore_updates = false;
|
||||||
|
fx_c_triggers = 0;
|
||||||
|
mark_fx_c_triggers = 0;
|
||||||
|
fx_s_triggers = 0;
|
||||||
|
move_trigger_states = 0;
|
||||||
|
z_velocity = 0.0f;
|
||||||
|
mark_idle = false;
|
||||||
|
idle_timer = 0.0f;
|
||||||
|
mark_s_landing = false;
|
||||||
|
speed_bias = 1.0f;
|
||||||
|
speed_bias_goal = 1.0f;
|
||||||
|
override_movement = 0;
|
||||||
|
movement_data.zero();
|
||||||
|
movement_op = 1;
|
||||||
|
last_movement_tag = 0;
|
||||||
|
footfallDecalOverride = 0;
|
||||||
|
footfallSoundOverride = 0;
|
||||||
|
footfallDustOverride = 0;
|
||||||
|
noFootfallFX = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 Player::afx_packUpdate(NetConnection* con, U32 mask, BitStream* stream, U32 retMask)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (stream->writeFlag(mask & LookOverrideMask))
|
||||||
|
#else
|
||||||
|
if (stream->writeFlag(mask & ActionMask))
|
||||||
|
#endif
|
||||||
|
stream->writeFlag(overrideLookAnimation);
|
||||||
|
|
||||||
|
if (stream->writeFlag(mask & TriggerMask))
|
||||||
|
stream->write(fx_s_triggers);
|
||||||
|
|
||||||
|
return retMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::afx_unpackUpdate(NetConnection* con, BitStream* stream)
|
||||||
|
{
|
||||||
|
if (stream->readFlag()) // LookOverrideMask
|
||||||
|
overrideLookAnimation = stream->readFlag();
|
||||||
|
|
||||||
|
if (stream->readFlag()) // TriggerMask
|
||||||
|
{
|
||||||
|
U32 mask;
|
||||||
|
stream->read(&mask);
|
||||||
|
mark_fx_c_triggers = mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code for overriding player's animation with sequences selected by the
|
||||||
|
// anim-clip component effect.
|
||||||
|
|
||||||
|
void Player::restoreAnimation(U32 tag)
|
||||||
|
{
|
||||||
|
// check if this is a blended clip
|
||||||
|
if ((tag & BLENDED_CLIP) != 0)
|
||||||
|
{
|
||||||
|
restoreBlendAnimation(tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag != 0 && tag == last_anim_tag)
|
||||||
|
{
|
||||||
|
bool is_death_anim = ((anim_clip_flags & IS_DEATH_ANIM) != 0);
|
||||||
|
|
||||||
|
anim_clip_flags &= ~(ANIM_OVERRIDDEN | IS_DEATH_ANIM);
|
||||||
|
|
||||||
|
if (isClientObject())
|
||||||
|
{
|
||||||
|
if (mDamageState != Enabled)
|
||||||
|
{
|
||||||
|
if (!is_death_anim)
|
||||||
|
{
|
||||||
|
// this is a bit hardwired and desperate,
|
||||||
|
// but if he's dead he needs to look like it.
|
||||||
|
setActionThread("death10", false, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mState != MoveState)
|
||||||
|
{
|
||||||
|
// not sure what happens here
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pickActionAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_anim_tag = 0;
|
||||||
|
last_anim_id = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 Player::getAnimationID(const char* name)
|
||||||
|
{
|
||||||
|
for (U32 i = 0; i < mDataBlock->actionCount; i++)
|
||||||
|
{
|
||||||
|
PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
|
||||||
|
if (dStricmp(anim.name, name) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::errorf("Player::getAnimationID() -- Player does not contain a sequence that matches the name, %s.", name);
|
||||||
|
return BAD_ANIM_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 Player::playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim)
|
||||||
|
{
|
||||||
|
if (anim_id == BAD_ANIM_ID)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
S32 seq_id = mDataBlock->actionList[anim_id].sequence;
|
||||||
|
if (seq_id == -1)
|
||||||
|
{
|
||||||
|
Con::errorf("Player::playAnimation() problem. BAD_SEQ_ID");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mShapeInstance->getShape()->sequences[seq_id].isBlend())
|
||||||
|
return playBlendAnimation(seq_id, pos, rate);
|
||||||
|
|
||||||
|
if (isClientObject())
|
||||||
|
{
|
||||||
|
PlayerData::ActionAnimation &anim = mDataBlock->actionList[anim_id];
|
||||||
|
if (anim.sequence != -1)
|
||||||
|
{
|
||||||
|
mActionAnimation.action = anim_id;
|
||||||
|
mActionAnimation.forward = (rate >= 0);
|
||||||
|
mActionAnimation.firstPerson = false;
|
||||||
|
mActionAnimation.holdAtEnd = hold;
|
||||||
|
mActionAnimation.waitForEnd = hold? true: wait;
|
||||||
|
mActionAnimation.animateOnServer = false;
|
||||||
|
mActionAnimation.atEnd = false;
|
||||||
|
mActionAnimation.delayTicks = (S32)sNewAnimationTickTime;
|
||||||
|
|
||||||
|
F32 transTime = (trans < 0) ? sAnimationTransitionTime : trans;
|
||||||
|
|
||||||
|
mShapeInstance->setTimeScale(mActionAnimation.thread, rate);
|
||||||
|
mShapeInstance->transitionToSequence(mActionAnimation.thread,anim.sequence,
|
||||||
|
pos, transTime, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_death_anim)
|
||||||
|
anim_clip_flags |= IS_DEATH_ANIM;
|
||||||
|
else
|
||||||
|
anim_clip_flags &= ~IS_DEATH_ANIM;
|
||||||
|
|
||||||
|
anim_clip_flags |= ANIM_OVERRIDDEN;
|
||||||
|
last_anim_tag = unique_anim_tag_counter++;
|
||||||
|
last_anim_id = anim_id;
|
||||||
|
|
||||||
|
return last_anim_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 Player::getAnimationDurationByID(U32 anim_id)
|
||||||
|
{
|
||||||
|
if (anim_id == BAD_ANIM_ID)
|
||||||
|
return 0.0f;
|
||||||
|
S32 seq_id = mDataBlock->actionList[anim_id].sequence;
|
||||||
|
if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
|
||||||
|
return mDataBlock->mShape->sequences[seq_id].duration;
|
||||||
|
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Player::isBlendAnimation(const char* name)
|
||||||
|
{
|
||||||
|
U32 anim_id = getAnimationID(name);
|
||||||
|
if (anim_id == BAD_ANIM_ID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
S32 seq_id = mDataBlock->actionList[anim_id].sequence;
|
||||||
|
if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
|
||||||
|
return mDataBlock->mShape->sequences[seq_id].isBlend();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* Player::getLastClipName(U32 clip_tag)
|
||||||
|
{
|
||||||
|
if (clip_tag != last_anim_tag || last_anim_id >= PlayerData::NumActionAnims)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return mDataBlock->actionList[last_anim_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::unlockAnimation(U32 tag, bool force)
|
||||||
|
{
|
||||||
|
if ((tag != 0 && tag == last_anim_lock_tag) || force)
|
||||||
|
anim_clip_flags &= ~BLOCK_USER_CONTROL;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 Player::lockAnimation()
|
||||||
|
{
|
||||||
|
anim_clip_flags |= BLOCK_USER_CONTROL;
|
||||||
|
last_anim_lock_tag = unique_anim_tag_counter++;
|
||||||
|
|
||||||
|
return last_anim_lock_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(Player, isAnimationLocked, bool, 2, 2, "isAnimationLocked()")
|
||||||
|
{
|
||||||
|
return object->isAnimationLocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Player::setLookAnimationOverride(bool flag)
|
||||||
|
{
|
||||||
|
overrideLookAnimation = flag;
|
||||||
|
#if 0
|
||||||
|
setMaskBits(LookOverrideMask);
|
||||||
|
#else
|
||||||
|
setMaskBits(ActionMask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(Player, setLookAnimationOverride, void, 3, 3, "setLookAnimationOverride(flag)")
|
||||||
|
{
|
||||||
|
object->setLookAnimationOverride(dAtob(argv[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(Player, copyHeadRotation, void, 3, 3, "copyHeadRotation(other_player)")
|
||||||
|
{
|
||||||
|
Player* other_player = dynamic_cast<Player*>(Sim::findObject(argv[2]));
|
||||||
|
if (other_player)
|
||||||
|
object->copyHeadRotation(other_player);
|
||||||
|
}
|
||||||
|
void Player::process_client_triggers(bool triggeredLeft, bool triggeredRight)
|
||||||
|
{
|
||||||
|
bool mark_landing = false;
|
||||||
|
Point3F my_vel = getVelocity();
|
||||||
|
if (my_vel.z > 5.0f)
|
||||||
|
z_velocity = 1;
|
||||||
|
else if (my_vel.z < -5.0f)
|
||||||
|
z_velocity = -1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (z_velocity < 0)
|
||||||
|
mark_landing = true;
|
||||||
|
z_velocity = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_c_triggers = mark_fx_c_triggers;
|
||||||
|
if (triggeredLeft)
|
||||||
|
fx_c_triggers |= PLAYER_LF_FOOT_C_TRIGGER;
|
||||||
|
if (triggeredRight)
|
||||||
|
fx_c_triggers |= PLAYER_RT_FOOT_C_TRIGGER;
|
||||||
|
if (mark_landing)
|
||||||
|
fx_c_triggers |= PLAYER_LANDING_C_TRIGGER;
|
||||||
|
if (idle_timer > 10.0f)
|
||||||
|
{
|
||||||
|
fx_c_triggers |= PLAYER_IDLE_C_TRIGGER;
|
||||||
|
idle_timer = 0.0f;
|
||||||
|
}
|
||||||
|
if (fx_c_triggers & PLAYER_LANDING_S_TRIGGER)
|
||||||
|
{
|
||||||
|
fx_c_triggers &= ~(PLAYER_LANDING_S_TRIGGER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
U32 Player::unique_movement_tag_counter = 1;
|
||||||
|
|
||||||
|
void Player::setMovementSpeedBias(F32 bias)
|
||||||
|
{
|
||||||
|
speed_bias_goal = bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 Player::setMovementOverride(F32 bias, const Point3F* mov, U32 op)
|
||||||
|
{
|
||||||
|
if (mov)
|
||||||
|
{
|
||||||
|
movement_data = *mov;
|
||||||
|
override_movement = true;
|
||||||
|
movement_op = (U8)op;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
override_movement = false;
|
||||||
|
|
||||||
|
speed_bias_goal = bias;
|
||||||
|
|
||||||
|
last_movement_tag = unique_movement_tag_counter++;
|
||||||
|
return last_movement_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::restoreMovement(U32 tag)
|
||||||
|
{
|
||||||
|
if (tag != 0 && tag == last_movement_tag)
|
||||||
|
{
|
||||||
|
speed_bias_goal = 1.0;
|
||||||
|
override_movement = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(Player, setMovementSpeedBias, void, 3, 3, "setMovementSpeedBias(F32 bias)")
|
||||||
|
{
|
||||||
|
object->setMovementSpeedBias(dAtof(argv[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::overrideFootfallFX(bool decals, bool sounds, bool dust)
|
||||||
|
{
|
||||||
|
if (decals)
|
||||||
|
footfallDecalOverride++;
|
||||||
|
if (sounds)
|
||||||
|
footfallSoundOverride++;
|
||||||
|
if (dust)
|
||||||
|
footfallDustOverride++;
|
||||||
|
noFootfallFX = (footfallDecalOverride > 0 && footfallSoundOverride > 0 && footfallDustOverride > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::restoreFootfallFX(bool decals, bool sounds, bool dust)
|
||||||
|
{
|
||||||
|
if (decals && footfallDecalOverride)
|
||||||
|
footfallDecalOverride--;
|
||||||
|
if (sounds && footfallSoundOverride)
|
||||||
|
footfallSoundOverride--;
|
||||||
|
if (dust && footfallDustOverride)
|
||||||
|
footfallDustOverride--;
|
||||||
|
noFootfallFX = (footfallDecalOverride > 0 && footfallSoundOverride > 0 && footfallDustOverride > 0);
|
||||||
|
}
|
||||||
#ifdef TORQUE_OPENVR
|
#ifdef TORQUE_OPENVR
|
||||||
void Player::setControllers(Vector<OpenVRTrackedObject*> controllerList)
|
void Player::setControllers(Vector<OpenVRTrackedObject*> controllerList)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _PLAYER_H_
|
#ifndef _PLAYER_H_
|
||||||
#define _PLAYER_H_
|
#define _PLAYER_H_
|
||||||
|
|
||||||
|
|
@ -401,7 +406,8 @@ protected:
|
||||||
ActionMask = Parent::NextFreeMask << 0,
|
ActionMask = Parent::NextFreeMask << 0,
|
||||||
MoveMask = Parent::NextFreeMask << 1,
|
MoveMask = Parent::NextFreeMask << 1,
|
||||||
ImpactMask = Parent::NextFreeMask << 2,
|
ImpactMask = Parent::NextFreeMask << 2,
|
||||||
NextFreeMask = Parent::NextFreeMask << 3
|
TriggerMask = Parent::NextFreeMask << 3,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 4
|
||||||
};
|
};
|
||||||
|
|
||||||
SimObjectPtr<ParticleEmitter> mSplashEmitter[PlayerData::NUM_SPLASH_EMITTERS];
|
SimObjectPtr<ParticleEmitter> mSplashEmitter[PlayerData::NUM_SPLASH_EMITTERS];
|
||||||
|
|
@ -780,6 +786,89 @@ public:
|
||||||
virtual void prepRenderImage( SceneRenderState* state );
|
virtual void prepRenderImage( SceneRenderState* state );
|
||||||
virtual void renderConvex( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
|
virtual void renderConvex( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
|
||||||
virtual void renderMountedImage( U32 imageSlot, TSRenderState &rstate, SceneRenderState *state );
|
virtual void renderMountedImage( U32 imageSlot, TSRenderState &rstate, SceneRenderState *state );
|
||||||
|
private:
|
||||||
|
static void afx_consoleInit();
|
||||||
|
void afx_init();
|
||||||
|
U32 afx_packUpdate(NetConnection*, U32 mask, BitStream*, U32 retMask);
|
||||||
|
void afx_unpackUpdate(NetConnection*, BitStream*);
|
||||||
|
private:
|
||||||
|
static bool sCorpsesHiddenFromRayCast;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void restoreAnimation(U32 tag);
|
||||||
|
virtual U32 getAnimationID(const char* name);
|
||||||
|
virtual U32 playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim);
|
||||||
|
virtual F32 getAnimationDurationByID(U32 anim_id);
|
||||||
|
virtual bool isBlendAnimation(const char* name);
|
||||||
|
virtual const char* getLastClipName(U32 clip_tag);
|
||||||
|
virtual void unlockAnimation(U32 tag, bool force=false);
|
||||||
|
virtual U32 lockAnimation();
|
||||||
|
virtual bool isAnimationLocked() const { return ((anim_clip_flags & BLOCK_USER_CONTROL) != 0); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool overrideLookAnimation;
|
||||||
|
F32 armLookOverridePos;
|
||||||
|
F32 headVLookOverridePos;
|
||||||
|
F32 headHLookOverridePos;
|
||||||
|
public:
|
||||||
|
void setLookAnimationOverride(bool flag);
|
||||||
|
void copyHeadRotation(const Player* p) { mHead = p->mHead; }
|
||||||
|
public:
|
||||||
|
bool ignore_updates;
|
||||||
|
void resetContactTimer() { mContactTimer = 0; }
|
||||||
|
private:
|
||||||
|
U8 move_trigger_states;
|
||||||
|
U32 fx_s_triggers;
|
||||||
|
U32 mark_fx_c_triggers;
|
||||||
|
U32 fx_c_triggers;
|
||||||
|
F32 z_velocity;
|
||||||
|
bool mark_idle;
|
||||||
|
F32 idle_timer;
|
||||||
|
bool mark_s_landing;
|
||||||
|
void process_client_triggers(bool triggeredLeft, bool triggeredRight);
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
// server events
|
||||||
|
PLAYER_MOVE_TRIGGER_0 = BIT(0),
|
||||||
|
PLAYER_MOVE_TRIGGER_1 = BIT(1),
|
||||||
|
PLAYER_MOVE_TRIGGER_2 = BIT(2),
|
||||||
|
PLAYER_MOVE_TRIGGER_3 = BIT(3),
|
||||||
|
PLAYER_MOVE_TRIGGER_4 = BIT(4),
|
||||||
|
PLAYER_MOVE_TRIGGER_5 = BIT(5),
|
||||||
|
PLAYER_LANDING_S_TRIGGER = BIT(6),
|
||||||
|
|
||||||
|
PLAYER_FIRE_S_TRIGGER = PLAYER_MOVE_TRIGGER_0,
|
||||||
|
PLAYER_FIRE_ALT_S_TRIGGER = PLAYER_MOVE_TRIGGER_1,
|
||||||
|
PLAYER_JUMP_S_TRIGGER = BIT(7),
|
||||||
|
|
||||||
|
// client events
|
||||||
|
PLAYER_LF_FOOT_C_TRIGGER = BIT(16),
|
||||||
|
PLAYER_RT_FOOT_C_TRIGGER = BIT(17),
|
||||||
|
PLAYER_LANDING_C_TRIGGER = BIT(18),
|
||||||
|
PLAYER_IDLE_C_TRIGGER = BIT(19),
|
||||||
|
};
|
||||||
|
U32 getClientEventTriggers() const { return fx_c_triggers; }
|
||||||
|
U32 getServerEventTriggers() const { return fx_s_triggers; }
|
||||||
|
private:
|
||||||
|
F32 speed_bias;
|
||||||
|
F32 speed_bias_goal;
|
||||||
|
bool override_movement;
|
||||||
|
Point3F movement_data;
|
||||||
|
U8 movement_op;
|
||||||
|
U32 last_movement_tag;
|
||||||
|
static U32 unique_movement_tag_counter;
|
||||||
|
public:
|
||||||
|
void setMovementSpeedBias(F32 bias);
|
||||||
|
U32 setMovementOverride(F32 bias, const Point3F* mov=0, U32 op=1);
|
||||||
|
void restoreMovement(U32 tag);
|
||||||
|
private:
|
||||||
|
S32 footfallDecalOverride;
|
||||||
|
S32 footfallSoundOverride;
|
||||||
|
S32 footfallDustOverride;
|
||||||
|
bool noFootfallFX;
|
||||||
|
public:
|
||||||
|
void overrideFootfallFX(bool decals=true, bool sounds=true, bool dust=true);
|
||||||
|
void restoreFootfallFX(bool decals=true, bool sounds=true, bool dust=true);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Player::Pose PlayerPose;
|
typedef Player::Pose PlayerPose;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/projectile.h"
|
#include "T3D/projectile.h"
|
||||||
|
|
||||||
|
|
@ -190,6 +195,40 @@ ProjectileData::ProjectileData()
|
||||||
lightDescId = 0;
|
lightDescId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProjectileData::ProjectileData(const ProjectileData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
projectileShapeName = other.projectileShapeName;
|
||||||
|
faceViewer = other.faceViewer; // -- always set to false
|
||||||
|
scale = other.scale;
|
||||||
|
velInheritFactor = other.velInheritFactor;
|
||||||
|
muzzleVelocity = other.muzzleVelocity;
|
||||||
|
impactForce = other.impactForce;
|
||||||
|
isBallistic = other.isBallistic;
|
||||||
|
bounceElasticity = other.bounceElasticity;
|
||||||
|
bounceFriction = other.bounceFriction;
|
||||||
|
gravityMod = other.gravityMod;
|
||||||
|
lifetime = other.lifetime;
|
||||||
|
armingDelay = other.armingDelay;
|
||||||
|
fadeDelay = other.fadeDelay;
|
||||||
|
explosion = other.explosion;
|
||||||
|
explosionId = other.explosionId; // -- for pack/unpack of explosion ptr
|
||||||
|
waterExplosion = other.waterExplosion;
|
||||||
|
waterExplosionId = other.waterExplosionId; // -- for pack/unpack of waterExplosion ptr
|
||||||
|
splash = other.splash;
|
||||||
|
splashId = other.splashId; // -- for pack/unpack of splash ptr
|
||||||
|
decal = other.decal;
|
||||||
|
decalId = other.decalId; // -- for pack/unpack of decal ptr
|
||||||
|
sound = other.sound;
|
||||||
|
lightDesc = other.lightDesc;
|
||||||
|
lightDescId = other.lightDescId; // -- for pack/unpack of lightDesc ptr
|
||||||
|
projectileShape = other.projectileShape; // -- TSShape loads using projectileShapeName
|
||||||
|
activateSeq = other.activateSeq; // -- from projectileShape sequence "activate"
|
||||||
|
maintainSeq = other.maintainSeq; // -- from projectileShape sequence "maintain"
|
||||||
|
particleEmitter = other.particleEmitter;
|
||||||
|
particleEmitterId = other.particleEmitterId; // -- for pack/unpack of particleEmitter ptr
|
||||||
|
particleWaterEmitter = other.particleWaterEmitter;
|
||||||
|
particleWaterEmitterId = other.particleWaterEmitterId; // -- for pack/unpack of particleWaterEmitter ptr
|
||||||
|
}
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
void ProjectileData::initPersistFields()
|
void ProjectileData::initPersistFields()
|
||||||
|
|
@ -274,6 +313,13 @@ void ProjectileData::initPersistFields()
|
||||||
"A value of 1.0 will assume \"normal\" influence upon it.\n"
|
"A value of 1.0 will assume \"normal\" influence upon it.\n"
|
||||||
"The magnitude of gravity is assumed to be 9.81 m/s/s\n\n"
|
"The magnitude of gravity is assumed to be 9.81 m/s/s\n\n"
|
||||||
"@note ProjectileData::isBallistic must be true for this to have any affect.");
|
"@note ProjectileData::isBallistic must be true for this to have any affect.");
|
||||||
|
// disallow some field substitutions
|
||||||
|
onlyKeepClearSubstitutions("explosion");
|
||||||
|
onlyKeepClearSubstitutions("particleEmitter");
|
||||||
|
onlyKeepClearSubstitutions("particleWaterEmitter");
|
||||||
|
onlyKeepClearSubstitutions("sound");
|
||||||
|
onlyKeepClearSubstitutions("splash");
|
||||||
|
onlyKeepClearSubstitutions("waterExplosion");
|
||||||
|
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
@ -574,6 +620,11 @@ Projectile::Projectile()
|
||||||
|
|
||||||
mLightState.clear();
|
mLightState.clear();
|
||||||
mLightState.setLightInfo( mLight );
|
mLightState.setLightInfo( mLight );
|
||||||
|
|
||||||
|
mDataBlock = 0;
|
||||||
|
ignoreSourceTimeout = false;
|
||||||
|
dynamicCollisionMask = csmDynamicCollisionMask;
|
||||||
|
staticCollisionMask = csmStaticCollisionMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
Projectile::~Projectile()
|
Projectile::~Projectile()
|
||||||
|
|
@ -582,6 +633,11 @@ Projectile::~Projectile()
|
||||||
|
|
||||||
delete mProjectileShape;
|
delete mProjectileShape;
|
||||||
mProjectileShape = NULL;
|
mProjectileShape = NULL;
|
||||||
|
if (mDataBlock && mDataBlock->isTempClone())
|
||||||
|
{
|
||||||
|
delete mDataBlock;
|
||||||
|
mDataBlock = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
@ -609,6 +665,7 @@ void Projectile::initPersistFields()
|
||||||
addField("sourceSlot", TypeS32, Offset(mSourceObjectSlot, Projectile),
|
addField("sourceSlot", TypeS32, Offset(mSourceObjectSlot, Projectile),
|
||||||
"@brief The sourceObject's weapon slot that the projectile originates from.\n\n");
|
"@brief The sourceObject's weapon slot that the projectile originates from.\n\n");
|
||||||
|
|
||||||
|
addField("ignoreSourceTimeout", TypeBool, Offset(ignoreSourceTimeout, Projectile));
|
||||||
endGroup("Source");
|
endGroup("Source");
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1088,7 +1145,7 @@ void Projectile::simulate( F32 dt )
|
||||||
// disable the source objects collision reponse for a short time while we
|
// disable the source objects collision reponse for a short time while we
|
||||||
// determine if the projectile is capable of moving from the old position
|
// determine if the projectile is capable of moving from the old position
|
||||||
// to the new position, otherwise we'll hit ourself
|
// to the new position, otherwise we'll hit ourself
|
||||||
bool disableSourceObjCollision = (mSourceObject.isValid() && mCurrTick <= SourceIdTimeoutTicks);
|
bool disableSourceObjCollision = (mSourceObject.isValid() && (ignoreSourceTimeout || mCurrTick <= SourceIdTimeoutTicks));
|
||||||
if ( disableSourceObjCollision )
|
if ( disableSourceObjCollision )
|
||||||
mSourceObject->disableCollision();
|
mSourceObject->disableCollision();
|
||||||
disableCollision();
|
disableCollision();
|
||||||
|
|
@ -1105,12 +1162,12 @@ void Projectile::simulate( F32 dt )
|
||||||
if ( mPhysicsWorld )
|
if ( mPhysicsWorld )
|
||||||
hit = mPhysicsWorld->castRay( oldPosition, newPosition, &rInfo, Point3F( newPosition - oldPosition) * mDataBlock->impactForce );
|
hit = mPhysicsWorld->castRay( oldPosition, newPosition, &rInfo, Point3F( newPosition - oldPosition) * mDataBlock->impactForce );
|
||||||
else
|
else
|
||||||
hit = getContainer()->castRay(oldPosition, newPosition, csmDynamicCollisionMask | csmStaticCollisionMask, &rInfo);
|
hit = getContainer()->castRay(oldPosition, newPosition, dynamicCollisionMask | staticCollisionMask, &rInfo);
|
||||||
|
|
||||||
if ( hit )
|
if ( hit )
|
||||||
{
|
{
|
||||||
// make sure the client knows to bounce
|
// make sure the client knows to bounce
|
||||||
if ( isServerObject() && ( rInfo.object->getTypeMask() & csmStaticCollisionMask ) == 0 )
|
if(isServerObject() && (rInfo.object->getTypeMask() & staticCollisionMask) == 0)
|
||||||
setMaskBits( BounceMask );
|
setMaskBits( BounceMask );
|
||||||
|
|
||||||
MatrixF xform( true );
|
MatrixF xform( true );
|
||||||
|
|
@ -1301,6 +1358,7 @@ U32 Projectile::packUpdate( NetConnection *con, U32 mask, BitStream *stream )
|
||||||
stream->writeRangedU32( U32(mSourceObjectSlot),
|
stream->writeRangedU32( U32(mSourceObjectSlot),
|
||||||
0,
|
0,
|
||||||
ShapeBase::MaxMountedImages - 1 );
|
ShapeBase::MaxMountedImages - 1 );
|
||||||
|
stream->writeFlag(ignoreSourceTimeout);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// have not recieved the ghost for the source object yet, try again later
|
// have not recieved the ghost for the source object yet, try again later
|
||||||
|
|
@ -1344,6 +1402,7 @@ void Projectile::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||||
mSourceObjectId = stream->readRangedU32( 0, NetConnection::MaxGhostCount );
|
mSourceObjectId = stream->readRangedU32( 0, NetConnection::MaxGhostCount );
|
||||||
mSourceObjectSlot = stream->readRangedU32( 0, ShapeBase::MaxMountedImages - 1 );
|
mSourceObjectSlot = stream->readRangedU32( 0, ShapeBase::MaxMountedImages - 1 );
|
||||||
|
|
||||||
|
ignoreSourceTimeout = stream->readFlag();
|
||||||
NetObject* pObject = con->resolveGhost( mSourceObjectId );
|
NetObject* pObject = con->resolveGhost( mSourceObjectId );
|
||||||
if ( pObject != NULL )
|
if ( pObject != NULL )
|
||||||
mSourceObject = dynamic_cast<ShapeBase*>( pObject );
|
mSourceObject = dynamic_cast<ShapeBase*>( pObject );
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _PROJECTILE_H_
|
#ifndef _PROJECTILE_H_
|
||||||
#define _PROJECTILE_H_
|
#define _PROJECTILE_H_
|
||||||
|
|
||||||
|
|
@ -144,6 +149,9 @@ public:
|
||||||
|
|
||||||
DECLARE_CALLBACK( void, onExplode, ( Projectile* proj, Point3F pos, F32 fade ) );
|
DECLARE_CALLBACK( void, onExplode, ( Projectile* proj, Point3F pos, F32 fade ) );
|
||||||
DECLARE_CALLBACK( void, onCollision, ( Projectile* proj, SceneObject* col, F32 fade, Point3F pos, Point3F normal ) );
|
DECLARE_CALLBACK( void, onCollision, ( Projectile* proj, SceneObject* col, F32 fade, Point3F pos, Point3F normal ) );
|
||||||
|
public:
|
||||||
|
ProjectileData(const ProjectileData&, bool = false);
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -279,6 +287,10 @@ protected:
|
||||||
Point3F mExplosionPosition;
|
Point3F mExplosionPosition;
|
||||||
Point3F mExplosionNormal;
|
Point3F mExplosionNormal;
|
||||||
U32 mCollideHitType;
|
U32 mCollideHitType;
|
||||||
|
public:
|
||||||
|
bool ignoreSourceTimeout;
|
||||||
|
U32 dynamicCollisionMask;
|
||||||
|
U32 staticCollisionMask;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _PROJECTILE_H_
|
#endif // _PROJECTILE_H_
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/shapeBase.h"
|
#include "T3D/shapeBase.h"
|
||||||
|
|
||||||
|
|
@ -194,6 +199,69 @@ ShapeBaseData::ShapeBaseData()
|
||||||
inheritEnergyFromMount( false )
|
inheritEnergyFromMount( false )
|
||||||
{
|
{
|
||||||
dMemset( mountPointNode, -1, sizeof( S32 ) * SceneObject::NumMountPoints );
|
dMemset( mountPointNode, -1, sizeof( S32 ) * SceneObject::NumMountPoints );
|
||||||
|
remap_txr_tags = NULL;
|
||||||
|
remap_buffer = NULL;
|
||||||
|
silent_bbox_check = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
shadowEnable = other.shadowEnable;
|
||||||
|
shadowSize = other.shadowSize;
|
||||||
|
shadowMaxVisibleDistance = other.shadowMaxVisibleDistance;
|
||||||
|
shadowProjectionDistance = other.shadowProjectionDistance;
|
||||||
|
shadowSphereAdjust = other.shadowSphereAdjust;
|
||||||
|
shapeName = other.shapeName;
|
||||||
|
cloakTexName = other.cloakTexName;
|
||||||
|
cubeDescName = other.cubeDescName;
|
||||||
|
cubeDescId = other.cubeDescId;
|
||||||
|
reflectorDesc = other.reflectorDesc;
|
||||||
|
debris = other.debris;
|
||||||
|
debrisID = other.debrisID; // -- for pack/unpack of debris ptr
|
||||||
|
debrisShapeName = other.debrisShapeName;
|
||||||
|
debrisShape = other.debrisShape; // -- TSShape loaded using debrisShapeName
|
||||||
|
explosion = other.explosion;
|
||||||
|
explosionID = other.explosionID; // -- for pack/unpack of explosion ptr
|
||||||
|
underwaterExplosion = other.underwaterExplosion;
|
||||||
|
underwaterExplosionID = other.underwaterExplosionID; // -- for pack/unpack of underwaterExplosion ptr
|
||||||
|
mass = other.mass;
|
||||||
|
drag = other.drag;
|
||||||
|
density = other.density;
|
||||||
|
maxEnergy = other.maxEnergy;
|
||||||
|
maxDamage = other.maxDamage;
|
||||||
|
repairRate = other.repairRate;
|
||||||
|
disabledLevel = other.disabledLevel;
|
||||||
|
destroyedLevel = other.destroyedLevel;
|
||||||
|
cameraMaxDist = other.cameraMaxDist;
|
||||||
|
cameraMinDist = other.cameraMinDist;
|
||||||
|
cameraDefaultFov = other.cameraDefaultFov;
|
||||||
|
cameraMinFov = other.cameraMinFov;
|
||||||
|
cameraMaxFov = other.cameraMaxFov;
|
||||||
|
cameraCanBank = other.cameraCanBank;
|
||||||
|
mountedImagesBank = other.mountedImagesBank;
|
||||||
|
mShape = other.mShape; // -- TSShape loaded using shapeName
|
||||||
|
mCRC = other.mCRC; // -- from shape, used to verify client shape
|
||||||
|
computeCRC = other.computeCRC;
|
||||||
|
eyeNode = other.eyeNode; // -- from shape node "eye"
|
||||||
|
earNode = other.earNode; // -- from shape node "ear"
|
||||||
|
cameraNode = other.cameraNode; // -- from shape node "cam"
|
||||||
|
dMemcpy(mountPointNode, other.mountPointNode, sizeof(mountPointNode)); // -- from shape nodes "mount#" 0-31
|
||||||
|
debrisDetail = other.debrisDetail; // -- from shape detail "Debris-17"
|
||||||
|
damageSequence = other.damageSequence; // -- from shape sequence "Damage"
|
||||||
|
hulkSequence = other.hulkSequence; // -- from shape sequence "Visibility"
|
||||||
|
observeThroughObject = other.observeThroughObject;
|
||||||
|
collisionDetails = other.collisionDetails; // -- calc from shape (this is a Vector copy)
|
||||||
|
collisionBounds = other.collisionBounds; // -- calc from shape (this is a Vector copy)
|
||||||
|
LOSDetails = other.LOSDetails; // -- calc from shape (this is a Vector copy)
|
||||||
|
firstPersonOnly = other.firstPersonOnly;
|
||||||
|
useEyePoint = other.useEyePoint;
|
||||||
|
isInvincible = other.isInvincible;
|
||||||
|
renderWhenDestroyed = other.renderWhenDestroyed;
|
||||||
|
inheritEnergyFromMount = other.inheritEnergyFromMount;
|
||||||
|
remap_txr_tags = other.remap_txr_tags;
|
||||||
|
remap_buffer = other.remap_buffer;
|
||||||
|
txr_tag_remappings = other.txr_tag_remappings;
|
||||||
|
silent_bbox_check = other.silent_bbox_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ShapeBaseDataProto
|
struct ShapeBaseDataProto
|
||||||
|
|
@ -228,6 +296,8 @@ static ShapeBaseDataProto gShapeBaseDataProto;
|
||||||
ShapeBaseData::~ShapeBaseData()
|
ShapeBaseData::~ShapeBaseData()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (remap_buffer && !isTempClone())
|
||||||
|
dFree(remap_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShapeBaseData::preload(bool server, String &errorStr)
|
bool ShapeBaseData::preload(bool server, String &errorStr)
|
||||||
|
|
@ -337,11 +407,13 @@ bool ShapeBaseData::preload(bool server, String &errorStr)
|
||||||
|
|
||||||
if (!mShape->bounds.isContained(collisionBounds.last()))
|
if (!mShape->bounds.isContained(collisionBounds.last()))
|
||||||
{
|
{
|
||||||
|
if (!silent_bbox_check)
|
||||||
Con::warnf("Warning: shape %s collision detail %d (Collision-%d) bounds exceed that of shape.", shapeName, collisionDetails.size() - 1, collisionDetails.last());
|
Con::warnf("Warning: shape %s collision detail %d (Collision-%d) bounds exceed that of shape.", shapeName, collisionDetails.size() - 1, collisionDetails.last());
|
||||||
collisionBounds.last() = mShape->bounds;
|
collisionBounds.last() = mShape->bounds;
|
||||||
}
|
}
|
||||||
else if (collisionBounds.last().isValidBox() == false)
|
else if (collisionBounds.last().isValidBox() == false)
|
||||||
{
|
{
|
||||||
|
if (!silent_bbox_check)
|
||||||
Con::errorf("Error: shape %s-collision detail %d (Collision-%d) bounds box invalid!", shapeName, collisionDetails.size() - 1, collisionDetails.last());
|
Con::errorf("Error: shape %s-collision detail %d (Collision-%d) bounds box invalid!", shapeName, collisionDetails.size() - 1, collisionDetails.last());
|
||||||
collisionBounds.last() = mShape->bounds;
|
collisionBounds.last() = mShape->bounds;
|
||||||
}
|
}
|
||||||
|
|
@ -413,6 +485,29 @@ bool ShapeBaseData::preload(bool server, String &errorStr)
|
||||||
F32 w = mShape->bounds.len_y() / 2;
|
F32 w = mShape->bounds.len_y() / 2;
|
||||||
if (cameraMaxDist < w)
|
if (cameraMaxDist < w)
|
||||||
cameraMaxDist = w;
|
cameraMaxDist = w;
|
||||||
|
// just parse up the string and collect the remappings in txr_tag_remappings.
|
||||||
|
if (!server && remap_txr_tags != NULL && remap_txr_tags != StringTable->insert(""))
|
||||||
|
{
|
||||||
|
txr_tag_remappings.clear();
|
||||||
|
if (remap_buffer)
|
||||||
|
dFree(remap_buffer);
|
||||||
|
|
||||||
|
remap_buffer = dStrdup(remap_txr_tags);
|
||||||
|
|
||||||
|
char* remap_token = dStrtok(remap_buffer, " \t");
|
||||||
|
while (remap_token != NULL)
|
||||||
|
{
|
||||||
|
char* colon = dStrchr(remap_token, ':');
|
||||||
|
if (colon)
|
||||||
|
{
|
||||||
|
*colon = '\0';
|
||||||
|
txr_tag_remappings.increment();
|
||||||
|
txr_tag_remappings.last().old_tag = remap_token;
|
||||||
|
txr_tag_remappings.last().new_tag = colon+1;
|
||||||
|
}
|
||||||
|
remap_token = dStrtok(NULL, " \t");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!server)
|
if(!server)
|
||||||
|
|
@ -586,6 +681,12 @@ void ShapeBaseData::initPersistFields()
|
||||||
|
|
||||||
endGroup( "Reflection" );
|
endGroup( "Reflection" );
|
||||||
|
|
||||||
|
addField("remapTextureTags", TypeString, Offset(remap_txr_tags, ShapeBaseData));
|
||||||
|
addField("silentBBoxValidation", TypeBool, Offset(silent_bbox_check, ShapeBaseData));
|
||||||
|
// disallow some field substitutions
|
||||||
|
onlyKeepClearSubstitutions("debris"); // subs resolving to "~~", or "~0" are OK
|
||||||
|
onlyKeepClearSubstitutions("explosion");
|
||||||
|
onlyKeepClearSubstitutions("underwaterExplosion");
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -738,6 +839,8 @@ void ShapeBaseData::packData(BitStream* stream)
|
||||||
//stream->write(reflectMinDist);
|
//stream->write(reflectMinDist);
|
||||||
//stream->write(reflectMaxDist);
|
//stream->write(reflectMaxDist);
|
||||||
//stream->write(reflectDetailAdjust);
|
//stream->write(reflectDetailAdjust);
|
||||||
|
stream->writeString(remap_txr_tags);
|
||||||
|
stream->writeFlag(silent_bbox_check);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBaseData::unpackData(BitStream* stream)
|
void ShapeBaseData::unpackData(BitStream* stream)
|
||||||
|
|
@ -839,6 +942,8 @@ void ShapeBaseData::unpackData(BitStream* stream)
|
||||||
//stream->read(&reflectMinDist);
|
//stream->read(&reflectMinDist);
|
||||||
//stream->read(&reflectMaxDist);
|
//stream->read(&reflectMaxDist);
|
||||||
//stream->read(&reflectDetailAdjust);
|
//stream->read(&reflectDetailAdjust);
|
||||||
|
remap_txr_tags = stream->readSTString();
|
||||||
|
silent_bbox_check = stream->readFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -941,6 +1046,13 @@ ShapeBase::ShapeBase()
|
||||||
|
|
||||||
for (i = 0; i < MaxTriggerKeys; i++)
|
for (i = 0; i < MaxTriggerKeys; i++)
|
||||||
mTrigger[i] = false;
|
mTrigger[i] = false;
|
||||||
|
anim_clip_flags = 0;
|
||||||
|
last_anim_id = -1;
|
||||||
|
last_anim_tag = 0;
|
||||||
|
last_anim_lock_tag = 0;
|
||||||
|
saved_seq_id = -1;
|
||||||
|
saved_pos = 0.0f;
|
||||||
|
saved_rate = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1079,6 +1191,16 @@ void ShapeBase::onSceneRemove()
|
||||||
|
|
||||||
bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
|
bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||||
{
|
{
|
||||||
|
// need to destroy blend-clips or we crash
|
||||||
|
if (isGhost())
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < blend_clips.size(); i++)
|
||||||
|
{
|
||||||
|
if (blend_clips[i].thread)
|
||||||
|
mShapeInstance->destroyThread(blend_clips[i].thread);
|
||||||
|
blend_clips.erase_fast(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
ShapeBaseData *prevDB = dynamic_cast<ShapeBaseData*>( mDataBlock );
|
ShapeBaseData *prevDB = dynamic_cast<ShapeBaseData*>( mDataBlock );
|
||||||
|
|
||||||
bool isInitialDataBlock = ( mDataBlock == 0 );
|
bool isInitialDataBlock = ( mDataBlock == 0 );
|
||||||
|
|
@ -1098,10 +1220,61 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||||
// a shape assigned to this object.
|
// a shape assigned to this object.
|
||||||
if (bool(mDataBlock->mShape)) {
|
if (bool(mDataBlock->mShape)) {
|
||||||
delete mShapeInstance;
|
delete mShapeInstance;
|
||||||
|
if (isClientObject() && mDataBlock->txr_tag_remappings.size() > 0)
|
||||||
|
{
|
||||||
|
// temporarily substitute material tags with alternates
|
||||||
|
TSMaterialList* mat_list = mDataBlock->mShape->materialList;
|
||||||
|
if (mat_list)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++)
|
||||||
|
{
|
||||||
|
ShapeBaseData::TextureTagRemapping* remap = &mDataBlock->txr_tag_remappings[i];
|
||||||
|
Vector<String> & mat_names = (Vector<String>&) mat_list->getMaterialNameList();
|
||||||
|
for (S32 j = 0; j < mat_names.size(); j++)
|
||||||
|
{
|
||||||
|
if (mat_names[j].compare(remap->old_tag, dStrlen(remap->old_tag), String::NoCase) == 0)
|
||||||
|
{
|
||||||
|
mat_names[j] = String(remap->new_tag);
|
||||||
|
mat_names[j].insert(0,'#');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
mShapeInstance = new TSShapeInstance(mDataBlock->mShape, isClientObject());
|
mShapeInstance = new TSShapeInstance(mDataBlock->mShape, isClientObject());
|
||||||
if (isClientObject())
|
if (isClientObject())
|
||||||
|
{
|
||||||
mShapeInstance->cloneMaterialList();
|
mShapeInstance->cloneMaterialList();
|
||||||
|
|
||||||
|
// restore the material tags to original form
|
||||||
|
if (mDataBlock->txr_tag_remappings.size() > 0)
|
||||||
|
{
|
||||||
|
TSMaterialList* mat_list = mDataBlock->mShape->materialList;
|
||||||
|
if (mat_list)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++)
|
||||||
|
{
|
||||||
|
ShapeBaseData::TextureTagRemapping* remap = &mDataBlock->txr_tag_remappings[i];
|
||||||
|
Vector<String> & mat_names = (Vector<String>&) mat_list->getMaterialNameList();
|
||||||
|
for (S32 j = 0; j < mat_names.size(); j++)
|
||||||
|
{
|
||||||
|
String::SizeType len = mat_names[j].length();
|
||||||
|
if (len > 1)
|
||||||
|
{
|
||||||
|
String temp_name = mat_names[j].substr(1,len-1);
|
||||||
|
if (temp_name.compare(remap->new_tag, dStrlen(remap->new_tag)) == 0)
|
||||||
|
{
|
||||||
|
mat_names[j] = String(remap->old_tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mObjBox = mDataBlock->mShape->bounds;
|
mObjBox = mDataBlock->mShape->bounds;
|
||||||
resetWorldBox();
|
resetWorldBox();
|
||||||
|
|
||||||
|
|
@ -3550,6 +3723,31 @@ void ShapeBase::setCurrentWaterObject( WaterObject *obj )
|
||||||
mCurrentWaterObject = obj;
|
mCurrentWaterObject = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShapeBase::notifyCollisionCallbacks(SceneObject* obj, const VectorF& vel)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < collision_callbacks.size(); i++)
|
||||||
|
if (collision_callbacks[i])
|
||||||
|
collision_callbacks[i]->collisionNotify(this, obj, vel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeBase::registerCollisionCallback(CollisionEventCallback* ce_cb)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < collision_callbacks.size(); i++)
|
||||||
|
if (collision_callbacks[i] == ce_cb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
collision_callbacks.push_back(ce_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeBase::unregisterCollisionCallback(CollisionEventCallback* ce_cb)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < collision_callbacks.size(); i++)
|
||||||
|
if (collision_callbacks[i] == ce_cb)
|
||||||
|
{
|
||||||
|
collision_callbacks.erase(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
DefineEngineMethod( ShapeBase, setHidden, void, ( bool show ),,
|
DefineEngineMethod( ShapeBase, setHidden, void, ( bool show ),,
|
||||||
|
|
@ -4945,3 +5143,202 @@ DefineEngineMethod( ShapeBase, getModelFile, const char *, (),,
|
||||||
const char *fieldName = StringTable->insert( String("shapeFile") );
|
const char *fieldName = StringTable->insert( String("shapeFile") );
|
||||||
return datablock->getDataField( fieldName, NULL );
|
return datablock->getDataField( fieldName, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
U32 ShapeBase::unique_anim_tag_counter = 1;
|
||||||
|
|
||||||
|
U32 ShapeBase::playBlendAnimation(S32 seq_id, F32 pos, F32 rate)
|
||||||
|
{
|
||||||
|
BlendThread blend_clip;
|
||||||
|
blend_clip.tag = ((unique_anim_tag_counter++) | BLENDED_CLIP);
|
||||||
|
blend_clip.thread = 0;
|
||||||
|
|
||||||
|
if (isClientObject())
|
||||||
|
{
|
||||||
|
blend_clip.thread = mShapeInstance->addThread();
|
||||||
|
mShapeInstance->setSequence(blend_clip.thread, seq_id, pos);
|
||||||
|
mShapeInstance->setTimeScale(blend_clip.thread, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
blend_clips.push_back(blend_clip);
|
||||||
|
|
||||||
|
return blend_clip.tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeBase::restoreBlendAnimation(U32 tag)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < blend_clips.size(); i++)
|
||||||
|
{
|
||||||
|
if (blend_clips[i].tag == tag)
|
||||||
|
{
|
||||||
|
if (blend_clips[i].thread)
|
||||||
|
{
|
||||||
|
mShapeInstance->destroyThread(blend_clips[i].thread);
|
||||||
|
}
|
||||||
|
blend_clips.erase_fast(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void ShapeBase::restoreAnimation(U32 tag)
|
||||||
|
{
|
||||||
|
if (!isClientObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// check if this is a blended clip
|
||||||
|
if ((tag & BLENDED_CLIP) != 0)
|
||||||
|
{
|
||||||
|
restoreBlendAnimation(tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag != 0 && tag == last_anim_tag)
|
||||||
|
{
|
||||||
|
anim_clip_flags &= ~(ANIM_OVERRIDDEN | IS_DEATH_ANIM);
|
||||||
|
|
||||||
|
stopThread(0);
|
||||||
|
|
||||||
|
if (saved_seq_id != -1)
|
||||||
|
{
|
||||||
|
setThreadSequence(0, saved_seq_id);
|
||||||
|
setThreadPosition(0, saved_pos);
|
||||||
|
setThreadTimeScale(0, saved_rate);
|
||||||
|
setThreadDir(0, (saved_rate >= 0));
|
||||||
|
playThread(0);
|
||||||
|
|
||||||
|
saved_seq_id = -1;
|
||||||
|
saved_pos = 0.0f;
|
||||||
|
saved_rate = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_anim_tag = 0;
|
||||||
|
last_anim_id = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 ShapeBase::getAnimationID(const char* name)
|
||||||
|
{
|
||||||
|
const TSShape* ts_shape = getShape();
|
||||||
|
S32 seq_id = (ts_shape) ? ts_shape->findSequence(name) : -1;
|
||||||
|
return (seq_id >= 0) ? (U32) seq_id : BAD_ANIM_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 ShapeBase::playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim)
|
||||||
|
{
|
||||||
|
if (!isClientObject())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (anim_id == BAD_ANIM_ID)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const TSShape* ts_shape = getShape();
|
||||||
|
if (!ts_shape)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
S32 seq_id = (S32) anim_id;
|
||||||
|
if (mShapeInstance->getShape()->sequences[seq_id].isBlend())
|
||||||
|
return playBlendAnimation(seq_id, pos, rate);
|
||||||
|
|
||||||
|
if (last_anim_tag == 0)
|
||||||
|
{
|
||||||
|
// try to save state of playing animation
|
||||||
|
Thread& st = mScriptThread[0];
|
||||||
|
if (st.sequence != -1)
|
||||||
|
{
|
||||||
|
saved_seq_id = st.sequence;
|
||||||
|
saved_pos = st.position;
|
||||||
|
saved_rate = st.timescale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// START OR TRANSITION TO SEQUENCE HERE
|
||||||
|
setThreadSequence(0, seq_id);
|
||||||
|
setThreadPosition(0, pos);
|
||||||
|
setThreadTimeScale(0, rate);
|
||||||
|
setThreadDir(0, (rate >= 0));
|
||||||
|
playThread(0);
|
||||||
|
|
||||||
|
if (is_death_anim)
|
||||||
|
anim_clip_flags |= IS_DEATH_ANIM;
|
||||||
|
else
|
||||||
|
anim_clip_flags &= ~IS_DEATH_ANIM;
|
||||||
|
|
||||||
|
anim_clip_flags |= ANIM_OVERRIDDEN;
|
||||||
|
last_anim_tag = unique_anim_tag_counter++;
|
||||||
|
last_anim_id = anim_id;
|
||||||
|
|
||||||
|
return last_anim_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 ShapeBase::getAnimationDurationByID(U32 anim_id)
|
||||||
|
{
|
||||||
|
if (anim_id == BAD_ANIM_ID)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
S32 seq_id = (S32) anim_id;
|
||||||
|
if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
|
||||||
|
return mDataBlock->mShape->sequences[seq_id].duration;
|
||||||
|
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShapeBase::isBlendAnimation(const char* name)
|
||||||
|
{
|
||||||
|
U32 anim_id = getAnimationID(name);
|
||||||
|
if (anim_id == BAD_ANIM_ID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
S32 seq_id = (S32) anim_id;
|
||||||
|
if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
|
||||||
|
return mDataBlock->mShape->sequences[seq_id].isBlend();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ShapeBase::getLastClipName(U32 clip_tag)
|
||||||
|
{
|
||||||
|
if (clip_tag != last_anim_tag)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
S32 seq_id = (S32) last_anim_id;
|
||||||
|
|
||||||
|
S32 idx = mDataBlock->mShape->sequences[seq_id].nameIndex;
|
||||||
|
if (idx < 0 || idx >= mDataBlock->mShape->names.size())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return mDataBlock->mShape->names[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
U32 ShapeBase::playAnimation(const char* name, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim)
|
||||||
|
{
|
||||||
|
return playAnimationByID(getAnimationID(name), pos, rate, trans, hold, wait, is_death_anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 ShapeBase::getAnimationDuration(const char* name)
|
||||||
|
{
|
||||||
|
return getAnimationDurationByID(getAnimationID(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeBase::setSelectionFlags(U8 flags)
|
||||||
|
{
|
||||||
|
Parent::setSelectionFlags(flags);
|
||||||
|
|
||||||
|
if (!mShapeInstance || !isClientObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mShapeInstance->ownMaterialList())
|
||||||
|
return;
|
||||||
|
|
||||||
|
TSMaterialList* pMatList = mShapeInstance->getMaterialList();
|
||||||
|
for (S32 j = 0; j < pMatList->size(); j++)
|
||||||
|
{
|
||||||
|
BaseMatInstance * bmi = pMatList->getMaterialInst(j);
|
||||||
|
bmi->setSelectionHighlighting(needsSelectionHighlighting());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,10 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
#ifndef _SHAPEBASE_H_
|
#ifndef _SHAPEBASE_H_
|
||||||
#define _SHAPEBASE_H_
|
#define _SHAPEBASE_H_
|
||||||
|
|
||||||
|
|
@ -654,6 +658,17 @@ public:
|
||||||
DECLARE_CALLBACK(void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name));
|
DECLARE_CALLBACK(void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name));
|
||||||
DECLARE_CALLBACK( void, onForceUncloak, ( ShapeBase* obj, const char* reason ) );
|
DECLARE_CALLBACK( void, onForceUncloak, ( ShapeBase* obj, const char* reason ) );
|
||||||
/// @}
|
/// @}
|
||||||
|
struct TextureTagRemapping
|
||||||
|
{
|
||||||
|
char* old_tag;
|
||||||
|
char* new_tag;
|
||||||
|
};
|
||||||
|
StringTableEntry remap_txr_tags;
|
||||||
|
char* remap_buffer;
|
||||||
|
Vector<TextureTagRemapping> txr_tag_remappings;
|
||||||
|
bool silent_bbox_check;
|
||||||
|
public:
|
||||||
|
ShapeBaseData(const ShapeBaseData&, bool = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1845,7 +1860,58 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DECLARE_CALLBACK( F32, validateCameraFov, (F32 fov) );
|
DECLARE_CALLBACK( F32, validateCameraFov, (F32 fov) );
|
||||||
|
public:
|
||||||
|
class CollisionEventCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void collisionNotify(SceneObject* shape0, SceneObject* shape1, const VectorF& vel)=0;
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
Vector<CollisionEventCallback*> collision_callbacks;
|
||||||
|
void notifyCollisionCallbacks(SceneObject*, const VectorF& vel);
|
||||||
|
public:
|
||||||
|
void registerCollisionCallback(CollisionEventCallback*);
|
||||||
|
void unregisterCollisionCallback(CollisionEventCallback*);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum {
|
||||||
|
ANIM_OVERRIDDEN = BIT(0),
|
||||||
|
BLOCK_USER_CONTROL = BIT(1),
|
||||||
|
IS_DEATH_ANIM = BIT(2),
|
||||||
|
BAD_ANIM_ID = 999999999,
|
||||||
|
BLENDED_CLIP = 0x80000000,
|
||||||
|
};
|
||||||
|
struct BlendThread
|
||||||
|
{
|
||||||
|
TSThread* thread;
|
||||||
|
U32 tag;
|
||||||
|
};
|
||||||
|
Vector<BlendThread> blend_clips;
|
||||||
|
static U32 unique_anim_tag_counter;
|
||||||
|
U8 anim_clip_flags;
|
||||||
|
S32 last_anim_id;
|
||||||
|
U32 last_anim_tag;
|
||||||
|
U32 last_anim_lock_tag;
|
||||||
|
S32 saved_seq_id;
|
||||||
|
F32 saved_pos;
|
||||||
|
F32 saved_rate;
|
||||||
|
U32 playBlendAnimation(S32 seq_id, F32 pos, F32 rate);
|
||||||
|
void restoreBlendAnimation(U32 tag);
|
||||||
|
public:
|
||||||
|
U32 playAnimation(const char* name, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim);
|
||||||
|
F32 getAnimationDuration(const char* name);
|
||||||
|
|
||||||
|
virtual void restoreAnimation(U32 tag);
|
||||||
|
virtual U32 getAnimationID(const char* name);
|
||||||
|
virtual U32 playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim);
|
||||||
|
virtual F32 getAnimationDurationByID(U32 anim_id);
|
||||||
|
virtual bool isBlendAnimation(const char* name);
|
||||||
|
virtual const char* getLastClipName(U32 clip_tag);
|
||||||
|
virtual void unlockAnimation(U32 tag, bool force=false) { }
|
||||||
|
virtual U32 lockAnimation() { return 0; }
|
||||||
|
virtual bool isAnimationLocked() const { return false; }
|
||||||
|
|
||||||
|
virtual void setSelectionFlags(U8 flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,10 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "core/dnet.h"
|
#include "core/dnet.h"
|
||||||
#include "core/stream/bitStream.h"
|
#include "core/stream/bitStream.h"
|
||||||
|
|
@ -97,6 +101,14 @@ StaticShapeData::StaticShapeData()
|
||||||
noIndividualDamage = false;
|
noIndividualDamage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StaticShapeData::StaticShapeData(const StaticShapeData& other, bool temp_clone) : ShapeBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
noIndividualDamage = other.noIndividualDamage;
|
||||||
|
dynamicTypeField = other.dynamicTypeField;
|
||||||
|
isShielded = other.isShielded; // -- uninitialized, unused
|
||||||
|
energyPerDamagePoint = other.energyPerDamagePoint; // -- uninitialized, unused
|
||||||
|
}
|
||||||
|
|
||||||
void StaticShapeData::initPersistFields()
|
void StaticShapeData::initPersistFields()
|
||||||
{
|
{
|
||||||
addField("noIndividualDamage", TypeBool, Offset(noIndividualDamage, StaticShapeData), "Deprecated\n\n @internal");
|
addField("noIndividualDamage", TypeBool, Offset(noIndividualDamage, StaticShapeData), "Deprecated\n\n @internal");
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _STATICSHAPE_H_
|
#ifndef _STATICSHAPE_H_
|
||||||
#define _STATICSHAPE_H_
|
#define _STATICSHAPE_H_
|
||||||
|
|
||||||
|
|
@ -38,12 +43,16 @@ struct StaticShapeData: public ShapeBaseData {
|
||||||
bool noIndividualDamage;
|
bool noIndividualDamage;
|
||||||
S32 dynamicTypeField;
|
S32 dynamicTypeField;
|
||||||
bool isShielded;
|
bool isShielded;
|
||||||
|
F32 energyPerDamagePoint; // Re-added for AFX
|
||||||
|
|
||||||
//
|
//
|
||||||
DECLARE_CONOBJECT(StaticShapeData);
|
DECLARE_CONOBJECT(StaticShapeData);
|
||||||
static void initPersistFields();
|
static void initPersistFields();
|
||||||
virtual void packData(BitStream* stream);
|
virtual void packData(BitStream* stream);
|
||||||
virtual void unpackData(BitStream* stream);
|
virtual void unpackData(BitStream* stream);
|
||||||
|
public:
|
||||||
|
StaticShapeData(const StaticShapeData&, bool = false);
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/tsStatic.h"
|
#include "T3D/tsStatic.h"
|
||||||
|
|
||||||
|
|
@ -54,6 +59,8 @@ using namespace Torque;
|
||||||
|
|
||||||
extern bool gEditingMission;
|
extern bool gEditingMission;
|
||||||
|
|
||||||
|
#include "afx/ce/afxZodiacMgr.h"
|
||||||
|
|
||||||
IMPLEMENT_CO_NETOBJECT_V1(TSStatic);
|
IMPLEMENT_CO_NETOBJECT_V1(TSStatic);
|
||||||
|
|
||||||
ConsoleDocClass( TSStatic,
|
ConsoleDocClass( TSStatic,
|
||||||
|
|
@ -124,6 +131,12 @@ TSStatic::TSStatic()
|
||||||
|
|
||||||
mCollisionType = CollisionMesh;
|
mCollisionType = CollisionMesh;
|
||||||
mDecalType = CollisionMesh;
|
mDecalType = CollisionMesh;
|
||||||
|
|
||||||
|
mIgnoreZodiacs = false;
|
||||||
|
mHasGradients = false;
|
||||||
|
mInvertGradientRange = false;
|
||||||
|
mGradientRangeUser.set(0.0f, 180.0f);
|
||||||
|
afxZodiacData::convertGradientRangeFromDegrees(mGradientRange, mGradientRangeUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSStatic::~TSStatic()
|
TSStatic::~TSStatic()
|
||||||
|
|
@ -222,6 +235,12 @@ void TSStatic::initPersistFields()
|
||||||
|
|
||||||
endGroup("Debug");
|
endGroup("Debug");
|
||||||
|
|
||||||
|
addGroup("AFX");
|
||||||
|
addField("ignoreZodiacs", TypeBool, Offset(mIgnoreZodiacs, TSStatic));
|
||||||
|
addField("useGradientRange", TypeBool, Offset(mHasGradients, TSStatic));
|
||||||
|
addField("gradientRange", TypePoint2F, Offset(mGradientRangeUser, TSStatic));
|
||||||
|
addField("invertGradientRange", TypeBool, Offset(mInvertGradientRange, TSStatic));
|
||||||
|
endGroup("AFX");
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -323,6 +342,8 @@ bool TSStatic::_createShape()
|
||||||
{
|
{
|
||||||
// Cleanup before we create.
|
// Cleanup before we create.
|
||||||
mCollisionDetails.clear();
|
mCollisionDetails.clear();
|
||||||
|
mDecalDetails.clear();
|
||||||
|
mDecalDetailsPtr = 0;
|
||||||
mLOSDetails.clear();
|
mLOSDetails.clear();
|
||||||
SAFE_DELETE( mPhysicsRep );
|
SAFE_DELETE( mPhysicsRep );
|
||||||
SAFE_DELETE( mShapeInstance );
|
SAFE_DELETE( mShapeInstance );
|
||||||
|
|
@ -354,6 +375,8 @@ bool TSStatic::_createShape()
|
||||||
|
|
||||||
mShapeInstance = new TSShapeInstance( mShape, isClientObject() );
|
mShapeInstance = new TSShapeInstance( mShape, isClientObject() );
|
||||||
|
|
||||||
|
if (isClientObject())
|
||||||
|
mShapeInstance->cloneMaterialList();
|
||||||
if( isGhost() )
|
if( isGhost() )
|
||||||
{
|
{
|
||||||
// Reapply the current skin
|
// Reapply the current skin
|
||||||
|
|
@ -396,11 +419,29 @@ void TSStatic::prepCollision()
|
||||||
|
|
||||||
// Cleanup any old collision data
|
// Cleanup any old collision data
|
||||||
mCollisionDetails.clear();
|
mCollisionDetails.clear();
|
||||||
|
mDecalDetails.clear();
|
||||||
|
mDecalDetailsPtr = 0;
|
||||||
mLOSDetails.clear();
|
mLOSDetails.clear();
|
||||||
mConvexList->nukeList();
|
mConvexList->nukeList();
|
||||||
|
|
||||||
if ( mCollisionType == CollisionMesh || mCollisionType == VisibleMesh )
|
if ( mCollisionType == CollisionMesh || mCollisionType == VisibleMesh )
|
||||||
|
{
|
||||||
mShape->findColDetails( mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails );
|
mShape->findColDetails( mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails );
|
||||||
|
if ( mDecalType == mCollisionType )
|
||||||
|
{
|
||||||
|
mDecalDetailsPtr = &mCollisionDetails;
|
||||||
|
}
|
||||||
|
else if ( mDecalType == CollisionMesh || mDecalType == VisibleMesh )
|
||||||
|
{
|
||||||
|
mShape->findColDetails( mDecalType == VisibleMesh, &mDecalDetails, 0 );
|
||||||
|
mDecalDetailsPtr = &mDecalDetails;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( mDecalType == CollisionMesh || mDecalType == VisibleMesh )
|
||||||
|
{
|
||||||
|
mShape->findColDetails( mDecalType == VisibleMesh, &mDecalDetails, 0 );
|
||||||
|
mDecalDetailsPtr = &mDecalDetails;
|
||||||
|
}
|
||||||
|
|
||||||
_updatePhysics();
|
_updatePhysics();
|
||||||
}
|
}
|
||||||
|
|
@ -681,6 +722,8 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
|
||||||
}
|
}
|
||||||
mShapeInstance->render( rdata );
|
mShapeInstance->render( rdata );
|
||||||
|
|
||||||
|
if (!mIgnoreZodiacs && mDecalDetailsPtr != 0)
|
||||||
|
afxZodiacMgr::renderPolysoupZodiacs(state, this);
|
||||||
if ( mRenderNormalScalar > 0 )
|
if ( mRenderNormalScalar > 0 )
|
||||||
{
|
{
|
||||||
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||||
|
|
@ -786,6 +829,13 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||||
stream->write(mInvertAlphaFade);
|
stream->write(mInvertAlphaFade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stream->writeFlag(mIgnoreZodiacs);
|
||||||
|
if (stream->writeFlag(mHasGradients))
|
||||||
|
{
|
||||||
|
stream->writeFlag(mInvertGradientRange);
|
||||||
|
stream->write(mGradientRange.x);
|
||||||
|
stream->write(mGradientRange.y);
|
||||||
|
}
|
||||||
if ( mLightPlugin )
|
if ( mLightPlugin )
|
||||||
retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
|
retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
|
||||||
|
|
||||||
|
|
@ -870,6 +920,14 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
stream->read(&mInvertAlphaFade);
|
stream->read(&mInvertAlphaFade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mIgnoreZodiacs = stream->readFlag();
|
||||||
|
mHasGradients = stream->readFlag();
|
||||||
|
if (mHasGradients)
|
||||||
|
{
|
||||||
|
mInvertGradientRange = stream->readFlag();
|
||||||
|
stream->read(&mGradientRange.x);
|
||||||
|
stream->read(&mGradientRange.y);
|
||||||
|
}
|
||||||
if ( mLightPlugin )
|
if ( mLightPlugin )
|
||||||
{
|
{
|
||||||
mLightPlugin->unpackUpdate(this, con, stream);
|
mLightPlugin->unpackUpdate(this, con, stream);
|
||||||
|
|
@ -882,6 +940,7 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
|
|
||||||
if ( isProperlyAdded() )
|
if ( isProperlyAdded() )
|
||||||
_updateShouldTick();
|
_updateShouldTick();
|
||||||
|
set_special_typing();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
@ -992,6 +1051,11 @@ bool TSStatic::buildPolyList(PolyListContext context, AbstractPolyList* polyList
|
||||||
polyList->addBox( mObjBox );
|
polyList->addBox( mObjBox );
|
||||||
else if ( meshType == VisibleMesh )
|
else if ( meshType == VisibleMesh )
|
||||||
mShapeInstance->buildPolyList( polyList, 0 );
|
mShapeInstance->buildPolyList( polyList, 0 );
|
||||||
|
else if (context == PLC_Decal && mDecalDetailsPtr != 0)
|
||||||
|
{
|
||||||
|
for ( U32 i = 0; i < mDecalDetailsPtr->size(); i++ )
|
||||||
|
mShapeInstance->buildPolyListOpcode( (*mDecalDetailsPtr)[i], polyList, box );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Everything else is done from the collision meshes
|
// Everything else is done from the collision meshes
|
||||||
|
|
@ -1324,3 +1388,41 @@ DefineEngineMethod( TSStatic, getModelFile, const char *, (),,
|
||||||
{
|
{
|
||||||
return object->getShapeFileName();
|
return object->getShapeFileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TSStatic::set_special_typing()
|
||||||
|
{
|
||||||
|
if (mCollisionType == VisibleMesh || mCollisionType == CollisionMesh)
|
||||||
|
mTypeMask |= InteriorLikeObjectType;
|
||||||
|
else
|
||||||
|
mTypeMask &= ~InteriorLikeObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TSStatic::onStaticModified(const char* slotName, const char*newValue)
|
||||||
|
{
|
||||||
|
if (slotName == afxZodiacData::GradientRangeSlot)
|
||||||
|
{
|
||||||
|
afxZodiacData::convertGradientRangeFromDegrees(mGradientRange, mGradientRangeUser);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_special_typing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TSStatic::setSelectionFlags(U8 flags)
|
||||||
|
{
|
||||||
|
Parent::setSelectionFlags(flags);
|
||||||
|
|
||||||
|
if (!mShapeInstance || !isClientObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mShapeInstance->ownMaterialList())
|
||||||
|
return;
|
||||||
|
|
||||||
|
TSMaterialList* pMatList = mShapeInstance->getMaterialList();
|
||||||
|
for (S32 j = 0; j < pMatList->size(); j++)
|
||||||
|
{
|
||||||
|
BaseMatInstance * bmi = pMatList->getMaterialInst(j);
|
||||||
|
bmi->setSelectionHighlighting(needsSelectionHighlighting());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -20,6 +20,11 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _TSSTATIC_H_
|
#ifndef _TSSTATIC_H_
|
||||||
#define _TSSTATIC_H_
|
#define _TSSTATIC_H_
|
||||||
|
|
||||||
|
|
@ -236,6 +241,20 @@ public:
|
||||||
|
|
||||||
const Vector<S32>& getLOSDetails() const { return mLOSDetails; }
|
const Vector<S32>& getLOSDetails() const { return mLOSDetails; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void onStaticModified(const char* slotName, const char*newValue = NULL);
|
||||||
|
protected:
|
||||||
|
Vector<S32> mDecalDetails;
|
||||||
|
Vector<S32>* mDecalDetailsPtr;
|
||||||
|
public:
|
||||||
|
bool mIgnoreZodiacs;
|
||||||
|
bool mHasGradients;
|
||||||
|
bool mInvertGradientRange;
|
||||||
|
Point2F mGradientRangeUser;
|
||||||
|
Point2F mGradientRange;
|
||||||
|
private:
|
||||||
|
void set_special_typing();
|
||||||
|
virtual void setSelectionFlags(U8 flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef TSStatic::MeshType TSMeshType;
|
typedef TSStatic::MeshType TSMeshType;
|
||||||
|
|
|
||||||
|
|
@ -151,16 +151,36 @@ public:
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// As shipped, AITurretShape plus the chain of classes it inherits from, consumes
|
||||||
|
// all 32 mask-bits. AFX uses one additional mask-bit in GameBase, which pushes
|
||||||
|
// AITurretShape over the mask-bit limit which will cause runtime crashes. As
|
||||||
|
// a workaround, AFX modifies AITurretShape so that it reuses the TurretUpdateMask
|
||||||
|
// defined by TurretShape rather than adding a unique TurretStateMask. This will
|
||||||
|
// make AITurretShape's network updates slightly less efficient, but should be
|
||||||
|
// acceptable for most uses of AITurretShape. If you plan to populate your levels
|
||||||
|
// with many AITurretShape objects, consider restoring it to use of a unique
|
||||||
|
// bit-mask, but if you do that, you will have to eliminate at use of at least one
|
||||||
|
// bit by one of it's parent classes. (FYI ShapeBase uses 20 bits.)
|
||||||
|
//
|
||||||
|
// Comment out this define if you want AITurretShape to define it's own bit-mask.
|
||||||
|
#define AFX_REUSE_TURRETSHAPE_MASKBITS
|
||||||
class AITurretShape: public TurretShape
|
class AITurretShape: public TurretShape
|
||||||
{
|
{
|
||||||
typedef TurretShape Parent;
|
typedef TurretShape Parent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
#ifdef AFX_REUSE_TURRETSHAPE_MASKBITS
|
||||||
|
enum MaskBits {
|
||||||
|
TurretStateMask = Parent::TurretUpdateMask,
|
||||||
|
NextFreeMask = Parent::NextFreeMask
|
||||||
|
};
|
||||||
|
#else // ORIGINAL CODE
|
||||||
enum MaskBits {
|
enum MaskBits {
|
||||||
TurretStateMask = Parent::NextFreeMask,
|
TurretStateMask = Parent::NextFreeMask,
|
||||||
NextFreeMask = Parent::NextFreeMask << 1
|
NextFreeMask = Parent::NextFreeMask << 1
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct TargetInfo
|
struct TargetInfo
|
||||||
{
|
{
|
||||||
|
|
|
||||||
1189
Engine/source/afx/afxCamera.cpp
Normal file
1189
Engine/source/afx/afxCamera.cpp
Normal file
File diff suppressed because it is too large
Load diff
189
Engine/source/afx/afxCamera.h
Normal file
189
Engine/source/afx/afxCamera.h
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 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.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// afxCamera implements a modified camera for demonstrating a third person camera style
|
||||||
|
// which is more common to RPG games than the standard FPS style camera. For the most part,
|
||||||
|
// it is a hybrid of the standard TGE camera and the third person mode of the Advanced Camera
|
||||||
|
// resource, authored by Thomas "Man of Ice" Lund. This camera implements the bare minimum
|
||||||
|
// required for demonstrating an RPG style camera and leaves tons of room for improvement.
|
||||||
|
// It should be replaced with a better camera if possible.
|
||||||
|
//
|
||||||
|
// Advanced Camera Resource by Thomas "Man of Ice" Lund:
|
||||||
|
// http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=5471
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_CAMERA_H_
|
||||||
|
#define _AFX_CAMERA_H_
|
||||||
|
|
||||||
|
#ifndef _SHAPEBASE_H_
|
||||||
|
#include "game/shapeBase.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct afxCameraData: public ShapeBaseData {
|
||||||
|
typedef ShapeBaseData Parent;
|
||||||
|
|
||||||
|
static U32 sCameraCollisionMask;
|
||||||
|
|
||||||
|
//
|
||||||
|
DECLARE_CONOBJECT(afxCameraData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
static void initPersistFields();
|
||||||
|
virtual void packData(BitStream* stream);
|
||||||
|
virtual void unpackData(BitStream* stream);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// Implements a basic camera object.
|
||||||
|
class afxCamera: public ShapeBase
|
||||||
|
{
|
||||||
|
typedef ShapeBase Parent;
|
||||||
|
|
||||||
|
enum MaskBits {
|
||||||
|
MoveMask = Parent::NextFreeMask,
|
||||||
|
SubjectMask = Parent::NextFreeMask << 1,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StateDelta {
|
||||||
|
Point3F pos;
|
||||||
|
Point3F rot;
|
||||||
|
VectorF posVec;
|
||||||
|
VectorF rotVec;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ThirdPersonMode = 1,
|
||||||
|
FlyMode = 2,
|
||||||
|
OrbitObjectMode = 3,
|
||||||
|
OrbitPointMode = 4,
|
||||||
|
CameraFirstMode = 0,
|
||||||
|
CameraLastMode = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mode;
|
||||||
|
Point3F mRot;
|
||||||
|
StateDelta delta;
|
||||||
|
|
||||||
|
SimObjectPtr<GameBase> mOrbitObject;
|
||||||
|
F32 mMinOrbitDist;
|
||||||
|
F32 mMaxOrbitDist;
|
||||||
|
F32 mCurOrbitDist;
|
||||||
|
Point3F mPosition;
|
||||||
|
bool mObservingClientObject;
|
||||||
|
|
||||||
|
SceneObject* cam_subject;
|
||||||
|
Point3F cam_offset;
|
||||||
|
Point3F coi_offset;
|
||||||
|
F32 cam_distance;
|
||||||
|
F32 cam_angle;
|
||||||
|
bool cam_dirty;
|
||||||
|
|
||||||
|
bool flymode_saved;
|
||||||
|
Point3F flymode_saved_pos;
|
||||||
|
S8 third_person_snap_c;
|
||||||
|
S8 third_person_snap_s;
|
||||||
|
|
||||||
|
void set_cam_pos(const Point3F& pos, const Point3F& viewRot);
|
||||||
|
void cam_update(F32 dt, bool on_server);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxCamera();
|
||||||
|
/*D*/ ~afxCamera();
|
||||||
|
|
||||||
|
Point3F& getPosition();
|
||||||
|
void setFlyMode();
|
||||||
|
void setOrbitMode(GameBase* obj, Point3F& pos, AngAxisF& rot, F32 minDist, F32 maxDist, F32 curDist, bool ownClientObject);
|
||||||
|
void validateEyePoint(F32 pos, MatrixF *mat);
|
||||||
|
|
||||||
|
GameBase* getOrbitObject() { return(mOrbitObject); }
|
||||||
|
bool isObservingClientObject() { return(mObservingClientObject); }
|
||||||
|
|
||||||
|
void snapToPosition(const Point3F& pos);
|
||||||
|
void setCameraSubject(SceneObject* subject);
|
||||||
|
void setThirdPersonOffset(const Point3F& offset);
|
||||||
|
void setThirdPersonOffset(const Point3F& offset, const Point3F& coi_offset);
|
||||||
|
const Point3F& getThirdPersonOffset() const { return cam_offset; }
|
||||||
|
const Point3F& getThirdPersonCOIOffset() const { return coi_offset; }
|
||||||
|
void setThirdPersonDistance(F32 distance);
|
||||||
|
F32 getThirdPersonDistance();
|
||||||
|
void setThirdPersonAngle(F32 angle);
|
||||||
|
F32 getThirdPersonAngle();
|
||||||
|
void setThirdPersonMode();
|
||||||
|
void setThirdPersonSnap();
|
||||||
|
void setThirdPersonSnapClient();
|
||||||
|
const char* getMode();
|
||||||
|
|
||||||
|
bool isCamera() const { return true; }
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxCamera);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
|
||||||
|
private: // 3POV SECTION
|
||||||
|
U32 blockers_mask_3pov;
|
||||||
|
|
||||||
|
void cam_update_3pov(F32 dt, bool on_server);
|
||||||
|
bool avoid_blocked_view(const Point3F& start, const Point3F& end, Point3F& newpos);
|
||||||
|
bool test_blocked_line(const Point3F& start, const Point3F& end);
|
||||||
|
|
||||||
|
public: // STD OVERRIDES SECTION
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
virtual void onDeleteNotify(SimObject *obj);
|
||||||
|
|
||||||
|
virtual void advanceTime(F32 dt);
|
||||||
|
virtual void processTick(const Move* move);
|
||||||
|
virtual void interpolateTick(F32 delta);
|
||||||
|
|
||||||
|
virtual void writePacketData(GameConnection *conn, BitStream *stream);
|
||||||
|
virtual void readPacketData(GameConnection *conn, BitStream *stream);
|
||||||
|
virtual U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||||
|
virtual void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||||
|
|
||||||
|
virtual void onCameraScopeQuery(NetConnection* cr, CameraScopeQuery*);
|
||||||
|
virtual void getCameraTransform(F32* pos,MatrixF* mat);
|
||||||
|
virtual void setTransform(const MatrixF& mat);
|
||||||
|
|
||||||
|
virtual void onEditorEnable();
|
||||||
|
virtual void onEditorDisable();
|
||||||
|
|
||||||
|
virtual F32 getCameraFov();
|
||||||
|
virtual F32 getDefaultCameraFov();
|
||||||
|
virtual bool isValidCameraFov(F32 fov);
|
||||||
|
virtual void setCameraFov(F32 fov);
|
||||||
|
|
||||||
|
virtual F32 getDamageFlash() const;
|
||||||
|
virtual F32 getWhiteOut() const;
|
||||||
|
|
||||||
|
virtual void setControllingClient( GameConnection* connection );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _AFX_CAMERA_H_
|
||||||
1084
Engine/source/afx/afxChoreographer.cpp
Normal file
1084
Engine/source/afx/afxChoreographer.cpp
Normal file
File diff suppressed because it is too large
Load diff
222
Engine/source/afx/afxChoreographer.h
Normal file
222
Engine/source/afx/afxChoreographer.h
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_CHOREOGRAPHER_H_
|
||||||
|
#define _AFX_CHOREOGRAPHER_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "afxEffectDefs.h"
|
||||||
|
#include "afxEffectWrapper.h"
|
||||||
|
#include "afxMagicMissile.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxChoreographerData
|
||||||
|
|
||||||
|
class afxChoreographerData : public GameBaseData, public afxEffectDefs
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool exec_on_new_clients;
|
||||||
|
U8 echo_packet_usage;
|
||||||
|
StringTableEntry client_script_file;
|
||||||
|
StringTableEntry client_init_func;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxChoreographerData();
|
||||||
|
/*C*/ afxChoreographerData(const afxChoreographerData&, bool = false);
|
||||||
|
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxChoreographerData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxChoreographer
|
||||||
|
|
||||||
|
class afxConstraint;
|
||||||
|
class afxConstraintMgr;
|
||||||
|
class afxEffectWrapper;
|
||||||
|
class afxParticlePool;
|
||||||
|
class afxParticlePoolData;
|
||||||
|
class SimSet;
|
||||||
|
class afxForceSetMgr;
|
||||||
|
|
||||||
|
class afxChoreographer : public GameBase, public afxEffectDefs, public afxMagicMissileCallback
|
||||||
|
{
|
||||||
|
typedef GameBase Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum MaskBits
|
||||||
|
{
|
||||||
|
TriggerMask = Parent::NextFreeMask << 0,
|
||||||
|
RemapConstraintMask = Parent::NextFreeMask << 1, // CONSTRAINT REMAPPING
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
USER_EXEC_CONDS_MASK = 0x00ffffff
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct dynConstraintDef
|
||||||
|
{
|
||||||
|
StringTableEntry cons_name;
|
||||||
|
U8 cons_type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
SceneObject* object;
|
||||||
|
Point3F* point;
|
||||||
|
MatrixF* xfm;
|
||||||
|
U16 scope_id;
|
||||||
|
} cons_obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
afxChoreographerData* datablock;
|
||||||
|
SimSet named_effects;
|
||||||
|
SimObject* exeblock;
|
||||||
|
afxForceSetMgr* force_set_mgr;
|
||||||
|
Vector<afxParticlePool*> particle_pools;
|
||||||
|
Vector<dynConstraintDef> dc_defs_a;
|
||||||
|
Vector<dynConstraintDef> dc_defs_b;
|
||||||
|
GameBase* proc_after_obj;
|
||||||
|
U32 trigger_mask;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector<dynConstraintDef>* dyn_cons_defs;
|
||||||
|
Vector<dynConstraintDef>* dyn_cons_defs2;
|
||||||
|
afxConstraintMgr* constraint_mgr;
|
||||||
|
U32 choreographer_id;
|
||||||
|
U8 ranking;
|
||||||
|
U8 lod;
|
||||||
|
U32 exec_conds_mask;
|
||||||
|
SimObject* extra;
|
||||||
|
Vector<NetConnection*> explicit_clients;
|
||||||
|
bool started_with_newop;
|
||||||
|
bool postpone_activation;
|
||||||
|
|
||||||
|
virtual void pack_constraint_info(NetConnection* conn, BitStream* stream);
|
||||||
|
virtual void unpack_constraint_info(NetConnection* conn, BitStream* stream);
|
||||||
|
void setup_dynamic_constraints();
|
||||||
|
void check_packet_usage(NetConnection*, BitStream*, S32 mark_stream_pos, const char* msg_tag);
|
||||||
|
SceneObject* get_camera(Point3F* cam_pos=0) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxChoreographer();
|
||||||
|
virtual ~afxChoreographer();
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
virtual bool onNewDataBlock(GameBaseData* dptr, bool reload);
|
||||||
|
virtual U32 packUpdate(NetConnection*, U32, BitStream*);
|
||||||
|
virtual void unpackUpdate(NetConnection*, BitStream*);
|
||||||
|
|
||||||
|
virtual void sync_with_clients() { }
|
||||||
|
|
||||||
|
afxConstraintMgr* getConstraintMgr() { return constraint_mgr; }
|
||||||
|
afxForceSetMgr* getForceSetMgr() { return force_set_mgr; }
|
||||||
|
|
||||||
|
afxParticlePool* findParticlePool(afxParticlePoolData* key_block, U32 key_index);
|
||||||
|
void registerParticlePool(afxParticlePool*);
|
||||||
|
void unregisterParticlePool(afxParticlePool*);
|
||||||
|
|
||||||
|
void setRanking(U8 value) { ranking = value; }
|
||||||
|
U8 getRanking() const { return ranking; }
|
||||||
|
bool testRanking(U8 low, U8 high) { return (ranking <= high && ranking >= low); }
|
||||||
|
void setLevelOfDetail(U8 value) { lod = value; }
|
||||||
|
U8 getLevelOfDetail() const { return lod; }
|
||||||
|
bool testLevelOfDetail(U8 low, U8 high) { return (lod <= high && lod >= low); }
|
||||||
|
void setExecConditions(U32 mask) { exec_conds_mask = mask; }
|
||||||
|
U32 getExecConditions() const { return exec_conds_mask; }
|
||||||
|
|
||||||
|
virtual void executeScriptEvent(const char* method, afxConstraint*,
|
||||||
|
const MatrixF& xfm, const char* data);
|
||||||
|
|
||||||
|
virtual void inflictDamage(const char * label, const char* flavor, SimObjectId target,
|
||||||
|
F32 amt, U8 count, F32 ad_amt, F32 rad, Point3F pos, F32 imp) { }
|
||||||
|
|
||||||
|
void addObjectConstraint(SceneObject*, const char* cons_name);
|
||||||
|
void addObjectConstraint(U16 scope_id, const char* cons_name, bool is_shape);
|
||||||
|
void addPointConstraint(Point3F&, const char* cons_name);
|
||||||
|
void addTransformConstraint(MatrixF&, const char* cons_name);
|
||||||
|
bool addConstraint(const char* source_spec, const char* cons_name);
|
||||||
|
|
||||||
|
void addNamedEffect(afxEffectWrapper*);
|
||||||
|
void removeNamedEffect(afxEffectWrapper*);
|
||||||
|
afxEffectWrapper* findNamedEffect(StringTableEntry);
|
||||||
|
|
||||||
|
void clearChoreographerId() { choreographer_id = 0; }
|
||||||
|
U32 getChoreographerId() { return choreographer_id; }
|
||||||
|
void setGhostConstraintObject(SceneObject*, StringTableEntry cons_name);
|
||||||
|
void setExtra(SimObject* extra) { this->extra = extra; }
|
||||||
|
void addExplicitClient(NetConnection* conn);
|
||||||
|
void removeExplicitClient(NetConnection* conn);
|
||||||
|
U32 getExplicitClientCount() { return explicit_clients.size(); }
|
||||||
|
|
||||||
|
void restoreScopedObject(SceneObject* obj);
|
||||||
|
virtual void restoreObject(SceneObject*) { };
|
||||||
|
|
||||||
|
void postProcessAfterObject(GameBase* obj);
|
||||||
|
U32 getTriggerMask() const { return trigger_mask; }
|
||||||
|
void setTriggerMask(U32 trigger_mask);
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// missile watcher callbacks
|
||||||
|
public:
|
||||||
|
virtual void impactNotify(const Point3F& p, const Point3F& n, SceneObject*) { }
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxChoreographer);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
|
||||||
|
// CONSTRAINT REMAPPING <<
|
||||||
|
protected:
|
||||||
|
Vector<dynConstraintDef*> remapped_cons_defs;
|
||||||
|
bool remapped_cons_sent;
|
||||||
|
virtual bool remap_builtin_constraint(SceneObject*, const char* cons_name) { return false; }
|
||||||
|
dynConstraintDef* find_cons_def_by_name(const char* cons_name);
|
||||||
|
public:
|
||||||
|
void remapObjectConstraint(SceneObject*, const char* cons_name);
|
||||||
|
void remapObjectConstraint(U16 scope_id, const char* cons_name, bool is_shape);
|
||||||
|
void remapPointConstraint(Point3F&, const char* cons_name);
|
||||||
|
void remapTransformConstraint(MatrixF&, const char* cons_name);
|
||||||
|
bool remapConstraint(const char* source_spec, const char* cons_name);
|
||||||
|
// CONSTRAINT REMAPPING >>
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_CHOREOGRAPHER_H_
|
||||||
2613
Engine/source/afx/afxConstraint.cpp
Normal file
2613
Engine/source/afx/afxConstraint.cpp
Normal file
File diff suppressed because it is too large
Load diff
677
Engine/source/afx/afxConstraint.h
Normal file
677
Engine/source/afx/afxConstraint.h
Normal file
|
|
@ -0,0 +1,677 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_CONSTRAINT_H_
|
||||||
|
#define _AFX_CONSTRAINT_H_
|
||||||
|
|
||||||
|
#include "core/util/tVector.h"
|
||||||
|
#include "T3D/shapeBase.h"
|
||||||
|
|
||||||
|
#include "afxEffectDefs.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxConstraintDef
|
||||||
|
|
||||||
|
class afxEffectBaseData;
|
||||||
|
|
||||||
|
struct afxConstraintDef : public afxEffectDefs
|
||||||
|
{
|
||||||
|
enum DefType
|
||||||
|
{
|
||||||
|
CONS_UNDEFINED,
|
||||||
|
CONS_PREDEFINED,
|
||||||
|
CONS_SCENE,
|
||||||
|
CONS_EFFECT,
|
||||||
|
CONS_GHOST
|
||||||
|
};
|
||||||
|
|
||||||
|
DefType def_type;
|
||||||
|
|
||||||
|
StringTableEntry cons_src_name;
|
||||||
|
StringTableEntry cons_node_name;
|
||||||
|
F32 history_time;
|
||||||
|
U8 sample_rate;
|
||||||
|
|
||||||
|
bool runs_on_server;
|
||||||
|
bool runs_on_client;
|
||||||
|
bool pos_at_box_center;
|
||||||
|
bool treat_as_camera;
|
||||||
|
|
||||||
|
/*C*/ afxConstraintDef();
|
||||||
|
|
||||||
|
bool isDefined();
|
||||||
|
|
||||||
|
bool isArbitraryObject();
|
||||||
|
void reset();
|
||||||
|
bool parseSpec(const char* spec, bool runs_on_server, bool runs_on_client);
|
||||||
|
|
||||||
|
static void gather_cons_defs(Vector<afxConstraintDef>& defs, Vector<afxEffectBaseData*>& fx);
|
||||||
|
|
||||||
|
static StringTableEntry SCENE_CONS_KEY;
|
||||||
|
static StringTableEntry EFFECT_CONS_KEY;
|
||||||
|
static StringTableEntry GHOST_CONS_KEY;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxConstraint
|
||||||
|
// Abstract base-class for a simple constraint mechanism used to constrain
|
||||||
|
// special effects to spell related objects such as the spellcaster, target,
|
||||||
|
// projectile, or impact location.
|
||||||
|
//
|
||||||
|
// note -- the direction vectors don't really fit... should probably consider separate
|
||||||
|
// constraint types for position, orientation, and possibly a look-at constraint.
|
||||||
|
//
|
||||||
|
|
||||||
|
class SceneObject;
|
||||||
|
class afxConstraintMgr;
|
||||||
|
|
||||||
|
class afxConstraint : public SimObject, public afxEffectDefs
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef SimObject Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
afxConstraintMgr* mgr;
|
||||||
|
afxConstraintDef cons_def;
|
||||||
|
bool is_defined;
|
||||||
|
bool is_valid;
|
||||||
|
Point3F last_pos;
|
||||||
|
MatrixF last_xfm;
|
||||||
|
F32 history_time;
|
||||||
|
bool is_alive;
|
||||||
|
bool gone_missing;
|
||||||
|
U32 change_code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxConstraint(afxConstraintMgr*);
|
||||||
|
virtual ~afxConstraint();
|
||||||
|
|
||||||
|
virtual bool getPosition(Point3F& pos, F32 hist=0.0f)
|
||||||
|
{ pos = last_pos; return is_valid; }
|
||||||
|
virtual bool getTransform(MatrixF& xfm, F32 hist=0.0f)
|
||||||
|
{ xfm = last_xfm; return is_valid;}
|
||||||
|
virtual bool getAltitudes(F32& terrain_alt, F32& interior_alt) { return false; }
|
||||||
|
|
||||||
|
virtual bool isDefined() { return is_defined; }
|
||||||
|
virtual bool isValid() { return is_valid; }
|
||||||
|
virtual U32 getChangeCode() { return change_code; }
|
||||||
|
|
||||||
|
virtual U32 setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans, bool is_death_anim)
|
||||||
|
{ return 0; };
|
||||||
|
virtual void resetAnimation(U32 tag) { };
|
||||||
|
virtual U32 lockAnimation() { return 0; }
|
||||||
|
virtual void unlockAnimation(U32 tag) { }
|
||||||
|
virtual F32 getAnimClipDuration(const char* clip) { return 0.0f; }
|
||||||
|
|
||||||
|
virtual S32 getDamageState() { return -1; }
|
||||||
|
virtual void setLivingState(bool state) { is_alive = state; };
|
||||||
|
virtual bool getLivingState() { return is_alive; };
|
||||||
|
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)=0;
|
||||||
|
|
||||||
|
virtual SceneObject* getSceneObject()=0;
|
||||||
|
virtual void restoreObject(SceneObject*)=0;
|
||||||
|
virtual U16 getScopeId()=0;
|
||||||
|
|
||||||
|
virtual U32 getTriggers()=0;
|
||||||
|
|
||||||
|
virtual void set_scope_id(U16 scope_id) { }
|
||||||
|
virtual void unset() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxConstraintMgr
|
||||||
|
|
||||||
|
class ShapeBase;
|
||||||
|
class afxEffectWrapper;
|
||||||
|
class afxShapeConstraint;
|
||||||
|
class afxObjectConstraint;
|
||||||
|
class BitStream;
|
||||||
|
class NetConnection;
|
||||||
|
|
||||||
|
struct afxConstraintID
|
||||||
|
{
|
||||||
|
S16 index;
|
||||||
|
S16 sub_index;
|
||||||
|
|
||||||
|
afxConstraintID() { index = -1; sub_index = 0; }
|
||||||
|
afxConstraintID(S16 idx, S16 sub=0) { index = idx; sub_index = sub; }
|
||||||
|
bool undefined() const { return (index < 0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Vector<afxConstraint*> afxConstraintList;
|
||||||
|
|
||||||
|
class afxConstraintMgr : public afxEffectDefs
|
||||||
|
{
|
||||||
|
typedef SimObject Parent;
|
||||||
|
|
||||||
|
struct preDef
|
||||||
|
{
|
||||||
|
StringTableEntry name;
|
||||||
|
U32 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<afxConstraintList*> constraints_v;
|
||||||
|
|
||||||
|
Vector<StringTableEntry> names_on_server;
|
||||||
|
Vector<S32> ghost_ids;
|
||||||
|
Vector<preDef> predefs;
|
||||||
|
U32 starttime;
|
||||||
|
bool on_server;
|
||||||
|
bool initialized;
|
||||||
|
F32 scoping_dist_sq;
|
||||||
|
|
||||||
|
SceneObject* find_object_from_name(StringTableEntry);
|
||||||
|
S32 find_cons_idx_from_name(StringTableEntry);
|
||||||
|
S32 find_effect_cons_idx_from_name(StringTableEntry);
|
||||||
|
|
||||||
|
void create_constraint(const afxConstraintDef&);
|
||||||
|
void set_ref_shape(afxConstraintID which_id, ShapeBase*);
|
||||||
|
void set_ref_shape(afxConstraintID which_id, U16 scope_id);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxConstraintMgr();
|
||||||
|
/*D*/ ~afxConstraintMgr();
|
||||||
|
|
||||||
|
void defineConstraint(U32 type, StringTableEntry);
|
||||||
|
|
||||||
|
afxConstraintID setReferencePoint(StringTableEntry which, Point3F point);
|
||||||
|
afxConstraintID setReferencePoint(StringTableEntry which, Point3F point, Point3F vector);
|
||||||
|
afxConstraintID setReferenceTransform(StringTableEntry which, MatrixF& xfm);
|
||||||
|
afxConstraintID setReferenceObject(StringTableEntry which, SceneObject*);
|
||||||
|
afxConstraintID setReferenceObjectByScopeId(StringTableEntry which, U16 scope_id, bool is_shape);
|
||||||
|
afxConstraintID setReferenceEffect(StringTableEntry which, afxEffectWrapper*);
|
||||||
|
afxConstraintID createReferenceEffect(StringTableEntry which, afxEffectWrapper*);
|
||||||
|
|
||||||
|
void setReferencePoint(afxConstraintID which_id, Point3F point);
|
||||||
|
void setReferencePoint(afxConstraintID which_id, Point3F point, Point3F vector);
|
||||||
|
void setReferenceTransform(afxConstraintID which_id, MatrixF& xfm);
|
||||||
|
void setReferenceObject(afxConstraintID which_id, SceneObject*);
|
||||||
|
void setReferenceObjectByScopeId(afxConstraintID which_id, U16 scope_id, bool is_shape);
|
||||||
|
void setReferenceEffect(afxConstraintID which_id, afxEffectWrapper*);
|
||||||
|
|
||||||
|
void invalidateReference(afxConstraintID which_id);
|
||||||
|
|
||||||
|
afxConstraintID getConstraintId(const afxConstraintDef&);
|
||||||
|
afxConstraint* getConstraint(afxConstraintID cons_id);
|
||||||
|
|
||||||
|
void sample(F32 dt, U32 now, const Point3F* cam_pos=0);
|
||||||
|
|
||||||
|
void setStartTime(U32 timestamp) { starttime = timestamp; }
|
||||||
|
void initConstraintDefs(Vector<afxConstraintDef>&, bool on_server, F32 scoping_dist=-1.0f);
|
||||||
|
void packConstraintNames(NetConnection* conn, BitStream* stream);
|
||||||
|
void unpackConstraintNames(BitStream* stream);
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// scope-tracking
|
||||||
|
private:
|
||||||
|
Vector<SceneObject*> scopeable_objs;
|
||||||
|
Vector<U16> scopeable_ids;
|
||||||
|
Vector<afxConstraint*>* missing_objs;
|
||||||
|
Vector<afxConstraint*>* missing_objs2;
|
||||||
|
Vector<afxConstraint*> missing_objs_a;
|
||||||
|
Vector<afxConstraint*> missing_objs_b;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void addScopeableObject(SceneObject*);
|
||||||
|
void removeScopeableObject(SceneObject*);
|
||||||
|
void clearAllScopeableObjs();
|
||||||
|
|
||||||
|
void postMissingConstraintObject(afxConstraint*, bool is_deleting=false);
|
||||||
|
void restoreScopedObject(SceneObject*, afxChoreographer* ch);
|
||||||
|
void adjustProcessOrdering(afxChoreographer*);
|
||||||
|
|
||||||
|
F32 getScopingDistanceSquared() const { return scoping_dist_sq; }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline afxConstraintID afxConstraintMgr::setReferencePoint(StringTableEntry which, Point3F point)
|
||||||
|
{
|
||||||
|
return setReferencePoint(which, point, Point3F(0,0,1));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void afxConstraintMgr::setReferencePoint(afxConstraintID which, Point3F point)
|
||||||
|
{
|
||||||
|
setReferencePoint(which, point, Point3F(0,0,1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxPointConstraint
|
||||||
|
// This constrains to a specific 3D position such as an impact location.
|
||||||
|
//
|
||||||
|
|
||||||
|
class afxPointConstraint : public afxConstraint
|
||||||
|
{
|
||||||
|
typedef afxConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Point3F point;
|
||||||
|
Point3F vector;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxPointConstraint(afxConstraintMgr*);
|
||||||
|
virtual ~afxPointConstraint();
|
||||||
|
|
||||||
|
virtual void set(Point3F point, Point3F vector);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual SceneObject* getSceneObject() { return 0; }
|
||||||
|
virtual void restoreObject(SceneObject*) { }
|
||||||
|
virtual U16 getScopeId() { return 0; }
|
||||||
|
virtual U32 getTriggers() { return 0; }
|
||||||
|
|
||||||
|
virtual void unset() { set(Point3F::Zero, Point3F(0,0,1)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxTransformConstraint
|
||||||
|
// This constrains to a specific 3D transformation.
|
||||||
|
//
|
||||||
|
|
||||||
|
class afxTransformConstraint : public afxConstraint
|
||||||
|
{
|
||||||
|
typedef afxConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MatrixF xfm;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxTransformConstraint(afxConstraintMgr*);
|
||||||
|
virtual ~afxTransformConstraint();
|
||||||
|
|
||||||
|
virtual void set(const MatrixF& xfm);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual SceneObject* getSceneObject() { return 0; }
|
||||||
|
virtual void restoreObject(SceneObject*) { }
|
||||||
|
virtual U16 getScopeId() { return 0; }
|
||||||
|
virtual U32 getTriggers() { return 0; }
|
||||||
|
|
||||||
|
virtual void unset() { set(MatrixF::Identity); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxShapeConstraint
|
||||||
|
// This constrains to a hierarchical shape (subclasses of ShapeBase), such as a
|
||||||
|
// Player or a Vehicle. You can also constrain to named sub-nodes of a shape.
|
||||||
|
|
||||||
|
class ShapeBase;
|
||||||
|
class SceneObject;
|
||||||
|
|
||||||
|
class afxShapeConstraint : public afxConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StringTableEntry arb_name;
|
||||||
|
ShapeBase* shape;
|
||||||
|
U16 scope_id;
|
||||||
|
U32 clip_tag;
|
||||||
|
U32 lock_tag;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxShapeConstraint(afxConstraintMgr*);
|
||||||
|
/*C*/ afxShapeConstraint(afxConstraintMgr*, StringTableEntry arb_name);
|
||||||
|
virtual ~afxShapeConstraint();
|
||||||
|
|
||||||
|
virtual void set(ShapeBase* shape);
|
||||||
|
virtual void set_scope_id(U16 scope_id);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual U32 setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans, bool is_death_anim);
|
||||||
|
virtual void resetAnimation(U32 tag);
|
||||||
|
virtual U32 lockAnimation();
|
||||||
|
virtual void unlockAnimation(U32 tag);
|
||||||
|
virtual F32 getAnimClipDuration(const char* clip);
|
||||||
|
|
||||||
|
void remapAnimation(U32 tag, ShapeBase* other_shape);
|
||||||
|
|
||||||
|
virtual S32 getDamageState();
|
||||||
|
|
||||||
|
virtual SceneObject* getSceneObject() { return shape; }
|
||||||
|
virtual void restoreObject(SceneObject*);
|
||||||
|
virtual U16 getScopeId() { return scope_id; }
|
||||||
|
virtual U32 getTriggers();
|
||||||
|
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
|
||||||
|
virtual void unset() { set(0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxShapeNodeConstraint
|
||||||
|
|
||||||
|
class afxShapeNodeConstraint : public afxShapeConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxShapeConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StringTableEntry arb_node;
|
||||||
|
S32 shape_node_ID;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxShapeNodeConstraint(afxConstraintMgr*);
|
||||||
|
/*C*/ afxShapeNodeConstraint(afxConstraintMgr*, StringTableEntry arb_name, StringTableEntry arb_node);
|
||||||
|
|
||||||
|
virtual void set(ShapeBase* shape);
|
||||||
|
virtual void set_scope_id(U16 scope_id);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
virtual void restoreObject(SceneObject*);
|
||||||
|
|
||||||
|
S32 getNodeID() const { return shape_node_ID; }
|
||||||
|
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxObjectConstraint
|
||||||
|
// This constrains to a simple 3D object (subclasses of SceneObject), such as an
|
||||||
|
// afxMagicMissile or a Projectile. You cannot constrain to sub-nodes with an
|
||||||
|
// afxObjectConstraint, use afxShapeConstraint instead.
|
||||||
|
|
||||||
|
class SceneObject;
|
||||||
|
|
||||||
|
class afxObjectConstraint : public afxConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StringTableEntry arb_name;
|
||||||
|
SceneObject* obj;
|
||||||
|
U16 scope_id;
|
||||||
|
bool is_camera;
|
||||||
|
|
||||||
|
public:
|
||||||
|
afxObjectConstraint(afxConstraintMgr*);
|
||||||
|
afxObjectConstraint(afxConstraintMgr*, StringTableEntry arb_name);
|
||||||
|
virtual ~afxObjectConstraint();
|
||||||
|
|
||||||
|
virtual void set(SceneObject* obj);
|
||||||
|
virtual void set_scope_id(U16 scope_id);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual SceneObject* getSceneObject() { return obj; }
|
||||||
|
virtual void restoreObject(SceneObject*);
|
||||||
|
virtual U16 getScopeId() { return scope_id; }
|
||||||
|
virtual U32 getTriggers();
|
||||||
|
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
|
||||||
|
virtual void unset() { set(0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxEffectConstraint
|
||||||
|
// This constrains to a hierarchical shape (subclasses of ShapeBase), such as a
|
||||||
|
// Player or a Vehicle. You can also constrain to named sub-nodes of a shape.
|
||||||
|
|
||||||
|
class afxEffectWrapper;
|
||||||
|
|
||||||
|
class afxEffectConstraint : public afxConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StringTableEntry effect_name;
|
||||||
|
afxEffectWrapper* effect;
|
||||||
|
U32 clip_tag;
|
||||||
|
bool is_death_clip;
|
||||||
|
U32 lock_tag;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectConstraint(afxConstraintMgr*);
|
||||||
|
/*C*/ afxEffectConstraint(afxConstraintMgr*, StringTableEntry effect_name);
|
||||||
|
virtual ~afxEffectConstraint();
|
||||||
|
|
||||||
|
virtual bool getPosition(Point3F& pos, F32 hist=0.0f);
|
||||||
|
virtual bool getTransform(MatrixF& xfm, F32 hist=0.0f);
|
||||||
|
virtual bool getAltitudes(F32& terrain_alt, F32& interior_alt);
|
||||||
|
|
||||||
|
virtual void set(afxEffectWrapper* effect);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos) { }
|
||||||
|
|
||||||
|
virtual U32 setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans, bool is_death_anim);
|
||||||
|
virtual void resetAnimation(U32 tag);
|
||||||
|
virtual F32 getAnimClipDuration(const char* clip);
|
||||||
|
|
||||||
|
virtual SceneObject* getSceneObject() { return 0; }
|
||||||
|
virtual void restoreObject(SceneObject*) { }
|
||||||
|
virtual U16 getScopeId() { return 0; }
|
||||||
|
virtual U32 getTriggers();
|
||||||
|
|
||||||
|
virtual void unset() { set(0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxEffectNodeConstraint
|
||||||
|
|
||||||
|
class afxEffectNodeConstraint : public afxEffectConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxEffectConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StringTableEntry effect_node;
|
||||||
|
S32 effect_node_ID;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectNodeConstraint(afxConstraintMgr*);
|
||||||
|
/*C*/ afxEffectNodeConstraint(afxConstraintMgr*, StringTableEntry name, StringTableEntry node);
|
||||||
|
|
||||||
|
virtual bool getPosition(Point3F& pos, F32 hist=0.0f);
|
||||||
|
virtual bool getTransform(MatrixF& xfm, F32 hist=0.0f);
|
||||||
|
|
||||||
|
virtual void set(afxEffectWrapper* effect);
|
||||||
|
|
||||||
|
S32 getNodeID() const { return effect_node_ID; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxSampleBuffer
|
||||||
|
|
||||||
|
class afxSampleBuffer
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
U32 buffer_sz;
|
||||||
|
U32 buffer_ms;
|
||||||
|
U32 ms_per_sample;
|
||||||
|
U32 elapsed_ms;
|
||||||
|
U32 last_sample_ms;
|
||||||
|
U32 next_sample_num;
|
||||||
|
U32 n_samples;
|
||||||
|
|
||||||
|
virtual void recSample(U32 idx, void* data) = 0;
|
||||||
|
bool compute_idx_from_lag(F32 lag, U32& idx);
|
||||||
|
bool compute_idx_from_lag(F32 lag, U32& idx1, U32& idx2, F32& t);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxSampleBuffer();
|
||||||
|
virtual ~afxSampleBuffer();
|
||||||
|
|
||||||
|
virtual void configHistory(F32 hist_len, U8 sample_rate);
|
||||||
|
void recordSample(F32 dt, U32 elapsed_ms, void* data);
|
||||||
|
virtual void getSample(F32 lag, void* data, bool& oob) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxSampleXfmBuffer
|
||||||
|
|
||||||
|
class afxSampleXfmBuffer : public afxSampleBuffer
|
||||||
|
{
|
||||||
|
typedef afxSampleBuffer Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MatrixF* xfm_buffer;
|
||||||
|
|
||||||
|
virtual void recSample(U32 idx, void* data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxSampleXfmBuffer();
|
||||||
|
virtual ~afxSampleXfmBuffer();
|
||||||
|
|
||||||
|
virtual void configHistory(F32 hist_len, U8 sample_rate);
|
||||||
|
virtual void getSample(F32 lag, void* data, bool& oob);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxPointHistConstraint
|
||||||
|
// This class extends afxPointConstraint to remember its values for a period of time.
|
||||||
|
|
||||||
|
class afxPointHistConstraint : public afxPointConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxPointConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
afxSampleBuffer* samples;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxPointHistConstraint(afxConstraintMgr*);
|
||||||
|
virtual ~afxPointHistConstraint();
|
||||||
|
|
||||||
|
virtual void set(Point3F point, Point3F vector);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual bool getPosition(Point3F& pos, F32 hist=0.0f);
|
||||||
|
virtual bool getTransform(MatrixF& xfm, F32 hist=0.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxPointHistConstraint
|
||||||
|
// This class extends afxTransformConstraint to remember its values for a period of time.
|
||||||
|
|
||||||
|
class afxTransformHistConstraint : public afxTransformConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxTransformConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
afxSampleBuffer* samples;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxTransformHistConstraint(afxConstraintMgr*);
|
||||||
|
virtual ~afxTransformHistConstraint();
|
||||||
|
|
||||||
|
virtual void set(const MatrixF& xfm);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual bool getPosition(Point3F& pos, F32 hist=0.0f);
|
||||||
|
virtual bool getTransform(MatrixF& xfm, F32 hist=0.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxShapeHistConstraint
|
||||||
|
// This class extends afxShapeConstraint to remember its values for a period of time.
|
||||||
|
|
||||||
|
class afxShapeHistConstraint : public afxShapeConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxShapeConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
afxSampleBuffer* samples;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxShapeHistConstraint(afxConstraintMgr*);
|
||||||
|
/*C*/ afxShapeHistConstraint(afxConstraintMgr*, StringTableEntry arb_name);
|
||||||
|
virtual ~afxShapeHistConstraint();
|
||||||
|
|
||||||
|
virtual void set(ShapeBase* shape);
|
||||||
|
virtual void set_scope_id(U16 scope_id);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual bool getPosition(Point3F& pos, F32 hist=0.0f);
|
||||||
|
virtual bool getTransform(MatrixF& xfm, F32 hist=0.0f);
|
||||||
|
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxShapeNodeHistConstraint
|
||||||
|
// This class extends afxShapeConstraint to remember its values for a period of time.
|
||||||
|
|
||||||
|
class afxShapeNodeHistConstraint : public afxShapeNodeConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxShapeNodeConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
afxSampleBuffer* samples;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxShapeNodeHistConstraint(afxConstraintMgr*);
|
||||||
|
/*C*/ afxShapeNodeHistConstraint(afxConstraintMgr*, StringTableEntry arb_name, StringTableEntry arb_node);
|
||||||
|
virtual ~afxShapeNodeHistConstraint();
|
||||||
|
|
||||||
|
virtual void set(ShapeBase* shape);
|
||||||
|
virtual void set_scope_id(U16 scope_id);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual bool getPosition(Point3F& pos, F32 hist=0.0f);
|
||||||
|
virtual bool getTransform(MatrixF& xfm, F32 hist=0.0f);
|
||||||
|
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxObjectHistConstraint
|
||||||
|
// This class extends afxObjectConstraint to remember its values for a period of time.
|
||||||
|
|
||||||
|
class SceneObject;
|
||||||
|
|
||||||
|
class afxObjectHistConstraint : public afxObjectConstraint
|
||||||
|
{
|
||||||
|
friend class afxConstraintMgr;
|
||||||
|
typedef afxObjectConstraint Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
afxSampleBuffer* samples;
|
||||||
|
|
||||||
|
public:
|
||||||
|
afxObjectHistConstraint(afxConstraintMgr*);
|
||||||
|
afxObjectHistConstraint(afxConstraintMgr*, StringTableEntry arb_name);
|
||||||
|
virtual ~afxObjectHistConstraint();
|
||||||
|
|
||||||
|
virtual void set(SceneObject* obj);
|
||||||
|
virtual void set_scope_id(U16 scope_id);
|
||||||
|
virtual void sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
|
||||||
|
|
||||||
|
virtual bool getPosition(Point3F& pos, F32 hist=0.0f);
|
||||||
|
virtual bool getTransform(MatrixF& xfm, F32 hist=0.0f);
|
||||||
|
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_CONSTRAINT_H_
|
||||||
|
|
||||||
114
Engine/source/afx/afxEffectDefs.h
Normal file
114
Engine/source/afx/afxEffectDefs.h
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_EFFECT_DEFS_H_
|
||||||
|
#define _AFX_EFFECT_DEFS_H_
|
||||||
|
|
||||||
|
#include "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxEffectBASE
|
||||||
|
|
||||||
|
class afxEffectDefs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAX_EFFECTS_PER_PHRASE = 1023,
|
||||||
|
EFFECTS_PER_PHRASE_BITS = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
// effect networking
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SERVER_ONLY = BIT(0),
|
||||||
|
SCOPE_ALWAYS = BIT(1),
|
||||||
|
GHOSTABLE = BIT(2),
|
||||||
|
CLIENT_ONLY = BIT(3),
|
||||||
|
SERVER_AND_CLIENT = BIT(4)
|
||||||
|
};
|
||||||
|
|
||||||
|
// effect condititons
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DISABLED = BIT(0),
|
||||||
|
ENABLED = BIT(1),
|
||||||
|
FAILING = BIT(2),
|
||||||
|
ALIVE = ENABLED,
|
||||||
|
DEAD = DISABLED,
|
||||||
|
DYING = FAILING,
|
||||||
|
//
|
||||||
|
IMPACTED_SOMETHING = BIT(31),
|
||||||
|
IMPACTED_TARGET = BIT(30),
|
||||||
|
IMPACTED_PRIMARY = BIT(29),
|
||||||
|
IMPACT_IN_WATER = BIT(28),
|
||||||
|
CASTER_IN_WATER = BIT(27),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
REQUIRES_STOP = BIT(0),
|
||||||
|
RUNS_ON_SERVER = BIT(1),
|
||||||
|
RUNS_ON_CLIENT = BIT(2),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAX_XFM_MODIFIERS = 32,
|
||||||
|
INFINITE_LIFETIME = (24*60*60)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
POINT_CONSTRAINT,
|
||||||
|
TRANSFORM_CONSTRAINT,
|
||||||
|
OBJECT_CONSTRAINT,
|
||||||
|
CAMERA_CONSTRAINT,
|
||||||
|
OBJECT_CONSTRAINT_SANS_OBJ,
|
||||||
|
OBJECT_CONSTRAINT_SANS_SHAPE,
|
||||||
|
UNDEFINED_CONSTRAINT_TYPE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DIRECT_DAMAGE,
|
||||||
|
DAMAGE_OVER_TIME,
|
||||||
|
AREA_DAMAGE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TIMING_DELAY = BIT(0),
|
||||||
|
TIMING_LIFETIME = BIT(1),
|
||||||
|
TIMING_FADE_IN = BIT(2),
|
||||||
|
TIMING_FADE_OUT = BIT(3),
|
||||||
|
TIMING_BITS = 2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_EFFECT_DEFS_H_
|
||||||
270
Engine/source/afx/afxEffectGroup.cpp
Normal file
270
Engine/source/afx/afxEffectGroup.cpp
Normal file
|
|
@ -0,0 +1,270 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
|
||||||
|
#include "afx/afxEffectGroup.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxEffectGroupData::egValidator
|
||||||
|
//
|
||||||
|
// When an effect is added using "addEffect", this validator intercepts the value
|
||||||
|
// and adds it to the dynamic effects list.
|
||||||
|
//
|
||||||
|
void afxEffectGroupData::egValidator::validateType(SimObject* object, void* typePtr)
|
||||||
|
{
|
||||||
|
afxEffectGroupData* eff_data = dynamic_cast<afxEffectGroupData*>(object);
|
||||||
|
afxEffectBaseData** ew = (afxEffectBaseData**)(typePtr);
|
||||||
|
|
||||||
|
if (eff_data && ew)
|
||||||
|
{
|
||||||
|
eff_data->fx_list.push_back(*ew);
|
||||||
|
*ew = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxEffectGroupData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxEffectGroupData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxEffectGroupData,
|
||||||
|
"@brief A datablock that describes an Effect Group.\n\n"
|
||||||
|
|
||||||
|
"afxEffectGroupData provides a way for adding several effects to a choreographer as a "
|
||||||
|
"group and can be used wherever an afxEffectWrapperData is used. Basically, an "
|
||||||
|
"effect-group is a simple list of effect-wrappers. When an effect-group is added to a "
|
||||||
|
"choreographer, the end result is almost the same as adding all of the group's "
|
||||||
|
"effect-wrappers directly to the choreographer. The main difference is that the "
|
||||||
|
"grouped effects can be turned on and off collectively and created in multiples. "
|
||||||
|
"Effect-groups can also contain other effect-groups, forming a hierarchy of effects.\n\n"
|
||||||
|
|
||||||
|
"A great strength of effect-groups is that they have a count setting that multiplies "
|
||||||
|
"the number of times the effects in the group are added to the owning choreographer "
|
||||||
|
"and this doesn't happen until the choreographer instance is created and launched. "
|
||||||
|
"This makes a big difference for certain kinds of effects, such as fireworks, that "
|
||||||
|
"tend to consist of small groupings of effects that are repeated many times with "
|
||||||
|
"slight variations. With groups, an effect like this has a very compact representation "
|
||||||
|
"for transmitting from server to clients, that only expands when actually used.\n\n"
|
||||||
|
|
||||||
|
"Effect-groups with a count greater than one are extremely useful when some of the "
|
||||||
|
"effects use field substitutions. When an effect-group is expanded, it essentially runs "
|
||||||
|
"through a for-loop from 0 to count-1 and creates a new set of effect instances each "
|
||||||
|
"time through the loop. For each new set of effects, their group-index is set to the "
|
||||||
|
"index of this for-loop, which in turn replaces the ## token used in any field "
|
||||||
|
"substitutions in the child effects. In essence, the for-loop index becomes a parameter "
|
||||||
|
"of the child effects which can be used to vary the effects created in each loop.\n\n"
|
||||||
|
|
||||||
|
"@see afxEffectBaseData\n\n"
|
||||||
|
"@see afxEffectWrapperData\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxEffectGroupData::afxEffectGroupData()
|
||||||
|
{
|
||||||
|
group_enabled = true;
|
||||||
|
group_count = 1;
|
||||||
|
idx_offset = 0;
|
||||||
|
assign_idx = false;
|
||||||
|
|
||||||
|
// dummy entry holds effect-wrapper pointer while a special validator
|
||||||
|
// grabs it and adds it to an appropriate effects list
|
||||||
|
dummy_fx_entry = NULL;
|
||||||
|
|
||||||
|
// marked true if datablock ids need to
|
||||||
|
// be converted into pointers
|
||||||
|
do_id_convert = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxEffectGroupData::afxEffectGroupData(const afxEffectGroupData& other, bool temp_clone) : afxEffectBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
group_enabled = other.group_enabled;
|
||||||
|
group_count = other.group_count;
|
||||||
|
idx_offset = other.idx_offset;
|
||||||
|
assign_idx = other.assign_idx;
|
||||||
|
timing = other.timing;
|
||||||
|
dummy_fx_entry = other.dummy_fx_entry;
|
||||||
|
do_id_convert = other.do_id_convert; // --
|
||||||
|
fx_list = other.fx_list; // --
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectGroupData::reloadReset()
|
||||||
|
{
|
||||||
|
fx_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectGroupData::pack_fx(BitStream* stream, const afxEffectList& fx, bool packed)
|
||||||
|
{
|
||||||
|
stream->writeInt(fx.size(), EFFECTS_PER_PHRASE_BITS);
|
||||||
|
for (int i = 0; i < fx.size(); i++)
|
||||||
|
writeDatablockID(stream, fx[i], packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectGroupData::unpack_fx(BitStream* stream, afxEffectList& fx)
|
||||||
|
{
|
||||||
|
fx.clear();
|
||||||
|
S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS);
|
||||||
|
for (int i = 0; i < n_fx; i++)
|
||||||
|
fx.push_back((afxEffectWrapperData*)readDatablockID(stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxEffectGroupData)
|
||||||
|
|
||||||
|
void afxEffectGroupData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("groupEnabled", TypeBool, myOffset(group_enabled),
|
||||||
|
"...");
|
||||||
|
addField("count", TypeS32, myOffset(group_count),
|
||||||
|
"...");
|
||||||
|
addField("indexOffset", TypeS8, myOffset(idx_offset),
|
||||||
|
"...");
|
||||||
|
addField("assignIndices", TypeBool, myOffset(assign_idx),
|
||||||
|
"...");
|
||||||
|
|
||||||
|
addField("delay", TypeF32, myOffset(timing.delay),
|
||||||
|
"...");
|
||||||
|
addField("lifetime", TypeF32, myOffset(timing.lifetime),
|
||||||
|
"...");
|
||||||
|
addField("fadeInTime", TypeF32, myOffset(timing.fade_in_time),
|
||||||
|
"...");
|
||||||
|
addField("fadeOutTime", TypeF32, myOffset(timing.fade_out_time),
|
||||||
|
"...");
|
||||||
|
|
||||||
|
// effect lists
|
||||||
|
// for each of these, dummy_fx_entry is set and then a validator adds it to the appropriate effects list
|
||||||
|
static egValidator emptyValidator(0);
|
||||||
|
|
||||||
|
addFieldV("addEffect", TYPEID<afxEffectBaseData>(), myOffset(dummy_fx_entry), &emptyValidator,
|
||||||
|
"...");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
|
||||||
|
// disallow some field substitutions
|
||||||
|
disableFieldSubstitutions("addEffect");
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectGroupData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
stream->writeFlag(group_enabled);
|
||||||
|
stream->write(group_count);
|
||||||
|
stream->write(idx_offset);
|
||||||
|
stream->writeFlag(assign_idx);
|
||||||
|
stream->write(timing.delay);
|
||||||
|
stream->write(timing.lifetime);
|
||||||
|
stream->write(timing.fade_in_time);
|
||||||
|
stream->write(timing.fade_out_time);
|
||||||
|
|
||||||
|
pack_fx(stream, fx_list, packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectGroupData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
group_enabled = stream->readFlag();
|
||||||
|
stream->read(&group_count);
|
||||||
|
stream->read(&idx_offset);
|
||||||
|
assign_idx = stream->readFlag();
|
||||||
|
stream->read(&timing.delay);
|
||||||
|
stream->read(&timing.lifetime);
|
||||||
|
stream->read(&timing.fade_in_time);
|
||||||
|
stream->read(&timing.fade_out_time);
|
||||||
|
|
||||||
|
do_id_convert = true;
|
||||||
|
unpack_fx(stream, fx_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxEffectGroupData::preload(bool server, String &errorStr)
|
||||||
|
{
|
||||||
|
if (!Parent::preload(server, errorStr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Resolve objects transmitted from server
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
if (do_id_convert)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < fx_list.size(); i++)
|
||||||
|
{
|
||||||
|
SimObjectId db_id = SimObjectId((uintptr_t)fx_list[i]);
|
||||||
|
if (db_id != 0)
|
||||||
|
{
|
||||||
|
// try to convert id to pointer
|
||||||
|
if (!Sim::findObject(db_id, fx_list[i]))
|
||||||
|
{
|
||||||
|
Con::errorf(ConsoleLogEntry::General,
|
||||||
|
"afxEffectGroupData::preload() -- bad datablockId: 0x%x",
|
||||||
|
db_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_id_convert = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectGroupData::gather_cons_defs(Vector<afxConstraintDef>& defs)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < fx_list.size(); i++)
|
||||||
|
{
|
||||||
|
if (fx_list[i])
|
||||||
|
fx_list[i]->gather_cons_defs(defs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
DefineEngineMethod(afxEffectGroupData, reset, void, (),,
|
||||||
|
"Resets an effect-group datablock during reload.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
object->reloadReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(afxEffectGroupData, addEffect, void, (afxEffectBaseData* effect),,
|
||||||
|
"Adds an effect (wrapper or group) to an effect-group.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
if (!effect)
|
||||||
|
{
|
||||||
|
Con::errorf("afxEffectGroupData::addEffect() -- missing afxEffectWrapperData.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
object->fx_list.push_back(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
103
Engine/source/afx/afxEffectGroup.h
Normal file
103
Engine/source/afx/afxEffectGroup.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_EFFECT_GROUP_H_
|
||||||
|
#define _AFX_EFFECT_GROUP_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "console/typeValidators.h"
|
||||||
|
|
||||||
|
#include "afx/afxEffectDefs.h"
|
||||||
|
#include "afx/afxEffectWrapper.h"
|
||||||
|
|
||||||
|
class afxEffectWrapperData;
|
||||||
|
|
||||||
|
struct afxGroupTimingData
|
||||||
|
{
|
||||||
|
F32 delay;
|
||||||
|
F32 lifetime;
|
||||||
|
F32 fade_in_time;
|
||||||
|
F32 fade_out_time;
|
||||||
|
|
||||||
|
afxGroupTimingData()
|
||||||
|
{
|
||||||
|
delay = 0.0f;
|
||||||
|
lifetime = 0.0f;
|
||||||
|
fade_in_time = 0.0f;
|
||||||
|
fade_out_time = 0.0f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class afxEffectGroupData : public afxEffectBaseData
|
||||||
|
{
|
||||||
|
typedef afxEffectBaseData Parent;
|
||||||
|
|
||||||
|
class egValidator : public TypeValidator
|
||||||
|
{
|
||||||
|
U32 id;
|
||||||
|
public:
|
||||||
|
egValidator(U32 id) { this->id = id; }
|
||||||
|
void validateType(SimObject *object, void *typePtr);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool do_id_convert;
|
||||||
|
|
||||||
|
public:
|
||||||
|
afxEffectList fx_list;
|
||||||
|
bool group_enabled;
|
||||||
|
S32 group_count;
|
||||||
|
U8 idx_offset;
|
||||||
|
bool assign_idx;
|
||||||
|
afxGroupTimingData timing;
|
||||||
|
afxEffectBaseData* dummy_fx_entry;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void pack_fx(BitStream* stream, const afxEffectList& fx, bool packed);
|
||||||
|
void unpack_fx(BitStream* stream, afxEffectList& fx);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectGroupData();
|
||||||
|
/*C*/ afxEffectGroupData(const afxEffectGroupData&, bool = false);
|
||||||
|
|
||||||
|
virtual void reloadReset();
|
||||||
|
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
virtual void gather_cons_defs(Vector<afxConstraintDef>& defs);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxEffectGroupData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
#endif // _AFX_EFFECT_GROUP_H_
|
||||||
358
Engine/source/afx/afxEffectVector.cpp
Normal file
358
Engine/source/afx/afxEffectVector.cpp
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "afxChoreographer.h"
|
||||||
|
#include "afxEffectVector.h"
|
||||||
|
#include "afxConstraint.h"
|
||||||
|
#include "afxEffectWrapper.h"
|
||||||
|
#include "afxEffectGroup.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxEffectVector::filter_client_server()
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (S32 i = 0; i < fx_v->size(); i++)
|
||||||
|
{
|
||||||
|
if ((*fx_v)[i]->datablock->runsHere(on_server))
|
||||||
|
fx_v2->push_back((*fx_v)[i]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete (*fx_v)[i];
|
||||||
|
(*fx_v)[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_vecs();
|
||||||
|
|
||||||
|
fx_v2->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectVector::calc_fx_dur_and_afterlife()
|
||||||
|
{
|
||||||
|
total_fx_dur = 0.0f;
|
||||||
|
after_life = 0.0f;
|
||||||
|
|
||||||
|
if (empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (S32 i = 0; i < fx_v->size(); i++)
|
||||||
|
{
|
||||||
|
afxEffectWrapper* ew = (*fx_v)[i];
|
||||||
|
if (ew)
|
||||||
|
{
|
||||||
|
F32 ew_dur;
|
||||||
|
if (ew->ew_timing.lifetime < 0)
|
||||||
|
{
|
||||||
|
if (phrase_dur > ew->ew_timing.delay)
|
||||||
|
ew_dur = phrase_dur + ew->afterStopTime();
|
||||||
|
else
|
||||||
|
ew_dur = ew->ew_timing.delay + ew->afterStopTime();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ew_dur = ew->ew_timing.delay + ew->ew_timing.lifetime + ew->ew_timing.fade_out_time;
|
||||||
|
|
||||||
|
if (ew_dur > total_fx_dur)
|
||||||
|
total_fx_dur = ew_dur;
|
||||||
|
|
||||||
|
F32 after = ew->afterStopTime();
|
||||||
|
if (after > after_life)
|
||||||
|
after_life = after;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
afxEffectVector::afxEffectVector()
|
||||||
|
{
|
||||||
|
fx_v = 0;
|
||||||
|
fx_v2 = 0;
|
||||||
|
active = false;
|
||||||
|
on_server = false;
|
||||||
|
total_fx_dur = 0;
|
||||||
|
after_life = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxEffectVector::~afxEffectVector()
|
||||||
|
{
|
||||||
|
stop(true);
|
||||||
|
delete fx_v;
|
||||||
|
delete fx_v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectVector::effects_init(afxChoreographer* chor, afxEffectList& effects, bool will_stop, F32 time_factor,
|
||||||
|
S32 group_index, const afxGroupTimingData* group_timing)
|
||||||
|
{
|
||||||
|
afxConstraintMgr* cons_mgr = chor->getConstraintMgr();
|
||||||
|
|
||||||
|
for (S32 i = 0; i < effects.size(); i++)
|
||||||
|
{
|
||||||
|
if (dynamic_cast<afxEffectGroupData*>(effects[i]))
|
||||||
|
{
|
||||||
|
afxEffectGroupData* eg = (afxEffectGroupData*)effects[i];
|
||||||
|
if (eg->getSubstitutionCount() > 0)
|
||||||
|
{
|
||||||
|
// clone the datablock and perform substitutions
|
||||||
|
afxEffectGroupData* orig_db = eg;
|
||||||
|
eg = new afxEffectGroupData(*orig_db, true);
|
||||||
|
orig_db->performSubstitutions(eg, chor, group_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eg->group_enabled)
|
||||||
|
{
|
||||||
|
if (eg->assign_idx)
|
||||||
|
{
|
||||||
|
for (S32 j = 0; j < eg->group_count; j++)
|
||||||
|
effects_init(chor, eg->fx_list, will_stop, time_factor, j+eg->idx_offset, &eg->timing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (S32 j = 0; j < eg->group_count; j++)
|
||||||
|
effects_init(chor, eg->fx_list, will_stop, time_factor, group_index, &eg->timing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eg->isTempClone())
|
||||||
|
delete eg;
|
||||||
|
}
|
||||||
|
else if (dynamic_cast<afxEffectWrapperData*>(effects[i]))
|
||||||
|
{
|
||||||
|
afxEffectWrapperData* ewd = (afxEffectWrapperData*)effects[i];
|
||||||
|
|
||||||
|
if (ewd->getSubstitutionCount() > 0)
|
||||||
|
{
|
||||||
|
// clone the ewd and perform substitutions
|
||||||
|
afxEffectWrapperData* orig_db = ewd;
|
||||||
|
ewd = new afxEffectWrapperData(*orig_db, true);
|
||||||
|
orig_db->performSubstitutions(ewd, chor, group_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ewd->effect_enabled)
|
||||||
|
{
|
||||||
|
static afxEffectTimingData inherited_timing;
|
||||||
|
bool use_inherited_timing = false;
|
||||||
|
if (ewd->inherit_timing != 0)
|
||||||
|
{
|
||||||
|
if (group_timing)
|
||||||
|
{
|
||||||
|
inherited_timing = ewd->ewd_timing;
|
||||||
|
if ((ewd->inherit_timing & afxEffectDefs::TIMING_DELAY) != 0)
|
||||||
|
inherited_timing.delay = group_timing->delay;
|
||||||
|
if ((ewd->inherit_timing & afxEffectDefs::TIMING_LIFETIME) != 0)
|
||||||
|
inherited_timing.lifetime = group_timing->lifetime;
|
||||||
|
if ((ewd->inherit_timing & afxEffectDefs::TIMING_FADE_IN) != 0)
|
||||||
|
inherited_timing.fade_in_time = group_timing->fade_in_time;
|
||||||
|
if ((ewd->inherit_timing & afxEffectDefs::TIMING_FADE_OUT) != 0)
|
||||||
|
inherited_timing.fade_out_time = group_timing->fade_out_time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con::warnf("afxEffectVector::effects_init() -- %s::inheritGroupTiming is non-zero but wrapper is not in a group.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const afxEffectTimingData& timing = (use_inherited_timing) ? inherited_timing : ewd->ewd_timing;
|
||||||
|
|
||||||
|
if ( (will_stop || !ewd->requiresStop(timing)) &&
|
||||||
|
(chor->testRanking(ewd->ranking_range.low, ewd->ranking_range.high)) &&
|
||||||
|
(chor->testLevelOfDetail(ewd->lod_range.low, ewd->lod_range.high)) &&
|
||||||
|
(ewd->testExecConditions(chor->getExecConditions()))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
afxEffectWrapper* effect;
|
||||||
|
effect = afxEffectWrapper::ew_create(chor, ewd, cons_mgr, time_factor, group_index);
|
||||||
|
if (effect)
|
||||||
|
fx_v->push_back(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ewd->isTempClone())
|
||||||
|
delete ewd;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectVector::ev_init(afxChoreographer* chor, afxEffectList& effects, bool on_server,
|
||||||
|
bool will_stop, F32 time_factor, F32 phrase_dur, S32 group_index)
|
||||||
|
{
|
||||||
|
this->on_server = on_server;
|
||||||
|
this->phrase_dur = phrase_dur;
|
||||||
|
|
||||||
|
fx_v = new Vector<afxEffectWrapper*>;
|
||||||
|
|
||||||
|
effects_init(chor, effects, will_stop, time_factor, group_index);
|
||||||
|
|
||||||
|
fx_v2 = new Vector<afxEffectWrapper*>(fx_v->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectVector::start(F32 timestamp)
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// At this point both client and server effects are in the list.
|
||||||
|
// Timing adjustments are made during prestart().
|
||||||
|
for (S32 i = 0; i < fx_v->size(); i++)
|
||||||
|
(*fx_v)[i]->prestart();
|
||||||
|
|
||||||
|
// duration and afterlife values are pre-calculated here
|
||||||
|
calc_fx_dur_and_afterlife();
|
||||||
|
|
||||||
|
// now we filter out client-only or server-only effects that
|
||||||
|
// don't belong here,
|
||||||
|
filter_client_server();
|
||||||
|
|
||||||
|
active = true;
|
||||||
|
|
||||||
|
for (S32 j = 0; j < fx_v->size(); j++)
|
||||||
|
{
|
||||||
|
if ((*fx_v)[j]->start(timestamp))
|
||||||
|
fx_v2->push_back((*fx_v)[j]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete (*fx_v)[j];
|
||||||
|
(*fx_v)[j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_vecs();
|
||||||
|
fx_v2->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectVector::update(F32 dt)
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fx_v->size(); i++)
|
||||||
|
{
|
||||||
|
(*fx_v)[i]->update(dt);
|
||||||
|
|
||||||
|
if ((*fx_v)[i]->isDone() || (*fx_v)[i]->isAborted())
|
||||||
|
{
|
||||||
|
// effect has ended, cleanup and delete
|
||||||
|
(*fx_v)[i]->cleanup();
|
||||||
|
delete (*fx_v)[i];
|
||||||
|
(*fx_v)[i] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// effect is still going, so keep it around
|
||||||
|
fx_v2->push_back((*fx_v)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_vecs();
|
||||||
|
|
||||||
|
fx_v2->clear();
|
||||||
|
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
delete fx_v; fx_v =0;
|
||||||
|
delete fx_v2; fx_v2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectVector::stop(bool force_cleanup)
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fx_v->size(); i++)
|
||||||
|
{
|
||||||
|
(*fx_v)[i]->stop();
|
||||||
|
|
||||||
|
if (force_cleanup || (*fx_v)[i]->deleteWhenStopped())
|
||||||
|
{
|
||||||
|
// effect is over when stopped, cleanup and delete
|
||||||
|
(*fx_v)[i]->cleanup();
|
||||||
|
delete (*fx_v)[i];
|
||||||
|
(*fx_v)[i] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// effect needs to fadeout or something, so keep it around
|
||||||
|
fx_v2->push_back((*fx_v)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_vecs();
|
||||||
|
|
||||||
|
fx_v2->clear();
|
||||||
|
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
delete fx_v; fx_v =0;
|
||||||
|
delete fx_v2; fx_v2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxEffectVector::interrupt()
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fx_v->size(); i++)
|
||||||
|
{
|
||||||
|
(*fx_v)[i]->stop();
|
||||||
|
(*fx_v)[i]->cleanup();
|
||||||
|
delete (*fx_v)[i];
|
||||||
|
(*fx_v)[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_vecs();
|
||||||
|
|
||||||
|
fx_v2->clear();
|
||||||
|
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
delete fx_v; fx_v =0;
|
||||||
|
delete fx_v2; fx_v2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
|
||||||
86
Engine/source/afx/afxEffectVector.h
Normal file
86
Engine/source/afx/afxEffectVector.h
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_EFFECT_VECTOR_H_
|
||||||
|
#define _AFX_EFFECT_VECTOR_H_
|
||||||
|
|
||||||
|
#include "afx/afxEffectWrapper.h"
|
||||||
|
#include "afx/afxEffectGroup.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxEffectVector
|
||||||
|
|
||||||
|
class afxEffectWrapper;
|
||||||
|
class afxChoreographer;
|
||||||
|
|
||||||
|
class afxEffectVector
|
||||||
|
{
|
||||||
|
Vector<afxEffectWrapper*>* fx_v;
|
||||||
|
Vector<afxEffectWrapper*>* fx_v2;
|
||||||
|
|
||||||
|
bool active;
|
||||||
|
bool on_server;
|
||||||
|
F32 phrase_dur;
|
||||||
|
F32 total_fx_dur;
|
||||||
|
F32 after_life;
|
||||||
|
|
||||||
|
void swap_vecs();
|
||||||
|
void filter_client_server();
|
||||||
|
void calc_fx_dur_and_afterlife();
|
||||||
|
|
||||||
|
void effects_init(afxChoreographer*, afxEffectList&, bool will_stop, F32 time_factor,
|
||||||
|
S32 group_index, const afxGroupTimingData* group_timing=0);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectVector();
|
||||||
|
/*D*/ ~afxEffectVector();
|
||||||
|
|
||||||
|
void ev_init(afxChoreographer*, afxEffectList&, bool on_server, bool will_stop,
|
||||||
|
F32 time_factor, F32 phrase_dur, S32 group_index=0);
|
||||||
|
|
||||||
|
void start(F32 timestamp);
|
||||||
|
void update(F32 dt);
|
||||||
|
void stop(bool force_cleanup=false);
|
||||||
|
void interrupt();
|
||||||
|
bool empty() { return (!fx_v || fx_v->empty()); }
|
||||||
|
bool isActive() { return active; }
|
||||||
|
S32 count() { return (fx_v) ? fx_v->size() : 0; }
|
||||||
|
|
||||||
|
F32 getTotalDur() { return total_fx_dur; }
|
||||||
|
F32 getAfterLife() { return after_life; }
|
||||||
|
|
||||||
|
Vector<afxEffectWrapper*>* getFX() { return fx_v; }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void afxEffectVector::swap_vecs()
|
||||||
|
{
|
||||||
|
Vector<afxEffectWrapper*>* tmp = fx_v;
|
||||||
|
fx_v = fx_v2;
|
||||||
|
fx_v2 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_EFFECT_VECTOR_H_
|
||||||
1193
Engine/source/afx/afxEffectWrapper.cpp
Normal file
1193
Engine/source/afx/afxEffectWrapper.cpp
Normal file
File diff suppressed because it is too large
Load diff
392
Engine/source/afx/afxEffectWrapper.h
Normal file
392
Engine/source/afx/afxEffectWrapper.h
Normal file
|
|
@ -0,0 +1,392 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_EFFECT_WRAPPER_H_
|
||||||
|
#define _AFX_EFFECT_WRAPPER_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "afx/arcaneFX.h"
|
||||||
|
#include "afxEffectDefs.h"
|
||||||
|
#include "afxConstraint.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
struct afxEffectTimingData
|
||||||
|
{
|
||||||
|
F32 delay;
|
||||||
|
F32 lifetime;
|
||||||
|
F32 fade_in_time;
|
||||||
|
F32 fade_out_time;
|
||||||
|
F32 residue_lifetime;
|
||||||
|
F32 residue_fadetime;
|
||||||
|
F32 life_bias;
|
||||||
|
Point2F fadein_ease;
|
||||||
|
Point2F fadeout_ease;
|
||||||
|
|
||||||
|
afxEffectTimingData()
|
||||||
|
{
|
||||||
|
delay = 0.0f;
|
||||||
|
lifetime = 0.0f;
|
||||||
|
fade_in_time = 0.0f;
|
||||||
|
fade_out_time = 0.0f;
|
||||||
|
residue_lifetime = 0.0f;
|
||||||
|
residue_fadetime = 0.0f;
|
||||||
|
life_bias = 1.0f;
|
||||||
|
fadein_ease.set(0.0f, 1.0f);
|
||||||
|
fadeout_ease.set(0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class afxEffectWrapperData;
|
||||||
|
class afxAnimCurve;
|
||||||
|
|
||||||
|
class afxEffectAdapterDesc
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static Vector<afxEffectAdapterDesc*>* adapters;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectAdapterDesc();
|
||||||
|
|
||||||
|
virtual bool testEffectType(const SimDataBlock*) const=0;
|
||||||
|
virtual bool requiresStop(const afxEffectWrapperData*, const afxEffectTimingData&) const=0;
|
||||||
|
virtual bool runsOnServer(const afxEffectWrapperData*) const=0;
|
||||||
|
virtual bool runsOnClient(const afxEffectWrapperData*) const=0;
|
||||||
|
virtual bool isPositional(const afxEffectWrapperData*) const { return true; }
|
||||||
|
virtual void prepEffect(afxEffectWrapperData*) const { }
|
||||||
|
|
||||||
|
virtual afxEffectWrapper* create() const=0;
|
||||||
|
|
||||||
|
static bool identifyEffect(afxEffectWrapperData*);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class afxXM_BaseData;
|
||||||
|
|
||||||
|
class afxEffectBaseData : public GameBaseData, public afxEffectDefs
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectBaseData() { }
|
||||||
|
/*C*/ afxEffectBaseData(const afxEffectBaseData& other, bool temp=false) : GameBaseData(other, temp){ }
|
||||||
|
|
||||||
|
virtual void gather_cons_defs(Vector<afxConstraintDef>& defs) { };
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxEffectBaseData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//class afxEffectWrapperData : public GameBaseData, public afxEffectDefs
|
||||||
|
class afxEffectWrapperData : public afxEffectBaseData
|
||||||
|
{
|
||||||
|
//typedef GameBaseData Parent;
|
||||||
|
typedef afxEffectBaseData Parent;
|
||||||
|
|
||||||
|
bool do_id_convert;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { MAX_CONDITION_STATES = 4 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringTableEntry effect_name;
|
||||||
|
bool use_as_cons_obj;
|
||||||
|
bool use_ghost_as_cons_obj;
|
||||||
|
|
||||||
|
StringTableEntry cons_spec;
|
||||||
|
StringTableEntry pos_cons_spec;
|
||||||
|
StringTableEntry orient_cons_spec;
|
||||||
|
StringTableEntry aim_cons_spec;
|
||||||
|
StringTableEntry life_cons_spec;
|
||||||
|
//
|
||||||
|
afxConstraintDef cons_def;
|
||||||
|
afxConstraintDef pos_cons_def;
|
||||||
|
afxConstraintDef orient_cons_def;
|
||||||
|
afxConstraintDef aim_cons_def;
|
||||||
|
afxConstraintDef life_cons_def;
|
||||||
|
|
||||||
|
afxEffectTimingData ewd_timing;
|
||||||
|
U32 inherit_timing;
|
||||||
|
|
||||||
|
F32 scale_factor; // scale size if applicable
|
||||||
|
F32 rate_factor; // scale rate if applicable
|
||||||
|
F32 user_fade_out_time;
|
||||||
|
|
||||||
|
bool is_looping;
|
||||||
|
U32 n_loops;
|
||||||
|
F32 loop_gap_time;
|
||||||
|
|
||||||
|
bool ignore_time_factor;
|
||||||
|
bool propagate_time_factor;
|
||||||
|
|
||||||
|
ByteRange ranking_range;
|
||||||
|
ByteRange lod_range;
|
||||||
|
S32 life_conds;
|
||||||
|
bool effect_enabled;
|
||||||
|
U32 exec_cond_on_bits[MAX_CONDITION_STATES];
|
||||||
|
U32 exec_cond_off_bits[MAX_CONDITION_STATES];
|
||||||
|
U32 exec_cond_bitmasks[MAX_CONDITION_STATES];
|
||||||
|
|
||||||
|
S32 data_ID;
|
||||||
|
|
||||||
|
afxXM_BaseData* xfm_modifiers[MAX_XFM_MODIFIERS];
|
||||||
|
|
||||||
|
Box3F forced_bbox;
|
||||||
|
bool update_forced_bbox;
|
||||||
|
|
||||||
|
S8 sort_priority;
|
||||||
|
Point3F direction;
|
||||||
|
F32 speed;
|
||||||
|
F32 mass;
|
||||||
|
|
||||||
|
bool borrow_altitudes;
|
||||||
|
StringTableEntry vis_keys_spec;
|
||||||
|
afxAnimCurve* vis_keys;
|
||||||
|
|
||||||
|
SimDataBlock* effect_data;
|
||||||
|
afxEffectAdapterDesc* effect_desc;
|
||||||
|
|
||||||
|
S32 group_index;
|
||||||
|
|
||||||
|
void parse_cons_specs();
|
||||||
|
void parse_vis_keys();
|
||||||
|
void gather_cons_defs(Vector<afxConstraintDef>& defs);
|
||||||
|
void pack_mods(BitStream*, afxXM_BaseData* mods[], bool packed);
|
||||||
|
void unpack_mods(BitStream*, afxXM_BaseData* mods[]);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectWrapperData();
|
||||||
|
/*C*/ afxEffectWrapperData(const afxEffectWrapperData&, bool = false);
|
||||||
|
/*D*/ ~afxEffectWrapperData();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
virtual void onPerformSubstitutions();
|
||||||
|
|
||||||
|
bool requiresStop(const afxEffectTimingData& timing) { return effect_desc->requiresStop(this, timing); }
|
||||||
|
bool runsOnServer() { return effect_desc->runsOnServer(this); }
|
||||||
|
bool runsOnClient() { return effect_desc->runsOnClient(this); }
|
||||||
|
bool runsHere(bool server_here) { return (server_here) ? runsOnServer() : runsOnClient(); }
|
||||||
|
bool isPositional() { return effect_desc->isPositional(this); }
|
||||||
|
bool testExecConditions(U32 conditions);
|
||||||
|
|
||||||
|
F32 afterStopTime() { return ewd_timing.fade_out_time; }
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxEffectWrapperData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool afxEffectWrapperData::testExecConditions(U32 conditions)
|
||||||
|
{
|
||||||
|
if (exec_cond_bitmasks[0] == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ((exec_cond_bitmasks[0] & conditions) == exec_cond_on_bits[0])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (S32 i = 1; i < MAX_CONDITION_STATES; i++)
|
||||||
|
{
|
||||||
|
if (exec_cond_bitmasks[i] == 0)
|
||||||
|
return false;
|
||||||
|
if ((exec_cond_bitmasks[i] & conditions) == exec_cond_on_bits[i])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Vector<afxEffectBaseData*> afxEffectList;
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxEffectWrapper
|
||||||
|
//
|
||||||
|
// NOTE -- this not a subclass of GameBase... it is only meant to exist on
|
||||||
|
// the client-side.
|
||||||
|
|
||||||
|
class ShapeBase;
|
||||||
|
class GameBase;
|
||||||
|
class TSShape;
|
||||||
|
class TSShapeInstance;
|
||||||
|
class SceneObject;
|
||||||
|
class afxConstraint;
|
||||||
|
class afxConstraintMgr;
|
||||||
|
class afxChoreographer;
|
||||||
|
class afxXM_Base;
|
||||||
|
|
||||||
|
class afxEffectWrapper : public SimObject, public afxEffectDefs
|
||||||
|
{
|
||||||
|
typedef SimObject Parent;
|
||||||
|
friend class afxEffectVector;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool test_life_conds();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
afxEffectWrapperData* datablock;
|
||||||
|
|
||||||
|
afxEffectTimingData ew_timing;
|
||||||
|
|
||||||
|
F32 fade_in_end;
|
||||||
|
F32 fade_out_start;
|
||||||
|
F32 full_lifetime;
|
||||||
|
|
||||||
|
F32 time_factor;
|
||||||
|
F32 prop_time_factor;
|
||||||
|
|
||||||
|
afxChoreographer* choreographer;
|
||||||
|
afxConstraintMgr* cons_mgr;
|
||||||
|
|
||||||
|
afxConstraintID pos_cons_id;
|
||||||
|
afxConstraintID orient_cons_id;
|
||||||
|
afxConstraintID aim_cons_id;
|
||||||
|
afxConstraintID life_cons_id;
|
||||||
|
|
||||||
|
afxConstraintID effect_cons_id;
|
||||||
|
|
||||||
|
F32 elapsed;
|
||||||
|
F32 life_elapsed;
|
||||||
|
F32 life_end;
|
||||||
|
bool stopped;
|
||||||
|
bool cond_alive;
|
||||||
|
|
||||||
|
U32 n_updates;
|
||||||
|
|
||||||
|
MatrixF updated_xfm;
|
||||||
|
Point3F updated_pos;
|
||||||
|
Point3F updated_aim;
|
||||||
|
Point3F updated_scale;
|
||||||
|
LinearColorF updated_color;
|
||||||
|
|
||||||
|
F32 fade_value;
|
||||||
|
F32 last_fade_value;
|
||||||
|
|
||||||
|
bool do_fade_inout;
|
||||||
|
bool do_fades;
|
||||||
|
bool in_scope;
|
||||||
|
bool is_aborted;
|
||||||
|
|
||||||
|
U8 effect_flags;
|
||||||
|
|
||||||
|
afxXM_Base* xfm_modifiers[MAX_XFM_MODIFIERS];
|
||||||
|
|
||||||
|
F32 live_scale_factor;
|
||||||
|
F32 live_fade_factor;
|
||||||
|
F32 terrain_altitude;
|
||||||
|
F32 interior_altitude;
|
||||||
|
|
||||||
|
S32 group_index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectWrapper();
|
||||||
|
virtual ~afxEffectWrapper();
|
||||||
|
|
||||||
|
void ew_init(afxChoreographer*, afxEffectWrapperData*, afxConstraintMgr*,
|
||||||
|
F32 time_factor);
|
||||||
|
|
||||||
|
F32 getFullLifetime() { return ew_timing.lifetime + ew_timing.fade_out_time; }
|
||||||
|
F32 getTimeFactor() { return time_factor; }
|
||||||
|
afxConstraint* getPosConstraint() { return cons_mgr->getConstraint(pos_cons_id); }
|
||||||
|
afxConstraint* getOrientConstraint() { return cons_mgr->getConstraint(orient_cons_id); }
|
||||||
|
afxConstraint* getAimConstraint() { return cons_mgr->getConstraint(aim_cons_id); }
|
||||||
|
afxConstraint* getLifeConstraint() { return cons_mgr->getConstraint(life_cons_id); }
|
||||||
|
afxChoreographer* getChoreographer() { return choreographer; }
|
||||||
|
|
||||||
|
virtual bool isDone();
|
||||||
|
virtual bool deleteWhenStopped() { return false; }
|
||||||
|
F32 afterStopTime() { return ew_timing.fade_out_time; }
|
||||||
|
bool isAborted() const { return is_aborted; }
|
||||||
|
|
||||||
|
void prestart();
|
||||||
|
bool start(F32 timestamp);
|
||||||
|
bool update(F32 dt);
|
||||||
|
void stop();
|
||||||
|
void cleanup(bool was_stopped=false);
|
||||||
|
void setScopeStatus(bool flag);
|
||||||
|
|
||||||
|
virtual void ea_set_datablock(SimDataBlock*) { }
|
||||||
|
virtual bool ea_start() { return true; }
|
||||||
|
virtual bool ea_update(F32 dt) { return true; }
|
||||||
|
virtual void ea_finish(bool was_stopped) { }
|
||||||
|
virtual void ea_set_scope_status(bool flag) { }
|
||||||
|
virtual bool ea_is_enabled() { return true; }
|
||||||
|
virtual SceneObject* ea_get_scene_object() const { return 0; }
|
||||||
|
U32 ea_get_triggers() const { return 0; }
|
||||||
|
|
||||||
|
void getUpdatedPosition(Point3F& pos) { pos = updated_pos;}
|
||||||
|
void getUpdatedTransform(MatrixF& xfm) { xfm = updated_xfm; }
|
||||||
|
void getUpdatedScale(Point3F& scale) { scale = updated_scale; }
|
||||||
|
void getUpdatedColor(LinearColorF& color) { color = updated_color; }
|
||||||
|
virtual void getUpdatedBoxCenter(Point3F& pos) { pos = updated_pos;}
|
||||||
|
|
||||||
|
virtual void getUnconstrainedPosition(Point3F& pos) { pos.zero();}
|
||||||
|
virtual void getUnconstrainedTransform(MatrixF& xfm) { xfm.identity(); }
|
||||||
|
virtual void getBaseColor(LinearColorF& color) { color.set(1.0f, 1.0f, 1.0f, 1.0f); }
|
||||||
|
|
||||||
|
SceneObject* getSceneObject() const { return ea_get_scene_object(); }
|
||||||
|
U32 getTriggers() const { return ea_get_triggers(); }
|
||||||
|
|
||||||
|
F32 getMass() { return datablock->mass; }
|
||||||
|
Point3F getDirection() { return datablock->direction; }
|
||||||
|
F32 getSpeed() { return datablock->speed; }
|
||||||
|
|
||||||
|
virtual TSShape* getTSShape() { return 0; }
|
||||||
|
virtual TSShapeInstance* getTSShapeInstance() { return 0; }
|
||||||
|
|
||||||
|
virtual U32 setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans) { return 0; }
|
||||||
|
virtual void resetAnimation(U32 tag) { }
|
||||||
|
virtual F32 getAnimClipDuration(const char* clip) { return 0.0f; }
|
||||||
|
|
||||||
|
void setTerrainAltitude(F32 alt) { terrain_altitude = alt; }
|
||||||
|
void setInteriorAltitude(F32 alt) { interior_altitude = alt; }
|
||||||
|
void getAltitudes(F32& terr_alt, F32& inter_alt) const { terr_alt = terrain_altitude; inter_alt = interior_altitude; }
|
||||||
|
|
||||||
|
void setGroupIndex(S32 idx) { group_index = idx; }
|
||||||
|
S32 getGroupIndex() const { return group_index; }
|
||||||
|
|
||||||
|
bool inScope() const { return in_scope; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
static afxEffectWrapper* ew_create(afxChoreographer*, afxEffectWrapperData*, afxConstraintMgr*, F32 time_factor, S32 group_index=0);
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxEffectWrapper);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_EFFECT_WRAPPER_H_
|
||||||
1119
Engine/source/afx/afxEffectron.cpp
Normal file
1119
Engine/source/afx/afxEffectron.cpp
Normal file
File diff suppressed because it is too large
Load diff
216
Engine/source/afx/afxEffectron.h
Normal file
216
Engine/source/afx/afxEffectron.h
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_COMPOSITE_EFFECT_H_
|
||||||
|
#define _AFX_COMPOSITE_EFFECT_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "console/typeValidators.h"
|
||||||
|
|
||||||
|
#include "afxChoreographer.h"
|
||||||
|
#include "afxEffectWrapper.h"
|
||||||
|
#include "afxPhrase.h"
|
||||||
|
|
||||||
|
class afxChoreographerData;
|
||||||
|
class afxEffectWrapperData;
|
||||||
|
|
||||||
|
class afxEffectronData : public afxChoreographerData
|
||||||
|
{
|
||||||
|
typedef afxChoreographerData Parent;
|
||||||
|
|
||||||
|
class ewValidator : public TypeValidator
|
||||||
|
{
|
||||||
|
U32 id;
|
||||||
|
public:
|
||||||
|
ewValidator(U32 id) { this->id = id; }
|
||||||
|
void validateType(SimObject *object, void *typePtr);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool do_id_convert;
|
||||||
|
|
||||||
|
public:
|
||||||
|
F32 duration;
|
||||||
|
S32 n_loops;
|
||||||
|
|
||||||
|
afxEffectBaseData* dummy_fx_entry;
|
||||||
|
|
||||||
|
afxEffectList fx_list;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void pack_fx(BitStream* stream, const afxEffectList& fx, bool packed);
|
||||||
|
void unpack_fx(BitStream* stream, afxEffectList& fx);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectronData();
|
||||||
|
/*C*/ afxEffectronData(const afxEffectronData&, bool = false);
|
||||||
|
|
||||||
|
virtual void reloadReset();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
void gatherConstraintDefs(Vector<afxConstraintDef>&);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxEffectronData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxEffectron
|
||||||
|
|
||||||
|
class afxEffectron : public afxChoreographer
|
||||||
|
{
|
||||||
|
typedef afxChoreographer Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum MaskBits
|
||||||
|
{
|
||||||
|
StateEventMask = Parent::NextFreeMask << 0,
|
||||||
|
SyncEventMask = Parent::NextFreeMask << 1,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NULL_EVENT,
|
||||||
|
ACTIVATE_EVENT,
|
||||||
|
SHUTDOWN_EVENT,
|
||||||
|
DEACTIVATE_EVENT,
|
||||||
|
INTERRUPT_EVENT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
INACTIVE_STATE,
|
||||||
|
ACTIVE_STATE,
|
||||||
|
CLEANUP_STATE,
|
||||||
|
DONE_STATE,
|
||||||
|
LATE_STATE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MARK_ACTIVATE = BIT(0),
|
||||||
|
MARK_SHUTDOWN = BIT(1),
|
||||||
|
MARK_DEACTIVATE = BIT(2),
|
||||||
|
MARK_INTERRUPT = BIT(3),
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectDeleteEvent : public SimEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void process(SimObject *obj) { if (obj) obj->deleteObject(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static StringTableEntry CAMERA_CONS;
|
||||||
|
static StringTableEntry LISTENER_CONS;
|
||||||
|
|
||||||
|
private:
|
||||||
|
afxEffectronData* datablock;
|
||||||
|
SimObject* exeblock;
|
||||||
|
|
||||||
|
bool constraints_initialized;
|
||||||
|
bool scoping_initialized;
|
||||||
|
|
||||||
|
U8 effect_state;
|
||||||
|
F32 effect_elapsed;
|
||||||
|
U8 marks_mask;
|
||||||
|
afxConstraintID listener_cons_id;
|
||||||
|
afxConstraintID camera_cons_id;
|
||||||
|
SceneObject* camera_cons_obj;
|
||||||
|
afxPhrase* active_phrase;
|
||||||
|
F32 time_factor;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
bool state_expired();
|
||||||
|
void init_constraints();
|
||||||
|
void init_scoping();
|
||||||
|
void setup_active_fx();
|
||||||
|
bool cleanup_over();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxEffectron();
|
||||||
|
/*C*/ afxEffectron(bool not_default);
|
||||||
|
/*D*/ ~afxEffectron();
|
||||||
|
|
||||||
|
// STANDARD OVERLOADED METHODS //
|
||||||
|
virtual bool onNewDataBlock(GameBaseData* dptr, bool reload);
|
||||||
|
virtual void processTick(const Move*);
|
||||||
|
virtual void advanceTime(F32 dt);
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual U32 packUpdate(NetConnection*, U32, BitStream*);
|
||||||
|
virtual void unpackUpdate(NetConnection*, BitStream*);
|
||||||
|
|
||||||
|
virtual void inflictDamage(const char * label, const char* flavor, SimObjectId target,
|
||||||
|
F32 amt, U8 count, F32 ad_amt, F32 rad, Point3F pos, F32 imp);
|
||||||
|
virtual void sync_with_clients();
|
||||||
|
void finish_startup();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxEffectron);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_server();
|
||||||
|
//
|
||||||
|
void change_state_s(U8 pending_state);
|
||||||
|
//
|
||||||
|
void enter_active_state_s();
|
||||||
|
void leave_active_state_s();
|
||||||
|
void enter_cleanup_state_s();
|
||||||
|
void enter_done_state_s();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_client(F32 dt);
|
||||||
|
//
|
||||||
|
void change_state_c(U8 pending_state);
|
||||||
|
//
|
||||||
|
void enter_active_state_c(F32 starttime);
|
||||||
|
void leave_active_state_c();
|
||||||
|
|
||||||
|
void sync_client(U16 marks, U8 state, F32 elapsed);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void postEvent(U8 event);
|
||||||
|
void setTimeFactor(F32 f) { time_factor = (f > 0) ? f : 1.0f; }
|
||||||
|
F32 getTimeFactor() { return time_factor; }
|
||||||
|
|
||||||
|
bool activationCallInit(bool postponed=false);
|
||||||
|
void activate();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static afxEffectron* start_effect(afxEffectronData*, SimObject* extra);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
#endif // _AFX_EFFECTRON_H_
|
||||||
2116
Engine/source/afx/afxMagicMissile.cpp
Normal file
2116
Engine/source/afx/afxMagicMissile.cpp
Normal file
File diff suppressed because it is too large
Load diff
435
Engine/source/afx/afxMagicMissile.h
Normal file
435
Engine/source/afx/afxMagicMissile.h
Normal file
|
|
@ -0,0 +1,435 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 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.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// afxMagicMissile is a heavily modified variation of the stock Projectile class. In
|
||||||
|
// addition to numerous AFX customizations, it also incorporates functionality based on
|
||||||
|
// the following TGE resources:
|
||||||
|
//
|
||||||
|
// Guided or Seeker Projectiles by Derk Adams
|
||||||
|
// http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=6778
|
||||||
|
//
|
||||||
|
// Projectile Ballistic Coefficients (drag factors) by Mark Owen
|
||||||
|
// http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=5128
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_MAGIC_MISSILE_H_
|
||||||
|
#define _AFX_MAGIC_MISSILE_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "T3D/lightDescription.h"
|
||||||
|
#include "T3D/fx/particleEmitter.h"
|
||||||
|
|
||||||
|
#include "afx/afxConstraint.h"
|
||||||
|
|
||||||
|
class SplashData;
|
||||||
|
class ShapeBase;
|
||||||
|
class TSShapeInstance;
|
||||||
|
class PhysicsWorld;
|
||||||
|
class SFXTrack;
|
||||||
|
class SFXSource;
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxMagicMissileData
|
||||||
|
|
||||||
|
class afxMagicMissileData : public GameBaseData
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onAdd();
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { MaxLifetimeTicks = 4095 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
// variables set in datablock definition:
|
||||||
|
// Shape related
|
||||||
|
StringTableEntry projectileShapeName;
|
||||||
|
|
||||||
|
//bool hasLight;
|
||||||
|
//F32 lightRadius;
|
||||||
|
//LinearColorF lightColor;
|
||||||
|
|
||||||
|
//bool hasWaterLight;
|
||||||
|
//LinearColorF waterLightColor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// Set to true if it is a billboard and want it to always face the viewer, false otherwise
|
||||||
|
bool faceViewer;
|
||||||
|
*/
|
||||||
|
Point3F scale;
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// [0,1] scale of how much velocity should be inherited from the parent object
|
||||||
|
F32 velInheritFactor;
|
||||||
|
/// Speed of the projectile when fired
|
||||||
|
*/
|
||||||
|
F32 muzzleVelocity;
|
||||||
|
|
||||||
|
/// Should it arc?
|
||||||
|
bool isBallistic;
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// How HIGH should it bounce (parallel to normal), [0,1]
|
||||||
|
F32 bounceElasticity;
|
||||||
|
/// How much momentum should be lost when it bounces (perpendicular to normal), [0,1]
|
||||||
|
F32 bounceFriction;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Should this projectile fall/rise different than a default object?
|
||||||
|
F32 gravityMod;
|
||||||
|
|
||||||
|
/// How long the projectile should exist before deleting itself
|
||||||
|
U32 lifetime; // ticks
|
||||||
|
/*
|
||||||
|
/// How long it should not detonate on impact
|
||||||
|
S32 armingDelay; // the values are converted on initialization with
|
||||||
|
*/
|
||||||
|
S32 fadeDelay; // ticks
|
||||||
|
|
||||||
|
/*
|
||||||
|
ExplosionData* explosion; // Explosion Datablock
|
||||||
|
S32 explosionId; // Explosion ID
|
||||||
|
ExplosionData* waterExplosion; // Water Explosion Datablock
|
||||||
|
S32 waterExplosionId; // Water Explosion ID
|
||||||
|
*/
|
||||||
|
|
||||||
|
SplashData* splash; // Water Splash Datablock
|
||||||
|
S32 splashId; // Water splash ID
|
||||||
|
|
||||||
|
SFXTrack* sound; // Projectile Sound
|
||||||
|
|
||||||
|
LightDescription *lightDesc;
|
||||||
|
S32 lightDescId;
|
||||||
|
|
||||||
|
/*
|
||||||
|
enum DecalConstants { // Number of decals constant
|
||||||
|
NumDecals = 6,
|
||||||
|
};
|
||||||
|
DecalData* decals[NumDecals]; // Decal Datablocks
|
||||||
|
S32 decalId[NumDecals]; // Decal IDs
|
||||||
|
U32 decalCount; // # of loaded Decal Datablocks
|
||||||
|
*/
|
||||||
|
|
||||||
|
// variables set on preload:
|
||||||
|
Resource<TSShape> projectileShape;
|
||||||
|
/*
|
||||||
|
S32 activateSeq;
|
||||||
|
S32 maintainSeq;
|
||||||
|
*/
|
||||||
|
|
||||||
|
ParticleEmitterData* particleEmitter;
|
||||||
|
S32 particleEmitterId;
|
||||||
|
ParticleEmitterData* particleWaterEmitter;
|
||||||
|
S32 particleWaterEmitterId;
|
||||||
|
|
||||||
|
U32 collision_mask;
|
||||||
|
|
||||||
|
Point3F starting_vel_vec;
|
||||||
|
|
||||||
|
// guidance behavior
|
||||||
|
bool isGuided;
|
||||||
|
F32 precision;
|
||||||
|
S32 trackDelay;
|
||||||
|
|
||||||
|
// simple physics
|
||||||
|
F32 ballisticCoefficient;
|
||||||
|
|
||||||
|
// terrain following
|
||||||
|
bool followTerrain;
|
||||||
|
F32 followTerrainHeight;
|
||||||
|
F32 followTerrainAdjustRate;
|
||||||
|
S32 followTerrainAdjustDelay;
|
||||||
|
|
||||||
|
F32 acceleration;
|
||||||
|
S32 accelDelay;
|
||||||
|
U32 accelLifetime;
|
||||||
|
|
||||||
|
StringTableEntry launch_node;
|
||||||
|
Point3F launch_offset;
|
||||||
|
Point3F launch_offset_server;
|
||||||
|
Point3F launch_offset_client;
|
||||||
|
Point3F launch_node_offset;
|
||||||
|
F32 launch_pitch;
|
||||||
|
F32 launch_pan;
|
||||||
|
bool echo_launch_offset;
|
||||||
|
|
||||||
|
StringTableEntry launch_cons_s_spec;
|
||||||
|
afxConstraintDef launch_cons_s_def;
|
||||||
|
StringTableEntry launch_cons_c_spec;
|
||||||
|
afxConstraintDef launch_cons_c_def;
|
||||||
|
|
||||||
|
// wiggle behavior
|
||||||
|
Vector<F32> wiggle_magnitudes;
|
||||||
|
Vector<F32> wiggle_speeds;
|
||||||
|
StringTableEntry wiggle_axis_string;
|
||||||
|
Point3F* wiggle_axis;
|
||||||
|
U32 wiggle_num_axis;
|
||||||
|
|
||||||
|
// hover behavior
|
||||||
|
F32 hover_altitude;
|
||||||
|
F32 hover_attack_distance;
|
||||||
|
F32 hover_attack_gradient;
|
||||||
|
U32 hover_time;
|
||||||
|
|
||||||
|
bool reverse_targeting;
|
||||||
|
|
||||||
|
U32 caster_safety_time;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxMagicMissileData();
|
||||||
|
/*D*/ ~afxMagicMissileData();
|
||||||
|
|
||||||
|
void packData(BitStream*);
|
||||||
|
void unpackData(BitStream*);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxMagicMissileData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxMagicMissileData(const afxMagicMissileData&, bool = false);
|
||||||
|
|
||||||
|
afxMagicMissileData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0);
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
void gather_cons_defs(Vector<afxConstraintDef>& defs);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxMagicMissile
|
||||||
|
|
||||||
|
//class afxMagicSpell;
|
||||||
|
class afxChoreographer;
|
||||||
|
|
||||||
|
class afxMagicMissile : public GameBase, public ISceneLight
|
||||||
|
{
|
||||||
|
typedef GameBase Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
// Initial conditions
|
||||||
|
enum ProjectileConstants {
|
||||||
|
SourceIdTimeoutTicks = 7, // = 231 ms
|
||||||
|
DeleteWaitTime = 500, ///< 500 ms delete timeout (for network transmission delays)
|
||||||
|
ExcessVelDirBits = 7,
|
||||||
|
MaxLivingTicks = 4095,
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
enum UpdateMasks {
|
||||||
|
/*
|
||||||
|
BounceMask = Parent::NextFreeMask,
|
||||||
|
ExplosionMask = Parent::NextFreeMask << 1,
|
||||||
|
*/
|
||||||
|
GuideMask = Parent::NextFreeMask << 0,
|
||||||
|
LaunchMask = Parent::NextFreeMask << 1,
|
||||||
|
ImpactMask = Parent::NextFreeMask << 2,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 3
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
PhysicsWorld *mPhysicsWorld;
|
||||||
|
|
||||||
|
afxMagicMissileData* mDataBlock;
|
||||||
|
|
||||||
|
ParticleEmitter* mParticleEmitter;
|
||||||
|
ParticleEmitter* mParticleWaterEmitter;
|
||||||
|
SFXSource* mSound;
|
||||||
|
|
||||||
|
Point3F mCurrPosition;
|
||||||
|
Point3F mCurrVelocity;
|
||||||
|
/*
|
||||||
|
S32 mSourceObjectId;
|
||||||
|
S32 mSourceObjectSlot;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Time related variables common to all projectiles, managed by processTick
|
||||||
|
|
||||||
|
U32 mCurrTick; ///< Current time in ticks
|
||||||
|
/*
|
||||||
|
SimObjectPtr<ShapeBase> mSourceObject; ///< Actual pointer to the source object, times out after SourceIdTimeoutTicks
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Rendering related variables
|
||||||
|
TSShapeInstance* mProjectileShape;
|
||||||
|
/*
|
||||||
|
TSThread* mActivateThread;
|
||||||
|
TSThread* mMaintainThread;
|
||||||
|
|
||||||
|
Point3F mLastRenderPos;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ISceneLight
|
||||||
|
virtual void submitLights( LightManager *lm, bool staticLighting );
|
||||||
|
virtual LightInfo* getLight() { return mLight; }
|
||||||
|
|
||||||
|
LightInfo *mLight;
|
||||||
|
LightState mLightState;
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool mHidden; ///< set by the derived class, if true, projectile doesn't render
|
||||||
|
F32 mFadeValue; ///< set in processTick, interpolation between fadeDelay and lifetime
|
||||||
|
///< in data block
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Warping and back delta variables. Only valid on the client
|
||||||
|
//
|
||||||
|
Point3F mWarpStart;
|
||||||
|
Point3F mWarpEnd;
|
||||||
|
U32 mWarpTicksRemaining;
|
||||||
|
*/
|
||||||
|
|
||||||
|
Point3F mCurrDeltaBase;
|
||||||
|
Point3F mCurrBackDelta;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Point3F mExplosionPosition;
|
||||||
|
Point3F mExplosionNormal;
|
||||||
|
U32 mCollideHitType;
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool onAdd();
|
||||||
|
void onRemove();
|
||||||
|
bool onNewDataBlock(GameBaseData *dptr, bool reload);
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
virtual void prepRenderImage(SceneRenderState*);
|
||||||
|
void prepBatchRender( SceneRenderState *state);
|
||||||
|
|
||||||
|
void processTick(const Move *move);
|
||||||
|
/*
|
||||||
|
void advanceTime(F32 dt);
|
||||||
|
*/
|
||||||
|
void interpolateTick(F32 delta);
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// What to do once this projectile collides with something
|
||||||
|
virtual void onCollision(const Point3F& p, const Point3F& n, SceneObject*);
|
||||||
|
|
||||||
|
/// What to do when this projectile explodes
|
||||||
|
virtual void explode(const Point3F& p, const Point3F& n, const U32 collideType );
|
||||||
|
|
||||||
|
/// Returns the velocity of the projectile
|
||||||
|
Point3F getVelocity() const;
|
||||||
|
*/
|
||||||
|
|
||||||
|
void emitParticles(const Point3F&, const Point3F&, const Point3F&, const U32);
|
||||||
|
void updateSound();
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
/*
|
||||||
|
void prepModelView ( SceneRenderState *state);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// These are stolen from the player class ..
|
||||||
|
bool pointInWater(const Point3F &point);
|
||||||
|
|
||||||
|
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||||
|
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||||
|
|
||||||
|
afxChoreographer* choreographer;
|
||||||
|
|
||||||
|
bool client_only;
|
||||||
|
bool server_only;
|
||||||
|
bool use_accel;
|
||||||
|
U32 collision_mask;
|
||||||
|
F32 prec_inc;
|
||||||
|
|
||||||
|
bool did_launch;
|
||||||
|
bool did_impact;
|
||||||
|
|
||||||
|
SceneObject* missile_target;
|
||||||
|
SceneObject* collide_exempt;
|
||||||
|
|
||||||
|
bool hover_attack_go;
|
||||||
|
U32 hover_attack_tick;
|
||||||
|
|
||||||
|
F32 starting_velocity;
|
||||||
|
Point3F starting_vel_vec;
|
||||||
|
|
||||||
|
SimObject* ss_object;
|
||||||
|
S32 ss_index;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init(bool on_server, bool on_client);
|
||||||
|
void create_splash(const Point3F& pos);
|
||||||
|
SceneObject* get_default_launcher() const;
|
||||||
|
void get_launch_constraint_data(Point3F& pos, Point3F& vel);
|
||||||
|
void get_launch_data(Point3F& pos, Point3F& vel);
|
||||||
|
bool is_active() const { return (did_launch && !did_impact); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
F32 getUpdatePriority(CameraScopeQuery *focusObject, U32 updateMask, S32 updateSkips);
|
||||||
|
*/
|
||||||
|
/*C*/ afxMagicMissile();
|
||||||
|
/*C*/ afxMagicMissile(bool on_server, bool on_client);
|
||||||
|
/*D*/ ~afxMagicMissile();
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxMagicMissile);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
/*
|
||||||
|
virtual bool calculateImpact(float simTime,
|
||||||
|
Point3F& pointOfImpact,
|
||||||
|
float& impactTime);
|
||||||
|
|
||||||
|
static U32 smProjectileWarpTicks;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static const U32 csmStaticCollisionMask;
|
||||||
|
static const U32 csmDynamicCollisionMask;
|
||||||
|
static const U32 csmDamageableMask;
|
||||||
|
*/
|
||||||
|
|
||||||
|
void launch();
|
||||||
|
void setChoreographer(afxChoreographer*);
|
||||||
|
void setStartingVelocityVector(const Point3F& vel_vec);
|
||||||
|
void setStartingVelocity(const F32 vel);
|
||||||
|
void getStartingVelocityValues(F32& vel, Point3F& vel_vec);
|
||||||
|
void setSubstitutionData(SimObject* obj, S32 idx=0) { ss_object = obj; ss_index = idx; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxMagicMissileCallback
|
||||||
|
|
||||||
|
class afxMagicMissileCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void impactNotify(const Point3F& p, const Point3F& n, SceneObject*)=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_MAGIC_MISSILE_H_
|
||||||
|
|
||||||
2709
Engine/source/afx/afxMagicSpell.cpp
Normal file
2709
Engine/source/afx/afxMagicSpell.cpp
Normal file
File diff suppressed because it is too large
Load diff
390
Engine/source/afx/afxMagicSpell.h
Normal file
390
Engine/source/afx/afxMagicSpell.h
Normal file
|
|
@ -0,0 +1,390 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_MAGIC_SPELL_H_
|
||||||
|
#define _AFX_MAGIC_SPELL_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "core/util/tVector.h"
|
||||||
|
#include "console/typeValidators.h"
|
||||||
|
|
||||||
|
#include "afxChoreographer.h"
|
||||||
|
#include "afxEffectDefs.h"
|
||||||
|
#include "afxEffectWrapper.h"
|
||||||
|
#include "afxMagicMissile.h"
|
||||||
|
|
||||||
|
class afxChoreographerData;
|
||||||
|
class afxMagicMissileData;
|
||||||
|
class afxEffectWrapperData;
|
||||||
|
class SceneObject;
|
||||||
|
class afxMagicSpell;
|
||||||
|
|
||||||
|
class afxMagicSpellDefs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CASTING_PHRASE,
|
||||||
|
LAUNCH_PHRASE,
|
||||||
|
DELIVERY_PHRASE,
|
||||||
|
IMPACT_PHRASE,
|
||||||
|
LINGER_PHRASE,
|
||||||
|
NUM_PHRASES
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class afxMagicSpellData : public afxChoreographerData, public afxMagicSpellDefs
|
||||||
|
{
|
||||||
|
typedef afxChoreographerData Parent;
|
||||||
|
|
||||||
|
class ewValidator : public TypeValidator
|
||||||
|
{
|
||||||
|
U32 id;
|
||||||
|
public:
|
||||||
|
ewValidator(U32 id) { this->id = id; }
|
||||||
|
void validateType(SimObject *object, void *typePtr);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool do_id_convert;
|
||||||
|
|
||||||
|
public:
|
||||||
|
F32 casting_dur;
|
||||||
|
F32 delivery_dur;
|
||||||
|
F32 linger_dur;
|
||||||
|
//
|
||||||
|
S32 n_casting_loops;
|
||||||
|
S32 n_delivery_loops;
|
||||||
|
S32 n_linger_loops;
|
||||||
|
//
|
||||||
|
F32 extra_casting_time;
|
||||||
|
F32 extra_delivery_time;
|
||||||
|
F32 extra_linger_time;
|
||||||
|
//
|
||||||
|
bool do_move_interrupts;
|
||||||
|
F32 move_interrupt_speed;
|
||||||
|
//
|
||||||
|
afxMagicMissileData* missile_db;
|
||||||
|
bool launch_on_server_signal;
|
||||||
|
U32 primary_target_types;
|
||||||
|
//
|
||||||
|
afxEffectWrapperData* dummy_fx_entry;
|
||||||
|
|
||||||
|
// various effects lists
|
||||||
|
afxEffectList casting_fx_list;
|
||||||
|
afxEffectList launch_fx_list;
|
||||||
|
afxEffectList delivery_fx_list;
|
||||||
|
afxEffectList impact_fx_list;
|
||||||
|
afxEffectList linger_fx_list;
|
||||||
|
|
||||||
|
void pack_fx(BitStream* stream, const afxEffectList& fx, bool packed);
|
||||||
|
void unpack_fx(BitStream* stream, afxEffectList& fx);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxMagicSpellData();
|
||||||
|
/*C*/ afxMagicSpellData(const afxMagicSpellData&, bool = false);
|
||||||
|
|
||||||
|
virtual void reloadReset();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
virtual bool writeField(StringTableEntry fieldname, const char* value);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
void gatherConstraintDefs(Vector<afxConstraintDef>&);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxMagicSpellData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
|
||||||
|
/// @name Callbacks
|
||||||
|
/// @{
|
||||||
|
DECLARE_CALLBACK( void, onDamage, (afxMagicSpell* spell, const char* label, const char* flaver, U32 target_id, F32 amount, U8 n, Point3F pos, F32 ad_amount, F32 radius, F32 impulse) );
|
||||||
|
DECLARE_CALLBACK( void, onDeactivate, (afxMagicSpell* spell) );
|
||||||
|
DECLARE_CALLBACK( void, onInterrupt, (afxMagicSpell* spell, ShapeBase* caster) );
|
||||||
|
DECLARE_CALLBACK( void, onLaunch, (afxMagicSpell* spell, ShapeBase* caster, SceneObject* target, afxMagicMissile* missile) );
|
||||||
|
DECLARE_CALLBACK( void, onImpact, (afxMagicSpell* spell, ShapeBase* caster, SceneObject* impacted, Point3F pos, Point3F normal) );
|
||||||
|
DECLARE_CALLBACK( bool, onPreactivate, (SimObject* param_holder, ShapeBase* caster, SceneObject* target, SimObject* extra) );
|
||||||
|
DECLARE_CALLBACK( void, onActivate, (afxMagicSpell* spell, ShapeBase* caster, SceneObject* target) );
|
||||||
|
/// @}
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxMagicSpell
|
||||||
|
|
||||||
|
class ShapeBase;
|
||||||
|
class GameConnection;
|
||||||
|
class afxEffectVector;
|
||||||
|
class afxConstraint;
|
||||||
|
class afxConstraintMgr;
|
||||||
|
class afxMagicMissile;
|
||||||
|
class afxChoreographer;
|
||||||
|
class afxPhrase;
|
||||||
|
|
||||||
|
class afxMagicSpell : public afxChoreographer, public afxMagicSpellDefs
|
||||||
|
{
|
||||||
|
typedef afxChoreographer Parent;
|
||||||
|
friend class afxMagicMissile;
|
||||||
|
|
||||||
|
enum MaskBits
|
||||||
|
{
|
||||||
|
MagicMissileMask = Parent::NextFreeMask << 0,
|
||||||
|
StateEventMask = Parent::NextFreeMask << 1,
|
||||||
|
LaunchEventMask = Parent::NextFreeMask << 2,
|
||||||
|
ImpactEventMask = Parent::NextFreeMask << 3,
|
||||||
|
SyncEventMask = Parent::NextFreeMask << 4,
|
||||||
|
RemapConstraintMask = Parent::NextFreeMask << 5, // CONSTRAINT REMAPPING
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 6
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NULL_EVENT,
|
||||||
|
ACTIVATE_EVENT,
|
||||||
|
LAUNCH_EVENT,
|
||||||
|
IMPACT_EVENT,
|
||||||
|
SHUTDOWN_EVENT,
|
||||||
|
DEACTIVATE_EVENT,
|
||||||
|
INTERRUPT_PHASE_EVENT,
|
||||||
|
INTERRUPT_SPELL_EVENT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
INACTIVE_STATE,
|
||||||
|
CASTING_STATE,
|
||||||
|
DELIVERY_STATE,
|
||||||
|
LINGER_STATE,
|
||||||
|
CLEANUP_STATE,
|
||||||
|
DONE_STATE,
|
||||||
|
LATE_STATE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MARK_ACTIVATE = BIT(0),
|
||||||
|
MARK_LAUNCH = BIT(1),
|
||||||
|
MARK_IMPACT = BIT(2),
|
||||||
|
MARK_SHUTDOWN = BIT(3),
|
||||||
|
MARK_DEACTIVATE = BIT(4),
|
||||||
|
MARK_END_CASTING = BIT(5),
|
||||||
|
MARK_END_DELIVERY = BIT(6),
|
||||||
|
MARK_END_LINGER = BIT(7),
|
||||||
|
MARK_INTERRUPT_CASTING = BIT(8),
|
||||||
|
MARK_INTERRUPT_DELIVERY = BIT(9),
|
||||||
|
MARK_INTERRUPT_LINGER = BIT(10),
|
||||||
|
MARK_INTERRUPT_CLEANUP = BIT(11),
|
||||||
|
//
|
||||||
|
MARK_ENDINGS = MARK_END_CASTING | MARK_END_DELIVERY | MARK_END_LINGER,
|
||||||
|
MARK_INTERRUPTS = MARK_INTERRUPT_CASTING | MARK_INTERRUPT_DELIVERY | MARK_INTERRUPT_LINGER | MARK_INTERRUPT_CLEANUP
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectDeleteEvent : public SimEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void process(SimObject *obj) { if (obj) obj->deleteObject(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static StringTableEntry CASTER_CONS;
|
||||||
|
static StringTableEntry TARGET_CONS;
|
||||||
|
static StringTableEntry MISSILE_CONS;
|
||||||
|
static StringTableEntry CAMERA_CONS;
|
||||||
|
static StringTableEntry LISTENER_CONS;
|
||||||
|
static StringTableEntry IMPACT_POINT_CONS;
|
||||||
|
static StringTableEntry IMPACTED_OBJECT_CONS;
|
||||||
|
|
||||||
|
private:
|
||||||
|
afxMagicSpellData* datablock;
|
||||||
|
SimObject* exeblock;
|
||||||
|
afxMagicMissileData* missile_db;
|
||||||
|
|
||||||
|
ShapeBase* caster;
|
||||||
|
SceneObject* target;
|
||||||
|
SimObject* caster_field;
|
||||||
|
SimObject* target_field;
|
||||||
|
|
||||||
|
U16 caster_scope_id;
|
||||||
|
U16 target_scope_id;
|
||||||
|
bool target_is_shape;
|
||||||
|
|
||||||
|
bool constraints_initialized;
|
||||||
|
bool scoping_initialized;
|
||||||
|
|
||||||
|
U8 spell_state;
|
||||||
|
F32 spell_elapsed;
|
||||||
|
|
||||||
|
afxConstraintID listener_cons_id;
|
||||||
|
afxConstraintID caster_cons_id;
|
||||||
|
afxConstraintID target_cons_id;
|
||||||
|
afxConstraintID impacted_cons_id;
|
||||||
|
afxConstraintID camera_cons_id;
|
||||||
|
SceneObject* camera_cons_obj;
|
||||||
|
|
||||||
|
afxPhrase* phrases[NUM_PHRASES];
|
||||||
|
F32 tfactors[NUM_PHRASES];
|
||||||
|
|
||||||
|
bool notify_castbar;
|
||||||
|
F32 overall_time_factor;
|
||||||
|
|
||||||
|
U16 marks_mask;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
bool state_expired();
|
||||||
|
F32 state_elapsed();
|
||||||
|
void init_constraints();
|
||||||
|
void init_scoping();
|
||||||
|
void setup_casting_fx();
|
||||||
|
void setup_launch_fx();
|
||||||
|
void setup_delivery_fx();
|
||||||
|
void setup_impact_fx();
|
||||||
|
void setup_linger_fx();
|
||||||
|
bool cleanup_over();
|
||||||
|
bool is_caster_moving();
|
||||||
|
bool is_caster_client(ShapeBase* caster, GameConnection* conn);
|
||||||
|
bool is_impact_in_water(SceneObject* obj, const Point3F& p);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool remap_builtin_constraint(SceneObject*, const char* cons_name); // CONSTRAINT REMAPPING
|
||||||
|
virtual void pack_constraint_info(NetConnection* conn, BitStream* stream);
|
||||||
|
virtual void unpack_constraint_info(NetConnection* conn, BitStream* stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
afxMagicMissile* missile;
|
||||||
|
bool missile_is_armed;
|
||||||
|
SceneObject* impacted_obj;
|
||||||
|
Point3F impact_pos;
|
||||||
|
Point3F impact_norm;
|
||||||
|
U16 impacted_scope_id;
|
||||||
|
bool impacted_is_shape;
|
||||||
|
|
||||||
|
void init_missile_s(afxMagicMissileData* mm);
|
||||||
|
void launch_missile_s();
|
||||||
|
|
||||||
|
void init_missile_c(afxMagicMissileData* mm);
|
||||||
|
void launch_missile_c();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void impactNotify(const Point3F& p, const Point3F& n, SceneObject*);
|
||||||
|
virtual void executeScriptEvent(const char* method, afxConstraint*,
|
||||||
|
const MatrixF& pos, const char* data);
|
||||||
|
virtual void inflictDamage(const char * label, const char* flavor, SimObjectId target,
|
||||||
|
F32 amt, U8 count, F32 ad_amt, F32 rad, Point3F pos, F32 imp);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxMagicSpell();
|
||||||
|
/*C*/ afxMagicSpell(ShapeBase* caster, SceneObject* target);
|
||||||
|
/*D*/ ~afxMagicSpell();
|
||||||
|
|
||||||
|
// STANDARD OVERLOADED METHODS //
|
||||||
|
virtual bool onNewDataBlock(GameBaseData* dptr, bool reload);
|
||||||
|
virtual void processTick(const Move*);
|
||||||
|
virtual void advanceTime(F32 dt);
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
virtual void onDeleteNotify(SimObject*);
|
||||||
|
virtual U32 packUpdate(NetConnection*, U32, BitStream*);
|
||||||
|
virtual void unpackUpdate(NetConnection*, BitStream*);
|
||||||
|
|
||||||
|
virtual void sync_with_clients();
|
||||||
|
void finish_startup();
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxMagicSpell);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_server();
|
||||||
|
//
|
||||||
|
void change_state_s(U8 pending_state);
|
||||||
|
//
|
||||||
|
void enter_casting_state_s();
|
||||||
|
void leave_casting_state_s();
|
||||||
|
void enter_delivery_state_s();
|
||||||
|
void leave_delivery_state_s();
|
||||||
|
void enter_linger_state_s();
|
||||||
|
void leave_linger_state_s();
|
||||||
|
void enter_done_state_s();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_client(F32 dt);
|
||||||
|
//
|
||||||
|
void change_state_c(U8 pending_state);
|
||||||
|
//
|
||||||
|
void enter_casting_state_c(F32 starttime);
|
||||||
|
void leave_casting_state_c();
|
||||||
|
void enter_delivery_state_c(F32 starttime);
|
||||||
|
void leave_delivery_state_c();
|
||||||
|
void enter_linger_state_c(F32 starttime);
|
||||||
|
void leave_linger_state_c();
|
||||||
|
//
|
||||||
|
void sync_client(U16 marks, U8 state, F32 state_elapsed, F32 spell_elapsed);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void postSpellEvent(U8 event);
|
||||||
|
void resolveTimeFactors();
|
||||||
|
|
||||||
|
void setTimeFactor(F32 f) { overall_time_factor = (f > 0) ? f : 1.0f; }
|
||||||
|
F32 getTimeFactor() { return overall_time_factor; }
|
||||||
|
void setTimeFactor(U8 phase, F32 f) { tfactors[phase] = (f > 0) ? f : 1.0f; }
|
||||||
|
F32 getTimeFactor(U8 phase) { return tfactors[phase]; }
|
||||||
|
|
||||||
|
ShapeBase* getCaster() const { return caster; }
|
||||||
|
SceneObject* getTarget() const { return target; }
|
||||||
|
afxMagicMissile* getMissile() const { return missile; }
|
||||||
|
SceneObject* getImpactedObject() const { return impacted_obj; }
|
||||||
|
|
||||||
|
virtual void restoreObject(SceneObject*);
|
||||||
|
|
||||||
|
bool activationCallInit(bool postponed=false);
|
||||||
|
void activate();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static afxMagicSpell* cast_spell(afxMagicSpellData*, ShapeBase* caster, SceneObject* target, SimObject* extra);
|
||||||
|
|
||||||
|
static void displayScreenMessage(ShapeBase* caster, const char* msg);
|
||||||
|
static Point3F getShapeImpactPos(SceneObject*);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool afxMagicSpell::is_caster_moving()
|
||||||
|
{
|
||||||
|
return (caster) ? (caster->getVelocity().len() > datablock->move_interrupt_speed) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool afxMagicSpell::is_caster_client(ShapeBase* caster, GameConnection* conn)
|
||||||
|
{
|
||||||
|
return (caster) ? (caster->getControllingClient() == conn) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_MAGIC_SPELL_H_
|
||||||
196
Engine/source/afx/afxPhrase.cpp
Normal file
196
Engine/source/afx/afxPhrase.cpp
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "afx/afxEffectVector.h"
|
||||||
|
#include "afx/afxPhrase.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxPhrase
|
||||||
|
|
||||||
|
void
|
||||||
|
afxPhrase::init_fx(S32 group_index)
|
||||||
|
{
|
||||||
|
fx->ev_init(init_chor, *init_fx_list, on_server, will_stop, init_time_factor, init_dur, group_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
afxPhrase::afxPhrase(bool on_server, bool will_stop)
|
||||||
|
{
|
||||||
|
this->on_server = on_server;
|
||||||
|
this->will_stop = will_stop;
|
||||||
|
|
||||||
|
init_fx_list = NULL;
|
||||||
|
init_dur = 0.0f;
|
||||||
|
init_chor = NULL;
|
||||||
|
init_time_factor = 1.0f;
|
||||||
|
|
||||||
|
fx = new afxEffectVector;
|
||||||
|
fx2 = NULL;
|
||||||
|
starttime = 0;
|
||||||
|
dur = 0;
|
||||||
|
|
||||||
|
n_loops = 1;
|
||||||
|
loop_cnt = 1;
|
||||||
|
|
||||||
|
extra_time = 0.0f;
|
||||||
|
extra_stoptime = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxPhrase::~afxPhrase()
|
||||||
|
{
|
||||||
|
delete fx;
|
||||||
|
delete fx2;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
afxPhrase::init(afxEffectList& fx_list, F32 dur, afxChoreographer* chor, F32 time_factor,
|
||||||
|
S32 n_loops, S32 group_index, F32 extra_time)
|
||||||
|
{
|
||||||
|
init_fx_list = &fx_list;
|
||||||
|
init_dur = dur;
|
||||||
|
init_chor = chor;
|
||||||
|
init_time_factor = time_factor;
|
||||||
|
|
||||||
|
this->n_loops = n_loops;
|
||||||
|
this->extra_time = extra_time;
|
||||||
|
this->dur = (init_dur < 0) ? init_dur : init_dur*init_time_factor;
|
||||||
|
|
||||||
|
init_fx(group_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
afxPhrase::start(F32 startstamp, F32 timestamp)
|
||||||
|
{
|
||||||
|
starttime = startstamp;
|
||||||
|
|
||||||
|
F32 loopstart = timestamp - startstamp;
|
||||||
|
|
||||||
|
if (dur > 0 && loopstart > dur)
|
||||||
|
{
|
||||||
|
loop_cnt += (S32) (loopstart/dur);
|
||||||
|
loopstart = mFmod(loopstart, dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fx->empty())
|
||||||
|
fx->start(loopstart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
afxPhrase::update(F32 dt, F32 timestamp)
|
||||||
|
{
|
||||||
|
if (fx->isActive())
|
||||||
|
fx->update(dt);
|
||||||
|
|
||||||
|
if (fx2 && fx2->isActive())
|
||||||
|
fx2->update(dt);
|
||||||
|
|
||||||
|
if (extra_stoptime > 0 && timestamp > extra_stoptime)
|
||||||
|
{
|
||||||
|
stop(timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
afxPhrase::stop(F32 timestamp)
|
||||||
|
{
|
||||||
|
if (extra_time > 0 && !(extra_stoptime > 0))
|
||||||
|
{
|
||||||
|
extra_stoptime = timestamp + extra_time;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fx->isActive())
|
||||||
|
fx->stop();
|
||||||
|
|
||||||
|
if (fx2 && fx2->isActive())
|
||||||
|
fx2->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
afxPhrase::expired(F32 timestamp)
|
||||||
|
{
|
||||||
|
if (dur < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ((timestamp - starttime) > loop_cnt*dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
F32
|
||||||
|
afxPhrase::elapsed(F32 timestamp)
|
||||||
|
{
|
||||||
|
return (timestamp - starttime);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
afxPhrase::recycle(F32 timestamp)
|
||||||
|
{
|
||||||
|
if (n_loops < 0 || loop_cnt < n_loops)
|
||||||
|
{
|
||||||
|
if (fx2)
|
||||||
|
delete fx2;
|
||||||
|
|
||||||
|
fx2 = fx;
|
||||||
|
|
||||||
|
fx = new afxEffectVector;
|
||||||
|
init_fx();
|
||||||
|
|
||||||
|
if (fx2 && !fx2->empty())
|
||||||
|
fx2->stop();
|
||||||
|
|
||||||
|
if (!fx->empty())
|
||||||
|
fx->start(0.0F);
|
||||||
|
|
||||||
|
loop_cnt++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
afxPhrase::interrupt(F32 timestamp)
|
||||||
|
{
|
||||||
|
if (fx->isActive())
|
||||||
|
fx->interrupt();
|
||||||
|
|
||||||
|
if (fx2 && fx2->isActive())
|
||||||
|
fx2->interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 afxPhrase::calcDoneTime()
|
||||||
|
{
|
||||||
|
return starttime + fx->getTotalDur();
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 afxPhrase::calcAfterLife()
|
||||||
|
{
|
||||||
|
return fx->getAfterLife();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
87
Engine/source/afx/afxPhrase.h
Normal file
87
Engine/source/afx/afxPhrase.h
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_PHRASE_H_
|
||||||
|
#define _AFX_PHRASE_H_
|
||||||
|
|
||||||
|
#include "afxEffectVector.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxPhrase
|
||||||
|
|
||||||
|
class afxChoreographer;
|
||||||
|
class afxConstraintMgr;
|
||||||
|
class afxEffectVector;
|
||||||
|
|
||||||
|
class afxPhrase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
afxEffectList* init_fx_list;
|
||||||
|
F32 init_dur;
|
||||||
|
afxChoreographer* init_chor;
|
||||||
|
F32 init_time_factor;
|
||||||
|
F32 extra_time;
|
||||||
|
|
||||||
|
afxEffectVector* fx;
|
||||||
|
afxEffectVector* fx2;
|
||||||
|
|
||||||
|
bool on_server;
|
||||||
|
bool will_stop;
|
||||||
|
|
||||||
|
F32 starttime;
|
||||||
|
F32 dur;
|
||||||
|
S32 n_loops;
|
||||||
|
S32 loop_cnt;
|
||||||
|
F32 extra_stoptime;
|
||||||
|
|
||||||
|
void init_fx(S32 group_index=0);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxPhrase(bool on_server, bool will_stop);
|
||||||
|
virtual ~afxPhrase();
|
||||||
|
|
||||||
|
virtual void init(afxEffectList&, F32 dur, afxChoreographer*, F32 time_factor,
|
||||||
|
S32 n_loops, S32 group_index=0, F32 extra_time=0.0f);
|
||||||
|
|
||||||
|
virtual void start(F32 startstamp, F32 timestamp);
|
||||||
|
virtual void update(F32 dt, F32 timestamp);
|
||||||
|
virtual void stop(F32 timestamp);
|
||||||
|
virtual void interrupt(F32 timestamp);
|
||||||
|
virtual bool expired(F32 timestamp);
|
||||||
|
virtual bool recycle(F32 timestamp);
|
||||||
|
virtual F32 elapsed(F32 timestamp);
|
||||||
|
|
||||||
|
bool isEmpty() { return fx->empty(); }
|
||||||
|
bool isInfinite() { return (init_dur < 0); }
|
||||||
|
F32 calcDoneTime();
|
||||||
|
F32 calcAfterLife();
|
||||||
|
bool willStop() { return will_stop; }
|
||||||
|
bool onServer() { return on_server; }
|
||||||
|
S32 count() { return fx->count(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_PHRASE_H_
|
||||||
176
Engine/source/afx/afxRenderHighlightMgr.cpp
Normal file
176
Engine/source/afx/afxRenderHighlightMgr.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// The afxRenderHighlightMgr class is adapted from the resource,
|
||||||
|
// "Silhoute selection via postFX for Torque3D" posted by Konrad Kiss.
|
||||||
|
// http://www.garagegames.com/community/resources/view/17821
|
||||||
|
// Supporting code mods in other areas of the engine are marked as
|
||||||
|
// "(selection-highlight)".
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#include "afxRenderHighlightMgr.h"
|
||||||
|
|
||||||
|
#include "scene/sceneManager.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "materials/sceneData.h"
|
||||||
|
#include "materials/matInstance.h"
|
||||||
|
//#include "materials/materialFeatureTypes.h"
|
||||||
|
#include "materials/processedMaterial.h"
|
||||||
|
#include "postFx/postEffect.h"
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "gfx/gfxDebugEvent.h"
|
||||||
|
#include "math/util/matrixSet.h"
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT( afxRenderHighlightMgr );
|
||||||
|
|
||||||
|
afxRenderHighlightMgr::afxRenderHighlightMgr()
|
||||||
|
: RenderTexTargetBinManager( RenderPassManager::RIT_Mesh,
|
||||||
|
1.0f,
|
||||||
|
1.0f,
|
||||||
|
GFXFormatR8G8B8A8,
|
||||||
|
Point2I( 512, 512 ) )
|
||||||
|
{
|
||||||
|
mNamedTarget.registerWithName( "highlight" );
|
||||||
|
mTargetSizeType = WindowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxRenderHighlightMgr::~afxRenderHighlightMgr()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PostEffect* afxRenderHighlightMgr::getSelectionEffect()
|
||||||
|
{
|
||||||
|
if ( !mSelectionEffect )
|
||||||
|
mSelectionEffect = dynamic_cast<PostEffect*>( Sim::findObject( "afxHighlightPostFX" ) );
|
||||||
|
|
||||||
|
return mSelectionEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxRenderHighlightMgr::isSelectionEnabled()
|
||||||
|
{
|
||||||
|
return getSelectionEffect() && getSelectionEffect()->isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxRenderHighlightMgr::addElement( RenderInst *inst )
|
||||||
|
{
|
||||||
|
// Skip out if we don't have the selection post
|
||||||
|
// effect enabled at this time.
|
||||||
|
if ( !isSelectionEnabled() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Skip it if we don't have a selection material.
|
||||||
|
BaseMatInstance *matInst = getMaterial( inst );
|
||||||
|
if ( !matInst || !matInst->needsSelectionHighlighting() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
internalAddElement(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxRenderHighlightMgr::render( SceneRenderState *state )
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE( RenderSelectionMgr_Render );
|
||||||
|
|
||||||
|
if ( !isSelectionEnabled() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const U32 binSize = mElementList.size();
|
||||||
|
|
||||||
|
// If this is a non-diffuse pass or we have no objects to
|
||||||
|
// render then tell the effect to skip rendering.
|
||||||
|
if ( !state->isDiffusePass() || binSize == 0 )
|
||||||
|
{
|
||||||
|
getSelectionEffect()->setSkip( true );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GFXDEBUGEVENT_SCOPE( RenderSelectionMgr_Render, ColorI::GREEN );
|
||||||
|
|
||||||
|
GFXTransformSaver saver;
|
||||||
|
|
||||||
|
// Tell the superclass we're about to render, preserve contents
|
||||||
|
const bool isRenderingToTarget = _onPreRender( state, true );
|
||||||
|
|
||||||
|
// Clear all the buffers to black.
|
||||||
|
//GFX->clear( GFXClearTarget, ColorI::BLACK, 1.0f, 0);
|
||||||
|
GFX->clear( GFXClearTarget, ColorI::ZERO, 1.0f, 0);
|
||||||
|
|
||||||
|
// Restore transforms
|
||||||
|
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
|
||||||
|
matrixSet.restoreSceneViewProjection();
|
||||||
|
|
||||||
|
// init loop data
|
||||||
|
SceneData sgData;
|
||||||
|
sgData.init( state, SceneData::HighlightBin );
|
||||||
|
|
||||||
|
for( U32 j=0; j<binSize; )
|
||||||
|
{
|
||||||
|
MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[j].inst);
|
||||||
|
|
||||||
|
setupSGData( ri, sgData );
|
||||||
|
|
||||||
|
BaseMatInstance *mat = ri->matInst;
|
||||||
|
|
||||||
|
U32 matListEnd = j;
|
||||||
|
|
||||||
|
while( mat && mat->setupPass( state, sgData ) )
|
||||||
|
{
|
||||||
|
U32 a;
|
||||||
|
for( a=j; a<binSize; a++ )
|
||||||
|
{
|
||||||
|
MeshRenderInst *passRI = static_cast<MeshRenderInst*>(mElementList[a].inst);
|
||||||
|
|
||||||
|
if ( newPassNeeded( ri, passRI ) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
matrixSet.setWorld(*passRI->objectToWorld);
|
||||||
|
matrixSet.setView(*passRI->worldToCamera);
|
||||||
|
matrixSet.setProjection(*passRI->projection);
|
||||||
|
mat->setTransforms(matrixSet, state);
|
||||||
|
|
||||||
|
mat->setSceneInfo(state, sgData);
|
||||||
|
mat->setBuffers(passRI->vertBuff, passRI->primBuff);
|
||||||
|
|
||||||
|
if ( passRI->prim )
|
||||||
|
GFX->drawPrimitive( *passRI->prim );
|
||||||
|
else
|
||||||
|
GFX->drawPrimitive( passRI->primBuffIndex );
|
||||||
|
}
|
||||||
|
matListEnd = a;
|
||||||
|
setupSGData( ri, sgData );
|
||||||
|
}
|
||||||
|
|
||||||
|
// force increment if none happened, otherwise go to end of batch
|
||||||
|
j = ( j == matListEnd ) ? j+1 : matListEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish up.
|
||||||
|
if ( isRenderingToTarget )
|
||||||
|
_onPostRender();
|
||||||
|
|
||||||
|
// Make sure the effect is gonna render.
|
||||||
|
getSelectionEffect()->setSkip( false );
|
||||||
|
}
|
||||||
76
Engine/source/afx/afxRenderHighlightMgr.h
Normal file
76
Engine/source/afx/afxRenderHighlightMgr.h
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// The afxRenderHighlightMgr class is adapted from the resource,
|
||||||
|
// "Silhoute selection via postFX for Torque3D" posted by Konrad Kiss.
|
||||||
|
// http://www.garagegames.com/community/resources/view/17821
|
||||||
|
// Supporting code mods in other areas of the engine are marked as
|
||||||
|
// "(selection-highlight)".
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _afxRENDERHIGHLIGHTMGR_H_
|
||||||
|
#define _afxRENDERHIGHLIGHTMGR_H_
|
||||||
|
|
||||||
|
#ifndef _TEXTARGETBIN_MGR_H_
|
||||||
|
#include "renderInstance/renderTexTargetBinManager.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class PostEffect;
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
class afxRenderHighlightMgr : public RenderTexTargetBinManager
|
||||||
|
{
|
||||||
|
typedef RenderTexTargetBinManager Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
afxRenderHighlightMgr();
|
||||||
|
virtual ~afxRenderHighlightMgr();
|
||||||
|
|
||||||
|
/// Returns the selection post effect.
|
||||||
|
PostEffect* getSelectionEffect();
|
||||||
|
|
||||||
|
/// Returns true if the highlight post effect is
|
||||||
|
/// enabled and the selection buffer should be updated.
|
||||||
|
bool isSelectionEnabled();
|
||||||
|
|
||||||
|
// RenderBinManager
|
||||||
|
virtual void addElement( RenderInst *inst );
|
||||||
|
virtual void render( SceneRenderState *state );
|
||||||
|
|
||||||
|
// ConsoleObject
|
||||||
|
DECLARE_CONOBJECT( afxRenderHighlightMgr );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
SimObjectPtr<PostEffect> mSelectionEffect;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _afxRENDERHIGHLIGHTMGR_H_
|
||||||
469
Engine/source/afx/afxResidueMgr.cpp
Normal file
469
Engine/source/afx/afxResidueMgr.cpp
Normal file
|
|
@ -0,0 +1,469 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "ts/tsShapeInstance.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxZodiacMgr.h"
|
||||||
|
#include "afx/ce/afxModel.h"
|
||||||
|
#include "afx/afxResidueMgr.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
int QSORT_CALLBACK afxResidueMgr::ResidueList::compare_residue(const void* p1, const void* p2)
|
||||||
|
{
|
||||||
|
const afxResidueMgr::Residue** pd1 = (const afxResidueMgr::Residue**)p1;
|
||||||
|
const afxResidueMgr::Residue** pd2 = (const afxResidueMgr::Residue**)p2;
|
||||||
|
|
||||||
|
return int(((char*)(*pd1)->data.simobject) - ((char*)(*pd2)->data.simobject));
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
inline void afxResidueMgr::ResidueList::swap_array_ptrs()
|
||||||
|
{
|
||||||
|
Vector<Residue*>* tmp = m_array;
|
||||||
|
m_array = m_scratch_array;
|
||||||
|
m_scratch_array = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::ResidueList::free_residue(Residue* residue)
|
||||||
|
{
|
||||||
|
if (the_mgr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (the_mgr->requires_delete_tracking(residue))
|
||||||
|
the_mgr->disable_delete_tracking(residue);
|
||||||
|
the_mgr->free_residue(residue);
|
||||||
|
}
|
||||||
|
|
||||||
|
afxResidueMgr::ResidueList::ResidueList()
|
||||||
|
{
|
||||||
|
VECTOR_SET_ASSOCIATION(m_array_a);
|
||||||
|
VECTOR_SET_ASSOCIATION(m_array_b);
|
||||||
|
|
||||||
|
m_array = &m_array_a;
|
||||||
|
m_scratch_array = &m_array_b ;
|
||||||
|
|
||||||
|
m_dirty = false;
|
||||||
|
m_pending = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxResidueMgr::ResidueList::~ResidueList()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::ResidueList::clear()
|
||||||
|
{
|
||||||
|
if (the_mgr)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < m_array->size(); i++)
|
||||||
|
{
|
||||||
|
Residue* r = (*m_array)[i];
|
||||||
|
the_mgr->free_residue(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_array_a.clear();
|
||||||
|
m_array_b.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::ResidueList::sort()
|
||||||
|
{
|
||||||
|
dQsort(m_array->address(), m_array->size(), sizeof(Residue*), compare_residue);
|
||||||
|
m_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::ResidueList::fadeAndCull(U32 now)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < m_array->size(); i++)
|
||||||
|
{
|
||||||
|
Residue* r = (*m_array)[i];
|
||||||
|
|
||||||
|
// done
|
||||||
|
if (now >= r->stop_time)
|
||||||
|
{
|
||||||
|
free_residue(r);
|
||||||
|
}
|
||||||
|
// fading
|
||||||
|
else if (now >= r->fade_time)
|
||||||
|
{
|
||||||
|
r->fade = 1.0f - ((F32)(now - r->fade_time))/((F32)(r->stop_time - r->fade_time));
|
||||||
|
m_scratch_array->push_back(r);
|
||||||
|
}
|
||||||
|
// opaque
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r->fade = 1.0f;
|
||||||
|
m_scratch_array->push_back(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_array->clear();
|
||||||
|
swap_array_ptrs();
|
||||||
|
}
|
||||||
|
|
||||||
|
// removes all residue with datablock matching obj
|
||||||
|
void afxResidueMgr::ResidueList::stripMatchingObjects(SimObject* db, bool del_notify)
|
||||||
|
{
|
||||||
|
if (del_notify)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < m_array->size(); i++)
|
||||||
|
{
|
||||||
|
Residue* r = (*m_array)[i];
|
||||||
|
if (db == r->data.simobject && the_mgr != NULL)
|
||||||
|
the_mgr->free_residue(r);
|
||||||
|
else
|
||||||
|
m_scratch_array->push_back(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < m_array->size(); i++)
|
||||||
|
{
|
||||||
|
Residue* r = (*m_array)[i];
|
||||||
|
if (db == r->data.simobject)
|
||||||
|
free_residue(r);
|
||||||
|
else
|
||||||
|
m_scratch_array->push_back(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_array->clear();
|
||||||
|
swap_array_ptrs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::ResidueList::add(Residue* residue)
|
||||||
|
{
|
||||||
|
m_array->push_back(residue);
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::manage_residue(const Residue* r)
|
||||||
|
{
|
||||||
|
if (r == NULL || r->fade < 0.01f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (r->type == ZODIAC)
|
||||||
|
{
|
||||||
|
LinearColorF zode_color = ColorI(r->params.zodiac.r, r->params.zodiac.g, r->params.zodiac.b, r->params.zodiac.a);
|
||||||
|
|
||||||
|
afxZodiacData* zd = (afxZodiacData*) r->data.zodiac;
|
||||||
|
if (zd->blend_flags == afxZodiacDefs::BLEND_SUBTRACTIVE)
|
||||||
|
zode_color *= r->fade;
|
||||||
|
else
|
||||||
|
zode_color.alpha *= r->fade;
|
||||||
|
|
||||||
|
Point3F zode_pos(r->params.zodiac.pos_x, r->params.zodiac.pos_y, r->params.zodiac.pos_z);
|
||||||
|
Point2F zode_vrange(r->params.zodiac.vrange_dn, r->params.zodiac.vrange_dn);
|
||||||
|
if (r->params.zodiac.on_terrain)
|
||||||
|
{
|
||||||
|
afxZodiacMgr::addTerrainZodiac(zode_pos, r->params.zodiac.rad, zode_color, r->params.zodiac.ang, zd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
afxZodiacMgr::addInteriorZodiac(zode_pos, r->params.zodiac.rad, zode_vrange, zode_color, r->params.zodiac.ang, zd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (r->type == MODEL)
|
||||||
|
{
|
||||||
|
r->data.model->setFadeAmount(r->fade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::ResidueList::manage()
|
||||||
|
{
|
||||||
|
if (the_mgr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
S32 n_residue = m_array->size();
|
||||||
|
|
||||||
|
for (S32 x = 0; x < n_residue; x++)
|
||||||
|
the_mgr->manage_residue((*m_array)[x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 afxResidueMgr::ResidueList::findPendingBestBump(U32 look_max)
|
||||||
|
{
|
||||||
|
U32 soonest = 1000*60*60*24;
|
||||||
|
m_pending = -1;
|
||||||
|
|
||||||
|
U32 n = m_array->size();
|
||||||
|
for (U32 i = 0; i < n && i < look_max; i++)
|
||||||
|
{
|
||||||
|
Residue* r = (*m_array)[i];
|
||||||
|
if (r->stop_time < soonest)
|
||||||
|
{
|
||||||
|
soonest = r->stop_time;
|
||||||
|
m_pending = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return soonest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::ResidueList::bumpPending()
|
||||||
|
{
|
||||||
|
if (m_pending >= 0 && m_pending < m_array->size())
|
||||||
|
{
|
||||||
|
Residue* r = (*m_array)[m_pending];
|
||||||
|
m_array->erase(m_pending);
|
||||||
|
free_residue(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pending = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxResidueMgr::requires_delete_tracking(Residue* r)
|
||||||
|
{
|
||||||
|
return (r->type == MODEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::enable_delete_tracking(Residue* r)
|
||||||
|
{
|
||||||
|
deleteNotify(r->data.simobject);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::disable_delete_tracking(Residue* r)
|
||||||
|
{
|
||||||
|
clearNotify(r->data.simobject);
|
||||||
|
r->data.simobject->deleteObject();
|
||||||
|
r->data.simobject = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
afxResidueMgr* afxResidueMgr::the_mgr = NULL;
|
||||||
|
U32 afxResidueMgr::m_max_residue_objs = 256;
|
||||||
|
bool afxResidueMgr::enabled = true;
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT(afxResidueMgr);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxResidueMgr,
|
||||||
|
"@brief A class that manages certain AFX effects that can persist for long durations.\n\n"
|
||||||
|
|
||||||
|
"A class that manages certain AFX effects that can persist much longer than the duration of choreographers.\n"
|
||||||
|
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// free-list management
|
||||||
|
|
||||||
|
afxResidueMgr::Residue* afxResidueMgr::alloc_free_pool_block()
|
||||||
|
{
|
||||||
|
// allocate new block for the free-list
|
||||||
|
m_free_pool_blocks.push_back(new Residue[FREE_POOL_BLOCK_SIZE]);
|
||||||
|
|
||||||
|
// link them onto the free-list
|
||||||
|
Residue* new_block = m_free_pool_blocks.last();
|
||||||
|
for (U32 i = 0; i < FREE_POOL_BLOCK_SIZE - 1; i++)
|
||||||
|
new_block[i].next = &new_block[i + 1];
|
||||||
|
|
||||||
|
// tail of free-list points to NULL
|
||||||
|
new_block[FREE_POOL_BLOCK_SIZE - 1].next = NULL;
|
||||||
|
|
||||||
|
return new_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxResidueMgr::Residue* afxResidueMgr::alloc_residue()
|
||||||
|
{
|
||||||
|
// need new free-list-block if m_next_free is null
|
||||||
|
if (!m_next_free)
|
||||||
|
m_next_free = alloc_free_pool_block();
|
||||||
|
|
||||||
|
// pop new residue from head of free-list
|
||||||
|
Residue* residue = m_next_free;
|
||||||
|
m_next_free = residue->next;
|
||||||
|
residue->next = NULL;
|
||||||
|
|
||||||
|
return residue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::free_residue(Residue* residue)
|
||||||
|
{
|
||||||
|
if (residue && residue->type == ZODIAC)
|
||||||
|
{
|
||||||
|
if (residue->data.zodiac && residue->data.zodiac->isTempClone())
|
||||||
|
{
|
||||||
|
delete residue->data.zodiac;
|
||||||
|
residue->data.zodiac = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// push residue onto head of free-list
|
||||||
|
residue->next = m_next_free;
|
||||||
|
m_next_free = residue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxResidueMgr::deleteResidueObject(SimObject* obj, bool del_notify)
|
||||||
|
{
|
||||||
|
m_managed.stripMatchingObjects(obj, del_notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::bump_residue()
|
||||||
|
{
|
||||||
|
if (m_managed.findPendingBestBump())
|
||||||
|
m_managed.bumpPending();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::add_residue(Residue* residue)
|
||||||
|
{
|
||||||
|
AssertFatal(residue != NULL, "residue pointer is NULL.");
|
||||||
|
|
||||||
|
if (m_managed.size() >= m_max_residue_objs)
|
||||||
|
bump_residue();
|
||||||
|
|
||||||
|
m_managed.add(residue);
|
||||||
|
manage_residue(residue);
|
||||||
|
|
||||||
|
if (requires_delete_tracking(residue))
|
||||||
|
enable_delete_tracking(residue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
afxResidueMgr::afxResidueMgr()
|
||||||
|
{
|
||||||
|
mObjBox.minExtents.set(-1e7, -1e7, -1e7);
|
||||||
|
mObjBox.maxExtents.set( 1e7, 1e7, 1e7);
|
||||||
|
mWorldBox.minExtents.set(-1e7, -1e7, -1e7);
|
||||||
|
mWorldBox.maxExtents.set( 1e7, 1e7, 1e7);
|
||||||
|
|
||||||
|
m_next_free = NULL;
|
||||||
|
|
||||||
|
VECTOR_SET_ASSOCIATION(m_free_pool_blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
afxResidueMgr::~afxResidueMgr()
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::cleanup()
|
||||||
|
{
|
||||||
|
m_managed.clear();
|
||||||
|
|
||||||
|
m_next_free = NULL;
|
||||||
|
|
||||||
|
for (S32 i = 0; i < m_free_pool_blocks.size(); i++)
|
||||||
|
delete [] m_free_pool_blocks[i];
|
||||||
|
|
||||||
|
m_free_pool_blocks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::onDeleteNotify(SimObject* obj)
|
||||||
|
{
|
||||||
|
deleteResidueObject(obj, true);
|
||||||
|
Parent::onDeleteNotify(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::residueAdvanceTime()
|
||||||
|
{
|
||||||
|
U32 now = Platform::getVirtualMilliseconds();
|
||||||
|
m_managed.fadeAndCull(now);
|
||||||
|
m_managed.sortIfDirty();
|
||||||
|
m_managed.manage();
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// add ZODIAC residue
|
||||||
|
void afxResidueMgr::add_interior_zodiac(F32 dur, F32 fade_dur, afxZodiacData* zode, const Point3F& pos,
|
||||||
|
F32 rad, const Point2F& vrange, const LinearColorF& col, F32 ang)
|
||||||
|
{
|
||||||
|
add_zodiac(dur, fade_dur, zode, pos, rad, vrange, col, ang, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::add_terrain_zodiac(F32 dur, F32 fade_dur, afxZodiacData* zode, const Point3F& pos,
|
||||||
|
F32 rad, const LinearColorF& col, F32 ang)
|
||||||
|
{
|
||||||
|
static Point2F vrange(0.0, 0.0);
|
||||||
|
add_zodiac(dur, fade_dur, zode, pos, rad, vrange, col, ang, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxResidueMgr::add_zodiac(F32 dur, F32 fade_dur, afxZodiacData* zode, const Point3F& pos,
|
||||||
|
F32 rad, const Point2F& vrange, const LinearColorF& col, F32 ang, bool on_terrain)
|
||||||
|
{
|
||||||
|
if (m_max_residue_objs == 0 || dur <= 0 || the_mgr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ColorI col_i = LinearColorF(col).toColorI();
|
||||||
|
U32 now = Platform::getVirtualMilliseconds();
|
||||||
|
|
||||||
|
Residue* residue = the_mgr->alloc_residue();
|
||||||
|
//
|
||||||
|
residue->type = ZODIAC;
|
||||||
|
residue->data.zodiac = zode;
|
||||||
|
residue->fade_time = now + (U32)(dur*1000);
|
||||||
|
residue->stop_time = residue->fade_time + (U32)(fade_dur*1000);
|
||||||
|
residue->fade = 1.0f;
|
||||||
|
//
|
||||||
|
residue->params.zodiac.pos_x = pos.x;
|
||||||
|
residue->params.zodiac.pos_y = pos.y;
|
||||||
|
residue->params.zodiac.pos_z = pos.z;
|
||||||
|
residue->params.zodiac.rad = rad;
|
||||||
|
residue->params.zodiac.vrange_dn = vrange.x;
|
||||||
|
residue->params.zodiac.vrange_up = vrange.y;
|
||||||
|
residue->params.zodiac.r = col_i.red;
|
||||||
|
residue->params.zodiac.g = col_i.green;
|
||||||
|
residue->params.zodiac.b = col_i.blue;
|
||||||
|
residue->params.zodiac.a = col_i.alpha;
|
||||||
|
residue->params.zodiac.ang = ang;
|
||||||
|
residue->params.zodiac.on_terrain = on_terrain;
|
||||||
|
//
|
||||||
|
residue->next = 0;
|
||||||
|
|
||||||
|
the_mgr->add_residue(residue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// add MODEL residue
|
||||||
|
|
||||||
|
void afxResidueMgr::add(F32 dur, F32 fade_dur, afxModel* model)
|
||||||
|
{
|
||||||
|
if (m_max_residue_objs == 0 || dur <= 0 || the_mgr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
U32 now = Platform::getVirtualMilliseconds();
|
||||||
|
|
||||||
|
Residue* residue = the_mgr->alloc_residue();
|
||||||
|
//
|
||||||
|
residue->type = MODEL;
|
||||||
|
residue->data.model = model;
|
||||||
|
residue->fade_time = now + (U32)(dur*1000);
|
||||||
|
residue->stop_time = residue->fade_time + (U32)(fade_dur*1000);
|
||||||
|
residue->fade = 1.0f;
|
||||||
|
//
|
||||||
|
residue->next = 0;
|
||||||
|
|
||||||
|
the_mgr->add_residue(residue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
179
Engine/source/afx/afxResidueMgr.h
Normal file
179
Engine/source/afx/afxResidueMgr.h
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_RESIDUE_MGR_H_
|
||||||
|
#define _AFX_RESIDUE_MGR_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class afxZodiacData;
|
||||||
|
class afxModel;
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxResidueMgr
|
||||||
|
//
|
||||||
|
// Manage transient objects in the world.
|
||||||
|
|
||||||
|
class afxResidueMgr : public GameBase
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef GameBase Parent;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ZODIAC,
|
||||||
|
MODEL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Residue
|
||||||
|
{
|
||||||
|
struct ZodiacParams
|
||||||
|
{
|
||||||
|
F32 pos_x, pos_y, pos_z;
|
||||||
|
F32 rad, vrange_dn, vrange_up;
|
||||||
|
U8 r,g,b,a;
|
||||||
|
F32 ang;
|
||||||
|
bool on_terrain;
|
||||||
|
};
|
||||||
|
|
||||||
|
union ResidueParams
|
||||||
|
{
|
||||||
|
ZodiacParams zodiac;
|
||||||
|
};
|
||||||
|
|
||||||
|
union ResidueData
|
||||||
|
{
|
||||||
|
afxZodiacData* zodiac;
|
||||||
|
afxModel* model;
|
||||||
|
SimObject* simobject;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
U32 type;
|
||||||
|
ResidueData data;
|
||||||
|
ResidueParams params;
|
||||||
|
U32 fade_time;
|
||||||
|
U32 stop_time;
|
||||||
|
F32 fade;
|
||||||
|
|
||||||
|
Residue* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ResidueList
|
||||||
|
{
|
||||||
|
Vector<Residue*> m_array_a;
|
||||||
|
Vector<Residue*> m_array_b;
|
||||||
|
|
||||||
|
Vector<Residue*>* m_array;
|
||||||
|
Vector<Residue*>* m_scratch_array;
|
||||||
|
bool m_dirty;
|
||||||
|
S32 m_pending;
|
||||||
|
|
||||||
|
void swap_array_ptrs();
|
||||||
|
void free_residue(Residue*);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ ResidueList();
|
||||||
|
/*D*/ ~ResidueList();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
S32 size() { return m_array->size(); }
|
||||||
|
bool empty() { return m_array->empty(); }
|
||||||
|
void sortIfDirty() { if (m_dirty) sort(); }
|
||||||
|
|
||||||
|
void sort();
|
||||||
|
void fadeAndCull(U32 now);
|
||||||
|
void stripMatchingObjects(SimObject* db, bool del_notify=false);
|
||||||
|
void add(Residue*);
|
||||||
|
|
||||||
|
void manage();
|
||||||
|
|
||||||
|
U32 findPendingBestBump(U32 look_max=256);
|
||||||
|
void bumpPending();
|
||||||
|
|
||||||
|
static int QSORT_CALLBACK compare_residue(const void* p1, const void* p2);
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class ResidueList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum { FREE_POOL_BLOCK_SIZE = 256 };
|
||||||
|
|
||||||
|
static afxResidueMgr* the_mgr;
|
||||||
|
|
||||||
|
static U32 m_max_residue_objs;
|
||||||
|
static bool enabled;
|
||||||
|
|
||||||
|
ResidueList m_managed;
|
||||||
|
|
||||||
|
Vector<Residue*> m_free_pool_blocks;
|
||||||
|
Residue* m_next_free;
|
||||||
|
|
||||||
|
Residue* alloc_free_pool_block();
|
||||||
|
Residue* alloc_residue();
|
||||||
|
void free_residue(Residue*);
|
||||||
|
|
||||||
|
void bump_residue();
|
||||||
|
void add_residue(Residue*);
|
||||||
|
static void add_zodiac(F32 dur, F32 fade_dur, afxZodiacData*, const Point3F& pos, F32 rad,
|
||||||
|
const Point2F& vrange, const LinearColorF& col, F32 ang, bool on_terrain);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void deleteResidueObject(SimObject* obj, bool del_notify=false);
|
||||||
|
|
||||||
|
void manage_residue(const Residue* r);
|
||||||
|
|
||||||
|
bool requires_delete_tracking(Residue*);
|
||||||
|
void enable_delete_tracking(Residue*);
|
||||||
|
void disable_delete_tracking(Residue*);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxResidueMgr();
|
||||||
|
/*D*/ ~afxResidueMgr();
|
||||||
|
|
||||||
|
void cleanup();
|
||||||
|
virtual void onDeleteNotify(SimObject *obj);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void residueAdvanceTime();
|
||||||
|
|
||||||
|
// ZODIAC
|
||||||
|
static void add_terrain_zodiac(F32 dur, F32 fade_dur, afxZodiacData*, const Point3F& pos, F32 rad,
|
||||||
|
const LinearColorF& col, F32 ang);
|
||||||
|
static void add_interior_zodiac(F32 dur, F32 fade_dur, afxZodiacData*, const Point3F& pos, F32 rad,
|
||||||
|
const Point2F& vrange, const LinearColorF& col, F32 ang);
|
||||||
|
|
||||||
|
// MODEL
|
||||||
|
static void add(F32 dur, F32 fade_dur, afxModel*);
|
||||||
|
|
||||||
|
static afxResidueMgr* getMaster() { return the_mgr; }
|
||||||
|
static void setMaster(afxResidueMgr* m) { the_mgr = m; }
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxResidueMgr);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_RESIDUE_MGR_H_
|
||||||
1173
Engine/source/afx/afxSelectron.cpp
Normal file
1173
Engine/source/afx/afxSelectron.cpp
Normal file
File diff suppressed because it is too large
Load diff
258
Engine/source/afx/afxSelectron.h
Normal file
258
Engine/source/afx/afxSelectron.h
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_SELECTION_EFFECT_H_
|
||||||
|
#define _AFX_SELECTION_EFFECT_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "console/typeValidators.h"
|
||||||
|
|
||||||
|
#include "afxChoreographer.h"
|
||||||
|
#include "afxEffectWrapper.h"
|
||||||
|
#include "afxPhrase.h"
|
||||||
|
|
||||||
|
class afxChoreographerData;
|
||||||
|
class afxEffectBaseData;
|
||||||
|
|
||||||
|
class afxSelectronDefs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
MAIN_PHRASE,
|
||||||
|
SELECT_PHRASE,
|
||||||
|
DESELECT_PHRASE,
|
||||||
|
NUM_PHRASES
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class afxSelectronData : public afxChoreographerData, public afxSelectronDefs
|
||||||
|
{
|
||||||
|
typedef afxChoreographerData Parent;
|
||||||
|
|
||||||
|
class ewValidator : public TypeValidator
|
||||||
|
{
|
||||||
|
U32 id;
|
||||||
|
public:
|
||||||
|
ewValidator(U32 id) { this->id = id; }
|
||||||
|
void validateType(SimObject *object, void *typePtr);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool do_id_convert;
|
||||||
|
|
||||||
|
public:
|
||||||
|
F32 main_dur;
|
||||||
|
F32 select_dur;
|
||||||
|
F32 deselect_dur;
|
||||||
|
|
||||||
|
S32 n_main_loops;
|
||||||
|
S32 n_select_loops;
|
||||||
|
S32 n_deselect_loops;
|
||||||
|
|
||||||
|
bool registered;
|
||||||
|
U8 obj_type_style;
|
||||||
|
U32 obj_type_mask;
|
||||||
|
|
||||||
|
afxEffectBaseData* dummy_fx_entry;
|
||||||
|
|
||||||
|
afxEffectList main_fx_list;
|
||||||
|
afxEffectList select_fx_list;
|
||||||
|
afxEffectList deselect_fx_list;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void pack_fx(BitStream* stream, const afxEffectList& fx, bool packed);
|
||||||
|
void unpack_fx(BitStream* stream, afxEffectList& fx);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxSelectronData();
|
||||||
|
/*C*/ afxSelectronData(const afxSelectronData&, bool = false);
|
||||||
|
/*D*/ ~afxSelectronData();
|
||||||
|
|
||||||
|
virtual void reloadReset();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
bool matches(U32 mask, U8 style);
|
||||||
|
void gatherConstraintDefs(Vector<afxConstraintDef>&);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxSelectronData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool afxSelectronData::matches(U32 mask, U8 style)
|
||||||
|
{
|
||||||
|
if (obj_type_style != style)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (obj_type_mask == 0 && mask == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return ((obj_type_mask & mask) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxSelectron
|
||||||
|
|
||||||
|
class afxSelectron : public afxChoreographer, public afxSelectronDefs
|
||||||
|
{
|
||||||
|
typedef afxChoreographer Parent;
|
||||||
|
friend class arcaneFX;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum MaskBits
|
||||||
|
{
|
||||||
|
StateEventMask = Parent::NextFreeMask << 0,
|
||||||
|
SyncEventMask = Parent::NextFreeMask << 1,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NULL_EVENT,
|
||||||
|
ACTIVATE_EVENT,
|
||||||
|
SHUTDOWN_EVENT,
|
||||||
|
DEACTIVATE_EVENT,
|
||||||
|
INTERRUPT_EVENT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
INACTIVE_STATE,
|
||||||
|
ACTIVE_STATE,
|
||||||
|
CLEANUP_STATE,
|
||||||
|
DONE_STATE,
|
||||||
|
LATE_STATE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MARK_ACTIVATE = BIT(0),
|
||||||
|
MARK_SHUTDOWN = BIT(1),
|
||||||
|
MARK_DEACTIVATE = BIT(2),
|
||||||
|
MARK_INTERRUPT = BIT(3),
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectDeleteEvent : public SimEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void process(SimObject *obj) { if (obj) obj->deleteObject(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static StringTableEntry CAMERA_CONS;
|
||||||
|
static StringTableEntry LISTENER_CONS;
|
||||||
|
static StringTableEntry FREE_TARGET_CONS;
|
||||||
|
|
||||||
|
private:
|
||||||
|
afxSelectronData* datablock;
|
||||||
|
SimObject* exeblock;
|
||||||
|
|
||||||
|
bool constraints_initialized;
|
||||||
|
bool client_only;
|
||||||
|
|
||||||
|
U8 effect_state;
|
||||||
|
F32 effect_elapsed;
|
||||||
|
|
||||||
|
afxConstraintID listener_cons_id;
|
||||||
|
afxConstraintID free_target_cons_id;
|
||||||
|
afxConstraintID camera_cons_id;
|
||||||
|
SceneObject* camera_cons_obj;
|
||||||
|
|
||||||
|
afxPhrase* phrases[NUM_PHRASES];
|
||||||
|
|
||||||
|
F32 time_factor;
|
||||||
|
U8 marks_mask;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
bool state_expired();
|
||||||
|
void init_constraints();
|
||||||
|
void setup_main_fx();
|
||||||
|
void setup_select_fx();
|
||||||
|
void setup_deselect_fx();
|
||||||
|
bool cleanup_over();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxSelectron();
|
||||||
|
/*C*/ afxSelectron(bool not_default);
|
||||||
|
/*D*/ ~afxSelectron();
|
||||||
|
|
||||||
|
// STANDARD OVERLOADED METHODS //
|
||||||
|
virtual bool onNewDataBlock(GameBaseData* dptr, bool reload);
|
||||||
|
virtual void processTick(const Move*);
|
||||||
|
virtual void advanceTime(F32 dt);
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
virtual U32 packUpdate(NetConnection*, U32, BitStream*);
|
||||||
|
virtual void unpackUpdate(NetConnection*, BitStream*);
|
||||||
|
|
||||||
|
virtual void sync_with_clients();
|
||||||
|
void finish_startup();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxSelectron);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_server();
|
||||||
|
//
|
||||||
|
void change_state_s(U8 pending_state);
|
||||||
|
//
|
||||||
|
void enter_active_state_s();
|
||||||
|
void leave_active_state_s();
|
||||||
|
void enter_cleanup_state_s();
|
||||||
|
void enter_done_state_s();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_client(F32 dt);
|
||||||
|
//
|
||||||
|
void change_state_c(U8 pending_state);
|
||||||
|
//
|
||||||
|
void enter_active_state_c(F32 starttime);
|
||||||
|
void enter_cleanup_state_c();
|
||||||
|
void enter_done_state_c();
|
||||||
|
void leave_active_state_c();
|
||||||
|
|
||||||
|
void sync_client(U16 marks, U8 state, F32 elapsed);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void postEvent(U8 event);
|
||||||
|
void setTimeFactor(F32 f) { time_factor = (f > 0) ? f : 1.0f; }
|
||||||
|
F32 getTimeFactor() { return time_factor; }
|
||||||
|
|
||||||
|
void activate();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static afxSelectron* start_selectron(SceneObject* picked, U8 subcode, SimObject* extra);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
#endif // _AFX_SELECTION_EFFECT_H_
|
||||||
357
Engine/source/afx/afxSpellBook.cpp
Normal file
357
Engine/source/afx/afxSpellBook.cpp
Normal file
|
|
@ -0,0 +1,357 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
#include "T3D/gameBase/gameBase.h"
|
||||||
|
|
||||||
|
#include "afx/afxSpellBook.h"
|
||||||
|
#include "afx/afxMagicSpell.h"
|
||||||
|
#include "afx/rpg/afxRPGMagicSpell.h"
|
||||||
|
#include "afx/ui/afxSpellButton.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxSpellBookData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxSpellBookData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxSpellBookData,
|
||||||
|
"@brief A spellbook datablock.\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxMisc\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxSpellBookData::afxSpellBookData()
|
||||||
|
{
|
||||||
|
spells_per_page = 12;
|
||||||
|
pages_per_book = 12;
|
||||||
|
dMemset(spells, 0, sizeof(spells));
|
||||||
|
dMemset(rpg_spells, 0, sizeof(rpg_spells));
|
||||||
|
|
||||||
|
// marked true if datablock ids need to
|
||||||
|
// be converted into pointers
|
||||||
|
do_id_convert = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxSpellBookData)
|
||||||
|
|
||||||
|
void afxSpellBookData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("spellsPerPage", TypeS8, myOffset(spells_per_page),
|
||||||
|
"...");
|
||||||
|
addField("pagesPerBook", TypeS8, myOffset(pages_per_book),
|
||||||
|
"...");
|
||||||
|
|
||||||
|
addField("spells", TYPEID<GameBaseData>(), myOffset(spells), MAX_PAGES_PER_BOOK*MAX_SPELLS_PER_PAGE,
|
||||||
|
"...");
|
||||||
|
addField("rpgSpells", TYPEID<GameBaseData>(), myOffset(rpg_spells), MAX_PAGES_PER_BOOK*MAX_SPELLS_PER_PAGE,
|
||||||
|
"...");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxSpellBookData::preload(bool server, String &errorStr)
|
||||||
|
{
|
||||||
|
if (!Parent::preload(server, errorStr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Resolve objects transmitted from server
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
if (do_id_convert)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < pages_per_book*spells_per_page; i++)
|
||||||
|
{
|
||||||
|
SimObjectId db_id = SimObjectId((uintptr_t)rpg_spells[i]);
|
||||||
|
if (db_id != 0)
|
||||||
|
{
|
||||||
|
// try to convert id to pointer
|
||||||
|
if (!Sim::findObject(db_id, rpg_spells[i]))
|
||||||
|
{
|
||||||
|
Con::errorf(ConsoleLogEntry::General,
|
||||||
|
"afxSpellBookData::preload() -- bad datablockId: 0x%x (afxRPGMagicSpellData)",
|
||||||
|
db_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_id_convert = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxSpellBookData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
stream->write(spells_per_page);
|
||||||
|
stream->write(pages_per_book);
|
||||||
|
|
||||||
|
for (S32 i = 0; i < pages_per_book*spells_per_page; i++)
|
||||||
|
writeDatablockID(stream, rpg_spells[i], packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxSpellBookData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
stream->read(&spells_per_page);
|
||||||
|
stream->read(&pages_per_book);
|
||||||
|
|
||||||
|
do_id_convert = true;
|
||||||
|
for (S32 i = 0; i < pages_per_book*spells_per_page; i++)
|
||||||
|
rpg_spells[i] = (afxRPGMagicSpellData*) readDatablockID(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(afxSpellBookData, getPageSlotIndex, S32, (Point2I bookSlot),,
|
||||||
|
"...\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return object->getPageSlotIndex(bookSlot.x, bookSlot.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(afxSpellBookData, getCapacity, S32, (),,
|
||||||
|
"Get the capacity (total number of spell slots) in a spellbook.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return object->spells_per_page*object->pages_per_book;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxSpellBook
|
||||||
|
|
||||||
|
IMPLEMENT_CO_NETOBJECT_V1(afxSpellBook);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxSpellBook,
|
||||||
|
"@brief A spellbook object.\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxMisc\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxSpellBook::afxSpellBook()
|
||||||
|
{
|
||||||
|
mNetFlags.set(Ghostable | ScopeAlways);
|
||||||
|
mDataBlock = NULL;
|
||||||
|
all_spell_cooldown = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxSpellBook::~afxSpellBook()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxSpellBook::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxSpellBook::processTick(const Move* m)
|
||||||
|
{
|
||||||
|
Parent::processTick(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxSpellBook::advanceTime(F32 dt)
|
||||||
|
{
|
||||||
|
Parent::advanceTime(dt);
|
||||||
|
|
||||||
|
if (all_spell_cooldown < 1.0f)
|
||||||
|
{
|
||||||
|
all_spell_cooldown += dt/2.0f;
|
||||||
|
if (all_spell_cooldown > 1.0f)
|
||||||
|
all_spell_cooldown = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
bool afxSpellBook::onNewDataBlock(GameBaseData* dptr, bool reload)
|
||||||
|
{
|
||||||
|
mDataBlock = dynamic_cast<afxSpellBookData*>(dptr);
|
||||||
|
if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
scriptOnNewDataBlock();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
bool afxSpellBook::onAdd()
|
||||||
|
{
|
||||||
|
if (!Parent::onAdd())
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxSpellBook::onRemove()
|
||||||
|
{
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
U32 afxSpellBook::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
|
||||||
|
{
|
||||||
|
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||||
|
|
||||||
|
if (stream->writeFlag(mask & InitialUpdateMask))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllSpellCooldown
|
||||||
|
if (stream->writeFlag(mask & AllSpellCooldownMask))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return(retMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxSpellBook::unpackUpdate(NetConnection * con, BitStream * stream)
|
||||||
|
{
|
||||||
|
Parent::unpackUpdate(con, stream);
|
||||||
|
|
||||||
|
// InitialUpdate
|
||||||
|
if (stream->readFlag())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllSpellCooldown
|
||||||
|
if (stream->readFlag())
|
||||||
|
{
|
||||||
|
all_spell_cooldown = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SPELL_DATA_NOT_FOUND "\n<just:center><font:Arial:20><color:FF0000>** Spell data not found **\n\n\n\n"
|
||||||
|
|
||||||
|
char* afxSpellBook::formatDesc(char* buffer, int len, S32 page, S32 slot) const
|
||||||
|
{
|
||||||
|
S32 idx = mDataBlock->getPageSlotIndex(page, slot);
|
||||||
|
if (idx < 0 || !mDataBlock->rpg_spells[idx])
|
||||||
|
return SPELL_DATA_NOT_FOUND;
|
||||||
|
|
||||||
|
return mDataBlock->rpg_spells[idx]->formatDesc(buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* afxSpellBook::getSpellIcon(S32 page, S32 slot) const
|
||||||
|
{
|
||||||
|
S32 idx = mDataBlock->getPageSlotIndex(page, slot);
|
||||||
|
if (idx < 0 || !mDataBlock->rpg_spells[idx])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return mDataBlock->rpg_spells[idx]->icon_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxSpellBook::isPlaceholder(S32 page, S32 slot) const
|
||||||
|
{
|
||||||
|
S32 idx = mDataBlock->getPageSlotIndex(page, slot);
|
||||||
|
if (idx < 0 || !mDataBlock->rpg_spells[idx])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return mDataBlock->rpg_spells[idx]->is_placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
afxMagicSpellData* afxSpellBook::getSpellData(S32 page, S32 slot)
|
||||||
|
{
|
||||||
|
S32 idx = mDataBlock->getPageSlotIndex(page, slot);
|
||||||
|
if (idx < 0 || !mDataBlock->spells[idx])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return mDataBlock->spells[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
afxRPGMagicSpellData* afxSpellBook::getSpellRPGData(S32 page, S32 slot)
|
||||||
|
{
|
||||||
|
S32 idx = mDataBlock->getPageSlotIndex(page, slot);
|
||||||
|
if (idx < 0 || !mDataBlock->rpg_spells[idx])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return mDataBlock->rpg_spells[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxSpellBook::startAllSpellCooldown()
|
||||||
|
{
|
||||||
|
//all_spell_cooldown = 0.0f;
|
||||||
|
setMaskBits(AllSpellCooldownMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 afxSpellBook::getCooldownFactor(S32 page, S32 slot)
|
||||||
|
{
|
||||||
|
return all_spell_cooldown;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
DefineEngineMethod(afxSpellBook, getPageSlotIndex, S32, (Point2I bookSlot),,
|
||||||
|
"...\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return object->getPageSlotIndex(bookSlot.x, bookSlot.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(afxSpellBook, getSpellData, S32, (Point2I bookSlot),,
|
||||||
|
"Get spell datablock for spell stored at spellbook index, (page, slot).\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
afxMagicSpellData* spell_data = object->getSpellData(bookSlot.x, bookSlot.y);
|
||||||
|
return (spell_data) ? spell_data->getId() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(afxSpellBook, getSpellRPGData, S32, (Point2I bookSlot),,
|
||||||
|
"Get spell RPG datablock for spell stored at spellbook index, (page, slot).\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
afxRPGMagicSpellData* spell_data = object->getSpellRPGData(bookSlot.x, bookSlot.y);
|
||||||
|
return (spell_data) ? spell_data->getId() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(afxSpellBook, startAllSpellCooldown, void, (),,
|
||||||
|
"...\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
object->startAllSpellCooldown();
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
142
Engine/source/afx/afxSpellBook.h
Normal file
142
Engine/source/afx/afxSpellBook.h
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_SPELL_BOOK_H_
|
||||||
|
#define _AFX_SPELL_BOOK_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "T3D/gameBase/gameBase.h"
|
||||||
|
|
||||||
|
class afxSpellBookDefs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
MAX_SPELLS_PER_PAGE = 12,
|
||||||
|
MAX_PAGES_PER_BOOK = 12
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class afxMagicSpellData;
|
||||||
|
class afxRPGMagicSpellData;
|
||||||
|
|
||||||
|
class afxSpellBookData : public GameBaseData, public afxSpellBookDefs
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
bool do_id_convert;
|
||||||
|
|
||||||
|
public:
|
||||||
|
U8 spells_per_page;
|
||||||
|
U8 pages_per_book;
|
||||||
|
afxMagicSpellData* spells[MAX_PAGES_PER_BOOK*MAX_SPELLS_PER_PAGE];
|
||||||
|
afxRPGMagicSpellData* rpg_spells[MAX_PAGES_PER_BOOK*MAX_SPELLS_PER_PAGE];
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxSpellBookData();
|
||||||
|
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
bool verifyPageSlot(S32 page, S32 slot);
|
||||||
|
S32 getPageSlotIndex(S32 page, S32 slot);
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxSpellBookData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool afxSpellBookData::verifyPageSlot(S32 page, S32 slot)
|
||||||
|
{
|
||||||
|
return (page >= 0 && page < pages_per_book && slot >= 0 && slot < spells_per_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline S32 afxSpellBookData::getPageSlotIndex(S32 page, S32 slot)
|
||||||
|
{
|
||||||
|
return (verifyPageSlot(page, slot)) ? page*spells_per_page + slot : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class afxMagicSpellData;
|
||||||
|
class afxSpellButton;
|
||||||
|
|
||||||
|
class afxSpellBook : public GameBase, public afxSpellBookDefs
|
||||||
|
{
|
||||||
|
typedef GameBase Parent;
|
||||||
|
|
||||||
|
enum MaskBits
|
||||||
|
{
|
||||||
|
AllSpellCooldownMask = Parent::NextFreeMask << 0,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
afxSpellBookData* mDataBlock;
|
||||||
|
F32 all_spell_cooldown;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxSpellBook();
|
||||||
|
/*D*/ ~afxSpellBook();
|
||||||
|
|
||||||
|
virtual bool onNewDataBlock(GameBaseData* dptr, bool reload);
|
||||||
|
virtual void processTick(const Move*);
|
||||||
|
virtual void advanceTime(F32 dt);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
|
||||||
|
virtual U32 packUpdate(NetConnection*, U32, BitStream*);
|
||||||
|
virtual void unpackUpdate(NetConnection*, BitStream*);
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
S32 getPageSlotIndex(S32 page, S32 slot);
|
||||||
|
char* formatDesc(char* buffer, int len, S32 page, S32 slot) const;
|
||||||
|
const char* getSpellIcon(S32 page, S32 slot) const;
|
||||||
|
bool isPlaceholder(S32 page, S32 slot) const;
|
||||||
|
afxMagicSpellData* getSpellData(S32 page, S32 slot);
|
||||||
|
afxRPGMagicSpellData* getSpellRPGData(S32 page, S32 slot);
|
||||||
|
|
||||||
|
void startAllSpellCooldown();
|
||||||
|
F32 getCooldownFactor(S32 page, S32 slot);
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxSpellBook);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
inline S32 afxSpellBook::getPageSlotIndex(S32 page, S32 slot)
|
||||||
|
{
|
||||||
|
return (mDataBlock) ? mDataBlock->getPageSlotIndex(page, slot) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_SPELL_BOOK_H_
|
||||||
311
Engine/source/afx/afxZodiacGroundPlaneRenderer_T3D.cpp
Normal file
311
Engine/source/afx/afxZodiacGroundPlaneRenderer_T3D.cpp
Normal file
|
|
@ -0,0 +1,311 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "materials/shaderData.h"
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "collision/concretePolyList.h"
|
||||||
|
#include "T3D/tsStatic.h"
|
||||||
|
#include "gfx/primBuilder.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxZodiacMgr.h"
|
||||||
|
#include "afx/afxZodiacGroundPlaneRenderer_T3D.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
const RenderInstType afxZodiacGroundPlaneRenderer::RIT_GroundPlaneZodiac("GroundPlaneZodiac");
|
||||||
|
|
||||||
|
afxZodiacGroundPlaneRenderer* afxZodiacGroundPlaneRenderer::master = 0;
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT(afxZodiacGroundPlaneRenderer);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxZodiacGroundPlaneRenderer,
|
||||||
|
"@brief A render bin for zodiac rendering on GroundPlane objects.\n\n"
|
||||||
|
|
||||||
|
"This bin renders instances of AFX zodiac effects onto GroundPlane surfaces.\n\n"
|
||||||
|
|
||||||
|
"@ingroup RenderBin\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxZodiacGroundPlaneRenderer::afxZodiacGroundPlaneRenderer()
|
||||||
|
: RenderBinManager(RIT_GroundPlaneZodiac, 1.0f, 1.0f)
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = this;
|
||||||
|
shader_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacGroundPlaneRenderer::afxZodiacGroundPlaneRenderer(F32 renderOrder, F32 processAddOrder)
|
||||||
|
: RenderBinManager(RIT_GroundPlaneZodiac, renderOrder, processAddOrder)
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = this;
|
||||||
|
shader_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacGroundPlaneRenderer::~afxZodiacGroundPlaneRenderer()
|
||||||
|
{
|
||||||
|
if (this == master)
|
||||||
|
master = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxZodiacGroundPlaneRenderer::initShader()
|
||||||
|
{
|
||||||
|
if (shader_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
shader_initialized = true;
|
||||||
|
|
||||||
|
shader_consts = 0;
|
||||||
|
norm_norefl_zb_SB = norm_refl_zb_SB;
|
||||||
|
add_norefl_zb_SB = add_refl_zb_SB;
|
||||||
|
sub_norefl_zb_SB = sub_refl_zb_SB;
|
||||||
|
|
||||||
|
zodiac_shader = afxZodiacMgr::getGroundPlaneZodiacShader();
|
||||||
|
if (!zodiac_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GFXStateBlockDesc d;
|
||||||
|
|
||||||
|
d.cullDefined = true;
|
||||||
|
d.ffLighting = false;
|
||||||
|
d.blendDefined = true;
|
||||||
|
d.blendEnable = true;
|
||||||
|
d.zDefined = false;
|
||||||
|
d.zEnable = true;
|
||||||
|
d.zWriteEnable = false;
|
||||||
|
d.zFunc = GFXCmpLessEqual;
|
||||||
|
d.zSlopeBias = 0;
|
||||||
|
d.alphaDefined = true;
|
||||||
|
d.alphaTestEnable = true;
|
||||||
|
d.alphaTestRef = 0;
|
||||||
|
d.alphaTestFunc = GFXCmpGreater;
|
||||||
|
d.samplersDefined = true;
|
||||||
|
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
|
||||||
|
|
||||||
|
// normal
|
||||||
|
d.blendSrc = GFXBlendSrcAlpha;
|
||||||
|
d.blendDest = GFXBlendInvSrcAlpha;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
norm_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
norm_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
// additive
|
||||||
|
d.blendSrc = GFXBlendSrcAlpha;
|
||||||
|
d.blendDest = GFXBlendOne;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
add_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
add_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
// subtractive
|
||||||
|
d.blendSrc = GFXBlendZero;
|
||||||
|
d.blendDest = GFXBlendInvSrcColor;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
sub_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
sub_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
shader_consts = zodiac_shader->getShader()->allocConstBuffer();
|
||||||
|
projection_sc = zodiac_shader->getShader()->getShaderConstHandle("$modelView");
|
||||||
|
color_sc = zodiac_shader->getShader()->getShaderConstHandle("$zodiacColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacGroundPlaneRenderer::clear()
|
||||||
|
{
|
||||||
|
Parent::clear();
|
||||||
|
groundPlane_zodiacs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacGroundPlaneRenderer::addZodiac(U32 zode_idx, const Point3F& pos, F32 ang, const GroundPlane* gp, F32 camDist)
|
||||||
|
{
|
||||||
|
groundPlane_zodiacs.increment();
|
||||||
|
GroundPlaneZodiacElem& elem = groundPlane_zodiacs.last();
|
||||||
|
|
||||||
|
elem.gp = gp;
|
||||||
|
elem.zode_idx = zode_idx;
|
||||||
|
elem.ang = ang;
|
||||||
|
elem.camDist = camDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacGroundPlaneRenderer* afxZodiacGroundPlaneRenderer::getMaster()
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = new afxZodiacGroundPlaneRenderer;
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
GFXStateBlock* afxZodiacGroundPlaneRenderer::chooseStateBlock(U32 blend, bool isReflectPass)
|
||||||
|
{
|
||||||
|
GFXStateBlock* sb = 0;
|
||||||
|
|
||||||
|
switch (blend)
|
||||||
|
{
|
||||||
|
case afxZodiacData::BLEND_ADDITIVE:
|
||||||
|
sb = (isReflectPass) ? add_refl_zb_SB : add_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
case afxZodiacData::BLEND_SUBTRACTIVE:
|
||||||
|
sb = (isReflectPass) ? sub_refl_zb_SB : sub_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
default: // afxZodiacData::BLEND_NORMAL:
|
||||||
|
sb = (isReflectPass) ? norm_refl_zb_SB : norm_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacGroundPlaneRenderer::render(SceneRenderState* state)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(afxRenderZodiacGroundPlaneMgr_render);
|
||||||
|
|
||||||
|
// Early out if no ground-plane zodiacs to draw.
|
||||||
|
if (groundPlane_zodiacs.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
initShader();
|
||||||
|
if (!zodiac_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool is_reflect_pass = state->isReflectPass();
|
||||||
|
|
||||||
|
// Automagically save & restore our viewport and transforms.
|
||||||
|
GFXTransformSaver saver;
|
||||||
|
|
||||||
|
MatrixF proj = GFX->getProjectionMatrix();
|
||||||
|
|
||||||
|
// Set up world transform
|
||||||
|
MatrixF world = GFX->getWorldMatrix();
|
||||||
|
proj.mul(world);
|
||||||
|
shader_consts->set(projection_sc, proj);
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// RENDER EACH ZODIAC
|
||||||
|
//
|
||||||
|
for (S32 zz = 0; zz < groundPlane_zodiacs.size(); zz++)
|
||||||
|
{
|
||||||
|
GroundPlaneZodiacElem& elem = groundPlane_zodiacs[zz];
|
||||||
|
|
||||||
|
afxZodiacMgr::ZodiacSpec* zode = &afxZodiacMgr::terr_zodes[elem.zode_idx];
|
||||||
|
if (!zode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (is_reflect_pass)
|
||||||
|
{
|
||||||
|
//if ((zode->zflags & afxZodiacData::SHOW_IN_REFLECTIONS) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((zode->zflags & afxZodiacData::SHOW_IN_NON_REFLECTIONS) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 fadebias = zode->calcDistanceFadeBias(elem.camDist);
|
||||||
|
if (fadebias < 0.01f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
F32 cos_ang = mCos(elem.ang);
|
||||||
|
F32 sin_ang = mSin(elem.ang);
|
||||||
|
|
||||||
|
GFXStateBlock* sb = chooseStateBlock(zode->zflags & afxZodiacData::BLEND_MASK, is_reflect_pass);
|
||||||
|
|
||||||
|
GFX->setShader(zodiac_shader->getShader());
|
||||||
|
GFX->setStateBlock(sb);
|
||||||
|
GFX->setShaderConstBuffer(shader_consts);
|
||||||
|
|
||||||
|
// set the texture
|
||||||
|
GFX->setTexture(0, *zode->txr);
|
||||||
|
LinearColorF zode_color = (LinearColorF)zode->color;
|
||||||
|
zode_color.alpha *= fadebias;
|
||||||
|
shader_consts->set(color_sc, zode_color);
|
||||||
|
|
||||||
|
F32 rad_xy = zode->radius_xy;
|
||||||
|
F32 inv_radius = 1.0f/rad_xy;
|
||||||
|
F32 offset_xy = mSqrt(2*rad_xy*rad_xy);
|
||||||
|
|
||||||
|
F32 zx = zode->pos.x;
|
||||||
|
F32 zy = zode->pos.y;
|
||||||
|
F32 z = 0.00001f;
|
||||||
|
|
||||||
|
Point3F verts[4];
|
||||||
|
verts[0].set(zx+offset_xy, zy+offset_xy, z);
|
||||||
|
verts[1].set(zx-offset_xy, zy+offset_xy, z);
|
||||||
|
verts[2].set(zx-offset_xy, zy-offset_xy, z);
|
||||||
|
verts[3].set(zx+offset_xy, zy-offset_xy, z);
|
||||||
|
|
||||||
|
S32 vertind[6];
|
||||||
|
vertind[0] = 2;
|
||||||
|
vertind[1] = 1;
|
||||||
|
vertind[2] = 0;
|
||||||
|
vertind[3] = 3;
|
||||||
|
vertind[4] = 2;
|
||||||
|
vertind[5] = 0;
|
||||||
|
|
||||||
|
PrimBuild::begin(GFXTriangleList, 6);
|
||||||
|
for (U32 i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
for (U32 j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
const Point3F& vtx = verts[vertind[i*3+j]];
|
||||||
|
|
||||||
|
// compute UV
|
||||||
|
F32 u1 = (vtx.x - zode->pos.x)*inv_radius;
|
||||||
|
F32 v1 = (vtx.y - zode->pos.y)*inv_radius;
|
||||||
|
F32 ru1 = u1*cos_ang - v1*sin_ang;
|
||||||
|
F32 rv1 = u1*sin_ang + v1*cos_ang;
|
||||||
|
|
||||||
|
F32 uu = (ru1 + 1.0f)/2.0f;
|
||||||
|
F32 vv = 1.0f - (rv1 + 1.0f)/2.0f;
|
||||||
|
|
||||||
|
PrimBuild::texCoord2f(uu, vv);
|
||||||
|
PrimBuild::vertex3fv(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrimBuild::end(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
91
Engine/source/afx/afxZodiacGroundPlaneRenderer_T3D.h
Normal file
91
Engine/source/afx/afxZodiacGroundPlaneRenderer_T3D.h
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_ZODIAC_GROUNDPLANE_RENDERER_H_
|
||||||
|
#define _AFX_ZODIAC_GROUNDPLANE_RENDERER_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "renderInstance/renderBinManager.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class ConcretePolyList;
|
||||||
|
class GroundPlane;
|
||||||
|
|
||||||
|
class afxZodiacGroundPlaneRenderer : public RenderBinManager
|
||||||
|
{
|
||||||
|
typedef RenderBinManager Parent;
|
||||||
|
|
||||||
|
struct GroundPlaneZodiacElem
|
||||||
|
{
|
||||||
|
const GroundPlane* gp;
|
||||||
|
U32 zode_idx;
|
||||||
|
F32 ang;
|
||||||
|
F32 camDist;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<GroundPlaneZodiacElem> groundPlane_zodiacs;
|
||||||
|
static afxZodiacGroundPlaneRenderer* master;
|
||||||
|
|
||||||
|
GFXStateBlockRef norm_norefl_zb_SB, norm_refl_zb_SB;
|
||||||
|
GFXStateBlockRef add_norefl_zb_SB, add_refl_zb_SB;
|
||||||
|
GFXStateBlockRef sub_norefl_zb_SB, sub_refl_zb_SB;
|
||||||
|
|
||||||
|
ShaderData* zodiac_shader;
|
||||||
|
GFXShaderConstBufferRef shader_consts;
|
||||||
|
GFXShaderConstHandle* projection_sc;
|
||||||
|
GFXShaderConstHandle* color_sc;
|
||||||
|
|
||||||
|
bool shader_initialized;
|
||||||
|
|
||||||
|
GFXStateBlock* chooseStateBlock(U32 blend, bool isReflectPass);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const RenderInstType RIT_GroundPlaneZodiac;
|
||||||
|
|
||||||
|
/*C*/ afxZodiacGroundPlaneRenderer();
|
||||||
|
/*C*/ afxZodiacGroundPlaneRenderer(F32 renderOrder, F32 processAddOrder);
|
||||||
|
/*D*/ ~afxZodiacGroundPlaneRenderer();
|
||||||
|
|
||||||
|
// RenderBinManager
|
||||||
|
virtual void sort(){} // don't sort them
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
|
void initShader();
|
||||||
|
void addZodiac(U32 zode_idx, const Point3F& pos, F32 ang, const GroundPlane*, F32 camDist);
|
||||||
|
|
||||||
|
virtual void render(SceneRenderState* state);
|
||||||
|
|
||||||
|
static afxZodiacGroundPlaneRenderer* getMaster();
|
||||||
|
|
||||||
|
// ConsoleObject
|
||||||
|
DECLARE_CONOBJECT(afxZodiacGroundPlaneRenderer);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_ZODIAC_GROUNDPLANE_RENDERER_H_
|
||||||
302
Engine/source/afx/afxZodiacMeshRoadRenderer_T3D.cpp
Normal file
302
Engine/source/afx/afxZodiacMeshRoadRenderer_T3D.cpp
Normal file
|
|
@ -0,0 +1,302 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "materials/shaderData.h"
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "collision/concretePolyList.h"
|
||||||
|
#include "T3D/tsStatic.h"
|
||||||
|
#include "gfx/primBuilder.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxZodiacMgr.h"
|
||||||
|
#include "afx/afxZodiacMeshRoadRenderer_T3D.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
const RenderInstType afxZodiacMeshRoadRenderer::RIT_MeshRoadZodiac("MeshRoadZodiac");
|
||||||
|
|
||||||
|
afxZodiacMeshRoadRenderer* afxZodiacMeshRoadRenderer::master = 0;
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT(afxZodiacMeshRoadRenderer);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxZodiacMeshRoadRenderer,
|
||||||
|
"@brief A render bin for zodiac rendering on MeshRoad objects.\n\n"
|
||||||
|
|
||||||
|
"This bin renders instances of AFX zodiac effects onto MeshRoad surfaces.\n\n"
|
||||||
|
|
||||||
|
"@ingroup RenderBin\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxZodiacMeshRoadRenderer::afxZodiacMeshRoadRenderer()
|
||||||
|
: RenderBinManager(RIT_MeshRoadZodiac, 1.0f, 1.0f)
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = this;
|
||||||
|
shader_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacMeshRoadRenderer::afxZodiacMeshRoadRenderer(F32 renderOrder, F32 processAddOrder)
|
||||||
|
: RenderBinManager(RIT_MeshRoadZodiac, renderOrder, processAddOrder)
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = this;
|
||||||
|
shader_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacMeshRoadRenderer::~afxZodiacMeshRoadRenderer()
|
||||||
|
{
|
||||||
|
if (this == master)
|
||||||
|
master = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxZodiacMeshRoadRenderer::initShader()
|
||||||
|
{
|
||||||
|
if (shader_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
shader_initialized = true;
|
||||||
|
|
||||||
|
shader_consts = 0;
|
||||||
|
norm_norefl_zb_SB = norm_refl_zb_SB;
|
||||||
|
add_norefl_zb_SB = add_refl_zb_SB;
|
||||||
|
sub_norefl_zb_SB = sub_refl_zb_SB;
|
||||||
|
|
||||||
|
zodiac_shader = afxZodiacMgr::getMeshRoadZodiacShader();
|
||||||
|
if (!zodiac_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GFXStateBlockDesc d;
|
||||||
|
|
||||||
|
d.cullDefined = true;
|
||||||
|
d.ffLighting = false;
|
||||||
|
d.blendDefined = true;
|
||||||
|
d.blendEnable = true;
|
||||||
|
d.zDefined = false;
|
||||||
|
d.zEnable = true;
|
||||||
|
d.zWriteEnable = false;
|
||||||
|
d.zFunc = GFXCmpLessEqual;
|
||||||
|
d.zSlopeBias = 0;
|
||||||
|
d.alphaDefined = true;
|
||||||
|
d.alphaTestEnable = true;
|
||||||
|
d.alphaTestRef = 0;
|
||||||
|
d.alphaTestFunc = GFXCmpGreater;
|
||||||
|
d.samplersDefined = true;
|
||||||
|
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
|
||||||
|
|
||||||
|
// normal
|
||||||
|
d.blendSrc = GFXBlendSrcAlpha;
|
||||||
|
d.blendDest = GFXBlendInvSrcAlpha;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
norm_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
norm_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
// additive
|
||||||
|
d.blendSrc = GFXBlendSrcAlpha;
|
||||||
|
d.blendDest = GFXBlendOne;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
add_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
add_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
// subtractive
|
||||||
|
d.blendSrc = GFXBlendZero;
|
||||||
|
d.blendDest = GFXBlendInvSrcColor;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
sub_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
sub_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
shader_consts = zodiac_shader->getShader()->allocConstBuffer();
|
||||||
|
projection_sc = zodiac_shader->getShader()->getShaderConstHandle("$modelView");
|
||||||
|
color_sc = zodiac_shader->getShader()->getShaderConstHandle("$zodiacColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacMeshRoadRenderer::clear()
|
||||||
|
{
|
||||||
|
Parent::clear();
|
||||||
|
for (S32 i = 0; i < meshRoad_zodiacs.size(); i++)
|
||||||
|
if (meshRoad_zodiacs[i].polys)
|
||||||
|
delete meshRoad_zodiacs[i].polys;
|
||||||
|
meshRoad_zodiacs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacMeshRoadRenderer::addZodiac(U32 zode_idx, ConcretePolyList* polys, const Point3F& pos, F32 ang, const MeshRoad* road, F32 camDist)
|
||||||
|
{
|
||||||
|
meshRoad_zodiacs.increment();
|
||||||
|
MeshRoadZodiacElem& elem = meshRoad_zodiacs.last();
|
||||||
|
|
||||||
|
elem.road = road;
|
||||||
|
elem.polys = polys;
|
||||||
|
elem.zode_idx = zode_idx;
|
||||||
|
elem.ang = ang;
|
||||||
|
elem.camDist = camDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacMeshRoadRenderer* afxZodiacMeshRoadRenderer::getMaster()
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = new afxZodiacMeshRoadRenderer;
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
GFXStateBlock* afxZodiacMeshRoadRenderer::chooseStateBlock(U32 blend, bool isReflectPass)
|
||||||
|
{
|
||||||
|
GFXStateBlock* sb = 0;
|
||||||
|
|
||||||
|
switch (blend)
|
||||||
|
{
|
||||||
|
case afxZodiacData::BLEND_ADDITIVE:
|
||||||
|
sb = (isReflectPass) ? add_refl_zb_SB : add_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
case afxZodiacData::BLEND_SUBTRACTIVE:
|
||||||
|
sb = (isReflectPass) ? sub_refl_zb_SB : sub_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
default: // afxZodiacData::BLEND_NORMAL:
|
||||||
|
sb = (isReflectPass) ? norm_refl_zb_SB : norm_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacMeshRoadRenderer::render(SceneRenderState* state)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(afxRenderZodiacMeshRoadMgr_render);
|
||||||
|
|
||||||
|
// Early out if no ground-plane zodiacs to draw.
|
||||||
|
if (meshRoad_zodiacs.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
initShader();
|
||||||
|
if (!zodiac_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool is_reflect_pass = state->isReflectPass();
|
||||||
|
|
||||||
|
// Automagically save & restore our viewport and transforms.
|
||||||
|
GFXTransformSaver saver;
|
||||||
|
|
||||||
|
MatrixF proj = GFX->getProjectionMatrix();
|
||||||
|
|
||||||
|
// Set up world transform
|
||||||
|
MatrixF world = GFX->getWorldMatrix();
|
||||||
|
proj.mul(world);
|
||||||
|
shader_consts->set(projection_sc, proj);
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// RENDER EACH ZODIAC
|
||||||
|
//
|
||||||
|
for (S32 zz = 0; zz < meshRoad_zodiacs.size(); zz++)
|
||||||
|
{
|
||||||
|
MeshRoadZodiacElem& elem = meshRoad_zodiacs[zz];
|
||||||
|
|
||||||
|
afxZodiacMgr::ZodiacSpec* zode = &afxZodiacMgr::terr_zodes[elem.zode_idx];
|
||||||
|
if (!zode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (is_reflect_pass)
|
||||||
|
{
|
||||||
|
if ((zode->zflags & afxZodiacData::SHOW_IN_REFLECTIONS) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((zode->zflags & afxZodiacData::SHOW_IN_NON_REFLECTIONS) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 fadebias = zode->calcDistanceFadeBias(elem.camDist);
|
||||||
|
if (fadebias < 0.01f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
F32 cos_ang = mCos(elem.ang);
|
||||||
|
F32 sin_ang = mSin(elem.ang);
|
||||||
|
|
||||||
|
GFXStateBlock* sb = chooseStateBlock(zode->zflags & afxZodiacData::BLEND_MASK, is_reflect_pass);
|
||||||
|
|
||||||
|
GFX->setShader(zodiac_shader->getShader());
|
||||||
|
GFX->setStateBlock(sb);
|
||||||
|
GFX->setShaderConstBuffer(shader_consts);
|
||||||
|
|
||||||
|
// set the texture
|
||||||
|
GFX->setTexture(0, *zode->txr);
|
||||||
|
LinearColorF zode_color = (LinearColorF)zode->color;
|
||||||
|
zode_color.alpha *= fadebias;
|
||||||
|
shader_consts->set(color_sc, zode_color);
|
||||||
|
|
||||||
|
F32 inv_radius = 1.0f/zode->radius_xy;
|
||||||
|
|
||||||
|
PrimBuild::begin(GFXTriangleList, 3*elem.polys->mPolyList.size());
|
||||||
|
for (U32 i = 0; i < elem.polys->mPolyList.size(); i++)
|
||||||
|
{
|
||||||
|
ConcretePolyList::Poly* poly = &elem.polys->mPolyList[i];
|
||||||
|
|
||||||
|
S32 vertind[3];
|
||||||
|
vertind[0] = elem.polys->mIndexList[poly->vertexStart];
|
||||||
|
vertind[1] = elem.polys->mIndexList[poly->vertexStart + 1];
|
||||||
|
vertind[2] = elem.polys->mIndexList[poly->vertexStart + 2];
|
||||||
|
|
||||||
|
for (U32 j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
Point3F vtx = elem.polys->mVertexList[vertind[j]];
|
||||||
|
|
||||||
|
// compute UV
|
||||||
|
F32 u1 = (vtx.x - zode->pos.x)*inv_radius;
|
||||||
|
F32 v1 = (vtx.y - zode->pos.y)*inv_radius;
|
||||||
|
F32 ru1 = u1*cos_ang - v1*sin_ang;
|
||||||
|
F32 rv1 = u1*sin_ang + v1*cos_ang;
|
||||||
|
|
||||||
|
F32 uu = (ru1 + 1.0f)/2.0f;
|
||||||
|
F32 vv = 1.0f - (rv1 + 1.0f)/2.0f;
|
||||||
|
|
||||||
|
PrimBuild::texCoord2f(uu, vv);
|
||||||
|
PrimBuild::vertex3fv(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrimBuild::end(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
92
Engine/source/afx/afxZodiacMeshRoadRenderer_T3D.h
Normal file
92
Engine/source/afx/afxZodiacMeshRoadRenderer_T3D.h
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_ZODIAC_MESHROAD_RENDERER_H_
|
||||||
|
#define _AFX_ZODIAC_MESHROAD_RENDERER_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "renderInstance/renderBinManager.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class ConcretePolyList;
|
||||||
|
class MeshRoad;
|
||||||
|
|
||||||
|
class afxZodiacMeshRoadRenderer : public RenderBinManager
|
||||||
|
{
|
||||||
|
typedef RenderBinManager Parent;
|
||||||
|
|
||||||
|
struct MeshRoadZodiacElem
|
||||||
|
{
|
||||||
|
const MeshRoad* road;
|
||||||
|
U32 zode_idx;
|
||||||
|
ConcretePolyList* polys;
|
||||||
|
F32 ang;
|
||||||
|
F32 camDist;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<MeshRoadZodiacElem> meshRoad_zodiacs;
|
||||||
|
static afxZodiacMeshRoadRenderer* master;
|
||||||
|
|
||||||
|
GFXStateBlockRef norm_norefl_zb_SB, norm_refl_zb_SB;
|
||||||
|
GFXStateBlockRef add_norefl_zb_SB, add_refl_zb_SB;
|
||||||
|
GFXStateBlockRef sub_norefl_zb_SB, sub_refl_zb_SB;
|
||||||
|
|
||||||
|
ShaderData* zodiac_shader;
|
||||||
|
GFXShaderConstBufferRef shader_consts;
|
||||||
|
GFXShaderConstHandle* projection_sc;
|
||||||
|
GFXShaderConstHandle* color_sc;
|
||||||
|
|
||||||
|
bool shader_initialized;
|
||||||
|
|
||||||
|
GFXStateBlock* chooseStateBlock(U32 blend, bool isReflectPass);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const RenderInstType RIT_MeshRoadZodiac;
|
||||||
|
|
||||||
|
/*C*/ afxZodiacMeshRoadRenderer();
|
||||||
|
/*C*/ afxZodiacMeshRoadRenderer(F32 renderOrder, F32 processAddOrder);
|
||||||
|
/*D*/ ~afxZodiacMeshRoadRenderer();
|
||||||
|
|
||||||
|
// RenderBinManager
|
||||||
|
virtual void sort(){} // don't sort them
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
|
void initShader();
|
||||||
|
void addZodiac(U32 zode_idx, ConcretePolyList*, const Point3F& pos, F32 ang, const MeshRoad*, F32 camDist);
|
||||||
|
|
||||||
|
virtual void render(SceneRenderState*);
|
||||||
|
|
||||||
|
static afxZodiacMeshRoadRenderer* getMaster();
|
||||||
|
|
||||||
|
// ConsoleObject
|
||||||
|
DECLARE_CONOBJECT(afxZodiacMeshRoadRenderer);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_ZODIAC_MESHROAD_RENDERER_H_
|
||||||
420
Engine/source/afx/afxZodiacPolysoupRenderer_T3D.cpp
Normal file
420
Engine/source/afx/afxZodiacPolysoupRenderer_T3D.cpp
Normal file
|
|
@ -0,0 +1,420 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "materials/shaderData.h"
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "collision/concretePolyList.h"
|
||||||
|
#include "T3D/tsStatic.h"
|
||||||
|
#include "gfx/primBuilder.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxZodiacMgr.h"
|
||||||
|
#include "afx/afxZodiacPolysoupRenderer_T3D.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
const RenderInstType afxZodiacPolysoupRenderer::RIT_PolysoupZodiac("PolysoupZodiac");
|
||||||
|
|
||||||
|
afxZodiacPolysoupRenderer* afxZodiacPolysoupRenderer::master = 0;
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT(afxZodiacPolysoupRenderer);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxZodiacPolysoupRenderer,
|
||||||
|
"@brief A render bin for zodiac rendering on polysoup TSStatic objects.\n\n"
|
||||||
|
|
||||||
|
"This bin renders instances of AFX zodiac effects onto polysoup TSStatic surfaces.\n\n"
|
||||||
|
|
||||||
|
"@ingroup RenderBin\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxZodiacPolysoupRenderer::afxZodiacPolysoupRenderer()
|
||||||
|
: RenderBinManager(RIT_PolysoupZodiac, 1.0f, 1.0f)
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = this;
|
||||||
|
shader_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacPolysoupRenderer::afxZodiacPolysoupRenderer(F32 renderOrder, F32 processAddOrder)
|
||||||
|
: RenderBinManager(RIT_PolysoupZodiac, renderOrder, processAddOrder)
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = this;
|
||||||
|
shader_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacPolysoupRenderer::~afxZodiacPolysoupRenderer()
|
||||||
|
{
|
||||||
|
if (this == master)
|
||||||
|
master = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxZodiacPolysoupRenderer::initShader()
|
||||||
|
{
|
||||||
|
if (shader_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
shader_initialized = true;
|
||||||
|
|
||||||
|
shader_consts = 0;
|
||||||
|
norm_norefl_zb_SB = norm_refl_zb_SB;
|
||||||
|
add_norefl_zb_SB = add_refl_zb_SB;
|
||||||
|
sub_norefl_zb_SB = sub_refl_zb_SB;
|
||||||
|
|
||||||
|
zodiac_shader = afxZodiacMgr::getPolysoupZodiacShader();
|
||||||
|
if (!zodiac_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GFXStateBlockDesc d;
|
||||||
|
|
||||||
|
d.cullDefined = true;
|
||||||
|
d.ffLighting = false;
|
||||||
|
d.blendDefined = true;
|
||||||
|
d.blendEnable = true;
|
||||||
|
d.zDefined = false;
|
||||||
|
d.zEnable = true;
|
||||||
|
d.zWriteEnable = false;
|
||||||
|
d.zFunc = GFXCmpLessEqual;
|
||||||
|
d.zSlopeBias = 0;
|
||||||
|
d.alphaDefined = true;
|
||||||
|
d.alphaTestEnable = true;
|
||||||
|
d.alphaTestRef = 0;
|
||||||
|
d.alphaTestFunc = GFXCmpGreater;
|
||||||
|
d.samplersDefined = true;
|
||||||
|
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
|
||||||
|
|
||||||
|
// normal
|
||||||
|
d.blendSrc = GFXBlendSrcAlpha;
|
||||||
|
d.blendDest = GFXBlendInvSrcAlpha;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
norm_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
norm_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
// additive
|
||||||
|
d.blendSrc = GFXBlendSrcAlpha;
|
||||||
|
d.blendDest = GFXBlendOne;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
add_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
add_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
// subtractive
|
||||||
|
d.blendSrc = GFXBlendZero;
|
||||||
|
d.blendDest = GFXBlendInvSrcColor;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
sub_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sPolysoupZodiacZBias;
|
||||||
|
sub_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
shader_consts = zodiac_shader->getShader()->allocConstBuffer();
|
||||||
|
projection_sc = zodiac_shader->getShader()->getShaderConstHandle("$modelView");
|
||||||
|
color_sc = zodiac_shader->getShader()->getShaderConstHandle("$zodiacColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacPolysoupRenderer::clear()
|
||||||
|
{
|
||||||
|
Parent::clear();
|
||||||
|
for (S32 i = 0; i < polysoup_zodes.size(); i++)
|
||||||
|
if (polysoup_zodes[i].polys)
|
||||||
|
delete polysoup_zodes[i].polys;
|
||||||
|
polysoup_zodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacPolysoupRenderer::addZodiac(U32 zode_idx, ConcretePolyList* polys, const Point3F& pos, F32 ang, const TSStatic* tss, F32 camDist)
|
||||||
|
{
|
||||||
|
polysoup_zodes.increment();
|
||||||
|
PolysoupZodiacElem& elem = polysoup_zodes.last();
|
||||||
|
|
||||||
|
elem.tss = tss;
|
||||||
|
elem.polys = polys;
|
||||||
|
elem.zode_idx = zode_idx;
|
||||||
|
elem.ang = ang;
|
||||||
|
elem.camDist = camDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacPolysoupRenderer* afxZodiacPolysoupRenderer::getMaster()
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = new afxZodiacPolysoupRenderer;
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
GFXStateBlock* afxZodiacPolysoupRenderer::chooseStateBlock(U32 blend, bool isReflectPass)
|
||||||
|
{
|
||||||
|
GFXStateBlock* sb = 0;
|
||||||
|
|
||||||
|
switch (blend)
|
||||||
|
{
|
||||||
|
case afxZodiacData::BLEND_ADDITIVE:
|
||||||
|
sb = (isReflectPass) ? add_refl_zb_SB : add_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
case afxZodiacData::BLEND_SUBTRACTIVE:
|
||||||
|
sb = (isReflectPass) ? sub_refl_zb_SB : sub_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
default: // afxZodiacData::BLEND_NORMAL:
|
||||||
|
sb = (isReflectPass) ? norm_refl_zb_SB : norm_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacPolysoupRenderer::render(SceneRenderState* state)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(afxRenderZodiacPolysoupMgr_render);
|
||||||
|
|
||||||
|
// Early out if no polysoup zodiacs to draw.
|
||||||
|
if (polysoup_zodes.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
initShader();
|
||||||
|
if (!zodiac_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool is_reflect_pass = state->isReflectPass();
|
||||||
|
|
||||||
|
// Automagically save & restore our viewport and transforms.
|
||||||
|
GFXTransformSaver saver;
|
||||||
|
|
||||||
|
MatrixF proj = GFX->getProjectionMatrix();
|
||||||
|
|
||||||
|
// Set up world transform
|
||||||
|
MatrixF world = GFX->getWorldMatrix();
|
||||||
|
proj.mul(world);
|
||||||
|
shader_consts->set(projection_sc, proj);
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// RENDER EACH ZODIAC
|
||||||
|
//
|
||||||
|
for (S32 zz = 0; zz < polysoup_zodes.size(); zz++)
|
||||||
|
{
|
||||||
|
PolysoupZodiacElem& elem = polysoup_zodes[zz];
|
||||||
|
|
||||||
|
afxZodiacMgr::ZodiacSpec* zode = &afxZodiacMgr::inter_zodes[elem.zode_idx];
|
||||||
|
if (!zode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (is_reflect_pass)
|
||||||
|
{
|
||||||
|
if ((zode->zflags & afxZodiacData::SHOW_IN_REFLECTIONS) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((zode->zflags & afxZodiacData::SHOW_IN_NON_REFLECTIONS) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 fadebias = zode->calcDistanceFadeBias(elem.camDist);
|
||||||
|
if (fadebias < 0.01f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
F32 cos_ang = mCos(elem.ang);
|
||||||
|
F32 sin_ang = mSin(elem.ang);
|
||||||
|
|
||||||
|
GFXStateBlock* sb = chooseStateBlock(zode->zflags & afxZodiacData::BLEND_MASK, is_reflect_pass);
|
||||||
|
|
||||||
|
GFX->setShader(zodiac_shader->getShader());
|
||||||
|
GFX->setStateBlock(sb);
|
||||||
|
GFX->setShaderConstBuffer(shader_consts);
|
||||||
|
|
||||||
|
// set the texture
|
||||||
|
GFX->setTexture(0, *zode->txr);
|
||||||
|
LinearColorF zode_color = (LinearColorF)zode->color;
|
||||||
|
zode_color.alpha *= fadebias;
|
||||||
|
shader_consts->set(color_sc, zode_color);
|
||||||
|
|
||||||
|
F32 inv_radius = 1.0f/zode->radius_xy;
|
||||||
|
|
||||||
|
// FILTER USING GRADIENT RANGE
|
||||||
|
if ((zode->zflags & afxZodiacData::USE_GRADE_RANGE) != 0)
|
||||||
|
{
|
||||||
|
bool skip_oob;
|
||||||
|
F32 grade_min, grade_max;
|
||||||
|
if (elem.tss->mHasGradients && ((zode->zflags & afxZodiacData::PREFER_DEST_GRADE) != 0))
|
||||||
|
{
|
||||||
|
skip_oob = (elem.tss->mInvertGradientRange == false);
|
||||||
|
grade_min = elem.tss->mGradientRange.x;
|
||||||
|
grade_max = elem.tss->mGradientRange.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skip_oob = ((zode->zflags & afxZodiacData::INVERT_GRADE_RANGE) == 0);
|
||||||
|
grade_min = zode->grade_range.x;
|
||||||
|
grade_max = zode->grade_range.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimBuild::begin(GFXTriangleList, 3*elem.polys->mPolyList.size());
|
||||||
|
for (U32 i = 0; i < elem.polys->mPolyList.size(); i++)
|
||||||
|
{
|
||||||
|
ConcretePolyList::Poly* poly = &elem.polys->mPolyList[i];
|
||||||
|
|
||||||
|
const PlaneF& plane = poly->plane;
|
||||||
|
|
||||||
|
bool oob = (plane.z > grade_max || plane.z < grade_min);
|
||||||
|
if (oob == skip_oob)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
S32 vertind[3];
|
||||||
|
vertind[0] = elem.polys->mIndexList[poly->vertexStart];
|
||||||
|
vertind[1] = elem.polys->mIndexList[poly->vertexStart + 1];
|
||||||
|
vertind[2] = elem.polys->mIndexList[poly->vertexStart + 2];
|
||||||
|
|
||||||
|
for (U32 j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
Point3F vtx = elem.polys->mVertexList[vertind[j]];
|
||||||
|
|
||||||
|
// compute UV
|
||||||
|
F32 u1 = (vtx.x - zode->pos.x)*inv_radius;
|
||||||
|
F32 v1 = (vtx.y - zode->pos.y)*inv_radius;
|
||||||
|
F32 ru1 = u1*cos_ang - v1*sin_ang;
|
||||||
|
F32 rv1 = u1*sin_ang + v1*cos_ang;
|
||||||
|
|
||||||
|
F32 uu = (ru1 + 1.0f)/2.0f;
|
||||||
|
F32 vv = 1.0f - (rv1 + 1.0f)/2.0f;
|
||||||
|
|
||||||
|
PrimBuild::texCoord2f(uu, vv);
|
||||||
|
PrimBuild::vertex3fv(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrimBuild::end(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILTER USING OTHER FILTERS
|
||||||
|
else if (zode->zflags & afxZodiacData::INTERIOR_FILTERS)
|
||||||
|
{
|
||||||
|
PrimBuild::begin(GFXTriangleList, 3*elem.polys->mPolyList.size());
|
||||||
|
for (U32 i = 0; i < elem.polys->mPolyList.size(); i++)
|
||||||
|
{
|
||||||
|
ConcretePolyList::Poly* poly = &elem.polys->mPolyList[i];
|
||||||
|
|
||||||
|
const PlaneF& plane = poly->plane;
|
||||||
|
if (zode->zflags & afxZodiacData::INTERIOR_HORIZ_ONLY)
|
||||||
|
{
|
||||||
|
if (!plane.isHorizontal())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (zode->zflags & afxZodiacData::INTERIOR_BACK_IGNORE)
|
||||||
|
{
|
||||||
|
if (plane.whichSide(zode->pos) == PlaneF::Back)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (zode->zflags & afxZodiacData::INTERIOR_VERT_IGNORE)
|
||||||
|
{
|
||||||
|
if (plane.isVertical())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zode->zflags & afxZodiacData::INTERIOR_BACK_IGNORE)
|
||||||
|
{
|
||||||
|
if (plane.whichSide(zode->pos) == PlaneF::Back)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 vertind[3];
|
||||||
|
vertind[0] = elem.polys->mIndexList[poly->vertexStart];
|
||||||
|
vertind[1] = elem.polys->mIndexList[poly->vertexStart + 1];
|
||||||
|
vertind[2] = elem.polys->mIndexList[poly->vertexStart + 2];
|
||||||
|
|
||||||
|
for (U32 j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
Point3F vtx = elem.polys->mVertexList[vertind[j]];
|
||||||
|
|
||||||
|
// compute UV
|
||||||
|
F32 u1 = (vtx.x - zode->pos.x)*inv_radius;
|
||||||
|
F32 v1 = (vtx.y - zode->pos.y)*inv_radius;
|
||||||
|
F32 ru1 = u1*cos_ang - v1*sin_ang;
|
||||||
|
F32 rv1 = u1*sin_ang + v1*cos_ang;
|
||||||
|
|
||||||
|
F32 uu = (ru1 + 1.0f)/2.0f;
|
||||||
|
F32 vv = 1.0f - (rv1 + 1.0f)/2.0f;
|
||||||
|
|
||||||
|
PrimBuild::texCoord2f(uu, vv);
|
||||||
|
PrimBuild::vertex3fv(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrimBuild::end(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NO FILTERING
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrimBuild::begin(GFXTriangleList, 3*elem.polys->mPolyList.size());
|
||||||
|
for (U32 i = 0; i < elem.polys->mPolyList.size(); i++)
|
||||||
|
{
|
||||||
|
ConcretePolyList::Poly* poly = &elem.polys->mPolyList[i];
|
||||||
|
|
||||||
|
S32 vertind[3];
|
||||||
|
vertind[0] = elem.polys->mIndexList[poly->vertexStart];
|
||||||
|
vertind[1] = elem.polys->mIndexList[poly->vertexStart + 1];
|
||||||
|
vertind[2] = elem.polys->mIndexList[poly->vertexStart + 2];
|
||||||
|
|
||||||
|
for (U32 j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
Point3F vtx = elem.polys->mVertexList[vertind[j]];
|
||||||
|
|
||||||
|
// compute UV
|
||||||
|
F32 u1 = (vtx.x - zode->pos.x)*inv_radius;
|
||||||
|
F32 v1 = (vtx.y - zode->pos.y)*inv_radius;
|
||||||
|
F32 ru1 = u1*cos_ang - v1*sin_ang;
|
||||||
|
F32 rv1 = u1*sin_ang + v1*cos_ang;
|
||||||
|
|
||||||
|
F32 uu = (ru1 + 1.0f)/2.0f;
|
||||||
|
F32 vv = 1.0f - (rv1 + 1.0f)/2.0f;
|
||||||
|
|
||||||
|
PrimBuild::texCoord2f(uu, vv);
|
||||||
|
PrimBuild::vertex3fv(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrimBuild::end(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
92
Engine/source/afx/afxZodiacPolysoupRenderer_T3D.h
Normal file
92
Engine/source/afx/afxZodiacPolysoupRenderer_T3D.h
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_ZODIAC_POLYSOUP_RENDERER_H_
|
||||||
|
#define _AFX_ZODIAC_POLYSOUP_RENDERER_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "renderInstance/renderBinManager.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class ConcretePolyList;
|
||||||
|
class TSStatic;
|
||||||
|
|
||||||
|
class afxZodiacPolysoupRenderer : public RenderBinManager
|
||||||
|
{
|
||||||
|
typedef RenderBinManager Parent;
|
||||||
|
|
||||||
|
struct PolysoupZodiacElem
|
||||||
|
{
|
||||||
|
const TSStatic* tss;
|
||||||
|
U32 zode_idx;
|
||||||
|
ConcretePolyList* polys;
|
||||||
|
F32 ang;
|
||||||
|
F32 camDist;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<PolysoupZodiacElem> polysoup_zodes;
|
||||||
|
static afxZodiacPolysoupRenderer* master;
|
||||||
|
|
||||||
|
GFXStateBlockRef norm_norefl_zb_SB, norm_refl_zb_SB;
|
||||||
|
GFXStateBlockRef add_norefl_zb_SB, add_refl_zb_SB;
|
||||||
|
GFXStateBlockRef sub_norefl_zb_SB, sub_refl_zb_SB;
|
||||||
|
|
||||||
|
ShaderData* zodiac_shader;
|
||||||
|
GFXShaderConstBufferRef shader_consts;
|
||||||
|
GFXShaderConstHandle* projection_sc;
|
||||||
|
GFXShaderConstHandle* color_sc;
|
||||||
|
|
||||||
|
bool shader_initialized;
|
||||||
|
|
||||||
|
GFXStateBlock* chooseStateBlock(U32 blend, bool isReflectPass);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const RenderInstType RIT_PolysoupZodiac;
|
||||||
|
|
||||||
|
/*C*/ afxZodiacPolysoupRenderer();
|
||||||
|
/*C*/ afxZodiacPolysoupRenderer(F32 renderOrder, F32 processAddOrder);
|
||||||
|
/*D*/ ~afxZodiacPolysoupRenderer();
|
||||||
|
|
||||||
|
// RenderBinManager
|
||||||
|
virtual void sort(){} // don't sort them
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
|
void initShader();
|
||||||
|
void addZodiac(U32 zode_idx, ConcretePolyList*, const Point3F& pos, F32 ang, const TSStatic*, F32 camDist);
|
||||||
|
|
||||||
|
virtual void render(SceneRenderState*);
|
||||||
|
|
||||||
|
static afxZodiacPolysoupRenderer* getMaster();
|
||||||
|
|
||||||
|
// ConsoleObject
|
||||||
|
DECLARE_CONOBJECT(afxZodiacPolysoupRenderer);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_ZODIAC_POLYSOUP_RENDERER_H_
|
||||||
344
Engine/source/afx/afxZodiacTerrainRenderer_T3D.cpp
Normal file
344
Engine/source/afx/afxZodiacTerrainRenderer_T3D.cpp
Normal file
|
|
@ -0,0 +1,344 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "materials/shaderData.h"
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "terrain/terrData.h"
|
||||||
|
#include "terrain/terrCell.h"
|
||||||
|
|
||||||
|
#include "gfx/primBuilder.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxZodiacMgr.h"
|
||||||
|
#include "afx/afxZodiacTerrainRenderer_T3D.h"
|
||||||
|
#include "afx/util/afxTriBoxCheck2D_T3D.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class TerrCellSpy : public TerrCell
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const U32 getMinCellSize() { return smMinCellSize; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
const RenderInstType afxZodiacTerrainRenderer::RIT_TerrainZodiac("TerrainZodiac");
|
||||||
|
|
||||||
|
afxZodiacTerrainRenderer* afxZodiacTerrainRenderer::master = 0;
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT(afxZodiacTerrainRenderer);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxZodiacTerrainRenderer,
|
||||||
|
"@brief A render bin for zodiac rendering on Terrain objects.\n\n"
|
||||||
|
|
||||||
|
"This bin renders instances of AFX zodiac effects onto Terrain surfaces.\n\n"
|
||||||
|
|
||||||
|
"@ingroup RenderBin\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxZodiacTerrainRenderer::afxZodiacTerrainRenderer()
|
||||||
|
: RenderBinManager(RIT_TerrainZodiac, 1.0f, 1.0f)
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = this;
|
||||||
|
shader_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacTerrainRenderer::afxZodiacTerrainRenderer(F32 renderOrder, F32 processAddOrder)
|
||||||
|
: RenderBinManager(RIT_TerrainZodiac, renderOrder, processAddOrder)
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = this;
|
||||||
|
shader_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacTerrainRenderer::~afxZodiacTerrainRenderer()
|
||||||
|
{
|
||||||
|
if (this == master)
|
||||||
|
master = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxZodiacTerrainRenderer::initShader()
|
||||||
|
{
|
||||||
|
if (shader_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
shader_initialized = true;
|
||||||
|
|
||||||
|
shader_consts = 0;
|
||||||
|
norm_norefl_zb_SB = norm_refl_zb_SB;
|
||||||
|
add_norefl_zb_SB = add_refl_zb_SB;
|
||||||
|
sub_norefl_zb_SB = sub_refl_zb_SB;
|
||||||
|
|
||||||
|
zodiac_shader = afxZodiacMgr::getTerrainZodiacShader();
|
||||||
|
if (!zodiac_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GFXStateBlockDesc d;
|
||||||
|
|
||||||
|
d.cullDefined = true;
|
||||||
|
d.ffLighting = false;
|
||||||
|
d.blendDefined = true;
|
||||||
|
d.blendEnable = true;
|
||||||
|
d.zDefined = false;
|
||||||
|
d.zEnable = true;
|
||||||
|
d.zWriteEnable = false;
|
||||||
|
d.zFunc = GFXCmpLessEqual;
|
||||||
|
d.zSlopeBias = 0;
|
||||||
|
d.alphaDefined = true;
|
||||||
|
d.alphaTestEnable = true;
|
||||||
|
d.alphaTestRef = 0;
|
||||||
|
d.alphaTestFunc = GFXCmpGreater;
|
||||||
|
d.samplersDefined = true;
|
||||||
|
d.samplers[0] = GFXSamplerStateDesc::getClampLinear();
|
||||||
|
|
||||||
|
// normal
|
||||||
|
d.blendSrc = GFXBlendSrcAlpha;
|
||||||
|
d.blendDest = GFXBlendInvSrcAlpha;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sTerrainZodiacZBias;
|
||||||
|
norm_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sTerrainZodiacZBias;
|
||||||
|
norm_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
// additive
|
||||||
|
d.blendSrc = GFXBlendSrcAlpha;
|
||||||
|
d.blendDest = GFXBlendOne;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sTerrainZodiacZBias;
|
||||||
|
add_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sTerrainZodiacZBias;
|
||||||
|
add_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
// subtractive
|
||||||
|
d.blendSrc = GFXBlendZero;
|
||||||
|
d.blendDest = GFXBlendInvSrcColor;
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCCW;
|
||||||
|
d.zBias = arcaneFX::sTerrainZodiacZBias;
|
||||||
|
sub_norefl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
//
|
||||||
|
d.cullMode = GFXCullCW;
|
||||||
|
d.zBias = arcaneFX::sTerrainZodiacZBias;
|
||||||
|
sub_refl_zb_SB = GFX->createStateBlock(d);
|
||||||
|
|
||||||
|
shader_consts = zodiac_shader->getShader()->allocConstBuffer();
|
||||||
|
projection_sc = zodiac_shader->getShader()->getShaderConstHandle("$modelView");
|
||||||
|
color_sc = zodiac_shader->getShader()->getShaderConstHandle("$zodiacColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacTerrainRenderer::clear()
|
||||||
|
{
|
||||||
|
Parent::clear();
|
||||||
|
|
||||||
|
terrain_zodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacTerrainRenderer::addZodiac(U32 zode_idx, const Point3F& pos, F32 ang,
|
||||||
|
const TerrainBlock* block, const TerrCell* cell,
|
||||||
|
const MatrixF& mRenderObjToWorld, F32 camDist)
|
||||||
|
{
|
||||||
|
terrain_zodes.increment();
|
||||||
|
TerrainZodiacElem& elem = terrain_zodes.last();
|
||||||
|
|
||||||
|
elem.block = block;
|
||||||
|
elem.cell = cell;
|
||||||
|
elem.zode_idx = zode_idx;
|
||||||
|
elem.ang = ang;
|
||||||
|
elem.mRenderObjToWorld = mRenderObjToWorld;
|
||||||
|
elem.camDist = camDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacTerrainRenderer* afxZodiacTerrainRenderer::getMaster()
|
||||||
|
{
|
||||||
|
if (!master)
|
||||||
|
master = new afxZodiacTerrainRenderer;
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
GFXStateBlock* afxZodiacTerrainRenderer::chooseStateBlock(U32 blend, bool isReflectPass)
|
||||||
|
{
|
||||||
|
GFXStateBlock* sb = 0;
|
||||||
|
|
||||||
|
switch (blend)
|
||||||
|
{
|
||||||
|
case afxZodiacData::BLEND_ADDITIVE:
|
||||||
|
sb = (isReflectPass) ? add_refl_zb_SB : add_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
case afxZodiacData::BLEND_SUBTRACTIVE:
|
||||||
|
sb = (isReflectPass) ? sub_refl_zb_SB : sub_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
default: // afxZodiacData::BLEND_NORMAL:
|
||||||
|
sb = (isReflectPass) ? norm_refl_zb_SB : norm_norefl_zb_SB;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxZodiacTerrainRenderer::render(SceneRenderState* state)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(afxRenderZodiacTerrainMgr_render);
|
||||||
|
|
||||||
|
// Early out if no terrain zodiacs to draw.
|
||||||
|
if (terrain_zodes.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
initShader();
|
||||||
|
if (!zodiac_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool is_reflect_pass = state->isReflectPass();
|
||||||
|
|
||||||
|
// Automagically save & restore our viewport and transforms.
|
||||||
|
GFXTransformSaver saver;
|
||||||
|
|
||||||
|
MatrixF proj = GFX->getProjectionMatrix();
|
||||||
|
|
||||||
|
// Set up world transform
|
||||||
|
MatrixF world = GFX->getWorldMatrix();
|
||||||
|
proj.mul(world);
|
||||||
|
shader_consts->set(projection_sc, proj);
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// RENDER EACH ZODIAC
|
||||||
|
//
|
||||||
|
for (S32 zz = 0; zz < terrain_zodes.size(); zz++)
|
||||||
|
{
|
||||||
|
TerrainZodiacElem& elem = terrain_zodes[zz];
|
||||||
|
|
||||||
|
TerrainBlock* block = (TerrainBlock*) elem.block;
|
||||||
|
|
||||||
|
afxZodiacMgr::ZodiacSpec* zode = &afxZodiacMgr::terr_zodes[elem.zode_idx];
|
||||||
|
if (!zode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (is_reflect_pass)
|
||||||
|
{
|
||||||
|
if ((zode->zflags & afxZodiacData::SHOW_IN_REFLECTIONS) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((zode->zflags & afxZodiacData::SHOW_IN_NON_REFLECTIONS) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 fadebias = zode->calcDistanceFadeBias(elem.camDist);
|
||||||
|
if (fadebias < 0.01f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
F32 cos_ang = mCos(elem.ang);
|
||||||
|
F32 sin_ang = mSin(elem.ang);
|
||||||
|
|
||||||
|
GFXStateBlock* sb = chooseStateBlock(zode->zflags & afxZodiacData::BLEND_MASK, is_reflect_pass);
|
||||||
|
|
||||||
|
GFX->setShader(zodiac_shader->getShader());
|
||||||
|
GFX->setStateBlock(sb);
|
||||||
|
GFX->setShaderConstBuffer(shader_consts);
|
||||||
|
|
||||||
|
// set the texture
|
||||||
|
GFX->setTexture(0, *zode->txr);
|
||||||
|
LinearColorF zode_color = (LinearColorF)zode->color;
|
||||||
|
zode_color.alpha *= fadebias;
|
||||||
|
shader_consts->set(color_sc, zode_color);
|
||||||
|
|
||||||
|
Point3F half_size(zode->radius_xy,zode->radius_xy,zode->radius_xy);
|
||||||
|
|
||||||
|
F32 inv_radius = 1.0f/zode->radius_xy;
|
||||||
|
|
||||||
|
GFXPrimitive cell_prim;
|
||||||
|
GFXVertexBufferHandle<TerrVertex> cell_verts;
|
||||||
|
GFXPrimitiveBufferHandle primBuff;
|
||||||
|
elem.cell->getRenderPrimitive(&cell_prim, &cell_verts, &primBuff);
|
||||||
|
|
||||||
|
U32 n_nonskirt_tris = TerrCellSpy::getMinCellSize()*TerrCellSpy::getMinCellSize()*2;
|
||||||
|
|
||||||
|
const Point3F* verts = ((TerrCell*)elem.cell)->getZodiacVertexBuffer();
|
||||||
|
const U16 *tris = block->getZodiacPrimitiveBuffer();
|
||||||
|
if (!tris)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PrimBuild::begin(GFXTriangleList, 3*n_nonskirt_tris);
|
||||||
|
|
||||||
|
/////////////////////////////////
|
||||||
|
U32 n_overlapping_tris = 0;
|
||||||
|
U32 idx = 0;
|
||||||
|
for (U32 i = 0; i < n_nonskirt_tris; i++)
|
||||||
|
{
|
||||||
|
Point3F tri_v[3];
|
||||||
|
tri_v[0] = verts[tris[idx++]];
|
||||||
|
tri_v[1] = verts[tris[idx++]];
|
||||||
|
tri_v[2] = verts[tris[idx++]];
|
||||||
|
|
||||||
|
elem.mRenderObjToWorld.mulP(tri_v[0]);
|
||||||
|
elem.mRenderObjToWorld.mulP(tri_v[1]);
|
||||||
|
elem.mRenderObjToWorld.mulP(tri_v[2]);
|
||||||
|
|
||||||
|
if (!afxTriBoxOverlap2D(zode->pos, half_size, tri_v[0], tri_v[1], tri_v[2]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
n_overlapping_tris++;
|
||||||
|
|
||||||
|
for (U32 j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
// compute UV
|
||||||
|
F32 u1 = (tri_v[j].x - zode->pos.x)*inv_radius;
|
||||||
|
F32 v1 = (tri_v[j].y - zode->pos.y)*inv_radius;
|
||||||
|
F32 ru1 = u1*cos_ang - v1*sin_ang;
|
||||||
|
F32 rv1 = u1*sin_ang + v1*cos_ang;
|
||||||
|
|
||||||
|
F32 uu = (ru1 + 1.0f)/2.0f;
|
||||||
|
F32 vv = 1.0f - (rv1 + 1.0f)/2.0f;
|
||||||
|
|
||||||
|
PrimBuild::texCoord2f(uu, vv);
|
||||||
|
PrimBuild::vertex3fv(tri_v[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
|
PrimBuild::end(false);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// RENDER EACH ZODIAC
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
92
Engine/source/afx/afxZodiacTerrainRenderer_T3D.h
Normal file
92
Engine/source/afx/afxZodiacTerrainRenderer_T3D.h
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_ZODIAC_TERRAIN_RENDERER_H_
|
||||||
|
#define _AFX_ZODIAC_TERRAIN_RENDERER_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#include "renderInstance/renderBinManager.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class TerrCell;
|
||||||
|
|
||||||
|
class afxZodiacTerrainRenderer : public RenderBinManager
|
||||||
|
{
|
||||||
|
typedef RenderBinManager Parent;
|
||||||
|
|
||||||
|
struct TerrainZodiacElem
|
||||||
|
{
|
||||||
|
const TerrainBlock* block;
|
||||||
|
const TerrCell* cell;
|
||||||
|
U32 zode_idx;
|
||||||
|
F32 ang;
|
||||||
|
MatrixF mRenderObjToWorld;
|
||||||
|
F32 camDist;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<TerrainZodiacElem> terrain_zodes;
|
||||||
|
static afxZodiacTerrainRenderer* master;
|
||||||
|
|
||||||
|
GFXStateBlockRef norm_norefl_zb_SB, norm_refl_zb_SB;
|
||||||
|
GFXStateBlockRef add_norefl_zb_SB, add_refl_zb_SB;
|
||||||
|
GFXStateBlockRef sub_norefl_zb_SB, sub_refl_zb_SB;
|
||||||
|
|
||||||
|
ShaderData* zodiac_shader;
|
||||||
|
GFXShaderConstBufferRef shader_consts;
|
||||||
|
GFXShaderConstHandle* projection_sc;
|
||||||
|
GFXShaderConstHandle* color_sc;
|
||||||
|
|
||||||
|
bool shader_initialized;
|
||||||
|
|
||||||
|
GFXStateBlock* chooseStateBlock(U32 blend, bool isReflectPass);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const RenderInstType RIT_TerrainZodiac;
|
||||||
|
|
||||||
|
/*C*/ afxZodiacTerrainRenderer();
|
||||||
|
/*C*/ afxZodiacTerrainRenderer(F32 renderOrder, F32 processAddOrder);
|
||||||
|
/*D*/ ~afxZodiacTerrainRenderer();
|
||||||
|
|
||||||
|
// RenderBinManager
|
||||||
|
virtual void sort(){} // don't sort them
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
|
void initShader();
|
||||||
|
void addZodiac(U32 zode_idx, const Point3F& pos, F32 ang, const TerrainBlock*, const TerrCell*, const MatrixF& mRenderObjToWorld, F32 camDist);
|
||||||
|
|
||||||
|
virtual void render(SceneRenderState*);
|
||||||
|
|
||||||
|
static afxZodiacTerrainRenderer* getMaster();
|
||||||
|
|
||||||
|
// ConsoleObject
|
||||||
|
DECLARE_CONOBJECT(afxZodiacTerrainRenderer);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_ZODIAC_TERRAIN_RENDERER_H_
|
||||||
959
Engine/source/afx/arcaneFX.cpp
Normal file
959
Engine/source/afx/arcaneFX.cpp
Normal file
|
|
@ -0,0 +1,959 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "scene/sceneObject.h"
|
||||||
|
#include "scene/sceneManager.h"
|
||||||
|
#include "T3D/gameBase/gameConnection.h"
|
||||||
|
#include "T3D/gameBase/gameProcess.h"
|
||||||
|
#include "T3D/player.h"
|
||||||
|
#include "math/mathUtils.h"
|
||||||
|
#include "console/compiler.h"
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
|
||||||
|
#include "afx/afxChoreographer.h"
|
||||||
|
#include "afx/afxSelectron.h"
|
||||||
|
#include "afx/afxResidueMgr.h"
|
||||||
|
#include "afx/ce/afxZodiacMgr.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#define N_LIGHTING_MODELS 6
|
||||||
|
//
|
||||||
|
// "SG - Original Advanced (Lighting Pack)"
|
||||||
|
// "SG - Original Stock (Lighting Pack)"
|
||||||
|
// "SG - Inverse Square (Lighting Pack)"
|
||||||
|
// "SG - Inverse Square Fast Falloff (Lighting Pack)"
|
||||||
|
// "SG - Near Linear (Lighting Pack)"
|
||||||
|
// "SG - Near Linear Fast Falloff (Lighting Pack)"
|
||||||
|
static StringTableEntry lm_old_names[N_LIGHTING_MODELS];
|
||||||
|
//
|
||||||
|
// "Original Advanced"
|
||||||
|
// "Original Stock"
|
||||||
|
// "Inverse Square"
|
||||||
|
// "Inverse Square Fast Falloff"
|
||||||
|
// "Near Linear"
|
||||||
|
// "Near Linear Fast Falloff"
|
||||||
|
static StringTableEntry lm_new_names[N_LIGHTING_MODELS];
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class ClientZoneInEvent : public NetEvent
|
||||||
|
{
|
||||||
|
typedef NetEvent Parent;
|
||||||
|
public:
|
||||||
|
ClientZoneInEvent() { mGuaranteeType = Guaranteed; }
|
||||||
|
~ClientZoneInEvent() { }
|
||||||
|
|
||||||
|
virtual void pack(NetConnection*, BitStream*bstream) { }
|
||||||
|
virtual void write(NetConnection*, BitStream *bstream) { }
|
||||||
|
virtual void unpack(NetConnection* /*ps*/, BitStream *bstream) { }
|
||||||
|
|
||||||
|
virtual void process(NetConnection* conn)
|
||||||
|
{
|
||||||
|
GameConnection* game_conn = dynamic_cast<GameConnection*>(conn);
|
||||||
|
if (game_conn && !game_conn->isZonedIn())
|
||||||
|
{
|
||||||
|
arcaneFX::syncToNewConnection(game_conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(ClientZoneInEvent);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
IMPLEMENT_CO_SERVEREVENT_V1(ClientZoneInEvent);
|
||||||
|
|
||||||
|
ConsoleDocClass( ClientZoneInEvent,
|
||||||
|
"@brief Event posted when player is fully loaded into the game and ready for interaction.\n\n"
|
||||||
|
"@internal");
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
Vector<afxChoreographer*> arcaneFX::active_choreographers;
|
||||||
|
Vector<afxChoreographer*> arcaneFX::client_choreographers;
|
||||||
|
Vector<afxSelectronData*> arcaneFX::selectrons;
|
||||||
|
Vector<SceneObject*> arcaneFX::scoped_objs;
|
||||||
|
|
||||||
|
StringTableEntry arcaneFX::NULLSTRING = 0;
|
||||||
|
U32 arcaneFX::sTargetSelectionMask = 0;
|
||||||
|
U32 arcaneFX::sFreeTargetSelectionMask = 0;
|
||||||
|
bool arcaneFX::sIsFreeTargeting = false;
|
||||||
|
Point3F arcaneFX::sFreeTargetPos = Point3F(0.0f, 0.0f, 0.0f);
|
||||||
|
bool arcaneFX::sFreeTargetPosValid = false;
|
||||||
|
F32 arcaneFX::sTargetSelectionRange = 200.0f;
|
||||||
|
U32 arcaneFX::sTargetSelectionTimeoutMS = 500;
|
||||||
|
bool arcaneFX::sClickToTargetSelf = false;
|
||||||
|
U32 arcaneFX::sMissileCollisionMask = 0;
|
||||||
|
StringTableEntry arcaneFX::sParameterFieldPrefix = 0;
|
||||||
|
F32 arcaneFX::sTerrainZodiacZBias = -0.00025f;
|
||||||
|
F32 arcaneFX::sInteriorZodiacZBias = -0.0001f;
|
||||||
|
F32 arcaneFX::sPolysoupZodiacZBias = -0.0001f;
|
||||||
|
U32 arcaneFX::master_choreographer_id = 1;
|
||||||
|
U16 arcaneFX::master_scope_id = 1;
|
||||||
|
bool arcaneFX::is_shutdown = true;
|
||||||
|
|
||||||
|
bool arcaneFX::sUsePlayerCentricListener = false;
|
||||||
|
|
||||||
|
void arcaneFX::init()
|
||||||
|
{
|
||||||
|
NULLSTRING = StringTable->insert("");
|
||||||
|
sParameterFieldPrefix = StringTable->insert("_");
|
||||||
|
|
||||||
|
#if defined(TORQUE_OS_MAC)
|
||||||
|
arcaneFX::sTerrainZodiacZBias = -0.00025f;
|
||||||
|
arcaneFX::sInteriorZodiacZBias = -0.00025f;
|
||||||
|
arcaneFX::sPolysoupZodiacZBias = -0.00025f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Con::addVariable( "pref::AFX::targetSelectionMask", TypeS32, &sTargetSelectionMask);
|
||||||
|
Con::addVariable( "pref::AFX::freeTargetSelectionMask", TypeS32, &sFreeTargetSelectionMask);
|
||||||
|
Con::addVariable( "pref::AFX::targetSelectionRange", TypeF32, &sTargetSelectionRange);
|
||||||
|
Con::addVariable( "pref::AFX::targetSelectionTimeoutMS", TypeS32, &sTargetSelectionTimeoutMS);
|
||||||
|
Con::addVariable( "pref::AFX::missileCollisionMask", TypeS32, &sMissileCollisionMask);
|
||||||
|
Con::addVariable( "pref::AFX::clickToTargetSelf", TypeBool, &sClickToTargetSelf);
|
||||||
|
Con::addVariable( "Pref::Server::AFX::parameterFieldPrefix", TypeString, &sParameterFieldPrefix);
|
||||||
|
|
||||||
|
Con::addVariable( "pref::AFX::terrainZodiacZBias", TypeF32, &sTerrainZodiacZBias);
|
||||||
|
Con::addVariable( "pref::AFX::interiorZodiacZBias", TypeF32, &sInteriorZodiacZBias);
|
||||||
|
Con::addVariable( "pref::AFX::polysoupZodiacZBias", TypeF32, &sPolysoupZodiacZBias);
|
||||||
|
|
||||||
|
Con::setIntVariable( "$AFX::TARGETING_OFF", TARGETING_OFF);
|
||||||
|
Con::setIntVariable( "$AFX::TARGETING_STANDARD", TARGETING_STANDARD);
|
||||||
|
Con::setIntVariable( "$AFX::TARGETING_FREE", TARGETING_FREE);
|
||||||
|
Con::setIntVariable( "$AFX::TARGET_CHECK_POLL", TARGET_CHECK_POLL);
|
||||||
|
Con::setIntVariable( "$AFX::TARGET_CHECK_ON_MOUSE_MOVE", TARGET_CHECK_ON_MOUSE_MOVE);
|
||||||
|
|
||||||
|
Con::setIntVariable( "$AFX::IMPACTED_SOMETHING", afxEffectDefs::IMPACTED_SOMETHING);
|
||||||
|
Con::setIntVariable( "$AFX::IMPACTED_TARGET", afxEffectDefs::IMPACTED_TARGET);
|
||||||
|
Con::setIntVariable( "$AFX::IMPACTED_PRIMARY", afxEffectDefs::IMPACTED_PRIMARY);
|
||||||
|
Con::setIntVariable( "$AFX::IMPACT_IN_WATER", afxEffectDefs::IMPACT_IN_WATER);
|
||||||
|
Con::setIntVariable( "$AFX::CASTER_IN_WATER", afxEffectDefs::CASTER_IN_WATER);
|
||||||
|
|
||||||
|
Con::setIntVariable( "$AFX::SERVER_ONLY", afxEffectDefs::SERVER_ONLY);
|
||||||
|
Con::setIntVariable( "$AFX::SCOPE_ALWAYS", afxEffectDefs::SCOPE_ALWAYS);
|
||||||
|
Con::setIntVariable( "$AFX::GHOSTABLE", afxEffectDefs::GHOSTABLE);
|
||||||
|
Con::setIntVariable( "$AFX::CLIENT_ONLY", afxEffectDefs::CLIENT_ONLY);
|
||||||
|
Con::setIntVariable( "$AFX::SERVER_AND_CLIENT", afxEffectDefs::SERVER_AND_CLIENT);
|
||||||
|
|
||||||
|
Con::setIntVariable( "$AFX::DELAY", afxEffectDefs::TIMING_DELAY);
|
||||||
|
Con::setIntVariable( "$AFX::LIFETIME", afxEffectDefs::TIMING_LIFETIME);
|
||||||
|
Con::setIntVariable( "$AFX::FADE_IN_TIME", afxEffectDefs::TIMING_FADE_IN);
|
||||||
|
Con::setIntVariable( "$AFX::FADE_OUT_TIME", afxEffectDefs::TIMING_FADE_OUT);
|
||||||
|
|
||||||
|
Con::setFloatVariable( "$AFX::INFINITE_TIME", -1.0f);
|
||||||
|
Con::setIntVariable( "$AFX::INFINITE_REPEATS", -1);
|
||||||
|
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_MOVE_TRIGGER_0", Player::PLAYER_MOVE_TRIGGER_0);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_MOVE_TRIGGER_1", Player::PLAYER_MOVE_TRIGGER_1);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_MOVE_TRIGGER_2", Player::PLAYER_MOVE_TRIGGER_2);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_MOVE_TRIGGER_3", Player::PLAYER_MOVE_TRIGGER_3);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_MOVE_TRIGGER_4", Player::PLAYER_MOVE_TRIGGER_4);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_MOVE_TRIGGER_5", Player::PLAYER_MOVE_TRIGGER_5);
|
||||||
|
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_FIRE_S_TRIGGER", Player::PLAYER_FIRE_S_TRIGGER);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_FIRE_ALT_S_TRIGGER", Player::PLAYER_FIRE_ALT_S_TRIGGER);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_JUMP_S_TRIGGER", Player::PLAYER_JUMP_S_TRIGGER);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_LANDING_S_TRIGGER", Player::PLAYER_LANDING_S_TRIGGER);
|
||||||
|
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_LF_FOOT_C_TRIGGER", Player::PLAYER_LF_FOOT_C_TRIGGER);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_RT_FOOT_C_TRIGGER", Player::PLAYER_RT_FOOT_C_TRIGGER);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_LANDING_C_TRIGGER", Player::PLAYER_LANDING_C_TRIGGER);
|
||||||
|
Con::setIntVariable( "$AFX::PLAYER_IDLE_C_TRIGGER", Player::PLAYER_IDLE_C_TRIGGER);
|
||||||
|
|
||||||
|
Con::setIntVariable( "$AFX::ILLUM_TERRAIN", 0);
|
||||||
|
Con::setIntVariable( "$AFX::ILLUM_ATLAS", 0);
|
||||||
|
Con::setIntVariable( "$AFX::ILLUM_DIF", 0);
|
||||||
|
Con::setIntVariable( "$AFX::ILLUM_DTS", 0);
|
||||||
|
Con::setIntVariable( "$AFX::ILLUM_ALL", 0);
|
||||||
|
|
||||||
|
Con::setIntVariable("$TypeMasks::TerrainLikeObjectType", TerrainLikeObjectType);
|
||||||
|
Con::setIntVariable("$TypeMasks::InteriorLikeObjectType", InteriorLikeObjectType);
|
||||||
|
Con::setIntVariable("$TypeMasks::PolysoupObjectType", InteriorLikeObjectType); // deprecated
|
||||||
|
|
||||||
|
Con::addVariable("$pref::Audio::usePlayerCentricListener", TypeBool, &sUsePlayerCentricListener);
|
||||||
|
|
||||||
|
afxResidueMgr* residue_mgr = new afxResidueMgr;
|
||||||
|
afxResidueMgr::setMaster(residue_mgr);
|
||||||
|
|
||||||
|
master_scope_id = 1;
|
||||||
|
master_choreographer_id = 1;
|
||||||
|
is_shutdown = false;
|
||||||
|
|
||||||
|
if (lm_old_names[0] == 0)
|
||||||
|
{
|
||||||
|
lm_old_names[0] = StringTable->insert("SG - Original Advanced (Lighting Pack)");
|
||||||
|
lm_old_names[1] = StringTable->insert("SG - Original Stock (Lighting Pack)");
|
||||||
|
lm_old_names[2] = StringTable->insert("SG - Inverse Square (Lighting Pack)");
|
||||||
|
lm_old_names[3] = StringTable->insert("SG - Inverse Square Fast Falloff (Lighting Pack)");
|
||||||
|
lm_old_names[4] = StringTable->insert("SG - Near Linear (Lighting Pack)");
|
||||||
|
lm_old_names[5] = StringTable->insert("SG - Near Linear Fast Falloff (Lighting Pack)");
|
||||||
|
//
|
||||||
|
lm_new_names[0] = StringTable->insert("Original Advanced");
|
||||||
|
lm_new_names[1] = StringTable->insert("Original Stock");
|
||||||
|
lm_new_names[2] = StringTable->insert("Inverse Square");
|
||||||
|
lm_new_names[3] = StringTable->insert("Inverse Square Fast Falloff");
|
||||||
|
lm_new_names[4] = StringTable->insert("Near Linear");
|
||||||
|
lm_new_names[5] = StringTable->insert("Near Linear Fast Falloff");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::shutdown()
|
||||||
|
{
|
||||||
|
is_shutdown = true;
|
||||||
|
|
||||||
|
for (S32 i = 0; i < scoped_objs.size(); i++)
|
||||||
|
if (scoped_objs[i])
|
||||||
|
scoped_objs[i]->setScopeRegistered(false);
|
||||||
|
scoped_objs.clear();
|
||||||
|
|
||||||
|
for (S32 i = 0; i < client_choreographers.size(); i++)
|
||||||
|
if (client_choreographers[i])
|
||||||
|
client_choreographers[i]->clearChoreographerId();
|
||||||
|
client_choreographers.clear();
|
||||||
|
|
||||||
|
for (S32 i = 0; i < selectrons.size(); i++)
|
||||||
|
if (selectrons[i])
|
||||||
|
selectrons[i]->registered = false;
|
||||||
|
selectrons.clear();
|
||||||
|
|
||||||
|
afxResidueMgr* residue_mgr = afxResidueMgr::getMaster();
|
||||||
|
delete residue_mgr;
|
||||||
|
afxResidueMgr::setMaster(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE_BEGIN( arcaneFX )
|
||||||
|
|
||||||
|
MODULE_INIT
|
||||||
|
{
|
||||||
|
arcaneFX::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE_SHUTDOWN
|
||||||
|
{
|
||||||
|
arcaneFX::shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE_END;
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void arcaneFX::advanceTime(U32 delta)
|
||||||
|
{
|
||||||
|
GameConnection* conn = GameConnection::getConnectionToServer();
|
||||||
|
if (conn && !conn->isZonedIn() && conn->getCameraObject() != 0)
|
||||||
|
{
|
||||||
|
conn->setZonedIn();
|
||||||
|
conn->postNetEvent(new ClientZoneInEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
afxZodiacMgr::frameReset();
|
||||||
|
afxResidueMgr::getMaster()->residueAdvanceTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
U32 arcaneFX::registerChoreographer(afxChoreographer* ch)
|
||||||
|
{
|
||||||
|
if (!ch)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
active_choreographers.push_back(ch);
|
||||||
|
|
||||||
|
//Con::printf("registerChoreographer() -- size=%d %s", active_choreographers.size(),
|
||||||
|
// (ch->isServerObject()) ? "server" : "client");
|
||||||
|
|
||||||
|
return master_choreographer_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::unregisterChoreographer(afxChoreographer* ch)
|
||||||
|
{
|
||||||
|
if (!ch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (U32 i = 0; i < active_choreographers.size(); i++)
|
||||||
|
{
|
||||||
|
if (ch == active_choreographers[i])
|
||||||
|
{
|
||||||
|
active_choreographers.erase_fast(i);
|
||||||
|
//Con::printf("unregisterChoreographer() -- size=%d %s", active_choreographers.size(),
|
||||||
|
// (ch->isServerObject()) ? "server" : "client");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::errorf("arcaneFX::unregisterChoreographer() -- failed to find choreographer in list.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::registerClientChoreographer(afxChoreographer* ch)
|
||||||
|
{
|
||||||
|
if (!ch || ch->getChoreographerId() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
client_choreographers.push_back(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::unregisterClientChoreographer(afxChoreographer* ch)
|
||||||
|
{
|
||||||
|
if (!ch || ch->getChoreographerId() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (U32 i = 0; i < client_choreographers.size(); i++)
|
||||||
|
{
|
||||||
|
if (ch == client_choreographers[i])
|
||||||
|
{
|
||||||
|
client_choreographers.erase_fast(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::errorf("arcaneFX::unregisterClientChoreographer() -- failed to find choreographer in list.");
|
||||||
|
}
|
||||||
|
|
||||||
|
afxChoreographer* arcaneFX::findClientChoreographer(U32 id)
|
||||||
|
{
|
||||||
|
for (U32 i = 0; i < client_choreographers.size(); i++)
|
||||||
|
{
|
||||||
|
if (id == client_choreographers[i]->getChoreographerId())
|
||||||
|
return client_choreographers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void arcaneFX::registerSelectronData(afxSelectronData* selectron)
|
||||||
|
{
|
||||||
|
if (!selectron)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selectrons.push_back(selectron);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::unregisterSelectronData(afxSelectronData* selectron)
|
||||||
|
{
|
||||||
|
if (!selectron)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (U32 i = 0; i < selectrons.size(); i++)
|
||||||
|
{
|
||||||
|
if (selectron == selectrons[i])
|
||||||
|
{
|
||||||
|
selectrons.erase_fast(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Con::errorf("arcaneFX::unregisterSelectronData() -- failed to find selectron in list.");
|
||||||
|
}
|
||||||
|
|
||||||
|
afxSelectronData* arcaneFX::findSelectronData(U32 mask, U8 style)
|
||||||
|
{
|
||||||
|
for (U32 i = 0; i < selectrons.size(); i++)
|
||||||
|
if (selectrons[i]->matches(mask, style))
|
||||||
|
return selectrons[i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
U16 arcaneFX::generateScopeId()
|
||||||
|
{
|
||||||
|
U16 ret_id = master_scope_id++;
|
||||||
|
if (master_scope_id >= BIT(GameBase::SCOPE_ID_BITS))
|
||||||
|
master_scope_id = 1;
|
||||||
|
return ret_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::registerScopedObject(SceneObject* object)
|
||||||
|
{
|
||||||
|
scoped_objs.push_back(object);
|
||||||
|
object->setScopeRegistered(true);
|
||||||
|
|
||||||
|
for (S32 i = 0; i < client_choreographers.size(); i++)
|
||||||
|
if (client_choreographers[i])
|
||||||
|
client_choreographers[i]->restoreScopedObject(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneObject* arcaneFX::findScopedObject(U16 scope_id)
|
||||||
|
{
|
||||||
|
if (scoped_objs.size() > 0)
|
||||||
|
{
|
||||||
|
for (S32 i = scoped_objs.size()-1; i >= 0; i--)
|
||||||
|
if (scoped_objs[i] && scoped_objs[i]->getScopeId() == scope_id)
|
||||||
|
return scoped_objs[i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::unregisterScopedObject(SceneObject* object)
|
||||||
|
{
|
||||||
|
if (scoped_objs.size() > 0)
|
||||||
|
{
|
||||||
|
for (S32 i = scoped_objs.size()-1; i >= 0; i--)
|
||||||
|
if (scoped_objs[i] == object)
|
||||||
|
{
|
||||||
|
scoped_objs.erase_fast(i);
|
||||||
|
if (object)
|
||||||
|
object->setScopeRegistered(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::syncToNewConnection(GameConnection* conn)
|
||||||
|
{
|
||||||
|
if (conn)
|
||||||
|
conn->setZonedIn();
|
||||||
|
|
||||||
|
for (U32 i = 0; i < active_choreographers.size(); i++)
|
||||||
|
{
|
||||||
|
if (active_choreographers[i])
|
||||||
|
active_choreographers[i]->sync_with_clients();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcaneFX::endMissionNotify()
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < scoped_objs.size(); i++)
|
||||||
|
if (scoped_objs[i])
|
||||||
|
scoped_objs[i]->setScopeRegistered(false);
|
||||||
|
scoped_objs.clear();
|
||||||
|
|
||||||
|
for (S32 i = 0; i < client_choreographers.size(); i++)
|
||||||
|
if (client_choreographers[i])
|
||||||
|
client_choreographers[i]->clearChoreographerId();
|
||||||
|
client_choreographers.clear();
|
||||||
|
|
||||||
|
for (S32 i = 0; i < selectrons.size(); i++)
|
||||||
|
if (selectrons[i])
|
||||||
|
selectrons[i]->registered = false;
|
||||||
|
selectrons.clear();
|
||||||
|
|
||||||
|
if (afxResidueMgr::getMaster())
|
||||||
|
afxResidueMgr::getMaster()->cleanup();
|
||||||
|
afxZodiacMgr::missionCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 arcaneFX::rolloverRayCast(Point3F start, Point3F end, U32 mask)
|
||||||
|
{
|
||||||
|
sIsFreeTargeting = false;
|
||||||
|
#if !defined(AFX_CAP_ROLLOVER_RAYCASTS)
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
GameConnection* conn = GameConnection::getConnectionToServer();
|
||||||
|
SceneObject* ctrl_obj = NULL;
|
||||||
|
|
||||||
|
if (!arcaneFX::sClickToTargetSelf && conn != NULL)
|
||||||
|
ctrl_obj = conn->getControlObject();
|
||||||
|
|
||||||
|
if (ctrl_obj)
|
||||||
|
ctrl_obj->disableCollision();
|
||||||
|
|
||||||
|
SceneObject* rollover_obj = (conn) ? conn->getRolloverObj() : 0;
|
||||||
|
SceneObject* picked_obj = 0;
|
||||||
|
|
||||||
|
RayInfo hit_info;
|
||||||
|
if (gClientContainer.castRay(start, end, mask, &hit_info))
|
||||||
|
picked_obj = dynamic_cast<SceneObject*>(hit_info.object);
|
||||||
|
|
||||||
|
if (ctrl_obj)
|
||||||
|
ctrl_obj->enableCollision();
|
||||||
|
|
||||||
|
if (picked_obj != rollover_obj)
|
||||||
|
{
|
||||||
|
if (rollover_obj)
|
||||||
|
rollover_obj->setSelectionFlags(rollover_obj->getSelectionFlags() & ~SceneObject::PRE_SELECTED);
|
||||||
|
if (picked_obj)
|
||||||
|
picked_obj->setSelectionFlags(picked_obj->getSelectionFlags() | SceneObject::PRE_SELECTED);
|
||||||
|
rollover_obj = picked_obj;
|
||||||
|
|
||||||
|
if (conn)
|
||||||
|
conn->setRolloverObj(rollover_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (picked_obj) ? picked_obj->getId() : -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool arcaneFX::freeTargetingRayCast(Point3F start, Point3F end, U32 mask)
|
||||||
|
{
|
||||||
|
sIsFreeTargeting = true;
|
||||||
|
|
||||||
|
RayInfo hit_info;
|
||||||
|
if (!gClientContainer.castRay(start, end, mask, &hit_info))
|
||||||
|
{
|
||||||
|
sFreeTargetPosValid = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sFreeTargetPosValid = true;
|
||||||
|
sFreeTargetPos = hit_info.point;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTableEntry arcaneFX::convertLightingModelName(StringTableEntry lm_name)
|
||||||
|
{
|
||||||
|
for (U32 i = 0; i < N_LIGHTING_MODELS; i++)
|
||||||
|
{
|
||||||
|
if (lm_name == lm_old_names[i])
|
||||||
|
return lm_new_names[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return lm_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Console Functions
|
||||||
|
|
||||||
|
DefineEngineFunction(afxEndMissionNotify, void, (),,
|
||||||
|
"...\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
arcaneFX::endMissionNotify();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(afxGetVersion, const char*, (),,
|
||||||
|
"...\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return AFX_VERSION_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(afxGetEngine, const char*, (),,
|
||||||
|
"...\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return "T3D";
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_ROLLOVER_RAYCASTS)
|
||||||
|
DefineEngineFunction(rolloverRayCast, S32, (Point3F start, Point3F end, U32 mask),,
|
||||||
|
"Performs a raycast from points start to end and returns the ID of nearest "
|
||||||
|
"intersecting object with a type found in the specified mask. "
|
||||||
|
"Returns -1 if no object is found.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return arcaneFX::rolloverRayCast(start, end, mask);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DefineEngineFunction(getRandomF, F32, (float a, float b), (F32_MAX, F32_MAX),
|
||||||
|
"Get a random float number between a and b.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
if (b == F32_MAX)
|
||||||
|
{
|
||||||
|
if (a == F32_MAX)
|
||||||
|
return gRandGen.randF();
|
||||||
|
|
||||||
|
return gRandGen.randF(0.0f, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (a + (b-a)*gRandGen.randF());
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(getRandomDir, Point3F, (Point3F axis, float thetaMin, float thetaMax, float phiMin, float phiMax),
|
||||||
|
(Point3F(0.0f,0.0f,0.0f), 0.0f, 180.0f, 0.0f, 360.0f),
|
||||||
|
"Get a random direction vector.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return MathUtils::randomDir(axis, thetaMin, thetaMax, phiMin, phiMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction( MatrixInverseMulVector, const char*, 3, 3, "(MatrixF xfrm, Point3F vector)"
|
||||||
|
"@brief Multiply the vector by the affine inverse of the transform.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
Point3F pos1(0.0f,0.0f,0.0f);
|
||||||
|
AngAxisF aa1(Point3F(0.0f,0.0f,0.0f),0.0f);
|
||||||
|
dSscanf(argv[1], "%g %g %g %g %g %g %g", &pos1.x, &pos1.y, &pos1.z, &aa1.axis.x, &aa1.axis.y, &aa1.axis.z, &aa1.angle);
|
||||||
|
|
||||||
|
MatrixF temp1(true);
|
||||||
|
aa1.setMatrix(&temp1);
|
||||||
|
temp1.setColumn(3, pos1);
|
||||||
|
|
||||||
|
Point3F vec1(0.0f,0.0f,0.0f);
|
||||||
|
dSscanf(argv[2], "%g %g %g", &vec1.x, &vec1.y, &vec1.z);
|
||||||
|
|
||||||
|
temp1.affineInverse();
|
||||||
|
|
||||||
|
Point3F result;
|
||||||
|
temp1.mulV(vec1, &result);
|
||||||
|
|
||||||
|
char* ret = Con::getReturnBuffer(256);
|
||||||
|
dSprintf(ret, 255, "%g %g %g", result.x, result.y, result.z);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(moveTransformAbs, const char*, 3, 3, "(MatrixF xfrm, Point3F pos)"
|
||||||
|
"@brief Move the transform to the new absolute position.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
Point3F pos1(0.0f,0.0f,0.0f);
|
||||||
|
AngAxisF aa1(Point3F(0.0f,0.0f,0.0f),0.0f);
|
||||||
|
dSscanf(argv[1], "%g %g %g %g %g %g %g", &pos1.x, &pos1.y, &pos1.z, &aa1.axis.x, &aa1.axis.y, &aa1.axis.z, &aa1.angle);
|
||||||
|
|
||||||
|
Point3F pos2(0.0f,0.0f,0.0f);
|
||||||
|
dSscanf(argv[2], "%g %g %g", &pos2.x, &pos2.y, &pos2.z);
|
||||||
|
|
||||||
|
char* returnBuffer = Con::getReturnBuffer(256);
|
||||||
|
dSprintf(returnBuffer, 255, "%g %g %g %g %g %g %g",
|
||||||
|
pos2.x, pos2.y, pos2.z,
|
||||||
|
aa1.axis.x, aa1.axis.y, aa1.axis.z,
|
||||||
|
aa1.angle);
|
||||||
|
return returnBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(moveTransformRel, const char*, 3, 3, "(MatrixF xfrm, Point3F pos)"
|
||||||
|
"@brief Move the transform to the new relative position.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
Point3F pos1(0.0f,0.0f,0.0f);
|
||||||
|
AngAxisF aa1(Point3F(0.0f,0.0f,0.0f),0.0f);
|
||||||
|
dSscanf(argv[1], "%g %g %g %g %g %g %g", &pos1.x, &pos1.y, &pos1.z, &aa1.axis.x, &aa1.axis.y, &aa1.axis.z, &aa1.angle);
|
||||||
|
|
||||||
|
Point3F pos2(0.0f,0.0f,0.0f);
|
||||||
|
dSscanf(argv[2], "%g %g %g", &pos2.x, &pos2.y, &pos2.z);
|
||||||
|
|
||||||
|
pos2 += pos1;
|
||||||
|
|
||||||
|
char* returnBuffer = Con::getReturnBuffer(256);
|
||||||
|
dSprintf(returnBuffer, 255, "%g %g %g %g %g %g %g",
|
||||||
|
pos2.x, pos2.y, pos2.z,
|
||||||
|
aa1.axis.x, aa1.axis.y, aa1.axis.z,
|
||||||
|
aa1.angle);
|
||||||
|
return returnBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(getFreeTargetPosition, Point3F, (),,
|
||||||
|
"@brief Returns the current location of the free target.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
if (!arcaneFX::sFreeTargetPosValid)
|
||||||
|
return Point3F(0.0f, 0.0f, 0.0f);
|
||||||
|
return arcaneFX::sFreeTargetPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(SceneObject, getSpeed, F32, (),,
|
||||||
|
"Returns the velocity of a scene-object.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return object->getVelocity().len();
|
||||||
|
}
|
||||||
|
|
||||||
|
static S32 mark_modkey = -1;
|
||||||
|
|
||||||
|
DefineEngineFunction(markDataBlocks, void, (),,
|
||||||
|
"@brief Called before a series of datablocks are reloaded to "
|
||||||
|
"help distinguish reloaded datablocks from already loaded ones.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
mark_modkey = SimDataBlock::getNextModifiedKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(touchDataBlocks, void, (),,
|
||||||
|
"@brief Called after a series of datablocks are reloaded to "
|
||||||
|
"trigger some important actions on the reloaded datablocks.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
if (mark_modkey < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SimDataBlockGroup* g = Sim::getDataBlockGroup();
|
||||||
|
|
||||||
|
U32 groupCount = g->size();
|
||||||
|
for (S32 i = groupCount-1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
SimDataBlock* simdb = (SimDataBlock*)(*g)[i];
|
||||||
|
if (simdb->getModifiedKey() > mark_modkey)
|
||||||
|
{
|
||||||
|
simdb->unregisterObject();
|
||||||
|
simdb->registerObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_modkey = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Syntax Error Checking
|
||||||
|
// (for checking eval() and compile() calls)
|
||||||
|
|
||||||
|
DefineEngineFunction(wasSyntaxError, bool, (),,
|
||||||
|
"@brief Returns true if script compiler had a syntax error. Useful "
|
||||||
|
"for detecting syntax errors after reloading a script.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return Compiler::gSyntaxError;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Network Object Identification
|
||||||
|
|
||||||
|
// These useful console methods come from the following code resource:
|
||||||
|
//
|
||||||
|
// How to Identify Objects from Client to Server or Server to Client by Nathan Davies
|
||||||
|
// http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=4852
|
||||||
|
//
|
||||||
|
|
||||||
|
DefineEngineMethod(NetConnection, GetGhostIndex, S32, (NetObject* obj),,
|
||||||
|
"Returns the ghost-index for an object.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
if (obj)
|
||||||
|
return object->getGhostIndex(obj);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(NetConnection, ResolveGhost, S32, (int ghostIndex),,
|
||||||
|
"Resolves a ghost-index into an object ID.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
if (ghostIndex != -1)
|
||||||
|
{
|
||||||
|
NetObject* pObject = NULL;
|
||||||
|
if( object->isGhostingTo())
|
||||||
|
pObject = object->resolveGhost(ghostIndex);
|
||||||
|
else if( object->isGhostingFrom())
|
||||||
|
pObject = object->resolveObjectFromGhostIndex(ghostIndex);
|
||||||
|
if (pObject)
|
||||||
|
return pObject->getId();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// TypeByteRange
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
IMPLEMENT_STRUCT( ByteRange, ByteRange,,
|
||||||
|
"" )
|
||||||
|
END_IMPLEMENT_STRUCT;
|
||||||
|
|
||||||
|
ConsoleType( ByteRange, TypeByteRange, ByteRange, "")
|
||||||
|
ConsoleType( ByteRange, TypeByteRange2, ByteRange, "")
|
||||||
|
|
||||||
|
ConsoleGetType( TypeByteRange )
|
||||||
|
{
|
||||||
|
ByteRange* pt = (ByteRange *) dptr;
|
||||||
|
char* returnBuffer = Con::getReturnBuffer(256);
|
||||||
|
dSprintf(returnBuffer, 256, "%u %u", pt->low, pt->high);
|
||||||
|
return returnBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleSetType( TypeByteRange )
|
||||||
|
{
|
||||||
|
if(argc == 1)
|
||||||
|
{
|
||||||
|
ByteRange* range = (ByteRange*) dptr;
|
||||||
|
U32 lo, hi;
|
||||||
|
S32 args = dSscanf(argv[0], "%u %u", &lo, &hi);
|
||||||
|
range->low = (args > 0) ? lo : 0;
|
||||||
|
range->high = (args > 1) ? hi : 255;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Con::printf("ByteRange must be set as \"low\" or \"low high\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleGetType( TypeByteRange2 )
|
||||||
|
{
|
||||||
|
ByteRange* pt = (ByteRange *) dptr;
|
||||||
|
char* returnBuffer = Con::getReturnBuffer(256);
|
||||||
|
dSprintf(returnBuffer, 256, "%u %u", pt->low, pt->high);
|
||||||
|
return returnBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleSetType( TypeByteRange2 )
|
||||||
|
{
|
||||||
|
if(argc == 1)
|
||||||
|
{
|
||||||
|
ByteRange* range = (ByteRange*) dptr;
|
||||||
|
U32 lo, hi;
|
||||||
|
S32 args = dSscanf(argv[0], "%u %u", &lo, &hi);
|
||||||
|
range->low = (args > 0) ? lo : 0;
|
||||||
|
range->high = (args > 1) ? hi : lo;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Con::printf("ByteRange must be set as \"low\" or \"low high\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
static void HSVtoRGB(F32 h, F32 s, F32 v, F32& r, F32& g, F32& b)
|
||||||
|
{
|
||||||
|
h = mFmod(h, 360.0f);
|
||||||
|
|
||||||
|
if (v == 0.0f)
|
||||||
|
r = g = b = 0.0f;
|
||||||
|
else if (s == 0.0f)
|
||||||
|
r = g = b = v;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
F32 hf = h/60.0f;
|
||||||
|
S32 i = (S32) mFloor(hf);
|
||||||
|
F32 f = hf - i;
|
||||||
|
|
||||||
|
F32 pv = v*(1.0f - s);
|
||||||
|
F32 qv = v*(1.0f - s*f);
|
||||||
|
F32 tv = v*(1.0f - s*(1.0f - f));
|
||||||
|
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
r = v; g = tv; b = pv;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r = qv; g = v; b = pv;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
r = pv; g = v; b = tv;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
r = pv; g = qv; b = v;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
r = tv; g = pv; b = v;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
r = v; g = pv; b = qv;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r = g = b = 0.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(getColorFromHSV, const char*, (float hue, float sat, float val, float alpha), (0.0, 0.0, 1.0, 1.0),
|
||||||
|
"Coverts an HSV formatted color into an RBG color.\n\n"
|
||||||
|
"@param hue The hue of the color (0-360).\n"
|
||||||
|
"@param sat The saturation of the color (0-1).\n"
|
||||||
|
"@param val The value of the color (0-1).\n"
|
||||||
|
"@param alpha The alpha of the color (0-1).\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
LinearColorF rgb;
|
||||||
|
HSVtoRGB(hue, sat, val, rgb.red, rgb.green, rgb.blue);
|
||||||
|
rgb.alpha = alpha;
|
||||||
|
|
||||||
|
char* returnBuffer = Con::getReturnBuffer(256);
|
||||||
|
dSprintf(returnBuffer, 256, "%g %g %g %g", rgb.red, rgb.green, rgb.blue, rgb.alpha);
|
||||||
|
|
||||||
|
return returnBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(ColorScale, const char*, ( LinearColorF color, float scalar ),,
|
||||||
|
"Returns color scaled by scalar (color*scalar).\n\n"
|
||||||
|
"@param color The color to be scaled.\n"
|
||||||
|
"@param scalar The amount to scale the color.\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
color *= scalar;
|
||||||
|
|
||||||
|
char* returnBuffer = Con::getReturnBuffer(256);
|
||||||
|
dSprintf(returnBuffer, 256, "%g %g %g %g", color.red, color.green, color.blue, color.alpha);
|
||||||
|
|
||||||
|
return returnBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(getMinF, F32, (float a, float b),,
|
||||||
|
"Returns the lesser of the two arguments.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return getMin(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineFunction(getMaxF, F32, (float a, float b),,
|
||||||
|
"Returns the greater of the two arguments.\n\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
return getMax(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(echoThru, const char*, 2, 0, "(string passthru, string text...)"
|
||||||
|
"Like echo(), but first argument is returned.\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
U32 len = 0;
|
||||||
|
S32 i;
|
||||||
|
for(i = 2; i < argc; i++)
|
||||||
|
len += dStrlen(argv[i]);
|
||||||
|
|
||||||
|
char *ret = Con::getReturnBuffer(len + 1);
|
||||||
|
ret[0] = 0;
|
||||||
|
for(i = 2; i < argc; i++)
|
||||||
|
dStrcat(ret, argv[i]);
|
||||||
|
|
||||||
|
Con::printf("%s -- [%s]", ret, argv[1].getStringValue());
|
||||||
|
ret[0] = 0;
|
||||||
|
|
||||||
|
return argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(warnThru, const char*, 2, 0, "(string passthru, string text...)"
|
||||||
|
"Like warn(), but first argument is returned.\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
U32 len = 0;
|
||||||
|
S32 i;
|
||||||
|
for(i = 2; i < argc; i++)
|
||||||
|
len += dStrlen(argv[i]);
|
||||||
|
|
||||||
|
char *ret = Con::getReturnBuffer(len + 1);
|
||||||
|
ret[0] = 0;
|
||||||
|
for(i = 2; i < argc; i++)
|
||||||
|
dStrcat(ret, argv[i]);
|
||||||
|
|
||||||
|
Con::warnf("%s -- [%s]", ret, argv[1].getStringValue());
|
||||||
|
ret[0] = 0;
|
||||||
|
|
||||||
|
return argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleFunction(errorThru, const char*, 2, 0, "(string passthru, string text...)"
|
||||||
|
"Like error(), but first argument is returned.\n"
|
||||||
|
"@ingroup AFX")
|
||||||
|
{
|
||||||
|
U32 len = 0;
|
||||||
|
S32 i;
|
||||||
|
for(i = 2; i < argc; i++)
|
||||||
|
len += dStrlen(argv[i]);
|
||||||
|
|
||||||
|
char *ret = Con::getReturnBuffer(len + 1);
|
||||||
|
ret[0] = 0;
|
||||||
|
for(i = 2; i < argc; i++)
|
||||||
|
dStrcat(ret, argv[i]);
|
||||||
|
|
||||||
|
Con::errorf("%s -- [%s]", ret, argv[1].getStringValue());
|
||||||
|
ret[0] = 0;
|
||||||
|
|
||||||
|
return argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
214
Engine/source/afx/arcaneFX.h
Normal file
214
Engine/source/afx/arcaneFX.h
Normal file
|
|
@ -0,0 +1,214 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _ARCANE_FX_H_
|
||||||
|
#define _ARCANE_FX_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _PLATFORM_H_
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AFX_VERSION_STRING "2.0"
|
||||||
|
#define AFX_VERSION 2.0
|
||||||
|
|
||||||
|
// #define AFX_CUSTOMIZED_BRANCH
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
#if defined(AFX_CUSTOMIZED_BRANCH)
|
||||||
|
|
||||||
|
#elif (TORQUE_GAME_ENGINE == 1100 || TORQUE_GAME_ENGINE >= 3000)
|
||||||
|
|
||||||
|
#define AFX_CAP_SCOPE_TRACKING
|
||||||
|
#define AFX_CAP_ROLLOVER_RAYCASTS
|
||||||
|
//#define AFX_CAP_AFXMODEL_TYPE
|
||||||
|
//#define BROKEN_POINT_IN_WATER
|
||||||
|
#define BROKEN_DAMAGEFLASH_WHITEOUT_BLACKOUT
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
#else
|
||||||
|
|
||||||
|
// This version of AFX source only supports T3D 1.1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _CONSOLETYPES_H_
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _ENGINEAPI_H_
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _SIMBASE_H_
|
||||||
|
#include "console/simBase.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _BITSTREAM_H_
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _GAMEBASE_H_
|
||||||
|
#include "T3D/gameBase/gameBase.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(DGL_GRAPHICS_LAYER)
|
||||||
|
#ifndef _DGL_H_
|
||||||
|
#include "dgl/dgl.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class afxChoreographer;
|
||||||
|
class afxSelectronData;
|
||||||
|
class GameConnection;
|
||||||
|
class SceneObject;
|
||||||
|
|
||||||
|
class arcaneFX
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
TARGETING_OFF,
|
||||||
|
TARGETING_STANDARD,
|
||||||
|
TARGETING_FREE
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
TARGET_CHECK_POLL,
|
||||||
|
TARGET_CHECK_ON_MOUSE_MOVE
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Vector<afxChoreographer*> active_choreographers;
|
||||||
|
static Vector<afxChoreographer*> client_choreographers;
|
||||||
|
static Vector<afxSelectronData*> selectrons;
|
||||||
|
static Vector<SceneObject*> scoped_objs;
|
||||||
|
static bool is_shutdown;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static StringTableEntry NULLSTRING;
|
||||||
|
static U32 sTargetSelectionMask;
|
||||||
|
static U32 sFreeTargetSelectionMask;
|
||||||
|
static bool sIsFreeTargeting;
|
||||||
|
static Point3F sFreeTargetPos;
|
||||||
|
static bool sFreeTargetPosValid;
|
||||||
|
static F32 sTargetSelectionRange;
|
||||||
|
static U32 sTargetSelectionTimeoutMS;
|
||||||
|
static bool sClickToTargetSelf;
|
||||||
|
static U32 sMissileCollisionMask;
|
||||||
|
static StringTableEntry sParameterFieldPrefix;
|
||||||
|
static F32 sTerrainZodiacZBias;
|
||||||
|
static F32 sInteriorZodiacZBias;
|
||||||
|
static F32 sPolysoupZodiacZBias;
|
||||||
|
static U32 master_choreographer_id;
|
||||||
|
static U16 master_scope_id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void init();
|
||||||
|
static void shutdown();
|
||||||
|
static void advanceTime(U32 delta);
|
||||||
|
|
||||||
|
static U32 registerChoreographer(afxChoreographer*);
|
||||||
|
static void unregisterChoreographer(afxChoreographer*);
|
||||||
|
static void registerClientChoreographer(afxChoreographer*);
|
||||||
|
static void unregisterClientChoreographer(afxChoreographer*);
|
||||||
|
static afxChoreographer* findClientChoreographer(U32 id);
|
||||||
|
|
||||||
|
static void registerSelectronData(afxSelectronData*);
|
||||||
|
static void unregisterSelectronData(afxSelectronData*);
|
||||||
|
static afxSelectronData* findSelectronData(U32 obj_type_mask, U8 code);
|
||||||
|
|
||||||
|
static U16 generateScopeId();
|
||||||
|
static void registerScopedObject(SceneObject*);
|
||||||
|
static SceneObject* findScopedObject(U16 scope_id);
|
||||||
|
static void unregisterScopedObject(SceneObject*);
|
||||||
|
|
||||||
|
static void syncToNewConnection(GameConnection* conn);
|
||||||
|
static void endMissionNotify();
|
||||||
|
static S32 rolloverRayCast(Point3F start, Point3F end, U32 mask);
|
||||||
|
static bool freeTargetingRayCast(Point3F start, Point3F end, U32 mask);
|
||||||
|
|
||||||
|
static bool isShutdown() { return is_shutdown; }
|
||||||
|
static StringTableEntry convertLightingModelName(StringTableEntry lm_name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool sUsePlayerCentricListener;
|
||||||
|
public:
|
||||||
|
static bool usePlayerCentricListener() { return sUsePlayerCentricListener; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
class ByteRange
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
U8 low;
|
||||||
|
U8 high;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ ByteRange() { low = 0; high = 255; }
|
||||||
|
/*C*/ ByteRange(U8 l, U8 h=255) { low = l; high = h; }
|
||||||
|
|
||||||
|
void set(U8 l, U8 h=255) { low = l; high = h; }
|
||||||
|
bool outOfRange(U8 v) { return (v < low || v > high); }
|
||||||
|
bool inRange(U8 v) { return !outOfRange(v); }
|
||||||
|
S32 getSpan() const { return high - low; }
|
||||||
|
};
|
||||||
|
|
||||||
|
DefineConsoleType(TypeByteRange, ByteRange)
|
||||||
|
DefineConsoleType(TypeByteRange2, ByteRange)
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
inline void writeDatablockID(BitStream* s, SimObject* simobj, bool packed=false)
|
||||||
|
{
|
||||||
|
if (s->writeFlag(simobj))
|
||||||
|
s->writeRangedU32(packed ? SimObjectId((uintptr_t)simobj) : simobj->getId(),
|
||||||
|
DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline S32 readDatablockID(BitStream* s)
|
||||||
|
{
|
||||||
|
return (!s->readFlag()) ? 0 : ((S32)s->readRangedU32(DataBlockObjectIdFirst,
|
||||||
|
DataBlockObjectIdLast));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void registerForCleanup(SimObject* obj)
|
||||||
|
{
|
||||||
|
SimGroup* cleanup_grp = dynamic_cast<SimGroup*>(Sim::findObject("MissionCleanup"));
|
||||||
|
if (cleanup_grp)
|
||||||
|
cleanup_grp->addObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#define ST_NULLSTRING (arcaneFX::NULLSTRING)
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _ARCANE_FX_H_
|
||||||
|
|
||||||
217
Engine/source/afx/ce/afxAnimClip.cpp
Normal file
217
Engine/source/afx/ce/afxAnimClip.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxAnimClip.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxAnimClipData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxAnimClipData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxAnimClipData,
|
||||||
|
"@brief A datablock that specifies an Animation Clip effect.\n\n"
|
||||||
|
|
||||||
|
"An Animation Clip forces a target ShapeBase-derived object, such as Player or AIPlayer, to perform a particular "
|
||||||
|
"animation sequence. Animation Clip does not supply any new animation data, but simply selects, by name, a "
|
||||||
|
"sequence that is already defined in the target. Animation Clip can also target afxModel effects within the same "
|
||||||
|
"choreographer."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"The target of an Animation Clip is the constraint source object specified by the posConstraint field of the enclosing "
|
||||||
|
"effect wrapper. The target must be a ShapeBase-derived object, or an afxModel and it must contain an animation "
|
||||||
|
"sequence with the same name as the clipName field."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"Animation Clip controls the rate of animation playback and can even play a sequence in reverse. When an Animation "
|
||||||
|
"Clip selects a blended animation sequence, it is mixed with the current animation instead of replacing it. Animation "
|
||||||
|
"Clips can be used to activate multiple, overlapping blend sequences."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"Normally when an Animation Clip is applied to a user-controlled Player, any interactive user actions will override the "
|
||||||
|
"animation selected by the clip, but Animation Clips can be configured to temporarily block out some user actions for "
|
||||||
|
"the duration of the clip."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxAnimClipData::afxAnimClipData()
|
||||||
|
{
|
||||||
|
clip_name = ST_NULLSTRING;
|
||||||
|
rate = 1.0f;
|
||||||
|
pos_offset = 0.0;
|
||||||
|
trans = 0.12f;
|
||||||
|
flags = 0;
|
||||||
|
|
||||||
|
ignore_disabled = false;
|
||||||
|
ignore_enabled = false;
|
||||||
|
is_death_anim = false;
|
||||||
|
lock_anim = false;
|
||||||
|
ignore_first_person = false;
|
||||||
|
ignore_third_person = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxAnimClipData::afxAnimClipData(const afxAnimClipData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
clip_name = other.clip_name;
|
||||||
|
rate = other.rate;
|
||||||
|
pos_offset = other.pos_offset;
|
||||||
|
trans = other.trans;
|
||||||
|
flags = other.flags;
|
||||||
|
|
||||||
|
expand_flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAnimClipData::onStaticModified(const char* slot, const char* newValue)
|
||||||
|
{
|
||||||
|
Parent::onStaticModified(slot, newValue);
|
||||||
|
merge_flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxAnimClipData)
|
||||||
|
|
||||||
|
void afxAnimClipData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("clipName", TYPEID< StringTableEntry >(), myOffset(clip_name),
|
||||||
|
"The name of an animation sequence to be played by a ShapeBase-derived object to which this effect is "
|
||||||
|
"constrained. Also works on afxModel effects.\n"
|
||||||
|
"default: \"\"\n");
|
||||||
|
addField("rate", TYPEID< F32 >(), myOffset(rate),
|
||||||
|
"The desired playback speed for the sequence. A value of 1.0 indicates forward playback at a normal rate. Negative "
|
||||||
|
"values cause the sequence to play backwards.\n"
|
||||||
|
"default: 1.0\n");
|
||||||
|
addField("posOffset", TYPEID< F32 >(), myOffset(pos_offset),
|
||||||
|
"Sets a starting offset for the selected animation clip. It directly specifies an animation thread position in the 0.0 to "
|
||||||
|
"1.0 range as a fraction of the clip's duration.\n"
|
||||||
|
"default: 1.0\n");
|
||||||
|
addField("transitionTime", TYPEID< F32 >(), myOffset(trans),
|
||||||
|
"The duration in which the active animation overlaps and blends into the sequence selected by the animation clip.\n"
|
||||||
|
"default: 0.12\n");
|
||||||
|
addField("ignoreCorpse", TYPEID< bool >(), myOffset(ignore_disabled),
|
||||||
|
"Specifies if the animation clip should not be applied to corpses or anything else with a disabled damage state.\n"
|
||||||
|
"default: false\n");
|
||||||
|
addField("ignoreLiving", TYPEID< bool >(), myOffset(ignore_enabled),
|
||||||
|
"Specifies if the animation clip should not be applied to living objects or anything else with an enabled damage "
|
||||||
|
"state.\n"
|
||||||
|
"default: false\n");
|
||||||
|
addField("treatAsDeathAnim", TYPEID< bool >(), myOffset(is_death_anim),
|
||||||
|
"Indicates if the animation clip is a death animation. If the target object dies during the effect, this will prevent "
|
||||||
|
"the object from playing another standard death animation after this clip finishes.\n"
|
||||||
|
"default: false\n");
|
||||||
|
addField("lockAnimation", TYPEID< bool >(), myOffset(lock_anim),
|
||||||
|
"Indicates if user control of a Player should be temporarily blocked during the clip. (See afxAnimLockData.)\n"
|
||||||
|
"default: false\n");
|
||||||
|
addField("ignoreFirstPerson", TYPEID< bool >(), myOffset(ignore_first_person),
|
||||||
|
"If true, the clip will not be played on targets that are the control object and the camera is in first person mode.\n"
|
||||||
|
"default: false\n");
|
||||||
|
addField("ignoreThirdPerson", TYPEID< bool >(), myOffset(ignore_third_person),
|
||||||
|
"If true, the clip will not be played on targets that are the control object and the camera is in third person mode.\n"
|
||||||
|
"default: false\n");
|
||||||
|
|
||||||
|
// synonyms
|
||||||
|
addField("ignoreDisabled", TYPEID< bool >(), myOffset(ignore_disabled),
|
||||||
|
"A synonym for ignoreLiving.");
|
||||||
|
addField("ignoreEnabled", TYPEID< bool >(), myOffset(ignore_enabled),
|
||||||
|
"A synonym for ignoreCorpse.");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxAnimClipData::onAdd()
|
||||||
|
{
|
||||||
|
if (Parent::onAdd() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAnimClipData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
merge_flags();
|
||||||
|
|
||||||
|
stream->writeString(clip_name);
|
||||||
|
stream->write(rate);
|
||||||
|
stream->write(pos_offset);
|
||||||
|
stream->write(trans);
|
||||||
|
stream->write(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAnimClipData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
clip_name = stream->readSTString();
|
||||||
|
stream->read(&rate);
|
||||||
|
stream->read(&pos_offset);
|
||||||
|
stream->read(&trans);
|
||||||
|
stream->read(&flags);
|
||||||
|
|
||||||
|
expand_flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxAnimClipData::writeField(StringTableEntry fieldname, const char* value)
|
||||||
|
{
|
||||||
|
if (!Parent::writeField(fieldname, value))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// don't write the synonyms
|
||||||
|
if( fieldname == StringTable->insert("ignoreDisabled") )
|
||||||
|
return false;
|
||||||
|
if( fieldname == StringTable->insert("ignoreEnabled") )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAnimClipData::expand_flags()
|
||||||
|
{
|
||||||
|
ignore_disabled = ((flags & IGNORE_DISABLED) != 0);
|
||||||
|
ignore_enabled = ((flags & IGNORE_ENABLED) != 0);
|
||||||
|
lock_anim = ((flags & BLOCK_USER_CONTROL) != 0);
|
||||||
|
is_death_anim = ((flags & IS_DEATH_ANIM) != 0);
|
||||||
|
ignore_first_person = ((flags & IGNORE_FIRST_PERSON) != 0);
|
||||||
|
ignore_third_person = ((flags & IGNORE_THIRD_PERSON) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAnimClipData::merge_flags()
|
||||||
|
{
|
||||||
|
flags = (((ignore_disabled) ? IGNORE_DISABLED : 0) |
|
||||||
|
((ignore_enabled) ? IGNORE_ENABLED : 0) |
|
||||||
|
((lock_anim) ? BLOCK_USER_CONTROL : 0) |
|
||||||
|
((ignore_first_person) ? IGNORE_FIRST_PERSON : 0) |
|
||||||
|
((ignore_third_person) ? IGNORE_THIRD_PERSON : 0) |
|
||||||
|
((is_death_anim) ? IS_DEATH_ANIM : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
81
Engine/source/afx/ce/afxAnimClip.h
Normal file
81
Engine/source/afx/ce/afxAnimClip.h
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_ANIM_CLIP_H_
|
||||||
|
#define _AFX_ANIM_CLIP_H_
|
||||||
|
|
||||||
|
class afxAnimClipData : public GameBaseData
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
IGNORE_DISABLED = BIT(0),
|
||||||
|
IGNORE_ENABLED = BIT(1),
|
||||||
|
IS_DEATH_ANIM = BIT(2),
|
||||||
|
BLOCK_USER_CONTROL = BIT(3),
|
||||||
|
IGNORE_FIRST_PERSON = BIT(4),
|
||||||
|
IGNORE_THIRD_PERSON = BIT(5)
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringTableEntry clip_name;
|
||||||
|
F32 rate;
|
||||||
|
F32 pos_offset;
|
||||||
|
F32 trans;
|
||||||
|
U8 flags;
|
||||||
|
|
||||||
|
bool ignore_disabled;
|
||||||
|
bool ignore_enabled;
|
||||||
|
bool is_death_anim;
|
||||||
|
bool lock_anim;
|
||||||
|
bool ignore_first_person;
|
||||||
|
bool ignore_third_person;
|
||||||
|
|
||||||
|
void expand_flags();
|
||||||
|
void merge_flags();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxAnimClipData();
|
||||||
|
/*C*/ afxAnimClipData(const afxAnimClipData&, bool = false);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
virtual bool writeField(StringTableEntry fieldname, const char* value);
|
||||||
|
|
||||||
|
virtual void onStaticModified(const char* slotName, const char* newValue = NULL);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxAnimClipData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_ANIM_CLIP_H_
|
||||||
95
Engine/source/afx/ce/afxAnimLock.cpp
Normal file
95
Engine/source/afx/ce/afxAnimLock.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxAnimLock.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxAnimLockData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxAnimLockData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxAnimLockData,
|
||||||
|
"@brief A datablock that specifies an Animation Lock effect.\n\n"
|
||||||
|
|
||||||
|
"Animation Lock is used to temporarily lock out user-controlled Player actions, usually while an Animation Clip is "
|
||||||
|
"concurrently playing. Animation Clips can already do this, but must lock out user actions for the entire clip length. "
|
||||||
|
"Sometimes you only want to block user actions for a short section of a longer playing animation, such as the part where "
|
||||||
|
"the Player is thrown into the air from an impact. With Animation Lock, you can set a specific timespan for when user "
|
||||||
|
"actions are blocked, independent of any Animation Clip timing."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"The target of an Animation Lock is the constraint source object specified by the posConstraint field of the enclosing effect "
|
||||||
|
"wrapper. The target must be a Player, a subclass of Player, or an afxModel."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"The timing of the Animation Lock is determined by the timing fields of the enclosing effect wrapper."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"Locking behavior timing is set by fields of the enclosing effect wrapper, so afxAnimLockData does not require any fields. "
|
||||||
|
"However, TorqueScript syntax disallows the declaration of an empty datablock. Therefore, it is recommended that you set "
|
||||||
|
"a dynamic field named 'priority' to zero in the body of the datablock as a workaround to this limitation."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxAnimLockData::afxAnimLockData()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxAnimLockData)
|
||||||
|
|
||||||
|
void afxAnimLockData::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxAnimLockData::onAdd()
|
||||||
|
{
|
||||||
|
if (Parent::onAdd() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAnimLockData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAnimLockData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
48
Engine/source/afx/ce/afxAnimLock.h
Normal file
48
Engine/source/afx/ce/afxAnimLock.h
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_ANIM_LOCK_H_
|
||||||
|
#define _AFX_ANIM_LOCK_H_
|
||||||
|
|
||||||
|
class afxAnimLockData : public GameBaseData
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxAnimLockData();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxAnimLockData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_ANIM_LOCK_H_
|
||||||
121
Engine/source/afx/ce/afxAreaDamage.cpp
Normal file
121
Engine/source/afx/ce/afxAreaDamage.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxAreaDamage.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxAreaDamageData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxAreaDamageData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxAreaDamageData,
|
||||||
|
"@brief A datablock that specifies an Area Damage effect.\n\n"
|
||||||
|
|
||||||
|
"An Area Damage effect is useful for assigning area damage with unusual timing that must be synchronized with other "
|
||||||
|
"effects. Negative damage amounts can be used for healing effects."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"The primary difference between afxAreaDamageData and afxDamageData, which is also capable of inflicting area damage, "
|
||||||
|
"is that afxAreaDamageData effects calculate the area damage in C++ code rather than calling out to the script function "
|
||||||
|
"radiusDamage(). In cases where area damage needs to be inflicted repeatedly or in areas crowded with many targets, "
|
||||||
|
"afxAreaDamageData is likely to get better performance."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxAreaDamageData::afxAreaDamageData()
|
||||||
|
{
|
||||||
|
flavor = ST_NULLSTRING;
|
||||||
|
amount = 0;
|
||||||
|
radius = 0;
|
||||||
|
impulse = 0;
|
||||||
|
notify_damage_src = false;
|
||||||
|
exclude_cons_obj = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxAreaDamageData::afxAreaDamageData(const afxAreaDamageData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
flavor = other.flavor;
|
||||||
|
amount = other.amount;
|
||||||
|
radius = other.radius;
|
||||||
|
impulse = other.impulse;
|
||||||
|
notify_damage_src = other.notify_damage_src;
|
||||||
|
exclude_cons_obj = other.exclude_cons_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxAreaDamageData)
|
||||||
|
|
||||||
|
void afxAreaDamageData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("flavor", TypeString, myOffset(flavor),
|
||||||
|
"An arbitrary string which is passed as an argument to a spell's onDamage() script "
|
||||||
|
"method. It is used to classify a type of damage such as 'melee', 'magical', or "
|
||||||
|
"'fire'.");
|
||||||
|
addField("damage", TypeF32, myOffset(amount),
|
||||||
|
"An amount of area damage to inflict on a target. Objects within half the radius "
|
||||||
|
"receive full damage which then diminishes out to the full distance of the specified "
|
||||||
|
"radius.");
|
||||||
|
addField("radius", TypeF32, myOffset(radius),
|
||||||
|
"Radius centered at the effect position in which damage will be applied.");
|
||||||
|
addField("impulse", TypeF32, myOffset(impulse),
|
||||||
|
"Specifies an amount of force to apply to damaged objects. Objects within half the "
|
||||||
|
"radius receive full impulse which then diminishes out to the full distance of the "
|
||||||
|
"specified radius.");
|
||||||
|
addField("notifyDamageSource", TypeBool, myOffset(notify_damage_src),
|
||||||
|
"When true, the onInflictedAreaDamage() method of the damaged object will be called "
|
||||||
|
"to notify it of the damage. This is useful for starting some effects or action that "
|
||||||
|
"responds to the damage.");
|
||||||
|
addField("excludeConstraintObject", TypeBool, myOffset(exclude_cons_obj),
|
||||||
|
"When true, the object specified as the effect's primary position constraint will not "
|
||||||
|
"receive any damage.");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxAreaDamageData::onAdd()
|
||||||
|
{
|
||||||
|
if (Parent::onAdd() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAreaDamageData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAreaDamageData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
62
Engine/source/afx/ce/afxAreaDamage.h
Normal file
62
Engine/source/afx/ce/afxAreaDamage.h
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_AREA_DAMAGE_H_
|
||||||
|
#define _AFX_AREA_DAMAGE_H_
|
||||||
|
|
||||||
|
#include "afx/afxEffectDefs.h"
|
||||||
|
|
||||||
|
class afxAreaDamageData : public GameBaseData, public afxEffectDefs
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringTableEntry flavor;
|
||||||
|
|
||||||
|
F32 amount;
|
||||||
|
F32 radius;
|
||||||
|
F32 impulse;
|
||||||
|
bool notify_damage_src;
|
||||||
|
bool exclude_cons_obj;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxAreaDamageData();
|
||||||
|
/*C*/ afxAreaDamageData(const afxAreaDamageData&, bool = false);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxAreaDamageData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_AREA_DAMAGE_H_
|
||||||
246
Engine/source/afx/ce/afxAudioBank.cpp
Normal file
246
Engine/source/afx/ce/afxAudioBank.cpp
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "sim/netConnection.h"
|
||||||
|
#include "sfx/sfxDescription.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxAudioBank.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxAudioBank);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxAudioBank,
|
||||||
|
"@brief A datablock that specifies an Audio Bank effect.\n\n"
|
||||||
|
|
||||||
|
"afxAudioBank is very similar to the stock Torque SFXProfile datablock but it allows specification of up to 32 different sound "
|
||||||
|
"files. The sound that actually plays is determined by the playIndex field."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"afxAudioBank is most useful when used in combination with field substitutions, whereby a substitution statement "
|
||||||
|
"assigned to playIndex selects a different sound (perhaps randomly) each time the effect is used."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxAudioBank::afxAudioBank()
|
||||||
|
{
|
||||||
|
mPath = ST_NULLSTRING;
|
||||||
|
mDescriptionObjectID = 0;
|
||||||
|
mDescriptionObject = NULL;
|
||||||
|
mPreload = false;
|
||||||
|
play_index = -1;
|
||||||
|
|
||||||
|
for (S32 i = 0; i < 32; i++)
|
||||||
|
mFilenames[i] = ST_NULLSTRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxAudioBank::afxAudioBank(const afxAudioBank& other, bool temp_clone) : SimDataBlock(other, temp_clone)
|
||||||
|
{
|
||||||
|
mPath = other.mPath;
|
||||||
|
mDescriptionObject = other.mDescriptionObject;
|
||||||
|
mDescriptionObjectID = other.mDescriptionObjectID; // -- for pack/unpack of mDescriptionObject ptr
|
||||||
|
mPreload = other.mPreload;
|
||||||
|
play_index = other.play_index;
|
||||||
|
|
||||||
|
for (S32 i = 0; i < 32; i++)
|
||||||
|
mFilenames[i] = other.mFilenames[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
afxAudioBank::~afxAudioBank()
|
||||||
|
{
|
||||||
|
if (!isTempClone())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mDescriptionObject && mDescriptionObject->isTempClone())
|
||||||
|
{
|
||||||
|
delete mDescriptionObject;
|
||||||
|
mDescriptionObject = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
afxAudioBank* afxAudioBank::cloneAndPerformSubstitutions(const SimObject* owner, S32 index)
|
||||||
|
{
|
||||||
|
if (!owner)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
afxAudioBank* sub_profile_db = this;
|
||||||
|
|
||||||
|
SFXDescription* desc_db;
|
||||||
|
if (mDescriptionObject && mDescriptionObject->getSubstitutionCount() > 0)
|
||||||
|
{
|
||||||
|
SFXDescription* orig_db = mDescriptionObject;
|
||||||
|
desc_db = new SFXDescription(*orig_db, true);
|
||||||
|
orig_db->performSubstitutions(desc_db, owner, index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
desc_db = 0;
|
||||||
|
|
||||||
|
if (this->getSubstitutionCount() > 0 || desc_db)
|
||||||
|
{
|
||||||
|
sub_profile_db = new afxAudioBank(*this, true);
|
||||||
|
performSubstitutions(sub_profile_db, owner, index);
|
||||||
|
if (desc_db)
|
||||||
|
sub_profile_db->mDescriptionObject = desc_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sub_profile_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAudioBank::onPerformSubstitutions()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAudioBank::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("path", TypeFilename, Offset(mPath, afxAudioBank),
|
||||||
|
"A filesystem path to the folder containing the sound files specified by the "
|
||||||
|
"filenames[] field. All sound files used in a single AudioBank must be located in "
|
||||||
|
"the same folder.");
|
||||||
|
addField("filenames", TypeString, Offset(mFilenames, afxAudioBank), 32,
|
||||||
|
"Up to 32 names of sound files found in the path folder. The sound that is actually "
|
||||||
|
"played by an Audio Bank effect is determined by the playIndex field.");
|
||||||
|
addField("description", TYPEID<SFXDescription>(), Offset(mDescriptionObject, afxAudioBank),
|
||||||
|
"SFXDescription datablock to use with this set of sounds.");
|
||||||
|
addField("preload", TypeBool, Offset(mPreload, afxAudioBank),
|
||||||
|
"If set to true, file is pre-loaded, otherwise it is loaded on-demand.");
|
||||||
|
addField("playIndex", TypeS32, Offset(play_index, afxAudioBank),
|
||||||
|
"An array index that selects a sound to play from the filenames[] field. Values "
|
||||||
|
"outside of the range of assigned filename[] entries will not play any sound.");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxAudioBank::preload(bool server, String &errorStr)
|
||||||
|
{
|
||||||
|
if(!Parent::preload(server, errorStr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxAudioBank::onAdd()
|
||||||
|
{
|
||||||
|
if (!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!mDescriptionObject && mDescriptionObjectID)
|
||||||
|
Sim::findObject(mDescriptionObjectID , mDescriptionObject);
|
||||||
|
|
||||||
|
// if this is client side, make sure that description is as well
|
||||||
|
if(mDescriptionObject)
|
||||||
|
{ // client side dataBlock id's are not in the dataBlock id range
|
||||||
|
if (getId() >= DataBlockObjectIdFirst && getId() <= DataBlockObjectIdLast)
|
||||||
|
{
|
||||||
|
SimObjectId pid = mDescriptionObject->getId();
|
||||||
|
if (pid < DataBlockObjectIdFirst || pid > DataBlockObjectIdLast)
|
||||||
|
{
|
||||||
|
Con::errorf(ConsoleLogEntry::General,"afxAudioBank: data dataBlock not networkable (use datablock to create).");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAudioBank::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
if (stream->writeFlag(mDescriptionObject))
|
||||||
|
stream->writeRangedU32(mDescriptionObject->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
|
||||||
|
/*
|
||||||
|
char buffer[256];
|
||||||
|
if(!mFilename)
|
||||||
|
buffer[0] = 0;
|
||||||
|
else
|
||||||
|
dStrcpy(buffer, mFilename);
|
||||||
|
stream->writeString(buffer);
|
||||||
|
*/
|
||||||
|
|
||||||
|
stream->writeString(mPath);
|
||||||
|
|
||||||
|
for (S32 i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
stream->writeString(mFilenames[i]);
|
||||||
|
if (mFilenames[i] == ST_NULLSTRING)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->writeFlag(mPreload);
|
||||||
|
|
||||||
|
if (stream->writeFlag(play_index >= 0 && play_index < 32))
|
||||||
|
stream->writeInt(play_index, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxAudioBank::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
if (stream->readFlag()) // AudioDescription
|
||||||
|
{
|
||||||
|
SimObjectId id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||||
|
mDescriptionObjectID = id;
|
||||||
|
Sim::findObject(id, mDescriptionObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filename
|
||||||
|
/*
|
||||||
|
char buffer[256];
|
||||||
|
stream->readString(buffer);
|
||||||
|
mFilename = StringTable->insert(buffer);
|
||||||
|
*/
|
||||||
|
|
||||||
|
char buffer[256];
|
||||||
|
|
||||||
|
stream->readString(buffer);
|
||||||
|
mPath = StringTable->insert(buffer);
|
||||||
|
|
||||||
|
for (S32 i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
stream->readString(buffer);
|
||||||
|
mFilenames[i] = StringTable->insert(buffer);
|
||||||
|
if (mFilenames[i] == ST_NULLSTRING)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPreload = stream->readFlag(); // Preload
|
||||||
|
|
||||||
|
if (stream->readFlag())
|
||||||
|
play_index = stream->readInt(5);
|
||||||
|
else
|
||||||
|
play_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
67
Engine/source/afx/ce/afxAudioBank.h
Normal file
67
Engine/source/afx/ce/afxAudioBank.h
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_AUDIO_BANK_H_
|
||||||
|
#define _AFX_AUDIO_BANK_H_
|
||||||
|
|
||||||
|
class SFXDescription;
|
||||||
|
|
||||||
|
class afxAudioBank: public SimDataBlock
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef SimDataBlock Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SFXDescription* mDescriptionObject;
|
||||||
|
U32 mDescriptionObjectID;
|
||||||
|
StringTableEntry mPath;
|
||||||
|
StringTableEntry mFilenames[32];
|
||||||
|
bool mPreload;
|
||||||
|
S32 play_index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxAudioBank();
|
||||||
|
/*C*/ afxAudioBank(const afxAudioBank&, bool = false);
|
||||||
|
/*D*/ ~afxAudioBank();
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream* stream);
|
||||||
|
virtual void unpackData(BitStream* stream);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
afxAudioBank* cloneAndPerformSubstitutions(const SimObject*, S32 index=0);
|
||||||
|
virtual void onPerformSubstitutions();
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxAudioBank);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_AUDIO_BANK_H_
|
||||||
294
Engine/source/afx/ce/afxBillboard.cpp
Normal file
294
Engine/source/afx/ce/afxBillboard.cpp
Normal file
|
|
@ -0,0 +1,294 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "gfx/gfxAPI.h"
|
||||||
|
#include "math/mathIO.h"
|
||||||
|
|
||||||
|
#include "afx/afxChoreographer.h"
|
||||||
|
#include "afx/ce/afxBillboard.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxBillboardData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxBillboardData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxBillboardData,
|
||||||
|
"@brief A datablock that specifies a Billboard effect.\n\n"
|
||||||
|
|
||||||
|
"A Billboard effect is a textured quadrangle which is always aligned to face towards the camera. It is much like a single "
|
||||||
|
"static particle and is rendered in a similar fashion."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxBillboardData::afxBillboardData()
|
||||||
|
{
|
||||||
|
color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
txr_name = ST_NULLSTRING;
|
||||||
|
dimensions.set(1.0f, 1.0f);
|
||||||
|
texCoords[0].set(0.0f, 0.0f);
|
||||||
|
texCoords[1].set(0.0f, 1.0f);
|
||||||
|
texCoords[2].set(1.0f, 1.0f);
|
||||||
|
texCoords[3].set(1.0f, 0.0f);
|
||||||
|
blendStyle = BlendUndefined;
|
||||||
|
srcBlendFactor = BLEND_UNDEFINED;
|
||||||
|
dstBlendFactor = BLEND_UNDEFINED;
|
||||||
|
texFunc = TexFuncModulate;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxBillboardData::afxBillboardData(const afxBillboardData& other, bool temp_clone)
|
||||||
|
: GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
color = other.color;
|
||||||
|
txr_name = other.txr_name;
|
||||||
|
txr = other.txr;
|
||||||
|
dimensions = other.dimensions;
|
||||||
|
texCoords[0] = other.texCoords[0];
|
||||||
|
texCoords[1] = other.texCoords[1];
|
||||||
|
texCoords[2] = other.texCoords[2];
|
||||||
|
texCoords[3] = other.texCoords[3];
|
||||||
|
blendStyle = other.blendStyle;
|
||||||
|
srcBlendFactor = other.srcBlendFactor;
|
||||||
|
dstBlendFactor = other.dstBlendFactor;
|
||||||
|
texFunc = other.texFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxBillboardData)
|
||||||
|
|
||||||
|
extern EnumTable srcBlendFactorTable;
|
||||||
|
extern EnumTable dstBlendFactorTable;
|
||||||
|
|
||||||
|
ImplementEnumType( afxBillboard_BlendStyle, "Possible blending types.\n" "@ingroup afxBillboard\n\n" )
|
||||||
|
{ afxBillboardData::BlendNormal, "NORMAL", "..." },
|
||||||
|
{ afxBillboardData::BlendAdditive, "ADDITIVE", "..." },
|
||||||
|
{ afxBillboardData::BlendSubtractive, "SUBTRACTIVE", "..." },
|
||||||
|
{ afxBillboardData::BlendPremultAlpha, "PREMULTALPHA", "..." },
|
||||||
|
EndImplementEnumType;
|
||||||
|
|
||||||
|
ImplementEnumType( afxBillboard_TexFuncType, "Possible texture function types.\n" "@ingroup afxBillboard\n\n" )
|
||||||
|
{ afxBillboardData::TexFuncReplace, "replace", "..." },
|
||||||
|
{ afxBillboardData::TexFuncModulate, "modulate", "..." },
|
||||||
|
{ afxBillboardData::TexFuncAdd, "add", "..." },
|
||||||
|
EndImplementEnumType;
|
||||||
|
|
||||||
|
void afxBillboardData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("color", TypeColorF, myOffset(color),
|
||||||
|
"The color assigned to the quadrangle geometry. The way it combines with the given "
|
||||||
|
"texture varies according to the setting of the textureFunction field.");
|
||||||
|
addField("texture", TypeFilename, myOffset(txr_name),
|
||||||
|
"An image to use as the billboard's texture.");
|
||||||
|
addField("dimensions", TypePoint2F, myOffset(dimensions),
|
||||||
|
"A value-pair that specifies the horizontal and vertical dimensions of the billboard "
|
||||||
|
"in scene units.");
|
||||||
|
addField("textureCoords", TypePoint2F, myOffset(texCoords), 4,
|
||||||
|
"An array of four value-pairs that specify the UV texture coordinates for the four "
|
||||||
|
"corners of the billboard's quadrangle.");
|
||||||
|
|
||||||
|
addField("blendStyle", TYPEID<afxBillboardData::BlendStyle>(), myOffset(blendStyle),
|
||||||
|
"Selects a common blend factor preset. When set to 'user', srcBlendFactor and "
|
||||||
|
"dstBlendFactor can be used to set additional blend factor combinations.\n"
|
||||||
|
"Possible values: normal, additive, subtractive, premultalpha, or user.");
|
||||||
|
addField("srcBlendFactor", TYPEID<GFXBlend>(), myOffset(srcBlendFactor),
|
||||||
|
"Specifies source blend factor when blendStyle is set to 'user'.\n"
|
||||||
|
"Possible values: GFXBlendZero, GFXBlendOne, GFXBlendDestColor, GFXBlendInvDestColor, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha, GFXBlendDestAlpha, GFXBlendInvDestAlpha, or GFXBlendSrcAlphaSat");
|
||||||
|
addField("dstBlendFactor", TYPEID<GFXBlend>(), myOffset(dstBlendFactor),
|
||||||
|
"Specifies destination blend factor when blendStyle is set to 'user'.\n"
|
||||||
|
"Possible values: GFXBlendZero, GFXBlendOne, GFXBlendSrcColor, GFXBlendInvSrcColor, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha, GFXBlendDestAlpha, or GFXBlendInvDestAlpha");
|
||||||
|
|
||||||
|
addField("textureFunction", TYPEID<afxBillboardData::TexFuncType>(), myOffset(texFunc),
|
||||||
|
"Selects a texture function that determines how the texture pixels are combined "
|
||||||
|
"with the shaded color of the billboard's quadrangle geometry.\n"
|
||||||
|
"Possible values: replace, modulate, or add.");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxBillboardData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
stream->write(color);
|
||||||
|
stream->writeString(txr_name);
|
||||||
|
mathWrite(*stream, dimensions);
|
||||||
|
mathWrite(*stream, texCoords[0]);
|
||||||
|
mathWrite(*stream, texCoords[1]);
|
||||||
|
mathWrite(*stream, texCoords[2]);
|
||||||
|
mathWrite(*stream, texCoords[3]);
|
||||||
|
|
||||||
|
stream->writeInt(srcBlendFactor, 4);
|
||||||
|
stream->writeInt(dstBlendFactor, 4);
|
||||||
|
stream->writeInt(texFunc, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxBillboardData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
stream->read(&color);
|
||||||
|
txr_name = stream->readSTString();
|
||||||
|
txr = GFXTexHandle();
|
||||||
|
mathRead(*stream, &dimensions);
|
||||||
|
mathRead(*stream, &texCoords[0]);
|
||||||
|
mathRead(*stream, &texCoords[1]);
|
||||||
|
mathRead(*stream, &texCoords[2]);
|
||||||
|
mathRead(*stream, &texCoords[3]);
|
||||||
|
|
||||||
|
srcBlendFactor = (GFXBlend) stream->readInt(4);
|
||||||
|
dstBlendFactor = (GFXBlend) stream->readInt(4);
|
||||||
|
texFunc = stream->readInt(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxBillboardData::preload(bool server, String &errorStr)
|
||||||
|
{
|
||||||
|
if (!Parent::preload(server, errorStr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
if (txr_name && txr_name[0] != '\0')
|
||||||
|
{
|
||||||
|
txr.set(txr_name, &GFXStaticTextureSRGBProfile, "Billboard Texture");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if blend-style is set to User, check for defined blend-factors
|
||||||
|
if (blendStyle == BlendUser && (srcBlendFactor == BLEND_UNDEFINED || dstBlendFactor == BLEND_UNDEFINED))
|
||||||
|
{
|
||||||
|
blendStyle = BlendUndefined;
|
||||||
|
Con::warnf(ConsoleLogEntry::General, "afxBillboardData(%s) incomplete blend factor specification.", getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// silently switch Undefined blend-style to User if blend factors are both defined
|
||||||
|
if (blendStyle == BlendUndefined && srcBlendFactor != BLEND_UNDEFINED && dstBlendFactor != BLEND_UNDEFINED)
|
||||||
|
{
|
||||||
|
blendStyle = BlendUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set pre-defined blend-factors
|
||||||
|
switch (blendStyle)
|
||||||
|
{
|
||||||
|
case BlendNormal:
|
||||||
|
srcBlendFactor = GFXBlendSrcAlpha;
|
||||||
|
dstBlendFactor = GFXBlendInvSrcAlpha;
|
||||||
|
break;
|
||||||
|
case BlendSubtractive:
|
||||||
|
srcBlendFactor = GFXBlendZero;
|
||||||
|
dstBlendFactor = GFXBlendInvSrcColor;
|
||||||
|
break;
|
||||||
|
case BlendPremultAlpha:
|
||||||
|
srcBlendFactor = GFXBlendOne;
|
||||||
|
dstBlendFactor = GFXBlendInvSrcAlpha;
|
||||||
|
break;
|
||||||
|
case BlendUser:
|
||||||
|
break;
|
||||||
|
case BlendAdditive:
|
||||||
|
srcBlendFactor = GFXBlendSrcAlpha;
|
||||||
|
dstBlendFactor = GFXBlendOne;
|
||||||
|
break;
|
||||||
|
case BlendUndefined:
|
||||||
|
default:
|
||||||
|
blendStyle = BlendNormal;
|
||||||
|
srcBlendFactor = GFXBlendSrcAlpha;
|
||||||
|
dstBlendFactor = GFXBlendInvSrcAlpha;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxBillboard
|
||||||
|
|
||||||
|
IMPLEMENT_CO_NETOBJECT_V1(afxBillboard);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxBillboard,
|
||||||
|
"@brief A Billboard effect as defined by an afxBillboardData datablock.\n\n"
|
||||||
|
|
||||||
|
"A Billboard effect is a textured quadrangle which is always aligned to "
|
||||||
|
"face towards the camera. It is much like a single static particle and is rendered "
|
||||||
|
"in a similar fashion.\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxBillboard::afxBillboard()
|
||||||
|
{
|
||||||
|
mNetFlags.clear();
|
||||||
|
mNetFlags.set(IsGhost);
|
||||||
|
|
||||||
|
mDataBlock = 0;
|
||||||
|
fade_amt = 1.0f;
|
||||||
|
is_visible = true;
|
||||||
|
sort_priority = 0;
|
||||||
|
live_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
afxBillboard::~afxBillboard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
bool afxBillboard::onNewDataBlock(GameBaseData* dptr, bool reload)
|
||||||
|
{
|
||||||
|
mDataBlock = dynamic_cast<afxBillboardData*>(dptr);
|
||||||
|
if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
live_color = mDataBlock->color;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxBillboard::onAdd()
|
||||||
|
{
|
||||||
|
if(!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
F32 width = mDataBlock->dimensions.x * 0.5f;
|
||||||
|
F32 height = mDataBlock->dimensions.y * 0.5f;
|
||||||
|
mObjBox = Box3F(Point3F(-width, -0.01f, -height), Point3F(width, 0.01f, height));
|
||||||
|
|
||||||
|
addToScene();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxBillboard::onRemove()
|
||||||
|
{
|
||||||
|
removeFromScene();
|
||||||
|
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
131
Engine/source/afx/ce/afxBillboard.h
Normal file
131
Engine/source/afx/ce/afxBillboard.h
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_BILLBOARD_H_
|
||||||
|
#define _AFX_BILLBOARD_H_
|
||||||
|
|
||||||
|
#include "afx/afxEffectDefs.h"
|
||||||
|
|
||||||
|
#define BLEND_UNDEFINED GFXBlend_COUNT
|
||||||
|
|
||||||
|
class afxBillboardData : public GameBaseData, public afxEffectDefs
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// This enum specifies common blend settings with predefined values
|
||||||
|
// for src/dst blend factors.
|
||||||
|
enum BlendStyle {
|
||||||
|
BlendUndefined,
|
||||||
|
BlendNormal,
|
||||||
|
BlendAdditive,
|
||||||
|
BlendSubtractive,
|
||||||
|
BlendPremultAlpha,
|
||||||
|
BlendUser,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TexFuncType {
|
||||||
|
TexFuncReplace,
|
||||||
|
TexFuncModulate,
|
||||||
|
TexFuncAdd,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringTableEntry txr_name;
|
||||||
|
GFXTexHandle txr;
|
||||||
|
|
||||||
|
LinearColorF color;
|
||||||
|
Point2F texCoords[4];
|
||||||
|
Point2F dimensions;
|
||||||
|
S32 blendStyle;
|
||||||
|
GFXBlend srcBlendFactor;
|
||||||
|
GFXBlend dstBlendFactor;
|
||||||
|
S32 texFunc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxBillboardData();
|
||||||
|
/*C*/ afxBillboardData(const afxBillboardData&, bool = false);
|
||||||
|
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
bool preload(bool server, String &errorStr);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxBillboardData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef afxBillboardData::BlendStyle afxBillboard_BlendStyle;
|
||||||
|
DefineEnumType( afxBillboard_BlendStyle );
|
||||||
|
|
||||||
|
typedef afxBillboardData::TexFuncType afxBillboard_TexFuncType;
|
||||||
|
DefineEnumType( afxBillboard_TexFuncType );
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxBillboard
|
||||||
|
|
||||||
|
class afxBillboard : public GameBase, public afxEffectDefs
|
||||||
|
{
|
||||||
|
typedef GameBase Parent;
|
||||||
|
friend class afxEA_Billboard;
|
||||||
|
|
||||||
|
private:
|
||||||
|
afxBillboardData* mDataBlock;
|
||||||
|
|
||||||
|
F32 fade_amt;
|
||||||
|
bool is_visible;
|
||||||
|
S8 sort_priority;
|
||||||
|
LinearColorF live_color;
|
||||||
|
|
||||||
|
GFXStateBlockRef normal_sb;
|
||||||
|
GFXStateBlockRef reflected_sb;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxBillboard();
|
||||||
|
/*D*/ ~afxBillboard();
|
||||||
|
|
||||||
|
virtual bool onNewDataBlock(GameBaseData* dptr, bool reload);
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
|
||||||
|
void setFadeAmount(F32 amt) { fade_amt = amt; }
|
||||||
|
void setSortPriority(S8 priority) { sort_priority = priority; }
|
||||||
|
void setVisibility(bool flag) { is_visible = flag; }
|
||||||
|
|
||||||
|
virtual void prepRenderImage(SceneRenderState*);
|
||||||
|
|
||||||
|
void _renderBillboard(ObjectRenderInst*, SceneRenderState*, BaseMatInstance*);
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxBillboard);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_BILLBOARD_H_
|
||||||
145
Engine/source/afx/ce/afxBillboard_T3D.cpp
Normal file
145
Engine/source/afx/ce/afxBillboard_T3D.cpp
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "gfx/primBuilder.h"
|
||||||
|
|
||||||
|
#include "afx/afxChoreographer.h"
|
||||||
|
#include "afx/ce/afxBillboard.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
void afxBillboard::prepRenderImage(SceneRenderState* state)
|
||||||
|
{
|
||||||
|
if (!is_visible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||||
|
ri->renderDelegate.bind(this, &afxBillboard::_renderBillboard);
|
||||||
|
ri->type = RenderPassManager::RIT_ObjectTranslucent;
|
||||||
|
ri->translucentSort = true;
|
||||||
|
ri->defaultKey = (U32)(dsize_t)mDataBlock;
|
||||||
|
ri->sortDistSq = getWorldBox().getSqDistanceToPoint( state->getCameraPosition() );
|
||||||
|
state->getRenderPass()->addInst(ri);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxBillboard::_renderBillboard(ObjectRenderInst *ri, SceneRenderState* state, BaseMatInstance* overrideMat)
|
||||||
|
{
|
||||||
|
if (overrideMat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// predraw
|
||||||
|
if (normal_sb.isNull())
|
||||||
|
{
|
||||||
|
GFXStateBlockDesc desc;
|
||||||
|
|
||||||
|
// Culling -- it's a billboard, so no backfaces
|
||||||
|
desc.setCullMode(GFXCullCW);
|
||||||
|
|
||||||
|
// Blending
|
||||||
|
desc.setBlend(true, mDataBlock->srcBlendFactor, mDataBlock->dstBlendFactor);
|
||||||
|
desc.alphaTestEnable = (desc.blendSrc == GFXBlendSrcAlpha &&
|
||||||
|
(desc.blendDest == GFXBlendInvSrcAlpha || desc.blendDest == GFXBlendOne));
|
||||||
|
desc.alphaTestRef = 1;
|
||||||
|
desc.alphaTestFunc = GFXCmpGreaterEqual;
|
||||||
|
|
||||||
|
desc.setZReadWrite(true);
|
||||||
|
desc.zFunc = GFXCmpLessEqual;
|
||||||
|
desc.zWriteEnable = false;
|
||||||
|
|
||||||
|
desc.samplersDefined = true;
|
||||||
|
switch (mDataBlock->texFunc)
|
||||||
|
{
|
||||||
|
case afxBillboardData::TexFuncReplace:
|
||||||
|
desc.samplers[0].textureColorOp = GFXTOPDisable;
|
||||||
|
break;
|
||||||
|
case afxBillboardData::TexFuncModulate:
|
||||||
|
desc.samplers[0].textureColorOp = GFXTOPModulate;
|
||||||
|
break;
|
||||||
|
case afxBillboardData::TexFuncAdd:
|
||||||
|
desc.samplers[0].textureColorOp = GFXTOPAdd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.samplers[1].textureColorOp = GFXTOPDisable;
|
||||||
|
|
||||||
|
normal_sb = GFX->createStateBlock(desc);
|
||||||
|
|
||||||
|
desc.setCullMode(GFXCullCCW);
|
||||||
|
reflected_sb = GFX->createStateBlock(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->isReflectPass())
|
||||||
|
GFX->setStateBlock(reflected_sb);
|
||||||
|
else
|
||||||
|
GFX->setStateBlock(normal_sb);
|
||||||
|
|
||||||
|
GFXTransformSaver saver;
|
||||||
|
GFX->multWorld(getRenderTransform());
|
||||||
|
|
||||||
|
GFX->setTexture(0, mDataBlock->txr);
|
||||||
|
|
||||||
|
MatrixF worldmod = GFX->getWorldMatrix();
|
||||||
|
MatrixF viewmod = GFX->getViewMatrix();
|
||||||
|
|
||||||
|
Point4F Position;
|
||||||
|
MatrixF ModelView;
|
||||||
|
ModelView.mul(viewmod, worldmod);
|
||||||
|
ModelView.getColumn(3, &Position);
|
||||||
|
ModelView.identity();
|
||||||
|
ModelView.setColumn(3, Position);
|
||||||
|
|
||||||
|
GFX->setWorldMatrix(ModelView);
|
||||||
|
MatrixF ident;
|
||||||
|
ident.identity();
|
||||||
|
GFX->setViewMatrix(ident);
|
||||||
|
|
||||||
|
F32 width = mDataBlock->dimensions.x * 0.5f * mObjScale.x;
|
||||||
|
F32 height = mDataBlock->dimensions.y * 0.5f * mObjScale.z;
|
||||||
|
|
||||||
|
Point3F points[4];
|
||||||
|
points[0].set( width, 0.0f, -height);
|
||||||
|
points[1].set(-width, 0.0f, -height);
|
||||||
|
points[2].set(-width, 0.0f, height);
|
||||||
|
points[3].set( width, 0.0f, height);
|
||||||
|
|
||||||
|
PrimBuild::begin(GFXTriangleStrip, 4);
|
||||||
|
{
|
||||||
|
PrimBuild::color4f(live_color.red, live_color.green, live_color.blue, live_color.alpha*fade_amt);
|
||||||
|
PrimBuild::texCoord2f(mDataBlock->texCoords[1].x, mDataBlock->texCoords[1].y);
|
||||||
|
PrimBuild::vertex3fv(points[1]);
|
||||||
|
PrimBuild::texCoord2f(mDataBlock->texCoords[2].x, mDataBlock->texCoords[2].y);
|
||||||
|
PrimBuild::vertex3fv(points[0]);
|
||||||
|
PrimBuild::texCoord2f(mDataBlock->texCoords[0].x, mDataBlock->texCoords[0].y);
|
||||||
|
PrimBuild::vertex3fv(points[2]);
|
||||||
|
PrimBuild::texCoord2f(mDataBlock->texCoords[3].x, mDataBlock->texCoords[3].y);
|
||||||
|
PrimBuild::vertex3fv(points[3]);
|
||||||
|
}
|
||||||
|
PrimBuild::end();
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
132
Engine/source/afx/ce/afxCameraPuppet.cpp
Normal file
132
Engine/source/afx/ce/afxCameraPuppet.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "math/mathIO.h"
|
||||||
|
|
||||||
|
#include "afx/afxChoreographer.h"
|
||||||
|
#include "afx/ce/afxCameraPuppet.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxCameraPuppetData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxCameraPuppetData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxCameraPuppetData,
|
||||||
|
"@brief A datablock that specifies a Camera Puppet effect.\n\n"
|
||||||
|
|
||||||
|
"A Camera Puppet effect is used to control the position and orientation of the camera using the AFX constraint system. "
|
||||||
|
"Camera Puppet effects are useful for creating small cut-scenes and can add a lot of visual drama to a spell or effectron "
|
||||||
|
"effect."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"Effective use of Camera Puppet effects require a fairly advanced understanding of how Torque cameras work in a "
|
||||||
|
"server-client context. Care must be taken to prevent client cameras from drifting too far out of sync from the server camera. "
|
||||||
|
"Otherwise, obvious discontinuities in the motion will result when the Camera Puppet ends and control is restored to the "
|
||||||
|
"server camera. Scoping problems can also result if a client camera is moved to a location that is inconsistent with the "
|
||||||
|
"scene scoping done by the server camera."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"Often it is useful to manage camera controlling in an isolated effectron rather than directly incorporated into a magic-spell. "
|
||||||
|
"This way the camera controlling effectron can target the specific client associated with the spellcaster. The spellcasting "
|
||||||
|
"player observes the spell in a dramatic cut-scene-like fashion while other players continue to observe from their own "
|
||||||
|
"viewing locations."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxCameraPuppetData::afxCameraPuppetData()
|
||||||
|
{
|
||||||
|
cam_spec = ST_NULLSTRING;
|
||||||
|
networking = SERVER_AND_CLIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxCameraPuppetData::afxCameraPuppetData(const afxCameraPuppetData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
cam_spec = other.cam_spec;
|
||||||
|
networking = other.networking;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxCameraPuppetData)
|
||||||
|
|
||||||
|
void afxCameraPuppetData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("cameraSpec", TypeString, myOffset(cam_spec),
|
||||||
|
"This field is like the effect-wrapper fields for specifying constraint sources, "
|
||||||
|
"but here it specifies a target for the camera-puppet effect.");
|
||||||
|
addField("networking", TypeS8, myOffset(networking),
|
||||||
|
"Specifies the networking model used for the camerapuppet effect. The effect can "
|
||||||
|
"puppet just the server camera, just the client camera, or both.\n"
|
||||||
|
"Possible values: $AFX::SERVER_ONLY, $AFX::CLIENT_ONLY, or $AFX::SERVER_AND_CLIENT.");
|
||||||
|
|
||||||
|
// disallow some field substitutions
|
||||||
|
disableFieldSubstitutions("cameraSpec");
|
||||||
|
disableFieldSubstitutions("networking");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxCameraPuppetData::onAdd()
|
||||||
|
{
|
||||||
|
if (Parent::onAdd() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool runs_on_s = ((networking & (SERVER_ONLY | SERVER_AND_CLIENT)) != 0);
|
||||||
|
bool runs_on_c = ((networking & (CLIENT_ONLY | SERVER_AND_CLIENT)) != 0);
|
||||||
|
cam_def.parseSpec(cam_spec, runs_on_s, runs_on_c);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxCameraPuppetData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
stream->writeString(cam_spec);
|
||||||
|
stream->write(networking);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxCameraPuppetData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
cam_spec = stream->readSTString();
|
||||||
|
stream->read(&networking);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxCameraPuppetData::gather_cons_defs(Vector<afxConstraintDef>& defs)
|
||||||
|
{
|
||||||
|
if (cam_def.isDefined())
|
||||||
|
defs.push_back(cam_def);
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
64
Engine/source/afx/ce/afxCameraPuppet.h
Normal file
64
Engine/source/afx/ce/afxCameraPuppet.h
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_CAMERA_PUPPET_H_
|
||||||
|
#define _AFX_CAMERA_PUPPET_H_
|
||||||
|
|
||||||
|
#include "afx/ce/afxComponentEffect.h"
|
||||||
|
#include "afx/afxEffectDefs.h"
|
||||||
|
#include "afx/afxConstraint.h"
|
||||||
|
|
||||||
|
class afxCameraPuppetData : public GameBaseData, public afxEffectDefs, public afxComponentEffectData
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringTableEntry cam_spec;
|
||||||
|
afxConstraintDef cam_def;
|
||||||
|
|
||||||
|
U8 networking;
|
||||||
|
|
||||||
|
virtual void gather_cons_defs(Vector<afxConstraintDef>& defs);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxCameraPuppetData();
|
||||||
|
/*C*/ afxCameraPuppetData(const afxCameraPuppetData&, bool = false);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxCameraPuppetData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_CAMERA_PUPPET_H_
|
||||||
118
Engine/source/afx/ce/afxCameraShake.cpp
Normal file
118
Engine/source/afx/ce/afxCameraShake.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxCameraShake.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxCameraShakeData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxCameraShakeData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxCameraShakeData,
|
||||||
|
"@brief A datablock that specifies a Camera Shake effect.\n\n"
|
||||||
|
|
||||||
|
"Camera Shake internally utilizes the standard Torque CameraShake class to implement a shaken camera effect."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxCameraShakeData::afxCameraShakeData()
|
||||||
|
{
|
||||||
|
camShakeFreq.set( 10.0, 10.0, 10.0 );
|
||||||
|
camShakeAmp.set( 1.0, 1.0, 1.0 );
|
||||||
|
camShakeRadius = 10.0;
|
||||||
|
camShakeFalloff = 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxCameraShakeData::afxCameraShakeData(const afxCameraShakeData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
camShakeFreq = other.camShakeFreq;
|
||||||
|
camShakeAmp = other.camShakeAmp;
|
||||||
|
camShakeRadius = other.camShakeRadius;
|
||||||
|
camShakeFalloff = other.camShakeFalloff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxCameraShakeData)
|
||||||
|
|
||||||
|
void afxCameraShakeData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("frequency", TypePoint3F, Offset(camShakeFreq, afxCameraShakeData),
|
||||||
|
"The camera shake frequencies for all three axes: X, Y, Z.");
|
||||||
|
addField("amplitude", TypePoint3F, Offset(camShakeAmp, afxCameraShakeData),
|
||||||
|
"The camera shake amplitudes for all three axes: X, Y, Z.");
|
||||||
|
addField("radius", TypeF32, Offset(camShakeRadius, afxCameraShakeData),
|
||||||
|
"Radius about the effect position in which shaking will be applied.");
|
||||||
|
addField("falloff", TypeF32, Offset(camShakeFalloff, afxCameraShakeData),
|
||||||
|
"Magnitude by which shaking decreases over distance to radius.");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxCameraShakeData::onAdd()
|
||||||
|
{
|
||||||
|
if (Parent::onAdd() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxCameraShakeData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
stream->write(camShakeFreq.x);
|
||||||
|
stream->write(camShakeFreq.y);
|
||||||
|
stream->write(camShakeFreq.z);
|
||||||
|
stream->write(camShakeAmp.x);
|
||||||
|
stream->write(camShakeAmp.y);
|
||||||
|
stream->write(camShakeAmp.z);
|
||||||
|
stream->write(camShakeRadius);
|
||||||
|
stream->write(camShakeFalloff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxCameraShakeData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
stream->read(&camShakeFreq.x);
|
||||||
|
stream->read(&camShakeFreq.y);
|
||||||
|
stream->read(&camShakeFreq.z);
|
||||||
|
stream->read(&camShakeAmp.x);
|
||||||
|
stream->read(&camShakeAmp.y);
|
||||||
|
stream->read(&camShakeAmp.z);
|
||||||
|
stream->read(&camShakeRadius);
|
||||||
|
stream->read(&camShakeFalloff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
57
Engine/source/afx/ce/afxCameraShake.h
Normal file
57
Engine/source/afx/ce/afxCameraShake.h
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_CAMERA_SHAKE_H_
|
||||||
|
#define _AFX_CAMERA_SHAKE_H_
|
||||||
|
|
||||||
|
class afxCameraShakeData : public GameBaseData
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VectorF camShakeFreq;
|
||||||
|
VectorF camShakeAmp;
|
||||||
|
F32 camShakeRadius;
|
||||||
|
F32 camShakeFalloff;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxCameraShakeData();
|
||||||
|
/*C*/ afxCameraShakeData(const afxCameraShakeData&, bool = false);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxCameraShakeData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_CAMERA_SHAKE_H_
|
||||||
103
Engine/source/afx/ce/afxCollisionEvent.cpp
Normal file
103
Engine/source/afx/ce/afxCollisionEvent.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxCollisionEvent.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxCollisionEventData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxCollisionEventData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxCollisionEventData,
|
||||||
|
"@brief A datablock that specifies a Collision Event effect.\n\n"
|
||||||
|
|
||||||
|
"MORE NEEDED HERE.\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxCollisionEventData::afxCollisionEventData()
|
||||||
|
{
|
||||||
|
method_name = ST_NULLSTRING;
|
||||||
|
script_data = ST_NULLSTRING;
|
||||||
|
gen_trigger = false;
|
||||||
|
trigger_bit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxCollisionEventData::afxCollisionEventData(const afxCollisionEventData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
method_name = other.method_name;
|
||||||
|
script_data = other.script_data;
|
||||||
|
gen_trigger = other.gen_trigger;
|
||||||
|
trigger_bit = other.trigger_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxCollisionEventData)
|
||||||
|
|
||||||
|
void afxCollisionEventData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("methodName", TypeString, myOffset(method_name),
|
||||||
|
"...");
|
||||||
|
addField("scriptData", TypeString, myOffset(script_data),
|
||||||
|
"...");
|
||||||
|
addField("generateTrigger", TypeBool, myOffset(gen_trigger),
|
||||||
|
"...");
|
||||||
|
addField("triggerBit", TypeS8, myOffset(trigger_bit),
|
||||||
|
"...");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxCollisionEventData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
stream->writeString(method_name);
|
||||||
|
stream->writeString(script_data);
|
||||||
|
if (stream->writeFlag(gen_trigger))
|
||||||
|
stream->write(trigger_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxCollisionEventData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
method_name = stream->readSTString();
|
||||||
|
script_data = stream->readSTString();
|
||||||
|
gen_trigger = stream->readFlag();
|
||||||
|
if (gen_trigger)
|
||||||
|
stream->read(&trigger_bit);
|
||||||
|
else
|
||||||
|
trigger_bit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
59
Engine/source/afx/ce/afxCollisionEvent.h
Normal file
59
Engine/source/afx/ce/afxCollisionEvent.h
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_COLLISION_EVENT_H_
|
||||||
|
#define _AFX_COLLISION_EVENT_H_
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxCollisionEventData
|
||||||
|
|
||||||
|
struct afxCollisionEventData : public GameBaseData
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringTableEntry method_name;
|
||||||
|
StringTableEntry script_data;
|
||||||
|
bool gen_trigger;
|
||||||
|
U8 trigger_bit;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxCollisionEventData();
|
||||||
|
/*C*/ afxCollisionEventData(const afxCollisionEventData&, bool = false);
|
||||||
|
|
||||||
|
void packData(BitStream* stream);
|
||||||
|
void unpackData(BitStream* stream);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxCollisionEventData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_COLLISION_EVENT_H_
|
||||||
41
Engine/source/afx/ce/afxComponentEffect.h
Normal file
41
Engine/source/afx/ce/afxComponentEffect.h
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_COMPONENT_EFFECT_H_
|
||||||
|
#define _AFX_COMPONENT_EFFECT_H_
|
||||||
|
|
||||||
|
#include "core/util/tVector.h"
|
||||||
|
|
||||||
|
#include "afx/afxConstraint.h"
|
||||||
|
|
||||||
|
class afxComponentEffectData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void gather_cons_defs(Vector<afxConstraintDef>& defs) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_COMPONENT_EFFECT_H_
|
||||||
93
Engine/source/afx/ce/afxConsoleMessage.cpp
Normal file
93
Engine/source/afx/ce/afxConsoleMessage.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxConsoleMessage.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxConsoleMessageData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxConsoleMessageData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxConsoleMessageData,
|
||||||
|
"@brief A datablock that specifies a Console Message effect.\n\n"
|
||||||
|
|
||||||
|
"Console Message effects are useful for debugging purposes when you want to make sure that an effect with a certain kind "
|
||||||
|
"of timing is actually getting executed and for evaluating some kinds of field substitutions."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxConsoleMessageData::afxConsoleMessageData()
|
||||||
|
{
|
||||||
|
message_str = ST_NULLSTRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxConsoleMessageData::afxConsoleMessageData(const afxConsoleMessageData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
message_str = other.message_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxConsoleMessageData)
|
||||||
|
|
||||||
|
void afxConsoleMessageData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("message", TypeString, myOffset(message_str),
|
||||||
|
"A text message to be displayed when the effect is executed.");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxConsoleMessageData::onAdd()
|
||||||
|
{
|
||||||
|
if (Parent::onAdd() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxConsoleMessageData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
stream->writeString(message_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxConsoleMessageData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
message_str = stream->readSTString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
54
Engine/source/afx/ce/afxConsoleMessage.h
Normal file
54
Engine/source/afx/ce/afxConsoleMessage.h
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_CONSOLE_MESSAGE_H_
|
||||||
|
#define _AFX_CONSOLE_MESSAGE_H_
|
||||||
|
|
||||||
|
class afxConsoleMessageData : public GameBaseData
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringTableEntry message_str;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxConsoleMessageData();
|
||||||
|
/*C*/ afxConsoleMessageData(const afxConsoleMessageData&, bool = false);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxConsoleMessageData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_CONSOLE_MESSAGE_H_
|
||||||
140
Engine/source/afx/ce/afxDamage.cpp
Normal file
140
Engine/source/afx/ce/afxDamage.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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 "afx/arcaneFX.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
|
||||||
|
#include "afx/ce/afxDamage.h"
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// afxDamageData
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(afxDamageData);
|
||||||
|
|
||||||
|
ConsoleDocClass( afxDamageData,
|
||||||
|
"@brief A datablock that specifies a Damage effect.\n\n"
|
||||||
|
|
||||||
|
"A Damage effect is useful for assigning damage with unusual timing that must be synchronized with other effects. They "
|
||||||
|
"can be used to deal direct damage, radius damage, and damage over time. Negative damage amounts can be used for "
|
||||||
|
"healing effects."
|
||||||
|
"\n\n"
|
||||||
|
|
||||||
|
"@ingroup afxEffects\n"
|
||||||
|
"@ingroup AFX\n"
|
||||||
|
"@ingroup Datablocks\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
afxDamageData::afxDamageData()
|
||||||
|
{
|
||||||
|
label = ST_NULLSTRING;
|
||||||
|
flavor = ST_NULLSTRING;
|
||||||
|
amount = 0;
|
||||||
|
repeats = 1;
|
||||||
|
ad_amount = 0;
|
||||||
|
radius = 0;
|
||||||
|
impulse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
afxDamageData::afxDamageData(const afxDamageData& other, bool temp_clone) : GameBaseData(other, temp_clone)
|
||||||
|
{
|
||||||
|
label = other.label;
|
||||||
|
flavor = other.flavor;
|
||||||
|
amount = other.amount;
|
||||||
|
repeats = other.repeats;
|
||||||
|
ad_amount = other.ad_amount;
|
||||||
|
radius = other.radius;
|
||||||
|
impulse = other.impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define myOffset(field) Offset(field, afxDamageData)
|
||||||
|
|
||||||
|
void afxDamageData::initPersistFields()
|
||||||
|
{
|
||||||
|
addField("label", TypeString, myOffset(label),
|
||||||
|
"An arbitrary string which is passed as an argument to a spell's onDamage() script "
|
||||||
|
"method. It can be used to identify which damage effect the damage came from in "
|
||||||
|
"cases where more than one damage effect is used in a single spell.");
|
||||||
|
addField("flavor", TypeString, myOffset(flavor),
|
||||||
|
"An arbitrary string which is passed as an argument to a spell's onDamage() script "
|
||||||
|
"method. It is used to classify a type of damage such as 'melee', 'magical', or "
|
||||||
|
"'fire'.");
|
||||||
|
addField("directDamage", TypeF32, myOffset(amount),
|
||||||
|
"An amount of direct damage to inflict on a target.");
|
||||||
|
addField("directDamageRepeats", TypeS8, myOffset(repeats),
|
||||||
|
"The number of times to inflict the damage specified by directDamage. Values "
|
||||||
|
"greater than 1 inflict damage over time, with the amount of directDamage "
|
||||||
|
"repeatedly dealt at evenly spaced intervals over the lifetime of the effect.");
|
||||||
|
addField("areaDamage", TypeF32, myOffset(ad_amount),
|
||||||
|
"An amount of area damage to inflict on a target. Objects within half the radius "
|
||||||
|
"receive full damage which then diminishes out to the full distance of "
|
||||||
|
"areaDamageRadius.");
|
||||||
|
addField("areaDamageRadius", TypeF32, myOffset(radius),
|
||||||
|
"Radius centered at the effect position in which damage will be applied.");
|
||||||
|
addField("areaDamageImpulse", TypeF32, myOffset(impulse),
|
||||||
|
"Specifies an amount of force to apply to damaged objects. Objects within half the "
|
||||||
|
"radius receive full impulse which then diminishes out to the full distance of "
|
||||||
|
"areaDamageRadius.");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afxDamageData::onAdd()
|
||||||
|
{
|
||||||
|
if (Parent::onAdd() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxDamageData::packData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::packData(stream);
|
||||||
|
|
||||||
|
stream->writeString(label);
|
||||||
|
stream->writeString(flavor);
|
||||||
|
stream->write(amount);
|
||||||
|
stream->write(repeats);
|
||||||
|
stream->write(ad_amount);
|
||||||
|
stream->write(radius);
|
||||||
|
stream->write(impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void afxDamageData::unpackData(BitStream* stream)
|
||||||
|
{
|
||||||
|
Parent::unpackData(stream);
|
||||||
|
|
||||||
|
label = stream->readSTString();
|
||||||
|
flavor = stream->readSTString();
|
||||||
|
stream->read(&amount);
|
||||||
|
stream->read(&repeats);
|
||||||
|
stream->read(&ad_amount);
|
||||||
|
stream->read(&radius);
|
||||||
|
stream->read(&impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
63
Engine/source/afx/ce/afxDamage.h
Normal file
63
Engine/source/afx/ce/afxDamage.h
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#ifndef _AFX_DAMAGE_H_
|
||||||
|
#define _AFX_DAMAGE_H_
|
||||||
|
|
||||||
|
#include "afx/afxEffectDefs.h"
|
||||||
|
|
||||||
|
class afxDamageData : public GameBaseData, public afxEffectDefs
|
||||||
|
{
|
||||||
|
typedef GameBaseData Parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringTableEntry label;
|
||||||
|
StringTableEntry flavor;
|
||||||
|
|
||||||
|
F32 amount;
|
||||||
|
U8 repeats;
|
||||||
|
F32 ad_amount;
|
||||||
|
F32 radius;
|
||||||
|
F32 impulse;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*C*/ afxDamageData();
|
||||||
|
/*C*/ afxDamageData(const afxDamageData&, bool = false);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void packData(BitStream*);
|
||||||
|
virtual void unpackData(BitStream*);
|
||||||
|
|
||||||
|
virtual bool allowSubstitutions() const { return true; }
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(afxDamageData);
|
||||||
|
DECLARE_CATEGORY("AFX");
|
||||||
|
};
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
|
#endif // _AFX_DAMAGE_H_
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue