Merge pull request #2056 from Bloodknight/afx_merge_main

Afx merge main
This commit is contained in:
Areloch 2017-10-11 08:47:47 -05:00 committed by GitHub
commit e023cf3a60
301 changed files with 59625 additions and 1480 deletions

View file

@ -20,6 +20,11 @@
// 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 "T3D/aiPlayer.h"
@ -97,6 +102,9 @@ AIPlayer::AIPlayer()
mMoveSlowdown = true;
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;
mAimLocationSet = false;
mTargetInLOS = false;
@ -547,23 +555,27 @@ bool AIPlayer::getAIMove(Move *movePtr)
mMoveState = ModeMove;
}
if (mMoveStuckTestCountdown > 0)
--mMoveStuckTestCountdown;
else
{
// We should check to see if we are stuck...
F32 locationDelta = (location - mLastLocation).len();
// Don't check for ai stuckness if animation during
// an anim-clip effect override.
if (mDamageState == Enabled && !(anim_clip_flags & ANIM_OVERRIDDEN) && !isAnimationLocked()) {
if (mMoveStuckTestCountdown > 0)
--mMoveStuckTestCountdown;
else
{
// We should check to see if we are stuck...
F32 locationDelta = (location - mLastLocation).len();
if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled)
{
// 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
// we should TRY to check if we've moved. This could use better detection.
if ( mMoveState != ModeSlowing || locationDelta == 0 )
{
mMoveState = ModeStuck;
onStuck();
}
}
{
mMoveState = ModeStuck;
onStuck();
}
}
}
}
}
}
@ -626,6 +638,7 @@ bool AIPlayer::getAIMove(Move *movePtr)
}
#endif // TORQUE_NAVIGATION_ENABLED
if (!(anim_clip_flags & ANIM_OVERRIDDEN) && !isAnimationLocked())
mLastLocation = location;
return true;
@ -1415,6 +1428,47 @@ DefineEngineMethod( AIPlayer, clearMoveTriggers, void, ( ),,
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)
{
if (!isServerObject()) return false;

View file

@ -20,6 +20,11 @@
// 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_
#define _AIPLAYER_H_
@ -225,6 +230,18 @@ public:
/// @}
#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

View file

@ -20,6 +20,11 @@
// 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_
#define _CAMERA_H_
@ -246,6 +251,8 @@ class Camera: public ShapeBase
DECLARE_CONOBJECT( Camera );
DECLARE_CATEGORY( "Game" );
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;

View file

@ -20,6 +20,11 @@
// 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 "T3D/containerQuery.h"
@ -91,7 +96,9 @@ void physicalZoneFind(SceneObject* obj, void *key)
if (pz->isActive()) {
info->gravityScale *= pz->getGravityMod();
info->appliedForce += pz->getForce();
Point3F center;
info->box.getCenter(&center);
info->appliedForce += pz->getForce(&center);
}
}

View file

@ -20,6 +20,11 @@
// 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 "T3D/debris.h"
@ -113,6 +118,85 @@ DebrisData::DebrisData()
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()
{
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.");
endGroup("Behavior");
// disallow some field substitutions
onlyKeepClearSubstitutions("emitters"); // subs resolving to "~~", or "~0" are OK
onlyKeepClearSubstitutions("explosion");
Parent::initPersistFields();
}
@ -451,6 +538,8 @@ Debris::Debris()
// Only allocated client side.
mNetFlags.set( IsGhost );
ss_object = 0;
ss_index = 0;
}
Debris::~Debris()
@ -466,6 +555,12 @@ Debris::~Debris()
delete mPart;
mPart = NULL;
}
if (mDataBlock && mDataBlock->isTempClone())
{
delete mDataBlock;
mDataBlock = 0;
}
}
void Debris::initPersistFields()
@ -495,6 +590,8 @@ bool Debris::onNewDataBlock( GameBaseData *dptr, bool reload )
if( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
return false;
if (mDataBlock->isTempClone())
return true;
scriptOnNewDataBlock();
return true;
@ -519,7 +616,7 @@ bool Debris::onAdd()
if( mDataBlock->emitterList[i] != NULL )
{
ParticleEmitter * pEmitter = new ParticleEmitter;
pEmitter->onNewDataBlock( mDataBlock->emitterList[i], false );
pEmitter->onNewDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index), false);
if( !pEmitter->registerObject() )
{
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[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 );
}
@ -546,7 +644,8 @@ bool Debris::onAdd()
{
sizeList[0] = 0.0;
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 );
}
@ -798,7 +897,8 @@ void Debris::explode()
Point3F explosionPos = getPosition();
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 );
trans.setPosition( getPosition() );

View file

@ -20,6 +20,11 @@
// 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_
#define _DEBRIS_H_
@ -97,6 +102,12 @@ struct DebrisData : public GameBaseData
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);
private:
SimObject* ss_object;
S32 ss_index;
public:
void setSubstitutionData(SimObject* obj, S32 idx=0) { ss_object = obj; ss_index = idx; }
};

View file

@ -20,6 +20,11 @@
// 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 "T3D/fx/explosion.h"
@ -50,6 +55,8 @@
#include "renderInstance/renderPassManager.h"
#include "console/engineAPI.h"
#include "sfx/sfxProfile.h"
IMPLEMENT_CONOBJECT(Explosion);
ConsoleDocClass( Explosion,
@ -281,6 +288,105 @@ ExplosionData::ExplosionData()
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()
{
addField( "explosionShape", TypeShapeFilename, Offset(dtsFileName, ExplosionData),
@ -412,6 +518,12 @@ void ExplosionData::initPersistFields()
"Distance (in the explosion normal direction) of the PointLight position "
"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();
}
@ -808,6 +920,10 @@ Explosion::Explosion()
mLight = LIGHTMGR->createLightInfo();
mNetFlags.set( IsGhost );
ss_object = 0;
ss_index = 0;
mDataBlock = 0;
soundProfile_clone = 0;
}
Explosion::~Explosion()
@ -820,6 +936,18 @@ Explosion::~Explosion()
}
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 ))
return false;
if (mDataBlock->isTempClone())
return true;
scriptOnNewDataBlock();
return true;
}
@ -1190,7 +1320,8 @@ void Explosion::launchDebris( Point3F &axis )
launchDir *= debrisVel;
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->init( pos, launchDir );
@ -1218,7 +1349,8 @@ void Explosion::spawnSubExplosions()
{
MatrixF trans = getTransform();
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->setInitialState( trans.getPosition(), mInitialNormal, 1);
if (!pExplosion->registerObject())
@ -1256,12 +1388,18 @@ bool Explosion::explode()
resetWorldBox();
}
if (mDataBlock->soundProfile)
SFX->playOnce( mDataBlock->soundProfile, &getTransform() );
SFXProfile* sound_prof = dynamic_cast<SFXProfile*>(mDataBlock->soundProfile);
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) {
mMainEmitter = new ParticleEmitter;
mMainEmitter->setDataBlock(mDataBlock->particleEmitter);
mMainEmitter->setDataBlock(mDataBlock->particleEmitter->cloneAndPerformSubstitutions(ss_object, ss_index));
mMainEmitter->registerObject();
mMainEmitter->emitParticles(getPosition(), mInitialNormal, mDataBlock->particleRadius,
@ -1273,7 +1411,7 @@ bool Explosion::explode()
if( mDataBlock->emitterList[i] != NULL )
{
ParticleEmitter * pEmitter = new ParticleEmitter;
pEmitter->setDataBlock( mDataBlock->emitterList[i] );
pEmitter->setDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index));
if( !pEmitter->registerObject() )
{
Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );

View file

@ -20,6 +20,11 @@
// 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_
#define _EXPLOSION_H_
@ -42,6 +47,7 @@ class TSThread;
class SFXTrack;
struct DebrisData;
class SFXProfile;
//--------------------------------------------------------------------------
class ExplosionData : public GameBaseData {
public:
@ -126,6 +132,11 @@ class ExplosionData : public GameBaseData {
static void initPersistFields();
virtual void packData(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);
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

View file

@ -43,6 +43,11 @@
// POTENTIAL TODO LIST:
// 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 "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." );
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.
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));
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);
@ -1705,6 +1718,7 @@ U32 fxFoliageReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * s
stream->writeFlag(mFieldData.mShowPlacementArea); // Show Placement Area Flag.
stream->write(mFieldData.mPlacementBandHeight); // Placement Area Height.
stream->write(mFieldData.mPlaceAreaColour); // Placement Area Colour.
stream->write(mFieldData.mAmbientModulationBias);
}
// Were done ...
@ -1782,6 +1796,7 @@ void fxFoliageReplicator::unpackUpdate(NetConnection * con, BitStream * stream)
stream->read(&mFieldData.mPlacementBandHeight); // Placement Area Height.
stream->read(&mFieldData.mPlaceAreaColour);
stream->read(&mFieldData.mAmbientModulationBias);
// Calculate Fade-In/Out Gradients.
mFadeInGradient = 1.0f / mFieldData.mFadeInRegion;
mFadeOutGradient = 1.0f / mFieldData.mFadeOutRegion;

View file

@ -20,6 +20,11 @@
// 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_
#define _FOLIAGEREPLICATOR_H_
@ -319,6 +324,7 @@ public:
U32 mPlacementBandHeight;
LinearColorF mPlaceAreaColour;
F32 mAmbientModulationBias;
tagFieldData()
{
// Set Defaults.
@ -377,6 +383,7 @@ public:
mShowPlacementArea = true;
mPlacementBandHeight = 25;
mPlaceAreaColour .set(0.4f, 0, 0.8f);
mAmbientModulationBias = 1.0f;
}
} mFieldData;

View file

@ -19,6 +19,12 @@
// 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.
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#include "particle.h"
#include "console/consoleTypes.h"
#include "console/typeValidators.h"
@ -72,6 +78,8 @@ static const F32 sgDefaultSpinSpeed = 1.f;
static const F32 sgDefaultSpinRandomMin = 0.f;
static const F32 sgDefaultSpinRandomMax = 0.f;
static const F32 sgDefaultSpinBias = 1.0f;
static const F32 sgDefaultSizeBias = 1.0f;
//-----------------------------------------------------------------------------
// Constructor
@ -102,9 +110,9 @@ ParticleData::ParticleData()
}
times[0] = 0.0f;
times[1] = 0.33f;
times[2] = 0.66f;
times[3] = 1.0f;
times[1] = 1.0f;
for (i = 2; i < PDC_NUM_KEYS; i++)
times[i] = -1.0f;
texCoords[0].set(0.0,0.0); // texture coords at 4 corners
texCoords[1].set(0.0,1.0); // of particle quad
@ -115,18 +123,20 @@ ParticleData::ParticleData()
animTexUVs = NULL; // array of tile vertex UVs
textureName = NULL; // texture filename
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
//-----------------------------------------------------------------------------
ParticleData::~ParticleData()
{
if (animTexUVs)
{
delete [] animTexUVs;
}
}
FRangeValidator dragCoefFValidator(0.f, 5.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"
"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();
}
@ -243,18 +262,22 @@ void ParticleData::packData(BitStream* stream)
stream->writeInt((S32)(spinRandomMin + 1000), 11);
stream->writeInt((S32)(spinRandomMax + 1000), 11);
}
if(stream->writeFlag(spinBias != sgDefaultSpinBias))
stream->write(spinBias);
stream->writeFlag(randomizeSpinDir);
stream->writeFlag(useInvAlpha);
S32 i, count;
// 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)
break;
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++ )
{
@ -262,7 +285,8 @@ void ParticleData::packData(BitStream* stream)
stream->writeFloat( colors[i].green, 7);
stream->writeFloat( colors[i].blue, 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);
}
@ -279,6 +303,13 @@ void ParticleData::packData(BitStream* stream)
mathWrite(*stream, animTexTiling);
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;
}
if(stream->readFlag())
stream->read(&spinBias);
else
spinBias = sgDefaultSpinBias;
randomizeSpinDir = stream->readFlag();
useInvAlpha = stream->readFlag();
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++)
{
colors[i].red = stream->readFloat(7);
colors[i].green = stream->readFloat(7);
colors[i].blue = 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);
}
textureName = (stream->readFlag()) ? stream->readSTString() : 0;
@ -346,6 +384,14 @@ void ParticleData::unpackData(BitStream* stream)
mathRead(*stream, &animTexTiling);
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)
@ -427,11 +473,33 @@ bool ParticleData::onAdd()
}
times[0] = 0.0f;
for (U32 i = 1; i < 4; i++) {
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];
}
for (U32 i = 1; i < PDC_NUM_KEYS; i++)
{
if (times[i] < 0.0f)
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
@ -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;
}
@ -495,6 +567,15 @@ bool ParticleData::preload(bool server, String &errorStr)
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)
{
@ -606,6 +687,11 @@ void ParticleData::initializeParticle(Particle* init, const Point3F& inheritVelo
// assign spin amount
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])
@ -653,3 +739,78 @@ DefineEngineMethod(ParticleData, reload, void, (),,
char errorBuffer[256];
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);
}

View file

@ -20,6 +20,11 @@
// 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_
#define _PARTICLE_H_
@ -44,7 +49,9 @@ class ParticleData : public SimDataBlock
public:
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;
@ -97,6 +104,23 @@ class ParticleData : public SimDataBlock
static void initPersistFields();
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;
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.
};

View file

@ -20,6 +20,11 @@
// 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 "T3D/fx/particleEmitter.h"
@ -38,6 +43,10 @@
#include "lighting/lightInfo.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 );
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;
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" );
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();
}
@ -358,6 +402,22 @@ void ParticleEmitterData::packData(BitStream* stream)
stream->writeFlag(renderReflection);
stream->writeFlag(glow);
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();
glow = stream->readFlag();
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 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
if (textureName && textureName[0])
{
@ -669,6 +761,8 @@ void ParticleEmitterData::allocPrimBuffer( S32 overrideSize )
partListInitSize = maxPartLife / (ejectionPeriodMS - periodVarianceMS);
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( overrideSize != -1 )
@ -705,6 +799,134 @@ void ParticleEmitterData::allocPrimBuffer( S32 overrideSize )
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
@ -736,6 +958,16 @@ ParticleEmitter::ParticleEmitter()
// ParticleEmitter should be allocated on the client only.
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];
}
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);
resetWorldBox();
#if defined(AFX_CAP_PARTICLE_POOLS)
if (pool)
pool->addParticleEmitter(this);
#endif
return true;
}
@ -780,6 +1030,14 @@ bool ParticleEmitter::onAdd()
//-----------------------------------------------------------------------------
void ParticleEmitter::onRemove()
{
#if defined(AFX_CAP_PARTICLE_POOLS)
if (pool)
{
pool->removeParticleEmitter(this);
pool = 0;
}
#endif
removeFromScene();
Parent::onRemove();
}
@ -825,6 +1083,11 @@ bool ParticleEmitter::onNewDataBlock( GameBaseData *dptr, bool reload )
part_list_head.next = NULL;
n_parts = 0;
}
if (mDataBlock->isTempClone())
{
db_temp_clone = true;
return true;
}
scriptOnNewDataBlock();
return true;
@ -861,6 +1124,11 @@ LinearColorF ParticleEmitter::getCollectiveColor()
//-----------------------------------------------------------------------------
void ParticleEmitter::prepRenderImage(SceneRenderState* state)
{
#if defined(AFX_CAP_PARTICLE_POOLS)
if (pool)
return;
#endif
if( state->isReflectPass() && !getDataBlock()->renderReflection )
return;
@ -889,6 +1157,7 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state)
ri->translucentSort = true;
ri->type = RenderPassManager::RIT_Particle;
ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint( camPos );
ri->defaultKey = (-sort_priority*100);
// Draw the system offscreen unless the highResOnly flag is set on the datablock
ri->systemState = ( getDataBlock()->highResOnly ? PSS_AwaitingHighResDraw : PSS_AwaitingOffscreenDraw );
@ -992,6 +1261,7 @@ void ParticleEmitter::emitParticles(const Point3F& point,
return;
}
pos_pe = point;
Point3F realStart;
if( useLastPosition && mHasLastPosition )
realStart = mLastPosition;
@ -1059,7 +1329,8 @@ void ParticleEmitter::emitParticles(const Point3F& start,
// Create particle at the correct position
Point3F pos;
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
addParticle(pos, axis, velocity, axisx);
addParticle(pos, axis, velocity, axisx, numMilliseconds-currTime);
particlesAdded = true;
mNextParticleTime = 0;
}
@ -1089,7 +1360,7 @@ void ParticleEmitter::emitParticles(const Point3F& start,
// Create particle at the correct position
Point3F pos;
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
addParticle(pos, axis, velocity, axisx);
addParticle(pos, axis, velocity, axisx, numMilliseconds-currTime);
particlesAdded = true;
// This override-advance code is restored in order to correctly adjust
@ -1114,17 +1385,27 @@ void ParticleEmitter::emitParticles(const Point3F& start,
{
if (advanceMS != 0)
{
F32 t = F32(advanceMS) / 1000.0;
F32 t = F32(advanceMS) / 1000.0;
Point3F a = last_part->acc;
a -= last_part->vel * last_part->dataBlock->dragCoefficient;
a -= mWindVelocity * last_part->dataBlock->windCoefficient;
a += Point3F(0.0f, 0.0f, -9.81f) * last_part->dataBlock->gravityCoefficient;
Point3F a = last_part->acc;
a -= last_part->vel * last_part->dataBlock->dragCoefficient;
a -= mWindVelocity * last_part->dataBlock->windCoefficient;
//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->pos += last_part->vel * t;
last_part->vel += a * 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();
pos += rCenter;
addParticle(pos, axis, velocity, axisz);
addParticle(pos, axis, velocity, axisz, 0);
}
// Set world bounding box
@ -1219,6 +1500,8 @@ void ParticleEmitter::emitParticles(const Point3F& rCenter,
//-----------------------------------------------------------------------------
void ParticleEmitter::updateBBox()
{
if (forced_bbox)
return;
Point3F minPt(1e10, 1e10, 1e10);
Point3F maxPt(-1e10, -1e10, -1e10);
@ -1239,15 +1522,18 @@ void ParticleEmitter::updateBBox()
boxScale.y = getMax(boxScale.y, 1.0f);
boxScale.z = getMax(boxScale.z, 1.0f);
mBBObjToWorld.scale(boxScale);
#if defined(AFX_CAP_PARTICLE_POOLS)
if (pool)
pool->updatePoolBBox(this);
#endif
}
//-----------------------------------------------------------------------------
// addParticle
//-----------------------------------------------------------------------------
void ParticleEmitter::addParticle(const Point3F& pos,
const Point3F& axis,
const Point3F& vel,
const Point3F& axisx)
void ParticleEmitter::addParticle(const Point3F& pos, const Point3F& axis, const Point3F& vel,
const Point3F& axisx, const U32 age_offset)
{
n_parts++;
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;
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;
F32 theta = (mDataBlock->thetaMax - mDataBlock->thetaMin) * gRandGen.randF() +
mDataBlock->thetaMin;
@ -1290,14 +1586,17 @@ void ParticleEmitter::addParticle(const Point3F& pos,
F32 initialVel = mDataBlock->ejectionVelocity;
initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
pNew->pos = pos + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
pNew->vel = ejectionAxis * initialVel;
pNew->orientDir = ejectionAxis;
pNew->pos = pos_start + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
pNew->pos_local = pNew->pos;
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->currentAge = 0;
// Choose a new particle datablack randomly from the list
U32 dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size();
pNew->currentAge = age_offset;
pNew->t_last = 0.0f;
mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel);
updateKeyData( pNew );
@ -1379,8 +1678,10 @@ void ParticleEmitter::updateKeyData( Particle *part )
if( part->totalLifetime < 1 )
part->totalLifetime = 1;
F32 t = F32(part->currentAge) / F32(part->totalLifetime);
AssertFatal(t <= 1.0f, "Out out bounds filter function for particle.");
if (part->currentAge > part->totalLifetime)
part->currentAge = part->totalLifetime;
F32 t = (F32)part->currentAge / (F32)part->totalLifetime;
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->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;
}
@ -1424,19 +1743,25 @@ void ParticleEmitter::updateKeyData( Particle *part )
//-----------------------------------------------------------------------------
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)
{
F32 t = F32(ms) / 1000.0;
Point3F a = part->acc;
a -= part->vel * part->dataBlock->dragCoefficient;
a -= part->vel * part->dataBlock->dragCoefficient;
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->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 );
}
@ -1999,3 +2324,43 @@ DefineEngineMethod(ParticleEmitterData, reload, void,(),,
{
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
}

View file

@ -20,6 +20,11 @@
// 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
#define _H_PARTICLE_EMITTER
@ -42,6 +47,12 @@
class RenderPassManager;
class ParticleData;
#define AFX_CAP_PARTICLE_POOLS
#if defined(AFX_CAP_PARTICLE_POOLS)
class afxParticlePoolData;
class afxParticlePool;
#endif
//*****************************************************************************
// Particle Emitter Data
//*****************************************************************************
@ -113,6 +124,26 @@ class ParticleEmitterData : public GameBaseData
bool glow; ///< Renders this emitter into the glow buffer.
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
{
typedef GameBase Parent;
#if defined(AFX_CAP_PARTICLE_POOLS)
friend class afxParticlePool;
#endif
public:
@ -190,7 +224,7 @@ class ParticleEmitter : public GameBase
/// @param axis
/// @param vel Initial velocity
/// @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,
@ -227,7 +261,12 @@ class ParticleEmitter : public GameBase
// PEngine interface
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 );
protected:
inline void updateKeyData( Particle *part );
@ -239,25 +278,30 @@ class ParticleEmitter : public GameBase
ParticleEmitterData* mDataBlock;
protected:
U32 mInternalClock;
U32 mNextParticleTime;
Point3F mLastPosition;
bool mHasLastPosition;
private:
MatrixF mBBObjToWorld;
bool mDeleteWhenEmpty;
bool mDeleteOnTick;
protected:
S32 mLifetimeMS;
S32 mElapsedTimeMS;
private:
F32 sizes[ ParticleData::PDC_NUM_KEYS ];
LinearColorF colors[ ParticleData::PDC_NUM_KEYS ];
GFXVertexBufferHandle<ParticleVertexType> mVertBuff;
protected:
// These members are for implementing a link-list of the active emitter
// particles. Member part_store contains blocks of particles that can be
// 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;
S32 n_part_capacity;
S32 n_parts;
private:
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

View file

@ -20,6 +20,11 @@
// 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 "T3D/gameBase/gameBase.h"
#include "console/consoleTypes.h"
@ -36,6 +41,7 @@
#include "T3D/aiConnection.h"
#endif
#include "afx/arcaneFX.h"
//----------------------------------------------------------------------------
// Ghost update relative priority values
@ -122,6 +128,12 @@ GameBaseData::GameBaseData()
category = "";
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()
{
@ -244,6 +256,8 @@ GameBase::GameBase()
GameBase::~GameBase()
{
if (scope_registered)
arcaneFX::unregisterScopedObject(this);
}
@ -256,8 +270,16 @@ bool GameBase::onAdd()
// Datablock must be initialized on the server.
// Client datablock are initialized by the initial update.
if ( isServerObject() && mDataBlock && !onNewDataBlock( mDataBlock, false ) )
return false;
if (isClientObject())
{
if (scope_id > 0 && !scope_registered)
arcaneFX::registerScopedObject(this);
}
else
{
if ( mDataBlock && !onNewDataBlock( mDataBlock, false ) )
return false;
}
setProcessTick( true );
@ -266,6 +288,8 @@ bool GameBase::onAdd()
void GameBase::onRemove()
{
if (scope_registered)
arcaneFX::unregisterScopedObject(this);
// EDITOR FEATURE: Remove us from the reload signal of our datablock.
if ( mDataBlock )
mDataBlock->mReloadSignal.remove( this, &GameBase::_onDatablockModified );
@ -290,6 +314,9 @@ bool GameBase::onNewDataBlock( GameBaseData *dptr, bool reload )
if ( !mDataBlock )
return false;
// Don't set mask when new datablock is a temp-clone.
if (mDataBlock->isTempClone())
return true;
setMaskBits(DataBlockMask);
return true;
@ -543,6 +570,11 @@ U32 GameBase::packUpdate( NetConnection *connection, U32 mask, BitStream *stream
stream->writeFlag(mIsAiControlled);
#endif
if (stream->writeFlag(mask & ScopeIdMask))
{
if (stream->writeFlag(scope_refs > 0))
stream->writeInt(scope_id, SCOPE_ID_BITS);
}
return retMask;
}
@ -581,6 +613,11 @@ void GameBase::unpackUpdate(NetConnection *con, BitStream *stream)
mTicksSinceLastMove = 0;
mIsAiControlled = stream->readFlag();
#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 )

View file

@ -20,6 +20,11 @@
// 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_
#define _GAMEBASE_H_
@ -113,6 +118,8 @@ public:
DECLARE_CALLBACK( void, onMount, ( 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 {
DataBlockMask = Parent::NextFreeMask << 0,
ExtendedInfoMask = Parent::NextFreeMask << 1,
NextFreeMask = Parent::NextFreeMask << 2
ScopeIdMask = Parent::NextFreeMask << 2,
NextFreeMask = Parent::NextFreeMask << 3,
};
// net flags added by game base
@ -453,6 +461,8 @@ private:
/// within this callback.
///
void _onDatablockModified();
protected:
void onScopeIdChange() { setMaskBits(ScopeIdMask); }
};

View file

@ -20,6 +20,11 @@
// 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 "T3D/gameBase/gameConnection.h"
@ -52,6 +57,11 @@
#include "T3D/gameBase/std/stdMoveList.h"
#endif
#ifdef AFX_CAP_DATABLOCK_CACHE
#include "core/stream/fileStream.h"
#endif
#include "afx/arcaneFX.h"
//----------------------------------------------------------------------------
#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"
"@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()
{
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;
mControlObject = NULL;
mCameraObject = NULL;
@ -246,6 +273,10 @@ GameConnection::~GameConnection()
dFree(mConnectArgv[i]);
dFree(mJoinPassword);
delete mMoveList;
#ifdef AFX_CAP_DATABLOCK_CACHE
delete client_db_stream;
#endif
}
//----------------------------------------------------------------------------
@ -1144,6 +1175,17 @@ void GameConnection::readPacket(BitStream *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;
mDamageFlash = 0;
mWhiteOut = 0;
@ -1387,6 +1429,35 @@ void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
// all the damage flash & white out
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())
{
gIndex = getGhostIndex(mControlObject);
@ -1608,6 +1679,14 @@ void GameConnection::preloadNextDataBlock(bool hadNewFiles)
sendConnectionMessage(DataBlocksDownloadDone, mDataBlockSequence);
// 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;
}
mFilesWereDownloaded = hadNewFiles;
@ -1771,7 +1850,11 @@ DefineEngineMethod( GameConnection, transmitDataBlocks, void, (S32 sequence),,
const U32 iCount = pGroup->size();
// If this is the local client...
#ifdef AFX_CAP_DATABLOCK_CACHE
if (GameConnection::getLocalClientConnection() == object && !GameConnection::serverCacheEnabled())
#else
if (GameConnection::getLocalClientConnection() == object)
#endif
{
// Set up a pointer to the datablock.
SimDataBlock* pDataBlock = 0;
@ -2166,6 +2249,13 @@ void GameConnection::consoleInit()
"@ingroup Networking\n");
// 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),,
@ -2360,4 +2450,522 @@ DefineEngineMethod( GameConnection, getVisibleGhostDistance, F32, (),,
)
{
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

View file

@ -20,6 +20,11 @@
// 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_
#define _GAMECONNECTION_H_
@ -55,6 +60,14 @@ class MoveList;
struct Move;
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 MaxCameraFov = 179.f; ///< max camera FOV
@ -372,6 +385,61 @@ protected:
DECLARE_CALLBACK( void, setLagIcon, (bool state) );
DECLARE_CALLBACK( void, onDataBlocksDone, (U32 sequence) );
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

View file

@ -20,6 +20,11 @@
// 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 "core/dnet.h"
#include "core/stream/bitStream.h"
@ -136,6 +141,9 @@ void SimDataBlockEvent::notifyDelivered(NetConnection *conn, bool )
void SimDataBlockEvent::pack(NetConnection *conn, BitStream *bstream)
{
#ifdef AFX_CAP_DATABLOCK_CACHE
((GameConnection *)conn)->tempDisableStringBuffering(bstream);
#endif
SimDataBlock* obj;
Sim::findObject(id,obj);
GameConnection *gc = (GameConnection *) conn;
@ -157,10 +165,18 @@ void SimDataBlockEvent::pack(NetConnection *conn, BitStream *bstream)
bstream->writeInt(classId ^ DebugChecksum, 32);
#endif
}
#ifdef AFX_CAP_DATABLOCK_CACHE
((GameConnection *)conn)->restoreStringBuffering(bstream);
#endif
}
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())
{
mProcess = true;
@ -215,6 +231,11 @@ void SimDataBlockEvent::unpack(NetConnection *cptr, BitStream *bstream)
#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)

View file

@ -20,6 +20,11 @@
// 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 "T3D/gameBase/processList.h"
@ -284,5 +289,20 @@ void ProcessList::advanceObjects()
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;
}

View file

@ -20,6 +20,11 @@
// 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_
#define _PROCESSLIST_H_
@ -188,6 +193,9 @@ protected:
PreTickSignal mPreTick;
PostTickSignal mPostTick;
// JTF: still needed?
public:
ProcessObject* findNearestToEnd(Vector<ProcessObject*>& objs) const;
};
#endif // _PROCESSLIST_H_

View file

@ -20,6 +20,11 @@
// 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 "T3D/groundPlane.h"
@ -40,6 +45,7 @@
#include "T3D/physics/physicsBody.h"
#include "T3D/physics/physicsCollision.h"
#include "afx/ce/afxZodiacMgr.h"
/// Minimum square size allowed. This is a cheap way to limit the amount
/// of geometry possibly generated by the GroundPlane (vertex buffers have a
@ -77,6 +83,7 @@ GroundPlane::GroundPlane()
mNetFlags.set( Ghostable | ScopeAlways );
mConvexList = new Convex;
mTypeMask |= TerrainLikeObjectType;
}
GroundPlane::~GroundPlane()
@ -356,6 +363,7 @@ void GroundPlane::prepRenderImage( SceneRenderState* state )
if( mVertexBuffer.isNull() )
return;
afxZodiacMgr::renderGroundPlaneZodiacs(state, this);
// Add a render instance.
RenderPassManager* pass = state->getRenderPass();

View file

@ -20,6 +20,11 @@
// 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 "T3D/lightBase.h"
@ -73,6 +78,7 @@ LightBase::LightBase()
mLight = LightManager::createLightInfo();
mFlareState.clear();
mLocalRenderViz = false;
}
LightBase::~LightBase()
@ -206,7 +212,7 @@ void LightBase::prepRenderImage( SceneRenderState *state )
// If the light is selected or light visualization
// is enabled then register the callback.
if ( smRenderViz || isSelectedInEditor )
if ( mLocalRenderViz || smRenderViz || isSelectedInEditor )
{
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
ri->renderDelegate.bind( this, &LightBase::_onRenderViz );

View file

@ -20,6 +20,11 @@
// 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_
#define _LIGHTBASE_H_
@ -132,6 +137,8 @@ public:
virtual void pauseAnimation( void );
virtual void playAnimation( void );
virtual void playAnimation( LightAnimData *animData );
protected:
bool mLocalRenderViz;
};
#endif // _LIGHTBASE_H_

View file

@ -20,11 +20,19 @@
// 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_
#define _OBJECTTYPES_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)
///
/// @note If a new object type is added, don't forget to add it to
@ -149,6 +157,11 @@ enum SceneObjectTypes
EntityObjectType = BIT(23),
/// @}
InteriorLikeObjectType = BIT(24),
TerrainLikeObjectType = BIT(25),
#if defined(AFX_CAP_AFXMODEL_TYPE)
afxModelObjectType = BIT(26)
#endif
};
enum SceneObjectTypeMasks : U32

View file

@ -20,6 +20,11 @@
// 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 "core/stream/bitStream.h"
#include "collision/boxConvex.h"
@ -33,6 +38,8 @@
#include "gfx/gfxDrawUtil.h"
#include "console/engineAPI.h"
//#include "console/engineTypes.h"
#include "sim/netConnection.h"
IMPLEMENT_CO_NETOBJECT_V1(PhysicalZone);
ConsoleDocClass( PhysicalZone,
@ -103,6 +110,10 @@ PhysicalZone::PhysicalZone()
mConvexList = new Convex;
mActive = true;
force_type = VECTOR;
force_mag = 0.0f;
orient_force = false;
fade_amt = 1.0f;
}
PhysicalZone::~PhysicalZone()
@ -111,6 +122,16 @@ PhysicalZone::~PhysicalZone()
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()
{
@ -129,6 +150,10 @@ void PhysicalZone::initPersistFields()
"point followed by three vectors representing the edges extending from the corner." );
endGroup("Misc");
addGroup("AFX");
addField("forceType", TYPEID<PhysicalZone::ForceType>(), Offset(force_type, PhysicalZone));
addField("orientForce", TypeBool, Offset(orient_force, PhysicalZone));
endGroup("AFX");
Parent::initPersistFields();
}
@ -158,6 +183,19 @@ bool PhysicalZone::onAdd()
Polyhedron temp = mPolyhedron;
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();
return true;
@ -191,7 +229,7 @@ void PhysicalZone::setTransform(const MatrixF & mat)
mClippedList.setBaseTransform(base);
if (isServerObject())
setMaskBits(InitialUpdateMask);
setMaskBits(MoveMask);
}
@ -242,12 +280,8 @@ U32 PhysicalZone::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
U32 i;
U32 retMask = Parent::packUpdate(con, mask, stream);
if (stream->writeFlag((mask & InitialUpdateMask) != 0)) {
// Note that we don't really care about efficiency here, since this is an
// edit-only ghost...
mathWrite(*stream, mObjToWorld);
mathWrite(*stream, mObjScale);
if (stream->writeFlag(mask & PolyhedronMask))
{
// Write the polyhedron
stream->write(mPolyhedron.pointList.size());
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[1]);
}
}
if (stream->writeFlag(mask & MoveMask))
{
stream->writeAffineTransform(mObjToWorld);
mathWrite(*stream, mObjScale);
}
if (stream->writeFlag(mask & SettingsMask))
{
stream->write(mVelocityMod);
stream->write(mGravityMod);
mathWrite(*stream, mAppliedForce);
stream->writeFlag(mActive);
} else {
stream->writeFlag(mActive);
stream->writeInt(force_type, FORCE_TYPE_BITS);
stream->writeFlag(orient_force);
}
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)
{
Parent::unpackUpdate(con, stream);
if (stream->readFlag()) {
bool new_ph = false;
if (stream->readFlag()) // PolyhedronMask
{
U32 i, size;
MatrixF temp;
Point3F tempScale;
Polyhedron tempPH;
// Transform
mathRead(*stream, &temp);
mathRead(*stream, &tempScale);
// Read the polyhedron
stream->read(&size);
tempPH.pointList.setSize(size);
@ -314,17 +360,46 @@ void PhysicalZone::unpackUpdate(NetConnection* con, BitStream* stream)
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(&mGravityMod);
mathRead(*stream, &mAppliedForce);
setPolyhedron(tempPH);
setScale(tempScale);
setTransform(temp);
mActive = stream->readFlag();
} else {
mActive = stream->readFlag();
force_type = stream->readInt(FORCE_TYPE_BITS); // AFX
orient_force = stream->readFlag(); // AFX
}
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;
}
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;
}
}

View file

@ -20,6 +20,11 @@
// 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
#define _H_PHYSICALZONE
@ -40,9 +45,14 @@ class PhysicalZone : public SceneObject
{
typedef SceneObject Parent;
enum UpdateMasks {
enum UpdateMasks {
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:
@ -83,7 +93,10 @@ class PhysicalZone : public SceneObject
inline F32 getVelocityMod() const { return mVelocityMod; }
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&);
bool testObject(SceneObject*);
@ -96,7 +109,25 @@ class PhysicalZone : public SceneObject
void deactivate();
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

View file

@ -20,6 +20,10 @@
// 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 "T3D/player.h"
@ -1656,6 +1660,8 @@ Player::Player()
mLastAbsoluteYaw = 0.0f;
mLastAbsolutePitch = 0.0f;
mLastAbsoluteRoll = 0.0f;
afx_init();
}
Player::~Player()
@ -2070,6 +2076,32 @@ void Player::processTick(const Move* 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
if (delta.warpTicks > 0) {
delta.warpTicks--;
@ -2085,7 +2117,10 @@ void Player::processTick(const Move* move)
else if (delta.rot.z > M_PI_F)
delta.rot.z -= M_2PI_F;
setPosition(delta.pos,delta.rot);
if (!ignore_updates)
{
setPosition(delta.pos,delta.rot);
}
updateDeathOffsets();
updateLookAnimation();
@ -2183,7 +2218,8 @@ void Player::interpolateTick(F32 dt)
Point3F pos = delta.pos + delta.posVec * 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
@ -2208,6 +2244,9 @@ void Player::advanceTime(F32 dt)
{
// Client side animations
Parent::advanceTime(dt);
// Increment timer for triggering idle events.
if (idle_timer >= 0.0f)
idle_timer += dt;
updateActionThread();
updateAnimation(dt);
updateSplash();
@ -2498,6 +2537,30 @@ AngAxisF gPlayerMoveRot;
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;
#ifdef TORQUE_OPENVR
@ -2740,7 +2803,12 @@ void Player::updateMove(const Move* move)
// Desired move direction & speed
VectorF moveVec;
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);
moveVec *= (move->x * (mPose == SprintPose ? mDataBlock->sprintStrafeScale : 1.0f));
@ -2799,6 +2867,9 @@ void Player::updateMove(const Move* move)
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
VectorF acc(0.0f, 0.0f, mGravity * mGravityMod * TickSec);
@ -3025,7 +3096,9 @@ void Player::updateMove(const Move* move)
mContactTimer++;
// 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
F32 zSpeedScale = mVelocity.z;
@ -3076,6 +3149,9 @@ void Player::updateMove(const Move* move)
setActionThread( seq, true, false, true );
mJumpSurfaceLastContact = JumpSkipContactsMax;
// Flag the jump event trigger.
fx_s_triggers |= PLAYER_JUMP_S_TRIGGER;
setMaskBits(TriggerMask);
}
}
else
@ -3493,6 +3569,19 @@ void Player::updateDamageState()
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.
Point3F renderHead = delta.head + delta.headVec * dt;
@ -3533,6 +3622,8 @@ void Player::updateLookAnimation(F32 dt)
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.action < mDataBlock->actionCount)
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)
{
if (anim_clip_flags & ANIM_OVERRIDDEN)
return false;
for (U32 i = 1; i < mDataBlock->actionCount; 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;
}
if (isClientObject())
{
mark_idle = (action == PlayerData::RootAnim);
idle_timer = (mark_idle) ? 0.0f : -1.0f;
}
PlayerData::ActionAnimation &anim = mDataBlock->actionList[action];
if (anim.sequence != -1)
{
@ -3858,7 +3956,8 @@ void Player::updateActionThread()
offset = mDataBlock->decalOffset * getScale().x;
}
if( triggeredLeft || triggeredRight )
process_client_triggers(triggeredLeft, triggeredRight);
if ((triggeredLeft || triggeredRight) && !noFootfallFX)
{
Point3F rot, pos;
RayInfo rInfo;
@ -3875,7 +3974,7 @@ void Player::updateActionThread()
// Put footprints on surface, if appropriate for material.
if( material && material->mShowFootprints
&& mDataBlock->decalData )
&& mDataBlock->decalData && !footfallDecalOverride )
{
Point3F normal;
Point3F tangent;
@ -3886,8 +3985,8 @@ void Player::updateActionThread()
// Emit footpuffs.
if( rInfo.t <= 0.5 && mWaterCoverage == 0.0
&& material && material->mShowDust )
if (!footfallDustOverride && rInfo.t <= 0.5f && mWaterCoverage == 0.0f
&& material && material->mShowDust )
{
// New emitter every time for visibility reasons
ParticleEmitter * emitter = new ParticleEmitter;
@ -3920,6 +4019,7 @@ void Player::updateActionThread()
// Play footstep sound.
if (footfallSoundOverride <= 0)
playFootstepSound( triggeredLeft, material, rInfo.object );
}
}
@ -3941,8 +4041,10 @@ void Player::updateActionThread()
pickActionAnimation();
}
// prevent scaling of AFX picked actions
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
PlayerData::ActionAnimation &anim =
@ -4560,6 +4662,10 @@ void Player::updateAnimation(F32 dt)
if (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
// to make sure the transforms are up to date as they are used
// to setup the camera.
@ -4573,6 +4679,11 @@ void Player::updateAnimation(F32 dt)
else
{
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
// and query 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
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)
{
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;
// 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(&rot.z);
rot.x = rot.y = 0;
setPosition(pos,rot);
if (!ignore_updates)
setPosition(pos,rot);
delta.head = mHead;
delta.rot = rot;
@ -6188,6 +6310,7 @@ U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
mArmAnimation.action != mDataBlock->lookAction))) {
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.
// 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;
}
afx_unpackUpdate(con, stream);
// Done if controlled by client ( and not initial update )
if(stream->readFlag())
return;
@ -6391,7 +6515,8 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream)
}
delta.pos = pos;
delta.rot = rot;
setPosition(pos,rot);
if (!ignore_updates)
setPosition(pos,rot);
}
}
else
@ -6403,7 +6528,8 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream)
delta.rotVec.set(0.0f, 0.0f, 0.0f);
delta.warpTicks = 0;
delta.dt = 0.0f;
setPosition(pos,rot);
if (!ignore_updates)
setPosition(pos,rot);
}
}
F32 energy = stream->readFloat(EnergyLevelBits) * mDataBlock->maxEnergy;
@ -6819,6 +6945,7 @@ void Player::consoleInit()
Con::addVariable("$player::extendedMoveHeadPosRotIndex", TypeS32, &smExtendedMoveHeadPosRotIndex,
"@brief The ExtendedMove position/rotation index used for head movements.\n\n"
"@ingroup GameObjects\n");
afx_consoleInit();
}
//--------------------------------------------------------------------------
@ -6863,6 +6990,8 @@ void Player::calcClassRenderData()
void Player::playFootstepSound( bool triggeredLeft, Material* contactMaterial, SceneObject* contactObject )
{
if (footfallSoundOverride > 0)
return;
MatrixF footMat = getTransform();
if( mWaterCoverage > 0.0 )
{
@ -7172,6 +7301,340 @@ void Player::renderConvex( ObjectRenderInst *ri, SceneRenderState *state, BaseMa
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
void Player::setControllers(Vector<OpenVRTrackedObject*> controllerList)
{

View file

@ -20,6 +20,11 @@
// 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_
#define _PLAYER_H_
@ -401,7 +406,8 @@ protected:
ActionMask = Parent::NextFreeMask << 0,
MoveMask = Parent::NextFreeMask << 1,
ImpactMask = Parent::NextFreeMask << 2,
NextFreeMask = Parent::NextFreeMask << 3
TriggerMask = Parent::NextFreeMask << 3,
NextFreeMask = Parent::NextFreeMask << 4
};
SimObjectPtr<ParticleEmitter> mSplashEmitter[PlayerData::NUM_SPLASH_EMITTERS];
@ -780,6 +786,89 @@ public:
virtual void prepRenderImage( SceneRenderState* state );
virtual void renderConvex( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
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;

View file

@ -20,6 +20,11 @@
// 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 "T3D/projectile.h"
@ -190,6 +195,40 @@ ProjectileData::ProjectileData()
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()
@ -274,6 +313,13 @@ void ProjectileData::initPersistFields()
"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"
"@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();
}
@ -574,6 +620,11 @@ Projectile::Projectile()
mLightState.clear();
mLightState.setLightInfo( mLight );
mDataBlock = 0;
ignoreSourceTimeout = false;
dynamicCollisionMask = csmDynamicCollisionMask;
staticCollisionMask = csmStaticCollisionMask;
}
Projectile::~Projectile()
@ -582,6 +633,11 @@ Projectile::~Projectile()
delete mProjectileShape;
mProjectileShape = NULL;
if (mDataBlock && mDataBlock->isTempClone())
{
delete mDataBlock;
mDataBlock = 0;
}
}
//--------------------------------------------------------------------------
@ -609,6 +665,7 @@ void Projectile::initPersistFields()
addField("sourceSlot", TypeS32, Offset(mSourceObjectSlot, Projectile),
"@brief The sourceObject's weapon slot that the projectile originates from.\n\n");
addField("ignoreSourceTimeout", TypeBool, Offset(ignoreSourceTimeout, Projectile));
endGroup("Source");
@ -1088,7 +1145,7 @@ void Projectile::simulate( F32 dt )
// disable the source objects collision reponse for a short time while we
// determine if the projectile is capable of moving from the old position
// to the new position, otherwise we'll hit ourself
bool disableSourceObjCollision = (mSourceObject.isValid() && mCurrTick <= SourceIdTimeoutTicks);
bool disableSourceObjCollision = (mSourceObject.isValid() && (ignoreSourceTimeout || mCurrTick <= SourceIdTimeoutTicks));
if ( disableSourceObjCollision )
mSourceObject->disableCollision();
disableCollision();
@ -1105,12 +1162,12 @@ void Projectile::simulate( F32 dt )
if ( mPhysicsWorld )
hit = mPhysicsWorld->castRay( oldPosition, newPosition, &rInfo, Point3F( newPosition - oldPosition) * mDataBlock->impactForce );
else
hit = getContainer()->castRay(oldPosition, newPosition, csmDynamicCollisionMask | csmStaticCollisionMask, &rInfo);
hit = getContainer()->castRay(oldPosition, newPosition, dynamicCollisionMask | staticCollisionMask, &rInfo);
if ( hit )
{
// make sure the client knows to bounce
if ( isServerObject() && ( rInfo.object->getTypeMask() & csmStaticCollisionMask ) == 0 )
if(isServerObject() && (rInfo.object->getTypeMask() & staticCollisionMask) == 0)
setMaskBits( BounceMask );
MatrixF xform( true );
@ -1301,6 +1358,7 @@ U32 Projectile::packUpdate( NetConnection *con, U32 mask, BitStream *stream )
stream->writeRangedU32( U32(mSourceObjectSlot),
0,
ShapeBase::MaxMountedImages - 1 );
stream->writeFlag(ignoreSourceTimeout);
}
else
// 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 );
mSourceObjectSlot = stream->readRangedU32( 0, ShapeBase::MaxMountedImages - 1 );
ignoreSourceTimeout = stream->readFlag();
NetObject* pObject = con->resolveGhost( mSourceObjectId );
if ( pObject != NULL )
mSourceObject = dynamic_cast<ShapeBase*>( pObject );

View file

@ -20,6 +20,11 @@
// 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_
#define _PROJECTILE_H_
@ -144,6 +149,9 @@ public:
DECLARE_CALLBACK( void, onExplode, ( Projectile* proj, Point3F pos, F32 fade ) );
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 mExplosionNormal;
U32 mCollideHitType;
public:
bool ignoreSourceTimeout;
U32 dynamicCollisionMask;
U32 staticCollisionMask;
};
#endif // _PROJECTILE_H_

View file

@ -20,6 +20,11 @@
// 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 "T3D/shapeBase.h"
@ -194,6 +199,69 @@ ShapeBaseData::ShapeBaseData()
inheritEnergyFromMount( false )
{
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
@ -228,6 +296,8 @@ static ShapeBaseDataProto gShapeBaseDataProto;
ShapeBaseData::~ShapeBaseData()
{
if (remap_buffer && !isTempClone())
dFree(remap_buffer);
}
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 (!silent_bbox_check)
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;
}
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());
collisionBounds.last() = mShape->bounds;
}
@ -413,6 +485,29 @@ bool ShapeBaseData::preload(bool server, String &errorStr)
F32 w = mShape->bounds.len_y() / 2;
if (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)
@ -586,6 +681,12 @@ void ShapeBaseData::initPersistFields()
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();
}
@ -738,6 +839,8 @@ void ShapeBaseData::packData(BitStream* stream)
//stream->write(reflectMinDist);
//stream->write(reflectMaxDist);
//stream->write(reflectDetailAdjust);
stream->writeString(remap_txr_tags);
stream->writeFlag(silent_bbox_check);
}
void ShapeBaseData::unpackData(BitStream* stream)
@ -839,6 +942,8 @@ void ShapeBaseData::unpackData(BitStream* stream)
//stream->read(&reflectMinDist);
//stream->read(&reflectMaxDist);
//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++)
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 )
{
// 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 );
bool isInitialDataBlock = ( mDataBlock == 0 );
@ -1098,10 +1220,61 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
// a shape assigned to this object.
if (bool(mDataBlock->mShape)) {
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());
if (isClientObject())
{
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;
resetWorldBox();
@ -3550,6 +3723,31 @@ void ShapeBase::setCurrentWaterObject( WaterObject *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 ),,
@ -4945,3 +5143,202 @@ DefineEngineMethod( ShapeBase, getModelFile, const char *, (),,
const char *fieldName = StringTable->insert( String("shapeFile") );
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());
}
}

View file

@ -20,6 +20,10 @@
// 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_
#define _SHAPEBASE_H_
@ -654,6 +658,17 @@ public:
DECLARE_CALLBACK(void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name));
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:
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);
};

View file

@ -20,6 +20,10 @@
// 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 "core/dnet.h"
#include "core/stream/bitStream.h"
@ -97,6 +101,14 @@ StaticShapeData::StaticShapeData()
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()
{
addField("noIndividualDamage", TypeBool, Offset(noIndividualDamage, StaticShapeData), "Deprecated\n\n @internal");

View file

@ -20,6 +20,11 @@
// 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_
#define _STATICSHAPE_H_
@ -38,12 +43,16 @@ struct StaticShapeData: public ShapeBaseData {
bool noIndividualDamage;
S32 dynamicTypeField;
bool isShielded;
F32 energyPerDamagePoint; // Re-added for AFX
//
DECLARE_CONOBJECT(StaticShapeData);
static void initPersistFields();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
public:
StaticShapeData(const StaticShapeData&, bool = false);
virtual bool allowSubstitutions() const { return true; }
};

View file

@ -20,6 +20,11 @@
// 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 "T3D/tsStatic.h"
@ -54,6 +59,8 @@ using namespace Torque;
extern bool gEditingMission;
#include "afx/ce/afxZodiacMgr.h"
IMPLEMENT_CO_NETOBJECT_V1(TSStatic);
ConsoleDocClass( TSStatic,
@ -124,6 +131,12 @@ TSStatic::TSStatic()
mCollisionType = CollisionMesh;
mDecalType = CollisionMesh;
mIgnoreZodiacs = false;
mHasGradients = false;
mInvertGradientRange = false;
mGradientRangeUser.set(0.0f, 180.0f);
afxZodiacData::convertGradientRangeFromDegrees(mGradientRange, mGradientRangeUser);
}
TSStatic::~TSStatic()
@ -222,6 +235,12 @@ void TSStatic::initPersistFields()
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();
}
@ -323,6 +342,8 @@ bool TSStatic::_createShape()
{
// Cleanup before we create.
mCollisionDetails.clear();
mDecalDetails.clear();
mDecalDetailsPtr = 0;
mLOSDetails.clear();
SAFE_DELETE( mPhysicsRep );
SAFE_DELETE( mShapeInstance );
@ -354,6 +375,8 @@ bool TSStatic::_createShape()
mShapeInstance = new TSShapeInstance( mShape, isClientObject() );
if (isClientObject())
mShapeInstance->cloneMaterialList();
if( isGhost() )
{
// Reapply the current skin
@ -396,11 +419,29 @@ void TSStatic::prepCollision()
// Cleanup any old collision data
mCollisionDetails.clear();
mDecalDetails.clear();
mDecalDetailsPtr = 0;
mLOSDetails.clear();
mConvexList->nukeList();
if ( mCollisionType == CollisionMesh || mCollisionType == VisibleMesh )
{
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();
}
@ -681,6 +722,8 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
}
mShapeInstance->render( rdata );
if (!mIgnoreZodiacs && mDecalDetailsPtr != 0)
afxZodiacMgr::renderPolysoupZodiacs(state, this);
if ( mRenderNormalScalar > 0 )
{
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
@ -786,6 +829,13 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
stream->write(mInvertAlphaFade);
}
stream->writeFlag(mIgnoreZodiacs);
if (stream->writeFlag(mHasGradients))
{
stream->writeFlag(mInvertGradientRange);
stream->write(mGradientRange.x);
stream->write(mGradientRange.y);
}
if ( mLightPlugin )
retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
@ -870,6 +920,14 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
stream->read(&mInvertAlphaFade);
}
mIgnoreZodiacs = stream->readFlag();
mHasGradients = stream->readFlag();
if (mHasGradients)
{
mInvertGradientRange = stream->readFlag();
stream->read(&mGradientRange.x);
stream->read(&mGradientRange.y);
}
if ( mLightPlugin )
{
mLightPlugin->unpackUpdate(this, con, stream);
@ -882,6 +940,7 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
if ( isProperlyAdded() )
_updateShouldTick();
set_special_typing();
}
//----------------------------------------------------------------------------
@ -992,6 +1051,11 @@ bool TSStatic::buildPolyList(PolyListContext context, AbstractPolyList* polyList
polyList->addBox( mObjBox );
else if ( meshType == VisibleMesh )
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
{
// Everything else is done from the collision meshes
@ -1324,3 +1388,41 @@ DefineEngineMethod( TSStatic, getModelFile, const char *, (),,
{
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

View file

@ -20,6 +20,11 @@
// 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_
#define _TSSTATIC_H_
@ -236,6 +241,20 @@ public:
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;

View file

@ -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
{
typedef TurretShape Parent;
protected:
#ifdef AFX_REUSE_TURRETSHAPE_MASKBITS
enum MaskBits {
TurretStateMask = Parent::TurretUpdateMask,
NextFreeMask = Parent::NextFreeMask
};
#else // ORIGINAL CODE
enum MaskBits {
TurretStateMask = Parent::NextFreeMask,
NextFreeMask = Parent::NextFreeMask << 1
};
#endif
struct TargetInfo
{

File diff suppressed because it is too large Load diff

View 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_

File diff suppressed because it is too large Load diff

View 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_

File diff suppressed because it is too large Load diff

View 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_

View 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_

View 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);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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;
}
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

File diff suppressed because it is too large Load diff

View 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_

File diff suppressed because it is too large Load diff

View 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_

File diff suppressed because it is too large Load diff

View 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_

File diff suppressed because it is too large Load diff

View 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_

View 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();
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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 );
}

View 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_

View 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);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

File diff suppressed because it is too large Load diff

View 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_

View 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();
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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);
}
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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);
}
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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);
}
}
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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];
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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));
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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;
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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();
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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();
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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);
};
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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;
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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_

View 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();
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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_

View 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);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View 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