diff options
author | Sergeanur <s.anureev@yandex.ua> | 2021-07-15 17:19:32 +0200 |
---|---|---|
committer | Sergeanur <s.anureev@yandex.ua> | 2021-07-17 23:04:26 +0200 |
commit | d0404cbdb77bd82abf578ce28093990db94743f2 (patch) | |
tree | 1a7232c3dcdd6c371ab5fbde0fc6bf04c5bc7005 /src/renderer/Coronas.cpp | |
parent | Merge pull request #1217 from Nopey/master (diff) | |
download | re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.gz re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.bz2 re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.lz re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.xz re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.zst re3-d0404cbdb77bd82abf578ce28093990db94743f2.zip |
Diffstat (limited to 'src/renderer/Coronas.cpp')
-rw-r--r-- | src/renderer/Coronas.cpp | 779 |
1 files changed, 779 insertions, 0 deletions
diff --git a/src/renderer/Coronas.cpp b/src/renderer/Coronas.cpp new file mode 100644 index 00000000..e9f9e662 --- /dev/null +++ b/src/renderer/Coronas.cpp @@ -0,0 +1,779 @@ +#include "common.h" + +#include "main.h" +#include "General.h" +#include "Entity.h" +#include "TxdStore.h" +#include "Camera.h" +#include "Sprite.h" +#include "Timer.h" +#include "World.h" +#include "Weather.h" +#include "Collision.h" +#include "Timecycle.h" +#include "Coronas.h" +#include "PointLights.h" +#include "Shadows.h" +#include "Clock.h" +#include "Bridge.h" + +struct FlareDef +{ + float position; + float size; + int16 red; + int16 green; + int16 blue; + int16 alpha; + int16 texture; +}; + +FlareDef SunFlareDef[] = { + { -0.5f, 15.0f, 50, 50, 0, 200, 1 }, + { -1.0f, 10.0f, 50, 20, 0, 200, 2 }, + { -1.5f, 15.0f, 50, 0, 0, 200, 3 }, + { -2.5f, 25.0f, 50, 0, 0, 200, 1 }, + { 0.5f, 12.5f, 40, 40, 25, 200, 1 }, + { 0.05f, 20.0f, 30, 22, 9, 200, 2 }, + { 1.3f, 7.5f, 50, 30, 9, 200, 3 }, + { 0.0f, 0.0f, 255, 255, 255, 255, 0 } +}; + +FlareDef HeadLightsFlareDef[] = { + { -0.5f, 15.5, 70, 70, 70, 200, 1 }, + { -1.0f, 10.0, 70, 70, 70, 200, 2 }, + { -1.5f, 5.5f, 50, 50, 50, 200, 3 }, + { 0.5f, 12.0f, 50, 50, 50, 200, 1 }, + { 0.05f, 20.0f, 40, 40, 40, 200, 2 }, + { 1.3f, 8.0f, 60, 60, 60, 200, 3 }, + { -2.0f, 12.0f, 50, 50, 50, 200, 1 }, + { -2.3f, 15.0f, 40, 40, 40, 200, 2 }, + { -3.0f, 16.0f, 40, 40, 40, 200, 3 }, + { 0.0f, 0.0f, 255, 255, 255, 255, 0 } +}; + + +RwTexture *gpCoronaTexture[9] = { nil, nil, nil, nil, nil, nil, nil, nil, nil }; + +float CCoronas::LightsMult = 1.0f; +float CCoronas::SunScreenX; +float CCoronas::SunScreenY; +bool CCoronas::bSmallMoon; +bool CCoronas::SunBlockedByClouds; +int CCoronas::bChangeBrightnessImmediately; + +CRegisteredCorona CCoronas::aCoronas[NUMCORONAS]; + +const char aCoronaSpriteNames[][32] = { + "coronastar", + "corona", + "coronamoon", + "coronareflect", + "coronaheadlightline", + "coronahex", + "coronacircle", + "coronaringa", + "streek" +}; + +void +CCoronas::Init(void) +{ + int i; + + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle")); + + for(i = 0; i < 9; i++) + if(gpCoronaTexture[i] == nil) + gpCoronaTexture[i] = RwTextureRead(aCoronaSpriteNames[i], nil); + + CTxdStore::PopCurrentTxd(); + + for(i = 0; i < NUMCORONAS; i++) + aCoronas[i].id = 0; +} + +void +CCoronas::Shutdown(void) +{ + int i; + for(i = 0; i < 9; i++) + if(gpCoronaTexture[i]){ + RwTextureDestroy(gpCoronaTexture[i]); + gpCoronaTexture[i] = nil; + } +} + +void +CCoronas::Update(void) +{ + int i; + static int LastCamLook = 0; + + LightsMult = Min(LightsMult + 0.03f * CTimer::GetTimeStep(), 1.0f); + + int CamLook = 0; + if(TheCamera.Cams[TheCamera.ActiveCam].LookingLeft) CamLook |= 1; + if(TheCamera.Cams[TheCamera.ActiveCam].LookingRight) CamLook |= 2; + if(TheCamera.Cams[TheCamera.ActiveCam].LookingBehind) CamLook |= 4; + // BUG? + if(TheCamera.GetLookDirection() == LOOKING_BEHIND) CamLook |= 8; + + if(LastCamLook != CamLook) + bChangeBrightnessImmediately = 3; + else + bChangeBrightnessImmediately = Max(bChangeBrightnessImmediately-1, 0); + LastCamLook = CamLook; + + for(i = 0; i < NUMCORONAS; i++) + if(aCoronas[i].id != 0) + aCoronas[i].Update(); +} + +void +CCoronas::RegisterCorona(uint32 id, uint8 red, uint8 green, uint8 blue, uint8 alpha, + const CVector &coors, float size, float drawDist, RwTexture *tex, + int8 flareType, uint8 reflection, uint8 LOScheck, uint8 drawStreak, float someAngle) +{ + int i; + + if(sq(drawDist) < (TheCamera.GetPosition() - coors).MagnitudeSqr2D()) + return; + + for(i = 0; i < NUMCORONAS; i++) + if(aCoronas[i].id == id) + break; + + if(i == NUMCORONAS){ + // add a new one + + // find empty slot + for(i = 0; i < NUMCORONAS; i++) + if(aCoronas[i].id == 0) + break; + if(i == NUMCORONAS) + return; // no space + + aCoronas[i].fadeAlpha = 0; + aCoronas[i].offScreen = true; + aCoronas[i].firstUpdate = true; + aCoronas[i].renderReflection = false; + aCoronas[i].lastLOScheck = 0; + aCoronas[i].sightClear = false; + aCoronas[i].hasValue[0] = false; + aCoronas[i].hasValue[1] = false; + aCoronas[i].hasValue[2] = false; + aCoronas[i].hasValue[3] = false; + aCoronas[i].hasValue[4] = false; + aCoronas[i].hasValue[5] = false; + + }else{ + // use existing one + + if(aCoronas[i].fadeAlpha == 0 && alpha == 0){ + // unregister + aCoronas[i].id = 0; + return; + } + } + + aCoronas[i].id = id; + aCoronas[i].red = red; + aCoronas[i].green = green; + aCoronas[i].blue = blue; + aCoronas[i].alpha = alpha; + aCoronas[i].coors = coors; + aCoronas[i].size = size; + aCoronas[i].someAngle = someAngle; + aCoronas[i].registeredThisFrame = true; + aCoronas[i].drawDist = drawDist; + aCoronas[i].texture = tex; + aCoronas[i].flareType = flareType; + aCoronas[i].reflection = reflection; + aCoronas[i].LOScheck = LOScheck; + aCoronas[i].drawStreak = drawStreak; +} + +void +CCoronas::RegisterCorona(uint32 id, uint8 red, uint8 green, uint8 blue, uint8 alpha, + const CVector &coors, float size, float drawDist, uint8 type, + int8 flareType, uint8 reflection, uint8 LOScheck, uint8 drawStreak, float someAngle) +{ + RegisterCorona(id, red, green, blue, alpha, coors, size, drawDist, + gpCoronaTexture[type], flareType, reflection, LOScheck, drawStreak, someAngle); +} + +void +CCoronas::UpdateCoronaCoors(uint32 id, const CVector &coors, float drawDist, float someAngle) +{ + int i; + + if(sq(drawDist) < (TheCamera.GetPosition() - coors).MagnitudeSqr2D()) + return; + + for(i = 0; i < NUMCORONAS; i++) + if(aCoronas[i].id == id) + break; + + if(i == NUMCORONAS) + return; + + if(aCoronas[i].fadeAlpha == 0) + aCoronas[i].id = 0; // faded out, remove + else{ + aCoronas[i].coors = coors; + aCoronas[i].someAngle = someAngle; + } +} + +static RwIm2DVertex vertexbufferX[2]; + +void +CCoronas::Render(void) +{ + int i, j; + int screenw, screenh; + + PUSH_RENDERGROUP("CCoronas::Render"); + + screenw = RwRasterGetWidth(RwCameraGetRaster(Scene.camera)); + screenh = RwRasterGetHeight(RwCameraGetRaster(Scene.camera)); + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + + for(i = 0; i < NUMCORONAS; i++){ + for(j = 5; j > 0; j--){ + aCoronas[i].prevX[j] = aCoronas[i].prevX[j-1]; + aCoronas[i].prevY[j] = aCoronas[i].prevY[j-1]; + aCoronas[i].prevRed[j] = aCoronas[i].prevRed[j-1]; + aCoronas[i].prevGreen[j] = aCoronas[i].prevGreen[j-1]; + aCoronas[i].prevBlue[j] = aCoronas[i].prevBlue[j-1]; + aCoronas[i].hasValue[j] = aCoronas[i].hasValue[j-1]; + } + aCoronas[i].hasValue[0] = false; + + if(aCoronas[i].id == 0 || + aCoronas[i].fadeAlpha == 0 && aCoronas[i].alpha == 0) + continue; + + CVector spriteCoors; + float spritew, spriteh; + if(!CSprite::CalcScreenCoors(aCoronas[i].coors, &spriteCoors, &spritew, &spriteh, true)){ + aCoronas[i].offScreen = true; + aCoronas[i].sightClear = false; + }else{ + aCoronas[i].offScreen = false; + + if(spriteCoors.x < 0.0f || spriteCoors.y < 0.0f || + spriteCoors.x > screenw || spriteCoors.y > screenh){ + aCoronas[i].offScreen = true; + aCoronas[i].sightClear = false; + }else{ + if(CTimer::GetTimeInMilliseconds() > aCoronas[i].lastLOScheck + 2000){ + aCoronas[i].lastLOScheck = CTimer::GetTimeInMilliseconds(); + aCoronas[i].sightClear = CWorld::GetIsLineOfSightClear( + aCoronas[i].coors, TheCamera.Cams[TheCamera.ActiveCam].Source, + true, true, false, false, false, true, false); + } + + // add new streak point + if(aCoronas[i].sightClear){ + aCoronas[i].prevX[0] = spriteCoors.x; + aCoronas[i].prevY[0] = spriteCoors.y; + aCoronas[i].prevRed[0] = aCoronas[i].red; + aCoronas[i].prevGreen[0] = aCoronas[i].green; + aCoronas[i].prevBlue[0] = aCoronas[i].blue; + aCoronas[i].hasValue[0] = true; + } + + // if distance too big, break streak + if(aCoronas[i].hasValue[1]){ + if(Abs(aCoronas[i].prevX[0] - aCoronas[i].prevX[1]) > 50.0f || + Abs(aCoronas[i].prevY[0] - aCoronas[i].prevY[1]) > 50.0f) + aCoronas[i].hasValue[0] = false; + } + } + + + if(aCoronas[i].fadeAlpha && spriteCoors.z < aCoronas[i].drawDist){ + float recipz = 1.0f/spriteCoors.z; + float fadeDistance = aCoronas[i].drawDist / 2.0f; + float distanceFade = spriteCoors.z < fadeDistance ? 1.0f : 1.0f - (spriteCoors.z - fadeDistance)/fadeDistance; + int totalFade = aCoronas[i].fadeAlpha * distanceFade; + + if(aCoronas[i].LOScheck) + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + else + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + + // render corona itself + if(aCoronas[i].texture){ + float fogscale = CWeather::Foggyness*Min(spriteCoors.z, 40.0f)/40.0f + 1.0f; + if(CCoronas::aCoronas[i].id == SUN_CORE) + spriteCoors.z = 0.95f * RwCameraGetFarClipPlane(Scene.camera); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(aCoronas[i].texture)); + spriteCoors.z -= 1.5f; + + if(aCoronas[i].texture == gpCoronaTexture[8]){ + // what's this? + float f = 1.0f - aCoronas[i].someAngle*2.0f/PI; + float wscale = 6.0f*sq(sq(sq(f))) + 0.5f; + float hscale = 0.35f - (wscale - 0.5f) * 0.06f; + hscale = Max(hscale, 0.15f); + + CSprite::RenderOneXLUSprite(spriteCoors.x, spriteCoors.y, spriteCoors.z, + spritew * aCoronas[i].size * wscale, + spriteh * aCoronas[i].size * fogscale * hscale, + CCoronas::aCoronas[i].red / fogscale, + CCoronas::aCoronas[i].green / fogscale, + CCoronas::aCoronas[i].blue / fogscale, + totalFade, + recipz, + 255); + }else{ + CSprite::RenderOneXLUSprite_Rotate_Aspect( + spriteCoors.x, spriteCoors.y, spriteCoors.z, + spritew * aCoronas[i].size * fogscale, + spriteh * aCoronas[i].size * fogscale, + CCoronas::aCoronas[i].red / fogscale, + CCoronas::aCoronas[i].green / fogscale, + CCoronas::aCoronas[i].blue / fogscale, + totalFade, + recipz, + 20.0f * recipz, + 255); + } + } + + // render flares + if(aCoronas[i].flareType != FLARE_NONE){ + FlareDef *flare; + + switch(aCoronas[i].flareType){ + case FLARE_SUN: flare = SunFlareDef; break; + case FLARE_HEADLIGHTS: flare = HeadLightsFlareDef; break; + default: assert(0); + } + + for(; flare->texture; flare++){ + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[flare->texture + 4])); + CSprite::RenderOneXLUSprite( + (spriteCoors.x - (screenw/2)) * flare->position + (screenw/2), + (spriteCoors.y - (screenh/2)) * flare->position + (screenh/2), + spriteCoors.z, + 4.0f*flare->size * spritew/spriteh, + 4.0f*flare->size, + (flare->red * aCoronas[i].red)>>8, + (flare->green * aCoronas[i].green)>>8, + (flare->blue * aCoronas[i].blue)>>8, + (totalFade * flare->alpha)>>8, + recipz, 255); + } + } + } + } + } + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + + // streaks + for(i = 0; i < NUMCORONAS; i++){ + if(aCoronas[i].id == 0 || !aCoronas[i].drawStreak) + continue; + + for(j = 0; j < 5; j++){ + if(!aCoronas[i].hasValue[j] || !aCoronas[i].hasValue[j+1]) + continue; + + int alpha1 = (float)(6 - j) / 6 * 128; + int alpha2 = (float)(6 - (j+1)) / 6 * 128; + + RwIm2DVertexSetScreenX(&vertexbufferX[0], aCoronas[i].prevX[j]); + RwIm2DVertexSetScreenY(&vertexbufferX[0], aCoronas[i].prevY[j]); + RwIm2DVertexSetIntRGBA(&vertexbufferX[0], aCoronas[i].prevRed[j] * alpha1 / 256, aCoronas[i].prevGreen[j] * alpha1 / 256, aCoronas[i].prevBlue[j] * alpha1 / 256, 255); + RwIm2DVertexSetScreenX(&vertexbufferX[1], aCoronas[i].prevX[j+1]); + RwIm2DVertexSetScreenY(&vertexbufferX[1], aCoronas[i].prevY[j+1]); + RwIm2DVertexSetIntRGBA(&vertexbufferX[1], aCoronas[i].prevRed[j+1] * alpha2 / 256, aCoronas[i].prevGreen[j+1] * alpha2 / 256, aCoronas[i].prevBlue[j+1] * alpha2 / 256, 255); + +#ifdef FIX_BUGS + RwIm2DVertexSetScreenZ(&vertexbufferX[0], RwIm2DGetNearScreenZ()); + RwIm2DVertexSetCameraZ(&vertexbufferX[0], RwCameraGetNearClipPlane(Scene.camera)); + RwIm2DVertexSetRecipCameraZ(&vertexbufferX[0], 1.0f/RwCameraGetNearClipPlane(Scene.camera)); + RwIm2DVertexSetScreenZ(&vertexbufferX[1], RwIm2DGetNearScreenZ()); + RwIm2DVertexSetCameraZ(&vertexbufferX[1], RwCameraGetNearClipPlane(Scene.camera)); + RwIm2DVertexSetRecipCameraZ(&vertexbufferX[1], 1.0f/RwCameraGetNearClipPlane(Scene.camera)); +#endif + + RwIm2DRenderLine(vertexbufferX, 2, 0, 1); + } + } + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + + POP_RENDERGROUP(); +} + +void +CCoronas::RenderReflections(void) +{ + int i; + CColPoint point; + CEntity *entity; + + if(CWeather::WetRoads > 0.0f){ + PUSH_RENDERGROUP("CCoronas::RenderReflections"); + +#ifdef FIX_BUGS + CSprite::InitSpriteBuffer(); +#endif + + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[3])); + + for(i = 0; i < NUMCORONAS; i++){ + if(aCoronas[i].id == 0 || + aCoronas[i].fadeAlpha == 0 && aCoronas[i].alpha == 0 || + aCoronas[i].reflection == 0) + continue; + + // check if we want a reflection on this corona + if(aCoronas[i].renderReflection){ + if(((CTimer::GetFrameCounter() + i) & 0xF) == 0 && + CWorld::ProcessVerticalLine(aCoronas[i].coors, -1000.0f, point, entity, true, false, false, false, true, false, nil)) + aCoronas[i].heightAboveRoad = aCoronas[i].coors.z - point.point.z; + }else{ + if(CWorld::ProcessVerticalLine(aCoronas[i].coors, -1000.0f, point, entity, true, false, false, false, true, false, nil)){ + aCoronas[i].heightAboveRoad = aCoronas[i].coors.z - point.point.z; + aCoronas[i].renderReflection = true; + } + } + + // Don't draw if reflection is too high + if(aCoronas[i].renderReflection && aCoronas[i].heightAboveRoad < 20.0f){ + // don't draw if camera is below road + if(CCoronas::aCoronas[i].coors.z - aCoronas[i].heightAboveRoad > TheCamera.GetPosition().z) + continue; + + CVector coors = aCoronas[i].coors; + coors.z -= 2.0f*aCoronas[i].heightAboveRoad; + + CVector spriteCoors; + float spritew, spriteh; + if(CSprite::CalcScreenCoors(coors, &spriteCoors, &spritew, &spriteh, true)){ + float drawDist = 0.75f * aCoronas[i].drawDist; + drawDist = Min(drawDist, 55.0f); + if(spriteCoors.z < drawDist){ + float fadeDistance = drawDist / 2.0f; + float distanceFade = spriteCoors.z < fadeDistance ? 1.0f : 1.0f - (spriteCoors.z - fadeDistance)/fadeDistance; + distanceFade = Clamp(distanceFade, 0.0f, 1.0f); + float recipz = 1.0f/RwCameraGetNearClipPlane(Scene.camera); + float heightFade = (20.0f - aCoronas[i].heightAboveRoad)/20.0f; + int intensity = distanceFade*heightFade * 230.0 * CWeather::WetRoads; + + CSprite::RenderBufferedOneXLUSprite( +#ifdef FIX_BUGS + spriteCoors.x, spriteCoors.y, spriteCoors.z, +#else + spriteCoors.x, spriteCoors.y, RwIm2DGetNearScreenZ(), +#endif + spritew * aCoronas[i].size * 0.75f, + spriteh * aCoronas[i].size * 2.0f, + (intensity * CCoronas::aCoronas[i].red)>>8, + (intensity * CCoronas::aCoronas[i].green)>>8, + (intensity * CCoronas::aCoronas[i].blue)>>8, + 255, + recipz, + 255); + } + } + } + } + CSprite::FlushSpriteBuffer(); + + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + + POP_RENDERGROUP(); + }else{ + for(i = 0; i < NUMCORONAS; i++) + aCoronas[i].renderReflection = false; + } +} + +void +CCoronas::DoSunAndMoon(void) +{ + // yeah, moon is done somewhere else.... + + CVector sunCoors = CTimeCycle::GetSunDirection(); + sunCoors *= 150.0f; + sunCoors += TheCamera.GetPosition(); + + if(CTimeCycle::GetSunDirection().z > -0.2f){ + float size = ((CGeneral::GetRandomNumber()&0xFF) * 0.005f + 10.0f) * CTimeCycle::GetSunSize(); + RegisterCorona(SUN_CORE, + CTimeCycle::GetSunCoreRed(), CTimeCycle::GetSunCoreGreen(), CTimeCycle::GetSunCoreBlue(), + 255, sunCoors, size, + 999999.88f, TYPE_STAR, FLARE_NONE, REFLECTION_OFF, LOSCHECK_OFF, STREAK_OFF, 0.0f); + + if(CTimeCycle::GetSunDirection().z > 0.0f) + RegisterCorona(SUN_CORONA, + CTimeCycle::GetSunCoronaRed(), CTimeCycle::GetSunCoronaGreen(), CTimeCycle::GetSunCoronaBlue(), + 255, sunCoors, 25.0f * CTimeCycle::GetSunSize(), + 999999.88f, TYPE_STAR, FLARE_SUN, REFLECTION_OFF, LOSCHECK_ON, STREAK_OFF, 0.0f); + } + + CVector spriteCoors; + float spritew, spriteh; + if(CSprite::CalcScreenCoors(sunCoors, &spriteCoors, &spritew, &spriteh, true)){ + SunScreenX = spriteCoors.x; + SunScreenY = spriteCoors.y; + }else{ + SunScreenX = 1000000.0f; + SunScreenY = 1000000.0f; + } +} + +void +CRegisteredCorona::Update(void) +{ + if(!registeredThisFrame) + alpha = 0; + + if(LOScheck && + (CCoronas::SunBlockedByClouds && id == CCoronas::SUN_CORONA || + !CWorld::GetIsLineOfSightClear(coors, TheCamera.GetPosition(), true, false, false, false, false, false))){ + // Corona is blocked, fade out + fadeAlpha = Max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), 0.0f); + }else if(offScreen){ + // Same when off screen + fadeAlpha = Max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), 0.0f); + }else{ + // Visible + if(alpha > fadeAlpha){ + // fade in + fadeAlpha = Min(fadeAlpha + 15.0f*CTimer::GetTimeStep(), alpha); + if(CCoronas::bChangeBrightnessImmediately) + fadeAlpha = alpha; + }else if(alpha < fadeAlpha){ + // too visible, decrease alpha but not below alpha + fadeAlpha = Max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), alpha); + } + + // darken scene when the sun is visible + if(id == CCoronas::SUN_CORONA) + CCoronas::LightsMult = Max(CCoronas::LightsMult - CTimer::GetTimeStep()*0.06f, 0.6f); + } + + // remove if invisible + if(fadeAlpha == 0 && !firstUpdate) + id = 0; + firstUpdate = false; + registeredThisFrame = false; +} + +void +CEntity::ProcessLightsForEntity(void) +{ + int i, n; + C2dEffect *effect; + CVector pos; + bool lightOn, lightFlickering; + uint32 flashTimer1, flashTimer2, flashTimer3; + + if(bRenderDamaged || !bIsVisible || GetUp().z < 0.96f) + return; + + flashTimer1 = 0; + flashTimer2 = 0; + flashTimer3 = 0; + + n = CModelInfo::GetModelInfo(GetModelIndex())->GetNum2dEffects(); + for(i = 0; i < n; i++, flashTimer1 += 0x80, flashTimer2 += 0x100, flashTimer3 += 0x200){ + effect = CModelInfo::GetModelInfo(GetModelIndex())->Get2dEffect(i); + + if(effect->type != EFFECT_LIGHT) + continue; + + pos = GetMatrix() * effect->pos; + + lightOn = false; + lightFlickering = false; + switch(effect->light.lightType){ + case LIGHT_ON: + lightOn = true; + break; + case LIGHT_ON_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + lightOn = true; + break; + case LIGHT_FLICKER: + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3) + lightOn = true; + break; + case LIGHT_FLICKER_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7 || CWeather::WetRoads > 0.5f){ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3) + lightOn = true; + } + break; + case LIGHT_FLASH1: + if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200) + lightOn = true; + break; + case LIGHT_FLASH1_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200) + lightOn = true; + break; + case LIGHT_FLASH2: + if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400) + lightOn = true; + break; + case LIGHT_FLASH2_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400) + lightOn = true; + break; + case LIGHT_FLASH3: + if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800) + lightOn = true; + break; + case LIGHT_FLASH3_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800) + lightOn = true; + break; + case LIGHT_RANDOM_FLICKER: + if(m_randomSeed > 16) + lightOn = true; + else{ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3) + lightOn = true; + } + break; + case LIGHT_RANDOM_FLICKER_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7){ + if(m_randomSeed > 16) + lightOn = true; + else{ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3) + lightOn = true; + } + } + break; + case LIGHT_BRIDGE_FLASH1: + if(CBridge::ShouldLightsBeFlashing() && CTimer::GetTimeInMilliseconds() & 0x200) + lightOn = true; + break; + case LIGHT_BRIDGE_FLASH2: + if(CBridge::ShouldLightsBeFlashing() && (CTimer::GetTimeInMilliseconds() & 0x1FF) < 60) + lightOn = true; + break; + } + + // Corona + if(lightOn) + CCoronas::RegisterCorona((uintptr)this + i, + effect->col.r, effect->col.g, effect->col.b, 255, + pos, effect->light.size, effect->light.dist, + effect->light.corona, effect->light.flareType, effect->light.roadReflection, + effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f); + else if(lightFlickering) + CCoronas::RegisterCorona((uintptr)this + i, + 0, 0, 0, 255, + pos, effect->light.size, effect->light.dist, + effect->light.corona, effect->light.flareType, effect->light.roadReflection, + effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f); + + // Pointlight + if(effect->light.flags & LIGHTFLAG_FOG_ALWAYS){ + CPointLights::AddLight(CPointLights::LIGHT_FOGONLY_ALWAYS, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f, + CPointLights::FOG_ALWAYS, true); + }else if(effect->light.flags & LIGHTFLAG_FOG_NORMAL && lightOn && effect->light.range == 0.0f){ + CPointLights::AddLight(CPointLights::LIGHT_FOGONLY, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f, + CPointLights::FOG_NORMAL, true); + }else if(lightOn && effect->light.range != 0.0f){ + if(effect->col.r == 0 && effect->col.g == 0 && effect->col.b == 0){ + CPointLights::AddLight(CPointLights::LIGHT_POINT, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + 0.0f, 0.0f, 0.0f, + CPointLights::FOG_NONE, true); + }else{ + CPointLights::AddLight(CPointLights::LIGHT_POINT, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + effect->col.r*CTimeCycle::GetSpriteBrightness()/255.0f, + effect->col.g*CTimeCycle::GetSpriteBrightness()/255.0f, + effect->col.b*CTimeCycle::GetSpriteBrightness()/255.0f, + // half-useless because LIGHTFLAG_FOG_ALWAYS can't be on + (effect->light.flags & LIGHTFLAG_FOG) >> 1, + true); + } + } + + // Light shadow + if(effect->light.shadowSize != 0.0f){ + if(lightOn){ + CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE, + effect->light.shadow, &pos, + effect->light.shadowSize, 0.0f, + 0.0f, -effect->light.shadowSize, + 128, + effect->col.r*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + effect->col.g*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + effect->col.b*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + 15.0f, 1.0f, 40.0f, false, 0.0f); + }else if(lightFlickering){ + CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE, + effect->light.shadow, &pos, + effect->light.shadowSize, 0.0f, + 0.0f, -effect->light.shadowSize, + 0, 0.0f, 0.0f, 0.0f, + 15.0f, 1.0f, 40.0f, false, 0.0f); + } + } + } +} |