| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378 |
- /*
- ** Command & Conquer Renegade(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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : Commando *
- * *
- * $Archive:: /Commando/Code/Combat/WeatherMgr.cpp $*
- * *
- * Author:: Ian Leslie *
- * *
- * $Modtime:: 1/02/02 1:26p $*
- * *
- * $Revision:: 27 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- // Includes.
- #include "weathermgr.h"
- #include "apppackettypes.h"
- #include "assetmgr.h"
- #include "audiblesound.h"
- #include "camera.h"
- #include "chunkio.h"
- #include "combat.h"
- #include "gameobjmanager.h"
- #include "gametype.h"
- #include "light.h"
- #include "dx8indexbuffer.h"
- #include "dx8wrapper.h"
- #include "phys.h"
- #include "physcoltest.h"
- #include "pscene.h"
- #include "rinfo.h"
- #include "scene.h"
- #include "sortingrenderer.h"
- #include "soundenvironment.h"
- #include "wwaudio.h"
- #include "wwmemlog.h"
- // Singletons.
- WeatherMgrClass _TheWeatherMgr;
- // Static data.
- DEFINE_AUTO_POOL(WeatherSystemClass::RayStruct, WeatherSystemClass::GROWTH_STEP);
- DEFINE_AUTO_POOL(WeatherSystemClass::ParticleStruct, WeatherSystemClass::GROWTH_STEP);
- Random2Class WeatherSystemClass::_RandomNumber (0x60486223);
- unsigned WeatherSystemClass::_GlobalParticleCount = 0;
- SoundEnvironmentClass *WeatherMgrClass::_SoundEnvironment;
- WeatherParameterClass WeatherMgrClass::_Parameters [PARAMETER_COUNT];
- bool WeatherMgrClass::_Prime;
- bool WeatherMgrClass::_Imported;
- unsigned WeatherMgrClass::_WindOverrideCount;
- unsigned WeatherMgrClass::_PrecipitationOverrideCount;
- WindClass *WeatherMgrClass::_Wind;
- WeatherSystemClass *WeatherMgrClass::_Precipitation [PRECIPITATION_COUNT];
- bool WeatherMgrClass::_FogEnabled;
- bool WeatherMgrClass::_Dirty;
- /***********************************************************************************************
- * WindClass::WindClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/09/01 IML : Created. *
- *=============================================================================================*/
- WindClass::WindClass (float heading, float speed, float variability, SoundEnvironmentClass *soundenvironment)
- : Velocity (0.0f, 0.0f),
- SoundEnvironment (soundenvironment)
- {
- const char *windsamplename = "Wind01";
- Set (heading, speed, variability);
- for (unsigned octave = 0; octave < OCTAVE_COUNT; octave++) {
- Theta [octave] = 0.0l;
- }
- // Create the wind sound effect.
- Sound = WWAudioClass::Get_Instance()->Create_Sound (windsamplename, NULL, 0, CLASSID_2D);
- if (Sound != NULL) {
- SoundEnvironment->Add_User();
- Sound->Set_Volume (0.0f);
- Sound->Play();
- }
- }
- /***********************************************************************************************
- * WindClass::~WindClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/09/01 IML : Created. *
- *=============================================================================================*/
- WindClass::~WindClass()
- {
- // Remove wind sound effect.
- if (Sound != NULL) {
- Sound->Stop();
- REF_PTR_RELEASE (Sound);
- SoundEnvironment->Remove_User();
- }
- }
- /***********************************************************************************************
- * WindClass::Set -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/09/01 IML : Created. *
- *=============================================================================================*/
- void WindClass::Set (float heading, float speed, float variability)
- {
- WWASSERT (speed >= 0.0f);
- Heading = DEG_TO_RADF (heading);
- Speed = speed;
- Variability = variability;
- }
- /***********************************************************************************************
- * WindClass::Update -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/09/01 IML : Created. *
- *=============================================================================================*/
- bool WindClass::Update()
- {
- const double frequency [OCTAVE_COUNT] = {0.5l, 0.2l};
- const double twopi = WWMATH_PI * 2.0l;
- float h, speed;
- if (Variability > 0.0f) {
- float f = 0.0f;
- int d;
- for (unsigned octave = 0; octave < OCTAVE_COUNT; octave++) {
- Theta [octave] += WW3D::Get_Frame_Time() * 0.001l * frequency [octave];
- d = floorf (Theta [octave] / twopi);
- if (d >= 1) Theta [octave] -= d * twopi;
- f += sinf (Theta [octave]);
- }
- speed = Speed - (Speed * ((f + 1.0f) * 0.5f) * Variability);
- } else {
- speed = Speed;
- }
- h = Heading + (0.5f * WWMATH_PI);
- Velocity.Set (cosf (h) * speed, sinf (h) * speed);
- // Update wind sound effect.
- if (Sound != NULL) {
- const float maxvolumespeed = 10.0f;
- float attenuation;
- // Precalculate volume attenuation based on speed.
- attenuation = (0.5f * (MIN (Speed, maxvolumespeed) + MIN (speed, maxvolumespeed))) / maxvolumespeed;
- Sound->Set_Volume (SoundEnvironment->Get_Amplitude() * attenuation);
- }
- // Is the wind essentially idle (ie. it is not contributing to the scene visually or audibly)?
- return (Speed > 0.0f);
- }
- /***********************************************************************************************
- * WeatherSystemClass::WeatherSystemClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- WeatherSystemClass::WeatherSystemClass (PhysicsSceneClass *scene,
- float emittersize,
- float emitterheight,
- float particledensity,
- float particlesperunitlength,
- float particlewidth,
- float particleheight,
- float particlespeed,
- const Vector2 &pageoffset,
- const Vector2 &pagesize,
- unsigned pagecount,
- bool staticpageexists,
- float minstatictime,
- float maxstatictime,
- RenderModeEnum rendermode,
- bool decayaftercollision,
- bool prime)
- : Scene (scene),
- EmitterSize (emittersize),
- EmitterHeight (emitterheight),
- EmitterPosition (Vector3 (0.0f, 0.0f, 0.0f)),
- ParticlesPerUnitLength (particlesperunitlength),
- ParticleSpeed (particlespeed),
- HalfParticleWidth (particlewidth * 0.5f),
- HalfParticleHeight (particleheight * 0.5f),
- RayHead (NULL),
- RayCount (0),
- RaySpawnPtr (NULL),
- RayUpdatePtr (NULL),
- ParticleHead (NULL),
- ParticleCount (0),
- MinRayEndZ (FLT_MAX),
- SpawnCountFraction (0.0f),
- PageCount (pagecount),
- StaticPageExists (staticpageexists),
- MinStaticTime (minstatictime),
- MaxStaticTime (maxstatictime),
- RenderMode (rendermode),
- DecayAfterCollision (decayaftercollision),
- CameraPositionValid (false)
- {
- const char *texturename = "WeatherParticles.tga";
- const TextureClass::MipCountType mipcount = TextureClass::MIP_LEVELS_5;
- const float oopagecount = 1.0f / pagecount;
- WWASSERT (particlespeed >= 0.0f);
- // How old is the weather system?
- Age = prime ? MAX_AGE : 0.0f;
- // Set density of system.
- Set_Density (particledensity);
- // Get the scene's bounding box.
- scene->Get_Level_Extents (SceneMin, SceneMax);
- // Expand the bounding box by a small amount so that we can distinguish between collisions with geometry and
- // collisions with the bounding box.
- SceneMin.Z -= 1.0f;
- SceneMax.Z += 1.0f;
- // Initialize an index buffer.
- #if WEATHER_PARTICLE_SORT
- IndexBuffer = NEW_REF (SortingIndexBufferClass, (MAX_IB_PARTICLE_COUNT * VERTICES_PER_TRIANGLE));
- #else
- IndexBuffer = NEW_REF (DX8IndexBufferClass, (MAX_IB_PARTICLE_COUNT * VERTICES_PER_TRIANGLE));
- #endif
- {
- SortingIndexBufferClass::WriteLockClass lock (IndexBuffer);
- unsigned short *indices = lock.Get_Index_Array();
- for (unsigned i = 0; i < MAX_IB_PARTICLE_COUNT * VERTICES_PER_TRIANGLE; i++) {
- *indices++ = i;
- }
- }
- // Configure material.
- Material = VertexMaterialClass::Get_Preset (VertexMaterialClass::PRELIT_NODIFFUSE);
- // Configure shader.
- Shader = ShaderClass::_PresetAlphaShader;
- Shader.Set_Primary_Gradient (ShaderClass::GRADIENT_MODULATE);
- Shader.Set_Cull_Mode (ShaderClass::CULL_MODE_DISABLE);
- Shader.Enable_Fog ("WeatherSystemClass");
- // Configure texture.
- Texture = WW3DAssetManager::Get_Instance()->Get_Texture (texturename, mipcount);
- Texture->Set_U_Addr_Mode (TextureClass::TEXTURE_ADDRESS_CLAMP);
- Texture->Set_V_Addr_Mode (TextureClass::TEXTURE_ADDRESS_CLAMP);
- Set_Translucent (true);
- // Configure texture coordinates according to given page count.
- // NOTE: Split the texture into vertical pages.
- WWASSERT (pagecount > 0);
- TextureArray = new Vector2 [pagecount * VERTICES_PER_TRIANGLE];
- WWASSERT (TextureArray != NULL);
- for (unsigned page = 0; page < pagecount; page++) {
- TextureArray [page * VERTICES_PER_TRIANGLE + 0].Set (pageoffset.U + (((page + 0.5f) * oopagecount) * pagesize.U), pageoffset.V + 0.0f);
- TextureArray [page * VERTICES_PER_TRIANGLE + 1].Set (pageoffset.U + (((page + 1.0f) * oopagecount) * pagesize.U), pageoffset.V + pagesize.V);
- TextureArray [page * VERTICES_PER_TRIANGLE + 2].Set (pageoffset.U + (((page + 0.0f) * oopagecount) * pagesize.U), pageoffset.V + pagesize.V);
- }
- }
- /***********************************************************************************************
- * WeatherSystemClass::WeatherSystemClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- WeatherSystemClass::~WeatherSystemClass()
- {
- RayStruct *rayptr;
- ParticleStruct *particleptr;
- // Clean-up rays.
- rayptr = RayHead;
- while (rayptr != NULL) {
- RayStruct *nextrayptr;
- nextrayptr = rayptr->Next;
- delete rayptr;
- rayptr = nextrayptr;
- RayCount--;
- }
- WWASSERT (RayCount == 0);
- // Clean-up particles.
- particleptr = ParticleHead;
- while (particleptr != NULL) {
- ParticleStruct *nextparticleptr = particleptr->Next;
- Kill (particleptr);
- particleptr = nextparticleptr;
- }
- WWASSERT (ParticleCount == 0);
- REF_PTR_RELEASE (Material);
- delete [] TextureArray;
- REF_PTR_RELEASE (Texture);
- REF_PTR_RELEASE (IndexBuffer);
- }
- /***********************************************************************************************
- * WeatherSystemClass::Set_Density -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherSystemClass::Set_Density (float density)
- {
- unsigned raycount;
- int signedcount, r;
- RayStruct *rayptr;
- // Calculate no. of rays required.
- ParticleDensity = density;
- raycount = Spawn_Count (1.0f) / (ParticlesPerUnitLength * ParticleSpeed);
- // Is the ray count increasing or decreasing in size?
- signedcount = ((int) RayCount) - ((int) raycount);
- if (signedcount < 0) {
- // Add new, uninitialized rays to head of list.
- for (r = signedcount; r < 0; r++) {
- rayptr = new RayStruct;
- WWASSERT (rayptr != NULL);
- rayptr->Next = RayHead;
- rayptr->Initialized = false;
- RayHead = rayptr;
- }
- // If necessary, initialize the spawn and update pointers.
- if (RaySpawnPtr == NULL) RaySpawnPtr = RayHead;
- if (RayUpdatePtr == NULL) RayUpdatePtr = RayHead;
- } else {
- // Remove rays from head of list.
- rayptr = RayHead;
- for (r = 0; r < signedcount; r++) {
- RayStruct *nextrayptr;
- if (rayptr == NULL) break;
- nextrayptr = rayptr->Next;
- // If this ray is referenced by the spawn or update pointers then change them.
- if (RaySpawnPtr == rayptr) RaySpawnPtr = nextrayptr;
- if (RayUpdatePtr == rayptr) RayUpdatePtr = nextrayptr;
- delete rayptr;
- rayptr = nextrayptr;
- }
- RayHead = rayptr;
- }
- RayCount = raycount;
- }
- /***********************************************************************************************
- * WeatherSystemClass::Update -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherSystemClass::Update (WindClass *wind, const Vector3 &cameraposition)
- {
- struct BoundingBoxStruct {
- Vector2 Min, Max;
- };
- const unsigned randomness = 10000;
- const float oorandomness = 1.0f / randomness;
- const float overlapdelta = EmitterSize * 2.0f;
- const unsigned rayupdatecount = MAX (RayCount * 0.018f, 1);
- Vector3 oldemitterposition;
- float ooz;
- Vector3 emitterdirection, emitteroffset;
- Vector3 projectedemitterposition;
- BoundingBoxStruct emitterbounds;
- float deltax, deltay;
- BoundingBoxStruct nonoverlapregions [2];
- float regionthreshold;
- Vector3 sceneminoffset, scenemaxoffset;
- Vector2 raystartoffset;
- RayStruct *rayptr;
- float spawncountfraction;
- float alpha, beta;
- Vector2 range;
- Vector3 minrayendposition;
- float l, boxoffset;
- ParticleStruct *particleptr;
- float s;
- unsigned spawncount;
- float time;
- oldemitterposition = EmitterPosition;
- // Calculate particle velocity based on wind.
- if (wind != NULL) {
- ParticleVelocity.Set (wind->Get_Velocity().X, wind->Get_Velocity().Y, -ParticleSpeed);
- } else {
- ParticleVelocity.Set (0.0f, 0.0f, -ParticleSpeed);
- }
- // Calculate new emitter position.
- ooz = 1.0f / ParticleVelocity.Z;
- emitterdirection.Set (ParticleVelocity.X * ooz, ParticleVelocity.Y * ooz, 1.0f);
- emitteroffset = EmitterHeight * emitterdirection;
- EmitterPosition = cameraposition + emitteroffset;
- // Define bounding box for new emitter area.
- emitterbounds.Min.Set (EmitterPosition.X - EmitterSize, EmitterPosition.Y - EmitterSize);
- emitterbounds.Max.Set (EmitterPosition.X + EmitterSize, EmitterPosition.Y + EmitterSize);
- // Calculate new regions that define the areas of non-overlap between the old and new emitter positions.
- // Project the old emitter onto the plane of the new emitter.
- projectedemitterposition = oldemitterposition + ((EmitterPosition.Z - oldemitterposition.Z) * emitterdirection);
- // If the old and new emitters partially overlap...
- deltax = WWMath::Fabs (EmitterPosition.X - projectedemitterposition.X);
- deltay = WWMath::Fabs (EmitterPosition.Y - projectedemitterposition.Y);
- if ((deltax < overlapdelta) && (deltay < overlapdelta) && (EmitterPosition != projectedemitterposition)) {
- float area0, area1;
- // Compare X-extents.
- if (EmitterPosition.X < projectedemitterposition.X) {
- nonoverlapregions [0].Min.X = emitterbounds.Min.X;
- nonoverlapregions [0].Max.X = projectedemitterposition.X - EmitterSize;
- nonoverlapregions [1].Min.X = nonoverlapregions [0].Max.X;
- nonoverlapregions [1].Max.X = emitterbounds.Max.X;
- } else {
- nonoverlapregions [0].Min.X = projectedemitterposition.X + EmitterSize;
- nonoverlapregions [0].Max.X = emitterbounds.Max.X;
- nonoverlapregions [1].Min.X = emitterbounds.Min.X;
- nonoverlapregions [1].Max.X = nonoverlapregions [0].Min.X;
- }
- nonoverlapregions [0].Min.Y = emitterbounds.Min.Y;
- nonoverlapregions [0].Max.Y = emitterbounds.Max.Y;
- // Compare Y-extents.
- if (EmitterPosition.Y < projectedemitterposition.Y) {
- nonoverlapregions [1].Min.Y = emitterbounds.Min.Y;
- nonoverlapregions [1].Max.Y = projectedemitterposition.Y - EmitterSize;
- } else {
- nonoverlapregions [1].Min.Y = projectedemitterposition.Y + EmitterSize;
- nonoverlapregions [1].Max.Y = emitterbounds.Max.Y;
- }
- area0 = (nonoverlapregions [0].Max.X - nonoverlapregions [0].Min.X) * (nonoverlapregions [0].Max.Y - nonoverlapregions [0].Min.Y);
- area1 = (nonoverlapregions [1].Max.X - nonoverlapregions [1].Min.X) * (nonoverlapregions [1].Max.Y - nonoverlapregions [1].Min.Y);
- if (area0 == 0.0f) {
- // Always select region 1.
- regionthreshold = -FLT_MAX;
- } else {
- if (area1 == 0.0f) {
- // Always select region 0.
- regionthreshold = +FLT_MAX;
- } else {
- // Select either region 0 or region 1 weighted by area.
- regionthreshold = area0 / (area0 + area1);
- }
- }
- } else {
- // No overlap or complete overlap: region 0 is emitter area, region 1 is not used.
- nonoverlapregions [0] = emitterbounds;
- regionthreshold = +FLT_MAX;
- }
- // Calculate offset of projection of ray start from old to new emitter.
- raystartoffset = (EmitterPosition.Z - oldemitterposition.Z) * Vector2 (emitterdirection.X, emitterdirection.Y);
- // Precalculate offsets to intersection with upper and lower planes of scene bounds from emitter position.
- sceneminoffset = (SceneMin.Z - EmitterPosition.Z) * emitterdirection;
- scenemaxoffset = (SceneMax.Z - EmitterPosition.Z) * emitterdirection;
- // Iterate over all rays...
- spawncountfraction = 0.0f;
- rayptr = RayHead;
- while (rayptr != NULL) {
- Vector3 raystartposition;
- // Does this ray need to be initialized?
- if (!rayptr->Initialized) {
- // Randomly allocate a new ray start position from the entire emitter region.
- alpha = _RandomNumber (0, randomness) * oorandomness;
- beta = _RandomNumber (0, randomness) * oorandomness;
- range = emitterbounds.Max - emitterbounds.Min;
- range.Scale (alpha, beta);
- rayptr->StartPosition = emitterbounds.Min + range;
- rayptr->Initialized = true;
- rayptr->RayCast = true;
- } else {
- // Project the ray's emitter position onto the plane of the new emitter.
- rayptr->StartPosition += raystartoffset;
- // Does the ray fall outside the emitter (and therefore needs to be raycast)?
- rayptr->RayCast = (rayptr->StartPosition.X < emitterbounds.Min.X) ||
- (rayptr->StartPosition.X > emitterbounds.Max.X) ||
- (rayptr->StartPosition.Y < emitterbounds.Min.Y) ||
- (rayptr->StartPosition.Y > emitterbounds.Max.Y);
- if (rayptr->RayCast) {
- unsigned regionindex;
- // Randomly allocate a new ray start position from one of the non-overlap regions.
- if ((_RandomNumber (0, randomness) * oorandomness) < regionthreshold) {
- regionindex = 0;
- } else {
- regionindex = 1;
- }
- alpha = _RandomNumber (0, randomness) * oorandomness;
- beta = _RandomNumber (0, randomness) * oorandomness;
- range = nonoverlapregions [regionindex].Max - nonoverlapregions [regionindex].Min;
- range.Scale (alpha, beta);
- rayptr->StartPosition = nonoverlapregions [regionindex].Min + range;
- } else {
- // Next ray.
- rayptr = rayptr->Next;
- continue;
- }
- }
- raystartposition.Set (rayptr->StartPosition.X, rayptr->StartPosition.Y, EmitterPosition.Z);
- // Raycast to find the ray's collision point with the environment.
- {
- Vector3 raycaststartpoint (raystartposition + scenemaxoffset);
- Vector3 raycastendpoint (raystartposition + sceneminoffset);
- LineSegClass raycast (raycaststartpoint, raycastendpoint);
- CastResultStruct rayresult;
- PhysRayCollisionTestClass raytest (raycast, &rayresult, TERRAIN_ONLY_COLLISION_GROUP, COLLISION_TYPE_PROJECTILE);
- Scene->Cast_Ray (raytest);
- raycast.Compute_Point (raytest.Result->Fraction, &(rayptr->EndPosition));
- if (raytest.Result->Fraction < 1.0f) {
- rayptr->ValidSurfaceNormal = true;
- rayptr->SurfaceNormal = raytest.Result->Normal;
- } else {
- rayptr->ValidSurfaceNormal = false;
- }
- }
- rayptr->ParticleVelocity = ParticleVelocity;
- if ((Age > 0.0f) && (Can_Spawn (rayptr))) {
- float s;
- unsigned spawncount;
- // Spawn some particles along the ray.
- // NOTE: For accuracy, accumulate fractional spawncounts so that they can be used on a later ray.
- s = ParticlesPerUnitLength * (rayptr->EndPosition - raystartposition).Quick_Length();
- spawncount = floor (s);
- spawncountfraction += s - spawncount;
- if (spawncountfraction >= 1.0f) {
- spawncountfraction -= 1.0f;
- spawncount++;
- }
- for (unsigned p = 0; p < spawncount; p++) {
- Spawn (rayptr);
- }
- }
- // Update minimum ray end Z.
- if (rayptr->EndPosition.Z < MinRayEndZ) {
- MinRayEndZ = rayptr->EndPosition.Z;
- }
- // Next ray.
- rayptr = rayptr->Next;
- }
- // Now iterate over rayupdatecount rays and randomize them so that the ray 'pattern' is
- // not discernable to the user (because it is constantly changing) and also to take
- // account of the new particle velocity.
- if (RayUpdatePtr != NULL) {
- for (unsigned r = 0; r < rayupdatecount; r++) {
- // NOTE: Only need to randomize those rays that have not just been relocated inside the emitter.
- if (!RayUpdatePtr->RayCast) {
- // Randomly allocate a new ray start position from the entire emitter region.
- alpha = _RandomNumber (0, randomness) * oorandomness;
- beta = _RandomNumber (0, randomness) * oorandomness;
- range = emitterbounds.Max - emitterbounds.Min;
- range.Scale (alpha, beta);
- RayUpdatePtr->StartPosition = emitterbounds.Min + range;
- // Raycast to find the ray's collision point with the environment.
- {
- Vector3 raystartposition (RayUpdatePtr->StartPosition.X, RayUpdatePtr->StartPosition.Y, EmitterPosition.Z);
- Vector3 raycaststartpoint (raystartposition + scenemaxoffset);
- Vector3 raycastendpoint (raystartposition + sceneminoffset);
- LineSegClass raycast (raycaststartpoint, raycastendpoint);
- CastResultStruct rayresult;
- PhysRayCollisionTestClass raytest (raycast, &rayresult, TERRAIN_ONLY_COLLISION_GROUP, COLLISION_TYPE_PROJECTILE);
- Scene->Cast_Ray (raytest);
- raycast.Compute_Point (raytest.Result->Fraction, &(RayUpdatePtr->EndPosition));
- if (raytest.Result->Fraction < 1.0f) {
- RayUpdatePtr->ValidSurfaceNormal = true;
- RayUpdatePtr->SurfaceNormal = raytest.Result->Normal;
- } else {
- RayUpdatePtr->ValidSurfaceNormal = false;
- }
- }
- RayUpdatePtr->ParticleVelocity = ParticleVelocity;
- // Update minimum ray end Z.
- if (RayUpdatePtr->EndPosition.Z < MinRayEndZ) {
- MinRayEndZ = RayUpdatePtr->EndPosition.Z;
- }
- }
- // Next ray. If necessary, wrap around to head of list.
- RayUpdatePtr = RayUpdatePtr->Next;
- if (RayUpdatePtr == NULL) RayUpdatePtr = RayHead;
- }
- }
- // Calculate a bounding box for the render object that encompasses the rays.
- // NOTE 0: For efficiency, calculate the parallelepiped that is generated by projecting
- // the emitter area onto the plane that contains the lowest ray end point and put
- // a bounding box around this.
- // NOTE 1: Make the bounding box a little bigger to account for the particle point size.
- minrayendposition = EmitterPosition + ((MinRayEndZ - EmitterPosition.Z) * emitterdirection);
- l = MAX (HalfParticleWidth, HalfParticleHeight);
- boxoffset = EmitterSize + l;
- ObjectMax.Set (MAX (EmitterPosition.X, minrayendposition.X) + boxoffset, MAX (EmitterPosition.Y, minrayendposition.Y) + boxoffset, MAX (EmitterPosition.Z, minrayendposition.Z) + l);
- ObjectMin.Set (MIN (EmitterPosition.X, minrayendposition.X) - boxoffset, MIN (EmitterPosition.Y, minrayendposition.Y) - boxoffset, MIN (EmitterPosition.Z, minrayendposition.Z) - l);
- // Flag that the object bounding box has been modified.
- Invalidate_Cached_Bounding_Volumes();
- // Iterate over all particles...
- time = WW3D::Get_Frame_Time() * 0.001f;
- particleptr = ParticleHead;
- while (particleptr != NULL) {
- Vector2 emitterposition;
- bool outside;
- ParticleStruct *nextparticleptr = particleptr->Next;
- // Advance time.
- particleptr->ElapsedTime += time;
- // Has it expired?
- if (particleptr->ElapsedTime >= particleptr->LifeTime) {
- Kill (particleptr);
- particleptr = nextparticleptr;
- continue;
- }
- // Has it just collided?
- if (particleptr->ElapsedTime >= particleptr->CollisionTime) {
- if (particleptr->Velocity.Z != 0.0f) {
- // Place the particle at the collision point.
- particleptr->Velocity.Set (0.0f, 0.0f, 0.0f);
- particleptr->CurrentPosition = particleptr->CollisionPosition;
- if (StaticPageExists) particleptr->Page = PageCount - 1;
- particleptr->RenderMode = RENDER_MODE_SURFACE_ALIGNED;
- }
- } else {
- // Advance position.
- particleptr->CurrentPosition += particleptr->Velocity * time;
- }
- // Project the particle's position onto the plane of the new emitter.
- emitterposition = Vector2 (particleptr->CurrentPosition.X, particleptr->CurrentPosition.Y) + ((EmitterPosition.Z - particleptr->CurrentPosition.Z) * particleptr->UnitZVelocity);
- // Does the particle fall outside the emitter?
- outside = (emitterposition.X < emitterbounds.Min.X) ||
- (emitterposition.X > emitterbounds.Max.X) ||
- (emitterposition.Y < emitterbounds.Min.Y) ||
- (emitterposition.Y > emitterbounds.Max.Y);
- if (outside) {
- Kill (particleptr);
- }
- particleptr = nextparticleptr;
- }
- // Spawn any new particles that need to be spawned on this update.
- // NOTE: For accuracy, accumulate fractional spawncounts so that they can be used on a later iteration.
- s = Spawn_Count (time);
- spawncount = floor (s);
- SpawnCountFraction += s - spawncount;
- if (SpawnCountFraction >= 1.0f) {
- SpawnCountFraction -= 1.0f;
- spawncount++;
- }
- for (unsigned p = 0; p < spawncount; p++) {
- Spawn();
- }
- // Advance weather system age.
- // NOTE: To prevent floating point overflow, don't advance the age past some maximum.
- if (Age < MAX_AGE) Age += time;
- // Is the weather still active (ie. it is contributing to the scene visually or audibly)?
- return ((ParticleDensity > 0.0f) || (ParticleCount > 0));
- }
- /***********************************************************************************************
- * WeatherSystemClass::Spawn -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherSystemClass::Spawn (RayStruct *suppliedrayptr)
- {
- const unsigned maxparticlecount = USHRT_MAX / (2 * VERTICES_PER_TRIANGLE);
- // Due to a limitation in the underlying rendering API, there cannot be more than USHRT_MAX
- // total vertices in the system. Conservatively restrict this to half of this to compensate
- // for other primitives in the system.
- if (_GlobalParticleCount < maxparticlecount) {
- RayStruct *rayptr;
- if (suppliedrayptr == NULL) {
- // Assign a ray to this particle.
- // If there are no rays to assign then return failure to spawn.
- if (RaySpawnPtr != NULL) {
- rayptr = RaySpawnPtr;
- RaySpawnPtr = RaySpawnPtr->Next;
- if (RaySpawnPtr == NULL) RaySpawnPtr = RayHead;
- } else {
- return (false);
- }
- } else {
- rayptr = suppliedrayptr;
- }
- // Ensure that this ray's endpoint lies below the emitter (otherwise there is an obstruction
- // between the ray's source and the emitter).
- if (Can_Spawn (rayptr)) {
- const unsigned randomness = 1000;
- const float oorandomness = 1.0f / randomness;
- const float ooz = 1.0f / rayptr->ParticleVelocity.Z;
- const float collisiontime = (rayptr->EndPosition.Z - EmitterPosition.Z) * ooz;
- ParticleStruct *particleptr;
- particleptr = new ParticleStruct;
- WWASSERT (particleptr != NULL);
- // Add this particle to the head of the list.
- if (ParticleHead != NULL) {
- ParticleHead->Prev = particleptr;
- }
- particleptr->Prev = NULL;
- particleptr->Next = ParticleHead;
- ParticleHead = particleptr;
- // Increment the no. of particles.
- ParticleCount++;
- // Increment total no. of global weather particles.
- _GlobalParticleCount++;
- particleptr->UnitZVelocity.Set (rayptr->ParticleVelocity.X * ooz, rayptr->ParticleVelocity.Y * ooz);
- particleptr->CollisionTime = collisiontime;
- particleptr->CollisionPosition = rayptr->EndPosition;
- // If the ray does not have a valid surface normal then the ray's end position intersects the level's bounding box.
- // In this case it is not necessary to sustain the particle past the collision time.
- if (rayptr->ValidSurfaceNormal) {
- particleptr->LifeTime = collisiontime + WWMath::Lerp (MinStaticTime, MaxStaticTime, _RandomNumber (0, randomness) * oorandomness);
- particleptr->SurfaceNormal = rayptr->SurfaceNormal;
- } else {
- particleptr->LifeTime = collisiontime;
- }
- if (suppliedrayptr == NULL) {
- // Start particle at emitter.
- particleptr->ElapsedTime = 0.0f;
- particleptr->Velocity = rayptr->ParticleVelocity;
- particleptr->CurrentPosition = Vector3 (rayptr->StartPosition.X, rayptr->StartPosition.Y, EmitterPosition.Z);
- particleptr->Page = _RandomNumber (0, PageCount - (StaticPageExists) ? 2 : 1);
- particleptr->RenderMode = RenderMode;
- } else {
- float t;
- // Advance the particle some random amount in time.
- // NOTE: The particle cannot have existed longer than the weather system itself.
- t = _RandomNumber (0, randomness) * oorandomness * particleptr->LifeTime;
- particleptr->ElapsedTime = MIN (t, Age);
- if (particleptr->ElapsedTime >= particleptr->CollisionTime) {
- particleptr->Velocity.Set (0.0f, 0.0f, 0.0f);
- particleptr->CurrentPosition = rayptr->EndPosition;
- if (StaticPageExists) {
- particleptr->Page = PageCount - 1;
- } else {
- particleptr->Page = _RandomNumber (0, PageCount - 1);
- }
- particleptr->RenderMode = RENDER_MODE_SURFACE_ALIGNED;
- } else {
- particleptr->Velocity = rayptr->ParticleVelocity;
- particleptr->CurrentPosition = Vector3 (rayptr->StartPosition.X, rayptr->StartPosition.Y, EmitterPosition.Z) + (particleptr->Velocity * particleptr->ElapsedTime);
- particleptr->Page = _RandomNumber (0, PageCount - (StaticPageExists) ? 2 : 1);
- particleptr->RenderMode = RenderMode;
- }
- }
- return (true);
- }
- }
- return (false);
- }
- /***********************************************************************************************
- * WeatherSystemClass::Kill -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherSystemClass::Kill (ParticleStruct *particleptr)
- {
- WWASSERT (ParticleCount > 0);
- // Remove this particle from the list.
- if (particleptr->Prev != NULL) {
- particleptr->Prev->Next = particleptr->Next;
- } else {
- ParticleHead = particleptr->Next;
- }
- if (particleptr->Next != NULL) {
- particleptr->Next->Prev = particleptr->Prev;
- }
- delete particleptr;
- // Decrement the no. of particles.
- ParticleCount--;
- // Decrement the no. of global weather particles.
- _GlobalParticleCount--;
- }
- /***********************************************************************************************
- * WeatherSystemClass::Render -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherSystemClass::Render (RenderInfoClass &rinfo)
- {
- if (WW3D::Are_Static_Sort_Lists_Enabled()) {
- const unsigned sortlevel = 31;
- WW3D::Add_To_Static_Sort_List (this, sortlevel);
- } else {
- const Vector3 zero (0.0f, 0.0f, 0.0f);
- const Vector3 white (1.0f, 1.0f, 1.0f);
- Vector3 cameravelocity;
- Vector3 color;
- unsigned dxcolor;
- Matrix4 viewmatrix (true), identitymatrix (true);
- float maxalphaheight, oomaxalphaheight, deltaheight;
- Vector3 x, y;
- float w, h;
- Vector3 offset [VERTICES_PER_TRIANGLE];
- Vector3 camerafocus;
- ParticleStruct *particleptr;
- unsigned processedparticlecount, bufferparticlecount;
- if (CameraPositionValid) {
- cameravelocity = ((rinfo.Camera.Get_Position() - CameraPosition) / (WW3D::Get_Frame_Time() * 0.001f));
- } else {
- cameravelocity.Set (0.0f, 0.0f, 0.0f);
- CameraPositionValid = true;
- }
- CameraPosition = rinfo.Camera.Get_Position();
- dxcolor = DX8Wrapper::Convert_Color (Vector3 (1.0f, 1.0f, 1.0f), 0.0f);
- // Precalculate alpha values.
- maxalphaheight = EmitterHeight * 0.2f;
- oomaxalphaheight = 1.0f / maxalphaheight;
- deltaheight = rinfo.Camera.Get_Position().Z + (EmitterHeight - maxalphaheight);
- // NOTE: All particle positions are already in world space.
- DX8Wrapper::Set_Transform (D3DTS_WORLD, identitymatrix);
- DX8Wrapper::Set_Material (Material);
- DX8Wrapper::Set_Shader (Shader);
- DX8Wrapper::Set_Texture (0, Texture);
- DX8Wrapper::Set_Index_Buffer (IndexBuffer, 0);
- #if WEATHER_PARTICLE_SORT
- #else
- DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 12);
- #endif
- camerafocus = rinfo.Camera.Get_Transform().Get_Z_Vector();
- particleptr = ParticleHead;
- processedparticlecount = 0;
- bufferparticlecount = MIN (MAX_IB_PARTICLE_COUNT, ParticleCount);
- while (processedparticlecount < ParticleCount) {
- unsigned particlecount, submittedparticlecount;
- #if WEATHER_PARTICLE_SORT
- DynamicVBAccessClass dynamicvb (BUFFER_TYPE_DYNAMIC_SORTING, dynamic_fvf_type, bufferparticlecount * VERTICES_PER_TRIANGLE);
- #else
- DynamicVBAccessClass dynamicvb (BUFFER_TYPE_DYNAMIC_DX8, dynamic_fvf_type, bufferparticlecount * VERTICES_PER_TRIANGLE);
- #endif
- // Copy the data into the sorting vertex buffer.
- particlecount = MIN (ParticleCount - processedparticlecount, MAX_IB_PARTICLE_COUNT);
- submittedparticlecount = 0;
- {
- DynamicVBAccessClass::WriteLockClass lock (&dynamicvb);
- VertexFormatXYZNDUV2 *vertex = lock.Get_Formatted_Vertex_Array();
- for (unsigned p = 0; p < particlecount; p++) {
- Vector3 position;
- WWASSERT (particleptr != NULL);
- position = particleptr->CurrentPosition;
- // Optimization: only submit this particle for rendering if it is in the view frustum.
- if (CollisionMath::Overlap_Test (rinfo.Camera.Get_Frustum(), position) != CollisionMath::OUTSIDE) {
- unsigned base;
- float alphaheight, alpha;
- switch (particleptr->RenderMode) {
- case RENDER_MODE_AXIS_ALIGNED:
- y = particleptr->Velocity - cameravelocity;
- y /= y.Quick_Length();
- x = Vector3::Cross_Product (camerafocus, y);
- x /= x.Quick_Length();
- w = HalfParticleWidth;
- h = HalfParticleHeight;
- break;
- case RENDER_MODE_CAMERA_ALIGNED:
- x = rinfo.Camera.Get_Transform().Get_X_Vector();
- y = rinfo.Camera.Get_Transform().Get_Y_Vector();
- w = HalfParticleWidth;
- h = HalfParticleHeight;
- break;
- case RENDER_MODE_SURFACE_ALIGNED:
- // Particle has an orientation so back-face cull it.
- if (Vector3::Dot_Product (camerafocus, particleptr->SurfaceNormal) > 0.0f) {
- x = Vector3::Cross_Product (camerafocus, particleptr->SurfaceNormal);
- x /= x.Quick_Length();
- y = Vector3::Cross_Product (x, particleptr->SurfaceNormal);
- if (DecayAfterCollision) {
- float decaytime, totaldecaytime, s;
- decaytime = particleptr->ElapsedTime - particleptr->CollisionTime;
- totaldecaytime = particleptr->LifeTime - particleptr->CollisionTime;
- if ((decaytime >= 0.0f) && (totaldecaytime > 0.0f)) {
- s = 1.0f - (decaytime / totaldecaytime);
- w = HalfParticleWidth * s;
- h = HalfParticleHeight * s;
- } else {
- w = h = 0.0f;
- }
- } else {
- w = HalfParticleWidth;
- h = HalfParticleHeight;
- }
- break;
- } else {
- // Advance to next particle.
- particleptr = particleptr->Next;
- continue;
- }
- default:
- WWASSERT (false);
- w = h = 0.0f;
- break;
- }
- offset [0] = -h * y;
- offset [1] = h * y + w * x;
- offset [2] = h * y - w * x;
- base = particleptr->Page * VERTICES_PER_TRIANGLE;
- alphaheight = position.Z - deltaheight;
- if (alphaheight > 0.0f) {
- alpha = 1.0f - (alphaheight * oomaxalphaheight);
- } else {
- alpha = 1.0f;
- }
- DX8Wrapper::Set_Alpha (alpha, dxcolor);
- // Vertex 0 of triangle.
- vertex->x = position.X + offset [0].X;
- vertex->y = position.Y + offset [0].Y;
- vertex->z = position.Z + offset [0].Z;
- vertex->diffuse = dxcolor;
- vertex->u1 = TextureArray [base].U;
- vertex->v1 = TextureArray [base].V;
- vertex++;
- // Vertex 1 of triangle.
- vertex->x = position.X + offset [1].X;
- vertex->y = position.Y + offset [1].Y;
- vertex->z = position.Z + offset [1].Z;
- vertex->diffuse = dxcolor;
- vertex->u1 = TextureArray [base + 1].U;
- vertex->v1 = TextureArray [base + 1].V;
- vertex++;
- // Vertex 2 of triangle.
- vertex->x = position.X + offset [2].X;
- vertex->y = position.Y + offset [2].Y;
- vertex->z = position.Z + offset [2].Z;
- vertex->diffuse = dxcolor;
- vertex->u1 = TextureArray [base + 2].U;
- vertex->v1 = TextureArray [base + 2].V;
- vertex++;
- submittedparticlecount++;
- }
- // Advance to next particle.
- particleptr = particleptr->Next;
- }
- }
- if (submittedparticlecount > 0) {
- DX8Wrapper::Set_Vertex_Buffer (dynamicvb);
- #if WEATHER_PARTICLE_SORT
- SortingRendererClass::Insert_Triangles (0, submittedparticlecount, 0, submittedparticlecount * VERTICES_PER_TRIANGLE);
- #else
- DX8Wrapper::Draw_Triangles (0, submittedparticlecount, 0, submittedparticlecount * VERTICES_PER_TRIANGLE);
- #endif
- }
- processedparticlecount += particlecount;
- }
- WWASSERT (particleptr == NULL);
- #if WEATHER_PARTICLE_SORT
- #else
- DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 0);
- #endif
- }
- }
- /***********************************************************************************************
- * WeatherSystemClass::Get_Obj_Space_Bounding_Sphere -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherSystemClass::Get_Obj_Space_Bounding_Sphere (SphereClass &sphere) const
- {
- sphere.Init ((ObjectMin + ObjectMax) * 0.5f, ((ObjectMax - ObjectMin) * 0.5f).Length());
- }
- /***********************************************************************************************
- * WeatherSystemClass::Get_Obj_Space_Bounding_Box -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherSystemClass::Get_Obj_Space_Bounding_Box (AABoxClass &box) const
- {
- box.Init ((ObjectMin + ObjectMax) * 0.5f, (ObjectMax - ObjectMin) * 0.5f);
- }
- /***********************************************************************************************
- * RainSystemClass::RainSystemClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- RainSystemClass::RainSystemClass (PhysicsSceneClass *scene, float particledensity, WindClass *wind, SoundEnvironmentClass *soundenvironment, bool prime)
- : WeatherSystemClass (scene, 20.0f, 20.0f, particledensity, 0.2f, 0.15f, 0.45f, 15.0f, Vector2 (0.0f, 0.0f), Vector2 (1.0f, 0.5f), PAGE_COUNT, true, 0.1f, 0.2f, WeatherSystemClass::RENDER_MODE_AXIS_ALIGNED, false, prime),
- SoundEnvironment (soundenvironment)
- {
- const char *rainsamplename = "Rainfall01";
- // Create the rain sound effect.
- // Optimization: Only add the sound effect if wind speed is non-zero.
- Sound = WWAudioClass::Get_Instance()->Create_Sound (rainsamplename, NULL, 0, CLASSID_2D);
- if (Sound != NULL) {
- SoundEnvironment->Add_User();
- Sound->Set_Volume (0.0f);
- Sound->Play();
- }
- }
- /***********************************************************************************************
- * RainSystemClass::~RainSystemClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- RainSystemClass::~RainSystemClass()
- {
- // Remove rain sound effect.
- if (Sound != NULL) {
- Sound->Stop();
- REF_PTR_RELEASE (Sound);
- SoundEnvironment->Remove_User();
- }
- }
- /***********************************************************************************************
- * RainSystemClass::Update -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool RainSystemClass::Update (WindClass *wind, const Vector3 &cameraposition)
- {
- if (Sound != NULL) {
- const float maxvolume = 4.0f;
- const float volumeperparticle = 0.0025f;
- float attenuation;
- // Calculate sound attenuation based on no. of particles in system.
- attenuation = MIN (ParticleCount * volumeperparticle, maxvolume) / maxvolume;
- Sound->Set_Volume (SoundEnvironment->Get_Amplitude() * attenuation);
- }
- // Base class update.
- return (WeatherSystemClass::Update (wind, cameraposition));
- }
- /***********************************************************************************************
- * SnowSystemClass::SnowSystemClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- SnowSystemClass::SnowSystemClass (PhysicsSceneClass *scene, float particledensity, WindClass *wind, bool prime)
- : WeatherSystemClass (scene, 40.0f, 20.0f, particledensity, 0.1f, 0.32f, 0.32f, 3.5f, Vector2 (0.0f, 0.5f), Vector2 (1.0f, 0.25f), PAGE_COUNT, false, 1.0f, 2.0f, WeatherSystemClass::RENDER_MODE_CAMERA_ALIGNED, true, prime)
- {
- }
- /***********************************************************************************************
- * SnowSystemClass::Update -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool SnowSystemClass::Update (WindClass *wind, const Vector3 &cameraposition)
- {
- // Base class update.
- return (WeatherSystemClass::Update (wind, cameraposition));
- }
- /***********************************************************************************************
- * AshSystemClass::AshSystemClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- AshSystemClass::AshSystemClass (PhysicsSceneClass *scene, float particledensity, WindClass *wind, bool prime)
- : WeatherSystemClass (scene, 40.0f, 20.0f, particledensity, 0.1f, 0.32f, 0.32f, 3.0f, Vector2 (0.0f, 0.75f), Vector2 (1.0f, 0.25f), PAGE_COUNT, false, 1.0f, 2.0f, WeatherSystemClass::RENDER_MODE_CAMERA_ALIGNED, true, prime)
- {
- }
- /***********************************************************************************************
- * AshSystemClass::Update -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool AshSystemClass::Update (WindClass *wind, const Vector3 &cameraposition)
- {
- // Base class update.
- return (WeatherSystemClass::Update (wind, cameraposition));
- }
- /***********************************************************************************************
- * WeatherParameterClass::Initialize -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/24/01 IML : Created. *
- *=============================================================================================*/
- void WeatherParameterClass::Initialize()
- {
- CurrentValue = 0.0f;
- NormalTarget = 0.0f;
- NormalDuration = 0.0f;
- OverrideTarget = 0.0f;
- OverrideDuration = 0.0f;
- }
- /***********************************************************************************************
- * WeatherParameterClass::Set -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/24/01 IML : Created. *
- *=============================================================================================*/
- void WeatherParameterClass::Set (float target, float ramptime, bool override)
- {
- if (!override) {
- NormalTarget = target;
- NormalDuration = ramptime;
- } else {
- OverrideTarget = target;
- OverrideDuration = ramptime;
- }
- }
- /***********************************************************************************************
- * WeatherParameterClass::Update -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/24/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherParameterClass::Update (float time, bool override)
- {
- const float previouscurrentvalue = CurrentValue;
- // Update the normal parameters.
- Update (NormalValue, NormalTarget, NormalDuration, time);
- // Update the override parameters?
- if (override) {
- Update (CurrentValue, OverrideTarget, OverrideDuration, time);
- } else {
- if (OverrideDuration > 0.0f) {
- Update (CurrentValue, NormalValue, OverrideDuration, time);
- } else {
- CurrentValue = NormalValue;
- }
- }
- return (CurrentValue != previouscurrentvalue);
- }
- /***********************************************************************************************
- * WeatherParameterClass::Update -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/24/01 IML : Created. *
- *=============================================================================================*/
- void WeatherParameterClass::Update (float &value, float &target, float &duration, float time)
- {
- if (value == target) {
- duration = 0.0f;
- } else {
- duration -= time;
- if (duration > 0.0f) {
- bool sign0, sign1;
- sign0 = value < target;
- value += ((target - value) * (time / duration));
- if (value == target) {
- duration = 0.0f;
- } else {
- sign1 = value < target;
- // If the value has 'blown past' the target value...
- if (sign0 ^ sign1) {
- duration = 0.0f;
- value = target;
- }
- }
- } else {
- duration = 0.0f;
- value = target;
- }
- }
- }
- /***********************************************************************************************
- * WeatherMgrClass::WeatherMgrClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- WeatherMgrClass::WeatherMgrClass()
- {
- Set_Network_ID (NETID_SERVER_WEATHER);
- Set_App_Packet_Type (APPPACKETTYPE_NETWEATHER);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Init -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Init (SoundEnvironmentClass *soundenvironment)
- {
- WWASSERT (soundenvironment != NULL);
- REF_PTR_SET (_SoundEnvironment, soundenvironment);
- _Wind = NULL;
- for (int p = PRECIPITATION_FIRST; p < PRECIPITATION_COUNT; p++) {
- _Precipitation [p] = NULL;
- }
- Reset();
- }
- /***********************************************************************************************
- * WeatherMgrClass::Reset -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Reset()
- {
- int p;
- // Iterate and initialize the parameters.
- for (p = 0; p < PARAMETER_COUNT; p++) {
- _Parameters [p].Initialize();
- }
- if (_Wind != NULL) {
- delete _Wind;
- _Wind = NULL;
- }
- // Restore the settings to default.
- Set_Wind (0.0f, 0.0f, 0.0f, 0.0f, false);
- for (p = PRECIPITATION_FIRST; p < PRECIPITATION_COUNT; p++) {
- if (_Precipitation [p] != NULL) {
- _Precipitation [p]->Remove();
- REF_PTR_RELEASE (_Precipitation [p]);
- Set_Precipitation ((PrecipitationEnum) p, 0.0f, 0.0f, false);
- }
- }
- Set_Fog_Enable (false);
- Set_Fog_Range (200.0f, 300.0f);
- _Prime = true;
- _Imported = false;
- _WindOverrideCount = 0;
- _PrecipitationOverrideCount = 0;
- Set_Dirty();
- }
- /***********************************************************************************************
- * WeatherMgrClass::Shutdown -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Shutdown()
- {
- Reset();
- REF_PTR_RELEASE (_SoundEnvironment);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Set_Wind -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Set_Wind (float heading, float speed, float variability, float ramptime)
- {
- if (CombatManager::I_Am_Server()) {
- if (Set_Wind (heading, speed, variability, ramptime, false)) {
- _TheWeatherMgr.Set_Object_Dirty_Bit (NetworkObjectClass::BIT_RARE, true);
- return (true);
- }
- }
- return (false);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Override_Wind -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Override_Wind (float heading, float speed, float variability, float ramptime)
- {
- if (CombatManager::I_Am_Server()) {
- _WindOverrideCount++;
- if (Set_Wind (heading, speed, variability, ramptime, true)) {
- _TheWeatherMgr.Set_Object_Dirty_Bit (NetworkObjectClass::BIT_RARE, true);
- return (true);
- }
- }
- return (false);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Set_Wind -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Set_Wind (float heading, float speed, float variability, float ramptime, bool override)
- {
- if ((heading >= 0.0f) && (heading <= 360.0f) && (speed >= 0.0f) && (variability >= 0.0f) &&
- (variability <= 1.0f) && (ramptime >= 0.0f)) {
- bool o;
- o = (_WindOverrideCount > 0) && override;
- _Parameters [PARAMETER_WIND_HEADING].Set (heading, ramptime, o);
- _Parameters [PARAMETER_WIND_SPEED].Set (speed, ramptime, o);
- _Parameters [PARAMETER_WIND_VARIABILITY].Set (variability, ramptime, o);
- return (true);
- }
- return (false);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Get_Wind -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Get_Wind (float &heading, float &speed, float &variability)
- {
- heading = _Parameters [PARAMETER_WIND_HEADING].Value();
- speed = _Parameters [PARAMETER_WIND_SPEED].Value();
- variability = _Parameters [PARAMETER_WIND_VARIABILITY].Value();
- }
- /***********************************************************************************************
- * WeatherMgrClass::Restore_Wind -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Restore_Wind (float ramptime)
- {
- if (CombatManager::I_Am_Server()) {
- _Parameters [PARAMETER_WIND_HEADING].Set (ramptime);
- _Parameters [PARAMETER_WIND_SPEED].Set (ramptime);
- _Parameters [PARAMETER_WIND_VARIABILITY].Set (ramptime);
- _WindOverrideCount--;
- _TheWeatherMgr.Set_Object_Dirty_Bit (NetworkObjectClass::BIT_RARE, true);
- }
- }
- /***********************************************************************************************
- * WeatherMgrClass::Set_Precipitation -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Set_Precipitation (PrecipitationEnum precipitation, float density, float ramptime)
- {
- if (CombatManager::I_Am_Server()) {
- if (Set_Precipitation (precipitation, density, ramptime, false)) {
- _TheWeatherMgr.Set_Object_Dirty_Bit (NetworkObjectClass::BIT_RARE, true);
- return (true);
- }
- }
- return (false);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Override_Precipitation -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Override_Precipitation (PrecipitationEnum precipitation, float density, float ramptime)
- {
- if (CombatManager::I_Am_Server()) {
- bool success;
- _PrecipitationOverrideCount++;
- // Override requested precipitation but also override and ramp down any other types of precipitation that may exist.
- success = true;
- for (int p = PRECIPITATION_FIRST; p < PRECIPITATION_COUNT; p++) {
- if (p != precipitation) {
- success &= Set_Precipitation ((PrecipitationEnum) p, 0.0f, ramptime, true);
- } else {
- success &= Set_Precipitation ((PrecipitationEnum) p, density, ramptime, true);
- }
- }
- _TheWeatherMgr.Set_Object_Dirty_Bit (NetworkObjectClass::BIT_RARE, true);
- return (success);
- }
- return (false);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Set_Precipitation -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Set_Precipitation (PrecipitationEnum precipitation, float density, float ramptime, bool override)
- {
- if ((density >= 0.0f) && (ramptime >= 0.0f)) {
- const bool o = (_PrecipitationOverrideCount > 0) && override;
- switch (precipitation) {
- case PRECIPITATION_RAIN:
- _Parameters [PARAMETER_RAIN_DENSITY].Set (density, ramptime, o);
- break;
- case PRECIPITATION_SNOW:
- _Parameters [PARAMETER_SNOW_DENSITY].Set (density, ramptime, o);
- break;
- case PRECIPITATION_ASH:
- _Parameters [PARAMETER_ASH_DENSITY].Set (density, ramptime, o);
- break;
- default:
- WWASSERT (false);
- break;
- }
- return (true);
- }
- return (false);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Get_Precipitation -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Get_Precipitation (PrecipitationEnum precipitation, float &density)
- {
- switch (precipitation) {
- case PRECIPITATION_RAIN:
- density = _Parameters [PARAMETER_RAIN_DENSITY].Value();
- break;
- case PRECIPITATION_SNOW:
- density = _Parameters [PARAMETER_SNOW_DENSITY].Value();
- break;
- case PRECIPITATION_ASH:
- density = _Parameters [PARAMETER_ASH_DENSITY].Value();
- break;
- default:
- WWASSERT (false);
- break;
- }
- }
- /***********************************************************************************************
- * WeatherMgrClass::Restore_Precipitation -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Restore_Precipitation (float ramptime)
- {
- if (CombatManager::I_Am_Server()) {
- _Parameters [PARAMETER_RAIN_DENSITY].Set (ramptime);
- _Parameters [PARAMETER_SNOW_DENSITY].Set (ramptime);
- _Parameters [PARAMETER_ASH_DENSITY].Set (ramptime);
- _PrecipitationOverrideCount--;
- _TheWeatherMgr.Set_Object_Dirty_Bit (NetworkObjectClass::BIT_RARE, true);
- }
- }
- /***********************************************************************************************
- * WeatherMgrClass::Set_Fog_Range -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 07/12/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Set_Fog_Range (float startdistance, float enddistance, float ramptime)
- {
- if ((startdistance >= 0.0f) && (enddistance >= startdistance)) {
- _Parameters [PARAMETER_FOG_START_DISTANCE].Set (startdistance, ramptime, false);
- _Parameters [PARAMETER_FOG_END_DISTANCE].Set (enddistance, ramptime, false);
- return (true);
- }
- return (false);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Get_Fog_Range -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 07/12/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Get_Fog_Range (float &startdistance, float &enddistance)
- {
- startdistance = _Parameters [PARAMETER_FOG_START_DISTANCE].Value();
- enddistance = _Parameters [PARAMETER_FOG_END_DISTANCE].Value();
- }
- /***********************************************************************************************
- * WeatherMgrClass::Update -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/06/01 IML : Created. *
- *=============================================================================================*/
- void WeatherMgrClass::Update (PhysicsSceneClass *scene, CameraClass *camera)
- {
- float time;
- bool windmodified, fogmodified;
- time = WW3D::Get_Frame_Time() * 0.001f;
- // Update wind.
- windmodified = _Parameters [PARAMETER_WIND_HEADING].Update (time, _WindOverrideCount > 0);
- windmodified |= _Parameters [PARAMETER_WIND_SPEED].Update (time, _WindOverrideCount > 0);
- windmodified |= _Parameters [PARAMETER_WIND_VARIABILITY].Update (time, _WindOverrideCount > 0);
- if (_Wind != NULL) {
- if (windmodified) {
- _Wind->Set (_Parameters [PARAMETER_WIND_HEADING].Value(), _Parameters [PARAMETER_WIND_SPEED].Value(), _Parameters [PARAMETER_WIND_VARIABILITY].Value());
- }
- // Optimization: if there is nothing to update, can safely remove the wind.
- if (!_Wind->Update()) {
- delete _Wind;
- _Wind = NULL;
- }
- } else {
- // Optimization: only create wind if speed is non-zero.
- if (_Parameters [PARAMETER_WIND_SPEED].Value() > 0.0f) {
- _Wind = new WindClass (_Parameters [PARAMETER_WIND_HEADING].Value(), _Parameters [PARAMETER_WIND_SPEED].Value(), _Parameters [PARAMETER_WIND_VARIABILITY].Value(), _SoundEnvironment);
- }
- }
- for (int p = PRECIPITATION_FIRST; p < PRECIPITATION_COUNT; p++) {
- WeatherParameterClass *parameterptr = NULL;
- bool modified;
- switch (p) {
- case PRECIPITATION_RAIN:
- parameterptr = &_Parameters [PARAMETER_RAIN_DENSITY];
- break;
- case PRECIPITATION_SNOW:
- parameterptr = &_Parameters [PARAMETER_SNOW_DENSITY];
- break;
- case PRECIPITATION_ASH:
- parameterptr = &_Parameters [PARAMETER_ASH_DENSITY];
- break;
- default:
- WWASSERT (false);
- break;
- }
- modified = parameterptr->Update (time, _PrecipitationOverrideCount > 0);
- if (_Precipitation [p] != NULL) {
- if (modified) {
- _Precipitation [p]->Set_Density (parameterptr->Value());
- }
- // Optimization: if there is nothing to update, can safely remove the weather system.
- if (!_Precipitation [p]->Update (_Wind, camera->Get_Position())) {
- _Precipitation [p]->Remove();
- REF_PTR_RELEASE (_Precipitation [p]);
- }
- } else {
- // Optimization: only create weather if density is non-zero.
- if (parameterptr->Value() > 0.0f) {
- // Don't bother on dedicated servers.
- if (!CombatManager::I_Am_Only_Server()) {
- switch (p) {
- case PRECIPITATION_RAIN:
- _Precipitation [p] = NEW_REF (RainSystemClass, (scene, parameterptr->Value(), _Wind, _SoundEnvironment, _Prime));
- break;
- case PRECIPITATION_SNOW:
- _Precipitation [p] = NEW_REF (SnowSystemClass, (scene, parameterptr->Value(), _Wind, _Prime));
- break;
- case PRECIPITATION_ASH:
- _Precipitation [p] = NEW_REF (AshSystemClass, (scene, parameterptr->Value(), _Wind, _Prime));
- break;
- default:
- WWASSERT (false);
- break;
- }
- scene->Add_Render_Object (_Precipitation [p]);
- }
- }
- }
- }
- fogmodified = _Parameters [PARAMETER_FOG_START_DISTANCE].Update (time, false);
- fogmodified |= _Parameters [PARAMETER_FOG_END_DISTANCE].Update (time, false);
- if (Is_Dirty() || fogmodified) {
- scene->Set_Fog_Enable (_FogEnabled);
- scene->Set_Fog_Range (_Parameters [PARAMETER_FOG_START_DISTANCE].Value(), _Parameters [PARAMETER_FOG_END_DISTANCE].Value());
- }
- if (CombatManager::I_Am_Server()) {
- // Server precipitation can only be primed on the first update iteration of a level.
- _Prime = false;
- } else {
- // Clients can be primed right up until the first import from the server.
- if (_Imported) _Prime = false;
- }
- // Everything necessary has been updated. Clear the dirty flag.
- Set_Dirty (false);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Save -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/02/01 IML : Created. *
- *=============================================================================================*/
- #define WRITE_PARAMETER(varname) \
- WRITE_MICRO_CHUNK (csave, VARID_ ## varname ## _CURRENT_VALUE, _Parameters [PARAMETER_ ## varname ##].CurrentValue); \
- WRITE_MICRO_CHUNK (csave, VARID_ ## varname ## _NORMAL_VALUE, _Parameters [PARAMETER_ ## varname ##].NormalValue); \
- WRITE_MICRO_CHUNK (csave, VARID_ ## varname ## _NORMAL_TARGET, _Parameters [PARAMETER_ ## varname ##].NormalTarget); \
- WRITE_MICRO_CHUNK (csave, VARID_ ## varname ## _NORMAL_DURATION, _Parameters [PARAMETER_ ## varname ##].NormalDuration); \
- WRITE_MICRO_CHUNK (csave, VARID_ ## varname ## _OVERRIDE_TARGET, _Parameters [PARAMETER_ ## varname ##].OverrideTarget); \
- WRITE_MICRO_CHUNK (csave, VARID_ ## varname ## _OVERRIDE_DURATION, _Parameters [PARAMETER_ ## varname ##].OverrideDuration)
- bool WeatherMgrClass::Save (ChunkSaveClass &csave)
- {
- csave.Begin_Chunk (CHUNKID_MICRO_CHUNKS);
- csave.End_Chunk ();
- Save_Dynamic (csave);
- return (true);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Save_Dynamic -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/02/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Save_Dynamic (ChunkSaveClass &csave)
- {
- csave.Begin_Chunk (CHUNKID_DYNAMIC_MICRO_CHUNKS);
- WRITE_PARAMETER (WIND_HEADING);
- WRITE_PARAMETER (WIND_SPEED);
- WRITE_PARAMETER (WIND_VARIABILITY);
- WRITE_PARAMETER (RAIN_DENSITY);
- WRITE_PARAMETER (SNOW_DENSITY);
- WRITE_PARAMETER (ASH_DENSITY);
- WRITE_MICRO_CHUNK (csave, VARID_WIND_OVERRIDE_COUNT, _WindOverrideCount);
- WRITE_MICRO_CHUNK (csave, VARID_PRECIPITATION_OVERRIDE_COUNT, _PrecipitationOverrideCount);
- WRITE_MICRO_CHUNK (csave, VARID_FOG_ENABLED, _FogEnabled);
- WRITE_PARAMETER (FOG_START_DISTANCE);
- WRITE_PARAMETER (FOG_END_DISTANCE);
- csave.End_Chunk ();
- return (true);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Load -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/02/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Load (ChunkLoadClass &cload)
- {
- WWMEMLOG (MEM_GAMEDATA);
- bool retval = true;
- while (cload.Open_Chunk ()) {
- switch (cload.Cur_Chunk_ID ()) {
- case CHUNKID_MICRO_CHUNKS:
- retval &= Load_Micro_Chunks (cload);
- break;
- case CHUNKID_DYNAMIC_MICRO_CHUNKS:
- retval &= Load_Dynamic_Micro_Chunks (cload);
- break;
- }
- cload.Close_Chunk ();
- }
- return (retval);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Load_Micro_Chunks -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/02/01 IML : Created. *
- *=============================================================================================*/
- #define READ_PARAMETER(varname) \
- READ_MICRO_CHUNK (cload, VARID_ ## varname ## _CURRENT_VALUE, _Parameters [PARAMETER_ ## varname ##].CurrentValue); \
- READ_MICRO_CHUNK (cload, VARID_ ## varname ## _NORMAL_VALUE, _Parameters [PARAMETER_ ## varname ##].NormalValue); \
- READ_MICRO_CHUNK (cload, VARID_ ## varname ## _NORMAL_TARGET, _Parameters [PARAMETER_ ## varname ##].NormalTarget); \
- READ_MICRO_CHUNK (cload, VARID_ ## varname ## _NORMAL_DURATION, _Parameters [PARAMETER_ ## varname ##].NormalDuration); \
- READ_MICRO_CHUNK (cload, VARID_ ## varname ## _OVERRIDE_TARGET, _Parameters [PARAMETER_ ## varname ##].OverrideTarget); \
- READ_MICRO_CHUNK (cload, VARID_ ## varname ## _OVERRIDE_DURATION, _Parameters [PARAMETER_ ## varname ##].OverrideDuration)
- bool WeatherMgrClass::Load_Micro_Chunks (ChunkLoadClass &cload)
- {
- // Read weather micro chunk.
- while (cload.Open_Micro_Chunk ()) {
- cload.Close_Micro_Chunk ();
- }
- return (true);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Load_Dynamic -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/02/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Load_Dynamic (ChunkLoadClass &cload)
- {
- WWMEMLOG (MEM_GAMEDATA);
- bool retval = true;
- while (cload.Open_Chunk ()) {
- switch (cload.Cur_Chunk_ID ()) {
- case CHUNKID_DYNAMIC_MICRO_CHUNKS:
- retval &= Load_Dynamic_Micro_Chunks (cload);
- break;
- }
- cload.Close_Chunk ();
- }
- return (retval);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Load_Dynamic_Micro_Chunks -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/02/01 IML : Created. *
- *=============================================================================================*/
- bool WeatherMgrClass::Load_Dynamic_Micro_Chunks (ChunkLoadClass &cload)
- {
- // Read weather micro chunk.
- while (cload.Open_Micro_Chunk ()) {
- switch (cload.Cur_Micro_Chunk_ID ()) {
- READ_PARAMETER (WIND_HEADING);
- READ_PARAMETER (WIND_SPEED);
- READ_PARAMETER (WIND_VARIABILITY);
- READ_PARAMETER (RAIN_DENSITY);
- READ_PARAMETER (SNOW_DENSITY);
- READ_PARAMETER (ASH_DENSITY);
- READ_MICRO_CHUNK (cload, VARID_WIND_OVERRIDE_COUNT, _WindOverrideCount);
- READ_MICRO_CHUNK (cload, VARID_PRECIPITATION_OVERRIDE_COUNT, _PrecipitationOverrideCount);
- READ_MICRO_CHUNK (cload, VARID_FOG_ENABLED, _FogEnabled);
- READ_PARAMETER (FOG_START_DISTANCE);
- READ_PARAMETER (FOG_END_DISTANCE);
- }
- cload.Close_Micro_Chunk ();
- }
- return (true);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Export_Rare -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/02/01 IML : Created. *
- *=============================================================================================*/
- #define EXPORT_PARAMETER(object, varname) \
- object.Add (_Parameters [PARAMETER_ ## varname ##].NormalTarget); \
- object.Add (_Parameters [PARAMETER_ ## varname ##].NormalDuration); \
- object.Add (_Parameters [PARAMETER_ ## varname ##].OverrideTarget); \
- object.Add (_Parameters [PARAMETER_ ## varname ##].OverrideDuration)
- void WeatherMgrClass::Export_Rare (BitStreamClass &packet)
- {
- WWASSERT (CombatManager::I_Am_Server());
- EXPORT_PARAMETER (packet, WIND_HEADING);
- EXPORT_PARAMETER (packet, WIND_SPEED);
- EXPORT_PARAMETER (packet, WIND_VARIABILITY);
- EXPORT_PARAMETER (packet, RAIN_DENSITY);
- EXPORT_PARAMETER (packet, SNOW_DENSITY);
- EXPORT_PARAMETER (packet, ASH_DENSITY);
- packet.Add (_WindOverrideCount);
- packet.Add (_PrecipitationOverrideCount);
- }
- /***********************************************************************************************
- * WeatherMgrClass::Import_Rare -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 03/02/01 IML : Created. *
- *=============================================================================================*/
- #define IMPORT_PARAMETER(object, varname) \
- object.Get (_Parameters [PARAMETER_ ## varname ##].NormalTarget); \
- object.Get (_Parameters [PARAMETER_ ## varname ##].NormalDuration); \
- object.Get (_Parameters [PARAMETER_ ## varname ##].OverrideTarget); \
- object.Get (_Parameters [PARAMETER_ ## varname ##].OverrideDuration)
- void WeatherMgrClass::Import_Rare (BitStreamClass &packet)
- {
- WWASSERT (CombatManager::I_Am_Client());
- IMPORT_PARAMETER (packet, WIND_HEADING);
- IMPORT_PARAMETER (packet, WIND_SPEED);
- IMPORT_PARAMETER (packet, WIND_VARIABILITY);
- IMPORT_PARAMETER (packet, RAIN_DENSITY);
- IMPORT_PARAMETER (packet, SNOW_DENSITY);
- IMPORT_PARAMETER (packet, ASH_DENSITY);
- packet.Get (_WindOverrideCount);
- packet.Get (_PrecipitationOverrideCount);
- // Flag that weather data has been imported.
- _Imported = true;
- }
- #undef EXPORT_PARAMETER
- #undef IMPORT_PARAMETER
- #undef READ_PARAMETER
- #undef WRITE_PARAMETER
|