12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625 |
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // 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__);
- dsize_t tokCopyLen = dStrlen(tpaths_string) + 1;
- char* tokCopy = new char[tokCopyLen];
- dStrcpy(tokCopy, tpaths_string, tokCopyLen);
-
- 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__);
- dsize_t tokCopyLen = dStrlen(epaths_string) + 1;
- char* tokCopy = new char[tokCopyLen];
- dStrcpy(tokCopy, epaths_string, tokCopyLen);
- 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__);
- dsize_t tokCopyLen = dStrlen(epaths_string) + 1;
- char* tokCopy = new char[tokCopyLen];
- dStrcpy(tokCopy, epaths_string, tokCopyLen);
- 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()
- {
- mDataBlock = NULL;
- 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()
- {
- mDataBlock = NULL;
- }
- 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()
- {
- mDataBlock = NULL;
- 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()
- {
- mDataBlock = NULL;
- 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()
- {
- mDataBlock = NULL;
- 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);
- }
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|