diff options
author | Sergeanur <s.anureev@yandex.ua> | 2021-07-17 23:03:57 +0200 |
---|---|---|
committer | Sergeanur <s.anureev@yandex.ua> | 2021-07-17 23:03:57 +0200 |
commit | c937bdbfea8f522d14d7a41f24372bddf5bdafcc (patch) | |
tree | eb8f97f6cf9fac31d7ab90388af232d51cc9c137 /src/renderer/Particle.cpp | |
parent | Merge pull request #1219 from withmorten/miami-ini (diff) | |
download | re3-c937bdbfea8f522d14d7a41f24372bddf5bdafcc.tar re3-c937bdbfea8f522d14d7a41f24372bddf5bdafcc.tar.gz re3-c937bdbfea8f522d14d7a41f24372bddf5bdafcc.tar.bz2 re3-c937bdbfea8f522d14d7a41f24372bddf5bdafcc.tar.lz re3-c937bdbfea8f522d14d7a41f24372bddf5bdafcc.tar.xz re3-c937bdbfea8f522d14d7a41f24372bddf5bdafcc.tar.zst re3-c937bdbfea8f522d14d7a41f24372bddf5bdafcc.zip |
Diffstat (limited to 'src/renderer/Particle.cpp')
-rw-r--r-- | src/renderer/Particle.cpp | 2534 |
1 files changed, 2534 insertions, 0 deletions
diff --git a/src/renderer/Particle.cpp b/src/renderer/Particle.cpp new file mode 100644 index 00000000..461a10a6 --- /dev/null +++ b/src/renderer/Particle.cpp @@ -0,0 +1,2534 @@ +#include "common.h" + +#include "main.h" +#include "General.h" +#include "Timer.h" +#include "TxdStore.h" +#include "Sprite.h" +#include "Camera.h" +#include "Clock.h" +#include "Collision.h" +#include "World.h" +#include "Shadows.h" +#include "Replay.h" +#include "Stats.h" +#include "Weather.h" +#include "MBlur.h" +#include "main.h" +#include "AudioScriptObject.h" +#include "ParticleObject.h" +#include "Particle.h" +#include "soundlist.h" +#include "SaveBuf.h" +#include "debugmenu.h" + +#define MAX_PARTICLES_ON_SCREEN (750) + + +//(5) +#define MAX_SMOKE_FILES ARRAY_SIZE(SmokeFiles) + +//(5) +#define MAX_RUBBER_FILES ARRAY_SIZE(RubberFiles) +//(5) +#define MAX_RAINSPLASH_FILES ARRAY_SIZE(RainSplashFiles) +//(3) +#define MAX_WATERSPRAY_FILES ARRAY_SIZE(WatersprayFiles) +//(6) +#define MAX_EXPLOSIONMEDIUM_FILES ARRAY_SIZE(ExplosionMediumFiles) +//(4) +#define MAX_GUNFLASH_FILES ARRAY_SIZE(GunFlashFiles) +//(2) +#define MAX_RAINSPLASHUP_FILES ARRAY_SIZE(RainSplashupFiles) +//(4) +#define MAX_BIRDFRONT_FILES ARRAY_SIZE(BirdfrontFiles) +//(8) +#define MAX_BOAT_FILES ARRAY_SIZE(BoatFiles) +//(4) +#define MAX_CARDEBRIS_FILES ARRAY_SIZE(CardebrisFiles) +//(4) +#define MAX_CARSPLASH_FILES ARRAY_SIZE(CarsplashFiles) + +#define MAX_RAINDRIP_FILES (2) + +#define MAX_LEAF_FILES (2) + + +const char SmokeFiles[][6+1] = +{ + "smoke1", + "smoke2", + "smoke3", + "smoke4", + "smoke5" +}; + + +const char RubberFiles[][7+1] = +{ + "rubber1", + "rubber2", + "rubber3", + "rubber4", + "rubber5" +}; + +const char RainSplashFiles[][7+1] = +{ + "splash1", + "splash2", + "splash3", + "splash4", + "splash5" +}; + +const char WatersprayFiles[][11+1] = +{ + "waterspray1", + "waterspray2", + "waterspray3" +}; + +const char ExplosionMediumFiles[][7+1] = +{ + "explo01", + "explo02", + "explo03", + "explo04", + "explo05", + "explo06" +}; + +const char GunFlashFiles[][9+1] = +{ + "gunflash1", + "gunflash2", + "gunflash3", + "gunflash4" +}; + +const char RainSplashupFiles[][10+1] = +{ + "splash_up1", + "splash_up2" +}; + +const char BirdfrontFiles[][8+1] = +{ + "birdf_01", + "birdf_02", + "birdf_03", + "birdf_04" +}; + +const char BoatFiles[][8+1] = +{ + "boats_01", + "boats_02", + "boats_03", + "boats_04", + "boats_05", + "boats_06", + "boats_07", + "boats_08" +}; + +const char CardebrisFiles[][12+1] = +{ + "cardebris_01", + "cardebris_02", + "cardebris_03", + "cardebris_04" +}; + +const char CarsplashFiles[][12+1] = +{ + "carsplash_01", + "carsplash_02", + "carsplash_03", + "carsplash_04" +}; + +CParticle gParticleArray[MAX_PARTICLES_ON_SCREEN]; + +RwTexture *gpSmokeTex[MAX_SMOKE_FILES]; +RwTexture *gpSmoke2Tex; +RwTexture *gpRubberTex[MAX_RUBBER_FILES]; +RwTexture *gpRainSplashTex[MAX_RAINSPLASH_FILES]; +RwTexture *gpWatersprayTex[MAX_WATERSPRAY_FILES]; +RwTexture *gpExplosionMediumTex[MAX_EXPLOSIONMEDIUM_FILES]; +RwTexture *gpGunFlashTex[MAX_GUNFLASH_FILES]; +RwTexture *gpRainSplashupTex[MAX_RAINSPLASHUP_FILES]; +RwTexture *gpBirdfrontTex[MAX_BIRDFRONT_FILES]; +RwTexture *gpBoatTex[MAX_BOAT_FILES]; +RwTexture *gpCarDebrisTex[MAX_CARDEBRIS_FILES]; +RwTexture *gpCarSplashTex[MAX_CARSPLASH_FILES]; + +RwTexture *gpBoatWakeTex; +RwTexture *gpFlame1Tex; +RwTexture *gpFlame5Tex; +RwTexture *gpRainDropSmallTex; +RwTexture *gpBloodTex; +RwTexture *gpLeafTex[MAX_LEAF_FILES]; +RwTexture *gpCloudTex1; +RwTexture *gpCloudTex4; +RwTexture *gpBloodSmallTex; +RwTexture *gpGungeTex; +RwTexture *gpCollisionSmokeTex; +RwTexture *gpBulletHitTex; +RwTexture *gpGunShellTex; +RwTexture *gpPointlightTex; + +RwRaster *gpSmokeRaster[MAX_SMOKE_FILES]; +RwRaster *gpSmoke2Raster; +RwRaster *gpRubberRaster[MAX_RUBBER_FILES]; +RwRaster *gpRainSplashRaster[MAX_RAINSPLASH_FILES]; +RwRaster *gpWatersprayRaster[MAX_WATERSPRAY_FILES]; +RwRaster *gpExplosionMediumRaster[MAX_EXPLOSIONMEDIUM_FILES]; +RwRaster *gpGunFlashRaster[MAX_GUNFLASH_FILES]; +RwRaster *gpRainSplashupRaster[MAX_RAINSPLASHUP_FILES]; +RwRaster *gpBirdfrontRaster[MAX_BIRDFRONT_FILES]; +RwRaster *gpBoatRaster[MAX_BOAT_FILES]; +RwRaster *gpCarDebrisRaster[MAX_CARDEBRIS_FILES]; +RwRaster *gpCarSplashRaster[MAX_CARSPLASH_FILES]; + +RwRaster *gpBoatWakeRaster; +RwRaster *gpFlame1Raster; +RwRaster *gpFlame5Raster; +RwRaster *gpRainDropSmallRaster; +RwRaster *gpBloodRaster; +RwRaster *gpLeafRaster[MAX_LEAF_FILES]; +RwRaster *gpCloudRaster1; +RwRaster *gpCloudRaster4; +RwRaster *gpBloodSmallRaster; +RwRaster *gpGungeRaster; +RwRaster *gpCollisionSmokeRaster; +RwRaster *gpBulletHitRaster; +RwRaster *gpGunShellRaster; +RwRaster *gpPointlightRaster; + +RwTexture *gpRainDropTex; +RwRaster *gpRainDropRaster; + +RwTexture *gpSparkTex; +RwTexture *gpNewspaperTex; +RwTexture *gpGunSmokeTex; +RwTexture *gpDotTex; +RwTexture *gpHeatHazeTex; +RwTexture *gpBeastieTex; +RwTexture *gpRainDripTex[MAX_RAINDRIP_FILES]; +RwTexture *gpRainDripDarkTex[MAX_RAINDRIP_FILES]; + +RwRaster *gpSparkRaster; +RwRaster *gpNewspaperRaster; +RwRaster *gpGunSmokeRaster; +RwRaster *gpDotRaster; +RwRaster *gpHeatHazeRaster; +RwRaster *gpBeastieRaster; +RwRaster *gpRainDripRaster[MAX_RAINDRIP_FILES]; +RwRaster *gpRainDripDarkRaster[MAX_RAINDRIP_FILES]; + +float CParticle::ms_afRandTable[CParticle::RAND_TABLE_SIZE]; +CParticle *CParticle::m_pUnusedListHead; +float CParticle::m_SinTable[CParticle::SIN_COS_TABLE_SIZE]; +float CParticle::m_CosTable[CParticle::SIN_COS_TABLE_SIZE]; + +int32 Randomizer; +int32 nParticleCreationInterval = 1; +float PARTICLE_WIND_TEST_SCALE = 0.002f; +float fParticleScaleLimit = 0.5f; + +bool clearWaterDrop; +int32 numWaterDropOnScreen; + +#ifdef DEBUGMENU +SETTWEAKPATH("Particle"); +TWEAKINT32(nParticleCreationInterval, 0, 5, 1); +TWEAKFLOAT(fParticleScaleLimit, 0.0f, 1.0f, 0.1f); +TWEAKFUNC(CParticle::ReloadConfig); +#endif + + + +void CParticle::ReloadConfig() +{ + debug("Initialising CParticleMgr..."); + + mod_ParticleSystemManager.Initialise(); + + debug("Initialising CParticle..."); + + m_pUnusedListHead = gParticleArray; + + for ( int32 i = 0; i < MAX_PARTICLES_ON_SCREEN; i++ ) + { + if ( i == MAX_PARTICLES_ON_SCREEN - 1 ) + gParticleArray[i].m_pNext = nil; + else + gParticleArray[i].m_pNext = &gParticleArray[i + 1]; + + gParticleArray[i].m_vecPosition = CVector(0.0f, 0.0f, 0.0f); + + gParticleArray[i].m_vecVelocity = CVector(0.0f, 0.0f, 0.0f); + + gParticleArray[i].m_nTimeWhenWillBeDestroyed = 0; + + gParticleArray[i].m_nTimeWhenColorWillBeChanged = 0; + + gParticleArray[i].m_fSize = 0.2f; + + gParticleArray[i].m_fExpansionRate = 0.0f; + + gParticleArray[i].m_nColorIntensity = 255; + + gParticleArray[i].m_nFadeToBlackTimer = 0; + + gParticleArray[i].m_nAlpha = 255; + + gParticleArray[i].m_nFadeAlphaTimer = 0; + + gParticleArray[i].m_nCurrentZRotation = 0; + + gParticleArray[i].m_nZRotationTimer = 0; + + gParticleArray[i].m_fCurrentZRadius = 0.0f; + + gParticleArray[i].m_nZRadiusTimer = 0; + + gParticleArray[i].m_nCurrentFrame = 0; + + gParticleArray[i].m_nAnimationSpeedTimer = 0; + + gParticleArray[i].m_nRotation = 0; + + gParticleArray[i].m_nRotationStep = 0; + } +} + +void CParticle::Initialise() +{ + ReloadConfig(); + + CParticleObject::Initialise(); + + float randVal = -1.0f; + for ( int32 i = 0; i < RAND_TABLE_SIZE; i++ ) + { + ms_afRandTable[i] = randVal; + randVal += 0.1f; + } + + for ( int32 i = 0; i < SIN_COS_TABLE_SIZE; i++ ) + { + float angle = DEGTORAD(float(i) * float(360.0f / SIN_COS_TABLE_SIZE)); + + m_SinTable[i] = ::Sin(angle); + m_CosTable[i] = ::Cos(angle); + } + + int32 slot = CTxdStore::FindTxdSlot("particle"); + + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(slot); + + for ( int32 i = 0; i < MAX_SMOKE_FILES; i++ ) + { + gpSmokeTex[i] = RwTextureRead(SmokeFiles[i], nil); + gpSmokeRaster[i] = RwTextureGetRaster(gpSmokeTex[i]); + } + + gpSmoke2Tex = RwTextureRead("smokeII_3", nil); + gpSmoke2Raster = RwTextureGetRaster(gpSmoke2Tex); + + for ( int32 i = 0; i < MAX_RUBBER_FILES; i++ ) + { + gpRubberTex[i] = RwTextureRead(RubberFiles[i], nil); + gpRubberRaster[i] = RwTextureGetRaster(gpRubberTex[i]); + } + + for ( int32 i = 0; i < MAX_RAINSPLASH_FILES; i++ ) + { + gpRainSplashTex[i] = RwTextureRead(RainSplashFiles[i], nil); + gpRainSplashRaster[i] = RwTextureGetRaster(gpRainSplashTex[i]); + } + + for ( int32 i = 0; i < MAX_WATERSPRAY_FILES; i++ ) + { + gpWatersprayTex[i] = RwTextureRead(WatersprayFiles[i], nil); + gpWatersprayRaster[i] = RwTextureGetRaster(gpWatersprayTex[i]); + } + + for ( int32 i = 0; i < MAX_EXPLOSIONMEDIUM_FILES; i++ ) + { + gpExplosionMediumTex[i] = RwTextureRead(ExplosionMediumFiles[i], nil); + gpExplosionMediumRaster[i] = RwTextureGetRaster(gpExplosionMediumTex[i]); + } + + for ( int32 i = 0; i < MAX_GUNFLASH_FILES; i++ ) + { + gpGunFlashTex[i] = RwTextureRead(GunFlashFiles[i], nil); + gpGunFlashRaster[i] = RwTextureGetRaster(gpGunFlashTex[i]); + } + + gpRainDropTex = RwTextureRead("raindrop4", nil); + gpRainDropRaster = RwTextureGetRaster(gpRainDropTex); + + + for ( int32 i = 0; i < MAX_RAINSPLASHUP_FILES; i++ ) + { + gpRainSplashupTex[i] = RwTextureRead(RainSplashupFiles[i], nil); + gpRainSplashupRaster[i] = RwTextureGetRaster(gpRainSplashupTex[i]); + } + + for ( int32 i = 0; i < MAX_BIRDFRONT_FILES; i++ ) + { + gpBirdfrontTex[i] = RwTextureRead(BirdfrontFiles[i], nil); + gpBirdfrontRaster[i] = RwTextureGetRaster(gpBirdfrontTex[i]); + } + + for ( int32 i = 0; i < MAX_BOAT_FILES; i++ ) + { + gpBoatTex[i] = RwTextureRead(BoatFiles[i], nil); + gpBoatRaster[i] = RwTextureGetRaster(gpBoatTex[i]); + } + + for ( int32 i = 0; i < MAX_CARDEBRIS_FILES; i++ ) + { + gpCarDebrisTex[i] = RwTextureRead(CardebrisFiles[i], nil); + gpCarDebrisRaster[i] = RwTextureGetRaster(gpCarDebrisTex[i]); + } + + for ( int32 i = 0; i < MAX_CARSPLASH_FILES; i++ ) + { + gpCarSplashTex[i] = RwTextureRead(CarsplashFiles[i], nil); + gpCarSplashRaster[i] = RwTextureGetRaster(gpCarSplashTex[i]); + } + + gpBoatWakeTex = RwTextureRead("boatwake2", nil); + gpBoatWakeRaster = RwTextureGetRaster(gpBoatWakeTex); + + gpFlame1Tex = RwTextureRead("flame1", nil); + gpFlame1Raster = RwTextureGetRaster(gpFlame1Tex); + + gpFlame5Tex = RwTextureRead("flame5", nil); + +//#ifdef FIX_BUGS +#if 0 + gpFlame5Raster = RwTextureGetRaster(gpFlame5Tex); +#else + // this seems to have become more of a design choice + gpFlame5Raster = RwTextureGetRaster(gpFlame1Tex); // copy-paste bug ? +#endif + + gpRainDropSmallTex = RwTextureRead("rainsmall", nil); + gpRainDropSmallRaster = RwTextureGetRaster(gpRainDropSmallTex); + + gpBloodTex = RwTextureRead("blood", nil); + gpBloodRaster = RwTextureGetRaster(gpBloodTex); + + gpLeafTex[0] = RwTextureRead("gameleaf01_64", nil); + gpLeafRaster[0] = RwTextureGetRaster(gpLeafTex[0]); + + gpLeafTex[1] = RwTextureRead("letter", nil); + gpLeafRaster[1] = RwTextureGetRaster(gpLeafTex[1]); + + gpCloudTex1 = RwTextureRead("cloud3", nil); + gpCloudRaster1 = RwTextureGetRaster(gpCloudTex1); + + gpCloudTex4 = RwTextureRead("cloudmasked", nil); + gpCloudRaster4 = RwTextureGetRaster(gpCloudTex4); + + gpBloodSmallTex = RwTextureRead("bloodsplat2", nil); + gpBloodSmallRaster = RwTextureGetRaster(gpBloodSmallTex); + + gpGungeTex = RwTextureRead("gunge", nil); + gpGungeRaster = RwTextureGetRaster(gpGungeTex); + + gpCollisionSmokeTex = RwTextureRead("collisionsmoke", nil); + gpCollisionSmokeRaster = RwTextureGetRaster(gpCollisionSmokeTex); + + gpBulletHitTex = RwTextureRead("bullethitsmoke", nil); + gpBulletHitRaster = RwTextureGetRaster(gpBulletHitTex); + + gpGunShellTex = RwTextureRead("gunshell", nil); + gpGunShellRaster = RwTextureGetRaster(gpGunShellTex); + + gpPointlightTex = RwTextureRead("pointlight", nil); + gpPointlightRaster = RwTextureGetRaster(gpPointlightTex); + + gpSparkTex = RwTextureRead("spark", nil); + gpSparkRaster = RwTextureGetRaster(gpSparkTex); + + gpNewspaperTex = RwTextureRead("newspaper02_64", nil); + gpNewspaperRaster = RwTextureGetRaster(gpNewspaperTex); + + gpGunSmokeTex = RwTextureRead("gunsmoke3", nil); + gpGunSmokeRaster = RwTextureGetRaster(gpGunSmokeTex); + + gpDotTex = RwTextureRead("dot", nil); + gpDotRaster = RwTextureGetRaster(gpDotTex); + + gpHeatHazeTex = RwTextureRead("heathaze", nil); + gpHeatHazeRaster = RwTextureGetRaster(gpHeatHazeTex); + + gpBeastieTex = RwTextureRead("beastie", nil); + gpBeastieRaster = RwTextureGetRaster(gpBeastieTex); + + gpRainDripTex[0] = RwTextureRead("raindrip64", nil); + gpRainDripRaster[0] = RwTextureGetRaster(gpRainDripTex[0]); + + gpRainDripTex[1] = RwTextureRead("raindripb64", nil); + gpRainDripRaster[1] = RwTextureGetRaster(gpRainDripTex[1]); + + gpRainDripDarkTex[0] = RwTextureRead("raindrip64_d", nil); + gpRainDripDarkRaster[0] = RwTextureGetRaster(gpRainDripDarkTex[0]); + + gpRainDripDarkTex[1] = RwTextureRead("raindripb64_d", nil); + gpRainDripDarkRaster[1] = RwTextureGetRaster(gpRainDripDarkTex[1]); + + CTxdStore::PopCurrentTxd(); + + for ( int32 i = 0; i < MAX_PARTICLES; i++ ) + { + tParticleSystemData *entry = &mod_ParticleSystemManager.m_aParticles[i]; + + switch ( i ) + { + case PARTICLE_SPARK: + case PARTICLE_SPARK_SMALL: + case PARTICLE_RAINDROP_SMALL: + case PARTICLE_HELI_ATTACK: + entry->m_ppRaster = &gpRainDropSmallRaster; + break; + + case PARTICLE_WATER_SPARK: + entry->m_ppRaster = &gpSparkRaster; + break; + + case PARTICLE_WHEEL_DIRT: + case PARTICLE_SAND: + case PARTICLE_STEAM2: + case PARTICLE_STEAM_NY: + case PARTICLE_STEAM_NY_SLOWMOTION: + case PARTICLE_GROUND_STEAM: + case PARTICLE_ENGINE_STEAM: + case PARTICLE_PEDFOOT_DUST: + case PARTICLE_CAR_DUST: + case PARTICLE_EXHAUST_FUMES: + entry->m_ppRaster = &gpSmoke2Raster; + break; + + case PARTICLE_WHEEL_WATER: + case PARTICLE_WATER: + case PARTICLE_SMOKE: + case PARTICLE_SMOKE_SLOWMOTION: + case PARTICLE_DRY_ICE: + case PARTICLE_GARAGEPAINT_SPRAY: + case PARTICLE_STEAM: + case PARTICLE_WATER_CANNON: + case PARTICLE_EXTINGUISH_STEAM: + case PARTICLE_HELI_DUST: + case PARTICLE_PAINT_SMOKE: + case PARTICLE_BULLETHIT_SMOKE: + entry->m_ppRaster = gpSmokeRaster; + break; + + case PARTICLE_BLOOD: + entry->m_ppRaster = &gpBloodRaster; + break; + + case PARTICLE_BLOOD_SMALL: + case PARTICLE_BLOOD_SPURT: + entry->m_ppRaster = &gpBloodSmallRaster; + break; + + case PARTICLE_DEBRIS: + case PARTICLE_TREE_LEAVES: + entry->m_ppRaster = gpLeafRaster; + break; + + case PARTICLE_DEBRIS2: + entry->m_ppRaster = &gpGungeRaster; + break; + + case PARTICLE_FLYERS: + entry->m_ppRaster = &gpNewspaperRaster; + break; + + case PARTICLE_FLAME: + case PARTICLE_CARFLAME: + entry->m_ppRaster = &gpFlame1Raster; + break; + + case PARTICLE_FIREBALL: + entry->m_ppRaster = &gpFlame5Raster; + break; + + case PARTICLE_GUNFLASH: + case PARTICLE_GUNFLASH_NOANIM: + entry->m_ppRaster = gpGunFlashRaster; + break; + + + case PARTICLE_GUNSMOKE: + case PARTICLE_WATERDROP: + case PARTICLE_BLOODDROP: + case PARTICLE_HEATHAZE: + case PARTICLE_HEATHAZE_IN_DIST: + entry->m_ppRaster = nil; + break; + + case PARTICLE_GUNSMOKE2: + case PARTICLE_BOAT_THRUSTJET: + case PARTICLE_RUBBER_SMOKE: + entry->m_ppRaster = gpRubberRaster; + break; + + case PARTICLE_CIGARETTE_SMOKE: + entry->m_ppRaster = &gpGunSmokeRaster; + break; + + case PARTICLE_TEARGAS: + entry->m_ppRaster = &gpHeatHazeRaster; + break; + + case PARTICLE_SHARD: + case PARTICLE_RAINDROP: + case PARTICLE_RAINDROP_2D: + entry->m_ppRaster = &gpRainDropRaster; + break; + + case PARTICLE_SPLASH: + case PARTICLE_PED_SPLASH: + case PARTICLE_CAR_SPLASH: + case PARTICLE_WATER_HYDRANT: + entry->m_ppRaster = gpCarSplashRaster; + break; + + case PARTICLE_RAIN_SPLASH: + case PARTICLE_RAIN_SPLASH_BIGGROW: + entry->m_ppRaster = gpRainSplashRaster; + break; + + case PARTICLE_RAIN_SPLASHUP: + entry->m_ppRaster = gpRainSplashupRaster; + break; + + case PARTICLE_WATERSPRAY: + entry->m_ppRaster = gpWatersprayRaster; + break; + + case PARTICLE_EXPLOSION_MEDIUM: + case PARTICLE_EXPLOSION_LARGE: + case PARTICLE_EXPLOSION_MFAST: + case PARTICLE_EXPLOSION_LFAST: + entry->m_ppRaster = gpExplosionMediumRaster; + break; + + case PARTICLE_BOAT_SPLASH: + entry->m_ppRaster = &gpBoatWakeRaster; + break; + + case PARTICLE_ENGINE_SMOKE: + case PARTICLE_ENGINE_SMOKE2: + case PARTICLE_CARFLAME_SMOKE: + case PARTICLE_FIREBALL_SMOKE: + case PARTICLE_ROCKET_SMOKE: + case PARTICLE_TEST: + entry->m_ppRaster = &gpCloudRaster4; + break; + + case PARTICLE_CARCOLLISION_DUST: + case PARTICLE_BURNINGRUBBER_SMOKE: + entry->m_ppRaster = &gpCollisionSmokeRaster; + break; + + case PARTICLE_CAR_DEBRIS: + case PARTICLE_HELI_DEBRIS: + case PARTICLE_BIRD_DEBRIS: + entry->m_ppRaster = gpCarDebrisRaster; + break; + + case PARTICLE_GUNSHELL_FIRST: + case PARTICLE_GUNSHELL: + case PARTICLE_GUNSHELL_BUMP1: + case PARTICLE_GUNSHELL_BUMP2: + entry->m_ppRaster = &gpGunShellRaster; + break; + + + case PARTICLE_BIRD_FRONT: + entry->m_ppRaster = gpBirdfrontRaster; + break; + + case PARTICLE_SHIP_SIDE: + entry->m_ppRaster = gpBoatRaster; + break; + + case PARTICLE_BEASTIE: + entry->m_ppRaster = &gpBeastieRaster; + break; + } + } + + debug("CParticle ready"); +} + +void CParticle::Shutdown() +{ + debug("Shutting down CParticle..."); + + for ( int32 i = 0; i < MAX_SMOKE_FILES; i++ ) + { + RwTextureDestroy(gpSmokeTex[i]); + gpSmokeTex[i] = nil; + } + + RwTextureDestroy(gpSmoke2Tex); + gpSmoke2Tex = nil; + + for ( int32 i = 0; i < MAX_RUBBER_FILES; i++ ) + { + RwTextureDestroy(gpRubberTex[i]); + gpRubberTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_RAINSPLASH_FILES; i++ ) + { + RwTextureDestroy(gpRainSplashTex[i]); + gpRainSplashTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_WATERSPRAY_FILES; i++ ) + { + RwTextureDestroy(gpWatersprayTex[i]); + gpWatersprayTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_EXPLOSIONMEDIUM_FILES; i++ ) + { + RwTextureDestroy(gpExplosionMediumTex[i]); + gpExplosionMediumTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_GUNFLASH_FILES; i++ ) + { + RwTextureDestroy(gpGunFlashTex[i]); + gpGunFlashTex[i] = nil; + } + + RwTextureDestroy(gpRainDropTex); + gpRainDropTex = nil; + + for ( int32 i = 0; i < MAX_RAINSPLASHUP_FILES; i++ ) + { + RwTextureDestroy(gpRainSplashupTex[i]); + gpRainSplashupTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_BIRDFRONT_FILES; i++ ) + { + RwTextureDestroy(gpBirdfrontTex[i]); + gpBirdfrontTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_BOAT_FILES; i++ ) + { + RwTextureDestroy(gpBoatTex[i]); + gpBoatTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_CARDEBRIS_FILES; i++ ) + { + RwTextureDestroy(gpCarDebrisTex[i]); + gpCarDebrisTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_CARSPLASH_FILES; i++ ) + { + RwTextureDestroy(gpCarSplashTex[i]); + gpCarSplashTex[i] = nil; + } + + for ( int32 i = 0; i < MAX_RAINDRIP_FILES; i++ ) + { + RwTextureDestroy(gpRainDripTex[i]); + gpRainDripTex[i] = nil; + + RwTextureDestroy(gpRainDripDarkTex[i]); + gpRainDripDarkTex[i] = nil; + } + + RwTextureDestroy(gpBoatWakeTex); + gpBoatWakeTex = nil; + + RwTextureDestroy(gpFlame1Tex); + gpFlame1Tex = nil; + + RwTextureDestroy(gpFlame5Tex); + gpFlame5Tex = nil; + + RwTextureDestroy(gpRainDropSmallTex); + gpRainDropSmallTex = nil; + + RwTextureDestroy(gpBloodTex); + gpBloodTex = nil; + + RwTextureDestroy(gpLeafTex[0]); + gpLeafTex[0] = nil; + + RwTextureDestroy(gpLeafTex[1]); + gpLeafTex[1] = nil; + + RwTextureDestroy(gpCloudTex1); + gpCloudTex1 = nil; + + RwTextureDestroy(gpCloudTex4); + gpCloudTex4 = nil; + + RwTextureDestroy(gpBloodSmallTex); + gpBloodSmallTex = nil; + + RwTextureDestroy(gpGungeTex); + gpGungeTex = nil; + + RwTextureDestroy(gpCollisionSmokeTex); + gpCollisionSmokeTex = nil; + + RwTextureDestroy(gpBulletHitTex); + gpBulletHitTex = nil; + + RwTextureDestroy(gpGunShellTex); + gpGunShellTex = nil; + + RwTextureDestroy(gpPointlightTex); + gpPointlightTex = nil; + + RwTextureDestroy(gpSparkTex); + gpSparkTex = nil; + + RwTextureDestroy(gpNewspaperTex); + gpNewspaperTex = nil; + + RwTextureDestroy(gpGunSmokeTex); + gpGunSmokeTex = nil; + + RwTextureDestroy(gpDotTex); + gpDotTex = nil; + RwTextureDestroy(gpHeatHazeTex); + gpHeatHazeTex = nil; + + RwTextureDestroy(gpBeastieTex); + gpBeastieTex = nil; + + int32 slot; + + slot = CTxdStore::FindTxdSlot("particle"); + CTxdStore::RemoveTxdSlot(slot); + + debug("CParticle shut down"); +} + + +void CParticle::AddParticlesAlongLine(tParticleType type, CVector const &vecStart, CVector const &vecEnd, CVector const &vecDir, float fPower, CEntity *pEntity, float fSize, int32 nRotationSpeed, int32 nRotation, int32 nCurFrame, int32 nLifeSpan) +{ + CVector vecDist = vecEnd - vecStart; + float fDist = vecDist.Magnitude(); + float fSteps = Max(fDist / fPower, 1.0f); + int32 nSteps = (int32)fSteps; + + CVector vecStep = vecDist * (1.0f / (float)nSteps); + + for ( int32 i = 0; i < nSteps; i++ ) + { + CVector vecPos = float(i) * vecStep + vecStart; + AddParticle(type, vecPos, vecDir, pEntity, fSize, nRotationSpeed, nRotation, nCurFrame, nLifeSpan); + } +} + +void CParticle::AddParticlesAlongLine(tParticleType type, CVector const &vecStart, CVector const &vecEnd, CVector const &vecDir, float fPower, CEntity *pEntity, float fSize, RwRGBA const &color, int32 nRotationSpeed, int32 nRotation, int32 nCurFrame, int32 nLifeSpan) +{ + CVector vecDist = vecEnd - vecStart; + float fDist = vecDist.Magnitude(); + float fSteps = Max(fDist / fPower, 1.0f); + int32 nSteps = (int32)fSteps; + + CVector vecStep = vecDist * (1.0f / (float)nSteps); + + for ( int32 i = 0; i < nSteps; i++ ) + { + CVector vecPos = float(i) * vecStep + vecStart; + + AddParticle(type, vecPos, vecDir, pEntity, fSize, color, nRotationSpeed, nRotation, nCurFrame, nLifeSpan); + } +} + +CParticle *CParticle::AddParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, CEntity *pEntity, float fSize, int32 nRotationSpeed, int32 nRotation, int32 nCurFrame, int32 nLifeSpan) +{ + CRGBA color(0, 0, 0, 0); + return AddParticle(type, vecPos, vecDir, pEntity, fSize, color, nRotationSpeed, nRotation, nCurFrame, nLifeSpan); +} + +CParticle *CParticle::AddParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, CEntity *pEntity, float fSize, RwRGBA const &color, int32 nRotationSpeed, int32 nRotation, int32 nCurFrame, int32 nLifeSpan) +{ + if ( CTimer::GetIsPaused() ) + return nil; + + if ( ( type == PARTICLE_ENGINE_SMOKE + || type == PARTICLE_ENGINE_SMOKE2 + || type == PARTICLE_ENGINE_STEAM + || type == PARTICLE_CARFLAME_SMOKE + || type == PARTICLE_RUBBER_SMOKE + || type == PARTICLE_BURNINGRUBBER_SMOKE + || type == PARTICLE_EXHAUST_FUMES + || type == PARTICLE_CARCOLLISION_DUST ) + && nParticleCreationInterval & CTimer::GetFrameCounter() ) + { + return nil; + } + + if ( !CReplay::IsPlayingBack() ) + CReplay::RecordParticle(type, vecPos, vecDir, fSize, color); + + CParticle *pParticle = m_pUnusedListHead; + + if ( pParticle == nil ) + return nil; + + tParticleSystemData *psystem = &mod_ParticleSystemManager.m_aParticles[type]; + + if ( psystem->m_fCreateRange != 0.0f && psystem->m_fCreateRange < ( TheCamera.GetPosition() - vecPos ).MagnitudeSqr() ) + return nil; + + + pParticle->m_fSize = psystem->m_fDefaultInitialRadius; + pParticle->m_fExpansionRate = psystem->m_fExpansionRate; + + if ( nLifeSpan != 0 ) + pParticle->m_nTimeWhenWillBeDestroyed = CTimer::GetTimeInMilliseconds() + nLifeSpan; + else + pParticle->m_nTimeWhenWillBeDestroyed = CTimer::GetTimeInMilliseconds() + psystem->m_nLifeSpan; + + pParticle->m_nColorIntensity = psystem->m_nFadeToBlackInitialIntensity; + + pParticle->m_nFadeToBlackTimer = psystem->m_nFadeToBlackAmount; + + if ( psystem->m_nFadeToBlackTime ) + pParticle->m_nFadeToBlackTimer /= psystem->m_nFadeToBlackTime; + + pParticle->m_nAlpha = psystem->m_nFadeAlphaInitialIntensity; + + pParticle->m_nFadeAlphaTimer = psystem->m_nFadeAlphaAmount; + + if ( psystem->m_nFadeAlphaTime ) + pParticle->m_nFadeAlphaTimer /= psystem->m_nFadeAlphaTime; + + pParticle->m_nCurrentZRotation = psystem->m_nZRotationInitialAngle; + pParticle->m_fCurrentZRadius = psystem->m_fInitialZRadius; + + if ( nCurFrame != 0 ) + pParticle->m_nCurrentFrame = nCurFrame; + else + pParticle->m_nCurrentFrame = psystem->m_nStartAnimationFrame; + + + pParticle->m_nZRotationTimer = 0; + pParticle->m_nZRadiusTimer = 0; + pParticle->m_nAnimationSpeedTimer = 0; + pParticle->m_fZGround = 0.0f; + + if ( type != PARTICLE_HEATHAZE ) + pParticle->m_vecPosition = vecPos; + else + { + CVector screen; + float w, h; + + if ( !CSprite::CalcScreenCoors(vecPos, &screen, &w, &h, true) ) + return nil; + + pParticle->m_vecPosition = screen; + psystem->m_vecTextureStretch.x = w; + psystem->m_vecTextureStretch.y = h; + } + + pParticle->m_vecVelocity = vecDir; + + pParticle->m_vecParticleMovementOffset = CVector(0.0f, 0.0f, 0.0f); + pParticle->m_nTimeWhenColorWillBeChanged = 0; + + if ( color.alpha != 0 ) + RwRGBAAssign(&pParticle->m_Color, &color); + else + { + RwRGBAAssign(&pParticle->m_Color, psystem->m_RenderColouring); + + if ( psystem->m_ColorFadeTime != 0 ) + pParticle->m_nTimeWhenColorWillBeChanged = CTimer::GetTimeInMilliseconds() + psystem->m_ColorFadeTime; + + if ( psystem->m_InitialColorVariation != 0 ) + { + int32 ColorVariation = CGeneral::GetRandomNumberInRange(-psystem->m_InitialColorVariation, psystem->m_InitialColorVariation); + //float ColorVariation = CGeneral::GetRandomNumberInRange((float)-psystem->m_InitialColorVariation, (float)psystem->m_InitialColorVariation); + + pParticle->m_Color.red = Clamp(pParticle->m_Color.red + + PERCENT(pParticle->m_Color.red, ColorVariation), + 0, 255); + + pParticle->m_Color.green = Clamp(pParticle->m_Color.green + + PERCENT(pParticle->m_Color.green, ColorVariation), + 0, 255); + + pParticle->m_Color.blue = Clamp(pParticle->m_Color.blue + + PERCENT(pParticle->m_Color.blue, ColorVariation), + 0, 255); + } + } + + pParticle->m_nRotation = nRotation; + + if ( nRotationSpeed != 0 ) + pParticle->m_nRotationStep = nRotationSpeed; + else + pParticle->m_nRotationStep = psystem->m_nRotationSpeed; + + if ( CGeneral::GetRandomNumber() & 1 ) + pParticle->m_nRotationStep = -pParticle->m_nRotationStep; + + if ( psystem->m_fPositionRandomError != 0.0f ) + { + pParticle->m_vecPosition.x += psystem->m_fPositionRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + pParticle->m_vecPosition.y += psystem->m_fPositionRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + + if ( psystem->Flags & RAND_VERT_V ) + pParticle->m_vecPosition.z += psystem->m_fPositionRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + } + + if ( psystem->m_fVelocityRandomError != 0.0f ) + { + pParticle->m_vecVelocity.x += psystem->m_fVelocityRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + pParticle->m_vecVelocity.y += psystem->m_fVelocityRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + + if ( psystem->Flags & RAND_VERT_V ) + pParticle->m_vecVelocity.z += psystem->m_fVelocityRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + } + + if ( psystem->m_fExpansionRateError != 0.0f && !(psystem->Flags & SCREEN_TRAIL) ) + pParticle->m_fExpansionRate += psystem->m_fExpansionRateError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE] + psystem->m_fExpansionRateError; + + if ( psystem->m_nRotationRateError != 0 ) + pParticle->m_nRotationStep += CGeneral::GetRandomNumberInRange(-psystem->m_nRotationRateError, psystem->m_nRotationRateError); + + if ( psystem->m_nLifeSpanErrorShape != 0 ) + { + float randVal = ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + if ( randVal > 0.0f ) + pParticle->m_nTimeWhenWillBeDestroyed += int32(float(psystem->m_nLifeSpan) * randVal * float(psystem->m_nLifeSpanErrorShape)); + else + pParticle->m_nTimeWhenWillBeDestroyed += int32(float(psystem->m_nLifeSpan) * randVal / float(psystem->m_nLifeSpanErrorShape)); + } + + if ( psystem->Flags & ZCHECK_FIRST ) + { + static bool bValidGroundFound = false; + static CVector LastTestCoors; + static float LastTestGroundZ; + + if ( bValidGroundFound + && vecPos.x == LastTestCoors.x + && vecPos.y == LastTestCoors.y + && vecPos.z == LastTestCoors.z ) + { + pParticle->m_fZGround = LastTestGroundZ; + } + else + { + bValidGroundFound = false; + + CColPoint point; + CEntity *entity; + + if ( !CWorld::ProcessVerticalLine( + pParticle->m_vecPosition + CVector(0.0f, 0.0f, 0.5f), + -100.0f, point, entity, true, true, false, false, true, false, nil) ) + { + return nil; + } + + if ( point.point.z >= pParticle->m_vecPosition.z ) + return nil; + + pParticle->m_fZGround = point.point.z; + bValidGroundFound = true; + LastTestCoors = vecPos; + LastTestGroundZ = point.point.z; + } + } + + if ( psystem->Flags & ZCHECK_BUMP ) + { + static float Z_Ground = 0.0f; + + if ( psystem->Flags & ZCHECK_BUMP_FIRST ) + { + bool bZFound = false; + + Z_Ground = CWorld::FindGroundZFor3DCoord(vecPos.x, vecPos.y, vecPos.z, (bool *)&bZFound); + + if ( bZFound == false ) + return nil; + + pParticle->m_fZGround = Z_Ground; + } + + pParticle->m_fZGround = Z_Ground; + } + + switch ( type ) + { + case PARTICLE_DEBRIS: + pParticle->m_vecVelocity.z *= CGeneral::GetRandomNumberInRange(0.5f, 3.0f); + break; + + case PARTICLE_EXPLOSION_MEDIUM: + pParticle->m_nColorIntensity -= 30 * (CGeneral::GetRandomNumber() & 1); // mb "+= -30 * rand" here ? + pParticle->m_nAnimationSpeedTimer = CGeneral::GetRandomNumber() & 7; + pParticle->m_fSize = CGeneral::GetRandomNumberInRange(0.3f, 0.8f); + pParticle->m_vecPosition.z -= CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + break; + + case PARTICLE_EXPLOSION_LARGE: + pParticle->m_nColorIntensity -= 30 * (CGeneral::GetRandomNumber() & 1); // mb "+= -30 * rand" here ? + pParticle->m_nAnimationSpeedTimer = CGeneral::GetRandomNumber() & 7; + pParticle->m_fSize = CGeneral::GetRandomNumberInRange(0.8f, 1.4f); + pParticle->m_vecPosition.z -= CGeneral::GetRandomNumberInRange(-0.3f, 0.3f); + break; + + case PARTICLE_WATER_HYDRANT: + pParticle->m_vecPosition.z += 20.0f * psystem->m_fPositionRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + break; + default: break; + } + + if ( fSize != 0.0f ) + pParticle->m_fSize = fSize; + + m_pUnusedListHead = pParticle->m_pNext; + + pParticle->m_pNext = psystem->m_pParticles; + + psystem->m_pParticles = pParticle; + + return pParticle; +} + +void CParticle::Update() +{ + if ( CTimer::GetIsPaused() ) + return; + + CRGBA color(0, 0, 0, 0); + + float fFricDeccel50 = pow(0.50f, CTimer::GetTimeStep()); + float fFricDeccel80 = pow(0.80f, CTimer::GetTimeStep()); + float fFricDeccel90 = pow(0.90f, CTimer::GetTimeStep()); + float fFricDeccel95 = pow(0.95f, CTimer::GetTimeStep()); + float fFricDeccel96 = pow(0.96f, CTimer::GetTimeStep()); + float fFricDeccel99 = pow(0.99f, CTimer::GetTimeStep()); + + CParticleObject::UpdateAll(); + + // ejaculation at 23:00, 23:15, 23:30, 23:45 + if ( CClock::ms_nGameClockHours == 23 && + ( CClock::ms_nGameClockMinutes == 0 + || CClock::ms_nGameClockMinutes == 15 + || CClock::ms_nGameClockMinutes == 30 + || CClock::ms_nGameClockMinutes == 45 ) ) + { + AddParticle(PARTICLE_CAR_SPLASH, + CVector(557.03f, -4.0f, 151.46f), + CVector(0.0f, 0.0f, 2.5f), + NULL, + 2.0f, + CRGBA(255, 255, 255, 255), + 0, + 0, + 1, + 1000); + } + + for ( int32 i = 0; i < MAX_PARTICLES; i++ ) + { + tParticleSystemData *psystem = &mod_ParticleSystemManager.m_aParticles[i]; + CParticle *particle = psystem->m_pParticles; + CParticle *prevParticle = nil; + bool bRemoveParticle; + + if ( particle == nil ) + continue; + + for ( ; particle != nil; _Next(particle, prevParticle, psystem, bRemoveParticle) ) + { + CVector vecWind(0.0f, 0.0f, 0.0f); + + bRemoveParticle = false; + + CVector vecMoveStep = particle->m_vecVelocity * CTimer::GetTimeStep(); + CVector vecPos = particle->m_vecPosition; + + if ( numWaterDropOnScreen == 0 ) + clearWaterDrop = false; + + if ( psystem->m_Type == PARTICLE_WATERDROP ) + { + if ( CGame::IsInInterior() || clearWaterDrop == true ) + { + bRemoveParticle = true; + continue; + } + + static uint8 nWaterDropCount; + + if ( nWaterDropCount == 5 ) + { + vecMoveStep = CVector(0.0f, 0.0f, 0.0f); + particle->m_nTimeWhenWillBeDestroyed += 1250; + nWaterDropCount = 0; + } + else + { + if ( TheCamera.m_CameraAverageSpeed > 0.35f ) + { + if ( vecMoveStep.Magnitude() > 0.5f ) + { + if ( vecMoveStep.Magnitude() > 0.4f && vecMoveStep.Magnitude() < 0.8f ) + { + vecMoveStep.x += TheCamera.m_CameraAverageSpeed * 1.5f; + vecMoveStep.y += TheCamera.m_CameraAverageSpeed * 1.5f; + } + else if ( vecMoveStep.Magnitude() != 0.0f ) + { + vecMoveStep.x += CGeneral::GetRandomNumberInRange(0.01f, 0.05f); + vecMoveStep.y += CGeneral::GetRandomNumberInRange(0.01f, 0.05f); + } + } + } + + nWaterDropCount++; + } + + if ( vecPos.z <= 1.5f ) + vecMoveStep.z = 0.0f; + } + + if ( psystem->m_Type == PARTICLE_HEATHAZE || psystem->m_Type == PARTICLE_HEATHAZE_IN_DIST ) + { +#ifdef FIX_BUGS + int32 nSinCosIndex = (int32(DEGTORAD((float)particle->m_nRotation) * float(SIN_COS_TABLE_SIZE) / TWOPI) + SIN_COS_TABLE_SIZE) % SIN_COS_TABLE_SIZE; +#else + int32 nSinCosIndex = int32(DEGTORAD((float)particle->m_nRotation) * float(SIN_COS_TABLE_SIZE) / TWOPI) % SIN_COS_TABLE_SIZE; +#endif + vecMoveStep.x = Sin(nSinCosIndex); + vecMoveStep.y = Sin(nSinCosIndex); + + if ( psystem->m_Type == PARTICLE_HEATHAZE_IN_DIST ) + particle->m_nRotation = int16((float)particle->m_nRotation + 0.75f); + else + particle->m_nRotation = int16((float)particle->m_nRotation + 1.0f); + } + + if ( psystem->m_Type == PARTICLE_BEASTIE ) + { +#ifdef FIX_BUGS + int32 nSinCosIndex = (int32(DEGTORAD((float)particle->m_nRotation) * float(SIN_COS_TABLE_SIZE) / TWOPI) + SIN_COS_TABLE_SIZE) % SIN_COS_TABLE_SIZE; +#else + int32 nSinCosIndex = int32(DEGTORAD((float)particle->m_nRotation) * float(SIN_COS_TABLE_SIZE) / TWOPI) % SIN_COS_TABLE_SIZE; +#endif + particle->m_vecVelocity.x = 0.50f * Cos(nSinCosIndex); + particle->m_vecVelocity.y = Cos(nSinCosIndex); + particle->m_vecVelocity.z = 0.25f * Sin(nSinCosIndex); + + if ( particle->m_vecVelocity.Magnitude() > 2.0f + || vecPos.z > 40.0f + || (TheCamera.GetPosition() - vecPos).Magnitude() < 60.0f + ) + { + bRemoveParticle = true; + continue; + } + } + + vecPos += vecMoveStep; + + if ( psystem->m_Type == PARTICLE_FIREBALL ) + { + AddParticle(PARTICLE_HEATHAZE, particle->m_vecPosition, CVector(0.0f, 0.0f, 0.0f), + nil, particle->m_fSize * 5.0f); + } + + if ( psystem->m_Type == PARTICLE_GUNSMOKE2 ) + { + if ( CTimer::GetFrameCounter() & 10 ) + { +#ifdef FIX_BUGS + if ( FindPlayerPed() && FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN ) +#else + if ( FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN ) +#endif + { + AddParticle(PARTICLE_HEATHAZE, particle->m_vecPosition, CVector(0.0f, 0.0f, 0.0f)); + } + } + } + + if ( CWeather::Wind > 0.0f ) + { + if ( vecMoveStep.Magnitude() != 0.0f ) + { + vecWind.x = CGeneral::GetRandomNumberInRange(0.75f, 1.25f) * -CWeather::Wind; + vecWind.y = CGeneral::GetRandomNumberInRange(0.75f, 1.25f) * -CWeather::Wind; + vecWind *= PARTICLE_WIND_TEST_SCALE * psystem->m_fWindFactor * CTimer::GetTimeStep(); + particle->m_vecVelocity += vecWind; + } + } + + if ( psystem->m_Type == PARTICLE_RAINDROP + || psystem->m_Type == PARTICLE_RAINDROP_SMALL + || psystem->m_Type == PARTICLE_RAIN_SPLASH + || psystem->m_Type == PARTICLE_RAIN_SPLASH_BIGGROW + || psystem->m_Type == PARTICLE_CAR_SPLASH + || psystem->m_Type == PARTICLE_BOAT_SPLASH + || psystem->m_Type == PARTICLE_RAINDROP_2D ) + { + int32 nMaxDrops = int32(6.0f * TheCamera.m_CameraAverageSpeed + 1.0f); + float fDistToCam = 0.0f; + + if ( psystem->m_Type == PARTICLE_BOAT_SPLASH || psystem->m_Type == PARTICLE_CAR_SPLASH ) + { + if ( vecPos.z + particle->m_fSize < 5.0f ) + { + bRemoveParticle = true; + continue; + } + + switch ( TheCamera.GetLookDirection() ) + { + case LOOKING_LEFT: + case LOOKING_RIGHT: + case LOOKING_FORWARD: + nMaxDrops /= 2; + break; + + default: + nMaxDrops = 0; + break; + } + + fDistToCam = (TheCamera.GetPosition() - vecPos).Magnitude(); + } + + if ( numWaterDropOnScreen < nMaxDrops && numWaterDropOnScreen < 63 + && fDistToCam < 10.0f + && clearWaterDrop == false + && !CGame::IsInInterior() ) + { + CVector vecWaterdropTarget + ( + CGeneral::GetRandomNumberInRange(-0.25f, 0.25f), + CGeneral::GetRandomNumberInRange(0.1f, 0.75f), + -0.01f + ); + + CVector vecWaterdropPos; + + if ( TheCamera.m_CameraAverageSpeed < 0.35f ) + vecWaterdropPos.x = (float)CGeneral::GetRandomNumberInRange(50, int32(SCREEN_WIDTH) - 50); + else + vecWaterdropPos.x = (float)CGeneral::GetRandomNumberInRange(200, int32(SCREEN_WIDTH) - 200); + + if ( psystem->m_Type == PARTICLE_BOAT_SPLASH || psystem->m_Type == PARTICLE_CAR_SPLASH ) + vecWaterdropPos.y = (float)CGeneral::GetRandomNumberInRange(SCREEN_HEIGHT / 2, SCREEN_HEIGHT); + else + { + if ( TheCamera.m_CameraAverageSpeed < 0.35f ) + vecWaterdropPos.y = (float)CGeneral::GetRandomNumberInRange(0, int32(SCREEN_HEIGHT)); + else + vecWaterdropPos.y = (float)CGeneral::GetRandomNumberInRange(150, int32(SCREEN_HEIGHT) - 200); + } + + vecWaterdropPos.z = 2.0f; + + if ( AddParticle(PARTICLE_WATERDROP, + vecWaterdropPos, + vecWaterdropTarget, + nil, + CGeneral::GetRandomNumberInRange(0.1f, 0.15f), + 0, + 0, + CGeneral::GetRandomNumber() & 1, + 0) != nil ) + { + numWaterDropOnScreen++; + } + } + } + + if ( CTimer::GetTimeInMilliseconds() > particle->m_nTimeWhenWillBeDestroyed || particle->m_nAlpha == 0 ) + { + bRemoveParticle = true; + continue; + } + + if ( particle->m_nTimeWhenColorWillBeChanged != 0 ) + { + if ( particle->m_nTimeWhenColorWillBeChanged > CTimer::GetTimeInMilliseconds() ) + { + float colorMul = 1.0f - float(particle->m_nTimeWhenColorWillBeChanged - CTimer::GetTimeInMilliseconds()) / float(psystem->m_ColorFadeTime); + + particle->m_Color.red = Clamp( + psystem->m_RenderColouring.red + int32(float(psystem->m_FadeDestinationColor.red - psystem->m_RenderColouring.red) * colorMul), + 0, 255); + + particle->m_Color.green = Clamp( + psystem->m_RenderColouring.green + int32(float(psystem->m_FadeDestinationColor.green - psystem->m_RenderColouring.green) * colorMul), + 0, 255); + + particle->m_Color.blue = Clamp( + psystem->m_RenderColouring.blue + int32(float(psystem->m_FadeDestinationColor.blue - psystem->m_RenderColouring.blue) * colorMul), + 0, 255); + } + else + RwRGBAAssign(&particle->m_Color, psystem->m_FadeDestinationColor); + } + + if ( psystem->Flags & CLIPOUT2D ) + { + if ( particle->m_vecPosition.x < -10.0f || particle->m_vecPosition.x > SCREEN_WIDTH + 10.0f + || particle->m_vecPosition.y < -10.0f || particle->m_vecPosition.y > SCREEN_HEIGHT + 10.0f ) + { + bRemoveParticle = true; + continue; + } + } + + if ( !(psystem->Flags & SCREEN_TRAIL) ) + { + float size; + + if ( particle->m_fExpansionRate > 0.0f ) + { + float speed = Max(vecWind.Magnitude(), vecMoveStep.Magnitude()); + + if ( psystem->m_Type == PARTICLE_EXHAUST_FUMES || psystem->m_Type == PARTICLE_ENGINE_STEAM ) + speed *= 2.0f; + + if ( ( psystem->m_Type == PARTICLE_BOAT_SPLASH || psystem->m_Type == PARTICLE_CAR_SPLASH ) + && particle->m_fSize > 1.2f ) + { + size = particle->m_fSize - (1.0f + speed) * particle->m_fExpansionRate; + particle->m_vecVelocity.z -= 0.15f; + } + else + size = particle->m_fSize + (1.0f + speed) * particle->m_fExpansionRate; + } + else + size = particle->m_fSize + particle->m_fExpansionRate; + + if ( psystem->m_Type == PARTICLE_WATERDROP ) + size = (size - Abs(vecMoveStep.x) * 0.000150000007f) + (Abs(vecMoveStep.z) * 0.0500000007f); //TODO: + + if ( size < 0.0f ) + { + bRemoveParticle = true; + continue; + } + + particle->m_fSize = size; + } + + switch ( psystem->m_nFrictionDecceleration ) + { + case 50: + particle->m_vecVelocity *= fFricDeccel50; + break; + + case 80: + particle->m_vecVelocity *= fFricDeccel80; + break; + + case 90: + particle->m_vecVelocity *= fFricDeccel90; + break; + + case 95: + particle->m_vecVelocity *= fFricDeccel95; + break; + + case 96: + particle->m_vecVelocity *= fFricDeccel96; + break; + + case 99: + particle->m_vecVelocity *= fFricDeccel99; + break; + } + + if ( psystem->m_fGravitationalAcceleration > 0.0f ) + { + if ( -50.0f * psystem->m_fGravitationalAcceleration < particle->m_vecVelocity.z ) + particle->m_vecVelocity.z -= psystem->m_fGravitationalAcceleration * CTimer::GetTimeStep(); + + if ( psystem->Flags & ZCHECK_FIRST ) + { + if ( particle->m_vecPosition.z < particle->m_fZGround ) + { + switch ( psystem->m_Type ) + { + case PARTICLE_RAINDROP: + case PARTICLE_RAINDROP_SMALL: + { + bRemoveParticle = true; + + if ( CGeneral::GetRandomNumber() & 1 ) + { + AddParticle(PARTICLE_RAIN_SPLASH, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 0, 0, 0, 0); + } + else + { + AddParticle(PARTICLE_RAIN_SPLASHUP, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 0, 0, 0, 0); + } + + continue; + } + break; + + case PARTICLE_WHEEL_WATER: + { + bRemoveParticle = true; + + int32 randVal = CGeneral::GetRandomNumber(); + + if ( randVal & 1 ) + { + if ( (randVal % 5) == 0 ) + { + AddParticle(PARTICLE_RAIN_SPLASH, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 0, 0, 0, 0); + } + else + { + AddParticle(PARTICLE_RAIN_SPLASHUP, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 0, 0, 0, 0); + } + + } + continue; + } + break; + + case PARTICLE_BLOOD: + case PARTICLE_BLOOD_SMALL: + { + bRemoveParticle = true; + + CVector vecPosn = particle->m_vecPosition; + vecPosn.z += 1.0f; + + Randomizer++; + int32 randVal = int32(Randomizer & 7); + + if ( randVal == 5 ) + { + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &vecPosn, + 0.1f, 0.0f, 0.0f, -0.1f, + 255, + 255, 0, 0, + 4.0f, (CGeneral::GetRandomNumber() & 4095) + 2000, 1.0f); + } + else if ( randVal == 2 ) + { + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &vecPosn, + 0.2f, 0.0f, 0.0f, -0.2f, + 255, + 255, 0, 0, + 4.0f, (CGeneral::GetRandomNumber() & 4095) + 8000, 1.0f); + } + continue; + } + break; + default: break; + } + } + } + else if ( psystem->Flags & ZCHECK_STEP ) + { + CColPoint point; + CEntity *entity; + + if ( CWorld::ProcessVerticalLine(particle->m_vecPosition, vecPos.z, point, entity, + true, true, false, false, true, false, nil) ) + { + if ( vecPos.z <= point.point.z ) + { + vecPos.z = point.point.z; + if ( psystem->m_Type == PARTICLE_DEBRIS2 ) + { + particle->m_vecVelocity.x *= 0.8f; + particle->m_vecVelocity.y *= 0.8f; + particle->m_vecVelocity.z *= -0.4f; + if ( particle->m_vecVelocity.z < 0.005f ) + particle->m_vecVelocity.z = 0.0f; + } + } + } + } + else if ( psystem->Flags & ZCHECK_BUMP ) + { + if ( particle->m_vecPosition.z < particle->m_fZGround ) + { + switch ( psystem->m_Type ) + { + case PARTICLE_GUNSHELL_FIRST: + case PARTICLE_GUNSHELL: + { + bRemoveParticle = true; + + AddParticle(PARTICLE_GUNSHELL_BUMP1, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector + ( + CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), + CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), + CGeneral::GetRandomNumberInRange(0.05f, 0.1f) + ), + nil, + particle->m_fSize, color, particle->m_nRotationStep, 0, 0, 0); + + PlayOneShotScriptObject(SCRIPT_SOUND_GUNSHELL_DROP, particle->m_vecPosition); + } + break; + + case PARTICLE_GUNSHELL_BUMP1: + { + bRemoveParticle = true; + + AddParticle(PARTICLE_GUNSHELL_BUMP2, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.03f, 0.06f)), + nil, + particle->m_fSize, color, 0, 0, 0, 0); + + PlayOneShotScriptObject(SCRIPT_SOUND_GUNSHELL_DROP_SOFT, particle->m_vecPosition); + } + break; + + case PARTICLE_GUNSHELL_BUMP2: + { + bRemoveParticle = true; + continue; + } + break; + default: break; + } + } + } + } + else + { + if ( psystem->m_fGravitationalAcceleration < 0.0f ) + { + if ( -5.0f * psystem->m_fGravitationalAcceleration > particle->m_vecVelocity.z ) + particle->m_vecVelocity.z -= psystem->m_fGravitationalAcceleration * CTimer::GetTimeStep(); + } + else + { + if ( psystem->Flags & ZCHECK_STEP ) + { + CColPoint point; + CEntity *entity; + + if ( CWorld::ProcessVerticalLine(particle->m_vecPosition, vecPos.z, point, entity, + true, false, false, false, true, false, nil) ) + { + if ( vecPos.z <= point.point.z ) + { + vecPos.z = point.point.z; + if ( psystem->m_Type == PARTICLE_HELI_ATTACK ) + { + bRemoveParticle = true; + AddParticle(PARTICLE_STEAM, vecPos, CVector(0.0f, 0.0f, 0.05f), nil, 0.2f, 0, 0, 0, 0); + continue; + } + } + } + } + } + } + + if ( particle->m_nFadeToBlackTimer != 0 ) + { + particle->m_nColorIntensity = Clamp(particle->m_nColorIntensity - particle->m_nFadeToBlackTimer, + 0, 255); + } + + if ( particle->m_nFadeAlphaTimer != 0 ) + { + particle->m_nAlpha = Clamp(particle->m_nAlpha - particle->m_nFadeAlphaTimer, + 0, 255); + if ( particle->m_nAlpha == 0 ) + { + bRemoveParticle = true; + continue; + } + } + + if ( psystem->m_nZRotationAngleChangeAmount != 0 ) + { + if ( particle->m_nZRotationTimer >= psystem->m_nZRotationChangeTime ) + { + particle->m_nZRotationTimer = 0; + particle->m_nCurrentZRotation += psystem->m_nZRotationAngleChangeAmount; + } + else + ++particle->m_nZRotationTimer; + } + + if ( psystem->m_fZRadiusChangeAmount != 0.0f ) + { + if ( particle->m_nZRadiusTimer >= psystem->m_nZRadiusChangeTime ) + { + particle->m_nZRadiusTimer = 0; + particle->m_fCurrentZRadius += psystem->m_fZRadiusChangeAmount; + } + else + ++particle->m_nZRadiusTimer; + } + + if ( psystem->m_nAnimationSpeed != 0 ) + { + if ( particle->m_nAnimationSpeedTimer > psystem->m_nAnimationSpeed ) + { + particle->m_nAnimationSpeedTimer = 0; + + if ( ++particle->m_nCurrentFrame > psystem->m_nFinalAnimationFrame ) + { + if ( psystem->Flags & CYCLE_ANIM ) + particle->m_nCurrentFrame = psystem->m_nStartAnimationFrame; + else + --particle->m_nCurrentFrame; + } + } + else + ++particle->m_nAnimationSpeedTimer; + } + + if ( particle->m_nRotationStep != 0 ) +#ifdef FIX_BUGS + particle->m_nRotation = CGeneral::LimitAngle(particle->m_nRotation + particle->m_nRotationStep); +#else + particle->m_nRotation += particle->m_nRotationStep; +#endif + + if ( particle->m_fCurrentZRadius != 0.0f ) + { + int32 nSinCosIndex = particle->m_nCurrentZRotation % SIN_COS_TABLE_SIZE; + + float fX = (Cos(nSinCosIndex) - Sin(nSinCosIndex)) * particle->m_fCurrentZRadius; + + float fY = (Sin(nSinCosIndex) + Cos(nSinCosIndex)) * particle->m_fCurrentZRadius; + + vecPos -= particle->m_vecParticleMovementOffset; + + vecPos += CVector(fX, fY, 0.0f); + + particle->m_vecParticleMovementOffset = CVector(fX, fY, 0.0f); + } + + particle->m_vecPosition = vecPos; + } + } +} + +void CParticle::Render() +{ + PUSH_RENDERGROUP("CParticle::Render"); + + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void *)rwTEXTUREADDRESSWRAP); + RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + + CSprite::InitSpriteBuffer2D(); + + uint32 flags = DRAW_OPAQUE; + + RwRaster *prevFrame = nil; + + for ( int32 i = 0; i < MAX_PARTICLES; i++ ) + { + tParticleSystemData *psystem = &mod_ParticleSystemManager.m_aParticles[i]; + bool particleBanned = false; + CParticle *particle = psystem->m_pParticles; + + RwRaster **frames = psystem->m_ppRaster; + tParticleType type = psystem->m_Type; + + if ( type == PARTICLE_ENGINE_SMOKE + || type == PARTICLE_ENGINE_SMOKE2 + || type == PARTICLE_ENGINE_STEAM + || type == PARTICLE_CARFLAME_SMOKE + || type == PARTICLE_RUBBER_SMOKE + || type == PARTICLE_BURNINGRUBBER_SMOKE + || type == PARTICLE_EXHAUST_FUMES + || type == PARTICLE_CARCOLLISION_DUST ) + { + particleBanned = true; + } + + if ( particle ) + { + if ( (flags & DRAW_OPAQUE) != (psystem->Flags & DRAW_OPAQUE) + || (flags & DRAW_DARK) != (psystem->Flags & DRAW_DARK) ) + { + CSprite::FlushSpriteBuffer(); + + if ( psystem->Flags & DRAW_OPAQUE ) + { + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + } + else + { + if ( psystem->Flags & DRAW_DARK ) + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + else + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE); + + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE); + } + + flags = psystem->Flags; + } + + if ( frames != nil ) + { + RwRaster *curFrame = *frames; + if ( curFrame != prevFrame ) + { + CSprite::FlushSpriteBuffer(); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)curFrame); + prevFrame = curFrame; + } + } + } + + while ( particle != nil ) + { + bool canDraw = true; + + if ( particle->m_nAlpha == 0 ) + canDraw = false; + + if ( canDraw && psystem->m_nFinalAnimationFrame != 0 && frames != nil ) + { + RwRaster *curFrame = frames[particle->m_nCurrentFrame]; + if ( prevFrame != curFrame ) + { + CSprite::FlushSpriteBuffer(); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)curFrame); + prevFrame = curFrame; + } + } + + if ( canDraw && psystem->Flags & DRAWTOP2D ) + { + float screenZ; +#ifdef FIX_BUGS + bool zIsZero = true; + if ( particle->m_vecPosition.z != 0.0f ) { +#endif + screenZ = (particle->m_vecPosition.z - CDraw::GetNearClipZ()) + * (CSprite::GetFarScreenZ() - CSprite::GetNearScreenZ()) + * CDraw::GetFarClipZ() + / ( (CDraw::GetFarClipZ() - CDraw::GetNearClipZ()) * particle->m_vecPosition.z ) + + CSprite::GetNearScreenZ(); +#ifdef FIX_BUGS + zIsZero = false; + } +#endif + + float stretchTexW; + float stretchTexH; + + if ( i == PARTICLE_RAINDROP || i == PARTICLE_RAINDROP_SMALL || i == PARTICLE_RAINDROP_2D ) + { + stretchTexW = CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.x * (float)particle->m_nCurrentFrame + 63.0f; + stretchTexH = CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.y * (float)particle->m_nCurrentFrame + 63.0f; + } + else + { + stretchTexW = CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.x + 63.0f; + stretchTexH = CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.y + 63.0f; + } + +#ifdef FIX_BUGS + if (!zIsZero) { +#endif + + if ( i == PARTICLE_WATERDROP ) + { + int32 timeLeft = (particle->m_nTimeWhenWillBeDestroyed - CTimer::GetTimeInMilliseconds()) / particle->m_nTimeWhenWillBeDestroyed; + + stretchTexH += (1.0f - (float)timeLeft ) * psystem->m_vecTextureStretch.y; + + RwRect rect; + + rect.x = int32(particle->m_vecPosition.x - SCREEN_STRETCH_X(particle->m_fSize * stretchTexW)); + rect.y = int32(particle->m_vecPosition.y - SCREEN_STRETCH_Y(particle->m_fSize * stretchTexH)); + rect.w = int32(particle->m_vecPosition.x + SCREEN_STRETCH_X(particle->m_fSize * stretchTexW)); + rect.h = int32(particle->m_vecPosition.y + SCREEN_STRETCH_Y(particle->m_fSize * stretchTexH)); + + FxType fxtype; + + if ( particle->m_nCurrentFrame != 0 ) + fxtype = FXTYPE_WATER2; + else + fxtype = FXTYPE_WATER1; + + CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, fxtype); + + canDraw = false; + } + + if ( i == PARTICLE_BLOODDROP ) + { + int32 timeLeft = (particle->m_nTimeWhenWillBeDestroyed - CTimer::GetTimeInMilliseconds()) / particle->m_nTimeWhenWillBeDestroyed; + + stretchTexH += (1.0f + (float)timeLeft) * psystem->m_vecTextureStretch.y; + stretchTexW += (1.0f - (float)timeLeft) * psystem->m_vecTextureStretch.x; + + RwRect rect; + + rect.x = int32(particle->m_vecPosition.x - SCREEN_STRETCH_X(particle->m_fSize * stretchTexW)); + rect.y = int32(particle->m_vecPosition.y - SCREEN_STRETCH_Y(particle->m_fSize * stretchTexH)); + rect.w = int32(particle->m_vecPosition.x + SCREEN_STRETCH_X(particle->m_fSize * stretchTexW)); + rect.h = int32(particle->m_vecPosition.y + SCREEN_STRETCH_Y(particle->m_fSize * stretchTexH)); + + FxType fxtype; + + if ( particle->m_nCurrentFrame ) + fxtype = FXTYPE_BLOOD2; + else + fxtype = FXTYPE_BLOOD1; + + CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, fxtype); + + canDraw = false; + } + + if ( i == PARTICLE_HEATHAZE_IN_DIST ) + { + RwRect rect; + + rect.x = int32(particle->m_vecPosition.x - SCREEN_STRETCH_X(particle->m_fSize * stretchTexW)); + rect.y = int32(particle->m_vecPosition.y - SCREEN_STRETCH_Y(particle->m_fSize * stretchTexH * 0.15f)); + rect.w = int32(particle->m_vecPosition.x + SCREEN_STRETCH_X(particle->m_fSize * stretchTexW)); + rect.h = int32(particle->m_vecPosition.y + SCREEN_STRETCH_Y(particle->m_fSize * stretchTexH * 0.15f)); + + CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_HEATHAZE); + + canDraw = false; + } + + if ( i == PARTICLE_HEATHAZE ) + { + RwRect rect; + + switch ( TheCamera.GetLookDirection() ) + { + case LOOKING_LEFT: + rect.x = int32(particle->m_vecPosition.x - SCREEN_STRETCH_X(particle->m_fSize * psystem->m_vecTextureStretch.x * 2.0f)); + rect.y = int32(particle->m_vecPosition.y - SCREEN_STRETCH_Y(particle->m_fSize * psystem->m_vecTextureStretch.y)); + rect.w = int32(particle->m_vecPosition.x - SCREEN_STRETCH_X(particle->m_fSize * psystem->m_vecTextureStretch.x)); + rect.h = int32(particle->m_vecPosition.y + SCREEN_STRETCH_Y(particle->m_fSize * psystem->m_vecTextureStretch.y)); + + break; + + case LOOKING_RIGHT: + rect.x = int32(particle->m_vecPosition.x + SCREEN_STRETCH_X(particle->m_fSize * psystem->m_vecTextureStretch.x)); + rect.y = int32(particle->m_vecPosition.y - SCREEN_STRETCH_Y(particle->m_fSize * psystem->m_vecTextureStretch.y)); + rect.w = int32(particle->m_vecPosition.x + SCREEN_STRETCH_X(particle->m_fSize * psystem->m_vecTextureStretch.x * 4.0f)); + rect.h = int32(particle->m_vecPosition.y + SCREEN_STRETCH_Y(particle->m_fSize * psystem->m_vecTextureStretch.y)); + + break; + + default: + rect.x = int32(particle->m_vecPosition.x - SCREEN_STRETCH_X(particle->m_fSize * psystem->m_vecTextureStretch.x)); + rect.y = int32(particle->m_vecPosition.y - SCREEN_STRETCH_Y(particle->m_fSize * psystem->m_vecTextureStretch.y)); + rect.w = int32(particle->m_vecPosition.x + SCREEN_STRETCH_X(particle->m_fSize * psystem->m_vecTextureStretch.x)); + rect.h = int32(particle->m_vecPosition.y + SCREEN_STRETCH_Y(particle->m_fSize * psystem->m_vecTextureStretch.y)); + + break; + } + + CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_HEATHAZE); + + canDraw = false; + } +#ifdef FIX_BUGS + } + if ( !(zIsZero && (i == PARTICLE_WATERDROP || i == PARTICLE_BLOODDROP || i == PARTICLE_HEATHAZE_IN_DIST || i == PARTICLE_HEATHAZE) ) ) +#endif + if ( canDraw ) + { + if ( particle->m_nRotation != 0 ) + { + CSprite::RenderBufferedOneXLUSprite2D_Rotate_Dimension( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + particle->m_fSize * stretchTexW, + particle->m_fSize * stretchTexH, + particle->m_Color, + particle->m_nColorIntensity, + DEGTORAD((float)particle->m_nRotation), + particle->m_nAlpha); + } + else + { + CSprite::RenderBufferedOneXLUSprite2D( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + particle->m_fSize * stretchTexW, + particle->m_fSize * stretchTexH, + particle->m_Color, + particle->m_nColorIntensity, + particle->m_nAlpha); + } + } + + canDraw = false; + } + + if ( canDraw ) + { + CVector coors; + float w; + float h; + + if ( CSprite::CalcScreenCoors(particle->m_vecPosition, &coors, &w, &h, true) ) + { + + if ( i == PARTICLE_ENGINE_STEAM + || i == PARTICLE_ENGINE_SMOKE + || i == PARTICLE_ENGINE_SMOKE2 + || i == PARTICLE_CARFLAME_SMOKE + || i == PARTICLE_CARCOLLISION_DUST + || i == PARTICLE_EXHAUST_FUMES + || i == PARTICLE_RUBBER_SMOKE + || i == PARTICLE_BURNINGRUBBER_SMOKE ) + { + switch ( TheCamera.GetLookDirection() ) + { + case LOOKING_LEFT: + case LOOKING_RIGHT: + w += CGeneral::GetRandomNumberInRange(1.0f, 7.5f) * psystem->m_vecTextureStretch.x; + h += CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.y; + break; + + default: + w += CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.x; + h += CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.y; + break; + } + } + else if ( i == PARTICLE_WATER_HYDRANT ) + { + int32 timeLeft = (particle->m_nTimeWhenWillBeDestroyed - CTimer::GetTimeInMilliseconds()) / particle->m_nTimeWhenWillBeDestroyed; + + w += (1.0f - (float)timeLeft) * psystem->m_vecTextureStretch.x; + h += (1.0f - (float)timeLeft) * psystem->m_vecTextureStretch.y; + } + else if ( i == PARTICLE_FLYERS ) + { + w += psystem->m_vecTextureStretch.x; + h += psystem->m_vecTextureStretch.y; + + w = Max(w, 12.0f); + h = Max(h, 12.0f); + } + else + { + w += CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.x; + h += CGeneral::GetRandomNumberInRange(0.1f, 1.0f) * psystem->m_vecTextureStretch.y; + } + + if ( i == PARTICLE_WATER_HYDRANT + || (!particleBanned || SCREEN_WIDTH * fParticleScaleLimit >= w) + && SCREEN_HEIGHT * fParticleScaleLimit >= h ) + { + if ( i == PARTICLE_WATER_HYDRANT ) + { + RwRect rect; + + if ( w > 0.0f ) + { + rect.x = int32(coors.x - SCREEN_STRETCH_X(particle->m_fSize * w)); + rect.w = int32(coors.x + SCREEN_STRETCH_X(particle->m_fSize * w)); + } + else + { + rect.w = int32(coors.x - SCREEN_STRETCH_X(particle->m_fSize * w)); + rect.x = int32(coors.x + SCREEN_STRETCH_X(particle->m_fSize * w)); + } + + if ( h > 0.0f ) + { + rect.y = int32(coors.y - SCREEN_STRETCH_Y(particle->m_fSize * h)); + rect.h = int32(coors.y + SCREEN_STRETCH_Y(particle->m_fSize * h)); + } + else + { + rect.h = int32(coors.y - SCREEN_STRETCH_Y(particle->m_fSize * h)); + rect.y = int32(coors.y + SCREEN_STRETCH_Y(particle->m_fSize * h)); + } + + float screenZ = (coors.z - CDraw::GetNearClipZ()) + * (CSprite::GetFarScreenZ() - CSprite::GetNearScreenZ()) * CDraw::GetFarClipZ() + / ( (CDraw::GetFarClipZ() - CDraw::GetNearClipZ()) * coors.z ) + CSprite::GetNearScreenZ(); + + CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_SPLASH1); + } + else + { + if ( particle->m_nRotation != 0 && i != PARTICLE_BEASTIE ) + { + CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(coors.x, coors.y, coors.z, + particle->m_fSize * w, particle->m_fSize * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + DEGTORAD((float)particle->m_nRotation), + particle->m_nAlpha); + } + else if ( psystem->Flags & SCREEN_TRAIL ) + { + float fRotation; + float fTrailLength; + + if ( particle->m_fZGround == 0.0f ) + { + fTrailLength = 0.0f; + fRotation = 0.0f; + } + else + { + CVector2D vecDist + ( + coors.x - particle->m_fZGround, + coors.y - particle->m_fExpansionRate + ); + + float fDist = vecDist.Magnitude(); + + fTrailLength = fDist; + + float fRot = Asin(vecDist.x / fDist); + + fRotation = fRot; + + if ( vecDist.y < 0.0f ) + fRotation = -1.0f * fRot + DEGTORAD(180.0f); + + float fSpeed = particle->m_vecVelocity.Magnitude(); + + float fNewTrailLength = fSpeed * CTimer::GetTimeStep() * w * 2.0f; + + if ( fDist > fNewTrailLength ) + fTrailLength = fNewTrailLength; + } + + CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(coors.x, coors.y, coors.z, + particle->m_fSize * w, + particle->m_fSize * h + fTrailLength * psystem->m_fTrailLengthMultiplier, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + fRotation, + particle->m_nAlpha); + + particle->m_fZGround = coors.x; // WTF ? + particle->m_fExpansionRate = coors.y; // WTF ? + } + else if ( psystem->Flags & SPEED_TRAIL ) + { + CVector vecPrevPos = particle->m_vecPosition - particle->m_vecVelocity; + float fRotation; + float fTrailLength; + CVector vecScreenPosition; + + if ( CSprite::CalcScreenCoors(vecPrevPos, &vecScreenPosition, &fTrailLength, &fRotation, true) ) + { + CVector2D vecDist + ( + coors.x - vecScreenPosition.x, + coors.y - vecScreenPosition.y + ); + + float fDist = vecDist.Magnitude(); + + fTrailLength = fDist; + + float fRot = Asin(vecDist.x / fDist); + + fRotation = fRot; + + if ( vecDist.y < 0.0f ) + fRotation = -1.0f * fRot + DEGTORAD(180.0f); + } + else + { + fRotation = 0.0f; + fTrailLength = 0.0f; + } + + CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(coors.x, coors.y, coors.z, + particle->m_fSize * w, + particle->m_fSize * h + fTrailLength * psystem->m_fTrailLengthMultiplier, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + fRotation, + particle->m_nAlpha); + } + else if ( psystem->Flags & VERT_TRAIL ) + { + float fTrailLength = fabsf(particle->m_vecVelocity.z * 10.0f); + + CSprite::RenderBufferedOneXLUSprite(coors.x, coors.y, coors.z, + particle->m_fSize * w, + (particle->m_fSize + fTrailLength * psystem->m_fTrailLengthMultiplier) * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + particle->m_nAlpha); + } + else if ( i == PARTICLE_RAINDROP_SMALL ) + { + CSprite::RenderBufferedOneXLUSprite(coors.x, coors.y, coors.z, + particle->m_fSize * w * 0.05f, + particle->m_fSize * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + particle->m_nAlpha); + } + /*else if ( i == PARTICLE_BOAT_WAKE )*/ + else + { + CSprite::RenderBufferedOneXLUSprite(coors.x, coors.y, coors.z, + particle->m_fSize * w, + particle->m_fSize * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + particle->m_nAlpha); + } + } + } + } + } + + particle = particle->m_pNext; + } + + CSprite::FlushSpriteBuffer(); + + } + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + + POP_RENDERGROUP(); +} + +void CParticle::RemovePSystem(tParticleType type) +{ + tParticleSystemData *psystemdata = &mod_ParticleSystemManager.m_aParticles[type]; + + for ( CParticle *particle = psystemdata->m_pParticles; particle; particle = psystemdata->m_pParticles ) + RemoveParticle(particle, nil, psystemdata); +} + +void CParticle::RemoveParticle(CParticle *pParticle, CParticle *pPrevParticle, tParticleSystemData *pPSystemData) +{ + if ( pPSystemData->m_Type == PARTICLE_WATERDROP ) + --numWaterDropOnScreen; + + if ( pPrevParticle ) + pPrevParticle->m_pNext = pParticle->m_pNext; + else + pPSystemData->m_pParticles = pParticle->m_pNext; + + pParticle->m_pNext = m_pUnusedListHead; + m_pUnusedListHead = pParticle; +} + +void CParticle::AddJetExplosion(CVector const &vecPos, float fPower, float fSize) +{ + CRGBA color(240, 240, 240, 255); + + if ( fPower < 1.0f ) + fPower = 1.0f; + + CVector vecRandOffset + ( + CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), + CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), + CGeneral::GetRandomNumberInRange(0.1f, 0.3f) + ); + + vecRandOffset *= 2.0f; + + CVector vecStepPos = vecPos; + + for ( int32 i = 0; i < int32(fPower * 4.0f); i++ ) + { + AddParticle(PARTICLE_EXPLOSION_MFAST, + vecStepPos, + CVector + ( + CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), + CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), + CGeneral::GetRandomNumberInRange(-0.02f, 0.0f) + ), + nil, + fSize, color, 0, 0, 0, 0); + + AddParticle(PARTICLE_EXPLOSION_MFAST, + vecStepPos, + CVector + ( + CGeneral::GetRandomNumberInRange(-0.04f, 0.04f), + CGeneral::GetRandomNumberInRange(-0.04f, 0.04f), + CGeneral::GetRandomNumberInRange(0.0f, 0.07f) + ), + nil, + fSize, color, 0, 0, 0, 0); + + AddParticle(PARTICLE_EXPLOSION_MFAST, + vecStepPos, + CVector + ( + CGeneral::GetRandomNumberInRange(-0.04f, 0.04f), + CGeneral::GetRandomNumberInRange(-0.04f, 0.04f), + CGeneral::GetRandomNumberInRange(0.0f, 0.07f) + ), + nil, + fSize, color, 0, 0, 0, 0); + + vecStepPos += vecRandOffset; + } +} + +void CParticle::AddYardieDoorSmoke(CVector const &vecPos, CMatrix const &matMatrix) +{ + CRGBA color(0, 0, 0, 0); + + CMatrix invMat(Invert(matMatrix)); + + CVector vecBasePos = matMatrix * (invMat * vecPos + CVector(0.0f, -1.0f, 0.5f)); + + for ( int32 i = 0; i < 5; i++ ) + { + CVector pos = vecBasePos; + + pos.x += CGeneral::GetRandomNumberInRange(-0.5f, 0.5f); + pos.y += CGeneral::GetRandomNumberInRange(-0.5f, 0.5f); + + AddParticle(PARTICLE_CARCOLLISION_DUST, + pos, + CVector(0.0f, 0.0f, 0.0f), + nil, + 0.3f, color, 0, 0, 0, 0); + } +} + +void CParticle::CalWindDir(CVector *vecDirIn, CVector *vecDirOut) +{ + vecDirOut->x = (Cos(128) * vecDirIn->x) + (Sin(128) * vecDirIn->y); + + vecDirOut->x = (Cos(128) * vecDirIn->x) + (Sin(128) * vecDirIn->y) * CWeather::Wind; + vecDirOut->y = (Sin(128) * vecDirIn->x) - (Cos(128) * vecDirIn->y) * CWeather::Wind; +} + +void CParticle::HandleShipsAtHorizonStuff() +{ + tParticleSystemData *psystemdata = &mod_ParticleSystemManager.m_aParticles[PARTICLE_SHIP_SIDE]; + + for ( CParticle *particle = psystemdata->m_pParticles; particle; particle = particle->m_pNext ) + { + if ( CTimer::GetTimeInMilliseconds() > particle->m_nTimeWhenWillBeDestroyed - 32000 + && CTimer::GetTimeInMilliseconds() < particle->m_nTimeWhenWillBeDestroyed - 22000 ) + { + particle->m_nAlpha = Min(particle->m_nAlpha + 1, 96); + } + if ( CTimer::GetTimeInMilliseconds() > particle->m_nTimeWhenWillBeDestroyed - 10000 ) + particle->m_nFadeAlphaTimer = 1; + } +} + +void CParticle::HandleShootableBirdsStuff(CEntity *entity, CVector const&camPos) +{ + float fHeadingRad = entity->GetForward().Heading(); + float fHeading = RADTODEG(fHeadingRad); + float fBirdAngle = ::Cos(DEGTORAD(1.5f)); + + tParticleSystemData *psystem = &mod_ParticleSystemManager.m_aParticles[PARTICLE_BIRD_FRONT]; + CParticle *particle = psystem->m_pParticles; + CParticle *prevParticle = nil; + bool bRemoveParticle; + + for ( ; particle != nil; _Next(particle, prevParticle, psystem, bRemoveParticle) ) + { + bRemoveParticle = false; + + CVector2D vecPos(particle->m_vecPosition.x, particle->m_vecPosition.y); + CVector2D vecCamPos(camPos.x, camPos.y); + + CVector2D vecDist = vecPos - vecCamPos; + vecDist.Normalise(); + + float fHead = DEGTORAD(fHeading); + + CVector2D vecDir(-::Sin(fHead), ::Cos(fHead)); + vecDir.Normalise(); + + float fDot = DotProduct2D(vecDir, vecDist); + + if ( fDot > 0.0f && fDot > fBirdAngle ) + { + if ( (camPos - particle->m_vecPosition).MagnitudeSqr() < 40000.0f ) + { + CStats::SeagullsKilled++; + + bRemoveParticle = true; + + for ( int32 i = 0; i < 8; i++ ) + { + CParticle *pBirdDerbis = AddParticle(PARTICLE_BIRD_DEBRIS, + particle->m_vecPosition, + CVector + ( + CGeneral::GetRandomNumberInRange(-3.0f, 3.0f), + CGeneral::GetRandomNumberInRange(-3.0f, 3.0f), + CGeneral::GetRandomNumberInRange(-3.0f, 3.0f) + ), + nil, + 0.3f, + particle->m_Color, + CGeneral::GetRandomNumberInRange(20, 40), + 0, + CGeneral::GetRandomNumber() & 3, + 200); + if ( pBirdDerbis ) + pBirdDerbis->m_nAlpha = particle->m_nAlpha; + } + } + } + } + +} + +void +CEntity::AddSteamsFromGround(CVector *unused) +{ + int i, n; + C2dEffect *effect; + CVector pos; + + n = CModelInfo::GetModelInfo(GetModelIndex())->GetNum2dEffects(); + for(i = 0; i < n; i++){ + effect = CModelInfo::GetModelInfo(GetModelIndex())->Get2dEffect(i); + if(effect->type != EFFECT_PARTICLE) + continue; + + pos = GetMatrix() * effect->pos; + switch(effect->particle.particleType){ + case 0: + CParticleObject::AddObject(POBJECT_PAVEMENT_STEAM, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 1: + CParticleObject::AddObject(POBJECT_WALL_STEAM, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 2: + CParticleObject::AddObject(POBJECT_DRY_ICE, pos, effect->particle.scale, false); + break; + case 3: + CParticleObject::AddObject(POBJECT_SMALL_FIRE, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 4: + CParticleObject::AddObject(POBJECT_DARK_SMOKE, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 5: + CParticleObject::AddObject(POBJECT_WATER_FOUNTAIN_VERT, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 6: + CParticleObject::AddObject(POBJECT_WATER_FOUNTAIN_HORIZ, pos, effect->particle.dir, effect->particle.scale, false); + break; + } + } +} |