| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442 |
- /*
- ** Command & Conquer Generals Zero Hour(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_angleZ = 0.0f;
- m_angularDamping = 0.0f;
- 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
- Real tempAngle=0; //temporary value to save out for backwards compatibility when we supported x,y
- xfer->xferReal( &tempAngle );
- xfer->xferReal( &tempAngle );
- xfer->xferReal( &m_angleZ );
- // angular rate
- xfer->xferReal( &tempAngle );
- xfer->xferReal( &tempAngle );
- 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.
- static Real angleBetween(const Coord2D *vecA, const Coord2D *vecB);
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // 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_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_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;
- 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 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
- ParticleSystemInfo::WindMotion windMotion = m_system->getWindMotion();
- // see if we should even do anything
- if( windMotion != ParticleSystemInfo::WIND_MOTION_NOT_USED )
- doWindMotion();
- // update orientation
- m_angleZ += m_angularRateZ;
- m_angularRateZ *= m_angularDamping;
- if (m_particleUpTowardsEmitter) {
- // adjust the up position back towards the particle
- static const Coord2D upVec = { 0.0f, 1.0f };
- Coord2D emitterDir;
- emitterDir.x = m_pos.x - m_emitterPos.x;
- emitterDir.y = m_pos.y - m_emitterPos.y;
- m_angleZ = (angleBetween(&upVec, &emitterDir) + PI);
- }
- // update size
- m_size += m_sizeRate;
- m_sizeRate *= m_sizeRateDamping;
- //
- // Update alpha (if used)
- //
- if (m_system->getShaderType() != ParticleSystemInfo::ADDITIVE)
- {
- 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.z=m_accel.y=m_accel.x= 0.0f;
- // 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 )
- {
- // 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 )
- {
- 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 + m_color.green + m_color.blue) <= 0.06f)
- return true;
- }
- return false;
- case ParticleSystemInfo::ALPHA:
- // if alpha is zero, this particle is invisible
- if (m_alpha < 0.02f)
- 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 * m_color.green * m_color.blue) > 0.95f)
- 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 = INVALID_DRAWABLE_ID;
- xfer->xferDrawableID( &drawableID ); //saving for backwards compatibility when we supported drawables.
- // 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
- GameClientRandomVariable tempRandom; //for backwards compatibility when we supported x,y
- xfer->xferUser( &tempRandom, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &tempRandom, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &m_angleZ, sizeof( GameClientRandomVariable ) );
- // angular rate
- xfer->xferUser( &tempRandom, sizeof( GameClientRandomVariable ) );
- xfer->xferUser( &tempRandom, 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_skipParentXfrm = false;
- 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_angleZ = sysTemplate->m_angleZ;
- 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_angleZ = m_angleZ.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_colorKey[i] = m_colorKey[i];
- }
- /*
- info.m_color.red = m_color.red.getValue();
- info.m_color.green = m_color.green.getValue();
- info.m_color.blue = m_color.blue.getValue();
- */
- 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
- if (m_windMotion != ParticleSystemInfo::WIND_MOTION_NOT_USED )
- 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();
- }
- }
- else if (m_attachedToObjectID)
- {
- Object *objectAttachedTo = TheGameLogic->findObjectByID( m_attachedToObjectID );
- if (objectAttachedTo)
- {
- if (!isShrouded)
- isShrouded = (objectAttachedTo->getShroudedStatus(localPlayerIndex) >= OBJECTSHROUD_FOGGED);
-
- const Drawable * draw = objectAttachedTo->getDrawable();
- if ( draw )
- parentXfrm = draw->getTransformMatrix();
- else
- parentXfrm = objectAttachedTo->getTransformMatrix();
-
- m_lastPos = m_pos;
- m_pos = *objectAttachedTo->getPosition();
- }
- else
- {
- // Drawable has been destroyed - lose our attachment to it
- m_attachedToObjectID = INVALID_ID;
- // destroy ourselves
- destroy();
- }
- }
- if (parentXfrm)
- {
- if (m_skipParentXfrm)
- {
- //this particle system is already in world space so no need to apply parent xform.
- m_transform = m_localTransform;
- }
- else
- {
- // 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_angleZ = info->m_angleZ;
- 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 ) },
- { "AngleZ", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemTemplate, m_angleZ ) },
- { "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");
- }
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- static Real angleBetween(const Coord2D *vecA, const Coord2D *vecB)
- {
- if (!(vecA && vecA->length() && vecB && vecB->length())) {
- return 0.0;
- }
- Real lengthA = vecA->length();
- Real lengthB = vecB->length();
- Real dotProduct = (vecA->x * vecB->x + vecA->y * vecB->y);
- Real cosTheta = dotProduct / (lengthA * lengthB);
- // If the dotproduct is 0.0, then they are orthogonal
- if (dotProduct == 0.0f) {
- if (vecB->x > 0) {
- return PI;
- }
- return 0.0f;
- }
- Real theta = ACos( cosTheta );
- if (vecB->x > 0) {
- return theta;
- }
-
- return -theta;
- }
|