| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // ParticleSys.cpp ////////////////////////////////////////////////////////////////////////////////
- // Particle System implementation
- // Author: Michael S. Booth, November 2001
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #define DEFINE_PARTICLE_SYSTEM_NAMES
- #include "Common/GameState.h"
- #include "Common/INI.h"
- #include "Common/PerfTimer.h"
- #include "Common/ThingFactory.h"
- #include "Common/GameLOD.h"
- #include "Common/Xfer.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/DebugDisplay.h"
- #include "GameClient/Display.h"
- #include "GameClient/GameClient.h"
- #include "GameClient/InGameUI.h"
- #include "GameClient/ParticleSys.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/TerrainLogic.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //------------------------------------------------------------------------------ Performance Timers
- //#include "Common/PerfMetrics.h"
- //#include "Common/PerfTimer.h"
- //static PerfTimer s_particleSys("ParticleSys::update", false, PERFMETRICS_LOGIC_STARTFRAME, PERFMETRICS_LOGIC_STOPFRAME);
- //-------------------------------------------------------------------------------------------------
- // the singleton
- ParticleSystemManager *TheParticleSystemManager = NULL;
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ParticleInfo::ParticleInfo( void )
- {
- //Added By Sadullah Nader
- //Initializations inserted
- m_angleX = m_angleY = m_angleZ = 0.0f;
- m_angularDamping = 0.0f;
- m_angularRateX = m_angularRateY = m_angularRateZ = 0.0f;
- m_colorScale =0.0f;
- m_size = 0.0f;
- m_sizeRate = 0.0f;
- m_sizeRateDamping = 0.0f;
- m_velDamping = 0.0f;
- m_windRandomness = 0.0f;
- m_emitterPos.zero();
- m_pos.zero();
- m_vel.zero();
- m_lifetime = 0;
- m_particleUpTowardsEmitter = FALSE;
-
- //
- } // end ParticleInfo
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void ParticleInfo::crc( Xfer *xfer )
- {
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void ParticleInfo::xfer( Xfer *xfer )
- {
- Int i;
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // velocity
- xfer->xferCoord3D( &m_vel );
- // position
- xfer->xferCoord3D( &m_pos );
- // emitter position
- xfer->xferCoord3D( &m_emitterPos );
- // velocity damping
- xfer->xferReal( &m_velDamping );
- // angle
- xfer->xferReal( &m_angleX );
- xfer->xferReal( &m_angleY );
- xfer->xferReal( &m_angleZ );
- // angular rate
- xfer->xferReal( &m_angularRateX );
- xfer->xferReal( &m_angularRateY );
- xfer->xferReal( &m_angularRateZ );
- // lifetime
- xfer->xferUnsignedInt( &m_lifetime );
- // size
- xfer->xferReal( &m_size );
- // size rate
- xfer->xferReal( &m_sizeRate );
- // size rate damping
- xfer->xferReal( &m_sizeRateDamping );
- // alpha keys
- for( i = 0; i < MAX_KEYFRAMES; ++i )
- {
- xfer->xferReal( &m_alphaKey[ i ].value );
- xfer->xferUnsignedInt( &m_alphaKey[ i ].frame );
- } // end for, i
- // color keys
- for( i = 0; i < MAX_KEYFRAMES; ++i )
- {
- xfer->xferRGBColor( &m_colorKey[ i ].color );
- xfer->xferUnsignedInt( &m_colorKey[ i ].frame );
- } // end for, i
- // color scale
- xfer->xferReal( &m_colorScale );
- // particle up towards emitter
- xfer->xferBool( &m_particleUpTowardsEmitter );
- // wind randomness
- xfer->xferReal( &m_windRandomness );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void ParticleInfo::loadPostProcess( void )
- {
- } // end loadPostProcess
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- enum
- {
- MAX_SIZE_BONUS = 50
- };
- //todo move this somewhere more useful.
- // ------------------------------------------------------------------------------------------------
- #if 0
- static Real angleBetween(const Coord2D &vecA, const Coord2D &vecB)
- {
- Real lengthA = vecA->length();
- if (lengthA < FLT_EPSILON) {
- return 0.0f;
- }
- Real lengthB = vecB->length();
- if (lengthB < FLT_EPSILON) {
- return 0.0f;
- }
- Real dotProduct = (vecA->x * vecB->x + vecA->y * vecB->y);
- // If the dotproduct is 0.0, then they are orthogonal
- if (dotProduct < FLT_EPSILON && dotProduct > -FLT_EPSILON) {
- return vecB->x > 0.0f ? PI : 0.0f;
- }
- Real cosTheta = dotProduct / (lengthA * lengthB);
- Real theta = ACos(cosTheta);
- return vecB->x > 0.0f ? theta : -theta;
- }
- #endif
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // Particle ///////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- /** Compute alpha rate to get to next key on given frame */
- // ------------------------------------------------------------------------------------------------
- void Particle::computeAlphaRate( void )
- {
- if (m_alphaKey[ m_alphaTargetKey ].frame == 0)
- {
- m_alphaRate = 0.0f;
- return;
- }
- Real delta = m_alphaKey[ m_alphaTargetKey ].value - m_alphaKey[ m_alphaTargetKey-1 ].value;
- UnsignedInt time = m_alphaKey[ m_alphaTargetKey ].frame - m_alphaKey[ m_alphaTargetKey-1 ].frame;
- m_alphaRate = delta/time;
- }
- // ------------------------------------------------------------------------------------------------
- /** Compute color rate to get to next key on given frame */
- // ------------------------------------------------------------------------------------------------
- void Particle::computeColorRate( void )
- {
- if (m_colorKey[ m_colorTargetKey ].frame == 0)
- {
- m_colorRate.red = 0.0f;
- m_colorRate.green = 0.0f;
- m_colorRate.blue = 0.0f;
- return;
- }
- UnsignedInt time = m_colorKey[ m_colorTargetKey ].frame - m_colorKey[ m_colorTargetKey-1 ].frame;
- Real delta = m_colorKey[ m_colorTargetKey ].color.red - m_colorKey[ m_colorTargetKey-1 ].color.red;
- m_colorRate.red = delta/time;
- delta = m_colorKey[ m_colorTargetKey ].color.green - m_colorKey[ m_colorTargetKey-1 ].color.green;
- m_colorRate.green = delta/time;
- delta = m_colorKey[ m_colorTargetKey ].color.blue - m_colorKey[ m_colorTargetKey-1 ].color.blue;
- m_colorRate.blue = delta/time;
- }
- // ------------------------------------------------------------------------------------------------
- /** Construct a particle from a particle template */
- // ------------------------------------------------------------------------------------------------
- Particle::Particle( ParticleSystem *system, const ParticleInfo *info )
- {
- m_system = system;
- m_isCulled = FALSE;
- m_accel.x = 0.0f;
- m_accel.y = 0.0f;
- m_accel.z = 0.0f;
- m_vel = info->m_vel;
- m_pos = info->m_pos;
- m_angleX = info->m_angleX;
- m_angleY = info->m_angleY;
- m_angleZ = info->m_angleZ;
- //Added By Sadullah Nader
- //Initializations inserted
- m_lastPos.zero();
- //
- m_windRandomness = info->m_windRandomness;
- m_particleUpTowardsEmitter = info->m_particleUpTowardsEmitter;
- m_emitterPos = info->m_emitterPos;
-
- m_angularRateX = info->m_angularRateX;
- m_angularRateY = info->m_angularRateY;
- m_angularRateZ = info->m_angularRateZ;
- m_angularDamping = info->m_angularDamping;
- m_velDamping = info->m_velDamping;
- m_lifetime = info->m_lifetime;
- m_lifetimeLeft = info->m_lifetime;
- m_createTimestamp = TheGameClient->getFrame();
- m_personality = 0;
- m_size = info->m_size;
- m_sizeRate = info->m_sizeRate;
- m_sizeRateDamping = info->m_sizeRateDamping;
- // set up alpha
- for( int i=0; i<MAX_KEYFRAMES; i++ )
- m_alphaKey[i] = info->m_alphaKey[i];
- m_alpha = m_alphaKey[0].value;
- m_alphaTargetKey = 1;
- computeAlphaRate();
- // set up colors
- for( i=0; i<MAX_KEYFRAMES; i++ )
- m_colorKey[i] = info->m_colorKey[i];
- m_color = m_colorKey[0].color;
- m_colorTargetKey = 1;
- computeColorRate();
- m_colorScale = info->m_colorScale;
- if (system->isUsingDrawables())
- {
- const ThingTemplate *tmpl = TheThingFactory->findTemplate(system->getParticleTypeName());
- DEBUG_ASSERTCRASH(tmpl, ("Drawable %s not found\n",system->getParticleTypeName().str()));
- if (tmpl)
- {
- m_drawable = TheThingFactory->newDrawable(tmpl);
- if (m_drawable)
- m_drawable->attachToParticleSystem( this );
- }
- }
- m_inSystemList = m_inOverallList = FALSE;
- m_systemPrev = m_systemNext = m_overallPrev = m_overallNext = NULL;
- // add this particle to the global list, retaining particle creation order
- TheParticleSystemManager->addParticle(this, system->getPriority() );
- // add this particle to the Particle System list, retaining local creation order
- m_system->addParticle(this);
- //DEBUG_ASSERTLOG(!(totalParticleCount % 100 == 0), ( "TotalParticleCount = %d\n", m_totalParticleCount ));
- }
- // ------------------------------------------------------------------------------------------------
- /** Destructor */
- // ------------------------------------------------------------------------------------------------
- Particle::~Particle()
- {
- // tell the particle system that this particle is gone
- m_system->removeParticle( this );
- if (m_drawable)
- TheGameClient->destroyDrawable( m_drawable );
- m_drawable = NULL;
- // if this particle was controlling another particle system, destroy that system
- if (m_systemUnderControl)
- {
- m_systemUnderControl->detachControlParticle( this );
- m_systemUnderControl->destroy();
- }
- m_systemUnderControl = NULL;
- // remove from the global list
- TheParticleSystemManager->removeParticle(this);
- //DEBUG_ASSERTLOG(!(totalParticleCount % 100 == 0), ( "TotalParticleCount = %d\n", m_totalParticleCount ));
- }
- // ------------------------------------------------------------------------------------------------
- /** Add the given acceleration */
- // ------------------------------------------------------------------------------------------------
- void Particle::applyForce( const Coord3D *force )
- {
- m_accel.x += force->x;
- m_accel.y += force->y;
- m_accel.z += force->z;
- }
- // ------------------------------------------------------------------------------------------------
- /** Update the behavior of an individual particle */
- // ------------------------------------------------------------------------------------------------
- Bool Particle::update( void )
- {
- // integrate acceleration into velocity
- m_vel.x += m_accel.x;
- m_vel.y += m_accel.y;
- m_vel.z += m_accel.z;
- m_vel.x *= m_velDamping;
- m_vel.y *= m_velDamping;
- m_vel.z *= m_velDamping;
- // integrate velocity into position
- const Coord3D *driftVel = m_system->getDriftVelocity();
- m_pos.x += m_vel.x + driftVel->x;
- m_pos.y += m_vel.y + driftVel->y;
- m_pos.z += m_vel.z + driftVel->z;
- // integrate the wind (if specified) into position
- doWindMotion();
- // update orientation
- m_angleX += m_angularRateX;
- m_angleY += m_angularRateY;
- m_angleZ += m_angularRateZ;
- m_angularRateX *= m_angularDamping;
- m_angularRateY *= m_angularDamping;
- m_angularRateZ *= m_angularDamping;
- if (m_particleUpTowardsEmitter) {
- // adjust the up position back towards the particle
- Coord2D emitterDir;
- emitterDir.x = m_pos.x - m_emitterPos.x;
- emitterDir.y = m_pos.y - m_emitterPos.y;
- #if 0
- static const Coord2D upVec = { 0.0f, 1.0f };
- m_angleZ = angleBetween(upVec, emitterDir) + PI;
- #else
- if (emitterDir.y < FLT_EPSILON && emitterDir.y > -FLT_EPSILON) {
- m_angleZ = emitterDir.x > 0.0f ? PI + PI : PI;
- } else {
- Real emitterDirLength = emitterDir.length();
- if (emitterDirLength < FLT_EPSILON) {
- m_angleZ = PI;
- } else {
- Real theta = ACos(emitterDir.y/emitterDirLength);
- m_angleZ = emitterDir.x > 0.0f ? PI + theta : PI - theta;
- }
- }
- #endif
- }
- // update size
- m_size += m_sizeRate;
- m_sizeRate *= m_sizeRateDamping;
- //
- // Update alpha
- //
- m_alpha += m_alphaRate;
- if (m_alphaTargetKey < MAX_KEYFRAMES && m_alphaKey[ m_alphaTargetKey ].frame)
- {
- if (TheGameClient->getFrame() - m_createTimestamp >= m_alphaKey[ m_alphaTargetKey ].frame)
- {
- m_alpha = m_alphaKey[ m_alphaTargetKey ].value;
- m_alphaTargetKey++;
- computeAlphaRate();
- }
- }
- else
- m_alphaRate = 0.0f;
- if (m_alpha < 0.0f)
- m_alpha = 0.0f;
- else if (m_alpha > 1.0f)
- m_alpha = 1.0f;
- //
- // Update color
- //
- m_color.red += m_colorRate.red;
- m_color.green += m_colorRate.green;
- m_color.blue += m_colorRate.blue;
- if (m_colorTargetKey < MAX_KEYFRAMES && m_colorKey[ m_colorTargetKey ].frame)
- {
- if (TheGameClient->getFrame() - m_createTimestamp >= m_colorKey[ m_colorTargetKey ].frame)
- {
- // can't set, because of colorscale
- // m_color = m_colorKey[ m_colorTargetKey ].color;
- m_colorTargetKey++;
- computeColorRate();
- }
- }
- else
- {
- m_colorRate.red = 0.0f;
- m_colorRate.green = 0.0f;
- m_colorRate.blue = 0.0f;
- }
- /// @todo Rethink this - at least its name
- m_color.red += m_colorScale;
- m_color.green += m_colorScale;
- m_color.blue += m_colorScale;
- if (m_color.red < 0.0f)
- m_color.red = 0.0f;
- else if (m_color.red > 1.0f)
- m_color.red = 1.0f;
- if (m_color.red < 0.0f)
- m_color.green = 0.0f;
- else if (m_color.green > 1.0f)
- m_color.green = 1.0f;
- if (m_color.blue < 0.0f)
- m_color.blue = 0.0f;
- else if (m_color.blue > 1.0f)
- m_color.blue = 1.0f;
- // reset the acceleration for accumulation next frame
- m_accel.x = 0.0f;
- m_accel.y = 0.0f;
- m_accel.z = 0.0f;
- if (m_drawable)
- {
- Matrix3D rot;
- rot.Make_Identity();
- rot.Rotate_X( m_angleX );
- rot.Rotate_Y( m_angleY );
- rot.Rotate_Z( m_angleZ );
- m_drawable->setInstanceMatrix( &rot );
- m_drawable->setPosition( &m_pos );
- }
- // monitor lifetime
- if (m_lifetimeLeft && --m_lifetimeLeft == 0)
- return false;
- DEBUG_ASSERTCRASH( m_lifetimeLeft, ( "A particle has an infinite lifetime..." ));
- // if we've gone totally invisible, destroy ourselves
- if (isInvisible())
- return false;
- return true;
- }
- // ------------------------------------------------------------------------------------------------
- /** Do wind motion as specified by the particle system template, if present */
- // ------------------------------------------------------------------------------------------------
- void Particle::doWindMotion( void )
- {
- ParticleSystemInfo::WindMotion windMotion = m_system->getWindMotion();
- // see if we should even do anything
- if( windMotion == ParticleSystemInfo::WIND_MOTION_NOT_USED )
- return;
- // get the angle of the wind
- Real windAngle = m_system->getWindAngle();
- // get the system position
- Coord3D systemPos;
- m_system->getPosition( &systemPos );
- // when we're attached objects and drawables we offset by that position as well
- if( ObjectID attachedObj = m_system->getAttachedObject() )
- {
- Object *obj = TheGameLogic->findObjectByID( attachedObj );
- if( obj )
- {
- const Coord3D *objPos = obj->getPosition();
- systemPos.x += objPos->x;
- systemPos.y += objPos->y;
- systemPos.z += objPos->z;
- } // end if
- } // end if
- else if( DrawableID attachedDraw = m_system->getAttachedDrawable() )
- {
- Drawable *draw = TheGameClient->findDrawableByID( attachedDraw );
- if( draw )
- {
- const Coord3D *drawPos = draw->getPosition();
- systemPos.x += drawPos->x;
- systemPos.y += drawPos->y;
- systemPos.z += drawPos->z;
- } // end if
- } // end else if
- //
- // compute a vector from the system position in the world to the particle ... we will use
- // this to compute how much force we apply
- //
- Coord3D v;
- v.x = m_pos.x - systemPos.x;
- v.y = m_pos.y - systemPos.y;
- v.z = m_pos.z - systemPos.z;
- // distance amounts for full force from wind and no force at all
- Real fullForceDistance = 75.0f;
- Real noForceDistance = 200.0f;
- //
- // given the distance from the wind position to the particle ... figure out how much
- // force we're going to apply to it. When it's further away (outside of the full force
- // distance) we will apply only a fraction of the force
- //
- Real distFromWind = v.length();
- if( distFromWind < noForceDistance )
- {
- Real windForceStrength = 2.0f * m_windRandomness;
- // only apply force if still within the circle of influence
- if( distFromWind > fullForceDistance )
- windForceStrength *= (1.0f - ((distFromWind - fullForceDistance) /
- (noForceDistance - fullForceDistance)));
- // integate the wind motion into the position
- m_pos.x += (Cos( windAngle ) * windForceStrength);
- m_pos.y += (Sin( windAngle ) * windForceStrength);
- } // end if
- } // doWindMotion
- // ------------------------------------------------------------------------------------------------
- /** Get priority of a particle ... which is the priority of it's attached system */
- // ------------------------------------------------------------------------------------------------
- ParticlePriorityType Particle::getPriority( void )
- {
- return m_system->getPriority();
- }
- // ------------------------------------------------------------------------------------------------
- /** Return true if this particle is invisible */
- // ------------------------------------------------------------------------------------------------
- Bool Particle::isInvisible( void )
- {
- // Drawables are never invisible (yet)
- /// @todo Allow Drawables to fade via alpha (MSB)
- if (m_drawable)
- return false;
- switch (m_system->getShaderType())
- {
- case ParticleSystemInfo::ADDITIVE:
- // if color is black, this particle is invisible
-
- // check that we're not in the process of going to another color
- if (m_colorKey[ m_colorTargetKey ].frame == 0)
- {
- if (m_color.red < 0.01f && m_color.green < 0.01f && m_color.blue < 0.01f)
- return true;
- }
- return false;
- case ParticleSystemInfo::ALPHA:
- // if alpha is zero, this particle is invisible
- if (m_alpha < 0.01f)
- return true;
- return false;
- case ParticleSystemInfo::ALPHA_TEST:
- // hmm... assume these particles are never invisible
- return false;
- case ParticleSystemInfo::MULTIPLY:
- // if color is white, this particle is invisible
- // check that we're not in the process of going to another color
- if (m_colorKey[ m_colorTargetKey ].frame == 0)
- {
- if (m_color.red > 0.99f && m_color.green > 0.99f && m_color.blue > 0.99f)
- return true;
- }
- return false;
- }
- // should never get here - if we do, data is incorrect
- return true;
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void Particle::crc( Xfer *xfer )
- {
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void Particle::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // base class particle info
- ParticleInfo::xfer( xfer );
- // personality
- xfer->xferUnsignedInt( &m_personality );
- // acceleration
- xfer->xferCoord3D( &m_accel );
- // last position
- xfer->xferCoord3D( &m_lastPos );
- // lifetime left
- xfer->xferUnsignedInt( &m_lifetimeLeft );
- // creation timestamp
- xfer->xferUnsignedInt( &m_createTimestamp );
- // alpha
- xfer->xferReal( &m_alpha );
- // alpha rate
- xfer->xferReal( &m_alphaRate );
- // alpha target key
- xfer->xferInt( &m_alphaTargetKey );
- // color
- xfer->xferRGBColor( &m_color );
- // color rate
- xfer->xferRGBColor( &m_colorRate );
- // color target key
- xfer->xferInt( &m_colorTargetKey );
- // drawable
- DrawableID drawableID = m_drawable ? m_drawable->getID() : INVALID_DRAWABLE_ID;
- xfer->xferDrawableID( &drawableID );
- if( xfer->getXferMode() == XFER_LOAD && drawableID != INVALID_DRAWABLE_ID )
- {
- //
- // save drawable pointer, note that this xfer block is after all the drawable stuff
- // so we don't need to post process anything all the correct drawables are loaded
- // and available to us
- //
- m_drawable = TheGameClient->findDrawableByID( drawableID );
- // sanity
- if( m_drawable == NULL )
- {
- DEBUG_CRASH(( "Particle::xfer - Unable to find matching drawable id for particle\n" ));
- throw SC_INVALID_DATA;
- } // end if
- // set the particle pointer in the drawable
- m_drawable->friend_setParticle( this );
- } // end if
- // system under control as an id
- ParticleSystemID systemUnderControlID = m_systemUnderControl ? m_systemUnderControl->getSystemID() : INVALID_PARTICLE_SYSTEM_ID;
- xfer->xferUser( &systemUnderControlID, sizeof( ParticleSystemID ) );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void Particle::loadPostProcess( void )
- {
- // call base class post process
- ParticleInfo::loadPostProcess();
- // tidy up the m_systemUnderControl pointer
- if( m_systemUnderControlID != INVALID_PARTICLE_SYSTEM_ID )
- {
- ParticleSystem *system;
-
- // find system
- system = TheParticleSystemManager->findParticleSystem( m_systemUnderControlID );
- // set us as the control particle for this system
- system->setControlParticle( this );
- controlParticleSystem( system );
- // sanity
- if( m_systemUnderControlID == NULL )
- {
- DEBUG_CRASH(( "Particle::loadPostProcess - Unable to find system under control pointer\n" ));
- throw SC_INVALID_DATA;
- } // end if
- } // end if
- } // end loadPostProcess
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ParticleSystemInfo::ParticleSystemInfo()
- {
- m_priority = PARTICLE_PRIORITY_LOWEST;
- m_isGroundAligned = false;
- m_isEmitAboveGroundOnly = false;
- m_isParticleUpTowardsEmitter = false;
-
- //Added By Sadullah Nader
- //Initializations inserted
- m_driftVelocity.zero();
- m_gravity = 0.0f;
- m_isEmissionVolumeHollow = FALSE;
- m_isOneShot = FALSE;
- m_slavePosOffset.zero();
- m_systemLifetime = 0;
-
- //
- // some default values for the wind motion values
- m_windMotion = WIND_MOTION_NOT_USED;
- m_windAngle = 0.0f;
- m_windAngleChange = 0.15f; // higher is ping pong faster
- m_windAngleChangeMin = 0.15f;
- m_windAngleChangeMax = 0.45f;
- m_windMotionStartAngleMin = 0.0f;
- m_windMotionStartAngleMax = PI / 4.0f;
- m_windMotionStartAngle = m_windMotionStartAngleMin;
- m_windMotionEndAngleMin = TWO_PI - (PI / 4.0f);
- m_windMotionEndAngleMax = TWO_PI;
- m_windMotionEndAngle = m_windMotionEndAngleMin;
- m_windMotionMovingToEndAngle = TRUE;
- m_volumeParticleDepth = DEFAULT_VOLUME_PARTICLE_DEPTH;
- }
- void ParticleSystemInfo::tintAllColors( Color tintColor )
- {
- RGBColor rgb;
- rgb.setFromInt(tintColor);
- //This tints all but the first colorKey!!!
- for (int key = 1; key < MAX_KEYFRAMES; ++key )
- {
- m_colorKey[ key ].color.red *= (Real)(rgb.red ) / 255.0f;
- m_colorKey[ key ].color.green *= (Real)(rgb.green) / 255.0f;
- m_colorKey[ key ].color.blue *= (Real)(rgb.blue ) / 255.0f;
- }
- } // end loadPostProcess
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemInfo::crc( Xfer *xfer )
- {
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemInfo::xfer( Xfer *xfer )
- {
- Int i;
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // is one shot
- xfer->xferBool( &m_isOneShot );
- // shader type
- xfer->xferUser( &m_shaderType, sizeof( ParticleShaderType ) );
- // particle type
- xfer->xferUser( &m_particleType, sizeof( ParticleType ) );
- // particle type name
- xfer->xferAsciiString( &m_particleTypeName );
- // angles
- xfer->xferUser( &m_angleX, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_angleY, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_angleZ, sizeof( GameClientRandomVariable ) );
- // angular rate
- xfer->xferUser( &m_angularRateX, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_angularRateY, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_angularRateZ, sizeof( GameClientRandomVariable ) );
- // angular damping
- xfer->xferUser( &m_angularDamping, sizeof( GameClientRandomVariable ) );
- // velocity damping
- xfer->xferUser( &m_velDamping, sizeof( GameClientRandomVariable ) );
- // lifetime
- xfer->xferUser( &m_lifetime, sizeof( GameClientRandomVariable ) );
- // system lifetime
- xfer->xferUnsignedInt( &m_systemLifetime );
- // start size
- xfer->xferUser( &m_startSize, sizeof( GameClientRandomVariable ) );
- // start size rate
- xfer->xferUser( &m_startSizeRate, sizeof( GameClientRandomVariable ) );
- // size rate
- xfer->xferUser( &m_sizeRate, sizeof( GameClientRandomVariable ) );
- // size rate damping
- xfer->xferUser( &m_sizeRateDamping, sizeof( GameClientRandomVariable ) );
- // alpha keys
- for( i = 0; i < MAX_KEYFRAMES; ++i )
- {
- xfer->xferUser( &m_alphaKey[ i ].var, sizeof( GameClientRandomVariable ) );
- xfer->xferUnsignedInt( &m_alphaKey[ i ].frame );
- } // end for, i
- // color keys
- for( i = 0; i < MAX_KEYFRAMES; ++i )
- {
- xfer->xferRGBColor( &m_colorKey[ i ].color );
- xfer->xferUnsignedInt( &m_colorKey[ i ].frame );
- } // end for, i
- // color scale
- xfer->xferUser( &m_colorScale, sizeof( GameClientRandomVariable ) );
-
- // burst delay
- xfer->xferUser( &m_burstDelay, sizeof( GameClientRandomVariable ) );
-
- // burst count
- xfer->xferUser( &m_burstCount, sizeof( GameClientRandomVariable ) );
-
- // initial delay
- xfer->xferUser( &m_initialDelay, sizeof( GameClientRandomVariable ) );
-
- // drift velocity
- xfer->xferCoord3D( &m_driftVelocity );
-
- // gravity
- xfer->xferReal( &m_gravity );
-
- // slave system name
- xfer->xferAsciiString( &m_slaveSystemName );
- // slave position offset
- xfer->xferCoord3D( &m_slavePosOffset );
- // attached system name
- xfer->xferAsciiString( &m_attachedSystemName );
- // emission velocity type, this must come before m_emissionVelocity
- xfer->xferUser( &m_emissionVelocityType, sizeof( EmissionVelocityType ) );
- // particle priority
- xfer->xferUser( &m_priority, sizeof( ParticlePriorityType ) );
- // emission velocity
- switch( m_emissionVelocityType )
- {
- // --------------------------------------------------------------------------------------------
- case ORTHO:
- xfer->xferUser( &m_emissionVelocity.ortho.x, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_emissionVelocity.ortho.y, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_emissionVelocity.ortho.z, sizeof( GameClientRandomVariable ) );
- break;
- // --------------------------------------------------------------------------------------------
- case SPHERICAL:
- xfer->xferUser( &m_emissionVelocity.spherical.speed, sizeof( GameClientRandomVariable ) );
- break;
- // --------------------------------------------------------------------------------------------
- case HEMISPHERICAL:
- xfer->xferUser( &m_emissionVelocity.hemispherical.speed, sizeof( GameClientRandomVariable ) );
- break;
- // --------------------------------------------------------------------------------------------
- case CYLINDRICAL:
- xfer->xferUser( &m_emissionVelocity.cylindrical.radial, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_emissionVelocity.cylindrical.normal, sizeof( GameClientRandomVariable ) );
- break;
- // --------------------------------------------------------------------------------------------
- case OUTWARD:
- xfer->xferUser( &m_emissionVelocity.outward.speed, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_emissionVelocity.outward.otherSpeed, sizeof( GameClientRandomVariable ) );
- break;
- } // end switch, m_emissionVelocityType
- // emission volume type
- xfer->xferUser( &m_emissionVolumeType, sizeof( EmissionVolumeType ) );
- // emission volume
- switch( m_emissionVolumeType )
- {
- // --------------------------------------------------------------------------------------------
- case POINT:
- // point has no data, it uses the systems position
- break;
- // --------------------------------------------------------------------------------------------
- case LINE:
- xfer->xferCoord3D( &m_emissionVolume.line.start );
- xfer->xferCoord3D( &m_emissionVolume.line.end );
- break;
- // --------------------------------------------------------------------------------------------
- case BOX:
- xfer->xferCoord3D( &m_emissionVolume.box.halfSize );
- break;
- // --------------------------------------------------------------------------------------------
- case SPHERE:
- xfer->xferReal( &m_emissionVolume.sphere.radius );
- break;
- // --------------------------------------------------------------------------------------------
- case CYLINDER:
- xfer->xferReal( &m_emissionVolume.cylinder.radius );
- xfer->xferReal( &m_emissionVolume.cylinder.length );
- break;
- } // end switch, m_emissionVolumeType
- // is emission volume hollow
- xfer->xferBool( &m_isEmissionVolumeHollow );
- // is ground aligned
- xfer->xferBool( &m_isGroundAligned );
- // emit above ground only
- xfer->xferBool( &m_isEmitAboveGroundOnly );
- // is particle up towards emitter
- xfer->xferBool( &m_isParticleUpTowardsEmitter );
- // wind motion
- xfer->xferUser( &m_windMotion, sizeof( WindMotion ) );
- // wind angle
- xfer->xferReal( &m_windAngle );
- // wind angle change
- xfer->xferReal( &m_windAngleChange );
- // wind angle change min
- xfer->xferReal( &m_windAngleChangeMin );
- // wind angle change max
- xfer->xferReal( &m_windAngleChangeMax );
- // wind motion start angle
- xfer->xferReal( &m_windMotionStartAngle );
- // wind motion start angle min
- xfer->xferReal( &m_windMotionStartAngleMin );
- // wind motion start angle max
- xfer->xferReal( &m_windMotionStartAngleMax );
- // wind motion end angle
- xfer->xferReal( &m_windMotionEndAngle );
- // wind motion end angle min
- xfer->xferReal( &m_windMotionEndAngleMin );
- // wind motion end angle max
- xfer->xferReal( &m_windMotionEndAngleMax );
- // wind motion moving to end angle
- xfer->xferByte( &m_windMotionMovingToEndAngle );
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemInfo::loadPostProcess( void )
- {
- } // end loadPostProcess
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ParticleSystem /////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- /** Read particle system properties from given file */
- // ------------------------------------------------------------------------------------------------
- ParticleSystem::ParticleSystem( const ParticleSystemTemplate *sysTemplate,
- ParticleSystemID id,
- Bool createSlaves )
- {
- m_systemParticlesHead = m_systemParticlesTail = NULL;
- m_isFirstPos = true;
- m_template = sysTemplate;
- m_systemID = id;
- //Added By Sadullah Nader
- //Initializations inserted
- m_lastPos.zero();
- m_pos.zero();
- m_velCoeff.zero();
- //
- m_attachedToDrawableID = INVALID_DRAWABLE_ID;
- m_attachedToObjectID = INVALID_ID;
- m_isLocalIdentity = true;
- m_localTransform.Make_Identity();
- m_isIdentity = true;
- m_transform.Make_Identity();
- m_isStopped = false;
- m_isDestroyed = false;
- m_isSaveable = true;
- m_slavePosOffset = sysTemplate->m_slavePosOffset;
- ///@todo: further formalize this parameter with an UnsignedInt field in the editor
- m_volumeParticleDepth = DEFAULT_VOLUME_PARTICLE_DEPTH;
- m_driftVelocity = sysTemplate->m_driftVelocity;
- m_velCoeff.x = 1.0f;
- m_velCoeff.y = 1.0f;
- m_velCoeff.z = 1.0f;
- m_countCoeff = 1.0f;
- m_delayCoeff = 1.0f;
- m_sizeCoeff = 1.0f;
- m_gravity = sysTemplate->m_gravity;
- m_lifetime = sysTemplate->m_lifetime;
- m_startSize = sysTemplate->m_startSize;
- m_startSizeRate = sysTemplate->m_startSizeRate;
- m_sizeRate = sysTemplate->m_sizeRate;
- m_sizeRateDamping = sysTemplate->m_sizeRateDamping;
- for( int i=0; i<MAX_KEYFRAMES; i++ )
- m_alphaKey[i] = sysTemplate->m_alphaKey[i];
- for( i=0; i<MAX_KEYFRAMES; i++ )
- m_colorKey[i] = sysTemplate->m_colorKey[i];
- /// @todo It is confusing to do this conversion here...
- Real low = sysTemplate->m_colorScale.getMinimumValue();
- Real hi = sysTemplate->m_colorScale.getMaximumValue();
- m_colorScale.setRange( low / 255.0f, hi / 255.0f );
- m_burstDelay = sysTemplate->m_burstDelay;
- m_burstDelayLeft = 0;
- m_burstCount = sysTemplate->m_burstCount;
- m_isOneShot = sysTemplate->m_isOneShot;
- m_delayLeft = (UnsignedInt)sysTemplate->m_initialDelay.getValue();
- m_startTimestamp = TheGameClient->getFrame();
- m_systemLifetimeLeft = sysTemplate->m_systemLifetime;
- if (sysTemplate->m_systemLifetime)
- m_isForever = false;
- else
- m_isForever = true;
- m_accumulatedSizeBonus = 0;
- m_velDamping = sysTemplate->m_velDamping;
- m_angleX = sysTemplate->m_angleX;
- m_angleY = sysTemplate->m_angleY;
- m_angleZ = sysTemplate->m_angleZ;
- m_angularRateX = sysTemplate->m_angularRateX;
- m_angularRateY = sysTemplate->m_angularRateY;
- m_angularRateZ = sysTemplate->m_angularRateZ;
- m_angularDamping = sysTemplate->m_angularDamping;
- m_priority = sysTemplate->m_priority;
- m_emissionVelocityType = sysTemplate->m_emissionVelocityType;
- m_emissionVelocity = sysTemplate->m_emissionVelocity;
- m_emissionVolumeType = sysTemplate->m_emissionVolumeType;
- m_emissionVolume = sysTemplate->m_emissionVolume;
- m_isEmissionVolumeHollow = sysTemplate->m_isEmissionVolumeHollow;
- m_isGroundAligned = sysTemplate->m_isGroundAligned;
- m_isEmitAboveGroundOnly = sysTemplate->m_isEmitAboveGroundOnly;
- m_isParticleUpTowardsEmitter = sysTemplate->m_isParticleUpTowardsEmitter;
- m_windMotion = sysTemplate->m_windMotion;
- m_windAngleChange = sysTemplate->m_windAngleChange;
- m_windAngleChangeMin = sysTemplate->m_windAngleChangeMin;
- m_windAngleChangeMax = sysTemplate->m_windAngleChangeMax;
- m_windMotionStartAngleMin = sysTemplate->m_windMotionStartAngleMin;
- m_windMotionStartAngleMax = sysTemplate->m_windMotionStartAngleMax;
- m_windMotionEndAngleMin = sysTemplate->m_windMotionEndAngleMin;
- m_windMotionEndAngleMax = sysTemplate->m_windMotionEndAngleMax;
- m_windMotionMovingToEndAngle = sysTemplate->m_windMotionMovingToEndAngle;
- m_windMotionStartAngle = GameClientRandomValueReal( m_windMotionStartAngleMin, m_windMotionStartAngleMax );
- m_windMotionEndAngle = GameClientRandomValueReal( m_windMotionEndAngleMin, m_windMotionEndAngleMax );
- m_windAngle = GameClientRandomValueReal( m_windMotionStartAngle, m_windMotionEndAngle );
-
- m_shaderType = sysTemplate->m_shaderType;
- m_particleType = sysTemplate->m_particleType;
- m_particleTypeName = sysTemplate->m_particleTypeName;
- m_isStopped = false;
- // set up slave particle system, if any
- m_masterSystemID = INVALID_PARTICLE_SYSTEM_ID;
- m_slaveSystemID = INVALID_PARTICLE_SYSTEM_ID;
- m_masterSystem = NULL;
- m_slaveSystem = NULL;
- if( createSlaves )
- {
- ParticleSystem *slaveSystem = sysTemplate->createSlaveSystem();
- if( slaveSystem )
- {
- setSlave( slaveSystem );
- m_slaveSystem->setMaster( this );
- } // end if
- } // end if
- m_attachedSystemName = sysTemplate->m_attachedSystemName;
- m_particleCount = 0;
- m_personalityStore = 0;
- m_controlParticle = NULL;
- TheParticleSystemManager->friend_addParticleSystem(this);
- //DEBUG_ASSERTLOG(!(m_totalParticleSystemCount % 10 == 0), ( "TotalParticleSystemCount = %d\n", m_totalParticleSystemCount ));
- }
- // ------------------------------------------------------------------------------------------------
- /** Destroy particle system and all of its particles */
- // ------------------------------------------------------------------------------------------------
- ParticleSystem::~ParticleSystem()
- {
- // tell any of our slave systems that we are going away
- if( m_slaveSystem )
- {
- DEBUG_ASSERTCRASH( m_slaveSystem->getMaster() == this, ("~ParticleSystem: Our slave doesn't have us as a master!\n") );
- m_slaveSystem->setMaster( NULL );
- setSlave( NULL );
- } // end if
- // tell any master system that *we* are going away
- if( m_masterSystem )
- {
- DEBUG_ASSERTCRASH( m_masterSystem->getSlave() == this, ("~ParticleSystem: Our master doesn't have us as a slave!\n") );
- m_masterSystem->setSlave( NULL );
- setMaster( NULL );
- } // end if
-
- // destroy all particles "in the air"
- while (m_systemParticlesHead)
- m_systemParticlesHead->deleteInstance();
- m_attachedToDrawableID = INVALID_DRAWABLE_ID;
- m_attachedToObjectID = INVALID_ID;
- // if this system was controlled by a particle, detach
- if (m_controlParticle)
- m_controlParticle->detachControlledParticleSystem();
- m_controlParticle = NULL;
-
- TheParticleSystemManager->friend_removeParticleSystem(this);
- //DEBUG_ASSERTLOG(!(m_totalParticleSystemCount % 10 == 0), ( "TotalParticleSystemCount = %d\n", m_totalParticleSystemCount ));
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::setMaster( ParticleSystem *master )
- {
- m_masterSystem = master;
- m_masterSystemID = master ? master->getSystemID() : INVALID_PARTICLE_SYSTEM_ID;
- } // end set Master
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::setSlave( ParticleSystem *slave )
- {
- m_slaveSystem = slave;
- m_slaveSystemID = slave ? slave->getSystemID() : INVALID_PARTICLE_SYSTEM_ID;
- } // end setSlave
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::setSaveable(Bool b)
- {
- m_isSaveable = b;
- if (m_slaveSystem)
- m_slaveSystem->setSaveable(b);
- }
- // ------------------------------------------------------------------------------------------------
- /** (Re)start a stopped particle system */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::start( void )
- {
- m_isStopped = false;
- }
- // ------------------------------------------------------------------------------------------------
- /** Stop a particle system from emitting */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::stop( void )
- {
- m_isStopped = true;
- }
- // ------------------------------------------------------------------------------------------------
- /** Stop emitting, wait for all of our particles to die, then destroy self. */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::destroy( void )
- {
- m_isDestroyed = true;
- if( m_slaveSystem )
- {
- m_slaveSystem->destroy(); // If we don't it will leak forever. We are solely responsible for it.
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Get the position of the particle system */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::getPosition( Coord3D *pos )
- {
- Vector3 vec;
- m_localTransform.Get_Translation(&vec);
- if (pos)
- { pos->x=vec.X;
- pos->y=vec.Y;
- pos->z=vec.Z;
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Set the position of the particle system */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::setPosition( const Coord3D *pos )
- {
- m_localTransform.Set_X_Translation( pos->x );
- m_localTransform.Set_Y_Translation( pos->y );
- m_localTransform.Set_Z_Translation( pos->z );
- m_isLocalIdentity = false;
- }
- // ------------------------------------------------------------------------------------------------
- /** Set the system's local transform */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::setLocalTransform( const Matrix3D *matrix )
- {
- m_localTransform = *matrix;
- m_isLocalIdentity = false;
- }
- // ------------------------------------------------------------------------------------------------
- /** Rotate local transform matrix */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::rotateLocalTransformX( Real x )
- {
- m_localTransform.Rotate_X( x );
- m_isLocalIdentity = false;
- }
- // ------------------------------------------------------------------------------------------------
- /** Rotate local transform matrix */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::rotateLocalTransformY( Real y )
- {
- m_localTransform.Rotate_Y( y );
- m_isLocalIdentity = false;
- }
- // ------------------------------------------------------------------------------------------------
- /** Rotate local transform matrix */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::rotateLocalTransformZ( Real z )
- {
- m_localTransform.Rotate_Z( z );
- m_isLocalIdentity = false;
- }
- // ------------------------------------------------------------------------------------------------
- /** Attach this particle system to a Drawable */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::attachToDrawable( const Drawable *draw )
- {
- if (draw)
- m_attachedToDrawableID = draw->getID();
- else
- m_attachedToDrawableID = INVALID_DRAWABLE_ID;
- }
- // ------------------------------------------------------------------------------------------------
- /** Attach this particle system to a Drawable */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::attachToObject( const Object *obj )
- {
- if (obj)
- m_attachedToObjectID = obj->getID();
- else
- m_attachedToObjectID = INVALID_ID;
- }
- // ------------------------------------------------------------------------------------------------
- /** Compute a random point on a unit sphere
- * @todo The density of random points generated is not uniform within the sphere */
- // ------------------------------------------------------------------------------------------------
- const Coord3D *ParticleSystem::computePointOnUnitSphere( void )
- {
- static Coord3D point;
- do
- {
- point.x = GameClientRandomValueReal( -1.0f, 1.0f );
- point.y = GameClientRandomValueReal( -1.0f, 1.0f );
- point.z = GameClientRandomValueReal( -1.0f, 1.0f );
- }
- while (point.x == 0.0f && point.y == 0.0f && point.z == 0.0f);
- point.normalize();
- return &point;
- }
- // ------------------------------------------------------------------------------------------------
- /** Compute a velocity vector based on emission properties */
- // ------------------------------------------------------------------------------------------------
- const Coord3D *ParticleSystem::computeParticleVelocity( const Coord3D *pos )
- {
- static Coord3D newVel;
- switch( m_emissionVelocityType )
- {
- case ORTHO:
- newVel.x = m_emissionVelocity.ortho.x.getValue();
- newVel.y = m_emissionVelocity.ortho.y.getValue();
- newVel.z = m_emissionVelocity.ortho.z.getValue();
- break;
-
- case CYLINDRICAL:
- {
- Real radialSpeed, angle;
- radialSpeed = m_emissionVelocity.cylindrical.radial.getValue();
- angle = GameClientRandomValueReal( 0, 2.0f*PI );
- newVel.x = radialSpeed * cos( angle );
- newVel.y = radialSpeed * sin( angle );
- newVel.z = m_emissionVelocity.cylindrical.normal.getValue();
- break;
- }
- // "outward" velocity is directed along the surface normal of the emission volume
- case OUTWARD:
- {
- Real speed = m_emissionVelocity.outward.speed.getValue();
- Real otherSpeed = m_emissionVelocity.outward.otherSpeed.getValue();
- Coord3D sysPos;
- /*
- sysPos.x = m_localTransform.Get_X_Translation();
- sysPos.y = m_localTransform.Get_Y_Translation();
- sysPos.z = m_localTransform.Get_Z_Translation();
- */
- sysPos.x = 0.0f;
- sysPos.y = 0.0f;
- sysPos.z = 0.0f;
- switch( m_emissionVolumeType )
- {
- case CYLINDER:
- Coord2D disk;
- disk.x = pos->x - sysPos.x;
- disk.y = pos->y - sysPos.y;
- disk.normalize();
- newVel.x = speed * disk.x;
- newVel.y = speed * disk.y;
- newVel.z = otherSpeed;
- break;
- case BOX: ///< @todo Implement BOX OUTWARD velocity
- case SPHERE:
- {
- newVel.x = pos->x - sysPos.x;
- newVel.y = pos->y - sysPos.y;
- newVel.z = pos->z - sysPos.z;
- newVel.normalize();
- newVel.x *= speed;
- newVel.y *= speed;
- newVel.z *= speed;
- break;
- }
- case LINE:
- {
- Coord3D along; // unit vector along line direction
- along.x = m_emissionVolume.line.end.x - m_emissionVolume.line.start.x;
- along.y = m_emissionVolume.line.end.y - m_emissionVolume.line.start.y;
- along.z = m_emissionVolume.line.end.z - m_emissionVolume.line.start.z;
- along.normalize();
- Coord3D perp; // unit vector perpendicular to the along/up plane
- Coord3D up; // unit vector in the up direction (Z)
- up.x = 0.0;
- up.y = 0.0;
- up.z = 1.0;
- perp.crossProduct( &up, &along, &perp );
- up.crossProduct( &along, &perp, &up );
- // "speed" is in 'horizontal' plane, and "otherSpeed" is 'vertical'
- newVel.x = speed * perp.x + otherSpeed * up.x;
- newVel.y = speed * perp.y + otherSpeed * up.y;
- newVel.z = speed * perp.z + otherSpeed * up.z;
- break;
- }
- case POINT:
- {
- Coord3D vel = *computePointOnUnitSphere();
- newVel.x = speed * vel.x;
- newVel.y = speed * vel.y;
- newVel.z = speed * vel.z;
- break;
- }
- }
- break;
- }
- case SPHERICAL:
- {
- Real speed = m_emissionVelocity.spherical.speed.getValue();
- Coord3D vel = *computePointOnUnitSphere();
- newVel.x = speed * vel.x;
- newVel.y = speed * vel.y;
- newVel.z = speed * vel.z;
- break;
- }
- case HEMISPHERICAL:
- {
- Coord3D vel;
- Real speed = m_emissionVelocity.spherical.speed.getValue();
- do
- {
- vel.x = GameClientRandomValueReal( -1.0f, 1.0f );
- vel.y = GameClientRandomValueReal( -1.0f, 1.0f );
- vel.z = GameClientRandomValueReal( 0.0f, 1.0f );
- }
- while (vel.x == 0.0f && vel.y == 0.0f && vel.z == 0.0f);
- vel.normalize();
- newVel.x = speed * vel.x;
- newVel.y = speed * vel.y;
- newVel.z = speed * vel.z;
- break;
- }
- default:
- newVel.x = 0.0f;
- newVel.y = 0.0f;
- newVel.z = 0.0f;
- break;
- }
- // scale the velocity by the velocity multiplier
- newVel.x *= m_velCoeff.x*(0.5f+TheGlobalData->m_particleScale/2.0f);
- newVel.y *= m_velCoeff.y*(0.5f+TheGlobalData->m_particleScale/2.0f);
- newVel.z *= m_velCoeff.z*(0.5f+TheGlobalData->m_particleScale/2.0f);
- return &newVel;
- }
- // ------------------------------------------------------------------------------------------------
- /** Compute a position based on emission properties */
- // ------------------------------------------------------------------------------------------------
- const Coord3D *ParticleSystem::computeParticlePosition( void )
- {
- static Coord3D newPos;
- switch( m_emissionVolumeType )
- {
- case CYLINDER:
- {
- Real angle = GameClientRandomValueReal( 0, 2.0f*PI );
- Real radius;
-
- if (m_isEmissionVolumeHollow)
- radius = m_emissionVolume.cylinder.radius;
- else
- radius = GameClientRandomValueReal( 0.0f, m_emissionVolume.cylinder.radius );
- newPos.x = radius * cos( angle );
- newPos.y = radius * sin( angle );
- Real halfLength = m_emissionVolume.cylinder.length/2.0f;
- newPos.z = GameClientRandomValueReal( -halfLength, halfLength );
- break;
- }
- case SPHERE:
- {
- Real radius;
- if (m_isEmissionVolumeHollow)
- radius = m_emissionVolume.sphere.radius;
- else
- radius = GameClientRandomValueReal( 0.0f, m_emissionVolume.sphere.radius );
- newPos = *computePointOnUnitSphere();
- newPos.x *= radius;
- newPos.y *= radius;
- newPos.z *= radius;
- break;
- }
- case BOX:
- {
- if (m_isEmissionVolumeHollow) {
- // determine which side to generate on.
- // 0 is bottom, 3 is top,
- // 1 is left , 4 is right
- // 2 is front, 5 is right back
- int side = GameClientRandomValue(0, 6);
- if (side % 3 == 0) {
- // generate X, Y
- newPos.x = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.x, m_emissionVolume.box.halfSize.x );
- newPos.y = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.y, m_emissionVolume.box.halfSize.y );
- if (side == 0) {
- newPos.z = -m_emissionVolume.box.halfSize.z;
- } else {
- newPos.z = m_emissionVolume.box.halfSize.z;
- }
-
- } else if (side % 3 == 1) {
- // generate Y, Z
- newPos.y = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.y, m_emissionVolume.box.halfSize.y );
- newPos.z = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.z, m_emissionVolume.box.halfSize.z );
- if (side == 1) {
- newPos.x = -m_emissionVolume.box.halfSize.x;
- } else {
- newPos.x = m_emissionVolume.box.halfSize.y;
- }
- } else if (side % 3 == 2) {
- // generate X, Z
- newPos.x = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.x, m_emissionVolume.box.halfSize.x );
- newPos.z = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.z, m_emissionVolume.box.halfSize.z );
- if (side == 2) {
- newPos.y = -m_emissionVolume.box.halfSize.y;
- } else {
- newPos.y = m_emissionVolume.box.halfSize.y;
- }
- }
- } else {
- newPos.x = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.x, m_emissionVolume.box.halfSize.x );
- newPos.y = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.y, m_emissionVolume.box.halfSize.y );
- newPos.z = GameClientRandomValueReal( -m_emissionVolume.box.halfSize.z, m_emissionVolume.box.halfSize.z );
- break;
- }
- }
- case LINE:
- {
- Coord3D delta, start, end;
- start = m_emissionVolume.line.start;
- end = m_emissionVolume.line.end;
- delta.x = end.x - start.x;
- delta.y = end.y - start.y;
- delta.z = end.z - start.z;
- Real t = GameClientRandomValueReal( 0.0f, 1.0f );
- newPos.x = start.x + t * delta.x;
- newPos.y = start.y + t * delta.y;
- newPos.z = start.z + t * delta.z;
- break;
- }
- case POINT:
- default:
- newPos.x = 0.0f;
- newPos.y = 0.0f;
- newPos.z = 0.0f;
- break;
- }
- newPos.x *= (0.5f+TheGlobalData->m_particleScale/2.0f);
- newPos.y *= (0.5f+TheGlobalData->m_particleScale/2.0f);
- newPos.z *= (0.5f+TheGlobalData->m_particleScale/2.0f);
- return &newPos;
- }
- // ------------------------------------------------------------------------------------------------
- /** Factory method for particles. */
- // ------------------------------------------------------------------------------------------------
- Particle *ParticleSystem::createParticle( const ParticleInfo *info,
- ParticlePriorityType priority,
- Bool forceCreate )
- {
- //
- // if we aren't absolutely forcing this particle to be created (which is needed when
- // loading and creating particle systems from the save games) we need to check a few
- // restrictions before this particle can really be created
- //
- if( forceCreate == FALSE )
- {
- if (TheGlobalData->m_useFX == FALSE)
- return NULL;
- //
- // Enforce particle limit.
- // If we are at the limit, destroy the oldest particle in order
- // to make room for this one.
- //
- //
- // Check if particle is below priorities we allow for this FPS or if it being skipped because
- // all particesl are being skipped (excluding special fps independent particles at
- // getMinDynamicParticleSkipPriority())
- //
- if( priority < TheGameLODManager->getMinDynamicParticlePriority() ||
- (priority < TheGameLODManager->getMinDynamicParticleSkipPriority() &&
- TheGameLODManager->isParticleSkipped()) )
- return NULL;
- if ( getParticleCount() > 0 && priority == AREA_EFFECT && m_isGroundAligned && TheParticleSystemManager->getFieldParticleCount() > (UnsignedInt)TheGlobalData->m_maxFieldParticleCount )
- return NULL;
-
- // ALWAYS_RENDER particles are exempt from all count limits, and are always created, regardless of LOD issues.
- if (priority != ALWAYS_RENDER)
- {
- int numInExcess = TheParticleSystemManager->getParticleCount() - (UnsignedInt)TheGlobalData->m_maxParticleCount;
- if ( numInExcess > 0)
- {
- if( TheParticleSystemManager->removeOldestParticles((UnsignedInt) numInExcess, priority) != numInExcess )
- return NULL; // could not remove enough particles, don't create new stuff
- }
- if (TheGlobalData->m_maxParticleCount == 0)
- return NULL;
- }
- } // end if
- Particle *p = newInstance(Particle)( this, info );
- return p;
- }
- // ------------------------------------------------------------------------------------------------
- /** Generate a new, random set of ParticleInfo
- * particleNum and particleCount are used to get 'tween frame particles emitted in the correct
- * place. (jkmcd) */
- // ------------------------------------------------------------------------------------------------
- const ParticleInfo *ParticleSystem::generateParticleInfo( Int particleNum, Int particleCount )
- {
- static ParticleInfo info;
- if (particleCount == 0) {
- DEBUG_CRASH(("particleCount must NOT be 0. Set to 1 or greater."));
- return &info;
- }
- // NOTE: position MUST be computed before velocity, in case OUTWARD velocity is
- // specified, which must know where the particle is in space.
- info.m_pos = *computeParticlePosition();
- info.m_vel = *computeParticleVelocity( &info.m_pos );
- // transform the position and velocity, if necessary
- /// @todo Avoid conversion from Coord3D to Vector3 somehow
- if (m_isIdentity == false)
- {
- // transform particle position to world coordinates
- Vector3 p, pr;
-
- Coord3D emissionAdjustment; // this is the adjustment for inter-frame emission
- // @todo : This should work, if m_lastPos = m_pos is removed from here but it doesn't.
- // @todo : Investigate why. jkmcd
- if (m_isFirstPos) {
- m_lastPos = m_pos;
- m_isFirstPos = false;
- }
-
- emissionAdjustment.x = (1 - (INT_TO_REAL(particleNum) / particleCount)) * (m_pos.x - m_lastPos.x);
- emissionAdjustment.y = (1 - (INT_TO_REAL(particleNum) / particleCount)) * (m_pos.y - m_lastPos.y);
- emissionAdjustment.z = (1 - (INT_TO_REAL(particleNum) / particleCount)) * (m_pos.z - m_lastPos.z);
- p.X = info.m_pos.x;
- p.Y = info.m_pos.y;
- p.Z = info.m_pos.z;
- #ifdef ALLOW_TEMPORARIES
- pr = m_transform * p;
- #else
- m_transform.mulVector3(p, pr);
- #endif
- info.m_pos.x = pr.X - emissionAdjustment.x;
- info.m_pos.y = pr.Y - emissionAdjustment.y;
- info.m_pos.z = pr.Z - emissionAdjustment.z;
- // transform particle velocity to world coordinates
- Vector3 v, vr;
- v.X = info.m_vel.x;
- v.Y = info.m_vel.y;
- v.Z = info.m_vel.z;
- Matrix3D::Rotate_Vector( m_transform, v, &vr );
- info.m_vel.x = vr.X;
- info.m_vel.y = vr.Y;
- info.m_vel.z = vr.Z;
- }
- info.m_velDamping = m_velDamping.getValue();
- info.m_angularDamping = m_angularDamping.getValue();
- info.m_angleX = m_angleX.getValue();
- info.m_angleY = m_angleY.getValue();
- info.m_angleZ = m_angleZ.getValue();
- info.m_angularRateX = m_angularRateX.getValue();
- info.m_angularRateY = m_angularRateY.getValue();
- info.m_angularRateZ = m_angularRateZ.getValue();
- info.m_lifetime = (UnsignedInt)m_lifetime.getValue();
- info.m_size = m_startSize.getValue()*m_sizeCoeff*TheGlobalData->m_particleScale;
- info.m_sizeRate = m_sizeRate.getValue()*m_sizeCoeff*TheGlobalData->m_particleScale;
- info.m_sizeRateDamping = m_sizeRateDamping.getValue();
- // Keeping a running tally makes each successive particle spawned start a bit bigger (or smaller).
- info.m_size += m_accumulatedSizeBonus;
- m_accumulatedSizeBonus += m_startSizeRate.getValue();
- if( m_accumulatedSizeBonus )
- m_accumulatedSizeBonus = min( m_accumulatedSizeBonus, (float)MAX_SIZE_BONUS );
- for( int i=0; i<MAX_KEYFRAMES; i++ )
- {
- info.m_alphaKey[i].value = m_alphaKey[i].var.getValue();
- info.m_alphaKey[i].frame = m_alphaKey[i].frame;
- }
- /*
- info.m_color.red = m_color.red.getValue();
- info.m_color.green = m_color.green.getValue();
- info.m_color.blue = m_color.blue.getValue();
- */
- for( i=0; i<MAX_KEYFRAMES; i++ )
- {
- info.m_colorKey[i] = m_colorKey[i];
- }
- info.m_colorScale = m_colorScale.getValue();
- #ifdef ALLOW_TEMPORARIES
- Vector3 pos = m_transform * Vector3(0, 0, 0);
- #else
- Vector3 pos;
- m_transform.mulVector3(Vector3(0, 0, 0), pos);
- #endif
- info.m_emitterPos.x = pos.X;
- info.m_emitterPos.y = pos.Y;
- info.m_emitterPos.z = pos.Z;
- info.m_particleUpTowardsEmitter = m_isParticleUpTowardsEmitter;
- info.m_windRandomness = GameClientRandomValueReal( 0.7f, 1.3f );
- return &info;
- }
- // ------------------------------------------------------------------------------------------------
- /** Update this particle system, potentially generating new particles */
- // ------------------------------------------------------------------------------------------------
- Bool ParticleSystem::update( Int localPlayerIndex )
- {
- if (TheGlobalData->m_useFX == FALSE)
- return false;
- // do initial delay ... note, this currently delays the lifetime
- if (m_delayLeft)
- {
- --m_delayLeft;
- // system actually "starts" once initial delay is over
- /// @todo reset start time when system is stopped/started
- if (m_delayLeft == 0)
- m_startTimestamp = TheGameClient->getFrame();
- return true;
- }
- // update the wind motion
- updateWindMotion();
- // if this system is attached to a Drawable/Object, update the current transform
- // matrix so generated particles' are relative to the parent Drawable's
- // position and orientation
- Bool transformSet = false;
- const Matrix3D *parentXfrm = NULL;
- Bool isShrouded = false;
- if (m_attachedToDrawableID)
- {
- Drawable *attachedTo = TheGameClient->findDrawableByID( m_attachedToDrawableID );
- if (attachedTo)
- {
- if (attachedTo->getFullyObscuredByShroud())
- isShrouded = true;
- parentXfrm = attachedTo->getTransformMatrix();
- m_lastPos = m_pos;
- m_pos = *attachedTo->getPosition();
- }
- else
- {
- // Drawable has been destroyed - lose our attachment to it
- m_attachedToDrawableID = INVALID_DRAWABLE_ID;
- // destroy ourselves
- destroy();
- }
- }
- if (m_attachedToObjectID)
- {
- Object *attachedTo = TheGameLogic->findObjectByID( m_attachedToObjectID );
- if (attachedTo)
- {
- if (!isShrouded)
- isShrouded = (attachedTo->getShroudedStatus(localPlayerIndex) >= OBJECTSHROUD_FOGGED);
-
- parentXfrm = attachedTo->getTransformMatrix();
- m_lastPos = m_pos;
- m_pos = *attachedTo->getPosition();
- }
- else
- {
- // Drawable has been destroyed - lose our attachment to it
- m_attachedToObjectID = INVALID_ID;
- // destroy ourselves
- destroy();
- }
- }
- if (parentXfrm)
- {
- // if system has its own local transform, concatenate them
- if (m_isLocalIdentity == false)
- #ifdef ALLOW_TEMPORARIES
- m_transform = (*parentXfrm) * m_localTransform;
- #else
- m_transform.mul(*parentXfrm, m_localTransform);
- #endif
- else
- m_transform = *parentXfrm;
- m_isIdentity = false;
- transformSet = true;
- }
- if (transformSet == false)
- {
- if (m_isLocalIdentity == false)
- {
- m_transform = m_localTransform;
- m_isIdentity = false;
- }
- else
- {
- m_isIdentity = true;
- }
- }
- // if we are controlled by a particle, its position is local origin
- if (m_controlParticle)
- {
- const Coord3D *controlPos = m_controlParticle->getPosition();
- /// @todo Concatenate this, instead of overriding (MSB)
- m_transform.Set_X_Translation( controlPos->x );
- m_transform.Set_Y_Translation( controlPos->y );
- m_transform.Set_Z_Translation( controlPos->z );
- m_isIdentity = false;
- m_lastPos = m_pos;
- m_pos = *controlPos;
- }
- //
- // Generate new particles if the system hasn't been 'stopped' or 'destroyed'
- // If we are a slave system, do not generate particles ourselves - our master will force us to
- //
- if (m_isDestroyed == false)
- {
- if (m_isForever || (m_isForever == false && m_systemLifetimeLeft > 0))
- {
- if (!isShrouded && m_isStopped == false && m_masterSystem == NULL)
- {
- if (m_burstDelayLeft == 0)
- {
- ParticlePriorityType priority = getPriority();
- // emit a burst of particles
- Int count = REAL_TO_INT(m_burstCount.getValue());
- count *= m_countCoeff;
- for( Int i=0; i<count; i++ )
- {
- // generate this particle's unique attributes
- const ParticleInfo *info = generateParticleInfo(i, count);
- if (!m_isEmitAboveGroundOnly || (info->m_pos.z >= TheTerrainLogic->getGroundHeight(info->m_pos.x, info->m_pos.y)))
- {
- // actually create a particle
- Particle *p = createParticle( info, priority );
- if (p == NULL)
- continue;
- if (m_attachedSystemName.isEmpty() == false)
- {
- const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate( m_attachedSystemName );
- if (tmp)
- {
- ParticleSystem *sys = TheParticleSystemManager->createParticleSystem( tmp, TRUE );
- sys->setControlParticle( p );
- p->controlParticleSystem( sys );
- }
- }
- // create a slave particle, if necessary
- if (m_slaveSystem)
- {
- ParticleInfo mergeInfo = ParticleSystem::mergeRelatedParticleSystems(this, m_slaveSystem, false);
- // create slaved particle
- m_slaveSystem->createParticle( &mergeInfo, priority );
- }
- }
- }
-
- // compute next burst delay
- m_burstDelayLeft = (UnsignedInt)m_burstDelay.getValue();
- m_burstDelayLeft *= m_delayCoeff;
- }
- else
- {
- m_burstDelayLeft--;
- }
- } // end if stopped check
- } // end if system lifetime check
- } // end if is destroyed
- //
- // Update all particles in the system
- //
- Particle *p = m_systemParticlesHead;
- Particle *oldParticle;
- while (p)
- {
- // apply 'gravity' force
- if (m_gravity != 0.0f)
- {
- Coord3D force;
- force.x = 0.0f;
- force.y = 0.0f;
- force.z = m_gravity;
- p->applyForce( &force );
- }
- if (p->update() == false)
- {
- oldParticle = p;
- p = p->m_systemNext;
- oldParticle->deleteInstance();
- } else {
- p = p->m_systemNext;
- }
- }
- //
- // If we have been "destroyed", wait for all of our particles to die off,
- // then destroy ourselves (return false).
- //
- if (m_isDestroyed && !m_systemParticlesHead)
- return false;
- // monitor particle system lifetime
- if (m_isForever == false)
- {
- // decrement lifetime if not zero
- if (m_systemLifetimeLeft)
- m_systemLifetimeLeft--;
- // if there are still particles "in the air", don't destroy yet
- if (getParticleCount())
- return true;
- // check if time is up
- if (m_systemLifetimeLeft == 0)
- return false;
- }
- return true;
- }
- // ------------------------------------------------------------------------------------------------
- /** Update the wind motion */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::updateWindMotion( void )
- {
- switch( m_windMotion )
- {
- // --------------------------------------------------------------------------------------------
- case ParticleSystemInfo::WIND_MOTION_PING_PONG:
- {
- Real startAngle = m_windMotionStartAngle;
- Real endAngle = m_windMotionEndAngle;
- // this only works when start angle is less than end angle
- DEBUG_ASSERTCRASH( startAngle < endAngle, ("updateWindMotion: startAngle must be < endAngle\n") );
- // how big is the total angle span
- Real totalSpan = endAngle - startAngle;
- Real halfSpan = totalSpan / 2.0f;
- // given our current angle ... how far away from the "center" of the span are we
- Real diffFromCenter = fabs( halfSpan - m_windAngle + startAngle );
-
- //
- // given our distance from the center ... we need to compute how much we will change
- // the angle. When we are closer to the center we change it faster (more), and when
- // we are near the edges we change is slower (less)
- //
- Real change = (1.0f - (diffFromCenter / halfSpan)) * m_windAngleChange;
- // we will always change a little bit
- #define MINIMUM_CHANGE 0.005f // lower #'s have softer swings at the edge angles
- if( change < MINIMUM_CHANGE )
- change = MINIMUM_CHANGE;
-
- //
- // if we are moving toward the end angle we add the change, if we're moving away
- // from it we subtract it
- //
- if( m_windMotionMovingToEndAngle )
- {
- // add angle
- m_windAngle += change;
- // see if we're at the end and should switch directions
- if( m_windAngle >= endAngle )
- {
- // change directions
- m_windMotionMovingToEndAngle = FALSE;
- // pick a new change delta
- m_windAngleChange =
- GameClientRandomValueReal( m_windAngleChangeMin, m_windAngleChangeMax );
- // pick new start and end angles
- m_windMotionStartAngle =
- GameClientRandomValueReal( m_windMotionStartAngleMin,
- m_windMotionStartAngleMax );
- m_windMotionEndAngle =
- GameClientRandomValueReal( m_windMotionEndAngleMin,
- m_windMotionEndAngleMax );
- } // end if
- } // end if
- else
- {
- // subtract angle
- m_windAngle -= change;
- // see if we're at the end and should switch directions
- if( m_windAngle <= startAngle )
- {
- // change directions
- m_windMotionMovingToEndAngle = TRUE;
- // pick a new change delta
- m_windAngleChange =
- GameClientRandomValueReal( m_windAngleChangeMin, m_windAngleChangeMax );
- // pick new start and end angles
- m_windMotionStartAngle =
- GameClientRandomValueReal( m_windMotionStartAngleMin,
- m_windMotionStartAngleMax );
- m_windMotionEndAngle =
- GameClientRandomValueReal( m_windMotionEndAngleMin,
- m_windMotionEndAngleMax );
- } // end if
- } // end else
- break;
- } // end case
- // --------------------------------------------------------------------------------------------
- case ParticleSystemInfo::WIND_MOTION_CIRCULAR:
- {
- // give us a wind angle change if one hasn't been specifed (this plays nice with the particle editor)
- if( m_windAngleChange == 0.0f )
- m_windAngleChange = GameClientRandomValueReal( m_windAngleChangeMin, m_windAngleChangeMax );
- // add to our wind angle
- m_windAngle += m_windAngleChange;
-
- // keep in 0 to 2PI range just to keep the numbers safe and sane
- if( m_windAngle > TWO_PI )
- m_windAngle -= TWO_PI;
- else if( m_windAngle < 0.0f )
- m_windAngle += TWO_PI;
- break;
- } // end case
- // ---------------------------------------------------------------------------------------------
- default:
- {
- break;
- } // end default
- } // end if
- } // end updateWindMotion
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::addParticle( Particle *particleToAdd )
- {
- if (particleToAdd->m_inSystemList)
- return;
- if (!m_systemParticlesHead)
- {
- m_systemParticlesHead = particleToAdd;
- }
- if (m_systemParticlesTail)
- {
- m_systemParticlesTail->m_systemNext = particleToAdd;
- particleToAdd->m_systemPrev = m_systemParticlesTail;
- }
- else
- {
- particleToAdd->m_systemPrev = NULL;
- }
- m_systemParticlesTail = particleToAdd;
- particleToAdd->m_systemNext = NULL;
- particleToAdd->m_inSystemList = TRUE;
- ++m_particleCount;
- particleToAdd->setPersonality( m_personalityStore++ );
- }
- // ------------------------------------------------------------------------------------------------
- /** Remove given particle from the list - ONLY FOR USE BY PARTICLE */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::removeParticle( Particle *particleToRemove )
- {
- if (!particleToRemove->m_inSystemList)
- return;
- // remove links from prev & next objs
- if (particleToRemove->m_systemNext)
- particleToRemove->m_systemNext->m_systemPrev = particleToRemove->m_systemPrev;
- if (particleToRemove->m_systemPrev)
- particleToRemove->m_systemPrev->m_systemNext = particleToRemove->m_systemNext;
- // update head & tail if neccessary
- if (particleToRemove == m_systemParticlesHead)
- m_systemParticlesHead = particleToRemove->m_systemNext;
- if (particleToRemove == m_systemParticlesTail)
- m_systemParticlesTail = particleToRemove->m_systemPrev;
- particleToRemove->m_systemNext = particleToRemove->m_systemPrev = NULL;
- particleToRemove->m_inSystemList = FALSE;
- --m_particleCount;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ParticleInfo ParticleSystem::mergeRelatedParticleSystems( ParticleSystem *masterParticleSystem, ParticleSystem *slaveParticleSystem, Bool slaveNeedsFullPromotion)
- {
- if (!masterParticleSystem || !slaveParticleSystem) {
- DEBUG_CRASH(("masterParticleSystem or slaveParticleSystem was NULL. Should not happen. JKMCD"));
- ParticleInfo bogus;
- memset( &bogus, 0, sizeof( bogus ) );
- return bogus;
- }
- // copy info
- ParticleInfo mergeInfo = *masterParticleSystem->generateParticleInfo(1, 1);
- // generate one from the slave system
- const ParticleInfo *info = slaveParticleSystem->generateParticleInfo(1, 1);
- // override unique attributes of slave particle
- mergeInfo.m_lifetime = info->m_lifetime;
- // size becomes a scale factor of master's particles
- mergeInfo.m_size *= info->m_size;
- mergeInfo.m_sizeRate *= info->m_sizeRate;
- mergeInfo.m_sizeRateDamping *= info->m_sizeRateDamping;
- mergeInfo.m_angleX = info->m_angleX;
- mergeInfo.m_angleY = info->m_angleY;
- mergeInfo.m_angleZ = info->m_angleZ;
- mergeInfo.m_angularRateX = info->m_angularRateX;
- mergeInfo.m_angularRateY = info->m_angularRateY;
- mergeInfo.m_angularRateZ = info->m_angularRateZ;
- mergeInfo.m_angularDamping = info->m_angularDamping;
- for( int i=0; i<MAX_KEYFRAMES; i++ )
- mergeInfo.m_alphaKey[i] = info->m_alphaKey[i];
- for( i=0; i<MAX_KEYFRAMES; i++ )
- mergeInfo.m_colorKey[i] = info->m_colorKey[i];
- mergeInfo.m_colorScale = info->m_colorScale;
- // offset slave's position relative to master's
- const Coord3D *offset = slaveParticleSystem->getSlavePositionOffset();
- mergeInfo.m_pos.x += offset->x;
- mergeInfo.m_pos.y += offset->y;
- mergeInfo.m_pos.z += offset->z;
- if (slaveNeedsFullPromotion) {
- slaveParticleSystem->m_burstCount = masterParticleSystem->m_burstCount;
- slaveParticleSystem->m_burstDelay = masterParticleSystem->m_burstDelay;
- slaveParticleSystem->m_priority = masterParticleSystem->m_priority;
- slaveParticleSystem->m_emissionVelocity = masterParticleSystem->m_emissionVelocity;
- slaveParticleSystem->m_emissionVelocityType = masterParticleSystem->m_emissionVelocityType;
- slaveParticleSystem->m_emissionVolume = masterParticleSystem->m_emissionVolume;
- slaveParticleSystem->m_emissionVolumeType = masterParticleSystem->m_emissionVolumeType;
- slaveParticleSystem->m_isEmissionVolumeHollow = masterParticleSystem->m_isEmissionVolumeHollow;
-
- slaveParticleSystem->m_startSize.setRange(masterParticleSystem->m_startSize.getMinimumValue() * slaveParticleSystem->m_startSize.getMinimumValue(),
- masterParticleSystem->m_startSize.getMaximumValue() * slaveParticleSystem->m_startSize.getMaximumValue(),
- masterParticleSystem->m_startSize.getDistributionType());
-
- slaveParticleSystem->m_sizeRate.setRange(masterParticleSystem->m_sizeRate.getMinimumValue() * slaveParticleSystem->m_sizeRate.getMinimumValue(),
- masterParticleSystem->m_sizeRate.getMaximumValue() * slaveParticleSystem->m_sizeRate.getMaximumValue(),
- masterParticleSystem->m_sizeRate.getDistributionType());
- slaveParticleSystem->m_sizeRateDamping.setRange(masterParticleSystem->m_sizeRateDamping.getMinimumValue() * slaveParticleSystem->m_sizeRateDamping.getMinimumValue(),
- masterParticleSystem->m_sizeRateDamping.getMaximumValue() * slaveParticleSystem->m_sizeRateDamping.getMaximumValue(),
- masterParticleSystem->m_sizeRateDamping.getDistributionType());
-
- // slaveParticleSystem->m_burstCount.setRange(masterParticleSystem->m_burstCount.getMinimumValue() / 2,
- // masterParticleSystem->m_burstCount.getMaximumValue() / 2,
- // masterParticleSystem->m_burstCount.getDistributionType());
-
- }
- return mergeInfo;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::setLifetimeRange( Real min, Real max )
- {
- m_lifetime.setRange( min, max );
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::setControlParticle( Particle *p )
- {
- m_controlParticle = p;
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::crc( Xfer *xfer )
- {
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // base class info
- ParticleSystemInfo::xfer( xfer );
- // particle system ID
- xfer->xferUser( &m_systemID, sizeof( ParticleSystemID ) );
- // attached to drawable id
- xfer->xferDrawableID( &m_attachedToDrawableID );
- // attached to object id
- xfer->xferObjectID( &m_attachedToObjectID );
- // is local identity
- xfer->xferBool( &m_isLocalIdentity );
- // local transform
- xfer->xferUser( &m_localTransform, sizeof( Matrix3D ) );
- // is identity
- xfer->xferBool( &m_isIdentity );
- // transform
- xfer->xferUser( &m_transform, sizeof( Matrix3D ) );
- // burst delay left
- xfer->xferUnsignedInt( &m_burstDelayLeft );
- // delay left
- xfer->xferUnsignedInt( &m_delayLeft );
- // start timestamp
- xfer->xferUnsignedInt( &m_startTimestamp );
- // system lifetime left
- xfer->xferUnsignedInt( &m_systemLifetimeLeft );
- // personality store
- xfer->xferUnsignedInt( &m_personalityStore );
- // is forever
- xfer->xferBool( &m_isForever );
- // accumulated size bonus
- xfer->xferReal( &m_accumulatedSizeBonus );
- // is stopped
- xfer->xferBool( &m_isStopped );
- // we never save destroyed particle systems so there is no need to consider m_isDestroyed
- // m_isDestroyed <-- do nothing with me
- // ditto for m_isSaveable
- // m_isSaveable <-- do nothing with me
- // velCoeff
- xfer->xferCoord3D( &m_velCoeff );
- // count coeff
- xfer->xferReal( &m_countCoeff );
- // delay coeff
- xfer->xferReal( &m_delayCoeff );
- // size coeff
- xfer->xferReal( &m_sizeCoeff );
- // position
- xfer->xferCoord3D( &m_pos );
- // last position
- xfer->xferCoord3D( &m_lastPos );
- // is first pos
- xfer->xferBool( &m_isFirstPos );
- // slave system id
- xfer->xferUser( &m_slaveSystemID, sizeof( ParticleSystemID ) );
- // master system
- xfer->xferUser( &m_masterSystemID, sizeof( ParticleSystemID ) );
- // particle count
- UnsignedInt particleCount = m_particleCount;
- xfer->xferUnsignedInt( &particleCount );
- // particles
- if( xfer->getXferMode() == XFER_SAVE )
- {
- Particle *particle;
- // go through all particles in this system
- for( particle = m_systemParticlesHead; particle; particle = particle->m_systemNext )
- {
- // write particle information
- xfer->xferSnapshot( particle );
- } // end for, particle
- } // end if, save
- else
- {
- ParticlePriorityType priority = getPriority();
- const ParticleInfo *info = generateParticleInfo( 0, 1 );
- Particle *particle;
- // read each particle data block
- for( UnsignedInt i = 0; i < particleCount; ++i )
- {
- // create a new particle
- particle = createParticle( info, priority, TRUE );
- // sanity
- DEBUG_ASSERTCRASH( particle, ("ParticleSyste::xfer - Unable to create particle for loading\n") );
- // read in the particle data
- xfer->xferSnapshot( particle );
- } // end for i
- } // end else, load
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystem::loadPostProcess( void )
- {
- // call base class post process
- ParticleSystemInfo::loadPostProcess();
- // reconnect slave pointers if needed
- if( m_slaveSystemID != INVALID_PARTICLE_SYSTEM_ID )
- {
- // sanity
- if( m_slaveSystem != NULL )
- {
- DEBUG_CRASH(( "ParticleSystem::loadPostProcess - m_slaveSystem is not NULL but should be\n" ));
- throw SC_INVALID_DATA;
- } // end if
- // assign system
- m_slaveSystem = TheParticleSystemManager->findParticleSystem( m_slaveSystemID );
- // sanity
- if( m_slaveSystem == NULL || m_slaveSystem->isDestroyed() == TRUE )
- {
- DEBUG_CRASH(( "ParticleSystem::loadPostProcess - m_slaveSystem is NULL or destroyed\n" ));
- throw SC_INVALID_DATA;
- } // end if
- } // end if
- // reconnect master pointers if needed
- if( m_masterSystemID != INVALID_PARTICLE_SYSTEM_ID )
- {
- // sanity
- if( m_masterSystem != NULL )
- {
- DEBUG_CRASH(( "ParticleSystem::loadPostProcess - m_masterSystem is not NULL but should be\n" ));
- throw SC_INVALID_DATA;
- } // end if
- // assign system
- m_masterSystem = TheParticleSystemManager->findParticleSystem( m_masterSystemID );
- // sanity
- if( m_masterSystem == NULL || m_masterSystem->isDestroyed() == TRUE )
- {
- DEBUG_CRASH(( "ParticleSystem::loadPostProcess - m_masterSystem is NULL or destroyed\n" ));
- throw SC_INVALID_DATA;
- } // end if
- } // end if
- } // end loadPostProcess
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ParticleSystemTemplate /////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- /** INI parse data */
- // ------------------------------------------------------------------------------------------------
- const FieldParse ParticleSystemTemplate::m_fieldParseTable[] =
- {
- { "Priority", INI::parseIndexList, ParticlePriorityNames, offsetof( ParticleSystemTemplate, m_priority ) },
- { "IsOneShot", INI::parseBool, NULL, offsetof( ParticleSystemTemplate, m_isOneShot ) },
- { "Shader", INI::parseIndexList, ParticleShaderTypeNames, offsetof( ParticleSystemTemplate, m_shaderType ) },
- { "Type", INI::parseIndexList, ParticleTypeNames, offsetof( ParticleSystemTemplate, m_particleType ) },
- { "ParticleName", INI::parseAsciiString, NULL, offsetof( ParticleSystemTemplate, m_particleTypeName ) },
- { "AngleX", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_angleX ) },
- { "AngleY", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_angleY ) },
- { "AngleZ", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_angleZ ) },
- { "AngularRateX", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_angularRateX ) },
- { "AngularRateY", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_angularRateY ) },
- { "AngularRateZ", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_angularRateZ ) },
- { "AngularDamping", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_angularDamping ) },
- { "VelocityDamping", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_velDamping ) },
- { "Gravity", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_gravity ) },
- { "SlaveSystem", INI::parseAsciiString, NULL, offsetof( ParticleSystemTemplate, m_slaveSystemName ) },
- { "SlavePosOffset", INI::parseCoord3D, NULL, offsetof( ParticleSystemTemplate, m_slavePosOffset ) },
- { "PerParticleAttachedSystem", INI::parseAsciiString, NULL, offsetof( ParticleSystemTemplate, m_attachedSystemName ) },
- { "Lifetime", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_lifetime ) },
- { "SystemLifetime", INI::parseUnsignedInt, NULL, offsetof( ParticleSystemTemplate, m_systemLifetime ) },
- { "Size", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_startSize ) },
- { "StartSizeRate", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_startSizeRate ) },
- { "SizeRate", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_sizeRate ) },
- { "SizeRateDamping", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_sizeRateDamping ) },
- { "Alpha1", ParticleSystemTemplate::parseRandomKeyframe, NULL, offsetof( ParticleSystemTemplate, m_alphaKey[0] ) },
- { "Alpha2", ParticleSystemTemplate::parseRandomKeyframe, NULL, offsetof( ParticleSystemTemplate, m_alphaKey[1] ) },
- { "Alpha3", ParticleSystemTemplate::parseRandomKeyframe, NULL, offsetof( ParticleSystemTemplate, m_alphaKey[2] ) },
- { "Alpha4", ParticleSystemTemplate::parseRandomKeyframe, NULL, offsetof( ParticleSystemTemplate, m_alphaKey[3] ) },
- { "Alpha5", ParticleSystemTemplate::parseRandomKeyframe, NULL, offsetof( ParticleSystemTemplate, m_alphaKey[4] ) },
- { "Alpha6", ParticleSystemTemplate::parseRandomKeyframe, NULL, offsetof( ParticleSystemTemplate, m_alphaKey[5] ) },
- { "Alpha7", ParticleSystemTemplate::parseRandomKeyframe, NULL, offsetof( ParticleSystemTemplate, m_alphaKey[6] ) },
- { "Alpha8", ParticleSystemTemplate::parseRandomKeyframe, NULL, offsetof( ParticleSystemTemplate, m_alphaKey[7] ) },
- { "Color1", ParticleSystemTemplate::parseRGBColorKeyframe,NULL, offsetof( ParticleSystemTemplate, m_colorKey[0] ) },
- { "Color2", ParticleSystemTemplate::parseRGBColorKeyframe,NULL, offsetof( ParticleSystemTemplate, m_colorKey[1] ) },
- { "Color3", ParticleSystemTemplate::parseRGBColorKeyframe,NULL, offsetof( ParticleSystemTemplate, m_colorKey[2] ) },
- { "Color4", ParticleSystemTemplate::parseRGBColorKeyframe,NULL, offsetof( ParticleSystemTemplate, m_colorKey[3] ) },
- { "Color5", ParticleSystemTemplate::parseRGBColorKeyframe,NULL, offsetof( ParticleSystemTemplate, m_colorKey[4] ) },
- { "Color6", ParticleSystemTemplate::parseRGBColorKeyframe,NULL, offsetof( ParticleSystemTemplate, m_colorKey[5] ) },
- { "Color7", ParticleSystemTemplate::parseRGBColorKeyframe,NULL, offsetof( ParticleSystemTemplate, m_colorKey[6] ) },
- { "Color8", ParticleSystemTemplate::parseRGBColorKeyframe,NULL, offsetof( ParticleSystemTemplate, m_colorKey[7] ) },
- // { "COLOR", ParticleSystemTemplate::parseRandomRGBColor, NULL, offsetof( ParticleSystemTemplate, m_color ) },
- { "ColorScale", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_colorScale ) },
- { "BurstDelay", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_burstDelay ) },
- { "BurstCount", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_burstCount ) },
- { "InitialDelay", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_initialDelay ) },
- { "DriftVelocity", INI::parseCoord3D, NULL, offsetof( ParticleSystemTemplate, m_driftVelocity ) },
- { "VelocityType", INI::parseIndexList, EmissionVelocityTypeNames, offsetof( ParticleSystemTemplate, m_emissionVelocityType ) },
- { "VelOrthoX", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.ortho.x ) },
- { "VelOrthoY", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.ortho.y ) },
- { "VelOrthoZ", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.ortho.z ) },
- { "VelSpherical", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.spherical.speed ) },
- { "VelHemispherical", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.hemispherical.speed ) },
- { "VelCylindricalRadial", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.cylindrical.radial ) },
- { "VelCylindricalNormal", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.cylindrical.normal ) },
- { "VelOutward", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.outward.speed ) },
- { "VelOutwardOther", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_emissionVelocity.outward.otherSpeed ) },
- { "VolumeType", INI::parseIndexList, EmissionVolumeTypeNames, offsetof( ParticleSystemTemplate, m_emissionVolumeType ) },
- { "VolLineStart", INI::parseCoord3D, NULL, offsetof( ParticleSystemTemplate, m_emissionVolume.line.start ) },
- { "VolLineEnd", INI::parseCoord3D, NULL, offsetof( ParticleSystemTemplate, m_emissionVolume.line.end ) },
- { "VolBoxHalfSize", INI::parseCoord3D, NULL, offsetof( ParticleSystemTemplate, m_emissionVolume.box.halfSize ) },
- { "VolSphereRadius", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_emissionVolume.sphere.radius ) },
- { "VolCylinderRadius", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_emissionVolume.cylinder.radius ) },
- { "VolCylinderLength", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_emissionVolume.cylinder.length ) },
- { "IsHollow", INI::parseBool, NULL, offsetof( ParticleSystemTemplate, m_isEmissionVolumeHollow ) },
- { "IsGroundAligned", INI::parseBool, NULL, offsetof( ParticleSystemTemplate, m_isGroundAligned ) },
- { "IsEmitAboveGroundOnly", INI::parseBool, NULL, offsetof( ParticleSystemTemplate, m_isEmitAboveGroundOnly) },
- { "IsParticleUpTowardsEmitter", INI::parseBool, NULL, offsetof( ParticleSystemTemplate, m_isParticleUpTowardsEmitter) },
- { "WindMotion", INI::parseIndexList, WindMotionNames, offsetof( ParticleSystemTemplate, m_windMotion ) },
- { "WindAngleChangeMin", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_windAngleChangeMin ) },
- { "WindAngleChangeMax", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_windAngleChangeMax ) },
- { "WindPingPongStartAngleMin", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_windMotionStartAngleMin ) },
- { "WindPingPongStartAngleMax", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_windMotionStartAngleMax ) },
- { "WindPingPongEndAngleMin", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_windMotionEndAngleMin ) },
- { "WindPingPongEndAngleMax", INI::parseReal, NULL, offsetof( ParticleSystemTemplate, m_windMotionEndAngleMax ) },
- { NULL, NULL, NULL, 0 },
- };
- // ------------------------------------------------------------------------------------------------
- /** Parse a "random keyframe".
- * The format is "FIELD = low high frame". */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemTemplate::parseRandomKeyframe( INI* ini, void *instance,
- void *store, const void* /*userData*/ )
- {
- RandomKeyframe *key = static_cast<RandomKeyframe *>(store);
- Real low = ini->scanReal(ini->getNextToken());
- Real high = ini->scanReal(ini->getNextToken());
- key->frame = ini->scanUnsignedInt(ini->getNextToken());
- // set the range of the random variable
- key->var.setRange( low, high );
- }
- // ------------------------------------------------------------------------------------------------
- /** Parse a "color keyframe".
- * The format is "FIELD = R:r G:g B:b frame". */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemTemplate::parseRGBColorKeyframe( INI* ini, void *instance,
- void *store, const void* /*userData*/ )
- {
- RGBColorKeyframe *key = static_cast<RGBColorKeyframe *>(store);
- INI::parseRGBColor( ini, instance, &key->color, NULL );
- INI::parseUnsignedInt( ini, instance, &key->frame, NULL );
- }
- // ------------------------------------------------------------------------------------------------
- /** Parse a RandomVariable RGB color.
- * Note that the components may be negative, as this is used for rates, as well. */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemTemplate::parseRandomRGBColor( INI* ini, void *instance,
- void *store, const void* /*userData*/ )
- {
- #if 0
- char seps[] = " \n\r\t=:RGB,";
- const char *token;
- Int colors[2][3];
- Int result;
- enum { LO = 0, HI = 1 };
- enum { RED = 0, GREEN = 1, BLUE = 2 };
- // initialize to invalid values
- colors[ LO ][ RED ] = -1;
- colors[ LO ][ GREEN ] = -1;
- colors[ LO ][ BLUE ] = -1;
- colors[ HI ][ RED ] = -1;
- colors[ HI ][ GREEN ] = -1;
- colors[ HI ][ BLUE ] = -1;
- // do each color part
- for( Int i = 0; i < 3; i++ )
- {
- for( Int j = 0; j < 2; j++ )
- {
- // get the color number
- token = ini->getNextToken(seps);
- // convert to number
- colors[j][i] = ini->scanInt(token);
- // check to see if it's within range
- if( colors[j][i] < -255 || colors[j][i] > 255 )
- throw INI_INVALID_DATA;
- } // end for i
- }
- // assign the color components to the "RGBColor" pointer at 'store'
- ParticleSystemInfo::RandomRGBColor *theColor = (ParticleSystemInfo::RandomRGBColor *)store;
- theColor->red.setRange( (Real)colors[ LO ][ RED ] / 255.0f, (Real)colors[ HI ][ RED ] / 255.0f );
- theColor->green.setRange( (Real)colors[ LO ][ GREEN ] / 255.0f, (Real)colors[ HI ][ GREEN ] / 255.0f );
- theColor->blue.setRange( (Real)colors[ LO ][ BLUE ] / 255.0f, (Real)colors[ HI ][ BLUE ] / 255.0f );
- #endif
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ParticleSystemTemplate::ParticleSystemTemplate( const AsciiString &name ) :
- m_name(name)
- {
- //Added By Sadullah Nader
- //Initializations inserted
- m_slaveTemplate = NULL;
- //
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ParticleSystemTemplate::~ParticleSystemTemplate()
- {
-
- }
- // ------------------------------------------------------------------------------------------------
- /** If returns non-NULL, it is a slave system for use ... the create slaves parameter
- * tells *this* slave system whether or not it should create any slaves itself
- * automatically during its own constructor */
- // ------------------------------------------------------------------------------------------------
- ParticleSystem *ParticleSystemTemplate::createSlaveSystem( Bool createSlaves ) const
- {
- if (m_slaveTemplate == NULL && m_slaveSystemName.isEmpty() == false)
- m_slaveTemplate = TheParticleSystemManager->findTemplate( m_slaveSystemName );
- ParticleSystem *slave = NULL;
- if (m_slaveTemplate)
- slave = TheParticleSystemManager->createParticleSystem( m_slaveTemplate, createSlaves );
- return slave;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ParticleSystemManager //////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ParticleSystemManager::ParticleSystemManager( void )
- {
- m_uniqueSystemID = INVALID_PARTICLE_SYSTEM_ID;
- m_onScreenParticleCount = 0;
- m_localPlayerIndex = 0;
-
- //Added By Sadullah Nader
- //Initializations inserted
- m_lastLogicFrameUpdate = 0;
- m_particleCount = 0;
- m_fieldParticleCount = 0;
- m_particleSystemCount = 0;
- //
- for( Int i = 0; i < NUM_PARTICLE_PRIORITIES; ++i )
- {
-
- m_allParticlesHead[ i ] = NULL;
- m_allParticlesTail[ i ] = NULL;
- } // end for, i
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ParticleSystemManager::~ParticleSystemManager()
- {
- reset();
- TemplateMap::iterator begin(m_templateMap.begin());
- TemplateMap::iterator end(m_templateMap.end());
- for (; begin != end; ++begin) {
- (*begin).second->deleteInstance();
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Initialize the manager */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::init( void )
- {
- /// Read INI data and build templates
- INI ini;
- ini.load( AsciiString( "Data\\INI\\ParticleSystem.ini" ), INI_LOAD_OVERWRITE, NULL );
- // sanity, our lists must be empty!!
- for( Int i = 0; i < NUM_PARTICLE_PRIORITIES; ++i )
- {
- // sanity
- DEBUG_ASSERTCRASH( m_allParticlesHead[ i ] == NULL, ("INIT: ParticleSystem all particles head[%d] is not NULL!\n", i) );
- DEBUG_ASSERTCRASH( m_allParticlesTail[ i ] == NULL, ("INIT: ParticleSystem all particles tail[%d] is not NULL!\n", i) );
- // just to be clean set them to NULL
- m_allParticlesHead[ i ] = NULL;
- m_allParticlesTail[ i ] = NULL;
- } // end for, i
- }
- // ------------------------------------------------------------------------------------------------
- /** Reset the manager and all particle systems */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::reset( void )
- {
- while (getParticleSystemCount()) {
- if (m_allParticleSystemList.front()) {
- m_allParticleSystemList.front()->deleteInstance();
- }
- }
- // sanity, our lists must be empty!!
- for( Int i = 0; i < NUM_PARTICLE_PRIORITIES; ++i )
- {
- // sanity
- DEBUG_ASSERTCRASH( m_allParticlesHead[ i ] == NULL, ("RESET: ParticleSystem all particles head[%d] is not NULL!\n", i) );
- DEBUG_ASSERTCRASH( m_allParticlesTail[ i ] == NULL, ("RESET: ParticleSystem all particles tail[%d] is not NULL!\n", i) );
- // just to be clean set them to NULL
- m_allParticlesHead[ i ] = NULL;
- m_allParticlesTail[ i ] = NULL;
- } // end for, i
- m_particleCount = 0;
- m_fieldParticleCount = 0;
- m_particleSystemCount = 0;
- m_uniqueSystemID = INVALID_PARTICLE_SYSTEM_ID;
-
- m_lastLogicFrameUpdate = -1;
- // leave templates as-is
- }
- // ------------------------------------------------------------------------------------------------
- /** Update all particle systems */
- // ------------------------------------------------------------------------------------------------
- //DECLARE_PERF_TIMER(ParticleSystemManager)
- void ParticleSystemManager::update( void )
- {
- if (m_lastLogicFrameUpdate == TheGameLogic->getFrame()) {
- return;
- }
- // update the last logic frame.
- m_lastLogicFrameUpdate = TheGameLogic->getFrame();
- //USE_PERF_TIMER(ParticleSystemManager)
- ParticleSystem *sys;
- for(ParticleSystemListIt it = m_allParticleSystemList.begin(); it != m_allParticleSystemList.end();)
- {
- sys = (*it);
- if (!sys) {
- continue;
- }
- if (sys->update(m_localPlayerIndex) == false)
- {
- ++it;
- sys->deleteInstance();
- } else {
- ++it;
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** sets the count of the particles on screen after each frame */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::setOnScreenParticleCount(int count)
- {
- m_onScreenParticleCount = count;
- }
- // ------------------------------------------------------------------------------------------------
- /** Given a file containing particle system properties, create a new instance of it */
- // ------------------------------------------------------------------------------------------------
- ParticleSystem *ParticleSystemManager::createParticleSystem( const ParticleSystemTemplate *sysTemplate, Bool createSlaves )
- {
- // sanity
- if (sysTemplate == NULL)
- return NULL;
- m_uniqueSystemID = (ParticleSystemID)((UnsignedInt)m_uniqueSystemID + 1);
- ParticleSystem *sys = newInstance(ParticleSystem)( sysTemplate, m_uniqueSystemID, createSlaves );
- return sys;
- }
- // ------------------------------------------------------------------------------------------------
- /// given a template, instantiate a particle system attached to the given object, and return its ID
- // ------------------------------------------------------------------------------------------------
- ParticleSystemID ParticleSystemManager::createAttachedParticleSystemID(
- const ParticleSystemTemplate *sysTemplate,
- Object* attachTo,
- Bool createSlaves )
- {
- ParticleSystem* pSystem = TheParticleSystemManager->createParticleSystem(sysTemplate, createSlaves);
- if (pSystem && attachTo)
- pSystem->attachToObject(attachTo);
- return pSystem ? pSystem->getSystemID() : INVALID_PARTICLE_SYSTEM_ID;
- }
- // ------------------------------------------------------------------------------------------------
- /** Find a particle system with the matching system id */
- // ------------------------------------------------------------------------------------------------
- ParticleSystem *ParticleSystemManager::findParticleSystem( ParticleSystemID id )
- {
- if (id == INVALID_PARTICLE_SYSTEM_ID)
- return NULL; // my, that was easy
- ParticleSystem *system = NULL;
- for( ParticleSystemListIt it = m_allParticleSystemList.begin(); it != m_allParticleSystemList.end(); ++it ) {
- system = *it;
- if (!system) {
- continue;
- }
- if( system->getSystemID() == id ) {
- return system;
- }
- }
- return NULL;
- } // end findParticleSystem
- // ------------------------------------------------------------------------------------------------
- /** destroy the particle system with the given id (if it still exists) */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::destroyParticleSystemByID(ParticleSystemID id)
- {
- ParticleSystem* pSystem = findParticleSystem(id);
- if( pSystem )
- pSystem->destroy();
- }
- // ------------------------------------------------------------------------------------------------
- /** Locate an existing ParticleSystemTemplate */
- // ------------------------------------------------------------------------------------------------
- ParticleSystemTemplate *ParticleSystemManager::findTemplate( const AsciiString &name ) const
- {
- ParticleSystemTemplate *sysTemplate = NULL;
- TemplateMap::const_iterator find(m_templateMap.find(name));
- if (find != m_templateMap.end()) {
- sysTemplate = (*find).second;
- }
- return sysTemplate;
- }
- // ------------------------------------------------------------------------------------------------
- /** Create a new ParticleSystemTemplate */
- // ------------------------------------------------------------------------------------------------
- ParticleSystemTemplate *ParticleSystemManager::newTemplate( const AsciiString &name )
- {
- ParticleSystemTemplate *sysTemplate = findTemplate(name);
- if (sysTemplate == NULL) {
- sysTemplate = newInstance(ParticleSystemTemplate)( name );
- if (! m_templateMap.insert(std::make_pair(name, sysTemplate)).second) {
- sysTemplate->deleteInstance();
- sysTemplate = NULL;
- }
- }
- return sysTemplate;
- }
- // ------------------------------------------------------------------------------------------------
- /** Find a particle system's parent. Should really only be called by TheScriptEngine */
- // ------------------------------------------------------------------------------------------------
- ParticleSystemTemplate *ParticleSystemManager::findParentTemplate( const AsciiString &name, Int parentNum ) const
- {
- if (name.isEmpty()) {
- return NULL;
- }
- TemplateMap::const_iterator begin(m_templateMap.begin());
- TemplateMap::const_iterator end(m_templateMap.end());
- for(; begin != end; ++begin) {
- ParticleSystemTemplate *sysTemplate = (*begin).second;
- if (name.compare(sysTemplate->m_slaveSystemName) == 0) {
- if (! parentNum--) {
- return sysTemplate;
- }
- }
- }
- return NULL;
- }
- // ------------------------------------------------------------------------------------------------
- /** Destroy any particle systems that are attached to this object */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::destroyAttachedSystems( Object *obj )
- {
- // sanity
- if( obj == NULL )
- return;
- // iterate through all systems
- ParticleSystem *system = NULL;
- for( ParticleSystemListIt it = m_allParticleSystemList.begin();
- it != m_allParticleSystemList.end();
- ++it )
- {
- system = *it;
- if( system == NULL )
- continue;
-
- if( system->getAttachedObject() == obj->getID() )
- system->destroy();
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Add a particle to the global particle list. */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::addParticle( Particle *particleToAdd, ParticlePriorityType priority )
- {
- if (particleToAdd->m_inOverallList)
- return;
- if (!m_allParticlesHead[ priority ])
- {
- m_allParticlesHead[ priority ] = particleToAdd;
- }
- if (m_allParticlesTail[ priority ])
- {
- m_allParticlesTail[ priority ]->m_overallNext = particleToAdd;
- particleToAdd->m_overallPrev = m_allParticlesTail[ priority ];
- }
- else
- {
- particleToAdd->m_overallPrev = NULL;
- }
- m_allParticlesTail[ priority ] = particleToAdd;
- particleToAdd->m_overallNext = NULL;
- particleToAdd->m_inOverallList = TRUE;
- ++m_particleCount;
-
- }
- // ------------------------------------------------------------------------------------------------
- /** Remove a particle from the global particle list. */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::removeParticle( Particle *particleToRemove)
- {
- if (!particleToRemove->m_inOverallList)
- return;
- // get priority of the particle we're removing
- ParticlePriorityType priority = particleToRemove->getPriority();
- // remove links from prev & next objs
- if (particleToRemove->m_overallNext)
- particleToRemove->m_overallNext->m_overallPrev = particleToRemove->m_overallPrev;
- if (particleToRemove->m_overallPrev)
- particleToRemove->m_overallPrev->m_overallNext = particleToRemove->m_overallNext;
- // update head & tail if neccessary
- if (particleToRemove == m_allParticlesHead[ priority ])
- m_allParticlesHead[ priority ] = particleToRemove->m_overallNext;
- if (particleToRemove == m_allParticlesTail[ priority ])
- m_allParticlesTail[ priority ] = particleToRemove->m_overallPrev;
- particleToRemove->m_overallNext = particleToRemove->m_overallPrev = NULL;
- particleToRemove->m_inOverallList = FALSE;
- --m_particleCount;
- }
- // ------------------------------------------------------------------------------------------------
- /** Add a particle system to the master particle system list. */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::friend_addParticleSystem( ParticleSystem *particleSystemToAdd )
- {
- m_allParticleSystemList.push_back(particleSystemToAdd);
- ++m_particleSystemCount;
- }
- // ------------------------------------------------------------------------------------------------
- /** Remove a particle system from the master particle system list. */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::friend_removeParticleSystem( ParticleSystem *particleSystemToRemove )
- {
- ParticleSystemListIt it = std::find(m_allParticleSystemList.begin(), m_allParticleSystemList.end(), particleSystemToRemove);
- if (it != m_allParticleSystemList.end()) {
- m_allParticleSystemList.erase(it);
- --m_particleSystemCount;
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Remove the oldest N number of particles from the lowest priority lists first. We will
- * not remove particles from any priorities higher or equal to the priorityCap parameter. */
- // ------------------------------------------------------------------------------------------------
- Int ParticleSystemManager::removeOldestParticles( UnsignedInt count,
- ParticlePriorityType priorityCap )
- {
- Int countToRemove = count;
- while (count-- && getParticleCount())
- {
- for( Int i = PARTICLE_PRIORITY_LOWEST;
- i < priorityCap;
- ++i )
- {
- if( m_allParticlesHead[ i ] )
- {
- m_allParticlesHead[ i ]->deleteInstance();
- break; // exit for
- }
- }
- }
- // return the number of particles actually removed
- return countToRemove - count;
- }
- // ------------------------------------------------------------------------------------------------
- /** Preload particle system textures */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::preloadAssets( TimeOfDay timeOfDay )
- {
- TemplateMap::iterator begin(m_templateMap.begin());
- TemplateMap::iterator end(m_templateMap.end());
- for (; begin != end; ++begin) {
- const ParticleSystemTemplate *tmplate = (*begin).second;
- if (tmplate->m_particleType == ParticleSystemInfo::PARTICLE &&
- (! tmplate->m_particleTypeName.isEmpty()))
- {
- TheDisplay->preloadTextureAssets(tmplate->m_particleTypeName);
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::crc( Xfer *xfer )
- {
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // unique system ID counter
- xfer->xferUser( &m_uniqueSystemID, sizeof( ParticleSystemID ) );
- // count of particle systems in the world
- UnsignedInt systemCount = m_particleSystemCount;
- xfer->xferUnsignedInt( &systemCount );
- // particle systems data
- AsciiString systemName;
- ParticleSystem *system;
- if( xfer->getXferMode() == XFER_SAVE )
- {
- // iterate each particle system
- ParticleSystemListIt it;
- for( it = m_allParticleSystemList.begin(); it != m_allParticleSystemList.end(); ++it )
- {
- systemCount--;
- // get system
- system = *it;
- // ignore destroyed systems and non-saveable systems
- if( system->isDestroyed() == TRUE || system->isSaveable() == FALSE ) {
- AsciiString mtString = "";
- xfer->xferAsciiString(&mtString); // write null string as key for destroyed system.
- continue;
- }
- // write template name
- systemName = system->getTemplate()->getName();
- xfer->xferAsciiString( &systemName );
- // write system data
- xfer->xferSnapshot( system );
- } // end for, it
- DEBUG_ASSERTCRASH(systemCount==0, ("Mismatch in write count."));
- } // end if, save
- else
- {
- const ParticleSystemTemplate *systemTemplate;
- // read each particle system
- for( UnsignedInt i = 0; i < systemCount; ++i )
- {
- // read system name and find template
- xfer->xferAsciiString( &systemName );
- if (systemName.isEmpty()) {
- continue; // destroyed particle system.
- }
- systemTemplate = findTemplate( systemName );
- // sanity
- if( systemTemplate == NULL )
- {
- DEBUG_CRASH(( "ParticleSystemManager::xfer - Unknown particle system template '%s'\n",
- systemName.str() ));
- throw SC_INVALID_DATA;
- } // end if
- // create system
- system = createParticleSystem( systemTemplate, FALSE );
- if( system == NULL )
- {
- DEBUG_CRASH(( "ParticleSystemManager::xfer - Unable to allocate particle system '%s'\n",
- systemName.str() ));
- throw SC_INVALID_DATA;
- } // end if
- // read system data
- xfer->xferSnapshot( system );
- } // end for, i
- } // end else, load
- } // end particleSystemManager
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemManager::loadPostProcess( void )
- {
- } // end loadPostProcess
- // ------------------------------------------------------------------------------------------------
- /** Output particle system statistics to the screen
- * @todo Implement a real console (MSB) */
- // ------------------------------------------------------------------------------------------------
- void ParticleSystemDebugDisplay( DebugDisplayInterface *dd, void *, FILE *fp )
- {
- if (!dd)
- return;
- dd->setCursorPos( 0, 0 );
- dd->setRightMargin( 2 );
-
- dd->printf( "Total Particles: %d\n", TheParticleSystemManager->getParticleCount() );
- dd->printf( "Total Particles (On Screen): %d\n", TheParticleSystemManager->getOnScreenParticleCount());
- dd->printf( "Total Particle Systems: %d\n", TheParticleSystemManager->getParticleSystemCount() );
- ParticleSystemManager::ParticleSystemList list = TheParticleSystemManager->getAllParticleSystems();
- ParticleSystemManager::ParticleSystemList::iterator it;
- std::map<AsciiString, Int> templateMap;
- std::map<AsciiString, Int> templateMapParticleCount;
- std::map<AsciiString, Int>::iterator templateMapIt;
- std::map<AsciiString, Int>::iterator templateMapParticleCountIt;
- for ( it = list.begin(); it != list.end(); ++it )
- {
- AsciiString templateName = (*it)->getTemplate()->getName();
- templateMapIt = templateMap.find(templateName);
- if (templateMapIt == templateMap.end())
- {
- templateMap.insert(std::make_pair(templateName, 1));
- templateMapParticleCount.insert(std::make_pair(templateName, (*it)->getParticleCount()));
- }
- else
- {
- ++templateMapIt->second;
- templateMapParticleCountIt = templateMapParticleCount.find(templateName);
- if (templateMapParticleCountIt != templateMapParticleCount.end())
- templateMapParticleCountIt->second += (*it)->getParticleCount();
- }
- }
- for (templateMapIt = templateMap.begin(); templateMapIt != templateMap.end(); ++templateMapIt)
- {
- templateMapParticleCountIt = templateMapParticleCount.find(templateMapIt->first);
- dd->printf(" %s: %d instances", templateMapIt->first.str(), templateMapIt->second);
- if (templateMapParticleCountIt != templateMapParticleCount.end())
- dd->printf(" (Avg per system %.2f)", INT_TO_REAL(templateMapParticleCountIt->second) / templateMapIt->second);
- dd->printf("\n");
- }
- }
- // ------------------------------------------------------------------------------------------------
|