2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
|
|
|
// 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 "math/mathIO.h"
|
|
|
|
|
|
|
|
|
|
#include "afx/ce/afxComponentEffect.h"
|
|
|
|
|
#include "afx/afxResidueMgr.h"
|
|
|
|
|
#include "afx/afxChoreographer.h"
|
|
|
|
|
#include "afx/afxConstraint.h"
|
|
|
|
|
#include "afx/xm/afxXfmMod.h"
|
|
|
|
|
#include "afx/afxEffectWrapper.h"
|
|
|
|
|
#include "afx/util/afxAnimCurve.h"
|
|
|
|
|
#include "afx/util/afxEase.h"
|
|
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
|
|
|
// afxEffectWrapperData
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_CO_DATABLOCK_V1(afxEffectBaseData);
|
|
|
|
|
|
|
|
|
|
ConsoleDocClass( afxEffectBaseData,
|
|
|
|
|
"@brief A datablock baseclass for afxEffectWrapperData and afxEffectGroupData.\n\n"
|
|
|
|
|
|
|
|
|
|
"Not intended to be used directly, afxEffectBaseData exists to provide base member "
|
|
|
|
|
"variables and generic functionality for the derived classes afxEffectWrapperData and "
|
|
|
|
|
"afxEffectGroupData.\n\n"
|
|
|
|
|
|
|
|
|
|
"@see afxEffectWrapperData\n\n"
|
|
|
|
|
"@see afxEffectGroupData\n\n"
|
|
|
|
|
|
|
|
|
|
"@ingroup afxEffects\n"
|
|
|
|
|
"@ingroup AFX\n"
|
|
|
|
|
"@ingroup Datablocks\n"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_CO_DATABLOCK_V1(afxEffectWrapperData);
|
|
|
|
|
|
|
|
|
|
ConsoleDocClass( afxEffectWrapperData,
|
|
|
|
|
"@brief A datablock that describes an Effect Wrapper.\n\n"
|
|
|
|
|
|
|
|
|
|
"Conceptually an effect wrapper encloses a building-block effect and acts "
|
|
|
|
|
"as a handle for adding the effect to a choreographer. Effect wrapper fields "
|
|
|
|
|
"primarily deal with effect timing, constraints, and conditional effect execution.\n\n"
|
|
|
|
|
|
|
|
|
|
"@see afxEffectBaseData\n\n"
|
|
|
|
|
"@see afxEffectGroupData\n\n"
|
|
|
|
|
|
|
|
|
|
"@ingroup afxEffects\n"
|
|
|
|
|
"@ingroup AFX\n"
|
|
|
|
|
"@ingroup Datablocks\n"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
afxEffectWrapperData::afxEffectWrapperData()
|
|
|
|
|
{
|
|
|
|
|
effect_name = ST_NULLSTRING;
|
|
|
|
|
effect_data = 0;
|
|
|
|
|
effect_desc = 0;
|
|
|
|
|
data_ID = 0;
|
|
|
|
|
use_as_cons_obj = false;
|
|
|
|
|
use_ghost_as_cons_obj = false;
|
|
|
|
|
|
|
|
|
|
// constraint data
|
|
|
|
|
cons_spec = ST_NULLSTRING;
|
|
|
|
|
pos_cons_spec = ST_NULLSTRING;
|
|
|
|
|
orient_cons_spec = ST_NULLSTRING;
|
|
|
|
|
aim_cons_spec = StringTable->insert("camera");
|
|
|
|
|
life_cons_spec = ST_NULLSTRING;
|
|
|
|
|
|
|
|
|
|
// conditional execution flags
|
|
|
|
|
effect_enabled = true;
|
|
|
|
|
ranking_range.set(0,255);
|
|
|
|
|
lod_range.set(0,255);
|
|
|
|
|
life_conds = 0;
|
|
|
|
|
for (S32 i = 0; i < MAX_CONDITION_STATES; i++)
|
|
|
|
|
{
|
|
|
|
|
exec_cond_on_bits[i] = 0;
|
|
|
|
|
exec_cond_off_bits[i] = 0;
|
|
|
|
|
exec_cond_bitmasks[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ewd_timing.lifetime = -1;
|
|
|
|
|
|
|
|
|
|
user_fade_out_time = 0.0;
|
|
|
|
|
|
|
|
|
|
is_looping = false;
|
|
|
|
|
n_loops = 0;
|
|
|
|
|
loop_gap_time = 0.0f;
|
|
|
|
|
|
|
|
|
|
ignore_time_factor = false;
|
|
|
|
|
propagate_time_factor = false;
|
|
|
|
|
|
|
|
|
|
// residue settings
|
|
|
|
|
|
|
|
|
|
// scaling factors
|
|
|
|
|
rate_factor = 1.0f;
|
|
|
|
|
scale_factor = 1.0f;
|
|
|
|
|
|
|
|
|
|
dMemset(xfm_modifiers, 0, sizeof(xfm_modifiers));
|
|
|
|
|
|
|
|
|
|
forced_bbox.minExtents.set(1,1,1);
|
|
|
|
|
forced_bbox.maxExtents.set(-1,-1,-1);
|
|
|
|
|
|
|
|
|
|
update_forced_bbox = false;
|
|
|
|
|
|
|
|
|
|
// marked true if datablock ids need to
|
|
|
|
|
// be converted into pointers
|
|
|
|
|
do_id_convert = false;
|
|
|
|
|
|
|
|
|
|
sort_priority = 0;
|
|
|
|
|
direction.set(0,1,0);
|
|
|
|
|
speed = 0.0f;
|
|
|
|
|
mass = 1.0f;
|
|
|
|
|
|
|
|
|
|
borrow_altitudes = false;
|
|
|
|
|
vis_keys_spec = ST_NULLSTRING;
|
|
|
|
|
vis_keys = 0;
|
|
|
|
|
|
|
|
|
|
group_index = -1;
|
|
|
|
|
inherit_timing = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
afxEffectWrapperData::afxEffectWrapperData(const afxEffectWrapperData& other, bool temp_clone) : afxEffectBaseData(other, temp_clone)
|
|
|
|
|
{
|
|
|
|
|
effect_name = other.effect_name;
|
|
|
|
|
effect_data = other.effect_data;
|
|
|
|
|
effect_desc = other.effect_desc;
|
|
|
|
|
data_ID = other.data_ID;
|
|
|
|
|
use_as_cons_obj = other.use_as_cons_obj;
|
|
|
|
|
use_ghost_as_cons_obj = other.use_ghost_as_cons_obj;
|
|
|
|
|
cons_spec = other.cons_spec;
|
|
|
|
|
pos_cons_spec = other.pos_cons_spec;
|
|
|
|
|
orient_cons_spec = other.orient_cons_spec;
|
|
|
|
|
aim_cons_spec = other.aim_cons_spec;
|
|
|
|
|
life_cons_spec = other.life_cons_spec;
|
|
|
|
|
cons_def = other.cons_def;
|
|
|
|
|
pos_cons_def = other.pos_cons_def;
|
|
|
|
|
orient_cons_def = other.orient_cons_def;
|
|
|
|
|
aim_cons_def = other.aim_cons_def;
|
|
|
|
|
life_cons_def = other.life_cons_def;
|
|
|
|
|
effect_enabled = other.effect_enabled;
|
|
|
|
|
ranking_range = other.ranking_range;
|
|
|
|
|
lod_range = other.lod_range;
|
|
|
|
|
life_conds = other.life_conds;
|
|
|
|
|
dMemcpy(exec_cond_on_bits, other.exec_cond_on_bits, sizeof(exec_cond_on_bits));
|
|
|
|
|
dMemcpy(exec_cond_off_bits, other.exec_cond_off_bits, sizeof(exec_cond_off_bits));
|
|
|
|
|
dMemcpy(exec_cond_bitmasks, other.exec_cond_bitmasks, sizeof(exec_cond_bitmasks));
|
|
|
|
|
ewd_timing = other.ewd_timing;
|
|
|
|
|
user_fade_out_time = other.user_fade_out_time;
|
|
|
|
|
is_looping = other.is_looping;
|
|
|
|
|
n_loops = other.n_loops;
|
|
|
|
|
loop_gap_time = other.loop_gap_time;
|
|
|
|
|
ignore_time_factor = other.ignore_time_factor;
|
|
|
|
|
propagate_time_factor = other.propagate_time_factor;
|
|
|
|
|
rate_factor = other.rate_factor;
|
|
|
|
|
scale_factor = other.scale_factor;
|
|
|
|
|
dMemcpy(xfm_modifiers, other.xfm_modifiers, sizeof(xfm_modifiers));
|
|
|
|
|
forced_bbox = other.forced_bbox;
|
|
|
|
|
update_forced_bbox = other.update_forced_bbox;
|
|
|
|
|
do_id_convert = other.do_id_convert;
|
|
|
|
|
sort_priority = other.sort_priority;
|
|
|
|
|
direction = other.direction;
|
|
|
|
|
speed = other.speed;
|
|
|
|
|
mass = other.mass;
|
|
|
|
|
borrow_altitudes = other.borrow_altitudes;
|
|
|
|
|
vis_keys_spec = other.vis_keys_spec;
|
|
|
|
|
vis_keys = other.vis_keys;
|
|
|
|
|
if (other.vis_keys)
|
|
|
|
|
{
|
|
|
|
|
vis_keys = new afxAnimCurve();
|
|
|
|
|
for (S32 i = 0; i < other.vis_keys->numKeys(); i++)
|
|
|
|
|
{
|
|
|
|
|
F32 when = other.vis_keys->getKeyTime(i);
|
|
|
|
|
F32 what = other.vis_keys->getKeyValue(i);
|
|
|
|
|
vis_keys->addKey(when, what);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
vis_keys = 0;
|
|
|
|
|
group_index = other.group_index;
|
|
|
|
|
inherit_timing = other.inherit_timing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
afxEffectWrapperData::~afxEffectWrapperData()
|
|
|
|
|
{
|
|
|
|
|
if (vis_keys)
|
|
|
|
|
delete vis_keys;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define myOffset(field) Offset(field, afxEffectWrapperData)
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::initPersistFields()
|
|
|
|
|
{
|
2023-01-27 07:13:15 +00:00
|
|
|
docsURL;
|
2017-07-26 08:35:44 +00:00
|
|
|
// the wrapped effect
|
|
|
|
|
addField("effect", TYPEID<SimDataBlock>(), myOffset(effect_data),
|
|
|
|
|
"...");
|
|
|
|
|
addField("effectName", TypeString, myOffset(effect_name),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
// constraints
|
|
|
|
|
addField("constraint", TypeString, myOffset(cons_spec),
|
|
|
|
|
"...");
|
|
|
|
|
addField("posConstraint", TypeString, myOffset(pos_cons_spec),
|
|
|
|
|
"...");
|
|
|
|
|
addField("posConstraint2", TypeString, myOffset(aim_cons_spec),
|
|
|
|
|
"...");
|
|
|
|
|
addField("orientConstraint", TypeString, myOffset(orient_cons_spec),
|
|
|
|
|
"...");
|
|
|
|
|
addField("lifeConstraint", TypeString, myOffset(life_cons_spec),
|
|
|
|
|
"...");
|
|
|
|
|
//
|
|
|
|
|
addField("isConstraintSrc", TypeBool, myOffset(use_as_cons_obj),
|
|
|
|
|
"...");
|
|
|
|
|
addField("ghostIsConstraintSrc", TypeBool, myOffset(use_ghost_as_cons_obj),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("delay", TypeF32, myOffset(ewd_timing.delay),
|
|
|
|
|
"...");
|
|
|
|
|
addField("lifetime", TypeF32, myOffset(ewd_timing.lifetime),
|
|
|
|
|
"...");
|
|
|
|
|
addField("fadeInTime", TypeF32, myOffset(ewd_timing.fade_in_time),
|
|
|
|
|
"...");
|
|
|
|
|
addField("residueLifetime", TypeF32, myOffset(ewd_timing.residue_lifetime),
|
|
|
|
|
"...");
|
|
|
|
|
addField("fadeInEase", TypePoint2F, myOffset(ewd_timing.fadein_ease),
|
|
|
|
|
"...");
|
|
|
|
|
addField("fadeOutEase", TypePoint2F, myOffset(ewd_timing.fadeout_ease),
|
|
|
|
|
"...");
|
|
|
|
|
addField("lifetimeBias", TypeF32, myOffset(ewd_timing.life_bias),
|
|
|
|
|
"...");
|
|
|
|
|
addField("fadeOutTime", TypeF32, myOffset(user_fade_out_time),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("rateFactor", TypeF32, myOffset(rate_factor),
|
|
|
|
|
"...");
|
|
|
|
|
addField("scaleFactor", TypeF32, myOffset(scale_factor),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("isLooping", TypeBool, myOffset(is_looping),
|
|
|
|
|
"...");
|
|
|
|
|
addField("loopCount", TypeS32, myOffset(n_loops),
|
|
|
|
|
"...");
|
|
|
|
|
addField("loopGapTime", TypeF32, myOffset(loop_gap_time),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("ignoreTimeFactor", TypeBool, myOffset(ignore_time_factor),
|
|
|
|
|
"...");
|
|
|
|
|
addField("propagateTimeFactor", TypeBool, myOffset(propagate_time_factor),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("effectEnabled", TypeBool, myOffset(effect_enabled),
|
|
|
|
|
"...");
|
|
|
|
|
addField("rankingRange", TypeByteRange, myOffset(ranking_range),
|
|
|
|
|
"...");
|
|
|
|
|
addField("levelOfDetailRange", TypeByteRange, myOffset(lod_range),
|
|
|
|
|
"...");
|
|
|
|
|
addField("lifeConditions", TypeS32, myOffset(life_conds),
|
|
|
|
|
"...");
|
|
|
|
|
addField("execConditions", TypeS32, myOffset(exec_cond_on_bits), MAX_CONDITION_STATES,
|
|
|
|
|
"...");
|
|
|
|
|
addField("execOffConditions", TypeS32, myOffset(exec_cond_off_bits), MAX_CONDITION_STATES,
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("xfmModifiers", TYPEID<afxXM_BaseData>(), myOffset(xfm_modifiers), MAX_XFM_MODIFIERS,
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("forcedBBox", TypeBox3F, myOffset(forced_bbox),
|
|
|
|
|
"...");
|
|
|
|
|
addField("updateForcedBBox", TypeBool, myOffset(update_forced_bbox),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("sortPriority", TypeS8, myOffset(sort_priority),
|
|
|
|
|
"...");
|
|
|
|
|
addField("direction", TypePoint3F, myOffset(direction),
|
|
|
|
|
"...");
|
|
|
|
|
addField("speed", TypeF32, myOffset(speed),
|
|
|
|
|
"...");
|
|
|
|
|
addField("mass", TypeF32, myOffset(mass),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("borrowAltitudes", TypeBool, myOffset(borrow_altitudes),
|
|
|
|
|
"...");
|
|
|
|
|
addField("visibilityKeys", TypeString, myOffset(vis_keys_spec),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
addField("groupIndex", TypeS32, myOffset(group_index),
|
|
|
|
|
"...");
|
|
|
|
|
addField("inheritGroupTiming", TypeS32, myOffset(inherit_timing),
|
|
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
Parent::initPersistFields();
|
|
|
|
|
|
|
|
|
|
// disallow some field substitutions
|
|
|
|
|
disableFieldSubstitutions("effect");
|
|
|
|
|
onlyKeepClearSubstitutions("xfmModifiers"); // subs resolving to "~~", or "~0" are OK
|
|
|
|
|
|
|
|
|
|
// Conditional Execution Flags
|
|
|
|
|
Con::setIntVariable("$afx::DISABLED", DISABLED);
|
|
|
|
|
Con::setIntVariable("$afx::ENABLED", ENABLED);
|
|
|
|
|
Con::setIntVariable("$afx::FAILING", FAILING);
|
|
|
|
|
Con::setIntVariable("$afx::DEAD", DEAD);
|
|
|
|
|
Con::setIntVariable("$afx::ALIVE", ALIVE);
|
|
|
|
|
Con::setIntVariable("$afx::DYING", DYING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool afxEffectWrapperData::onAdd()
|
|
|
|
|
{
|
|
|
|
|
if (Parent::onAdd() == false)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!effect_data)
|
|
|
|
|
{
|
|
|
|
|
if (!Sim::findObject((SimObjectId)data_ID, effect_data))
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("afxEffectWrapperData::onAdd() -- bad datablockId: 0x%x", data_ID);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (effect_data)
|
|
|
|
|
{
|
|
|
|
|
if (!afxEffectAdapterDesc::identifyEffect(this))
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("afxEffectWrapperData::onAdd() -- unknown effect type.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parse_cons_specs();
|
|
|
|
|
parse_vis_keys();
|
|
|
|
|
|
|
|
|
|
// figure out if fade-out is for effect of residue
|
|
|
|
|
if (ewd_timing.residue_lifetime > 0)
|
|
|
|
|
{
|
|
|
|
|
ewd_timing.residue_fadetime = user_fade_out_time;
|
|
|
|
|
ewd_timing.fade_out_time = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ewd_timing.residue_fadetime = 0.0f;
|
|
|
|
|
ewd_timing.fade_out_time = user_fade_out_time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// adjust fade-in time
|
|
|
|
|
if (ewd_timing.lifetime >= 0)
|
|
|
|
|
{
|
|
|
|
|
ewd_timing.fade_in_time = getMin(ewd_timing.lifetime, ewd_timing.fade_in_time);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// adjust exec-conditions
|
|
|
|
|
for (S32 i = 0; i < MAX_CONDITION_STATES; i++)
|
|
|
|
|
exec_cond_bitmasks[i] = exec_cond_on_bits[i] | exec_cond_off_bits[i];
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::packData(BitStream* stream)
|
|
|
|
|
{
|
|
|
|
|
Parent::packData(stream);
|
|
|
|
|
|
2018-03-29 04:41:47 +00:00
|
|
|
writeDatablockID(stream, effect_data, mPacked);
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
stream->writeString(effect_name);
|
|
|
|
|
|
|
|
|
|
stream->writeString(cons_spec);
|
|
|
|
|
stream->writeString(pos_cons_spec);
|
|
|
|
|
stream->writeString(orient_cons_spec);
|
|
|
|
|
stream->writeString(aim_cons_spec);
|
|
|
|
|
stream->writeString(life_cons_spec);
|
|
|
|
|
//
|
|
|
|
|
stream->write(use_as_cons_obj);
|
|
|
|
|
//stream->write(use_ghost_as_cons_obj);
|
|
|
|
|
|
|
|
|
|
stream->writeFlag(effect_enabled);
|
|
|
|
|
stream->write(ranking_range.low);
|
|
|
|
|
stream->write(ranking_range.high);
|
|
|
|
|
stream->write(lod_range.low);
|
|
|
|
|
stream->write(lod_range.high);
|
|
|
|
|
|
|
|
|
|
for (S32 i = 0; i < MAX_CONDITION_STATES; i++)
|
|
|
|
|
{
|
|
|
|
|
stream->write(exec_cond_on_bits[i]);
|
|
|
|
|
stream->write(exec_cond_off_bits[i]);
|
|
|
|
|
}
|
|
|
|
|
stream->write(life_conds);
|
|
|
|
|
stream->write(ewd_timing.delay);
|
|
|
|
|
stream->write(ewd_timing.lifetime);
|
|
|
|
|
stream->write(ewd_timing.fade_in_time);
|
|
|
|
|
stream->write(user_fade_out_time);
|
|
|
|
|
stream->write(is_looping);
|
|
|
|
|
stream->write(n_loops);
|
|
|
|
|
stream->write(loop_gap_time);
|
|
|
|
|
stream->write(ignore_time_factor);
|
|
|
|
|
stream->write(propagate_time_factor);
|
|
|
|
|
stream->write(ewd_timing.residue_lifetime);
|
|
|
|
|
stream->write(rate_factor);
|
|
|
|
|
stream->write(scale_factor);
|
|
|
|
|
|
|
|
|
|
// modifiers
|
2018-03-29 04:41:47 +00:00
|
|
|
pack_mods(stream, xfm_modifiers, mPacked);
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
mathWrite(*stream, forced_bbox);
|
|
|
|
|
stream->write(update_forced_bbox);
|
|
|
|
|
|
|
|
|
|
stream->write(sort_priority);
|
|
|
|
|
mathWrite(*stream, direction);
|
|
|
|
|
stream->write(speed);
|
|
|
|
|
stream->write(mass);
|
|
|
|
|
|
|
|
|
|
stream->write(borrow_altitudes);
|
|
|
|
|
if (stream->writeFlag(vis_keys_spec != ST_NULLSTRING))
|
|
|
|
|
stream->writeLongString(1023, vis_keys_spec);
|
|
|
|
|
|
|
|
|
|
if (stream->writeFlag(group_index != -1))
|
|
|
|
|
stream->write(group_index);
|
|
|
|
|
|
|
|
|
|
stream->writeInt(inherit_timing, TIMING_BITS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::unpackData(BitStream* stream)
|
|
|
|
|
{
|
|
|
|
|
Parent::unpackData(stream);
|
|
|
|
|
|
|
|
|
|
data_ID = readDatablockID(stream);
|
|
|
|
|
|
|
|
|
|
effect_name = stream->readSTString();
|
|
|
|
|
|
|
|
|
|
cons_spec = stream->readSTString();
|
|
|
|
|
pos_cons_spec = stream->readSTString();
|
|
|
|
|
orient_cons_spec = stream->readSTString();
|
|
|
|
|
aim_cons_spec = stream->readSTString();
|
|
|
|
|
life_cons_spec = stream->readSTString();
|
|
|
|
|
//
|
|
|
|
|
stream->read(&use_as_cons_obj);
|
|
|
|
|
//stream->read(&use_ghost_as_cons_obj);
|
|
|
|
|
|
|
|
|
|
effect_enabled = stream->readFlag();
|
|
|
|
|
stream->read(&ranking_range.low);
|
|
|
|
|
stream->read(&ranking_range.high);
|
|
|
|
|
stream->read(&lod_range.low);
|
|
|
|
|
stream->read(&lod_range.high);
|
|
|
|
|
|
|
|
|
|
for (S32 i = 0; i < MAX_CONDITION_STATES; i++)
|
|
|
|
|
{
|
|
|
|
|
stream->read(&exec_cond_on_bits[i]);
|
|
|
|
|
stream->read(&exec_cond_off_bits[i]);
|
|
|
|
|
}
|
|
|
|
|
stream->read(&life_conds);
|
|
|
|
|
stream->read(&ewd_timing.delay);
|
|
|
|
|
stream->read(&ewd_timing.lifetime);
|
|
|
|
|
stream->read(&ewd_timing.fade_in_time);
|
|
|
|
|
stream->read(&user_fade_out_time);
|
|
|
|
|
stream->read(&is_looping);
|
|
|
|
|
stream->read(&n_loops);
|
|
|
|
|
stream->read(&loop_gap_time);
|
|
|
|
|
stream->read(&ignore_time_factor);
|
|
|
|
|
stream->read(&propagate_time_factor);
|
|
|
|
|
stream->read(&ewd_timing.residue_lifetime);
|
|
|
|
|
stream->read(&rate_factor);
|
|
|
|
|
stream->read(&scale_factor);
|
|
|
|
|
|
|
|
|
|
// modifiers
|
|
|
|
|
do_id_convert = true;
|
|
|
|
|
unpack_mods(stream, xfm_modifiers);
|
|
|
|
|
|
|
|
|
|
mathRead(*stream, &forced_bbox);
|
|
|
|
|
stream->read(&update_forced_bbox);
|
|
|
|
|
|
|
|
|
|
stream->read(&sort_priority);
|
|
|
|
|
mathRead(*stream, &direction);
|
|
|
|
|
stream->read(&speed);
|
|
|
|
|
stream->read(&mass);
|
|
|
|
|
|
|
|
|
|
stream->read(&borrow_altitudes);
|
|
|
|
|
if (stream->readFlag())
|
|
|
|
|
{
|
|
|
|
|
char buf[1024];
|
|
|
|
|
stream->readLongString(1023, buf);
|
|
|
|
|
vis_keys_spec = StringTable->insert(buf);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
vis_keys_spec = ST_NULLSTRING;
|
|
|
|
|
|
|
|
|
|
if (stream->readFlag())
|
|
|
|
|
stream->read(&group_index);
|
|
|
|
|
else
|
|
|
|
|
group_index = -1;
|
|
|
|
|
|
|
|
|
|
inherit_timing = stream->readInt(TIMING_BITS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* static*/
|
|
|
|
|
S32 num_modifiers(afxXM_BaseData* mods[])
|
|
|
|
|
{
|
|
|
|
|
S32 n_mods = 0;
|
|
|
|
|
for (int i = 0; i < afxEffectDefs::MAX_XFM_MODIFIERS; i++)
|
|
|
|
|
{
|
|
|
|
|
if (mods[i])
|
|
|
|
|
{
|
|
|
|
|
if (i != n_mods)
|
|
|
|
|
{
|
|
|
|
|
mods[n_mods] = mods[i];
|
|
|
|
|
mods[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
n_mods++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return n_mods;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::parse_cons_specs()
|
|
|
|
|
{
|
|
|
|
|
// parse the constraint specifications
|
|
|
|
|
bool runs_on_s = runsOnServer();
|
|
|
|
|
bool runs_on_c = runsOnClient();
|
|
|
|
|
cons_def.parseSpec(cons_spec, runs_on_s, runs_on_c);
|
|
|
|
|
pos_cons_def.parseSpec(pos_cons_spec, runs_on_s, runs_on_c);
|
|
|
|
|
orient_cons_def.parseSpec(orient_cons_spec, runs_on_s, runs_on_c);
|
|
|
|
|
aim_cons_def.parseSpec(aim_cons_spec, runs_on_s, runs_on_c);
|
|
|
|
|
life_cons_def.parseSpec(life_cons_spec, runs_on_s, runs_on_c);
|
|
|
|
|
if (cons_def.isDefined())
|
|
|
|
|
{
|
|
|
|
|
pos_cons_def = cons_def;
|
|
|
|
|
if (!orient_cons_def.isDefined())
|
|
|
|
|
orient_cons_def = cons_def;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::parse_vis_keys()
|
|
|
|
|
{
|
|
|
|
|
if (vis_keys_spec != ST_NULLSTRING)
|
|
|
|
|
{
|
|
|
|
|
if (vis_keys)
|
|
|
|
|
delete vis_keys;
|
|
|
|
|
vis_keys = new afxAnimCurve();
|
|
|
|
|
|
|
|
|
|
char* keys_buffer = dStrdup(vis_keys_spec);
|
|
|
|
|
|
|
|
|
|
char* key_token = dStrtok(keys_buffer, " \t");
|
|
|
|
|
while (key_token != NULL)
|
|
|
|
|
{
|
|
|
|
|
char* colon = dStrchr(key_token, ':');
|
|
|
|
|
if (colon)
|
|
|
|
|
{
|
|
|
|
|
*colon = '\0';
|
|
|
|
|
|
|
|
|
|
F32 when = dAtof(key_token);
|
|
|
|
|
F32 what = dAtof(colon+1);
|
|
|
|
|
|
|
|
|
|
vis_keys->addKey(when, what);
|
|
|
|
|
}
|
|
|
|
|
key_token = dStrtok(NULL, " \t");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dFree(keys_buffer);
|
|
|
|
|
vis_keys->sort();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::gather_cons_defs(Vector<afxConstraintDef>& defs)
|
|
|
|
|
{
|
|
|
|
|
if (pos_cons_def.isDefined())
|
|
|
|
|
defs.push_back(pos_cons_def);
|
|
|
|
|
if (orient_cons_def.isDefined())
|
|
|
|
|
defs.push_back(orient_cons_def);
|
|
|
|
|
if (aim_cons_def.isDefined())
|
|
|
|
|
defs.push_back(aim_cons_def);
|
|
|
|
|
if (life_cons_def.isDefined())
|
|
|
|
|
defs.push_back(life_cons_def);
|
|
|
|
|
|
|
|
|
|
afxComponentEffectData* ce_data = dynamic_cast<afxComponentEffectData*>(effect_data);
|
|
|
|
|
if (ce_data)
|
|
|
|
|
ce_data->gather_cons_defs(defs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::pack_mods(BitStream* stream, afxXM_BaseData* mods[], bool packed)
|
|
|
|
|
{
|
|
|
|
|
S32 n_mods = num_modifiers(mods);
|
|
|
|
|
stream->writeInt(n_mods, 6);
|
|
|
|
|
for (int i = 0; i < n_mods; i++)
|
|
|
|
|
writeDatablockID(stream, mods[i], packed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::unpack_mods(BitStream* stream, afxXM_BaseData* mods[])
|
|
|
|
|
{
|
|
|
|
|
S32 n_mods = stream->readInt(6);
|
|
|
|
|
for (int i = 0; i < n_mods; i++)
|
2019-02-03 04:09:55 +00:00
|
|
|
mods[i] = (afxXM_BaseData*)(uintptr_t)readDatablockID(stream);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool afxEffectWrapperData::preload(bool server, String &errorStr)
|
|
|
|
|
{
|
|
|
|
|
if (!Parent::preload(server, errorStr))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Resolve objects transmitted from server
|
|
|
|
|
if (!server)
|
|
|
|
|
{
|
|
|
|
|
if (do_id_convert)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < MAX_XFM_MODIFIERS; i++)
|
|
|
|
|
{
|
|
|
|
|
SimObjectId db_id = SimObjectId((uintptr_t)xfm_modifiers[i]);
|
|
|
|
|
if (db_id != 0)
|
|
|
|
|
{
|
|
|
|
|
// try to convert id to pointer
|
|
|
|
|
if (!Sim::findObject(db_id, xfm_modifiers[i]))
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("afxEffectWrapperData::preload() -- bad datablockId: 0x%x (xfm_modifiers[%d])",
|
|
|
|
|
db_id, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
do_id_convert = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapperData::onPerformSubstitutions()
|
|
|
|
|
{
|
|
|
|
|
Parent::onPerformSubstitutions();
|
|
|
|
|
|
|
|
|
|
parse_cons_specs();
|
|
|
|
|
parse_vis_keys();
|
|
|
|
|
|
|
|
|
|
if (ewd_timing.residue_lifetime > 0)
|
|
|
|
|
{
|
|
|
|
|
ewd_timing.residue_fadetime = user_fade_out_time;
|
|
|
|
|
ewd_timing.fade_out_time = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ewd_timing.residue_fadetime = 0.0f;
|
|
|
|
|
ewd_timing.fade_out_time = user_fade_out_time;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
|
|
|
// afxEffectWrapper
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_CONOBJECT(afxEffectWrapper);
|
|
|
|
|
|
|
|
|
|
ConsoleDocClass( afxEffectWrapper,
|
|
|
|
|
"@brief An Effect Wrapper as defined by an afxEffectWrapperData datablock.\n\n"
|
|
|
|
|
|
|
|
|
|
"Conceptually an effect wrapper encloses a building-block effect and acts "
|
|
|
|
|
"as a handle for adding the effect to a choreographer. Effect wrapper fields "
|
|
|
|
|
"primarily deal with effect timing, constraints, and conditional effect execution.\n\n"
|
|
|
|
|
|
|
|
|
|
"Not intended to be used directly, afxEffectWrapper is an internal baseclass used to "
|
|
|
|
|
"implement effect-specific adapter classes.\n\n"
|
|
|
|
|
|
|
|
|
|
"@ingroup afxEffects\n"
|
|
|
|
|
"@ingroup AFX\n"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
afxEffectWrapper::afxEffectWrapper()
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mChoreographer = 0;
|
|
|
|
|
mDatablock = 0;
|
|
|
|
|
mCons_mgr = 0;
|
|
|
|
|
|
|
|
|
|
mCond_alive = true;
|
|
|
|
|
mElapsed = 0;
|
|
|
|
|
mLife_end = 0;
|
|
|
|
|
mLife_elapsed = 0;
|
|
|
|
|
mStopped = false;
|
|
|
|
|
mNum_updates = 0;
|
|
|
|
|
mFade_value = 1.0f;
|
|
|
|
|
mLast_fade_value = 0.0f;
|
|
|
|
|
mFade_in_end = 0.0;
|
|
|
|
|
mFade_out_start = 0.0f;
|
|
|
|
|
mIn_scope = true;
|
|
|
|
|
mIs_aborted = false;
|
|
|
|
|
mDo_fade_inout = false;
|
|
|
|
|
mDo_fades = false;
|
|
|
|
|
mFull_lifetime = 0;
|
|
|
|
|
|
|
|
|
|
mTime_factor = 1.0f;
|
|
|
|
|
mProp_time_factor = 1.0f;
|
|
|
|
|
|
|
|
|
|
mLive_scale_factor = 1.0f;
|
|
|
|
|
mLive_fade_factor = 1.0f;
|
|
|
|
|
mTerrain_altitude = -1.0f;
|
|
|
|
|
mInterior_altitude = -1.0f;
|
|
|
|
|
|
|
|
|
|
mGroup_index = 0;
|
|
|
|
|
|
|
|
|
|
dMemset(mXfm_modifiers, 0, sizeof(mXfm_modifiers));
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
afxEffectWrapper::~afxEffectWrapper()
|
|
|
|
|
{
|
|
|
|
|
for (S32 i = 0; i < MAX_XFM_MODIFIERS; i++)
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mXfm_modifiers[i])
|
|
|
|
|
delete mXfm_modifiers[i];
|
2017-07-26 08:35:44 +00:00
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mDatablock && mDatablock->effect_name != ST_NULLSTRING)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mChoreographer->removeNamedEffect(this);
|
|
|
|
|
if (mDatablock->use_as_cons_obj && !mEffect_cons_id.undefined())
|
|
|
|
|
mCons_mgr->setReferenceEffect(mEffect_cons_id, 0);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mDatablock && mDatablock->isTempClone())
|
|
|
|
|
delete mDatablock;
|
|
|
|
|
mDatablock = 0;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef myOffset
|
|
|
|
|
#define myOffset(field) Offset(field, afxEffectWrapper)
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapper::initPersistFields()
|
|
|
|
|
{
|
2023-01-27 07:13:15 +00:00
|
|
|
docsURL;
|
2018-03-29 22:46:57 +00:00
|
|
|
addField("liveScaleFactor", TypeF32, myOffset(mLive_scale_factor),
|
2017-07-26 08:35:44 +00:00
|
|
|
"...");
|
2018-03-29 22:46:57 +00:00
|
|
|
addField("liveFadeFactor", TypeF32, myOffset(mLive_fade_factor),
|
2017-07-26 08:35:44 +00:00
|
|
|
"...");
|
|
|
|
|
|
|
|
|
|
Parent::initPersistFields();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapper::ew_init(afxChoreographer* choreographer,
|
|
|
|
|
afxEffectWrapperData* datablock,
|
|
|
|
|
afxConstraintMgr* cons_mgr,
|
|
|
|
|
F32 time_factor)
|
|
|
|
|
{
|
|
|
|
|
AssertFatal(choreographer != NULL, "Choreographer is missing.");
|
|
|
|
|
AssertFatal(datablock != NULL, "Datablock is missing.");
|
|
|
|
|
AssertFatal(cons_mgr != NULL, "Constraint manager is missing.");
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
mChoreographer = choreographer;
|
|
|
|
|
mDatablock = datablock;
|
|
|
|
|
mCons_mgr = cons_mgr;
|
2017-07-26 08:35:44 +00:00
|
|
|
ea_set_datablock(datablock->effect_data);
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
mEW_timing = datablock->ewd_timing;
|
|
|
|
|
if (mEW_timing.life_bias != 1.0f)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mEW_timing.lifetime > 0)
|
|
|
|
|
mEW_timing.lifetime *= mEW_timing.life_bias;
|
|
|
|
|
mEW_timing.fade_in_time *= mEW_timing.life_bias;
|
|
|
|
|
mEW_timing.fade_out_time *= mEW_timing.life_bias;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
mPos_cons_id = cons_mgr->getConstraintId(datablock->pos_cons_def);
|
|
|
|
|
mOrient_cons_id = cons_mgr->getConstraintId(datablock->orient_cons_def);
|
|
|
|
|
mAim_cons_id = cons_mgr->getConstraintId(datablock->aim_cons_def);
|
|
|
|
|
mLife_cons_id = cons_mgr->getConstraintId(datablock->life_cons_def);
|
2017-07-26 08:35:44 +00:00
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
mTime_factor = (datablock->ignore_time_factor) ? 1.0f : time_factor;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
if (datablock->propagate_time_factor)
|
2018-03-29 22:46:57 +00:00
|
|
|
mProp_time_factor = time_factor;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
if (datablock->runsHere(choreographer->isServerObject()))
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < MAX_XFM_MODIFIERS && datablock->xfm_modifiers[i] != 0; i++)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mXfm_modifiers[i] = datablock->xfm_modifiers[i]->create(this, choreographer->isServerObject());
|
|
|
|
|
AssertFatal(mXfm_modifiers[i] != 0, avar("Error, creation failed for xfm_modifiers[%d] of %s.", i, datablock->getName()));
|
|
|
|
|
if (mXfm_modifiers[i] == 0)
|
2017-07-26 08:35:44 +00:00
|
|
|
Con::errorf("Error, creation failed for xfm_modifiers[%d] of %s.", i, datablock->getName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (datablock->effect_name != ST_NULLSTRING)
|
|
|
|
|
{
|
|
|
|
|
assignName(datablock->effect_name);
|
|
|
|
|
choreographer->addNamedEffect(this);
|
|
|
|
|
if (datablock->use_as_cons_obj)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mEffect_cons_id = cons_mgr->setReferenceEffect(datablock->effect_name, this);
|
|
|
|
|
if (mEffect_cons_id.undefined() && datablock->isTempClone() && datablock->runsHere(choreographer->isServerObject()))
|
|
|
|
|
mEffect_cons_id = cons_mgr->createReferenceEffect(datablock->effect_name, this);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapper::prestart()
|
|
|
|
|
{
|
|
|
|
|
// modify timing values by time_factor
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mEW_timing.lifetime > 0)
|
|
|
|
|
mEW_timing.lifetime *= mTime_factor;
|
|
|
|
|
mEW_timing.delay *= mTime_factor;
|
|
|
|
|
mEW_timing.fade_in_time *= mTime_factor;
|
|
|
|
|
mEW_timing.fade_out_time *= mTime_factor;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mEW_timing.lifetime < 0)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mFull_lifetime = INFINITE_LIFETIME;
|
|
|
|
|
mLife_end = INFINITE_LIFETIME;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mFull_lifetime = mEW_timing.lifetime + mEW_timing.fade_out_time;
|
|
|
|
|
mLife_end = mEW_timing.delay + mEW_timing.lifetime;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
if ((mEW_timing.fade_in_time + mEW_timing.fade_out_time) > 0.0f)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mFade_in_end = mEW_timing.delay + mEW_timing.fade_in_time;
|
2023-04-27 03:27:35 +00:00
|
|
|
if (mFull_lifetime == (F32)INFINITE_LIFETIME)
|
|
|
|
|
mFade_out_start = (F32)INFINITE_LIFETIME;
|
2017-07-26 08:35:44 +00:00
|
|
|
else
|
2018-03-29 22:46:57 +00:00
|
|
|
mFade_out_start = mEW_timing.delay + mEW_timing.lifetime;
|
|
|
|
|
mDo_fade_inout = true;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
if (!mDo_fade_inout && mDatablock->vis_keys != NULL && mDatablock->vis_keys->numKeys() > 0)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
|
|
|
|
//do_fades = true;
|
2018-03-29 22:46:57 +00:00
|
|
|
mFade_out_start = mEW_timing.delay + mEW_timing.lifetime;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool afxEffectWrapper::start(F32 timestamp)
|
|
|
|
|
{
|
|
|
|
|
if (!ea_is_enabled())
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
Con::warnf("afxEffectWrapper::start() -- effect type of %s is currently disabled.", mDatablock->getName());
|
2017-07-26 08:35:44 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
afxConstraint* life_constraint = getLifeConstraint();
|
|
|
|
|
if (life_constraint)
|
2018-03-29 22:46:57 +00:00
|
|
|
mCond_alive = life_constraint->getLivingState();
|
2017-07-26 08:35:44 +00:00
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
mElapsed = timestamp;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
for (S32 i = 0; i < MAX_XFM_MODIFIERS; i++)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
if (!mXfm_modifiers[i])
|
2017-07-26 08:35:44 +00:00
|
|
|
break;
|
|
|
|
|
else
|
2018-03-29 22:46:57 +00:00
|
|
|
mXfm_modifiers[i]->start(timestamp);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ea_start())
|
|
|
|
|
{
|
|
|
|
|
// subclass should print error message if applicable, so no message here.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update(0.0f);
|
|
|
|
|
return !isAborted();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool afxEffectWrapper::test_life_conds()
|
|
|
|
|
{
|
|
|
|
|
afxConstraint* life_constraint = getLifeConstraint();
|
2018-03-29 22:46:57 +00:00
|
|
|
if (!life_constraint || mDatablock->life_conds == 0)
|
2017-07-26 08:35:44 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
S32 now_state = life_constraint->getDamageState();
|
2018-03-29 22:46:57 +00:00
|
|
|
if ((mDatablock->life_conds & DEAD) != 0 && now_state == ShapeBase::Disabled)
|
2017-07-26 08:35:44 +00:00
|
|
|
return true;
|
2018-03-29 22:46:57 +00:00
|
|
|
if ((mDatablock->life_conds & ALIVE) != 0 && now_state == ShapeBase::Enabled)
|
2017-07-26 08:35:44 +00:00
|
|
|
return true;
|
2018-03-29 22:46:57 +00:00
|
|
|
if ((mDatablock->life_conds & DYING) != 0)
|
|
|
|
|
return (mCond_alive && now_state == ShapeBase::Disabled);
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool afxEffectWrapper::update(F32 dt)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mElapsed += dt;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
// life_elapsed won't exceed full_lifetime
|
2018-03-29 22:46:57 +00:00
|
|
|
mLife_elapsed = getMin(mElapsed - mEW_timing.delay, mFull_lifetime);
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
// update() returns early if elapsed is outside of active timing range
|
|
|
|
|
// (delay <= elapsed <= delay+lifetime)
|
|
|
|
|
// note: execution is always allowed beyond this point at least once,
|
|
|
|
|
// even if elapsed exceeds the lifetime.
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mElapsed < mEW_timing.delay)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
|
|
|
|
setScopeStatus(false);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
if (!mDatablock->requiresStop(mEW_timing) && mEW_timing.lifetime < 0)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
F32 afterlife = mElapsed - mEW_timing.delay;
|
|
|
|
|
if (afterlife > 1.0f || ((afterlife > 0.0f) && (mNum_updates > 0)))
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
setScopeStatus(mEW_timing.residue_lifetime > 0.0f);
|
2017-07-26 08:35:44 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
F32 afterlife = mElapsed - (mFull_lifetime + mEW_timing.delay);
|
|
|
|
|
if (afterlife > 1.0f || ((afterlife > 0.0f) && (mNum_updates > 0)))
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
setScopeStatus(mEW_timing.residue_lifetime > 0.0f);
|
2017-07-26 08:35:44 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// first time here, test if required conditions for effect are met
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mNum_updates == 0)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
|
|
|
|
if (!test_life_conds())
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mElapsed = mFull_lifetime + mEW_timing.delay;
|
2017-07-26 08:35:44 +00:00
|
|
|
setScopeStatus(false);
|
2018-03-29 22:46:57 +00:00
|
|
|
mNum_updates++;
|
2017-07-26 08:35:44 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setScopeStatus(true);
|
2018-03-29 22:46:57 +00:00
|
|
|
mNum_updates++;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// calculate current fade value if enabled
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mDo_fade_inout)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mEW_timing.fade_in_time > 0 && mElapsed <= mFade_in_end)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
F32 t = mClampF((mElapsed - mEW_timing.delay)/ mEW_timing.fade_in_time, 0.0f, 1.0f);
|
|
|
|
|
mFade_value = afxEase::t(t, mEW_timing.fadein_ease.x, mEW_timing.fadein_ease.y);
|
|
|
|
|
mDo_fades = true;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
2018-03-29 22:46:57 +00:00
|
|
|
else if (mElapsed > mFade_out_start)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mEW_timing.fade_out_time == 0)
|
|
|
|
|
mFade_value = 0.0f;
|
2017-07-26 08:35:44 +00:00
|
|
|
else
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
F32 t = mClampF(1.0f-(mElapsed - mFade_out_start)/ mEW_timing.fade_out_time, 0.0f, 1.0f);
|
|
|
|
|
mFade_value = afxEase::t(t, mEW_timing.fadeout_ease.x, mEW_timing.fadeout_ease.y);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
2018-03-29 22:46:57 +00:00
|
|
|
mDo_fades = true;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mFade_value = 1.0f;
|
|
|
|
|
mDo_fades = false;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mFade_value = 1.0;
|
|
|
|
|
mDo_fades = false;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mDatablock->vis_keys && mDatablock->vis_keys->numKeys() > 0)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
F32 vis = mDatablock->vis_keys->evaluate(mElapsed - mEW_timing.delay);
|
|
|
|
|
mFade_value *= mClampF(vis, 0.0f, 1.0f);
|
|
|
|
|
mDo_fades = (mFade_value < 1.0f);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DEAL WITH CONSTRAINTS
|
|
|
|
|
afxXM_Params params;
|
|
|
|
|
Point3F& CONS_POS = params.pos;
|
|
|
|
|
MatrixF& CONS_XFM = params.ori;
|
|
|
|
|
Point3F& CONS_AIM = params.pos2;
|
|
|
|
|
Point3F& CONS_SCALE = params.scale;
|
|
|
|
|
LinearColorF& CONS_COLOR = params.color;
|
|
|
|
|
|
|
|
|
|
afxConstraint* pos_constraint = getPosConstraint();
|
|
|
|
|
if (pos_constraint)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
bool valid = pos_constraint->getPosition(CONS_POS, mDatablock->pos_cons_def.mHistory_time);
|
2017-07-26 08:35:44 +00:00
|
|
|
if (!valid)
|
|
|
|
|
getUnconstrainedPosition(CONS_POS);
|
|
|
|
|
setScopeStatus(valid);
|
2018-03-29 22:46:57 +00:00
|
|
|
if (valid && mDatablock->borrow_altitudes)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
|
|
|
|
F32 terr_alt, inter_alt;
|
|
|
|
|
if (pos_constraint->getAltitudes(terr_alt, inter_alt))
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mTerrain_altitude = terr_alt;
|
|
|
|
|
mInterior_altitude = inter_alt;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
getUnconstrainedPosition(CONS_POS);
|
|
|
|
|
setScopeStatus(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
afxConstraint* orient_constraint = getOrientConstraint();
|
|
|
|
|
if (orient_constraint)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
orient_constraint->getTransform(CONS_XFM, mDatablock->pos_cons_def.mHistory_time);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
getUnconstrainedTransform(CONS_XFM);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
afxConstraint* aim_constraint = getAimConstraint();
|
|
|
|
|
if (aim_constraint)
|
2018-03-29 22:46:57 +00:00
|
|
|
aim_constraint->getPosition(CONS_AIM, mDatablock->pos_cons_def.mHistory_time);
|
2017-07-26 08:35:44 +00:00
|
|
|
else
|
|
|
|
|
CONS_AIM.zero();
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
CONS_SCALE.set(mDatablock->scale_factor, mDatablock->scale_factor, mDatablock->scale_factor);
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if (datablock->isPositional() && CONS_POS.isZero() && in_scope)
|
|
|
|
|
Con::errorf("#EFFECT AT ORIGIN [%s] time=%g", datablock->getName(), dt);
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
getBaseColor(CONS_COLOR);
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
params.vis = mFade_value;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
// apply modifiers
|
|
|
|
|
for (int i = 0; i < MAX_XFM_MODIFIERS; i++)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
if (!mXfm_modifiers[i])
|
2017-07-26 08:35:44 +00:00
|
|
|
break;
|
|
|
|
|
else
|
2018-03-29 22:46:57 +00:00
|
|
|
mXfm_modifiers[i]->updateParams(dt, mLife_elapsed, params);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// final pos/orient is determined
|
2018-03-29 22:46:57 +00:00
|
|
|
mUpdated_xfm = CONS_XFM;
|
|
|
|
|
mUpdated_pos = CONS_POS;
|
|
|
|
|
mUpdated_aim = CONS_AIM;
|
|
|
|
|
mUpdated_xfm.setPosition(mUpdated_pos);
|
|
|
|
|
mUpdated_scale = CONS_SCALE;
|
|
|
|
|
mUpdated_color = CONS_COLOR;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
if (params.vis > 1.0f)
|
2018-03-29 22:46:57 +00:00
|
|
|
mFade_value = 1.0f;
|
2017-07-26 08:35:44 +00:00
|
|
|
else
|
2018-03-29 22:46:57 +00:00
|
|
|
mFade_value = params.vis;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mLast_fade_value != mFade_value)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mDo_fades = true;
|
|
|
|
|
mLast_fade_value = mFade_value;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mDo_fades = (mFade_value < 1.0f);
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ea_update(dt))
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mIs_aborted = true;
|
|
|
|
|
Con::errorf("afxEffectWrapper::update() -- effect %s ended unexpectedly.", mDatablock->getName());
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapper::stop()
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
if (!mDatablock->requiresStop(mEW_timing))
|
2017-07-26 08:35:44 +00:00
|
|
|
return;
|
|
|
|
|
|
2018-03-29 22:46:57 +00:00
|
|
|
mStopped = true;
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
// this resets full_lifetime so it starts to shrink or fade
|
2023-04-27 03:27:35 +00:00
|
|
|
if (mFull_lifetime == (F32)INFINITE_LIFETIME)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mFull_lifetime = (mElapsed - mEW_timing.delay) + afterStopTime();
|
|
|
|
|
mLife_end = mElapsed;
|
|
|
|
|
if (mEW_timing.fade_out_time > 0)
|
|
|
|
|
mFade_out_start = mElapsed;
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapper::cleanup(bool was_stopped)
|
|
|
|
|
{
|
|
|
|
|
ea_finish(was_stopped);
|
2018-03-29 22:46:57 +00:00
|
|
|
if (!mEffect_cons_id.undefined())
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mCons_mgr->setReferenceEffect(mEffect_cons_id, 0);
|
|
|
|
|
mEffect_cons_id = afxConstraintID();
|
2017-07-26 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void afxEffectWrapper::setScopeStatus(bool in_scope)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
if (mIn_scope != in_scope)
|
2017-07-26 08:35:44 +00:00
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
mIn_scope = in_scope;
|
2017-07-26 08:35:44 +00:00
|
|
|
ea_set_scope_status(in_scope);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool afxEffectWrapper::isDone()
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
if (!mDatablock->is_looping)
|
|
|
|
|
return (mElapsed >= (mLife_end + mEW_timing.fade_out_time));
|
2017-07-26 08:35:44 +00:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
afxEffectWrapper* afxEffectWrapper::ew_create(afxChoreographer* choreographer,
|
|
|
|
|
afxEffectWrapperData* datablock,
|
|
|
|
|
afxConstraintMgr* cons_mgr,
|
|
|
|
|
F32 time_factor,
|
|
|
|
|
S32 group_index)
|
|
|
|
|
{
|
|
|
|
|
afxEffectWrapper* adapter = datablock->effect_desc->create();
|
|
|
|
|
|
|
|
|
|
if (adapter)
|
|
|
|
|
{
|
2018-03-29 22:46:57 +00:00
|
|
|
adapter->mGroup_index = (datablock->group_index != -1) ? datablock->group_index : group_index;
|
2017-07-26 08:35:44 +00:00
|
|
|
adapter->ew_init(choreographer, datablock, cons_mgr, time_factor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return adapter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
|
|
|
|
|
|
|
|
Vector<afxEffectAdapterDesc*>* afxEffectAdapterDesc::adapters = 0;
|
|
|
|
|
|
|
|
|
|
afxEffectAdapterDesc::afxEffectAdapterDesc()
|
|
|
|
|
{
|
|
|
|
|
if (!adapters)
|
|
|
|
|
adapters = new Vector<afxEffectAdapterDesc*>;
|
|
|
|
|
|
|
|
|
|
adapters->push_back(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool afxEffectAdapterDesc::identifyEffect(afxEffectWrapperData* ew)
|
|
|
|
|
{
|
|
|
|
|
if (!ew || !ew->effect_data)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("afxEffectAdapterDesc::identifyEffect() -- effect datablock was not specified.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!adapters)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("afxEffectAdapterDesc::identifyEffect() -- adapter registration list has not been allocated.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (adapters->size() == 0)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("afxEffectAdapterDesc::identifyEffect() -- no effect adapters have been registered.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (S32 i = 0; i < adapters->size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if ((*adapters)[i]->testEffectType(ew->effect_data))
|
|
|
|
|
{
|
|
|
|
|
ew->effect_desc = (*adapters)[i];
|
|
|
|
|
(*adapters)[i]->prepEffect(ew);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Con::errorf("afxEffectAdapterDesc::identifyEffect() -- effect %s has an undefined type. -- %d",
|
|
|
|
|
ew->effect_data->getName(), adapters->size());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|