Torque3D Documentation / _generateds / afxEffectWrapper.cpp

afxEffectWrapper.cpp

Engine/source/afx/afxEffectWrapper.cpp

More...

Public Defines

define
myOffset(field) (field, )
define
myOffset(field) (field, )

Public Functions

ConsoleDocClass(afxEffectBaseData , "@brief A datablock baseclass <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/class/classafxeffectwrapperdata/">afxEffectWrapperData</a> and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectGroupData.\n\n</a>" "Not intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used directly, <a href="/coding/class/classafxeffectbasedata/">afxEffectBaseData</a> exists <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> provide base member " "variables and generic functionality <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the derived classes <a href="/coding/class/classafxeffectwrapperdata/">afxEffectWrapperData</a> and " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectGroupData.\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectWrapperData\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectGroupData\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
ConsoleDocClass(afxEffectWrapper , "@brief An Effect Wrapper as defined by an <a href="/coding/class/classafxeffectwrapperdata/">afxEffectWrapperData</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">datablock.\n\n</a>" "Conceptually an effect wrapper encloses <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> building-block effect and acts " "as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> handle <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> adding the effect <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> choreographer. Effect wrapper fields " "primarily deal with effect timing, constraints , and conditional effect <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">execution.\n\n</a>" "Not intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used directly, <a href="/coding/class/classafxeffectwrapper/">afxEffectWrapper</a> is an internal baseclass used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> " "implement effect-specific adapter <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">classes.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" )
ConsoleDocClass(afxEffectWrapperData , "@brief A datablock that describes an Effect <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Wrapper.\n\n</a>" "Conceptually an effect wrapper encloses <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> building-block effect and acts " "as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> handle <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> adding the effect <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> choreographer. Effect wrapper fields " "primarily deal with effect timing, constraints , and conditional effect <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">execution.\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectBaseData\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectGroupData\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )

Detailed Description

Public Defines

myOffset(field) (field, )
myOffset(field) (field, )

Public Functions

ConsoleDocClass(afxEffectBaseData , "@brief A datablock baseclass <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/class/classafxeffectwrapperdata/">afxEffectWrapperData</a> and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectGroupData.\n\n</a>" "Not intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used directly, <a href="/coding/class/classafxeffectbasedata/">afxEffectBaseData</a> exists <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> provide base member " "variables and generic functionality <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the derived classes <a href="/coding/class/classafxeffectwrapperdata/">afxEffectWrapperData</a> and " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectGroupData.\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectWrapperData\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectGroupData\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )

ConsoleDocClass(afxEffectWrapper , "@brief An Effect Wrapper as defined by an <a href="/coding/class/classafxeffectwrapperdata/">afxEffectWrapperData</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">datablock.\n\n</a>" "Conceptually an effect wrapper encloses <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> building-block effect and acts " "as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> handle <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> adding the effect <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> choreographer. Effect wrapper fields " "primarily deal with effect timing, constraints , and conditional effect <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">execution.\n\n</a>" "Not intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used directly, <a href="/coding/class/classafxeffectwrapper/">afxEffectWrapper</a> is an internal baseclass used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> " "implement effect-specific adapter <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">classes.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" )

ConsoleDocClass(afxEffectWrapperData , "@brief A datablock that describes an Effect <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Wrapper.\n\n</a>" "Conceptually an effect wrapper encloses <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> building-block effect and acts " "as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> handle <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> adding the effect <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> choreographer. Effect wrapper fields " "primarily deal with effect timing, constraints , and conditional effect <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">execution.\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectBaseData\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffectGroupData\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )

IMPLEMENT_CO_DATABLOCK_V1(afxEffectBaseData )

IMPLEMENT_CO_DATABLOCK_V1(afxEffectWrapperData )

IMPLEMENT_CONOBJECT(afxEffectWrapper )

num_modifiers(afxXM_BaseData * mods)

   1
   2
   3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
   4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
   5// Copyright (C) 2015 Faust Logic, Inc.
   6//
   7// Permission is hereby granted, free of charge, to any person obtaining a copy
   8// of this software and associated documentation files (the "Software"), to
   9// deal in the Software without restriction, including without limitation the
  10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  11// sell copies of the Software, and to permit persons to whom the Software is
  12// furnished to do so, subject to the following conditions:
  13//
  14// The above copyright notice and this permission notice shall be included in
  15// all copies or substantial portions of the Software.
  16//
  17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  23// IN THE SOFTWARE.
  24//
  25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26
  27#include "afx/arcaneFX.h"
  28
  29#include "math/mathIO.h"
  30
  31#include "afx/ce/afxComponentEffect.h"
  32#include "afx/afxResidueMgr.h"
  33#include "afx/afxChoreographer.h"
  34#include "afx/afxConstraint.h"
  35#include "afx/xm/afxXfmMod.h"
  36#include "afx/afxEffectWrapper.h"
  37#include "afx/util/afxAnimCurve.h"
  38#include "afx/util/afxEase.h"
  39
  40//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  41// afxEffectWrapperData
  42
  43IMPLEMENT_CO_DATABLOCK_V1(afxEffectBaseData);
  44
  45ConsoleDocClass( afxEffectBaseData,
  46   "@brief A datablock baseclass for afxEffectWrapperData and afxEffectGroupData.\n\n"
  47
  48   "Not intended to be used directly, afxEffectBaseData exists to provide base member "
  49   "variables and generic functionality for the derived classes afxEffectWrapperData and "
  50   "afxEffectGroupData.\n\n"
  51
  52   "@see afxEffectWrapperData\n\n"
  53   "@see afxEffectGroupData\n\n"
  54
  55   "@ingroup afxEffects\n"
  56   "@ingroup AFX\n"
  57   "@ingroup Datablocks\n"
  58);
  59
  60IMPLEMENT_CO_DATABLOCK_V1(afxEffectWrapperData);
  61
  62ConsoleDocClass( afxEffectWrapperData,
  63   "@brief A datablock that describes an Effect Wrapper.\n\n"
  64
  65   "Conceptually an effect wrapper encloses a building-block effect and acts "
  66   "as a handle for adding the effect to a choreographer. Effect wrapper fields "
  67   "primarily deal with effect timing, constraints, and conditional effect execution.\n\n"
  68
  69   "@see afxEffectBaseData\n\n"
  70   "@see afxEffectGroupData\n\n"
  71
  72   "@ingroup afxEffects\n"
  73   "@ingroup AFX\n"
  74   "@ingroup Datablocks\n"
  75);
  76
  77afxEffectWrapperData::afxEffectWrapperData()
  78{
  79  effect_name = ST_NULLSTRING;
  80  effect_data = 0;
  81  effect_desc = 0;
  82  data_ID = 0;
  83  use_as_cons_obj = false;
  84  use_ghost_as_cons_obj = false;
  85
  86  // constraint data
  87  cons_spec = ST_NULLSTRING;
  88  pos_cons_spec = ST_NULLSTRING;
  89  orient_cons_spec = ST_NULLSTRING;
  90  aim_cons_spec = StringTable->insert("camera");
  91  life_cons_spec = ST_NULLSTRING;
  92
  93  // conditional execution flags
  94  effect_enabled = true;
  95  ranking_range.set(0,255);
  96  lod_range.set(0,255);
  97  life_conds = 0;
  98  for (S32 i = 0; i < MAX_CONDITION_STATES; i++)
  99  { 
 100    exec_cond_on_bits[i] = 0;
 101    exec_cond_off_bits[i] = 0;
 102    exec_cond_bitmasks[i] = 0;
 103  }
 104
 105  ewd_timing.lifetime = -1;
 106
 107  user_fade_out_time = 0.0;
 108
 109  is_looping = false;
 110  n_loops = 0;
 111  loop_gap_time = 0.0f;
 112
 113  ignore_time_factor = false;
 114  propagate_time_factor = false;
 115
 116  // residue settings
 117
 118  // scaling factors
 119  rate_factor = 1.0f;
 120  scale_factor = 1.0f;
 121
 122  dMemset(xfm_modifiers, 0, sizeof(xfm_modifiers));
 123
 124  forced_bbox.minExtents.set(1,1,1);
 125  forced_bbox.maxExtents.set(-1,-1,-1);
 126
 127  update_forced_bbox = false;
 128
 129  // marked true if datablock ids need to
 130  // be converted into pointers
 131  do_id_convert = false;
 132
 133  sort_priority = 0;
 134  direction.set(0,1,0);
 135  speed = 0.0f;
 136  mass = 1.0f;
 137
 138  borrow_altitudes = false;
 139  vis_keys_spec = ST_NULLSTRING;
 140  vis_keys = 0;
 141
 142  group_index = -1;
 143  inherit_timing = 0;
 144}
 145
 146afxEffectWrapperData::afxEffectWrapperData(const afxEffectWrapperData& other, bool temp_clone) : afxEffectBaseData(other, temp_clone)
 147{
 148  effect_name = other.effect_name;
 149  effect_data = other.effect_data;
 150  effect_desc = other.effect_desc;
 151  data_ID = other.data_ID;
 152  use_as_cons_obj = other.use_as_cons_obj;
 153  use_ghost_as_cons_obj = other.use_ghost_as_cons_obj;
 154  cons_spec = other.cons_spec;
 155  pos_cons_spec = other.pos_cons_spec;
 156  orient_cons_spec = other.orient_cons_spec;
 157  aim_cons_spec = other.aim_cons_spec;
 158  life_cons_spec = other.life_cons_spec;
 159  cons_def = other.cons_def;
 160  pos_cons_def = other.pos_cons_def;
 161  orient_cons_def = other.orient_cons_def;
 162  aim_cons_def = other.aim_cons_def;
 163  life_cons_def = other.life_cons_def;
 164  effect_enabled = other.effect_enabled;
 165  ranking_range = other.ranking_range;
 166  lod_range = other.lod_range;
 167  life_conds = other.life_conds;
 168  dMemcpy(exec_cond_on_bits, other.exec_cond_on_bits, sizeof(exec_cond_on_bits));
 169  dMemcpy(exec_cond_off_bits, other.exec_cond_off_bits, sizeof(exec_cond_off_bits));
 170  dMemcpy(exec_cond_bitmasks, other.exec_cond_bitmasks, sizeof(exec_cond_bitmasks));
 171  ewd_timing = other.ewd_timing;
 172  user_fade_out_time = other.user_fade_out_time;
 173  is_looping = other.is_looping;
 174  n_loops = other.n_loops;
 175  loop_gap_time = other.loop_gap_time;
 176  ignore_time_factor = other.ignore_time_factor;
 177  propagate_time_factor = other.propagate_time_factor;
 178  rate_factor = other.rate_factor;
 179  scale_factor = other.scale_factor;
 180  dMemcpy(xfm_modifiers, other.xfm_modifiers, sizeof(xfm_modifiers));
 181  forced_bbox = other.forced_bbox;
 182  update_forced_bbox = other.update_forced_bbox;
 183  do_id_convert = other.do_id_convert;
 184  sort_priority = other.sort_priority;
 185  direction = other.direction;
 186  speed = other.speed;
 187  mass = other.mass;
 188  borrow_altitudes = other.borrow_altitudes;
 189  vis_keys_spec = other.vis_keys_spec;
 190  vis_keys = other.vis_keys;
 191  if (other.vis_keys)
 192  {
 193    vis_keys = new afxAnimCurve();
 194    for (S32 i = 0; i < other.vis_keys->numKeys(); i++)
 195    {
 196      F32 when = other.vis_keys->getKeyTime(i);
 197      F32 what = other.vis_keys->getKeyValue(i);
 198      vis_keys->addKey(when, what);
 199    }
 200  }
 201  else
 202    vis_keys = 0;
 203  group_index = other.group_index;
 204  inherit_timing = other.inherit_timing;
 205}
 206
 207afxEffectWrapperData::~afxEffectWrapperData()
 208{
 209  if (vis_keys)
 210    delete vis_keys;
 211}
 212
 213#define myOffset(field) Offset(field, afxEffectWrapperData)
 214
 215void afxEffectWrapperData::initPersistFields()
 216{
 217  // the wrapped effect
 218  addField("effect",       TYPEID<SimDataBlock>(),    myOffset(effect_data),
 219    "...");
 220  addField("effectName",   TypeString,                myOffset(effect_name),
 221    "...");
 222
 223  // constraints
 224  addField("constraint",              TypeString,   myOffset(cons_spec),
 225    "...");
 226  addField("posConstraint",           TypeString,   myOffset(pos_cons_spec),
 227    "...");
 228  addField("posConstraint2",          TypeString,   myOffset(aim_cons_spec),
 229    "...");
 230  addField("orientConstraint",        TypeString,   myOffset(orient_cons_spec),
 231    "...");
 232  addField("lifeConstraint",          TypeString,   myOffset(life_cons_spec),
 233    "...");
 234  //
 235  addField("isConstraintSrc",         TypeBool,     myOffset(use_as_cons_obj),
 236    "...");
 237  addField("ghostIsConstraintSrc",    TypeBool,     myOffset(use_ghost_as_cons_obj),
 238    "...");
 239
 240  addField("delay",             TypeF32,          myOffset(ewd_timing.delay),
 241    "...");
 242  addField("lifetime",          TypeF32,          myOffset(ewd_timing.lifetime),
 243    "...");
 244  addField("fadeInTime",        TypeF32,          myOffset(ewd_timing.fade_in_time),
 245    "...");
 246  addField("residueLifetime",   TypeF32,          myOffset(ewd_timing.residue_lifetime),
 247    "...");
 248  addField("fadeInEase",        TypePoint2F,      myOffset(ewd_timing.fadein_ease),
 249    "...");
 250  addField("fadeOutEase",       TypePoint2F,      myOffset(ewd_timing.fadeout_ease),
 251    "...");
 252  addField("lifetimeBias",      TypeF32,          myOffset(ewd_timing.life_bias),
 253    "...");
 254  addField("fadeOutTime",       TypeF32,          myOffset(user_fade_out_time),
 255    "...");
 256
 257  addField("rateFactor",        TypeF32,          myOffset(rate_factor),
 258    "...");
 259  addField("scaleFactor",       TypeF32,          myOffset(scale_factor),
 260    "...");
 261
 262  addField("isLooping",         TypeBool,         myOffset(is_looping),
 263    "...");
 264  addField("loopCount",         TypeS32,          myOffset(n_loops),
 265    "...");
 266  addField("loopGapTime",       TypeF32,          myOffset(loop_gap_time),
 267    "...");
 268
 269  addField("ignoreTimeFactor",    TypeBool,       myOffset(ignore_time_factor),
 270    "...");
 271  addField("propagateTimeFactor", TypeBool,       myOffset(propagate_time_factor),
 272    "...");
 273
 274  addField("effectEnabled",         TypeBool,         myOffset(effect_enabled),
 275    "...");
 276  addField("rankingRange",          TypeByteRange,    myOffset(ranking_range),
 277    "...");
 278  addField("levelOfDetailRange",    TypeByteRange,    myOffset(lod_range),
 279    "...");
 280  addField("lifeConditions",        TypeS32,      myOffset(life_conds),
 281    "...");
 282  addField("execConditions",        TypeS32,      myOffset(exec_cond_on_bits),  MAX_CONDITION_STATES,
 283    "...");
 284  addField("execOffConditions",     TypeS32,      myOffset(exec_cond_off_bits), MAX_CONDITION_STATES,
 285    "...");
 286
 287  addField("xfmModifiers",    TYPEID<afxXM_BaseData>(),  myOffset(xfm_modifiers),  MAX_XFM_MODIFIERS,
 288    "...");
 289
 290  addField("forcedBBox",        TypeBox3F,        myOffset(forced_bbox),
 291    "...");
 292  addField("updateForcedBBox",  TypeBool,         myOffset(update_forced_bbox),
 293    "...");
 294
 295  addField("sortPriority",      TypeS8,           myOffset(sort_priority),
 296    "...");
 297  addField("direction",         TypePoint3F,      myOffset(direction),
 298    "...");
 299  addField("speed",             TypeF32,          myOffset(speed),
 300    "...");
 301  addField("mass",              TypeF32,          myOffset(mass),
 302    "...");
 303
 304  addField("borrowAltitudes",   TypeBool,         myOffset(borrow_altitudes),
 305    "...");
 306  addField("visibilityKeys",    TypeString,       myOffset(vis_keys_spec),
 307    "...");
 308
 309  addField("groupIndex",          TypeS32,        myOffset(group_index),
 310    "...");
 311  addField("inheritGroupTiming",  TypeS32,        myOffset(inherit_timing),
 312    "...");
 313
 314  Parent::initPersistFields();
 315
 316  // disallow some field substitutions
 317  disableFieldSubstitutions("effect");
 318  onlyKeepClearSubstitutions("xfmModifiers"); // subs resolving to "~~", or "~0" are OK
 319
 320  // Conditional Execution Flags
 321  Con::setIntVariable("$afx::DISABLED", DISABLED);
 322  Con::setIntVariable("$afx::ENABLED", ENABLED);
 323  Con::setIntVariable("$afx::FAILING", FAILING);
 324  Con::setIntVariable("$afx::DEAD", DEAD);
 325  Con::setIntVariable("$afx::ALIVE", ALIVE);
 326  Con::setIntVariable("$afx::DYING", DYING);
 327}
 328
 329bool afxEffectWrapperData::onAdd()
 330{
 331  if (Parent::onAdd() == false)
 332    return false;
 333
 334  if (!effect_data)
 335  {
 336    if (!Sim::findObject((SimObjectId)data_ID, effect_data))
 337    {
 338      Con::errorf("afxEffectWrapperData::onAdd() -- bad datablockId: 0x%x", data_ID);
 339      return false;
 340    }
 341  }
 342
 343  if (effect_data)
 344  {
 345    if (!afxEffectAdapterDesc::identifyEffect(this))
 346    {
 347      Con::errorf("afxEffectWrapperData::onAdd() -- unknown effect type.");
 348      return false;
 349    }
 350  }
 351
 352  parse_cons_specs();
 353  parse_vis_keys();
 354
 355  // figure out if fade-out is for effect of residue
 356  if (ewd_timing.residue_lifetime > 0)
 357  {
 358    ewd_timing.residue_fadetime = user_fade_out_time;
 359    ewd_timing.fade_out_time = 0.0f;
 360  }
 361  else
 362  {
 363    ewd_timing.residue_fadetime = 0.0f;
 364    ewd_timing.fade_out_time = user_fade_out_time;
 365  }
 366
 367  // adjust fade-in time
 368  if (ewd_timing.lifetime >= 0)
 369  {
 370    ewd_timing.fade_in_time = getMin(ewd_timing.lifetime, ewd_timing.fade_in_time);
 371  }
 372
 373  // adjust exec-conditions
 374  for (S32 i = 0; i < MAX_CONDITION_STATES; i++)
 375    exec_cond_bitmasks[i] = exec_cond_on_bits[i] | exec_cond_off_bits[i];
 376
 377  return true;
 378}
 379
 380void afxEffectWrapperData::packData(BitStream* stream)
 381{
 382  Parent::packData(stream);
 383
 384  writeDatablockID(stream, effect_data, mPacked);
 385
 386  stream->writeString(effect_name);
 387
 388  stream->writeString(cons_spec);
 389  stream->writeString(pos_cons_spec);
 390  stream->writeString(orient_cons_spec);
 391  stream->writeString(aim_cons_spec);
 392  stream->writeString(life_cons_spec);
 393  //
 394  stream->write(use_as_cons_obj);
 395  //stream->write(use_ghost_as_cons_obj);
 396
 397  stream->writeFlag(effect_enabled);
 398  stream->write(ranking_range.low);
 399  stream->write(ranking_range.high);
 400  stream->write(lod_range.low);
 401  stream->write(lod_range.high);
 402
 403  for (S32 i = 0; i < MAX_CONDITION_STATES; i++)
 404  {
 405    stream->write(exec_cond_on_bits[i]);
 406    stream->write(exec_cond_off_bits[i]);
 407  }
 408  stream->write(life_conds);
 409  stream->write(ewd_timing.delay);
 410  stream->write(ewd_timing.lifetime);
 411  stream->write(ewd_timing.fade_in_time);
 412  stream->write(user_fade_out_time);
 413  stream->write(is_looping);
 414  stream->write(n_loops);
 415  stream->write(loop_gap_time);
 416  stream->write(ignore_time_factor);
 417  stream->write(propagate_time_factor);
 418  stream->write(ewd_timing.residue_lifetime);
 419  stream->write(rate_factor);
 420  stream->write(scale_factor);
 421
 422  // modifiers
 423  pack_mods(stream, xfm_modifiers, mPacked);
 424
 425  mathWrite(*stream, forced_bbox);
 426  stream->write(update_forced_bbox);
 427
 428  stream->write(sort_priority);
 429  mathWrite(*stream, direction);
 430  stream->write(speed);
 431  stream->write(mass);
 432
 433  stream->write(borrow_altitudes);
 434  if (stream->writeFlag(vis_keys_spec != ST_NULLSTRING))
 435    stream->writeLongString(1023, vis_keys_spec);
 436
 437  if (stream->writeFlag(group_index != -1))
 438    stream->write(group_index);
 439
 440  stream->writeInt(inherit_timing, TIMING_BITS);
 441}
 442
 443void afxEffectWrapperData::unpackData(BitStream* stream)
 444{
 445  Parent::unpackData(stream);
 446
 447  data_ID = readDatablockID(stream);
 448
 449  effect_name = stream->readSTString();
 450
 451  cons_spec = stream->readSTString();
 452  pos_cons_spec = stream->readSTString();
 453  orient_cons_spec = stream->readSTString();
 454  aim_cons_spec = stream->readSTString();
 455  life_cons_spec = stream->readSTString();
 456  //
 457  stream->read(&use_as_cons_obj);
 458  //stream->read(&use_ghost_as_cons_obj);
 459
 460  effect_enabled = stream->readFlag();
 461  stream->read(&ranking_range.low);
 462  stream->read(&ranking_range.high);
 463  stream->read(&lod_range.low);
 464  stream->read(&lod_range.high);
 465
 466  for (S32 i = 0; i < MAX_CONDITION_STATES; i++)
 467  {
 468    stream->read(&exec_cond_on_bits[i]);
 469    stream->read(&exec_cond_off_bits[i]);
 470  }
 471  stream->read(&life_conds);
 472  stream->read(&ewd_timing.delay);
 473  stream->read(&ewd_timing.lifetime);
 474  stream->read(&ewd_timing.fade_in_time);
 475  stream->read(&user_fade_out_time);
 476  stream->read(&is_looping);
 477  stream->read(&n_loops);
 478  stream->read(&loop_gap_time);
 479  stream->read(&ignore_time_factor);
 480  stream->read(&propagate_time_factor);
 481  stream->read(&ewd_timing.residue_lifetime);
 482  stream->read(&rate_factor);
 483  stream->read(&scale_factor);
 484
 485  // modifiers
 486  do_id_convert = true;
 487  unpack_mods(stream, xfm_modifiers);
 488
 489  mathRead(*stream, &forced_bbox);
 490  stream->read(&update_forced_bbox);
 491
 492  stream->read(&sort_priority);
 493  mathRead(*stream, &direction);
 494  stream->read(&speed);
 495  stream->read(&mass);
 496
 497  stream->read(&borrow_altitudes);
 498  if (stream->readFlag())
 499  {
 500    char buf[1024];
 501    stream->readLongString(1023, buf);
 502    vis_keys_spec = StringTable->insert(buf);
 503  }
 504  else
 505    vis_keys_spec = ST_NULLSTRING;
 506
 507  if (stream->readFlag())
 508    stream->read(&group_index);
 509  else
 510    group_index = -1;
 511
 512  inherit_timing = stream->readInt(TIMING_BITS);
 513}
 514
 515/* static*/ 
 516S32 num_modifiers(afxXM_BaseData* mods[])
 517{
 518  S32 n_mods = 0;
 519  for (int i = 0; i < afxEffectDefs::MAX_XFM_MODIFIERS; i++)
 520  {
 521    if (mods[i])
 522    {
 523      if (i != n_mods)
 524      {
 525        mods[n_mods] = mods[i];
 526        mods[i] = 0;
 527      }
 528      n_mods++;
 529    }
 530  }
 531
 532  return n_mods;
 533}
 534
 535void afxEffectWrapperData::parse_cons_specs()
 536{
 537  // parse the constraint specifications
 538  bool runs_on_s = runsOnServer();
 539  bool runs_on_c = runsOnClient();
 540  cons_def.parseSpec(cons_spec, runs_on_s, runs_on_c);
 541  pos_cons_def.parseSpec(pos_cons_spec, runs_on_s, runs_on_c);
 542  orient_cons_def.parseSpec(orient_cons_spec, runs_on_s, runs_on_c);
 543  aim_cons_def.parseSpec(aim_cons_spec, runs_on_s, runs_on_c);
 544  life_cons_def.parseSpec(life_cons_spec, runs_on_s, runs_on_c);
 545  if (cons_def.isDefined())
 546  {
 547    pos_cons_def = cons_def;
 548    if (!orient_cons_def.isDefined())
 549      orient_cons_def = cons_def;
 550  }
 551}
 552
 553void afxEffectWrapperData::parse_vis_keys()
 554{
 555  if (vis_keys_spec != ST_NULLSTRING)
 556  {
 557    if (vis_keys)
 558      delete vis_keys;
 559    vis_keys = new afxAnimCurve();
 560
 561    char* keys_buffer = dStrdup(vis_keys_spec);
 562
 563    char* key_token = dStrtok(keys_buffer, " \t");
 564    while (key_token != NULL)
 565    {
 566      char* colon = dStrchr(key_token, ':');
 567      if (colon)
 568      {
 569        *colon = '\0';
 570
 571        F32 when = dAtof(key_token);
 572        F32 what = dAtof(colon+1);
 573
 574        vis_keys->addKey(when, what);
 575      }
 576      key_token = dStrtok(NULL, " \t");
 577    }
 578
 579    dFree(keys_buffer);
 580    vis_keys->sort();
 581  }
 582}
 583
 584void afxEffectWrapperData::gather_cons_defs(Vector<afxConstraintDef>& defs)
 585{
 586  if (pos_cons_def.isDefined())
 587    defs.push_back(pos_cons_def);
 588  if (orient_cons_def.isDefined())
 589    defs.push_back(orient_cons_def);
 590  if (aim_cons_def.isDefined())
 591    defs.push_back(aim_cons_def);
 592  if (life_cons_def.isDefined())
 593    defs.push_back(life_cons_def);
 594
 595  afxComponentEffectData* ce_data = dynamic_cast<afxComponentEffectData*>(effect_data);
 596  if (ce_data)
 597    ce_data->gather_cons_defs(defs);
 598}
 599
 600void afxEffectWrapperData::pack_mods(BitStream* stream, afxXM_BaseData* mods[], bool packed)
 601{
 602  S32 n_mods = num_modifiers(mods);
 603  stream->writeInt(n_mods, 6);
 604  for (int i = 0; i < n_mods; i++)
 605    writeDatablockID(stream, mods[i], packed);
 606}
 607
 608void afxEffectWrapperData::unpack_mods(BitStream* stream, afxXM_BaseData* mods[])
 609{
 610  S32 n_mods = stream->readInt(6);
 611  for (int i = 0; i < n_mods; i++)
 612    mods[i] = (afxXM_BaseData*)(uintptr_t)readDatablockID(stream);
 613}
 614
 615bool afxEffectWrapperData::preload(bool server, String &errorStr)
 616{
 617  if (!Parent::preload(server, errorStr))
 618    return false;
 619  
 620  // Resolve objects transmitted from server
 621  if (!server) 
 622  {
 623    if (do_id_convert)
 624    {
 625      for (int i = 0; i < MAX_XFM_MODIFIERS; i++)
 626      {
 627        SimObjectId db_id = SimObjectId((uintptr_t)xfm_modifiers[i]);
 628        if (db_id != 0)
 629        {
 630          // try to convert id to pointer
 631          if (!Sim::findObject(db_id, xfm_modifiers[i]))
 632          {
 633            Con::errorf("afxEffectWrapperData::preload() -- bad datablockId: 0x%x (xfm_modifiers[%d])",
 634              db_id, i);
 635          }
 636        }
 637        do_id_convert = false;
 638      }
 639    }
 640  }
 641  
 642  return true;
 643}
 644
 645void afxEffectWrapperData::onPerformSubstitutions()
 646{
 647  Parent::onPerformSubstitutions();
 648
 649  parse_cons_specs();
 650  parse_vis_keys();
 651
 652  if (ewd_timing.residue_lifetime > 0)
 653  {
 654    ewd_timing.residue_fadetime = user_fade_out_time;
 655    ewd_timing.fade_out_time = 0.0f;
 656  }
 657  else
 658  {
 659    ewd_timing.residue_fadetime = 0.0f;
 660    ewd_timing.fade_out_time = user_fade_out_time;
 661  }
 662}
 663
 664//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 665// afxEffectWrapper
 666
 667IMPLEMENT_CONOBJECT(afxEffectWrapper);
 668
 669ConsoleDocClass( afxEffectWrapper,
 670   "@brief An Effect Wrapper as defined by an afxEffectWrapperData datablock.\n\n"
 671
 672   "Conceptually an effect wrapper encloses a building-block effect and acts "
 673   "as a handle for adding the effect to a choreographer. Effect wrapper fields "
 674   "primarily deal with effect timing, constraints, and conditional effect execution.\n\n"
 675
 676   "Not intended to be used directly, afxEffectWrapper is an internal baseclass used to "
 677   "implement effect-specific adapter classes.\n\n"
 678
 679   "@ingroup afxEffects\n"
 680   "@ingroup AFX\n"
 681);
 682
 683afxEffectWrapper::afxEffectWrapper()
 684{
 685  mChoreographer = 0;
 686  mDatablock = 0;
 687  mCons_mgr = 0;
 688
 689  mCond_alive = true;
 690  mElapsed = 0;
 691  mLife_end = 0;
 692  mLife_elapsed = 0;
 693  mStopped = false;
 694  mNum_updates = 0;
 695  mFade_value = 1.0f;
 696  mLast_fade_value = 0.0f;
 697  mFade_in_end = 0.0;
 698  mFade_out_start = 0.0f;
 699  mIn_scope = true;
 700  mIs_aborted = false;
 701  mDo_fade_inout = false;
 702  mDo_fades = false;
 703  mFull_lifetime = 0;
 704
 705  mTime_factor = 1.0f;
 706  mProp_time_factor = 1.0f;
 707
 708  mLive_scale_factor = 1.0f;
 709  mLive_fade_factor = 1.0f;
 710  mTerrain_altitude = -1.0f;
 711  mInterior_altitude = -1.0f;
 712
 713  mGroup_index = 0;
 714
 715  dMemset(mXfm_modifiers, 0, sizeof(mXfm_modifiers));
 716}
 717
 718afxEffectWrapper::~afxEffectWrapper()
 719{
 720  for (S32 i = 0; i < MAX_XFM_MODIFIERS; i++)
 721    if (mXfm_modifiers[i])
 722      delete mXfm_modifiers[i];
 723
 724  if (mDatablock && mDatablock->effect_name != ST_NULLSTRING)
 725  {
 726    mChoreographer->removeNamedEffect(this);
 727    if (mDatablock->use_as_cons_obj && !mEffect_cons_id.undefined())
 728      mCons_mgr->setReferenceEffect(mEffect_cons_id, 0);
 729  }
 730
 731  if (mDatablock && mDatablock->isTempClone())
 732    delete mDatablock;
 733  mDatablock = 0;
 734}
 735
 736#undef myOffset
 737#define myOffset(field) Offset(field, afxEffectWrapper)
 738
 739void afxEffectWrapper::initPersistFields()
 740{
 741  addField("liveScaleFactor",     TypeF32,    myOffset(mLive_scale_factor),
 742    "...");
 743  addField("liveFadeFactor",      TypeF32,    myOffset(mLive_fade_factor),
 744    "...");
 745
 746  Parent::initPersistFields();
 747}
 748
 749void afxEffectWrapper::ew_init(afxChoreographer*     choreographer, 
 750                               afxEffectWrapperData* datablock, 
 751                               afxConstraintMgr*     cons_mgr,
 752                               F32                   time_factor)
 753{
 754  AssertFatal(choreographer != NULL, "Choreographer is missing.");
 755  AssertFatal(datablock != NULL, "Datablock is missing.");
 756  AssertFatal(cons_mgr != NULL, "Constraint manager is missing.");
 757
 758  mChoreographer = choreographer;
 759  mDatablock = datablock;
 760  mCons_mgr = cons_mgr;
 761  ea_set_datablock(datablock->effect_data);
 762
 763  mEW_timing = datablock->ewd_timing;
 764  if (mEW_timing.life_bias != 1.0f)
 765  {
 766    if (mEW_timing.lifetime > 0)
 767      mEW_timing.lifetime *= mEW_timing.life_bias;
 768   mEW_timing.fade_in_time *= mEW_timing.life_bias;
 769   mEW_timing.fade_out_time *= mEW_timing.life_bias;
 770  }
 771
 772  mPos_cons_id = cons_mgr->getConstraintId(datablock->pos_cons_def);
 773  mOrient_cons_id = cons_mgr->getConstraintId(datablock->orient_cons_def);
 774  mAim_cons_id = cons_mgr->getConstraintId(datablock->aim_cons_def);
 775  mLife_cons_id = cons_mgr->getConstraintId(datablock->life_cons_def);
 776
 777  mTime_factor = (datablock->ignore_time_factor) ? 1.0f : time_factor;
 778
 779  if (datablock->propagate_time_factor)
 780    mProp_time_factor = time_factor;
 781
 782  if (datablock->runsHere(choreographer->isServerObject()))
 783  {
 784    for (int i = 0; i < MAX_XFM_MODIFIERS && datablock->xfm_modifiers[i] != 0; i++)
 785    {
 786      mXfm_modifiers[i] = datablock->xfm_modifiers[i]->create(this, choreographer->isServerObject());
 787      AssertFatal(mXfm_modifiers[i] != 0, avar("Error, creation failed for xfm_modifiers[%d] of %s.", i, datablock->getName()));
 788      if (mXfm_modifiers[i] == 0)
 789        Con::errorf("Error, creation failed for xfm_modifiers[%d] of %s.", i, datablock->getName());
 790    }
 791  }
 792
 793  if (datablock->effect_name != ST_NULLSTRING)
 794  {
 795    assignName(datablock->effect_name);
 796    choreographer->addNamedEffect(this);
 797    if (datablock->use_as_cons_obj)
 798    {
 799      mEffect_cons_id = cons_mgr->setReferenceEffect(datablock->effect_name, this);
 800      if (mEffect_cons_id.undefined() && datablock->isTempClone() && datablock->runsHere(choreographer->isServerObject()))
 801        mEffect_cons_id = cons_mgr->createReferenceEffect(datablock->effect_name, this);
 802    }
 803  }
 804}
 805
 806void afxEffectWrapper::prestart() 
 807{
 808  // modify timing values by time_factor
 809  if (mEW_timing.lifetime > 0)
 810    mEW_timing.lifetime *= mTime_factor;
 811  mEW_timing.delay *= mTime_factor;
 812  mEW_timing.fade_in_time *= mTime_factor;
 813  mEW_timing.fade_out_time *= mTime_factor;
 814
 815  if (mEW_timing.lifetime < 0)
 816  {
 817    mFull_lifetime = INFINITE_LIFETIME;
 818    mLife_end = INFINITE_LIFETIME;
 819  }
 820  else
 821  {
 822    mFull_lifetime = mEW_timing.lifetime + mEW_timing.fade_out_time;
 823   mLife_end = mEW_timing.delay + mEW_timing.lifetime;
 824  }
 825
 826  if ((mEW_timing.fade_in_time + mEW_timing.fade_out_time) > 0.0f)
 827  {
 828    mFade_in_end = mEW_timing.delay + mEW_timing.fade_in_time;
 829    if (mFull_lifetime == INFINITE_LIFETIME)
 830      mFade_out_start = INFINITE_LIFETIME;
 831    else
 832      mFade_out_start = mEW_timing.delay + mEW_timing.lifetime;
 833    mDo_fade_inout = true;
 834  }
 835
 836  if (!mDo_fade_inout && mDatablock->vis_keys != NULL && mDatablock->vis_keys->numKeys() > 0)
 837  {
 838    //do_fades = true;
 839    mFade_out_start = mEW_timing.delay + mEW_timing.lifetime;
 840  }
 841}
 842
 843bool afxEffectWrapper::start(F32 timestamp) 
 844{ 
 845  if (!ea_is_enabled())
 846  {
 847    Con::warnf("afxEffectWrapper::start() -- effect type of %s is currently disabled.", mDatablock->getName());
 848    return false;
 849  }
 850
 851  afxConstraint* life_constraint = getLifeConstraint();
 852  if (life_constraint)
 853    mCond_alive = life_constraint->getLivingState();
 854
 855  mElapsed = timestamp; 
 856
 857  for (S32 i = 0; i < MAX_XFM_MODIFIERS; i++)
 858  {
 859    if (!mXfm_modifiers[i])
 860      break;
 861    else
 862      mXfm_modifiers[i]->start(timestamp);
 863  }
 864
 865  if (!ea_start())
 866  {
 867    // subclass should print error message if applicable, so no message here.
 868    return false;
 869  }
 870
 871  update(0.0f);
 872  return !isAborted();
 873}
 874
 875bool afxEffectWrapper::test_life_conds()
 876{
 877  afxConstraint* life_constraint = getLifeConstraint();
 878  if (!life_constraint || mDatablock->life_conds == 0)
 879    return true;
 880
 881  S32 now_state = life_constraint->getDamageState();
 882  if ((mDatablock->life_conds & DEAD) != 0 && now_state == ShapeBase::Disabled)
 883    return true;
 884  if ((mDatablock->life_conds & ALIVE) != 0 && now_state == ShapeBase::Enabled)
 885    return true;
 886  if ((mDatablock->life_conds & DYING) != 0)
 887    return (mCond_alive && now_state == ShapeBase::Disabled);
 888
 889  return false;
 890}
 891
 892bool afxEffectWrapper::update(F32 dt) 
 893{ 
 894  mElapsed += dt; 
 895
 896  // life_elapsed won't exceed full_lifetime
 897  mLife_elapsed = getMin(mElapsed - mEW_timing.delay, mFull_lifetime);
 898
 899  // update() returns early if elapsed is outside of active timing range 
 900  //     (delay <= elapsed <= delay+lifetime)
 901  // note: execution is always allowed beyond this point at least once, 
 902  //       even if elapsed exceeds the lifetime.
 903  if (mElapsed < mEW_timing.delay)
 904  {
 905    setScopeStatus(false);
 906    return false;
 907  }
 908  
 909  if (!mDatablock->requiresStop(mEW_timing) && mEW_timing.lifetime < 0)
 910  {
 911    F32 afterlife = mElapsed - mEW_timing.delay;
 912    if (afterlife > 1.0f || ((afterlife > 0.0f) && (mNum_updates > 0)))
 913    {
 914      setScopeStatus(mEW_timing.residue_lifetime > 0.0f);
 915      return false;
 916    }
 917  }
 918  else
 919  {
 920    F32 afterlife = mElapsed - (mFull_lifetime + mEW_timing.delay);
 921    if (afterlife > 1.0f || ((afterlife > 0.0f) && (mNum_updates > 0)))
 922    {
 923      setScopeStatus(mEW_timing.residue_lifetime > 0.0f);
 924      return false;
 925    }
 926  }
 927
 928  // first time here, test if required conditions for effect are met
 929  if (mNum_updates == 0)
 930  {
 931    if (!test_life_conds())
 932    {
 933      mElapsed = mFull_lifetime + mEW_timing.delay;
 934      setScopeStatus(false);
 935     mNum_updates++;
 936      return false;
 937    }
 938  }
 939
 940  setScopeStatus(true);
 941  mNum_updates++;
 942
 943
 944  // calculate current fade value if enabled
 945  if (mDo_fade_inout)
 946  {
 947    if (mEW_timing.fade_in_time > 0 && mElapsed <= mFade_in_end)
 948    {
 949      F32 t = mClampF((mElapsed - mEW_timing.delay)/ mEW_timing.fade_in_time, 0.0f, 1.0f);
 950      mFade_value = afxEase::t(t, mEW_timing.fadein_ease.x, mEW_timing.fadein_ease.y);
 951      mDo_fades = true;
 952    }
 953    else if (mElapsed > mFade_out_start)
 954    {
 955      if (mEW_timing.fade_out_time == 0)
 956        mFade_value = 0.0f;
 957      else
 958      {
 959        F32 t = mClampF(1.0f-(mElapsed - mFade_out_start)/ mEW_timing.fade_out_time, 0.0f, 1.0f);
 960        mFade_value = afxEase::t(t, mEW_timing.fadeout_ease.x, mEW_timing.fadeout_ease.y);
 961      }
 962     mDo_fades = true;
 963    }
 964    else
 965    {
 966      mFade_value = 1.0f;
 967     mDo_fades = false;
 968    }
 969  }
 970  else
 971  {
 972    mFade_value = 1.0;
 973   mDo_fades = false;
 974  }
 975
 976  if (mDatablock->vis_keys && mDatablock->vis_keys->numKeys() > 0)
 977  {
 978    F32 vis = mDatablock->vis_keys->evaluate(mElapsed - mEW_timing.delay);
 979    mFade_value *= mClampF(vis, 0.0f, 1.0f);
 980   mDo_fades = (mFade_value < 1.0f);
 981  }
 982
 983  // DEAL WITH CONSTRAINTS
 984  afxXM_Params params;
 985  Point3F& CONS_POS = params.pos;
 986  MatrixF& CONS_XFM = params.ori;
 987  Point3F& CONS_AIM = params.pos2;
 988  Point3F& CONS_SCALE = params.scale;
 989  LinearColorF& CONS_COLOR = params.color;
 990
 991  afxConstraint* pos_constraint = getPosConstraint();
 992  if (pos_constraint)
 993  {
 994    bool valid = pos_constraint->getPosition(CONS_POS, mDatablock->pos_cons_def.mHistory_time);
 995    if (!valid)
 996      getUnconstrainedPosition(CONS_POS);
 997    setScopeStatus(valid);
 998    if (valid && mDatablock->borrow_altitudes)
 999    {
1000      F32 terr_alt, inter_alt;
1001      if (pos_constraint->getAltitudes(terr_alt, inter_alt))
1002      {
1003        mTerrain_altitude = terr_alt;
1004        mInterior_altitude = inter_alt;
1005      }
1006    }
1007  }
1008  else
1009  {
1010    getUnconstrainedPosition(CONS_POS);
1011    setScopeStatus(false);
1012  }
1013
1014  afxConstraint* orient_constraint = getOrientConstraint();
1015  if (orient_constraint) 
1016  {
1017    orient_constraint->getTransform(CONS_XFM, mDatablock->pos_cons_def.mHistory_time);
1018  }
1019  else
1020  {
1021    getUnconstrainedTransform(CONS_XFM);
1022  }
1023
1024  afxConstraint* aim_constraint = getAimConstraint();
1025  if (aim_constraint)
1026    aim_constraint->getPosition(CONS_AIM, mDatablock->pos_cons_def.mHistory_time);
1027  else
1028    CONS_AIM.zero();
1029
1030  CONS_SCALE.set(mDatablock->scale_factor, mDatablock->scale_factor, mDatablock->scale_factor);
1031
1032  /*
1033  if (datablock->isPositional() && CONS_POS.isZero() && in_scope)
1034    Con::errorf("#EFFECT AT ORIGIN [%s] time=%g", datablock->getName(), dt);
1035  */
1036
1037  getBaseColor(CONS_COLOR);
1038
1039  params.vis = mFade_value;
1040
1041  // apply modifiers
1042  for (int i = 0; i < MAX_XFM_MODIFIERS; i++)
1043  {
1044    if (!mXfm_modifiers[i])
1045      break;
1046    else
1047      mXfm_modifiers[i]->updateParams(dt, mLife_elapsed, params);
1048  }
1049
1050  // final pos/orient is determined
1051  mUpdated_xfm = CONS_XFM;  
1052  mUpdated_pos = CONS_POS;
1053  mUpdated_aim = CONS_AIM;
1054  mUpdated_xfm.setPosition(mUpdated_pos);
1055  mUpdated_scale = CONS_SCALE;
1056  mUpdated_color = CONS_COLOR;
1057
1058  if (params.vis > 1.0f)
1059    mFade_value = 1.0f;
1060  else
1061    mFade_value = params.vis;
1062
1063  if (mLast_fade_value != mFade_value)
1064  {
1065    mDo_fades = true;
1066   mLast_fade_value = mFade_value;
1067  }
1068  else
1069  {
1070    mDo_fades = (mFade_value < 1.0f);
1071  }
1072
1073  if (!ea_update(dt))
1074  {
1075    mIs_aborted = true;
1076    Con::errorf("afxEffectWrapper::update() -- effect %s ended unexpectedly.", mDatablock->getName());
1077  }
1078
1079  return true;
1080}
1081
1082void afxEffectWrapper::stop() 
1083{ 
1084  if (!mDatablock->requiresStop(mEW_timing))
1085    return;
1086
1087  mStopped = true; 
1088
1089  // this resets full_lifetime so it starts to shrink or fade
1090  if (mFull_lifetime == INFINITE_LIFETIME)
1091  {
1092    mFull_lifetime = (mElapsed - mEW_timing.delay) + afterStopTime();
1093   mLife_end = mElapsed;
1094    if (mEW_timing.fade_out_time > 0)
1095      mFade_out_start = mElapsed;
1096  }
1097}
1098
1099void afxEffectWrapper::cleanup(bool was_stopped)
1100{ 
1101  ea_finish(was_stopped);
1102  if (!mEffect_cons_id.undefined())
1103  {
1104    mCons_mgr->setReferenceEffect(mEffect_cons_id, 0);
1105   mEffect_cons_id = afxConstraintID();
1106  }
1107}
1108
1109void afxEffectWrapper::setScopeStatus(bool in_scope)
1110{ 
1111  if (mIn_scope != in_scope)
1112  {
1113    mIn_scope = in_scope;
1114    ea_set_scope_status(in_scope);
1115  }
1116}
1117
1118bool afxEffectWrapper::isDone() 
1119{ 
1120  if (!mDatablock->is_looping)
1121    return (mElapsed >= (mLife_end + mEW_timing.fade_out_time));
1122
1123  return false;
1124}
1125
1126
1127//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1128
1129// static 
1130afxEffectWrapper* afxEffectWrapper::ew_create(afxChoreographer*      choreographer, 
1131                                              afxEffectWrapperData*  datablock, 
1132                                              afxConstraintMgr*      cons_mgr,
1133                                              F32                    time_factor,
1134                                              S32                    group_index)
1135{
1136  afxEffectWrapper* adapter = datablock->effect_desc->create();
1137
1138  if (adapter)
1139  {
1140    adapter->mGroup_index = (datablock->group_index != -1) ? datablock->group_index : group_index;
1141    adapter->ew_init(choreographer, datablock, cons_mgr, time_factor); 
1142  }
1143
1144  return adapter;
1145}
1146
1147//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1148
1149Vector<afxEffectAdapterDesc*>* afxEffectAdapterDesc::adapters = 0;
1150
1151afxEffectAdapterDesc::afxEffectAdapterDesc() 
1152{ 
1153  if (!adapters)
1154    adapters = new Vector<afxEffectAdapterDesc*>;
1155
1156  adapters->push_back(this);
1157}
1158
1159bool afxEffectAdapterDesc::identifyEffect(afxEffectWrapperData* ew)
1160{
1161  if (!ew || !ew->effect_data)
1162  {
1163    Con::errorf("afxEffectAdapterDesc::identifyEffect() -- effect datablock was not specified.");
1164    return false;
1165  }
1166
1167  if (!adapters)
1168  {
1169    Con::errorf("afxEffectAdapterDesc::identifyEffect() -- adapter registration list has not been allocated.");
1170    return false;
1171  }
1172
1173  if (adapters->size() == 0)
1174  {
1175    Con::errorf("afxEffectAdapterDesc::identifyEffect() -- no effect adapters have been registered.");
1176    return false;
1177  }
1178
1179  for (S32 i = 0; i < adapters->size(); i++)
1180  {
1181    if ((*adapters)[i]->testEffectType(ew->effect_data))
1182    {
1183      ew->effect_desc = (*adapters)[i];
1184      (*adapters)[i]->prepEffect(ew);
1185      return true;
1186    }
1187  }
1188
1189  Con::errorf("afxEffectAdapterDesc::identifyEffect() -- effect %s has an undefined type. -- %d", 
1190    ew->effect_data->getName(), adapters->size());
1191  return false;
1192}
1193
1194//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1195