mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 20:54:46 +00:00
272 lines
9.3 KiB
C++
272 lines
9.3 KiB
C++
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
|
// Copyright (C) 2015 Faust Logic, Inc.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
|
|
#include "afx/arcaneFX.h"
|
|
|
|
#include "console/engineAPI.h"
|
|
|
|
#include "afx/afxEffectGroup.h"
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
// afxEffectGroupData::egValidator
|
|
//
|
|
// When an effect is added using "addEffect", this validator intercepts the value
|
|
// and adds it to the dynamic effects list.
|
|
//
|
|
void afxEffectGroupData::egValidator::validateType(SimObject* object, StringTableEntry varname, void* typePtr)
|
|
{
|
|
afxEffectGroupData* eff_data = dynamic_cast<afxEffectGroupData*>(object);
|
|
afxEffectBaseData** ew = (afxEffectBaseData**)(typePtr);
|
|
|
|
if (eff_data && ew)
|
|
{
|
|
eff_data->fx_list.push_back(*ew);
|
|
*ew = 0;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
// afxEffectGroupData
|
|
|
|
IMPLEMENT_CO_DATABLOCK_V1(afxEffectGroupData);
|
|
|
|
ConsoleDocClass( afxEffectGroupData,
|
|
"@brief A datablock that describes an Effect Group.\n\n"
|
|
|
|
"afxEffectGroupData provides a way for adding several effects to a choreographer as a "
|
|
"group and can be used wherever an afxEffectWrapperData is used. Basically, an "
|
|
"effect-group is a simple list of effect-wrappers. When an effect-group is added to a "
|
|
"choreographer, the end result is almost the same as adding all of the group's "
|
|
"effect-wrappers directly to the choreographer. The main difference is that the "
|
|
"grouped effects can be turned on and off collectively and created in multiples. "
|
|
"Effect-groups can also contain other effect-groups, forming a hierarchy of effects.\n\n"
|
|
|
|
"A great strength of effect-groups is that they have a count setting that multiplies "
|
|
"the number of times the effects in the group are added to the owning choreographer "
|
|
"and this doesn't happen until the choreographer instance is created and launched. "
|
|
"This makes a big difference for certain kinds of effects, such as fireworks, that "
|
|
"tend to consist of small groupings of effects that are repeated many times with "
|
|
"slight variations. With groups, an effect like this has a very compact representation "
|
|
"for transmitting from server to clients, that only expands when actually used.\n\n"
|
|
|
|
"Effect-groups with a count greater than one are extremely useful when some of the "
|
|
"effects use field substitutions. When an effect-group is expanded, it essentially runs "
|
|
"through a for-loop from 0 to count-1 and creates a new set of effect instances each "
|
|
"time through the loop. For each new set of effects, their group-index is set to the "
|
|
"index of this for-loop, which in turn replaces the ## token used in any field "
|
|
"substitutions in the child effects. In essence, the for-loop index becomes a parameter "
|
|
"of the child effects which can be used to vary the effects created in each loop.\n\n"
|
|
|
|
"@see afxEffectBaseData\n\n"
|
|
"@see afxEffectWrapperData\n\n"
|
|
|
|
"@ingroup afxEffects\n"
|
|
"@ingroup AFX\n"
|
|
"@ingroup Datablocks\n"
|
|
);
|
|
|
|
afxEffectGroupData::afxEffectGroupData()
|
|
{
|
|
group_enabled = true;
|
|
group_count = 1;
|
|
idx_offset = 0;
|
|
assign_idx = false;
|
|
|
|
// dummy entry holds effect-wrapper pointer while a special validator
|
|
// grabs it and adds it to an appropriate effects list
|
|
dummy_fx_entry = NULL;
|
|
|
|
// marked true if datablock ids need to
|
|
// be converted into pointers
|
|
do_id_convert = false;
|
|
}
|
|
|
|
afxEffectGroupData::afxEffectGroupData(const afxEffectGroupData& other, bool temp_clone) : afxEffectBaseData(other, temp_clone)
|
|
{
|
|
group_enabled = other.group_enabled;
|
|
group_count = other.group_count;
|
|
idx_offset = other.idx_offset;
|
|
assign_idx = other.assign_idx;
|
|
timing = other.timing;
|
|
dummy_fx_entry = other.dummy_fx_entry;
|
|
do_id_convert = other.do_id_convert; // --
|
|
fx_list = other.fx_list; // --
|
|
}
|
|
|
|
void afxEffectGroupData::reloadReset()
|
|
{
|
|
fx_list.clear();
|
|
}
|
|
|
|
void afxEffectGroupData::pack_fx(BitStream* stream, const afxEffectList& fx, bool packed)
|
|
{
|
|
stream->writeInt(fx.size(), EFFECTS_PER_PHRASE_BITS);
|
|
for (int i = 0; i < fx.size(); i++)
|
|
writeDatablockID(stream, fx[i], packed);
|
|
}
|
|
|
|
void afxEffectGroupData::unpack_fx(BitStream* stream, afxEffectList& fx)
|
|
{
|
|
fx.clear();
|
|
S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS);
|
|
for (int i = 0; i < n_fx; i++)
|
|
fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream));
|
|
}
|
|
|
|
#define myOffset(field) Offset(field, afxEffectGroupData)
|
|
|
|
void afxEffectGroupData::initPersistFields()
|
|
{
|
|
docsURL;
|
|
addField("groupEnabled", TypeBool, myOffset(group_enabled),
|
|
"...");
|
|
addFieldV("count", TypeRangedS32, myOffset(group_count), &CommonValidators::NaturalNumber,
|
|
"...");
|
|
addField("indexOffset", TypeS8, myOffset(idx_offset),
|
|
"...");
|
|
addField("assignIndices", TypeBool, myOffset(assign_idx),
|
|
"...");
|
|
|
|
addFieldV("delay", TypeRangedF32, myOffset(timing.delay), &CommonValidators::PositiveFloat,
|
|
"...");
|
|
addFieldV("lifetime", TypeRangedF32, myOffset(timing.lifetime), &CommonValidators::PositiveFloat,
|
|
"...");
|
|
addFieldV("fadeInTime", TypeRangedF32, myOffset(timing.fade_in_time), &CommonValidators::PositiveFloat,
|
|
"...");
|
|
addFieldV("fadeOutTime", TypeRangedF32, myOffset(timing.fade_out_time), &CommonValidators::PositiveFloat,
|
|
"...");
|
|
|
|
// effect lists
|
|
// for each of these, dummy_fx_entry is set and then a validator adds it to the appropriate effects list
|
|
static egValidator emptyValidator(0);
|
|
|
|
addFieldV("addEffect", TYPEID<afxEffectBaseData>(), myOffset(dummy_fx_entry), &emptyValidator,
|
|
"...");
|
|
|
|
Parent::initPersistFields();
|
|
|
|
// disallow some field substitutions
|
|
disableFieldSubstitutions("addEffect");
|
|
}
|
|
|
|
void afxEffectGroupData::packData(BitStream* stream)
|
|
{
|
|
Parent::packData(stream);
|
|
|
|
stream->writeFlag(group_enabled);
|
|
stream->write(group_count);
|
|
stream->write(idx_offset);
|
|
stream->writeFlag(assign_idx);
|
|
stream->write(timing.delay);
|
|
stream->write(timing.lifetime);
|
|
stream->write(timing.fade_in_time);
|
|
stream->write(timing.fade_out_time);
|
|
|
|
pack_fx(stream, fx_list, mPacked);
|
|
}
|
|
|
|
void afxEffectGroupData::unpackData(BitStream* stream)
|
|
{
|
|
Parent::unpackData(stream);
|
|
|
|
group_enabled = stream->readFlag();
|
|
stream->read(&group_count);
|
|
stream->read(&idx_offset);
|
|
assign_idx = stream->readFlag();
|
|
stream->read(&timing.delay);
|
|
stream->read(&timing.lifetime);
|
|
stream->read(&timing.fade_in_time);
|
|
stream->read(&timing.fade_out_time);
|
|
|
|
do_id_convert = true;
|
|
unpack_fx(stream, fx_list);
|
|
}
|
|
|
|
bool afxEffectGroupData::preload(bool server, String &errorStr)
|
|
{
|
|
if (!Parent::preload(server, errorStr))
|
|
return false;
|
|
|
|
// Resolve objects transmitted from server
|
|
if (!server)
|
|
{
|
|
if (do_id_convert)
|
|
{
|
|
for (S32 i = 0; i < fx_list.size(); i++)
|
|
{
|
|
SimObjectId db_id = SimObjectId((uintptr_t)fx_list[i]);
|
|
if (db_id != 0)
|
|
{
|
|
// try to convert id to pointer
|
|
if (!Sim::findObject(db_id, fx_list[i]))
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General,
|
|
"afxEffectGroupData::preload() -- bad datablockId: 0x%x",
|
|
db_id);
|
|
}
|
|
}
|
|
}
|
|
do_id_convert = false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void afxEffectGroupData::gather_cons_defs(Vector<afxConstraintDef>& defs)
|
|
{
|
|
for (S32 i = 0; i < fx_list.size(); i++)
|
|
{
|
|
if (fx_list[i])
|
|
fx_list[i]->gather_cons_defs(defs);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
|
|
|
|
DefineEngineMethod(afxEffectGroupData, reset, void, (),,
|
|
"Resets an effect-group datablock during reload.\n\n"
|
|
"@ingroup AFX")
|
|
{
|
|
object->reloadReset();
|
|
}
|
|
|
|
DefineEngineMethod(afxEffectGroupData, pushEffect, void, (afxEffectBaseData* effect),,
|
|
"Adds an effect (wrapper or group) to an effect-group.\n\n"
|
|
"@ingroup AFX")
|
|
{
|
|
if (!effect)
|
|
{
|
|
Con::errorf("afxEffectGroupData::pushEffect() -- missing afxEffectWrapperData.");
|
|
return;
|
|
}
|
|
|
|
object->fx_list.push_back(effect);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
|
|