Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -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_
@@ -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) 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);
}

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

@@ -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_
@@ -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;
}
}

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//


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

Large diffs are not rendered by default.

@@ -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;
ColorF 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(ColorF& 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(ColorF& 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_

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -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_
@@ -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();
}


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