123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617 |
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // 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 "scene/sceneManager.h"
- #include "T3D/gameBase/gameProcess.h"
- #include "afx/util/afxPath.h"
- #include "afx/util/afxPath3D.h"
- #include "afx/ce/afxParticleEmitter.h"
- IMPLEMENT_CO_DATABLOCK_V1(afxParticleEmitterData);
- ConsoleDocClass( afxParticleEmitterData,
- "@brief A base datablock inherited by AFX Particle Emitter effects.\n\n"
- "A base datablock inherited by AFX Particle Emitter effects."
- "\n\n"
- "@ingroup afxEffects\n"
- "@ingroup AFX\n"
- "@ingroup Datablocks\n"
- );
- afxParticleEmitterData::afxParticleEmitterData()
- {
- fade_velocity = false; // coordinate velocity amount with fade amout
- fade_offset = false; // coordinate ejection-offset amount with fade amount
- pe_vector.set(0.0,0.0,0.0);
- pe_vector_is_world = false;
- tpaths_string = ST_NULLSTRING;
- tPathDataBlocks.clear();
- tPathDataBlockIds.clear();
- }
- afxParticleEmitterData::afxParticleEmitterData(const afxParticleEmitterData& other, bool temp_clone) : ParticleEmitterData(other, temp_clone)
- {
- fade_velocity = other.fade_velocity;
- fade_offset = other.fade_offset;
- pe_vector = other.pe_vector;
- pe_vector_is_world = other.pe_vector_is_world;
- tpaths_string = other.tpaths_string;
- tPathDataBlocks = other.tPathDataBlocks;
- //tPathDataBlockIds = other.tPathDataBlockIds;
- }
- void afxParticleEmitterData::initPersistFields()
- {
- addField("fadeVelocity", TypeBool, Offset(fade_velocity, afxParticleEmitterData),
- "If true, the initial velocity of emitted particles is multiplied by the fade amount "
- "of the containing effect wrapper. As the effect fades-in and out, so does the "
- "initial velocity of new particles.");
- addField("fadeOffset", TypeBool, Offset(fade_offset, afxParticleEmitterData),
- "If true, the ejection offset of emitted particles is multiplied by the fade amount "
- "of the containing effect wrapper. As the effect fades-in and out, so does the "
- "ejection offset of new particles.");
- addField("vector", TypePoint3F, Offset(pe_vector, afxParticleEmitterData),
- "General direction vector used for emitting particles. Its exact interpretation is "
- "determined by the particle emitter subclass.");
- addField("vectorIsWorld", TypeBool, Offset(pe_vector_is_world, afxParticleEmitterData),
- "Sets whether the vector field should be interpreted as a vector in the world "
- "coordinate system.");
- addField("pathsTransform", TypeString, Offset(tpaths_string, afxParticleEmitterData),
- "A string of paths to be used as transform paths. Each path name must reference an "
- "afxPathData datablock. Transform paths are used to translate particles along a given "
- "path or series of paths.");
- Parent::initPersistFields();
- }
- void afxParticleEmitterData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- stream->writeFlag(fade_velocity);
- stream->writeFlag(fade_offset);
- mathWrite(*stream, pe_vector);
- stream->writeFlag(pe_vector_is_world);
- stream->write(tPathDataBlockIds.size());
- for (int i = 0; i < tPathDataBlockIds.size(); i++)
- stream->write(tPathDataBlockIds[i]);
- }
- void afxParticleEmitterData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- fade_velocity = stream->readFlag();
- fade_offset = stream->readFlag();
- mathRead(*stream, &pe_vector);
- pe_vector_is_world = stream->readFlag();
- U32 n_db; stream->read(&n_db);
- tPathDataBlockIds.setSize(n_db);
- for (U32 i = 0; i < n_db; i++)
- stream->read(&tPathDataBlockIds[i]);
- }
- bool afxParticleEmitterData::onAdd()
- {
- if( Parent::onAdd() == false )
- return false;
- if (tpaths_string != ST_NULLSTRING && tpaths_string[0] == '\0')
- {
- Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) empty transform paths string.", getName());
- return false;
- }
-
- if (tpaths_string != ST_NULLSTRING && dStrlen(tpaths_string) > 255)
- {
- Con::errorf(ConsoleLogEntry::General, "ParticleEmitterData(%s) transform paths string too long [> 255 chars].", getName());
- return false;
- }
-
- if (tpaths_string != ST_NULLSTRING)
- {
- Vector<char*> dataBlocks(__FILE__, __LINE__);
- char* tokCopy = new char[dStrlen(tpaths_string) + 1];
- dStrcpy(tokCopy, tpaths_string, dStrlen(tpaths_string) + 1);
-
- char* currTok = dStrtok(tokCopy, " \t");
- while (currTok != NULL)
- {
- dataBlocks.push_back(currTok);
- currTok = dStrtok(NULL, " \t");
- }
- if (dataBlocks.size() == 0)
- {
- Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) invalid transform paths string. No datablocks found", getName());
- delete [] tokCopy;
- return false;
- }
- tPathDataBlocks.clear();
- tPathDataBlockIds.clear();
-
- for (U32 i = 0; i < dataBlocks.size(); i++)
- {
- afxPathData* pData = NULL;
- if (Sim::findObject(dataBlocks[i], pData) == false)
- {
- Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) unable to find transform path datablock: %s", getName(), dataBlocks[i]);
- }
- else
- {
- tPathDataBlocks.push_back(pData);
- tPathDataBlockIds.push_back(pData->getId());
- }
- }
- delete [] tokCopy;
- if (tPathDataBlocks.size() == 0)
- {
- Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) unable to find any transform path datablocks", getName());
- return false;
- }
- }
- return true;
- }
- bool afxParticleEmitterData::preload(bool server, String &errorStr)
- {
- if (Parent::preload(server, errorStr) == false)
- return false;
- tPathDataBlocks.clear();
- for (U32 i = 0; i < tPathDataBlockIds.size(); i++)
- {
- afxPathData* pData = NULL;
- if (Sim::findObject(tPathDataBlockIds[i], pData) == false)
- {
- Con::warnf(ConsoleLogEntry::General,
- "ParticleEmitterData(%s) unable to find transform path datablock: %d",
- getName(), tPathDataBlockIds[i]);
- }
- else
- tPathDataBlocks.push_back(pData);
- }
- return true;
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // VECTOR
- IMPLEMENT_CO_DATABLOCK_V1(afxParticleEmitterVectorData);
- ConsoleDocClass( afxParticleEmitterVectorData,
- "@brief An AFX customized particle emitter that emits particles along a 3D vector.\n\n"
- "An AFX customized particle emitter that emits particles along a 3D vector."
- "\n\n"
- "@ingroup afxEffects\n"
- "@ingroup AFX\n"
- "@ingroup Datablocks\n"
- );
- afxParticleEmitterVectorData::afxParticleEmitterVectorData()
- {
- }
- afxParticleEmitterVectorData::afxParticleEmitterVectorData(const afxParticleEmitterVectorData& other, bool temp_clone) : afxParticleEmitterData(other, temp_clone)
- {
- }
- void afxParticleEmitterVectorData::initPersistFields()
- {
- Parent::initPersistFields();
- }
- void afxParticleEmitterVectorData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- }
- void afxParticleEmitterVectorData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- }
- bool afxParticleEmitterVectorData::onAdd()
- {
- if (Parent::onAdd() == false)
- return false;
- return true;
- }
- bool afxParticleEmitterVectorData::preload(bool server, String &errorStr)
- {
- if (Parent::preload(server, errorStr) == false)
- return false;
- return true;
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // CONE
- IMPLEMENT_CO_DATABLOCK_V1(afxParticleEmitterConeData);
- ConsoleDocClass( afxParticleEmitterConeData,
- "@brief An AFX customized particle emitter that emits particles within a cone shape.\n\n"
- "An AFX customized particle emitter that emits particles within a cone shape."
- "\n\n"
- "@ingroup afxEffects\n"
- "@ingroup AFX\n"
- "@ingroup Datablocks\n"
- );
- afxParticleEmitterConeData::afxParticleEmitterConeData()
- {
- spread_min = 0.0f;
- spread_max = 90.0f;
- }
- afxParticleEmitterConeData::afxParticleEmitterConeData(const afxParticleEmitterConeData& other, bool temp_clone) : afxParticleEmitterData(other, temp_clone)
- {
- spread_min = other.spread_min;
- spread_max = other.spread_max;
- }
- void afxParticleEmitterConeData::initPersistFields()
- {
- addField("spreadMin", TypeF32, Offset(spread_min, afxParticleEmitterConeData),
- "...");
- addField("spreadMax", TypeF32, Offset(spread_max, afxParticleEmitterConeData),
- "...");
- Parent::initPersistFields();
- }
- void afxParticleEmitterConeData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- stream->writeRangedU32((U32)spread_min, 0, 180);
- stream->writeRangedU32((U32)spread_max, 0, 180);
- }
- void afxParticleEmitterConeData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- spread_min = stream->readRangedU32(0, 180);
- spread_max = stream->readRangedU32(0, 180);
- }
- bool afxParticleEmitterConeData::onAdd()
- {
- if( Parent::onAdd() == false )
- return false;
- if (spread_min < 0.0f)
- {
- Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) spreadMin < 0.0", getName());
- spread_min = 0.0f;
- }
- if (spread_max > 180.0f)
- {
- Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) spreadMax > 180.0f", getName());
- spread_max = 180.0f;
- }
- if (spread_max > 179.5f)
- spread_max = 179.5f;
- if (spread_min > 179.5f)
- spread_min = 179.5f;
- if (spread_min > spread_max)
- {
- Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) spreadMin > spreadMax", getName());
- spread_min = spread_max;
- }
- return true;
- }
- bool afxParticleEmitterConeData::preload(bool server, String &errorStr)
- {
- if (Parent::preload(server, errorStr) == false)
- return false;
- return true;
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // PATH
- IMPLEMENT_CO_DATABLOCK_V1(afxParticleEmitterPathData);
- ConsoleDocClass( afxParticleEmitterPathData,
- "@brief An AFX customized particle emitter that emits particles along a path.\n\n"
- "An AFX customized particle emitter that emits particles along a path."
- "\n\n"
- "@ingroup afxEffects\n"
- "@ingroup AFX\n"
- "@ingroup Datablocks\n"
- );
- afxParticleEmitterPathData::afxParticleEmitterPathData()
- {
- epaths_string = ST_NULLSTRING;
- epathDataBlocks.clear();
- epathDataBlockIds.clear();
- path_origin_type = PATHEMIT_ORIGIN;
- ground_conform = false;
- ground_conform_terrain = true;
- ground_conform_interiors = true;
- ground_conform_height = 0.0f;
- }
- afxParticleEmitterPathData::afxParticleEmitterPathData(const afxParticleEmitterPathData& other, bool temp_clone) : afxParticleEmitterData(other, temp_clone)
- {
- epaths_string = other.epaths_string;
- epathDataBlocks = other.epathDataBlocks;
- //epathDataBlockIds = other.epathDataBlockIds;
- path_origin_type = other.path_origin_type;
- ground_conform = other.ground_conform;
- ground_conform_terrain = other.ground_conform_terrain;
- ground_conform_interiors = other.ground_conform_interiors;
- ground_conform_height = other.ground_conform_height;
- }
- ImplementEnumType( afxParticleEmitterPath_OriginType, "Possible particle emitter path origin types.\n" "@ingroup afxParticleEmitterPath\n\n" )
- { afxParticleEmitterPathData::PATHEMIT_ORIGIN, "origin", "..." },
- { afxParticleEmitterPathData::PATHEMIT_POINT, "point", "..." },
- { afxParticleEmitterPathData::PATHEMIT_VECTOR, "vector", "..." },
- { afxParticleEmitterPathData::PATHEMIT_TANGENT, "tangent", "..." },
- EndImplementEnumType;
- void afxParticleEmitterPathData::initPersistFields()
- {
- addField("paths", TypeString, Offset(epaths_string, afxParticleEmitterPathData),
- "...");
- addField("pathOrigin", TYPEID<afxParticleEmitterPathData::PathOriginType>(), Offset(path_origin_type, afxParticleEmitterPathData),
- "...");
- // JTF Note: take a look at these and make sure they are ok.
- addField("groundConform", TypeBool, Offset(ground_conform, afxParticleEmitterPathData),
- "...");
- addField("groundConformTerrain", TypeBool, Offset(ground_conform_terrain, afxParticleEmitterPathData),
- "...");
- addField("groundConformInteriors", TypeBool, Offset(ground_conform_interiors, afxParticleEmitterPathData),
- "...");
- addField("groundConformHeight", TypeF32, Offset(ground_conform_height, afxParticleEmitterPathData),
- "...");
- Parent::initPersistFields();
- }
- void afxParticleEmitterPathData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- stream->write(epathDataBlockIds.size());
- for (int i = 0; i < epathDataBlockIds.size(); i++)
- stream->write(epathDataBlockIds[i]);
- stream->write(path_origin_type);
- stream->writeFlag(ground_conform);
- stream->writeFlag(ground_conform_terrain);
- stream->writeFlag(ground_conform_interiors);
- stream->write(ground_conform_height);
- }
- void afxParticleEmitterPathData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- U32 n_db; stream->read(&n_db);
- epathDataBlockIds.setSize(n_db);
- for (U32 i = 0; i < n_db; i++)
- stream->read(&epathDataBlockIds[i]);
- stream->read(&path_origin_type);
- ground_conform = stream->readFlag();
- ground_conform_terrain = stream->readFlag();
- ground_conform_interiors = stream->readFlag();
- stream->read(&ground_conform_height);
- }
- bool afxParticleEmitterPathData::onAdd()
- {
- if( Parent::onAdd() == false )
- return false;
- // path
- if (epaths_string != ST_NULLSTRING && epaths_string[0] == '\0')
- {
- Con::warnf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) empty paths string.", getName());
- return false;
- }
- if (epaths_string != ST_NULLSTRING && dStrlen(epaths_string) > 255)
- {
- Con::errorf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) paths string too long [> 255 chars].", getName());
- return false;
- }
- if (epaths_string != ST_NULLSTRING)
- {
- Vector<char*> dataBlocks(__FILE__, __LINE__);
- char* tokCopy = new char[dStrlen(epaths_string) + 1];
- dStrcpy(tokCopy, epaths_string, dStrlen(epaths_string) + 1);
- char* currTok = dStrtok(tokCopy, " \t");
- while (currTok != NULL)
- {
- dataBlocks.push_back(currTok);
- currTok = dStrtok(NULL, " \t");
- }
- if (dataBlocks.size() == 0)
- {
- Con::warnf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) invalid paths string. No datablocks found", getName());
- delete [] tokCopy;
- return false;
- }
- epathDataBlocks.clear();
- epathDataBlockIds.clear();
- for (U32 i = 0; i < dataBlocks.size(); i++)
- {
- afxPathData* pData = NULL;
- if (Sim::findObject(dataBlocks[i], pData) == false)
- {
- Con::warnf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) unable to find path datablock: %s", getName(), dataBlocks[i]);
- }
- else
- {
- epathDataBlocks.push_back(pData);
- epathDataBlockIds.push_back(pData->getId());
- }
- }
- delete [] tokCopy;
- if (epathDataBlocks.size() == 0)
- {
- Con::warnf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) unable to find any path datablocks", getName());
- return false;
- }
- }
- return true;
- }
- bool afxParticleEmitterPathData::preload(bool server, String &errorStr)
- {
- if (Parent::preload(server, errorStr) == false)
- return false;
- epathDataBlocks.clear();
- for (U32 i = 0; i < epathDataBlockIds.size(); i++)
- {
- afxPathData* pData = NULL;
- if (Sim::findObject(epathDataBlockIds[i], pData) == false)
- {
- Con::warnf(ConsoleLogEntry::General,
- "afxParticleEmitterPathData(%s) unable to find path datablock: %d",
- getName(), epathDataBlockIds[i]);
- }
- else
- epathDataBlocks.push_back(pData);
- }
- parts_per_eject = epathDataBlocks.size();
- return true;
- }
- void afxParticleEmitterPathData::onPerformSubstitutions()
- {
- Parent::onPerformSubstitutions();
- if (epaths_string != ST_NULLSTRING && epaths_string[0] == '\0')
- {
- Con::warnf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) empty paths string.", getName());
- return;// false;
- }
- if (epaths_string != ST_NULLSTRING && dStrlen(epaths_string) > 255)
- {
- Con::errorf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) paths string too long [> 255 chars].", getName());
- return;// false;
- }
- if (epaths_string != ST_NULLSTRING)
- {
- Vector<char*> dataBlocks(__FILE__, __LINE__);
- char* tokCopy = new char[dStrlen(epaths_string) + 1];
- dStrcpy(tokCopy, epaths_string, dStrlen(epaths_string) + 1);
- char* currTok = dStrtok(tokCopy, " \t");
- while (currTok != NULL)
- {
- dataBlocks.push_back(currTok);
- currTok = dStrtok(NULL, " \t");
- }
- if (dataBlocks.size() == 0)
- {
- Con::warnf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) invalid paths string. No datablocks found", getName());
- delete [] tokCopy;
- return;// false;
- }
- epathDataBlocks.clear();
- epathDataBlockIds.clear();
- for (U32 i = 0; i < dataBlocks.size(); i++)
- {
- afxPathData* pData = NULL;
- if (Sim::findObject(dataBlocks[i], pData) == false)
- {
- Con::warnf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) unable to find path datablock: %s", getName(), dataBlocks[i]);
- }
- else
- {
- epathDataBlocks.push_back(pData);
- epathDataBlockIds.push_back(pData->getId());
- }
- }
- delete [] tokCopy;
- if (epathDataBlocks.size() == 0)
- {
- Con::warnf(ConsoleLogEntry::General, "afxParticleEmitterPathData(%s) unable to find any path datablocks", getName());
- return;// false;
- }
- }
- /*epathDataBlocks.clear();
- for (U32 i = 0; i < epathDataBlockIds.size(); i++)
- {
- afxPathData* pData = NULL;
- if (Sim::findObject(epathDataBlockIds[i], pData) == false)
- {
- Con::warnf(ConsoleLogEntry::General,
- "afxParticleEmitterPathData(%s) unable to find path datablock: %d",
- getName(), epathDataBlockIds[i]);
- }
- else
- epathDataBlocks.push_back(pData);
- }
- */
- parts_per_eject = epathDataBlocks.size();
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // DISC
- IMPLEMENT_CO_DATABLOCK_V1(afxParticleEmitterDiscData);
- ConsoleDocClass( afxParticleEmitterDiscData,
- "@brief An AFX customized particle emitter that emits particles within a disc shape.\n\n"
- "An AFX customized particle emitter that emits particles within a disc shape."
- "\n\n"
- "@ingroup afxEffects\n"
- "@ingroup AFX\n"
- "@ingroup Datablocks\n"
- );
- afxParticleEmitterDiscData::afxParticleEmitterDiscData()
- {
- pe_radius_min = 0.0f;
- pe_radius_max = 1.0f;
- }
- afxParticleEmitterDiscData::afxParticleEmitterDiscData(const afxParticleEmitterDiscData& other, bool temp_clone) : afxParticleEmitterData(other, temp_clone)
- {
- pe_radius_min = other.pe_radius_min;
- pe_radius_max = other.pe_radius_max;
- }
- void afxParticleEmitterDiscData::initPersistFields()
- {
- addField("radiusMin", TypeF32, Offset(pe_radius_min, afxParticleEmitterDiscData),
- "...");
- addField("radiusMax", TypeF32, Offset(pe_radius_max, afxParticleEmitterDiscData),
- "...");
- Parent::initPersistFields();
- }
- void afxParticleEmitterDiscData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- stream->writeInt((S32)(pe_radius_min * 100), 16);
- stream->writeInt((S32)(pe_radius_max * 100), 16);
- }
- void afxParticleEmitterDiscData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- pe_radius_min = stream->readInt(16) / 100.0f;
- pe_radius_max = stream->readInt(16) / 100.0f;
- }
- bool afxParticleEmitterDiscData::onAdd()
- {
- if( Parent::onAdd() == false )
- return false;
- return true;
- }
- bool afxParticleEmitterDiscData::preload(bool server, String &errorStr)
- {
- if (Parent::preload(server, errorStr) == false)
- return false;
- return true;
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- afxParticleEmitter::afxParticleEmitter()
- {
- pe_vector.set(0,0,1);
- pe_vector_norm.set(0,0,1);
- tpaths.clear();
- tpath_mults.clear();
- n_tpath_points = 0;
- tpath_points = NULL;
- afx_owner = 0;
- }
- afxParticleEmitter::~afxParticleEmitter()
- {
- }
- bool afxParticleEmitter::onAdd()
- {
- if( !Parent::onAdd() )
- return false;
- if (dynamic_cast<afxParticleEmitterData*>(mDataBlock))
- init_paths();
- return true;
- }
- void afxParticleEmitter::onRemove()
- {
- if (dynamic_cast<afxParticleEmitterData*>(mDataBlock))
- cleanup_paths();
- Parent::onRemove();
- }
- void afxParticleEmitter::init_paths()
- {
- if (!mDataBlock)
- {
- n_tpath_points = 0;
- tpath_points = NULL;
- return;
- }
- if (mDataBlock->tPathDataBlocks.size() < 1)
- {
- n_tpath_points = 0;
- tpath_points = NULL;
- }
- else
- {
- n_tpath_points = mDataBlock->tPathDataBlocks.size();
- tpath_points = new Point3F*[n_tpath_points];
-
- for (U32 i=0; i < n_tpath_points; i++)
- {
- afxPathData* pd = mDataBlock->tPathDataBlocks[i];
- if (!pd)
- continue;
- if (pd->getSubstitutionCount() > 0 && afx_owner)
- {
- afxPathData* orig_db = pd;
- pd = new afxPathData(*orig_db, true);
- orig_db->performSubstitutions(pd, afx_owner);
- }
- if (pd->num_points > 0)
- {
- afxPath3D* path = new afxPath3D();
- if (pd->times)
- path->buildPath( pd->num_points, pd->points, pd->times, pd->delay, 1.0f );
- else if (pd->lifetime == 0)
- path->buildPath( pd->num_points, pd->points, pd->delay, 1.0f );
- else
- path->buildPath( pd->num_points, pd->points, pd->delay, pd->delay+pd->lifetime );
- path->setLoopType( pd->loop_type );
- tpaths.push_back(path);
- tpath_mults.push_back( pd->mult );
- tpath_points[i] = new Point3F[pd->num_points];
- for (U32 j=0; j<pd->num_points; j++)
- tpath_points[i][j] = pd->points[j];
- }
- else
- {
- Con::warnf("afxParticleEmitter::init_paths() -- pathsTransform datablock (%d) has no points.", i);
- }
- if (pd->isTempClone())
- delete pd;
- }
- }
- }
- void afxParticleEmitter::cleanup_paths()
- {
- if (n_tpath_points < 1)
- return;
- for (U32 i=0; i < tpaths.size(); i++)
- {
- if (tpaths[i])
- delete tpaths[i];
- }
- tpaths.clear();
-
- if (tpath_points)
- {
- if (mDataBlock)
- {
- for (U32 i=0; i < n_tpath_points; i++)
- {
- if (tpath_points[i])
- delete [] tpath_points[i];
- }
- }
-
- delete [] tpath_points;
- tpath_points = 0;
- }
- }
- void afxParticleEmitter::sub_particleUpdate(Particle* part)
- {
- if (tpaths.size() < 1)
- return;
- F32 t = ((F32)part->currentAge)/((F32)part->totalLifetime);
- for (U32 i=0; i < tpaths.size(); i++)
- {
- F32 t_last = part->t_last;
- Point3F path_delta = (t_last <= 0.0f) ? tpaths[i]->evaluateAtTime(t) : tpaths[i]->evaluateAtTime(t_last, t);
- if (mDataBlock->tPathDataBlocks[i]->concentric)
- {
- // scale radial vector by x-component of path
- part->pos_local += part->radial_v*path_delta.x;
- // scale axis vector by z-component of path
- part->pos_local += pe_vector_norm*path_delta.z;
- // y-component is ignored
- }
- else
- {
- part->pos_local += path_delta;
- }
- }
- part->t_last = t;
- }
- void afxParticleEmitter::preCompute(const MatrixF& mat)
- {
- // Put vector into the space of the input matrix
- pe_vector = mDataBlock->pe_vector;
- if (!mDataBlock->pe_vector_is_world)
- mat.mulV(pe_vector);
- pe_vector_norm = pe_vector;
- pe_vector_norm.normalize();
- // Transform Paths: rebuild with current matrix
- for( U32 i=0; i < tpaths.size(); i++ )
- {
- for( U32 j=0; j < tpaths[i]->getNumPoints(); j++ )
- {
- Point3F p = tpath_points[i][j];
- mat.mulV(p);
- tpaths[i]->setPointPosition(j, p);
- }
- tpaths[i]->reBuildPath();
- }
- sub_preCompute(mat);
- }
- void afxParticleEmitter::afx_emitParticles(const Point3F& point, const bool useLastPosition, const Point3F& velocity, const U32 numMilliseconds)
- {
- if (mDead) return;
- // lifetime over - no more particles
- if (mLifetimeMS > 0 && mElapsedTimeMS > mLifetimeMS)
- return;
- Point3F realStart;
- if (useLastPosition && mHasLastPosition)
- realStart = mLastPosition;
- else
- realStart = point;
- afx_emitParticles(realStart, point, velocity, numMilliseconds);
- }
- void afxParticleEmitter::afx_emitParticles(const Point3F& start, const Point3F& end, const Point3F& velocity, const U32 numMilliseconds)
- {
- if (mDead) return;
- // lifetime over - no more particles
- if (mLifetimeMS > 0 && mElapsedTimeMS > mLifetimeMS)
- return;
- U32 currTime = 0;
- bool particlesAdded = false;
- if (mNextParticleTime != 0)
- {
- // Need to handle next particle
- //
- if (mNextParticleTime > numMilliseconds)
- {
- // Defer to next update
- // (Note that this introduces a potential spatial irregularity if the owning
- // object is accelerating, and updating at a low frequency)
- //
- mNextParticleTime -= numMilliseconds;
- mInternalClock += numMilliseconds;
- mLastPosition = end;
- mHasLastPosition = true;
- return;
- }
- else
- {
- currTime += mNextParticleTime;
- mInternalClock += mNextParticleTime;
- // Emit particle at curr time
- // Create particle at the correct position
- Point3F pos;
- pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
- for (S32 p = 0; p < mDataBlock->parts_per_eject; p++)
- {
- sub_addParticle(pos, velocity, numMilliseconds-currTime, p);
- particlesAdded = true;
- }
- mNextParticleTime = 0;
- }
- }
- while (currTime < numMilliseconds)
- {
- S32 nextTime = mDataBlock->ejectionPeriodMS;
- if (mDataBlock->periodVarianceMS != 0)
- {
- nextTime += S32(gRandGen.randI() % (2 * mDataBlock->periodVarianceMS + 1)) -
- S32(mDataBlock->periodVarianceMS);
- }
- AssertFatal(nextTime > 0, "Error, next particle ejection time must always be greater than 0");
- if (currTime + nextTime > numMilliseconds)
- {
- mNextParticleTime = (currTime + nextTime) - numMilliseconds;
- mInternalClock += numMilliseconds - currTime;
- AssertFatal(mNextParticleTime > 0, "Error, should not have deferred this particle!");
- break;
- }
- currTime += nextTime;
- mInternalClock += nextTime;
- // Create particle at the correct position
- Point3F pos;
- pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
- U32 advanceMS = numMilliseconds - currTime;
- if (mDataBlock->overrideAdvance == false && advanceMS != 0)
- {
- for (S32 p = 0; p < mDataBlock->parts_per_eject; p++)
- {
- sub_addParticle(pos, velocity, numMilliseconds-currTime, p);
- particlesAdded = true;
- Particle* last_part = part_list_head.next;
- if (last_part)
- {
- if (advanceMS > last_part->totalLifetime)
- {
- part_list_head.next = last_part->next;
- n_parts--;
- last_part->next = part_freelist;
- part_freelist = last_part;
- }
- else
- {
- F32 t = F32(advanceMS) / 1000.0;
- Point3F a = last_part->acc;
- a -= last_part->vel*last_part->dataBlock->dragCoefficient;
- a -= mWindVelocity*last_part->dataBlock->windCoefficient;
- //a += Point3F(0, 0, -9.81) * last_part->dataBlock->gravityCoefficient;
- a.z += -9.81f*last_part->dataBlock->gravityCoefficient; // as long as gravity is a constant, this is faster
- last_part->vel += a * t;
- last_part->pos_local += last_part->vel * t;
- // allow subclasses to adjust the particle params here
- sub_particleUpdate(last_part);
- if (last_part->dataBlock->constrain_pos)
- last_part->pos = last_part->pos_local + this->pos_pe;
- else
- last_part->pos = last_part->pos_local;
- updateKeyData(last_part);
- }
- }
- }
- }
- else
- {
- for (S32 p = 0; p < mDataBlock->parts_per_eject; p++)
- {
- sub_addParticle(pos, velocity, numMilliseconds-currTime, p);
- particlesAdded = true;
- }
- }
- }
- if( particlesAdded == true )
- updateBBox();
- if( n_parts > 0 && mSceneManager == NULL )
- {
- gClientSceneGraph->addObjectToScene(this);
- ClientProcessList::get()->addObject(this);
- }
- mLastPosition = end;
- mHasLastPosition = true;
- }
- Particle* afxParticleEmitter::alloc_particle()
- {
- n_parts++;
- // this should happen rarely
- if (n_parts > n_part_capacity)
- {
- Particle* store_block = new Particle[16];
- part_store.push_back(store_block);
- n_part_capacity += 16;
- for (S32 i = 0; i < 16; i++)
- {
- store_block[i].next = part_freelist;
- part_freelist = &store_block[i];
- }
- mDataBlock->allocPrimBuffer(n_part_capacity);
- }
- Particle* pNew = part_freelist;
- part_freelist = pNew->next;
- pNew->next = part_list_head.next;
- part_list_head.next = pNew;
- return pNew;
- }
- ParticleData* afxParticleEmitter::pick_particle_type()
- {
- U32 dBlockIndex = (U32)(mCeil(gRandGen.randF() * F32(mDataBlock->particleDataBlocks.size())) - 1);
- return mDataBlock->particleDataBlocks[dBlockIndex];
- }
- bool afxParticleEmitter::onNewDataBlock(GameBaseData* dptr, bool reload)
- {
- mDataBlock = dynamic_cast<afxParticleEmitterData*>(dptr);
- if( !mDataBlock || !Parent::onNewDataBlock(dptr, reload) )
- return false;
- if (mDataBlock->isTempClone())
- return true;
- scriptOnNewDataBlock();
- return true;
- }
- void afxParticleEmitter::emitParticlesExt(const MatrixF& xfm, const Point3F& point, const Point3F& velocity, const U32 numMilliseconds)
- {
- if (mDataBlock->use_emitter_xfm)
- {
- Point3F zero_point(0.0f, 0.0f, 0.0f);
- pos_pe = zero_point;
- setTransform(xfm);
- preCompute(xfm);
- afx_emitParticles(zero_point, true, velocity, numMilliseconds);
- }
- else
- {
- pos_pe = point;
- preCompute(xfm);
- afx_emitParticles(point, true, velocity, numMilliseconds);
- }
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // VECTOR
- afxParticleEmitterVector::afxParticleEmitterVector()
- {
- }
- afxParticleEmitterVector::~afxParticleEmitterVector()
- {
- }
- bool afxParticleEmitterVector::onNewDataBlock(GameBaseData* dptr, bool reload)
- {
- mDataBlock = dynamic_cast<afxParticleEmitterVectorData*>(dptr);
- if( !mDataBlock || !Parent::onNewDataBlock(dptr, reload) )
- return false;
- if (mDataBlock->isTempClone())
- return true;
- scriptOnNewDataBlock();
- return true;
- }
- void afxParticleEmitterVector::sub_addParticle(const Point3F& pos, const Point3F& vel, const U32 age_offset, S32 part_idx)
- {
- Particle* pNew = alloc_particle();
- ParticleData* part_db = pick_particle_type();
- Point3F pos_start = pos;
- if (part_db->constrain_pos)
- pos_start.set(0,0,0);
- F32 initialVel = mDataBlock->ejectionVelocity;
- initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
- if(mDataBlock->fade_velocity)
- initialVel *= fade_amt;
- F32 ejection_offset = mDataBlock->ejectionOffset;
- if(mDataBlock->fade_offset)
- ejection_offset *= fade_amt;
- pNew->pos = pos_start + (pe_vector_norm * ejection_offset);
- pNew->pos_local = pNew->pos;
- pNew->vel = pe_vector_norm * initialVel;
- if (mDataBlock->orientParticles)
- pNew->orientDir = pe_vector_norm;
- else
- // note -- for non-oriented particles, we use orientDir.x to store the billboard start angle.
- pNew->orientDir.x = mDegToRad(part_db->start_angle + part_db->angle_variance*2.0f*gRandGen.randF() - part_db->angle_variance);
- pNew->acc.set(0, 0, 0);
- pNew->currentAge = age_offset;
- pNew->t_last = 0.0f;
- pNew->radial_v.set(0.0f, 0.0f, 0.0f);
- part_db->initializeParticle(pNew, vel);
- updateKeyData( pNew );
- }
- void afxParticleEmitterVector::sub_preCompute(const MatrixF& mat)
- {
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // CONE
- afxParticleEmitterCone::afxParticleEmitterCone()
- {
- cone_v.set(0,0,1);
- cone_s0.set(0,0,1);
- cone_s1.set(0,0,1);
- }
- afxParticleEmitterCone::~afxParticleEmitterCone()
- {
- }
- bool afxParticleEmitterCone::onNewDataBlock(GameBaseData* dptr, bool reload)
- {
- mDataBlock = dynamic_cast<afxParticleEmitterConeData*>(dptr);
- if( !mDataBlock || !Parent::onNewDataBlock(dptr, reload) )
- return false;
- if (mDataBlock->isTempClone())
- return true;
- scriptOnNewDataBlock();
- return true;
- }
- void afxParticleEmitterCone::sub_addParticle(const Point3F& pos, const Point3F& vel, const U32 age_offset, S32 part_idx)
- {
- Particle* pNew = alloc_particle();
- ParticleData* part_db = pick_particle_type();
- Point3F pos_start = pos;
- if (part_db->constrain_pos)
- pos_start.set(0,0,0);
- F32 initialVel = mDataBlock->ejectionVelocity;
- initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
- if(mDataBlock->fade_velocity)
- initialVel *= fade_amt;
- // Randomly choose a vector between cone_s0 and cone_s1 and normalize:
- Point3F vec;
- F32 t = mRandF(0.0f, 1.0f);
- vec.interpolate(cone_s0, cone_s1, t);
- vec.normalize();
- // Randomly rotate about cone_v
- F32 theta = mRandF(0.0f, M_2PI_F);
- AngAxisF thetaRot(cone_v, theta);
- MatrixF temp(true);
- thetaRot.setMatrix(&temp);
- temp.mulP(vec);
- F32 ejection_offset = mDataBlock->ejectionOffset;
- if(mDataBlock->fade_offset)
- ejection_offset *= fade_amt;
- pNew->pos = pos_start + (vec * ejection_offset);
- pNew->pos_local = pNew->pos;
- pNew->vel = mDataBlock->ejectionInvert ? vec * -initialVel : vec * initialVel;
- if (mDataBlock->orientParticles)
- pNew->orientDir = vec;
- else
- // note -- for non-oriented particles, we use orientDir.x to store the billboard start angle.
- pNew->orientDir.x = mDegToRad(part_db->start_angle + part_db->angle_variance*2.0f*gRandGen.randF() - part_db->angle_variance);
- pNew->acc.set(0, 0, 0);
- pNew->currentAge = age_offset;
- pNew->t_last = 0.0f;
- pNew->radial_v.set(0.0f, 0.0f, 0.0f);
- part_db->initializeParticle(pNew, vel);
- updateKeyData( pNew );
- }
- void afxParticleEmitterCone::sub_preCompute(const MatrixF& mat)
- {
- // Find vectors on the XZ plane corresponding to the inner and outer spread angles:
- // (tan is infinite at PI/4 or 90 degrees)
- cone_v.set( 0.0f, 0.0f, 1.0f );
- cone_s0.x = mTan( mDegToRad( ((afxParticleEmitterConeData*)mDataBlock)->spread_min / 2.0f ));
- cone_s0.y = 0.0f;
- cone_s0.z = 1.0f;
- cone_s1.x = mTan( mDegToRad(((afxParticleEmitterConeData*)mDataBlock)->spread_max / 2.0f ));
- cone_s1.y = 0.0f;
- cone_s1.z = 1.0f;
- Point3F axis;
- F32 theta = mAcos( mDot(cone_v, pe_vector_norm) );
- if( M_PI_F-theta < POINT_EPSILON )
- {
- cone_v.neg();
- cone_s0.neg();
- cone_s1.neg();
- }
- else if( theta > POINT_EPSILON )
- {
- mCross(pe_vector_norm, cone_v, &axis);
- axis.normalize();
- AngAxisF thetaRot(axis, theta);
- MatrixF temp(true);
- thetaRot.setMatrix(&temp);
- temp.mulP(cone_v);
- temp.mulP(cone_s0);
- temp.mulP(cone_s1);
- }
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // PATH
- afxParticleEmitterPath::afxParticleEmitterPath()
- {
- epaths.clear();
- epath_mults.clear();
- n_epath_points = 0;
- epath_points = NULL;
- }
- afxParticleEmitterPath::~afxParticleEmitterPath()
- {
- }
- bool afxParticleEmitterPath::onNewDataBlock(GameBaseData* dptr, bool reload)
- {
- mDataBlock = dynamic_cast<afxParticleEmitterPathData*>(dptr);
- if( !mDataBlock || !Parent::onNewDataBlock(dptr, reload) )
- return false;
- if (mDataBlock->isTempClone())
- return true;
- scriptOnNewDataBlock();
- return true;
- }
- bool afxParticleEmitterPath::onAdd()
- {
- if( !Parent::onAdd() )
- return false;
- if (dynamic_cast<afxParticleEmitterPathData*>(mDataBlock))
- init_paths();
- return true;
- }
- void afxParticleEmitterPath::onRemove()
- {
- if (dynamic_cast<afxParticleEmitterPathData*>(mDataBlock))
- cleanup_paths();
- Parent::onRemove();
- }
- void afxParticleEmitterPath::init_paths()
- {
- if (!mDataBlock || ((afxParticleEmitterPathData*)mDataBlock)->epathDataBlocks.size() < 1)
- {
- n_epath_points = 0;
- epath_points = NULL;
- return;
- }
- n_epath_points = ((afxParticleEmitterPathData*)mDataBlock)->epathDataBlocks.size();
- epath_points = new Point3F*[n_epath_points];
- dMemset(epath_points, 0, n_epath_points*sizeof(Point3F*));
-
- for (U32 i=0; i < n_epath_points; i++)
- {
- afxPathData* pd = ((afxParticleEmitterPathData*)mDataBlock)->epathDataBlocks[i];
- if (!pd)
- continue;
- if (pd->getSubstitutionCount() > 0 && afx_owner)
- {
- afxPathData* orig_db = pd;
- pd = new afxPathData(*orig_db, true);
- orig_db->performSubstitutions(pd, afx_owner);
- }
-
- if (pd->num_points > 0)
- {
- afxPath3D* path = new afxPath3D();
- if (pd->times)
- path->buildPath( pd->num_points, pd->points, pd->times, 0.0f, 1.0f );
- else
- path->buildPath( pd->num_points, pd->points, 0.0f, 1.0f );
- epaths.push_back(path);
- epath_mults.push_back( pd->mult );
- epath_points[i] = new Point3F[pd->num_points];
- for (U32 j=0; j<pd->num_points; j++)
- epath_points[i][j] = pd->points[j];
- }
- else
- {
- Con::warnf("afxParticleEmitterPath::init_paths() -- paths datablock (%d) has no points.", i);
- }
- if (pd->isTempClone())
- delete pd;
- }
- }
- void afxParticleEmitterPath::cleanup_paths()
- {
- if (n_epath_points < 1)
- return;
- for (U32 i=0; i < epaths.size(); i++)
- {
- if (epaths[i])
- delete epaths[i];
- }
- epaths.clear();
-
- if (epath_points)
- {
- if (mDataBlock)
- {
- for (U32 i=0; i < n_epath_points; i++)
- {
- if (epath_points[i])
- delete [] epath_points[i];
- }
- }
-
- delete [] epath_points;
- epath_points = 0;
- }
- }
- void afxParticleEmitterPath::sub_addParticle(const Point3F& pos, const Point3F& vel, const U32 age_offset, S32 part_idx)
- {
- if (part_idx >= epaths.size() || !epaths[part_idx])
- return;
- Particle* pNew = alloc_particle();
- ParticleData* part_db = pick_particle_type();
- Point3F pos_start = pos;
- if (part_db->constrain_pos)
- pos_start.set(0,0,0);
- F32 initialVel = mDataBlock->ejectionVelocity;
- initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
- if(mDataBlock->fade_velocity)
- initialVel *= fade_amt;
- // Randomly choose a curve parameter between [0.0,1.0] and evaluate the curve there
- F32 param = mRandF(0.0f, 1.0f);
- Point3F curve_pos = epaths[part_idx]->evaluateAtTime(param);
- Point3F vec;
- switch (((afxParticleEmitterPathData*)mDataBlock)->path_origin_type)
- {
- case afxParticleEmitterPathData::PATHEMIT_ORIGIN :
- vec = curve_pos;
- vec.normalize();
- break;
- case afxParticleEmitterPathData::PATHEMIT_POINT :
- vec = curve_pos-pe_vector;
- vec.normalize();
- break;
- case afxParticleEmitterPathData::PATHEMIT_VECTOR :
- vec = pe_vector_norm;
- break;
- case afxParticleEmitterPathData::PATHEMIT_TANGENT :
- vec = epaths[part_idx]->evaluateTangentAtTime(param);
- vec.normalize();
- break;
- }
- F32 ejection_offset = mDataBlock->ejectionOffset;
- if(mDataBlock->fade_offset)
- ejection_offset *= fade_amt;
- pNew->pos = pos_start + curve_pos + (vec * ejection_offset);
- pNew->pos_local = pNew->pos;
- pNew->vel = mDataBlock->ejectionInvert ? vec * -initialVel : vec * initialVel;
- if (mDataBlock->orientParticles)
- pNew->orientDir = vec;
- else
- // note -- for non-oriented particles, we use orientDir.x to store the billboard start angle.
- pNew->orientDir.x = mDegToRad(part_db->start_angle + part_db->angle_variance*2.0f*gRandGen.randF() - part_db->angle_variance);
- pNew->acc.set(0, 0, 0);
- pNew->currentAge = age_offset;
- pNew->t_last = 0.0f;
- pNew->radial_v.set(0.0f, 0.0f, 0.0f);
- part_db->initializeParticle(pNew, vel);
- updateKeyData( pNew );
- }
- void afxParticleEmitterPath::sub_preCompute(const MatrixF& mat)
- {
- for( U32 i=0; i < epaths.size(); i++ )
- {
- for( U32 j=0; j < epaths[i]->getNumPoints(); j++ )
- {
- Point3F p = epath_points[i][j];
- mat.mulV(p);
- p *= epath_mults[i];
- if(mDataBlock->ground_conform) {
- groundConformPoint(p, mat);
- }
- epaths[i]->setPointPosition(j, p);
- }
- epaths[i]->reBuildPath();
- }
- }
- void afxParticleEmitterPath::groundConformPoint(Point3F& point, const MatrixF& mat)
- {
- point += mat.getPosition();
- RayInfo rInfo;
- bool hit = false;
- if (mDataBlock->ground_conform_interiors)
- {
- U32 mask = InteriorLikeObjectType;
- if (mDataBlock->ground_conform_terrain)
- {
- mask |= TerrainObjectType | TerrainLikeObjectType;
- }
-
- Point3F above_pos(point); above_pos.z += 0.1f;
- Point3F below_pos(point); below_pos.z -= 10000;
- hit = gClientContainer.castRay(above_pos, below_pos, mask, &rInfo);
- if (!hit)
- {
- above_pos.z = point.z + 10000;
- below_pos.z = point.z - 0.1f;
- hit = gClientContainer.castRay(below_pos, above_pos, mask, &rInfo);
- }
- }
- else if (mDataBlock->ground_conform_terrain)
- {
- U32 mask = TerrainObjectType | TerrainLikeObjectType;
- Point3F above_pos(point); above_pos.z += 10000;
- Point3F below_pos(point); below_pos.z -= 10000;
- hit = gClientContainer.castRay(above_pos, below_pos, mask, &rInfo);
- }
- if (hit)
- {
- F32 terrain_z = rInfo.point.z;
- F32 new_z = terrain_z + mDataBlock->ground_conform_height;
- point.z = new_z;
- }
- point -= mat.getPosition();
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // DISC
- afxParticleEmitterDisc::afxParticleEmitterDisc()
- {
- disc_v.set(0,0,1);
- disc_r.set(1,0,0);
- }
- afxParticleEmitterDisc::~afxParticleEmitterDisc()
- {
- }
- bool afxParticleEmitterDisc::onNewDataBlock(GameBaseData* dptr, bool reload)
- {
- mDataBlock = dynamic_cast<afxParticleEmitterDiscData*>(dptr);
- if( !mDataBlock || !Parent::onNewDataBlock(dptr, reload) )
- return false;
- if (mDataBlock->isTempClone())
- return true;
- return true;
- }
- void afxParticleEmitterDisc::sub_addParticle(const Point3F& pos, const Point3F& vel, const U32 age_offset, S32 part_idx)
- {
- Particle* pNew = alloc_particle();
- ParticleData* part_db = pick_particle_type();
- Point3F pos_start = pos;
- if (part_db->constrain_pos)
- pos_start.set(0,0,0);
- F32 initialVel = mDataBlock->ejectionVelocity;
- initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
- if(mDataBlock->fade_velocity)
- initialVel *= fade_amt;
- // Randomly choose a radius vector
- Point3F r( disc_r );
- F32 radius = mRandF(((afxParticleEmitterDiscData*)mDataBlock)->pe_radius_min, ((afxParticleEmitterDiscData*)mDataBlock)->pe_radius_max);
- r *= radius;
- // Randomly rotate r about disc_v
- F32 theta = mRandF(0.0f, M_2PI_F);
- AngAxisF thetaRot(disc_v, theta);
- MatrixF temp(true);
- thetaRot.setMatrix(&temp);
- temp.mulP(r);
- F32 ejection_offset = mDataBlock->ejectionOffset;
- if(mDataBlock->fade_offset)
- ejection_offset *= fade_amt;
- pNew->pos = pos_start + r + (disc_v * ejection_offset);
- pNew->pos_local = pNew->pos;
- pNew->vel = (mDataBlock->ejectionInvert) ? (disc_v * -initialVel) : (disc_v * initialVel);
- if (mDataBlock->orientParticles)
- pNew->orientDir = disc_v;
- else
- // note -- for non-oriented particles, we use orientDir.x to store the billboard start angle.
- pNew->orientDir.x = mDegToRad(part_db->start_angle + part_db->angle_variance*2.0f*gRandGen.randF() - part_db->angle_variance);
- pNew->acc.set(0, 0, 0);
- pNew->currentAge = age_offset;
- pNew->t_last = 0.0f;
- pNew->radial_v = r;
- part_db->initializeParticle(pNew, vel);
- updateKeyData( pNew );
- }
- void afxParticleEmitterDisc::sub_preCompute(const MatrixF& mat)
- {
- disc_v.set(0.0f, 0.0f, 1.0f);
- disc_r.set(1.0f, 0.0f, 0.0f);
- Point3F axis;
- F32 theta = mAcos( mDot(disc_v, pe_vector_norm) );
- if( M_PI_F-theta < POINT_EPSILON )
- {
- disc_v.neg();
- }
- else if( theta > POINT_EPSILON )
- {
- mCross(pe_vector_norm, disc_v, &axis);
- axis.normalize();
- AngAxisF thetaRot(axis, theta);
- MatrixF temp(true);
- thetaRot.setMatrix(&temp);
- temp.mulP(disc_v);
- temp.mulP(disc_r);
- }
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|