From 65d22d6ee6c6beeadc6f2e37de7157d2b9fc5eab Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sat, 6 May 2023 01:39:37 +0200 Subject: [PATCH 01/15] Save progress on `CClouds::Render` --- source/game_sa/Clouds.cpp | 144 ++++++++++++++++++++++++++++++++++++-- source/game_sa/Clouds.h | 2 + 2 files changed, 142 insertions(+), 4 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index 0b99efe48f..b4e94ed10e 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -221,10 +221,9 @@ void CClouds::MovingFogRender() { { const float step = CTimer::GetTimeStep() / 300.f; if (CCullZones::CamNoRain() && CCullZones::PlayerNoRain()) - CurrentFogIntensity = std::max(CurrentFogIntensity - step, 0.f); + CurrentFogIntensity = std::max(CurrentFogIntensity - step, 0.f); // Decreasing [towards 0] else - CurrentFogIntensity = std::min(CurrentFogIntensity + step, 1.f); - + CurrentFogIntensity = std::min(CurrentFogIntensity + step, 1.f); // Increasing [towards 1] if (CWeather::UnderWaterness >= CPostEffects::m_fWaterFXStartUnderWaterness) { CurrentFogIntensity = 0.f; @@ -301,9 +300,146 @@ void CClouds::MovingFogRender() { MovingFog_Update(); } +// From `CClouds::Render` [0x7139B2 - 0x713D2A] +void CClouds::Render_MaybeRenderMoon(float colorBalance) { + // 3D position offset of the moon relative to the camera + constexpr auto CAMERA_TO_CLOUD_OFFSET = CVector{ 0.f, -100.f, 15.f }; + + // How big the [moon] mask texture is relative to the actual moon + constexpr auto MOON_TO_MASK_SIZE_MULT = 1.7f; + + // Time range the moon is visible in + // The default value [220] means the moon is visible starting at + // 220 minutes before noon, and until 220 minutes after it + // So, that's 20:20 - 03:40 + constexpr auto MOON_VISIBILITY_RANGE_MINS = 3u * 60u + 40u; + + // Unused + //const auto clckHrs = CClock::ms_nGameClockHours; + //const auto clckMins = CClock::ms_nGameClockMinutes; + + const auto moonVisibilityTimeMins = (size_t)std::abs(CClock::GetMinutesToday() - (float)MOON_VISIBILITY_RANGE_MINS); + if (moonVisibilityTimeMins >= MOON_VISIBILITY_RANGE_MINS) { + return; // Moon not visible at the current time + } + + const auto ccolorB = MOON_VISIBILITY_RANGE_MINS - moonVisibilityTimeMins; + static_assert(MOON_VISIBILITY_RANGE_MINS == 220); // NOTE/TODO: The above will break otherwise, as it's really just a clever trick to avoid a more complex solution + const auto ccolorRG = lerp((float)ccolorB, 0.f, colorBalance); // AKA (1.f - colorBalance) * ccolorB + if (ccolorRG == 0) { + return; + } + + // + // Calculate moon position on the screen [From the 3D position] + // + CVector moonPosScr; + CVector2D scrSize; + if (!CSprite::CalcScreenCoors(TheCamera.GetPosition() + CAMERA_TO_CLOUD_OFFSET, &moonPosScr, &scrSize.x, &scrSize.y, false, true)) { + return; + } + + const auto z = CDraw::GetFarClipZ(); + const auto rhw = 1.f / z; + + // + // Draw black [textureless] sprite + // + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(NULL)); + RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDSRCALPHA)); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDONE)); + + const auto moonSz = scrSize * ((float)CCoronas::MoonSize * 2.f + 4.f); + CSprite::RenderOneXLUSprite( + moonPosScr.x, moonPosScr.y, z, + moonSz.x, moonSz.y, + 0, 0, 0, 255, + rhw, + 255, + 0, + 0 + ); + + // + // Draw moon's mask + // + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpMoonMask))); + RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDSRCALPHA)); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDONE)); + + const auto moonMaskSz = moonSz * MOON_TO_MASK_SIZE_MULT; + const auto moonMaskPosScr = moonPosScr + moonMaskSz * CVector2D{ + 0.7f, + 5.4f * (((float)CClock::GetGameClockDays() / 31.f - 0.5f)) // Slowly glide on the X axis according to current game day + }; + CSprite::RenderOneXLUSprite( + moonMaskPosScr.x, moonMaskPosScr.y, z, + moonMaskSz.x, moonMaskSz.y, + 0, 0, 0, 0, // NOTE/TODO: Alpha 0? + rhw, + 255, + 0, + 0 + ); + + // + // Draw the actual moon texture + // + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCoronaTexture[2]))); + RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDDESTALPHA)); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDONE)); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, RWRSTATE(FALSE)); + + CSprite::RenderOneXLUSprite( + moonPosScr.x, moonPosScr.y, z, + moonSz.x, moonSz.y, + ccolorRG, ccolorRG, (uint8)((float)ccolorB * 0.85f), 255, + rhw, + 255, + 0, + 0 + ); + + // + // [Cleanup]: Restore generic render states + // + RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDONE)); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDONE)); +} + +void CClouds::Render_MaybeRenderStars(float colorBalance) { + constexpr struct { + size_t begin, end; + } STARS_VISIBILITY_HRS{ + 22u, + 5u + }; + + const auto clckHrs = CClock::GetGameClockHours(); + const auto clckMins = CClock::GetGameClockMinutes(); + + if (STARS_VISIBILITY_HRS.begin ) +} + // 0x713950 void CClouds::Render() { - plugin::Call<0x713950>(); + if (!CGame::CanSeeOutSideFromCurrArea()) { + return; + } + + CCoronas::SunBlockedByClouds = false; + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, RWRSTATE(FALSE)); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, RWRSTATE(FALSE)); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, RWRSTATE(TRUE)); + RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDONE)); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDONE)); + + CSprite::InitSpriteBuffer(); + + Render_MaybeRenderMoon(); // [0x7139B2 - 0x713D2A] + Render_MaybeRenderStars(); + } // 0x714650 diff --git a/source/game_sa/Clouds.h b/source/game_sa/Clouds.h index ef2927f431..6188c8a9ab 100644 --- a/source/game_sa/Clouds.h +++ b/source/game_sa/Clouds.h @@ -76,6 +76,8 @@ class CClouds { static void MovingFog_Delete(int32 fogSlotIndex); static void MovingFog_Update(); static void MovingFogRender(); + static void Render_MaybeRenderMoon(float colorBalance); + static void Render_MaybeRenderStars(float colorBalance); static float MovingFog_GetFXIntensity(); static CVector MovingFog_GetWind(); static int32 MovingFog_GetFirstFreeSlot(); From bb0b4b30d8725317b094a1ec8f3b8d692aee6aef Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 7 May 2023 00:03:07 +0200 Subject: [PATCH 02/15] CClouds::Render --- source/game_sa/Clouds.cpp | 273 ++++++++++++++++++++++++++-- source/game_sa/Clouds.h | 14 +- source/game_sa/Core/Vector2D.h | 5 + source/game_sa/Coronas.h | 2 +- source/game_sa/Enums/eWeatherType.h | 13 ++ source/game_sa/RenderBuffer.cpp | 27 ++- source/game_sa/RenderBuffer.hpp | 16 +- source/game_sa/Sprite.cpp | 10 +- source/game_sa/common.h | 4 +- 9 files changed, 322 insertions(+), 42 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index b4e94ed10e..73628cb15c 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -48,7 +48,7 @@ void CClouds::InjectHooks() { RH_ScopedInstall(MovingFog_GetWind, 0x7136E0); RH_ScopedInstall(MovingFog_GetFirstFreeSlot, 0x713710); RH_ScopedInstall(MovingFogRender, 0x716C90); - RH_ScopedInstall(Render, 0x713950, { .reversed = false }); + RH_ScopedInstall(Render, 0x713950); RH_ScopedInstall(RenderSkyPolys, 0x714650); RH_ScopedInstall(RenderBottomFromHeight, 0x7154B0, { .reversed = false }); RH_ScopedInstall(VolumetricCloudsInit, 0x7131C0); @@ -300,6 +300,10 @@ void CClouds::MovingFogRender() { MovingFog_Update(); } +uint8 CalculateColorWithBalance(uint8 blue, float colorBalance) { + return lerp(blue, 0u, colorBalance); +} + // From `CClouds::Render` [0x7139B2 - 0x713D2A] void CClouds::Render_MaybeRenderMoon(float colorBalance) { // 3D position offset of the moon relative to the camera @@ -323,10 +327,10 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { return; // Moon not visible at the current time } - const auto ccolorB = MOON_VISIBILITY_RANGE_MINS - moonVisibilityTimeMins; + const auto colorB = MOON_VISIBILITY_RANGE_MINS - moonVisibilityTimeMins; static_assert(MOON_VISIBILITY_RANGE_MINS == 220); // NOTE/TODO: The above will break otherwise, as it's really just a clever trick to avoid a more complex solution - const auto ccolorRG = lerp((float)ccolorB, 0.f, colorBalance); // AKA (1.f - colorBalance) * ccolorB - if (ccolorRG == 0) { + const auto colorRG = CalculateColorWithBalance(colorB, colorBalance); + if (colorRG == 0) { return; } @@ -393,7 +397,7 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { CSprite::RenderOneXLUSprite( moonPosScr.x, moonPosScr.y, z, moonSz.x, moonSz.y, - ccolorRG, ccolorRG, (uint8)((float)ccolorB * 0.85f), 255, + colorRG, colorRG, (uint8)((float)colorB * 0.85f), 255, rhw, 255, 0, @@ -407,18 +411,247 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDONE)); } -void CClouds::Render_MaybeRenderStars(float colorBalance) { - constexpr struct { - size_t begin, end; - } STARS_VISIBILITY_HRS{ - 22u, - 5u +// From `CClouds::Render` [0x713D2A - 0x714019] +// Draws the R* logo on the sky +void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { + constexpr auto STARS_VISIBLE_FROM_HRS = 5u, + STARS_VISIBLE_TO_HRS = 22u; + + constexpr auto STARS_OFFSET_FROM_CAMERA = CVector{ 100.f, 0.f, 10.f }; + constexpr auto LAST_STAR_OFFSET_FROM_CAMERA = CVector{ 100.f, 0.f, STARS_OFFSET_FROM_CAMERA.z - 90.f }; + + constexpr auto STARS_NUM_POSITIONS = 9; + constexpr float STARS_Y_POSITIONS[STARS_NUM_POSITIONS] = { 0.00f, 0.05f, 0.13f, 0.40f, 0.70f, 0.60f, 0.27f, 0.55f, 0.75f }; // 0x8D55EC + constexpr float STARS_Z_POSITIONS[STARS_NUM_POSITIONS] = { 0.00f, 0.45f, 0.90f, 1.00f, 0.85f, 0.52f, 0.48f, 0.35f, 0.20f }; // 0x8D5610 + constexpr float STARS_SIZES[STARS_NUM_POSITIONS] = { 1.00f, 1.40f, 0.90f, 1.00f, 0.60f, 1.50f, 1.30f, 1.00f, 0.80f }; // 0x8D5634 + + if (!CClock::GetIsTimeInRange(STARS_VISIBLE_FROM_HRS, STARS_VISIBLE_TO_HRS)) { + return; + } + + const auto time = CClock::GetGameClockHours() == STARS_VISIBLE_FROM_HRS + ? CClock::GetGameClockMinutes() + : 60u - CClock::GetGameClockMinutes(); + + const auto colorB = 255u * time / 60u; + const auto colorRG = CalculateColorWithBalance(colorB, colorBalance); + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCoronaTexture[0]))); + + const auto camPos = TheCamera.GetPosition(); + + // + // Draw R + // + for (auto i = 0; i < 11; i++) { + CVector offset = STARS_OFFSET_FROM_CAMERA; + if (i >= 9) { // Clever trick to save memory I guess, re-uses the first 2 star vertices, but with X adjusted to be on the flipside + offset.x = -offset.x; + } + + const auto posIdx = i % STARS_NUM_POSITIONS; + offset.y -= STARS_Y_POSITIONS[posIdx] * 90.f; + offset.z += STARS_Z_POSITIONS[posIdx] * 80.f; + + CVector starPosScr; + CVector2D starSizeScr; + if (!CSprite::CalcScreenCoors(camPos + offset, &starPosScr, &starSizeScr.x, &starSizeScr.y, false, true)) { + continue; + } + + const auto cc = CalculateColorWithBalance(colorB, (float)(rand() % 32) * 0.0015f); + + starSizeScr *= STARS_SIZES[posIdx] * 0.8f; + + CSprite::RenderBufferedOneXLUSprite( + starPosScr.x, starPosScr.y, starPosScr.z, + starSizeScr.x, starSizeScr.y, + cc, cc, cc, 255, + 1.f / starPosScr.z, + 255 + ); + } + + // + // Draw the `*` + // + CVector lastStarPosScr; + CVector2D lastStarSizeScr; + if (CSprite::CalcScreenCoors(camPos + LAST_STAR_OFFSET_FROM_CAMERA, &lastStarPosScr, &lastStarSizeScr.x, &lastStarSizeScr.y, false, true)) { + const auto cc = CalculateColorWithBalance(colorB, (float)(rand() % 128) * 0.0015625f); + + lastStarSizeScr *= 5.f; + + CSprite::RenderBufferedOneXLUSprite( + lastStarPosScr.x, lastStarPosScr.y, lastStarPosScr.z, + lastStarSizeScr.x, lastStarSizeScr.y, + cc, cc, cc, 255, + 1.f / lastStarPosScr.z, + 255 + ); + } + + // + // Finally, draw it + // + CSprite::FlushSpriteBuffer(); +} + +// From `CClouds::Render` [0x714019 - 0x71422A] +void CClouds::Render_RenderLowClouds(float colorBalance) { + constexpr size_t NUM_LOW_CLOUDS = 12u; + constexpr float LOW_CLOUDS_X_COORDS[NUM_LOW_CLOUDS]{ 1.0f, 0.7f, 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, 0.8f, -0.8f, 0.4f, 0.4f }; // 0x8D5394 + constexpr float LOW_CLOUDS_Y_COORDS[NUM_LOW_CLOUDS]{ 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, 1.0f, 0.7f, 0.4f, 0.4f, -0.8f, -0.8f }; // 0x8D53C4 + constexpr float LOW_CLOUDS_Z_COORDS[NUM_LOW_CLOUDS]{ 0.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.3f, 0.9f, 0.4f, 1.3f, 1.4f, 1.2f, 1.7f }; // 0x8D53F4 + + const auto colorR = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsRed, colorBalance); + const auto colorG = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsGreen, colorBalance); + const auto colorB = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsBlue, colorBalance); + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCloudTex))); + + // Calculate camera roll + ms_cameraRoll = [&] { + const auto cmat = TheCamera.m_matrix; + if (!cmat) { + return 0.f; + } + const auto& right = cmat->GetRight(); + const auto xymag = CVector2D{ right }.SquaredMagnitude(); + return std::atan2(right.z, cmat->GetUp().z < 0.f ? -xymag : xymag); + }(); + + const auto camPos = TheCamera.GetPosition(); + for (auto i = 0u; i < NUM_LOW_CLOUDS; i++) { + // Offset from camera + const auto offset = CVector{ + LOW_CLOUDS_X_COORDS[i] * 800.f, + LOW_CLOUDS_Y_COORDS[i] * 800.f, + LOW_CLOUDS_Z_COORDS[i] * 60.f + 40.f + }; + + CVector cloudPosScr; + CVector2D cloudSizeScr; + if (!CSprite::CalcScreenCoors(camPos + offset, &cloudPosScr, &cloudSizeScr.x, &cloudSizeScr.y, false, true)) { + continue; + } + cloudSizeScr *= CVector2D{ 40.f, 320.f }; + + CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension( + cloudPosScr.x, cloudPosScr.y, cloudPosScr.z, + cloudSizeScr.x, cloudSizeScr.y, + colorR, colorG, colorB, 255, + 1.f / cloudPosScr.z, + ms_cameraRoll, + 255 + ); + } + + CSprite::FlushSpriteBuffer(); +} + +// From `CClouds::Render` [0x71422A - 0x714387] +void CClouds::Render_MaybeRenderRainbows() { + constexpr size_t NUM_RAINBOW_LINES = 6; + constexpr uint8 RAINBOW_LINES_COLOR_RED[NUM_RAINBOW_LINES]{ 30, 30, 30, 10, 0, 15 }; + constexpr uint8 RAINBOW_LINES_COLOR_GREEN[NUM_RAINBOW_LINES]{ 0, 15, 30, 30, 0, 0 }; + constexpr uint8 RAINBOW_LINES_COLOR_BLUE[NUM_RAINBOW_LINES]{ 0, 0, 0, 10, 30, 30 }; + + if (CWeather::Rainbow == 0.f) { + return; + } + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCoronaTexture[0]))); + + const auto camPos = TheCamera.GetPosition(); + + for (auto i = 0; i < NUM_RAINBOW_LINES; i++) { + const auto offset = CVector{ + (float)i * 1.5f, + 100.f, + 5.f + }; + + CVector rblinePosScr; + CVector2D rblineSizeScr; + if (!CSprite::CalcScreenCoors(camPos + offset, &rblinePosScr, &rblineSizeScr.x, &rblineSizeScr.y, false, true)) { + continue; + } + rblineSizeScr *= CVector2D{ 2.f, 50.f }; + + CSprite::RenderBufferedOneXLUSprite( + rblinePosScr.x, rblinePosScr.y, rblinePosScr.z, + rblineSizeScr.x, rblineSizeScr.y, + (uint8)((float)RAINBOW_LINES_COLOR_RED[i] * CWeather::Rainbow), + (uint8)((float)RAINBOW_LINES_COLOR_GREEN[i] * CWeather::Rainbow), + (uint8)((float)RAINBOW_LINES_COLOR_BLUE[i] * CWeather::Rainbow), + 255, + 1.f / rblinePosScr.z, + 255 + ); + } + + CSprite::FlushSpriteBuffer(); +} + +// From `CClouds::Render` [0x714387 - 0x714640] +void CClouds::Render_MaybeRenderStreaks() { + constexpr auto REPEAT_INTERVAL_MS = 8192; // Use power-of-2 numbers here if possible + constexpr auto VISIBILE_TIME_MS = 800; + static_assert(REPEAT_INTERVAL_MS >= VISIBILE_TIME_MS); + + RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDSRCALPHA)); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDINVSRCALPHA)); + + if (CClock::GetGameClockHours() >= 5) { + return; + } + + if (!IsExtraSunny(CWeather::OldWeatherType) && !IsExtraSunny(CWeather::NewWeatherType)) { + return; + } + + const auto repeatDelta = CTimer::GetTimeInMS() % REPEAT_INTERVAL_MS; + if (repeatDelta >= VISIBILE_TIME_MS) { + return; + } + + const auto repeatIdx = CTimer::GetTimeInMS() / REPEAT_INTERVAL_MS; + + //> 0x714464 + const auto size = CVector{ + (float)(repeatIdx % 64 % 7 - 3) * 0.1f, + (float)(repeatIdx - 4) * 0.1f, + 1.f + }.Normalized(); + + //> 0x7144C7 + const auto offsetDir = CVector{ + (float)(repeatIdx % 64 % 9 - 5), + (float)(repeatIdx % 64 % 10 - 5), + 0.1f + }.Normalized(); + + const auto basePos = offsetDir * 1000.f + TheCamera.GetPosition(); + + const auto v0Scale = (float)((VISIBILE_TIME_MS / 2 - repeatDelta) * 2); + const auto v1Scale = v0Scale + 50.f; + + RenderBuffer::ClearRenderBuffer(); + + const auto PushVertex = [=](float scale, CRGBA color) { + RenderBuffer::PushVertex( + basePos + size * scale, + color + ); }; - - const auto clckHrs = CClock::GetGameClockHours(); - const auto clckMins = CClock::GetGameClockMinutes(); - if (STARS_VISIBILITY_HRS.begin ) + PushVertex(v0Scale, { 255, 255, 255, 225 }); + PushVertex(v1Scale, { 255, 255, 255, 0 }); + + RenderBuffer::PushIndices({ 0, 1 }, true); + + RenderBuffer::Render(rwPRIMTYPEPOLYLINE, nullptr, rwIM3D_VERTEXRGBA | rwIM3D_VERTEXXYZ); } // 0x713950 @@ -437,9 +670,15 @@ void CClouds::Render() { CSprite::InitSpriteBuffer(); - Render_MaybeRenderMoon(); // [0x7139B2 - 0x713D2A] - Render_MaybeRenderStars(); + const auto colorBalance = std::max(CWeather::Foggyness, CWeather::CloudCoverage); + + // I've broken up this function into several others to make the code easier to understand + Render_MaybeRenderMoon(colorBalance); // [0x7139B2 - 0x713D2A] + Render_MaybeRenderRockstarLogo(colorBalance); // 0x713D2A - 0x714019 + Render_RenderLowClouds(std::max(colorBalance, CWeather::ExtraSunnyness)); + Render_MaybeRenderRainbows(); + Render_MaybeRenderStreaks(); } // 0x714650 diff --git a/source/game_sa/Clouds.h b/source/game_sa/Clouds.h index 6188c8a9ab..c77f984c08 100644 --- a/source/game_sa/Clouds.h +++ b/source/game_sa/Clouds.h @@ -77,7 +77,10 @@ class CClouds { static void MovingFog_Update(); static void MovingFogRender(); static void Render_MaybeRenderMoon(float colorBalance); - static void Render_MaybeRenderStars(float colorBalance); + static void Render_MaybeRenderRockstarLogo(float colorBalance); + static void Render_RenderLowClouds(float colorBalance); + static void Render_MaybeRenderRainbows(); + static void Render_MaybeRenderStreaks(); static float MovingFog_GetFXIntensity(); static CVector MovingFog_GetWind(); static int32 MovingFog_GetFirstFreeSlot(); @@ -94,15 +97,6 @@ class CClouds { static void RenderBottomFromHeight(); }; -extern uint8* RAINBOW_LINES_COLOR_RED; // RAINBOW_LINES_COLOR_RED[6] = { 30, 30, 30, 10, 0, 15 } -extern uint8* RAINBOW_LINES_COLOR_GREEN; // RAINBOW_LINES_COLOR_GREEN[6] = { 0, 15, 30, 30, 0, 0 } -extern uint8* RAINBOW_LINES_COLOR_BLUE; // RAINBOW_LINES_COLOR_BLUE[6] = { 0, 0, 0, 10, 30, 30 } -extern float* LOW_CLOUDS_X_COORDS; // LOW_CLOUDS_X_COORDS[12] = { 1.0f, 0.7f, 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, 0.8f, -0.8f, 0.4f, 0.4f } -extern float* LOW_CLOUDS_Y_COORDS; // LOW_CLOUDS_Y_COORDS[12] = { 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, 1.0f, 0.7f, 0.4f, 0.4f, -0.8f. -0.8f } -extern float* LOW_CLOUDS_Z_COORDS; // LOW_CLOUDS_Z_COORDS[12] = { 0.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.3f, 0.9f, 0.4f, 1.3f, 1.4f, 1.2f, 1.7f } -extern float* STARS_Y_POSITIONS; // STARS_Y_POSITIONS[9] = { 0.0f, 0.05f, 0.13f, 0.4f, 0.7f, 0.6f, 0.27f, 0.55f, 0.75f } -extern float* STARS_Z_POSITIONS; // STARS_Z_POSITIONS[9] = { 0.0f, 0.45f, 0.9f, 1.0f, 0.85f, 0.52f, 0.48f, 0.35f, 0.2f } -extern float* STARS_SIZES; // STARS_SIZES[9] = { 1.0f, 1.4f, 0.9f, 1.0f, 0.6f, 1.5f, 1.3f, 1.0f, 0.8f } extern float& CurrentFogIntensity; // default 1.0f extern RwTexture*& gpMoonMask; extern RwTexture*& gpCloudTex; diff --git a/source/game_sa/Core/Vector2D.h b/source/game_sa/Core/Vector2D.h index a5cc4a239a..85f03ac4ab 100644 --- a/source/game_sa/Core/Vector2D.h +++ b/source/game_sa/Core/Vector2D.h @@ -95,6 +95,11 @@ class CVector2D : public RwV2d { y *= multiplier; } + inline void operator*=(CVector2D multiplier) { + x *= multiplier.x; + y *= multiplier.y; + } + inline void operator/=(float divisor) { x /= divisor; y /= divisor; diff --git a/source/game_sa/Coronas.h b/source/game_sa/Coronas.h index 2420ca3d4a..8747b39dce 100644 --- a/source/game_sa/Coronas.h +++ b/source/game_sa/Coronas.h @@ -14,7 +14,7 @@ class CCoronas { static float& SunScreenX; static float& SunScreenY; // are there any obstacles between sun and camera - static bool& SunBlockedByClouds; + static inline auto& SunBlockedByClouds = StaticRef(); // change coronas brightness immediately static bool& bChangeBrightnessImmediately; // num of registered coronas in frame diff --git a/source/game_sa/Enums/eWeatherType.h b/source/game_sa/Enums/eWeatherType.h index bcad834999..28f52d7d03 100644 --- a/source/game_sa/Enums/eWeatherType.h +++ b/source/game_sa/Enums/eWeatherType.h @@ -35,3 +35,16 @@ enum eWeatherType : int16 { NUM_WEATHERS, WEATHER_EXTRA_START = WEATHER_EXTRACOLOURS_1 }; + +inline bool IsExtraSunny(eWeatherType wt) { + switch (wt) { + case WEATHER_EXTRASUNNY_LA: + case WEATHER_EXTRASUNNY_SMOG_LA: + case WEATHER_EXTRASUNNY_COUNTRYSIDE: + case WEATHER_EXTRASUNNY_SF: + case WEATHER_EXTRASUNNY_VEGAS: + case WEATHER_EXTRASUNNY_DESERT: + return true; + } + return false; +} diff --git a/source/game_sa/RenderBuffer.cpp b/source/game_sa/RenderBuffer.cpp index 73a412d721..ba73ef82ff 100644 --- a/source/game_sa/RenderBuffer.cpp +++ b/source/game_sa/RenderBuffer.cpp @@ -58,17 +58,22 @@ void StopStoring() { } } -// 0x707800 -void RenderStuffInBuffer() { +// NOTSA +void Render(RwPrimitiveType primType, RwMatrix* ltm, RwUInt32 /*RwIm3DTransformFlags*/ flags) { if (uiTempBufferVerticesStored) { if (RwIm3DTransform(aTempBufferVertices, uiTempBufferVerticesStored, nullptr, rwIM3D_VERTEXUV)) { - RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, aTempBufferIndices, uiTempBufferIndicesStored); + RwIm3DRenderIndexedPrimitive(primType, aTempBufferIndices, uiTempBufferIndicesStored); RwIm3DEnd(); } } ClearRenderBuffer(); } +// 0x707800 +void RenderStuffInBuffer() { + Render(rwPRIMTYPETRILIST, nullptr, rwIM3D_VERTEXUV); +} + // 0x707790 void ClearRenderBuffer() { uiTempBufferIndicesStored = 0; @@ -83,18 +88,30 @@ void RenderIfDoesntFit(int32 nIdxNeeded, int32 nVtxNeeded) { } // notsa -void PushVertex(CVector pos, CVector2D uv, CRGBA color) { +RwIm3DVertex* PushVertex(CVector pos, CRGBA color) { const auto vtx = &aTempBufferVertices[uiTempBufferVerticesStored++]; RwIm3DVertexSetPos(vtx, pos.x, pos.y, pos.z); RwIm3DVertexSetRGBA(vtx, color.r, color.g, color.b, color.a); + + return vtx; +} + +// notsa +RwIm3DVertex* PushVertex(CVector pos, CVector2D uv, CRGBA color) { + const auto vtx = PushVertex(pos, color); + RwIm3DVertexSetU(vtx, uv.x); RwIm3DVertexSetV(vtx, uv.y); + + return vtx; } // notsa void PushIndex(RwImVertexIndex idx, bool useCurrentVtxAsBase) { - aTempBufferIndices[uiTempBufferIndicesStored++] = useCurrentVtxAsBase ? uiTempBufferVerticesStored + idx : idx; + aTempBufferIndices[uiTempBufferIndicesStored++] = useCurrentVtxAsBase + ? uiTempBufferVerticesStored + idx + : idx; } // notsa diff --git a/source/game_sa/RenderBuffer.hpp b/source/game_sa/RenderBuffer.hpp index 6c31a59a47..b6cf879cb3 100644 --- a/source/game_sa/RenderBuffer.hpp +++ b/source/game_sa/RenderBuffer.hpp @@ -38,6 +38,12 @@ void StopStoring(); */ void RenderStuffInBuffer(); +/*! +* @notsa +* @brief Render out the contents of the temporary buffer as specified by the arguments. Frequently inlined! +*/ +void Render(RwPrimitiveType primType, RwMatrix* ltm = nullptr, RwUInt32 /*RwIm3DTransformFlags*/ flags = 0); + /*! * @addr 0x707790 * @brief Reset the index/vertex buffer stored counters. @@ -53,9 +59,15 @@ void RenderIfDoesntFit(int32 nIdx, int32 nVtx); /* * @addr notsa -* @brief Push a vertex to the buffer. Not to be used with `StartStoring`! +* @brief Push a vertex to the buffer. Not to be used with `StartStoring`! Use if the VERTEXUV flag **IS NOT** used when calling `Render` +*/ +RwIm3DVertex* PushVertex(CVector pos, CRGBA color); + +/* +* @addr notsa +* @brief Push a vertex to the buffer. Not to be used with `StartStoring`! Use if the VERTEXUV flag **IS** used when calling `Render` */ -void PushVertex(CVector pos, CVector2D uv, CRGBA color); +RwIm3DVertex* PushVertex(CVector pos, CVector2D uv, CRGBA color); /*! * @addr notsa diff --git a/source/game_sa/Sprite.cpp b/source/game_sa/Sprite.cpp index f63eee86ed..b761de4749 100644 --- a/source/game_sa/Sprite.cpp +++ b/source/game_sa/Sprite.cpp @@ -67,13 +67,13 @@ bool CSprite::CalcScreenCoors(const RwV3d& posn, RwV3d* out, float* w, float* h, if (out->z >= CDraw::GetFarClipZ() && checkMaxVisible) return false; - const float recip = 1.0f / out->z; + const float rd = 1.0f / out->z; // reciprocal of depth - out->x = SCREEN_WIDTH * recip * out->x; - out->y = SCREEN_HEIGHT * recip * out->y; + out->x = SCREEN_WIDTH * rd * out->x; + out->y = SCREEN_HEIGHT * rd * out->y; - *w = SCREEN_WIDTH * recip / CDraw::GetFOV() * 70.0f; - *h = SCREEN_HEIGHT * recip / CDraw::GetFOV() * 70.0f; + *w = SCREEN_WIDTH * rd / CDraw::GetFOV() * 70.0f; + *h = SCREEN_HEIGHT * rd / CDraw::GetFOV() * 70.0f; return true; } diff --git a/source/game_sa/common.h b/source/game_sa/common.h index db5e168889..336a5c4ef2 100644 --- a/source/game_sa/common.h +++ b/source/game_sa/common.h @@ -154,8 +154,8 @@ constexpr float RadiansToDegrees(float angleInRadians) { } template -auto lerp(const T& from, const T& to, float t) { - return to * t + from * (1.f - t); +T lerp(const T& from, const T& to, float t) { + return static_cast(to * t + from * (1.f - t)); } inline const float invLerp(float fMin, float fMax, float fVal) { From 44742fa8a2ef08c6f3f5a371828fcacb3944b97b Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 7 May 2023 14:37:29 +0200 Subject: [PATCH 03/15] Add `CloudsDebugModule` --- source/game_sa/Clouds.cpp | 82 +++++++++++++++---- source/game_sa/Clouds.h | 6 ++ .../DebugModules/CloudsDebugModule.cpp | 67 +++++++++++++++ .../DebugModules/CloudsDebugModule.hpp | 16 ++++ .../toolsmenu/DebugModules/DebugModules.cpp | 2 + 5 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 source/toolsmenu/DebugModules/CloudsDebugModule.cpp create mode 100644 source/toolsmenu/DebugModules/CloudsDebugModule.hpp diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index 73628cb15c..c2d33930bd 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -322,9 +322,19 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { //const auto clckHrs = CClock::ms_nGameClockHours; //const auto clckMins = CClock::ms_nGameClockMinutes; +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.Moon.Enabled) { + return; + } +#endif + const auto moonVisibilityTimeMins = (size_t)std::abs(CClock::GetMinutesToday() - (float)MOON_VISIBILITY_RANGE_MINS); - if (moonVisibilityTimeMins >= MOON_VISIBILITY_RANGE_MINS) { - return; // Moon not visible at the current time + if (moonVisibilityTimeMins >= MOON_VISIBILITY_RANGE_MINS) { // Check is the moon not visible at the current time +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.Moon.Force) { + return; + } +#endif } const auto colorB = MOON_VISIBILITY_RANGE_MINS - moonVisibilityTimeMins; @@ -414,22 +424,32 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { // From `CClouds::Render` [0x713D2A - 0x714019] // Draws the R* logo on the sky void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { - constexpr auto STARS_VISIBLE_FROM_HRS = 5u, - STARS_VISIBLE_TO_HRS = 22u; + constexpr auto LOGO_VISIBLE_FROM_HRS = 22u, + LOGO_VISIBLE_UNTIL_HRS = 5u; - constexpr auto STARS_OFFSET_FROM_CAMERA = CVector{ 100.f, 0.f, 10.f }; - constexpr auto LAST_STAR_OFFSET_FROM_CAMERA = CVector{ 100.f, 0.f, STARS_OFFSET_FROM_CAMERA.z - 90.f }; + constexpr auto R_OFFSET_FROM_CAMERA = CVector{ 100.f, 0.f, 10.f }; // Letter `R` offset from camera + constexpr auto STAR_OFFSET_FROM_CAMERA = CVector{ 100.f, 0.f, R_OFFSET_FROM_CAMERA.z - 90.f }; // `*` [As in R*] offset from camera constexpr auto STARS_NUM_POSITIONS = 9; constexpr float STARS_Y_POSITIONS[STARS_NUM_POSITIONS] = { 0.00f, 0.05f, 0.13f, 0.40f, 0.70f, 0.60f, 0.27f, 0.55f, 0.75f }; // 0x8D55EC constexpr float STARS_Z_POSITIONS[STARS_NUM_POSITIONS] = { 0.00f, 0.45f, 0.90f, 1.00f, 0.85f, 0.52f, 0.48f, 0.35f, 0.20f }; // 0x8D5610 constexpr float STARS_SIZES[STARS_NUM_POSITIONS] = { 1.00f, 1.40f, 0.90f, 1.00f, 0.60f, 1.50f, 1.30f, 1.00f, 0.80f }; // 0x8D5634 - if (!CClock::GetIsTimeInRange(STARS_VISIBLE_FROM_HRS, STARS_VISIBLE_TO_HRS)) { +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.Rockstar.Enabled) { return; } +#endif - const auto time = CClock::GetGameClockHours() == STARS_VISIBLE_FROM_HRS + if (!CClock::GetIsTimeInRange(LOGO_VISIBLE_FROM_HRS, LOGO_VISIBLE_UNTIL_HRS)) { +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.Rockstar.Force) { + return; + } +#endif + } + + const auto time = CClock::GetGameClockHours() == LOGO_VISIBLE_FROM_HRS ? CClock::GetGameClockMinutes() : 60u - CClock::GetGameClockMinutes(); @@ -441,10 +461,10 @@ void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { const auto camPos = TheCamera.GetPosition(); // - // Draw R + // Draw `R` // for (auto i = 0; i < 11; i++) { - CVector offset = STARS_OFFSET_FROM_CAMERA; + CVector offset = R_OFFSET_FROM_CAMERA; if (i >= 9) { // Clever trick to save memory I guess, re-uses the first 2 star vertices, but with X adjusted to be on the flipside offset.x = -offset.x; } @@ -459,7 +479,7 @@ void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { continue; } - const auto cc = CalculateColorWithBalance(colorB, (float)(rand() % 32) * 0.0015f); + const auto cc = CalculateColorWithBalance(colorB, (float)(rand() % 32) * 0.015f); starSizeScr *= STARS_SIZES[posIdx] * 0.8f; @@ -477,8 +497,8 @@ void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { // CVector lastStarPosScr; CVector2D lastStarSizeScr; - if (CSprite::CalcScreenCoors(camPos + LAST_STAR_OFFSET_FROM_CAMERA, &lastStarPosScr, &lastStarSizeScr.x, &lastStarSizeScr.y, false, true)) { - const auto cc = CalculateColorWithBalance(colorB, (float)(rand() % 128) * 0.0015625f); + if (CSprite::CalcScreenCoors(camPos + STAR_OFFSET_FROM_CAMERA, &lastStarPosScr, &lastStarSizeScr.x, &lastStarSizeScr.y, false, true)) { + const auto cc = CalculateColorWithBalance(colorB, (float)(rand() % 128) * 0.0015625f + 0.5f); lastStarSizeScr *= 5.f; @@ -508,6 +528,12 @@ void CClouds::Render_RenderLowClouds(float colorBalance) { const auto colorG = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsGreen, colorBalance); const auto colorB = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsBlue, colorBalance); +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.LowClouds.Enabled) { + return; + } +#endif + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCloudTex))); // Calculate camera roll @@ -557,9 +583,19 @@ void CClouds::Render_MaybeRenderRainbows() { constexpr uint8 RAINBOW_LINES_COLOR_GREEN[NUM_RAINBOW_LINES]{ 0, 15, 30, 30, 0, 0 }; constexpr uint8 RAINBOW_LINES_COLOR_BLUE[NUM_RAINBOW_LINES]{ 0, 0, 0, 10, 30, 30 }; - if (CWeather::Rainbow == 0.f) { +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.Rainbow.Enabled) { return; } +#endif + + if (CWeather::Rainbow == 0.f) { +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.Rainbow.Force) { + return; + } +#endif + } RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCoronaTexture[0]))); @@ -603,14 +639,26 @@ void CClouds::Render_MaybeRenderStreaks() { RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDSRCALPHA)); RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDINVSRCALPHA)); - if (CClock::GetGameClockHours() >= 5) { +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.Rainbow.Enabled) { return; } +#endif - if (!IsExtraSunny(CWeather::OldWeatherType) && !IsExtraSunny(CWeather::NewWeatherType)) { - return; +#ifdef NOTSA_DEBUG + if (!s_DebugSettings.Rainbow.Force) +#endif + { + if (CClock::GetGameClockHours() >= 5) { + return; + } + + if (!IsExtraSunny(CWeather::OldWeatherType) && !IsExtraSunny(CWeather::NewWeatherType)) { + return; + } } + // This must always be checked, otherwise code breaks const auto repeatDelta = CTimer::GetTimeInMS() % REPEAT_INTERVAL_MS; if (repeatDelta >= VISIBILE_TIME_MS) { return; diff --git a/source/game_sa/Clouds.h b/source/game_sa/Clouds.h index c77f984c08..12483d60f8 100644 --- a/source/game_sa/Clouds.h +++ b/source/game_sa/Clouds.h @@ -62,6 +62,12 @@ class CClouds { static CVector& PlayerCoords; static CVector& CameraCoors; + static inline struct DebugSettings { + struct RenderSettingPair { + bool Enabled = true, Force = false; + } Moon, Rockstar, LowClouds, Rainbow, Streaks; + } s_DebugSettings; + public: static void InjectHooks(); diff --git a/source/toolsmenu/DebugModules/CloudsDebugModule.cpp b/source/toolsmenu/DebugModules/CloudsDebugModule.cpp new file mode 100644 index 0000000000..76e50ff47c --- /dev/null +++ b/source/toolsmenu/DebugModules/CloudsDebugModule.cpp @@ -0,0 +1,67 @@ +#include +#include "CloudsDebugModule.hpp" +#include + +using namespace ImGui; + +namespace notsa { +namespace debugmodules { +void RenderDebugSettingPairs() { + if (!BeginTable("Settings", 6, ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_ScrollY)) { + return; + } + + TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed); + TableSetupColumn("Enabled", ImGuiTableColumnFlags_WidthFixed); + TableSetupColumn("Force Render", ImGuiTableColumnFlags_WidthFixed); + + TableHeadersRow(); + + const auto DoRenderSettingPair = [](const char* name, auto& pair) { + const ui::ScopedID scopeID{ name }; + + TableNextRow(); + BeginGroup(); + + TableNextColumn(); + TextUnformatted(name); + + TableNextColumn(); + Checkbox("###Enabled", &pair.Enabled); + + TableNextColumn(); + Checkbox("###Force", &pair.Force); + + EndGroup(); + }; + +#define RenderSettingPair(_name) DoRenderSettingPair(#_name, CClouds::s_DebugSettings._name) + RenderSettingPair(Moon); + RenderSettingPair(Rockstar); + RenderSettingPair(LowClouds); + RenderSettingPair(Rainbow); + RenderSettingPair(Streaks); +#undef RenderSettingPair + + EndTable(); +} + +void CloudsDebugModule::RenderWindow() { + const ::notsa::ui::ScopedWindow window{ "CloudsDebugModule", {}, m_IsOpen }; + if (!m_IsOpen) { + return; + } + + if (TreeNodeEx("Render Settings")) { + RenderDebugSettingPairs(); + TreePop(); + } +} + +void CloudsDebugModule::RenderMenuEntry() { + notsa::ui::DoNestedMenuIL({ "Extra" }, [&] { + ImGui::MenuItem("Clouds", nullptr, &m_IsOpen); + }); +} +}; // namespace debugmodules +}; // namespace notsa diff --git a/source/toolsmenu/DebugModules/CloudsDebugModule.hpp b/source/toolsmenu/DebugModules/CloudsDebugModule.hpp new file mode 100644 index 0000000000..a1ddb8d47a --- /dev/null +++ b/source/toolsmenu/DebugModules/CloudsDebugModule.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "DebugModule.h" + +namespace notsa { +namespace debugmodules { +class CloudsDebugModule final : public DebugModule { +public: + void RenderWindow() override; + void RenderMenuEntry() override; + +private: + bool m_IsOpen{}; +}; +}; // namespace debugmodules +}; // namespace notsa diff --git a/source/toolsmenu/DebugModules/DebugModules.cpp b/source/toolsmenu/DebugModules/DebugModules.cpp index 6229ba6907..ea00c53334 100644 --- a/source/toolsmenu/DebugModules/DebugModules.cpp +++ b/source/toolsmenu/DebugModules/DebugModules.cpp @@ -23,6 +23,7 @@ #include "./Spawner/SpawnerDebugModule.hpp" #include "./ImGuiDebugModule.hpp" #include "./ScriptDebugModule.hpp" +#include "./CloudsDebugModule.hpp" DebugModules::DebugModules(ImGuiContext* ctx) : m_ImCtx(ctx) @@ -81,6 +82,7 @@ void DebugModules::CreateModules() { Add(); Add(); Add(); + Add(); // Stuff that is present in multiple menus Add(); // Visualization + Extra From 28f6e5fe7603a5f365afcbf9b2375920f36a58ab Mon Sep 17 00:00:00 2001 From: Pirulax Date: Mon, 8 May 2023 00:04:25 +0200 Subject: [PATCH 04/15] `VolumetricCloudsRender` + Debug stuff --- source/game_sa/Clouds.cpp | 491 +++++++++++++----- source/game_sa/Clouds.h | 38 +- source/game_sa/RenderBuffer.cpp | 16 +- source/game_sa/RenderBuffer.hpp | 8 +- .../DebugModules/CloudsDebugModule.cpp | 1 + 5 files changed, 404 insertions(+), 150 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index c2d33930bd..f789c274ba 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -3,9 +3,6 @@ #include "Clouds.h" #include "PostEffects.h" -// float& CClouds::m_fVolumetricCloudDensity; // unused -// bool& CClouds::m_bVolumetricCloudHeightSwitch; // unused -// float& CClouds::m_fVolumetricCloudWindMoveFactor; // unused float& CClouds::m_fVolumetricCloudMaxDistance = *reinterpret_cast(0xC6AA58); uint32& CClouds::m_VolumetricCloudsUsedNum = *reinterpret_cast(0xC6AA5C); @@ -52,7 +49,7 @@ void CClouds::InjectHooks() { RH_ScopedInstall(RenderSkyPolys, 0x714650); RH_ScopedInstall(RenderBottomFromHeight, 0x7154B0, { .reversed = false }); RH_ScopedInstall(VolumetricCloudsInit, 0x7131C0); - RH_ScopedInstall(VolumetricClouds_Create, 0x715F40, { .reversed = false }); + RH_ScopedInstall(VolumetricClouds_Create, 0x715F40); RH_ScopedInstall(VolumetricClouds_Delete, 0x7135F0); RH_ScopedInstall(VolumetricClouds_GetFirstFreeSlot, 0x7135C0); RH_ScopedInstall(VolumetricCloudsGetMaxDistance, 0x713630); @@ -66,7 +63,7 @@ void CClouds::Init() { gpCloudTex = RwTextureRead("cloud1", nullptr); gpCloudMaskTex = RwTextureRead("cloudmasked", nullptr); gpMoonMask = RwTextureRead("lunar", "lunarm"); - ms_vc.m_pTex = RwTextureRead("cloudhigh", "cloudhighm"); + ms_vc.texture = RwTextureRead("cloudhigh", "cloudhighm"); CTxdStore::PopCurrentTxd(); CloudRotation = 0.0f; VolumetricCloudsInit(); @@ -87,8 +84,8 @@ void CClouds::Shutdown() { RwTextureDestroy(gpCloudMaskTex); gpCloudMaskTex = nullptr; - RwTextureDestroy(ms_vc.m_pTex); - ms_vc.m_pTex = nullptr; + RwTextureDestroy(ms_vc.texture); + ms_vc.texture = nullptr; } // 0x713060 @@ -887,137 +884,188 @@ void CClouds::RenderBottomFromHeight() { plugin::Call<0x7154B0>(); } +// +// -- VOLUMETRIC CLOUDS -- +// + // 0x7131C0 void CClouds::VolumetricCloudsInit() { - ms_vc.m_vecCloudsSpace[0] = CVector(0.0f, 1.0f, 0.0f); - ms_vc.m_vecCloudsSpace[1] = CVector(0.0f, 0.0f, 1.0f); - ms_vc.m_vecCloudsSpace[2] = CVector(1.0f, 0.0f, 0.0f); - - ms_vc.m_fCloudXCoords[0] = -0.5f; - ms_vc.m_fCloudYCoords[0] = 0.0f; - ms_vc.m_fCloudZCoords[0] = 0.5f; - ms_vc.m_fCloudUCoords[0] = 0.0f; - ms_vc.m_fCloudVCoords[0] = 0.0f; - - ms_vc.m_fCloudXCoords[1] = 0.5f; - ms_vc.m_fCloudYCoords[1] = 0.0f; - ms_vc.m_fCloudZCoords[1] = 0.5f; - ms_vc.m_fCloudUCoords[1] = 1.0f; - ms_vc.m_fCloudVCoords[1] = 0.0f; - - ms_vc.m_fCloudXCoords[2] = -0.5f; - ms_vc.m_fCloudYCoords[2] = 0.0f; - ms_vc.m_fCloudZCoords[2] = -0.5f; - ms_vc.m_fCloudUCoords[2] = 0.0f; - ms_vc.m_fCloudVCoords[2] = 1.0f; - - ms_vc.m_fCloudXCoords[3] = 0.5f; - ms_vc.m_fCloudYCoords[3] = 0.0f; - ms_vc.m_fCloudZCoords[3] = 0.5f; - ms_vc.m_fCloudUCoords[3] = 1.0f; - ms_vc.m_fCloudVCoords[3] = 0.0f; - - ms_vc.m_fCloudXCoords[4] = 0.5f; - ms_vc.m_fCloudYCoords[4] = 0.0f; - ms_vc.m_fCloudZCoords[4] = -0.5f; - ms_vc.m_fCloudUCoords[4] = 1.0f; - ms_vc.m_fCloudVCoords[4] = 1.0f; - - ms_vc.m_fCloudXCoords[5] = -0.5f; - ms_vc.m_fCloudYCoords[5] = 0.0f; - ms_vc.m_fCloudZCoords[5] = -0.5f; - ms_vc.m_fCloudUCoords[5] = 0.0f; - ms_vc.m_fCloudVCoords[5] = 1.0f; - - ms_vc.m_fCloudXCoords[6] = -0.5f; - ms_vc.m_fCloudYCoords[6] = 0.5f; - ms_vc.m_fCloudZCoords[6] = 0.0f; - ms_vc.m_fCloudUCoords[6] = 0.0f; - ms_vc.m_fCloudVCoords[6] = 0.0f; - - ms_vc.m_fCloudXCoords[7] = 0.5f; - ms_vc.m_fCloudYCoords[7] = 0.5f; - ms_vc.m_fCloudZCoords[7] = 0.0f; - ms_vc.m_fCloudUCoords[7] = 1.0f; - ms_vc.m_fCloudVCoords[7] = 0.0f; - - ms_vc.m_fCloudXCoords[8] = -0.5f; - ms_vc.m_fCloudYCoords[8] = -0.5f; - ms_vc.m_fCloudZCoords[8] = 0.0f; - ms_vc.m_fCloudUCoords[8] = 0.0f; - ms_vc.m_fCloudVCoords[8] = 1.0f; - - ms_vc.m_fCloudXCoords[9] = 0.5f; - ms_vc.m_fCloudYCoords[9] = 0.5f; - ms_vc.m_fCloudZCoords[9] = 0.0f; - ms_vc.m_fCloudUCoords[9] = 1.0f; - ms_vc.m_fCloudVCoords[9] = 0.0f; - - ms_vc.m_fCloudXCoords[10] = 0.5f; - ms_vc.m_fCloudYCoords[10] = -0.5f; - ms_vc.m_fCloudZCoords[10] = 0.0f; - ms_vc.m_fCloudUCoords[10] = 1.0f; - ms_vc.m_fCloudVCoords[10] = 1.0f; - - ms_vc.m_fCloudXCoords[11] = -0.5f; - ms_vc.m_fCloudYCoords[11] = -0.5f; - ms_vc.m_fCloudZCoords[11] = 0.0f; - ms_vc.m_fCloudUCoords[11] = 0.0f; - ms_vc.m_fCloudVCoords[11] = 1.0f; - - ms_vc.m_fCloudXCoords[12] = 0.0f; - ms_vc.m_fCloudYCoords[12] = -0.5f; - ms_vc.m_fCloudZCoords[12] = 0.5f; - ms_vc.m_fCloudUCoords[12] = 0.0f; - ms_vc.m_fCloudVCoords[12] = 0.0f; - - ms_vc.m_fCloudXCoords[13] = 0.0f; - ms_vc.m_fCloudYCoords[13] = 0.5f; - ms_vc.m_fCloudZCoords[13] = 0.5f; - ms_vc.m_fCloudUCoords[13] = 1.0f; - ms_vc.m_fCloudVCoords[13] = 0.0f; - - ms_vc.m_fCloudXCoords[14] = 0.0f; - ms_vc.m_fCloudYCoords[14] = -0.5f; - ms_vc.m_fCloudZCoords[14] = -0.5f; - ms_vc.m_fCloudUCoords[14] = 0.0f; - ms_vc.m_fCloudVCoords[14] = 1.0f; - - ms_vc.m_fCloudXCoords[15] = 0.0f; - ms_vc.m_fCloudYCoords[15] = 0.5f; - ms_vc.m_fCloudZCoords[15] = 0.5f; - ms_vc.m_fCloudUCoords[15] = 1.0f; - ms_vc.m_fCloudVCoords[15] = 0.0f; - - ms_vc.m_fCloudXCoords[16] = 0.0f; - ms_vc.m_fCloudYCoords[16] = 0.5f; - ms_vc.m_fCloudZCoords[16] = -0.5f; - ms_vc.m_fCloudUCoords[16] = 1.0f; - ms_vc.m_fCloudVCoords[16] = 1.0f; - - ms_vc.m_fCloudXCoords[17] = 0.0f; - ms_vc.m_fCloudYCoords[17] = -0.5f; - ms_vc.m_fCloudZCoords[17] = -0.5f; - ms_vc.m_fCloudUCoords[17] = 0.0f; - ms_vc.m_fCloudVCoords[17] = 1.0f; + ms_vc.quadNormal[0] = CVector(0.0f, 1.0f, 0.0f); + ms_vc.quadNormal[1] = CVector(0.0f, 0.0f, 1.0f); + ms_vc.quadNormal[2] = CVector(1.0f, 0.0f, 0.0f); + + ms_vc.modelX[0] = -0.5f; + ms_vc.modelY[0] = 0.0f; + ms_vc.modelZ[0] = 0.5f; + ms_vc.modelU[0] = 0.0f; + ms_vc.modelV[0] = 0.0f; + + ms_vc.modelX[1] = 0.5f; + ms_vc.modelY[1] = 0.0f; + ms_vc.modelZ[1] = 0.5f; + ms_vc.modelU[1] = 1.0f; + ms_vc.modelV[1] = 0.0f; + + ms_vc.modelX[2] = -0.5f; + ms_vc.modelY[2] = 0.0f; + ms_vc.modelZ[2] = -0.5f; + ms_vc.modelU[2] = 0.0f; + ms_vc.modelV[2] = 1.0f; + + ms_vc.modelX[3] = 0.5f; + ms_vc.modelY[3] = 0.0f; + ms_vc.modelZ[3] = 0.5f; + ms_vc.modelU[3] = 1.0f; + ms_vc.modelV[3] = 0.0f; + + ms_vc.modelX[4] = 0.5f; + ms_vc.modelY[4] = 0.0f; + ms_vc.modelZ[4] = -0.5f; + ms_vc.modelU[4] = 1.0f; + ms_vc.modelV[4] = 1.0f; + + ms_vc.modelX[5] = -0.5f; + ms_vc.modelY[5] = 0.0f; + ms_vc.modelZ[5] = -0.5f; + ms_vc.modelU[5] = 0.0f; + ms_vc.modelV[5] = 1.0f; + + ms_vc.modelX[6] = -0.5f; + ms_vc.modelY[6] = 0.5f; + ms_vc.modelZ[6] = 0.0f; + ms_vc.modelU[6] = 0.0f; + ms_vc.modelV[6] = 0.0f; + + ms_vc.modelX[7] = 0.5f; + ms_vc.modelY[7] = 0.5f; + ms_vc.modelZ[7] = 0.0f; + ms_vc.modelU[7] = 1.0f; + ms_vc.modelV[7] = 0.0f; + + ms_vc.modelX[8] = -0.5f; + ms_vc.modelY[8] = -0.5f; + ms_vc.modelZ[8] = 0.0f; + ms_vc.modelU[8] = 0.0f; + ms_vc.modelV[8] = 1.0f; + + ms_vc.modelX[9] = 0.5f; + ms_vc.modelY[9] = 0.5f; + ms_vc.modelZ[9] = 0.0f; + ms_vc.modelU[9] = 1.0f; + ms_vc.modelV[9] = 0.0f; + + ms_vc.modelX[10] = 0.5f; + ms_vc.modelY[10] = -0.5f; + ms_vc.modelZ[10] = 0.0f; + ms_vc.modelU[10] = 1.0f; + ms_vc.modelV[10] = 1.0f; + + ms_vc.modelX[11] = -0.5f; + ms_vc.modelY[11] = -0.5f; + ms_vc.modelZ[11] = 0.0f; + ms_vc.modelU[11] = 0.0f; + ms_vc.modelV[11] = 1.0f; + + ms_vc.modelX[12] = 0.0f; + ms_vc.modelY[12] = -0.5f; + ms_vc.modelZ[12] = 0.5f; + ms_vc.modelU[12] = 0.0f; + ms_vc.modelV[12] = 0.0f; + + ms_vc.modelX[13] = 0.0f; + ms_vc.modelY[13] = 0.5f; + ms_vc.modelZ[13] = 0.5f; + ms_vc.modelU[13] = 1.0f; + ms_vc.modelV[13] = 0.0f; + + ms_vc.modelX[14] = 0.0f; + ms_vc.modelY[14] = -0.5f; + ms_vc.modelZ[14] = -0.5f; + ms_vc.modelU[14] = 0.0f; + ms_vc.modelV[14] = 1.0f; + + ms_vc.modelX[15] = 0.0f; + ms_vc.modelY[15] = 0.5f; + ms_vc.modelZ[15] = 0.5f; + ms_vc.modelU[15] = 1.0f; + ms_vc.modelV[15] = 0.0f; + + ms_vc.modelX[16] = 0.0f; + ms_vc.modelY[16] = 0.5f; + ms_vc.modelZ[16] = -0.5f; + ms_vc.modelU[16] = 1.0f; + ms_vc.modelV[16] = 1.0f; + + ms_vc.modelX[17] = 0.0f; + ms_vc.modelY[17] = -0.5f; + ms_vc.modelZ[17] = -0.5f; + ms_vc.modelU[17] = 0.0f; + ms_vc.modelV[17] = 1.0f; for (auto i = 0u; i < MAX_VOLUMETRIC_CLOUDS; ++i) { - ms_vc.m_bSlots[i] = false; - ms_vc.m_bInsideVisibilityRange[i] = 0; + ms_vc.bUsed[i] = false; + ms_vc.bJustCreated[i] = 0; } } -// see VolumetricClouds_GetFirstFreeSlot // 0x715F40 void CClouds::VolumetricClouds_Create(CVector* posn) { - plugin::Call<0x715F40, CVector*>(posn); + using CGeneral::GetRandomNumberInRange; + + const auto rand1To5 = GetRandomNumberInRange(1.f, 5.f); + + const auto AddVolumetricCloud = [ + randMinSizeXYZ = rand1To5 * 20.f, + randMaxSizeXY = rand1To5 * 100.f, + randMaxSizeZ = rand1To5 * 40.f + ](int32 vcidx, CVector pos) { + ms_vc.bUsed[vcidx] = true; + ms_vc.bJustCreated[vcidx] = true; + ms_vc.alpha[vcidx] = GetRandomNumberInRange(36, 128); + + ms_vc.size[vcidx] = CVector{ + GetRandomNumberInRange(randMinSizeXYZ, randMaxSizeXY), + GetRandomNumberInRange(randMinSizeXYZ, randMaxSizeXY), + GetRandomNumberInRange(randMinSizeXYZ, randMaxSizeZ), + }; + + ms_vc.pos[vcidx] = pos; + }; + + if (posn) { + const auto randMinMaxOffsetXYZ = rand1To5 * 3.f; + for (auto i = 0; i < 5; i++) { + const auto vcidx = VolumetricClouds_GetFirstFreeSlot(); + if (vcidx == -1) { + return; + } + const auto pos = *posn = *posn + CVector::Random(-randMinMaxOffsetXYZ, randMinMaxOffsetXYZ); + AddVolumetricCloud( + vcidx, + pos + ); + } + } else { + const auto camPos = TheCamera.GetPosition(); + const auto maxDist = m_fVolumetricCloudMaxDistance; + for (auto i = 0; i < MAX_VOLUMETRIC_CLOUDS; i++) { + AddVolumetricCloud( + i, + camPos + CVector{ + GetRandomNumberInRange(-maxDist, maxDist), + GetRandomNumberInRange(-maxDist, maxDist), + GetRandomNumberInRange(-maxDist * 0.25f, maxDist * 0.25f), + } + ); + } + } } // 0x7135F0 void CClouds::VolumetricClouds_Delete(int32 vcSlotIndex) { vcSlotIndex = std::clamp(vcSlotIndex, 0, MAX_VOLUMETRIC_CLOUDS - 1); - ms_vc.m_bSlots[vcSlotIndex] = false; - ms_vc.m_bInsideVisibilityRange[vcSlotIndex] = false; + ms_vc.bUsed[vcSlotIndex] = false; + ms_vc.bJustCreated[vcSlotIndex] = false; } // unused @@ -1025,20 +1073,203 @@ void CClouds::VolumetricClouds_Delete(int32 vcSlotIndex) { // 0x7135C0 int32 CClouds::VolumetricClouds_GetFirstFreeSlot() { for (auto i = 0u; i < m_VolumetricCloudsUsedNum; i++) { - if (!ms_vc.m_bSlots[i]) - return i; + if (!ms_vc.bUsed[i]) { + return (int32)i; + } } - return -1; } // 0x713630 float CClouds::VolumetricCloudsGetMaxDistance() { - const auto farPlane = RwCameraGetFarClipPlane(Scene.m_pRwCamera); - return farPlane < 600.0f ? farPlane : 600.0f; + return std::min(RwCameraGetFarClipPlane(Scene.m_pRwCamera), 600.f); } // 0x716380 void CClouds::VolumetricCloudsRender() { - plugin::Call<0x716380>(); + if (!s_DebugSettings.VolumetricClouds.Enabled) { + return; + } + + const auto plyr = FindPlayerPed(); + if (!CGame::CanSeeOutSideFromCurrArea() || plyr->IsInCurrentArea()) { + if (!s_DebugSettings.VolumetricClouds.Force) { + return; + } + } + + m_fVolumetricCloudDensity = [] { + switch (g_fx.GetFxQuality()) { + case FX_QUALITY_LOW: return 0.5f; + case FX_QUALITY_MEDIUM: return 1.f / 3.f; + default: return 1.f; + } + }(); + + m_VolumetricCloudsUsedNum = lerp(0, MAX_VOLUMETRIC_CLOUDS, m_fVolumetricCloudDensity); + + if (!m_VolumetricCloudsUsedNum) { + return; + } + + m_fVolumetricCloudMaxDistance = CClouds::VolumetricCloudsGetMaxDistance(); + + const auto fadeOutBeginDist = m_fVolumetricCloudMaxDistance - 100.f; + const auto fadeOutDist = m_fVolumetricCloudMaxDistance + 200.f; + + const auto camPos = TheCamera.GetPosition(); + + auto& gfVolumetricCloudFader = StaticRef(); + if (m_bVolumetricCloudHeightSwitch) { + const auto delta = CTimer::GetTimeStep() * 4.f; + if (camPos.z < 220.f) { + gfVolumetricCloudFader += delta; + if (gfVolumetricCloudFader >= 255.f) { + gfVolumetricCloudFader = 255.f; + return; + } + } else { + gfVolumetricCloudFader -= delta; + if (gfVolumetricCloudFader < 0.f) { + gfVolumetricCloudFader = 0.f; + } + } + } else { + gfVolumetricCloudFader = 0.f; + } + + CPostEffects::ImmediateModeRenderStatesStore(); + CPostEffects::ImmediateModeRenderStatesSet(); + + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, RWRSTATE(TRUE)); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(ms_vc.texture))); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, RWRSTATE(rwFILTERLINEAR)); + + const auto plyrPos = FindPlayerCoors(); + const auto plyrVeh = FindPlayerVehicle(); + + //> 0x71653F + auto& gVecCameraCoors = StaticRef(); + auto& gVecPlayerCoors = StaticRef(); + + const auto bIsCameraOrPlayerPosNotStatic = (camPos != gVecCameraCoors) || (plyrPos != gVecPlayerCoors); + + gVecCameraCoors = camPos; + gVecPlayerCoors = plyrPos; + + if (bIsCameraOrPlayerPosNotStatic) { // If player/it's veh has moved, recreate the clouds + const auto t = plyrVeh ? (CPlaceable*)plyrVeh : (CPlaceable*)&TheCamera; + auto pos = ( + t->GetPosition() + + t->GetForward() * fadeOutDist + + CVector::Random( + CVector{-200.f, -200.f, -50.f}, + CVector{ 200.f, 200.f, 50.f} + ) + ); + VolumetricClouds_Create(&pos); + } + + //> 0x7166DD - Calculate color + const auto& cc = CTimeCycle::m_CurrentColours; + const auto vcClr = (uint8)std::min(( + cc.m_nSkyTopRed + + cc.m_nSkyTopGreen + + cc.m_nSkyTopBlue + + cc.m_nSkyBottomRed + + cc.m_nSkyBottomGreen + + cc.m_nSkyBottomBlue + ) / 6 + 64, 255); + + if (!m_VolumetricCloudsUsedNum) { + CPostEffects::ImmediateModeRenderStatesReStore(); + return; + } + + // + // Actually render the vc's + // + + + // NOTE: They didn't use RenderBuffer functions, but to make our life easier [and the code nicer] we do + RenderBuffer::ClearRenderBuffer(); + + const auto RenderOutBuffer = [] { + RenderBuffer::Render(rwPRIMTYPETRILIST, nullptr, rwIM3D_VERTEXXYZ | rwIM3D_VERTEXUV, false); + }; + + for (auto vcidx = 0u; vcidx < MAX_VOLUMETRIC_CLOUDS; vcidx++) { + if (!ms_vc.bUsed[vcidx]) { + continue; + } + + auto& vcpos = ms_vc.pos[vcidx]; + auto& vcsz = ms_vc.size[vcidx]; + + const auto vcDistToCam2D = (camPos - vcpos).Magnitude2D(); + + // Adjust vc position by wind [TODO: Should use TimeStep/Framedelta] + vcpos += CVector{ m_fVolumetricCloudWindMoveFactor * CVector2D{ CWeather::WindDir } }; + + //> 0x716772 - VC too far, delete it + if (!ms_vc.bJustCreated[vcidx] && vcDistToCam2D > m_fVolumetricCloudMaxDistance) { + VolumetricClouds_Delete(vcidx); + continue; + } + + if (vcDistToCam2D <= m_fVolumetricCloudMaxDistance || fadeOutDist <= vcDistToCam2D) { + ms_vc.bJustCreated[vcidx] = false; + } + + //> 0x7167DC - Alpha calculation [I don't understand it either] + auto vcAlpha = std::max(0, (int32)(ms_vc.alpha[vcidx] - gfVolumetricCloudFader)); + if (vcDistToCam2D > fadeOutBeginDist) { + if (!vcAlpha) { + continue; + } + if (vcDistToCam2D > m_fVolumetricCloudMaxDistance) { + continue; + } + const auto distAlpha = std::max(0, (int32)(((m_fVolumetricCloudMaxDistance - fadeOutBeginDist) - (vcDistToCam2D - fadeOutBeginDist)) * (float)vcAlpha / (m_fVolumetricCloudMaxDistance - fadeOutBeginDist))); + vcAlpha = std::min(vcAlpha, distAlpha); + if (!vcAlpha) { + continue; + } + } + + // Direction of vc to camera + const auto vcToCamDir = (vcpos - camPos).Normalized(); + + //> 0x7168F0 - Calculate quad colors + CRGBA quadColors[3]; + for (auto i = 0; i < 3; i++) { + quadColors[i] = { + vcClr, + vcClr, + vcClr, + (uint8)(std::abs(vcToCamDir.Dot(ms_vc.quadNormal[i]) * (float)vcAlpha)) + }; + } + + //> 0x7169F0 - Each quad has 3 vertices [As each quad consists of 2 triangles, each with 3 vertices] + for (auto k = 0; k < 3 * 6; k++) { + const auto quadIdx = k / 6; + + RenderBuffer::PushVertex( + vcpos + CVector{ ms_vc.modelX[k], ms_vc.modelY[k], ms_vc.modelZ[k] } * vcsz, + CVector2D{ms_vc.modelU[k], ms_vc.modelV[k]}, + quadColors[quadIdx] + ); + + // If the buffer is full - Render it to make space for the upcoming vertices + if (!RenderBuffer::CanFitVertices(1)) { + RenderOutBuffer(); + } + } + } + + // Render whatever remains in the buffer + RenderOutBuffer(); + + CPostEffects::ImmediateModeRenderStatesReStore(); } diff --git a/source/game_sa/Clouds.h b/source/game_sa/Clouds.h index 12483d60f8..7c8cee684b 100644 --- a/source/game_sa/Clouds.h +++ b/source/game_sa/Clouds.h @@ -33,25 +33,31 @@ struct tMovingFog { }; struct tVolumetricClouds { - bool m_bSlots[MAX_VOLUMETRIC_CLOUDS]; - bool m_bInsideVisibilityRange[MAX_VOLUMETRIC_CLOUDS]; - CVector field_168[MAX_VOLUMETRIC_CLOUDS]; - CVector field_9D8[MAX_VOLUMETRIC_CLOUDS]; - int32 m_nHeight[MAX_VOLUMETRIC_CLOUDS]; - RwTexture* m_pTex; - CVector m_vecCloudsSpace[3]; - float m_fCloudXCoords[18]; - float m_fCloudYCoords[18]; - float m_fCloudZCoords[18]; - float m_fCloudUCoords[18]; - float m_fCloudVCoords[18]; + bool bUsed[MAX_VOLUMETRIC_CLOUDS]; + bool bJustCreated[MAX_VOLUMETRIC_CLOUDS]; + + CVector pos[MAX_VOLUMETRIC_CLOUDS]; + CVector size[MAX_VOLUMETRIC_CLOUDS]; + + int32 alpha[MAX_VOLUMETRIC_CLOUDS]; + + RwTexture* texture; + + CVector quadNormal[3]; + + float modelX[18]; + float modelY[18]; + float modelZ[18]; + + float modelU[18]; + float modelV[18]; }; class CClouds { public: - static float& m_fVolumetricCloudDensity; // default 1.0f - static bool& m_bVolumetricCloudHeightSwitch; // default true - static float& m_fVolumetricCloudWindMoveFactor; // default 0.1f + static inline auto& m_fVolumetricCloudDensity = StaticRef(); + static inline auto& m_bVolumetricCloudHeightSwitch = StaticRef(); + static inline auto& m_fVolumetricCloudWindMoveFactor = StaticRef(); static float& m_fVolumetricCloudMaxDistance; static uint32& m_VolumetricCloudsUsedNum; static float& ms_cameraRoll; @@ -65,7 +71,7 @@ class CClouds { static inline struct DebugSettings { struct RenderSettingPair { bool Enabled = true, Force = false; - } Moon, Rockstar, LowClouds, Rainbow, Streaks; + } Moon, Rockstar, LowClouds, Rainbow, Streaks, VolumetricClouds; } s_DebugSettings; public: diff --git a/source/game_sa/RenderBuffer.cpp b/source/game_sa/RenderBuffer.cpp index ba73ef82ff..881079ecce 100644 --- a/source/game_sa/RenderBuffer.cpp +++ b/source/game_sa/RenderBuffer.cpp @@ -59,10 +59,15 @@ void StopStoring() { } // NOTSA -void Render(RwPrimitiveType primType, RwMatrix* ltm, RwUInt32 /*RwIm3DTransformFlags*/ flags) { +void Render(RwPrimitiveType primType, RwMatrix* ltm, RwUInt32 /*RwIm3DTransformFlags*/ flags, bool isIndexed) { if (uiTempBufferVerticesStored) { - if (RwIm3DTransform(aTempBufferVertices, uiTempBufferVerticesStored, nullptr, rwIM3D_VERTEXUV)) { - RwIm3DRenderIndexedPrimitive(primType, aTempBufferIndices, uiTempBufferIndicesStored); + if (RwIm3DTransform(aTempBufferVertices, uiTempBufferVerticesStored, ltm, flags)) { + if (isIndexed) { + assert(aTempBufferIndices); + RwIm3DRenderIndexedPrimitive(primType, aTempBufferIndices, uiTempBufferIndicesStored); + } else { + RwIm3DRenderPrimitive(primType); + } RwIm3DEnd(); } } @@ -120,4 +125,9 @@ void PushIndices(std::initializer_list idxs, bool useCurrentVtx PushIndex(idx, useCurrentVtxAsBase); } } + +bool CanFitVertices(int32 nVtxNeeded) { + return uiTempBufferVerticesStored + nVtxNeeded <= VtxBufferSize; +} + }; // namespace RenderBuffer diff --git a/source/game_sa/RenderBuffer.hpp b/source/game_sa/RenderBuffer.hpp index b6cf879cb3..5aee9682fc 100644 --- a/source/game_sa/RenderBuffer.hpp +++ b/source/game_sa/RenderBuffer.hpp @@ -42,7 +42,7 @@ void RenderStuffInBuffer(); * @notsa * @brief Render out the contents of the temporary buffer as specified by the arguments. Frequently inlined! */ -void Render(RwPrimitiveType primType, RwMatrix* ltm = nullptr, RwUInt32 /*RwIm3DTransformFlags*/ flags = 0); +void Render(RwPrimitiveType primType, RwMatrix* ltm = nullptr, RwUInt32 /*RwIm3DTransformFlags*/ flags = 0, bool isIndexed = true); /*! * @addr 0x707790 @@ -81,4 +81,10 @@ void PushIndex(RwImVertexIndex idx, bool useCurrentVtxAsBase); * @brief Push multiple indices into the buffer. Not to be used with `StartStoring`! */ void PushIndices(std::initializer_list idxs, bool useCurrentVtxAsBase); + +/*! +* @addr notsa +* @brief Check if the buffer can fit `nVtxNeeded` vertices +*/ +bool CanFitVertices(int32 nVtxNeeded); }; // namespace RenderBuffer diff --git a/source/toolsmenu/DebugModules/CloudsDebugModule.cpp b/source/toolsmenu/DebugModules/CloudsDebugModule.cpp index 76e50ff47c..36b3db54c4 100644 --- a/source/toolsmenu/DebugModules/CloudsDebugModule.cpp +++ b/source/toolsmenu/DebugModules/CloudsDebugModule.cpp @@ -41,6 +41,7 @@ void RenderDebugSettingPairs() { RenderSettingPair(LowClouds); RenderSettingPair(Rainbow); RenderSettingPair(Streaks); + RenderSettingPair(VolumetricClouds); #undef RenderSettingPair EndTable(); From 09343d434a7261aff5bb128bbc9f4b40ff82194f Mon Sep 17 00:00:00 2001 From: Pirulax Date: Mon, 8 May 2023 22:36:15 +0200 Subject: [PATCH 05/15] Fix `VolumetricCloudsRender` --- source/game_sa/Clouds.cpp | 56 ++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index f789c274ba..87deda6237 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -53,7 +53,7 @@ void CClouds::InjectHooks() { RH_ScopedInstall(VolumetricClouds_Delete, 0x7135F0); RH_ScopedInstall(VolumetricClouds_GetFirstFreeSlot, 0x7135C0); RH_ScopedInstall(VolumetricCloudsGetMaxDistance, 0x713630); - RH_ScopedInstall(VolumetricCloudsRender, 0x716380, { .reversed = false }); + RH_ScopedInstall(VolumetricCloudsRender, 0x716380); } // 0x7138D0 @@ -1092,7 +1092,7 @@ void CClouds::VolumetricCloudsRender() { } const auto plyr = FindPlayerPed(); - if (!CGame::CanSeeOutSideFromCurrArea() || plyr->IsInCurrentArea()) { + if (!CGame::CanSeeOutSideFromCurrArea() || !plyr->IsInCurrentArea()) { if (!s_DebugSettings.VolumetricClouds.Force) { return; } @@ -1129,10 +1129,7 @@ void CClouds::VolumetricCloudsRender() { return; } } else { - gfVolumetricCloudFader -= delta; - if (gfVolumetricCloudFader < 0.f) { - gfVolumetricCloudFader = 0.f; - } + gfVolumetricCloudFader = std::max(0.f, gfVolumetricCloudFader - delta); } } else { gfVolumetricCloudFader = 0.f; @@ -1145,9 +1142,12 @@ void CClouds::VolumetricCloudsRender() { RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(ms_vc.texture))); RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, RWRSTATE(rwFILTERLINEAR)); + FindPlayerPed()->GetMoveSpeed() = CVector{0.f, 0.f, 0.f}; + const auto plyrPos = FindPlayerCoors(); const auto plyrVeh = FindPlayerVehicle(); + //> 0x71653F auto& gVecCameraCoors = StaticRef(); auto& gVecPlayerCoors = StaticRef(); @@ -1198,39 +1198,39 @@ void CClouds::VolumetricCloudsRender() { RenderBuffer::Render(rwPRIMTYPETRILIST, nullptr, rwIM3D_VERTEXXYZ | rwIM3D_VERTEXUV, false); }; - for (auto vcidx = 0u; vcidx < MAX_VOLUMETRIC_CLOUDS; vcidx++) { + for (auto vcidx = 0u; vcidx < m_VolumetricCloudsUsedNum; vcidx++) { if (!ms_vc.bUsed[vcidx]) { continue; } - auto& vcpos = ms_vc.pos[vcidx]; - auto& vcsz = ms_vc.size[vcidx]; + auto& vcPos = ms_vc.pos[vcidx]; + auto& vcSz = ms_vc.size[vcidx]; - const auto vcDistToCam2D = (camPos - vcpos).Magnitude2D(); + const auto vcDistToCam = (camPos - vcPos).Magnitude(); - // Adjust vc position by wind [TODO: Should use TimeStep/Framedelta] - vcpos += CVector{ m_fVolumetricCloudWindMoveFactor * CVector2D{ CWeather::WindDir } }; + //> 0x71674E - Adjust vc position by wind [TODO: Should use TimeStep/Framedelta] + vcPos += CVector{ m_fVolumetricCloudWindMoveFactor * CVector2D{ CWeather::WindDir } }; //> 0x716772 - VC too far, delete it - if (!ms_vc.bJustCreated[vcidx] && vcDistToCam2D > m_fVolumetricCloudMaxDistance) { + if (!ms_vc.bJustCreated[vcidx] && vcDistToCam > m_fVolumetricCloudMaxDistance) { VolumetricClouds_Delete(vcidx); continue; } - if (vcDistToCam2D <= m_fVolumetricCloudMaxDistance || fadeOutDist <= vcDistToCam2D) { + if (vcDistToCam <= m_fVolumetricCloudMaxDistance || fadeOutDist <= vcDistToCam) { ms_vc.bJustCreated[vcidx] = false; } //> 0x7167DC - Alpha calculation [I don't understand it either] - auto vcAlpha = std::max(0, (int32)(ms_vc.alpha[vcidx] - gfVolumetricCloudFader)); - if (vcDistToCam2D > fadeOutBeginDist) { + auto vcAlpha = std::max(0, ms_vc.alpha[vcidx] - (int32)gfVolumetricCloudFader); + if (vcDistToCam > fadeOutBeginDist) { if (!vcAlpha) { continue; } - if (vcDistToCam2D > m_fVolumetricCloudMaxDistance) { + if (vcDistToCam > m_fVolumetricCloudMaxDistance) { continue; } - const auto distAlpha = std::max(0, (int32)(((m_fVolumetricCloudMaxDistance - fadeOutBeginDist) - (vcDistToCam2D - fadeOutBeginDist)) * (float)vcAlpha / (m_fVolumetricCloudMaxDistance - fadeOutBeginDist))); + const auto distAlpha = std::max(0, (int32)(((m_fVolumetricCloudMaxDistance - fadeOutBeginDist) - (vcDistToCam - fadeOutBeginDist)) * (float)vcAlpha / (m_fVolumetricCloudMaxDistance - fadeOutBeginDist))); vcAlpha = std::min(vcAlpha, distAlpha); if (!vcAlpha) { continue; @@ -1238,7 +1238,7 @@ void CClouds::VolumetricCloudsRender() { } // Direction of vc to camera - const auto vcToCamDir = (vcpos - camPos).Normalized(); + const auto vcToCamDir = (vcPos - camPos).Normalized(); //> 0x7168F0 - Calculate quad colors CRGBA quadColors[3]; @@ -1247,7 +1247,7 @@ void CClouds::VolumetricCloudsRender() { vcClr, vcClr, vcClr, - (uint8)(std::abs(vcToCamDir.Dot(ms_vc.quadNormal[i]) * (float)vcAlpha)) + (uint8)(std::abs(vcToCamDir.Dot(ms_vc.quadNormal[i])) * (float)vcAlpha) }; } @@ -1255,16 +1255,18 @@ void CClouds::VolumetricCloudsRender() { for (auto k = 0; k < 3 * 6; k++) { const auto quadIdx = k / 6; - RenderBuffer::PushVertex( - vcpos + CVector{ ms_vc.modelX[k], ms_vc.modelY[k], ms_vc.modelZ[k] } * vcsz, - CVector2D{ms_vc.modelU[k], ms_vc.modelV[k]}, - quadColors[quadIdx] - ); - // If the buffer is full - Render it to make space for the upcoming vertices - if (!RenderBuffer::CanFitVertices(1)) { + // This does differ a little from what they did originally, but it's fine, as the + // end result is the same + if (!RenderBuffer::CanFitVertices(3)) { // Must be rendered in groups of 3, otherwise triangles would be rendered with the wrong vertices RenderOutBuffer(); } + + RenderBuffer::PushVertex( + vcPos + CVector{ ms_vc.modelX[k], ms_vc.modelY[k], ms_vc.modelZ[k] } * vcSz, + CVector2D{ms_vc.modelU[k], ms_vc.modelV[k]}, + quadColors[k / 6] + ); } } From 76865e0b54d46c3a6e2fce675850cb137c015b8c Mon Sep 17 00:00:00 2001 From: Pirulax Date: Thu, 11 May 2023 21:42:37 +0200 Subject: [PATCH 06/15] remove PP wrap from debug stuff --- source/game_sa/Clouds.cpp | 49 +++++++++++++-------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index 87deda6237..777fec1494 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -25,18 +25,21 @@ RwTexture*& gpCloudTex = *reinterpret_cast(0xC6AA78); RwTexture*& gpCloudMaskTex = *reinterpret_cast(0xC6AA78 + 0x4); float& flt_C6E954 = *reinterpret_cast(0xC6E954); // see CClouds::RenderBottomFromHeight, CClouds::MovingFogRender -float& flt_C6E970 = *reinterpret_cast(0xC6E970); // see CClouds::VolumetricCloudsRender - -int32& dword_C6E974 = *reinterpret_cast(0xC6E974); // see CClouds::VolumetricCloudsRender void CClouds::InjectHooks() { RH_ScopedClass(CClouds); RH_ScopedCategoryGlobal(); + // Clouds RH_ScopedInstall(Init, 0x7138D0); RH_ScopedInstall(Update, 0x712FF0); RH_ScopedInstall(Shutdown, 0x712FA0); RH_ScopedInstall(SetUpOneSkyPoly, 0x713060); + RH_ScopedInstall(Render, 0x713950); + RH_ScopedInstall(RenderSkyPolys, 0x714650); + RH_ScopedInstall(RenderBottomFromHeight, 0x7154B0, { .reversed = false }); + + // Moving fog RH_ScopedInstall(MovingFogInit, 0x713660); RH_ScopedInstall(MovingFog_Create, 0x713760); RH_ScopedInstall(MovingFog_Delete, 0x713730); @@ -45,9 +48,8 @@ void CClouds::InjectHooks() { RH_ScopedInstall(MovingFog_GetWind, 0x7136E0); RH_ScopedInstall(MovingFog_GetFirstFreeSlot, 0x713710); RH_ScopedInstall(MovingFogRender, 0x716C90); - RH_ScopedInstall(Render, 0x713950); - RH_ScopedInstall(RenderSkyPolys, 0x714650); - RH_ScopedInstall(RenderBottomFromHeight, 0x7154B0, { .reversed = false }); + + // Volumetric clouds RH_ScopedInstall(VolumetricCloudsInit, 0x7131C0); RH_ScopedInstall(VolumetricClouds_Create, 0x715F40); RH_ScopedInstall(VolumetricClouds_Delete, 0x7135F0); @@ -319,19 +321,15 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { //const auto clckHrs = CClock::ms_nGameClockHours; //const auto clckMins = CClock::ms_nGameClockMinutes; -#ifdef NOTSA_DEBUG if (!s_DebugSettings.Moon.Enabled) { return; } -#endif const auto moonVisibilityTimeMins = (size_t)std::abs(CClock::GetMinutesToday() - (float)MOON_VISIBILITY_RANGE_MINS); - if (moonVisibilityTimeMins >= MOON_VISIBILITY_RANGE_MINS) { // Check is the moon not visible at the current time -#ifdef NOTSA_DEBUG - if (!s_DebugSettings.Moon.Force) { + if (!s_DebugSettings.Moon.Force) { + if (moonVisibilityTimeMins >= MOON_VISIBILITY_RANGE_MINS) { // Check is the moon not visible at the current time return; } -#endif } const auto colorB = MOON_VISIBILITY_RANGE_MINS - moonVisibilityTimeMins; @@ -432,18 +430,14 @@ void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { constexpr float STARS_Z_POSITIONS[STARS_NUM_POSITIONS] = { 0.00f, 0.45f, 0.90f, 1.00f, 0.85f, 0.52f, 0.48f, 0.35f, 0.20f }; // 0x8D5610 constexpr float STARS_SIZES[STARS_NUM_POSITIONS] = { 1.00f, 1.40f, 0.90f, 1.00f, 0.60f, 1.50f, 1.30f, 1.00f, 0.80f }; // 0x8D5634 -#ifdef NOTSA_DEBUG if (!s_DebugSettings.Rockstar.Enabled) { return; } -#endif - if (!CClock::GetIsTimeInRange(LOGO_VISIBLE_FROM_HRS, LOGO_VISIBLE_UNTIL_HRS)) { -#ifdef NOTSA_DEBUG - if (!s_DebugSettings.Rockstar.Force) { + if (!s_DebugSettings.Rockstar.Force) { + if (!CClock::GetIsTimeInRange(LOGO_VISIBLE_FROM_HRS, LOGO_VISIBLE_UNTIL_HRS)) { return; } -#endif } const auto time = CClock::GetGameClockHours() == LOGO_VISIBLE_FROM_HRS @@ -525,11 +519,9 @@ void CClouds::Render_RenderLowClouds(float colorBalance) { const auto colorG = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsGreen, colorBalance); const auto colorB = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsBlue, colorBalance); -#ifdef NOTSA_DEBUG if (!s_DebugSettings.LowClouds.Enabled) { return; } -#endif RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCloudTex))); @@ -580,18 +572,14 @@ void CClouds::Render_MaybeRenderRainbows() { constexpr uint8 RAINBOW_LINES_COLOR_GREEN[NUM_RAINBOW_LINES]{ 0, 15, 30, 30, 0, 0 }; constexpr uint8 RAINBOW_LINES_COLOR_BLUE[NUM_RAINBOW_LINES]{ 0, 0, 0, 10, 30, 30 }; -#ifdef NOTSA_DEBUG if (!s_DebugSettings.Rainbow.Enabled) { return; } -#endif - if (CWeather::Rainbow == 0.f) { -#ifdef NOTSA_DEBUG - if (!s_DebugSettings.Rainbow.Force) { + if (!s_DebugSettings.Rainbow.Force) { + if (CWeather::Rainbow == 0.f) { return; } -#endif } RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCoronaTexture[0]))); @@ -636,16 +624,11 @@ void CClouds::Render_MaybeRenderStreaks() { RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDSRCALPHA)); RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDINVSRCALPHA)); -#ifdef NOTSA_DEBUG - if (!s_DebugSettings.Rainbow.Enabled) { + if (!s_DebugSettings.Streaks.Enabled) { return; } -#endif -#ifdef NOTSA_DEBUG - if (!s_DebugSettings.Rainbow.Force) -#endif - { + if (!s_DebugSettings.Streaks.Force) { if (CClock::GetGameClockHours() >= 5) { return; } From 1665203381f09fff5d568327ff32787e6c7b4f17 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Thu, 11 May 2023 21:47:38 +0200 Subject: [PATCH 07/15] Add and use `CPlaceable::GetRoll` --- source/game_sa/Clouds.cpp | 10 +--------- source/game_sa/Entity/Placeable.cpp | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index 777fec1494..50b5c87bc5 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -526,15 +526,7 @@ void CClouds::Render_RenderLowClouds(float colorBalance) { RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCloudTex))); // Calculate camera roll - ms_cameraRoll = [&] { - const auto cmat = TheCamera.m_matrix; - if (!cmat) { - return 0.f; - } - const auto& right = cmat->GetRight(); - const auto xymag = CVector2D{ right }.SquaredMagnitude(); - return std::atan2(right.z, cmat->GetUp().z < 0.f ? -xymag : xymag); - }(); + ms_cameraRoll = TheCamera.GetRoll(); const auto camPos = TheCamera.GetPosition(); for (auto i = 0u; i < NUM_LOW_CLOUDS; i++) { diff --git a/source/game_sa/Entity/Placeable.cpp b/source/game_sa/Entity/Placeable.cpp index fd463d720b..61576df180 100644 --- a/source/game_sa/Entity/Placeable.cpp +++ b/source/game_sa/Entity/Placeable.cpp @@ -17,6 +17,7 @@ void CPlaceable::InjectHooks() { RH_ScopedOverloadedInstall(SetOrientation, "xyz", 0x439A80, void(CPlaceable::*)(float, float, float)); RH_ScopedInstall(SetHeading, 0x43E0C0); RH_ScopedInstall(GetHeading, 0x441DB0); + RH_ScopedInstall(GetRoll, 0x420B30); RH_ScopedOverloadedInstall(IsWithinArea, "xy", 0x54F200, bool(CPlaceable::*)(float, float, float, float) const); RH_ScopedOverloadedInstall(IsWithinArea, "xyz", 0x54F2B0, bool(CPlaceable::*)(float, float, float, float, float, float) const); RH_ScopedInstall(RemoveMatrix, 0x54F3B0); @@ -89,11 +90,23 @@ void CPlaceable::SetHeading(float heading) { } float CPlaceable::GetHeading() { - if (!m_matrix) + if (!m_matrix) { return m_placement.m_fHeading; + } - const auto& vecForward = m_matrix->GetForward(); - return std::atan2(-vecForward.x, vecForward.y); + const auto& fwd = m_matrix->GetForward(); + return std::atan2(-fwd.x, fwd.y); +} + +// 0x420B30 +float CPlaceable::GetRoll() const { + if (!m_matrix) { + return 0.f; + } + + const auto& right = m_matrix->GetRight(); + const auto xymag = CVector2D{ right }.SquaredMagnitude(); // NOTE: We're using sqmag here because it doesn't matter, and we save a sqrt this way. + return std::atan2(right.z, m_matrix->GetUp().z < 0.f ? -xymag : xymag); } bool CPlaceable::IsWithinArea(float x1, float y1, float x2, float y2) const { From c104f4a0eb43c8d021debc61daa3b72185dfef20 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 28 May 2023 11:04:37 +0200 Subject: [PATCH 08/15] Possibly fix bug in `Render_MaybeRenderStreaks` that caused the streaks to be rendered horizontally, instead of vertically --- source/game_sa/Clouds.cpp | 34 +++++++++++++++++++++++-------- source/game_sa/Entity/Placeable.h | 1 + 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index 50b5c87bc5..ab3eb0b3eb 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -528,6 +528,7 @@ void CClouds::Render_RenderLowClouds(float colorBalance) { // Calculate camera roll ms_cameraRoll = TheCamera.GetRoll(); + // Render clouds const auto camPos = TheCamera.GetPosition(); for (auto i = 0u; i < NUM_LOW_CLOUDS; i++) { // Offset from camera @@ -621,11 +622,10 @@ void CClouds::Render_MaybeRenderStreaks() { } if (!s_DebugSettings.Streaks.Force) { - if (CClock::GetGameClockHours() >= 5) { + if (CClock::GetGameClockHours() >= 5) { // Time is between 0 and 5 AM return; } - - if (!IsExtraSunny(CWeather::OldWeatherType) && !IsExtraSunny(CWeather::NewWeatherType)) { + if (!IsExtraSunny(CWeather::OldWeatherType) || !IsExtraSunny(CWeather::NewWeatherType)) { // Both weathers must be extra sunny return; } } @@ -636,19 +636,20 @@ void CClouds::Render_MaybeRenderStreaks() { return; } - const auto repeatIdx = CTimer::GetTimeInMS() / REPEAT_INTERVAL_MS; + const auto timeMs = CTimer::GetTimeInMS(); + const auto repeat64 = (timeMs / REPEAT_INTERVAL_MS) % 64; //> 0x714464 const auto size = CVector{ - (float)(repeatIdx % 64 % 7 - 3) * 0.1f, - (float)(repeatIdx - 4) * 0.1f, + (float)(repeat64 % 7 - 3) * 0.1f, + (float)((timeMs & 0xFFFF) / REPEAT_INTERVAL_MS - 4) * 0.1f, 1.f }.Normalized(); //> 0x7144C7 const auto offsetDir = CVector{ - (float)(repeatIdx % 64 % 9 - 5), - (float)(repeatIdx % 64 % 10 - 5), + (float)(repeat64 % 9 - 5), + (float)(repeat64 % 10 - 5), 0.1f }.Normalized(); @@ -856,7 +857,22 @@ void CClouds::RenderSkyPolys() { // 0x7154B0 void CClouds::RenderBottomFromHeight() { - plugin::Call<0x7154B0>(); + const auto camPos = TheCamera.GetPosition(); + if (camPos.z < -90.f) { // 0x71557D + return; + } + + const auto& cc = CTimeCycle::m_CurrentColours; + const auto ClampClr = [](float clr) { + return (uint8)std::min(255.f, clr); + }; + const auto fcClr = CRGBA{ + ClampClr(cc.m_nFluffyCloudsBottomRed * 2.f + 20.f), + ClampClr(cc.m_nFluffyCloudsBottomGreen * 1.5f), + ClampClr(cc.m_nFluffyCloudsBottomBlue * 1.5f), + 255 + }; + } // diff --git a/source/game_sa/Entity/Placeable.h b/source/game_sa/Entity/Placeable.h index bf572d7b7a..59d996293b 100644 --- a/source/game_sa/Entity/Placeable.h +++ b/source/game_sa/Entity/Placeable.h @@ -40,6 +40,7 @@ class CPlaceable { void GetOrientation(float& x, float& y, float& z); void SetHeading(float heading); float GetHeading(); + float GetRoll() const; bool IsWithinArea(float x1, float y1, float x2, float y2) const; bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2) const; void RemoveMatrix(); From 23463ef0abc8755db4e64fe0b821a2014fb8f619 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 28 May 2023 12:50:07 +0200 Subject: [PATCH 09/15] Add Python script to format garbage RwRenderStateSet calls to be nice --- contrib/clean-srs-calls.py | 124 +++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 contrib/clean-srs-calls.py diff --git a/contrib/clean-srs-calls.py b/contrib/clean-srs-calls.py new file mode 100644 index 0000000000..8eb8d47aa1 --- /dev/null +++ b/contrib/clean-srs-calls.py @@ -0,0 +1,124 @@ +""" +Python script to format garbage RwRenderStateSet calls to be nice +Make sure to copy the garbage looking code to the clipboard, then run the program +And the output will be set on the clipboard. +When pasting to VS make sure to press CTRL Z once, because it automatically gets formatted incorrectly +""" + +import pyperclip as pyc # If the program fails here, please run `pip install pyperclip` +from typing import Type +import re +from enum import Enum + +def cint(val : str): # C-style int + return int(val.rstrip('u')) + +def cenum(enum_type : Type[Enum]): # enum cast + return lambda val: enum_type(cint(val)).name + +def cbool(val : str): # c-style capitalized bool [TRUE, FALSE] + return str(bool(val)).upper() + +# +# RW renderstate enums +# + +class RwTextureAddressMode(Enum): + rwTEXTUREADDRESSNATEXTUREADDRESS = 0 + rwTEXTUREADDRESSWRAP = 1 + rwTEXTUREADDRESSMIRROR = 2 + rwTEXTUREADDRESSCLAMP = 3 + rwTEXTUREADDRESSBORDER = 4 + +class RwBlendFunction(Enum): + rwBLENDNABLEND = 0 + rwBLENDZERO = 1 + rwBLENDONE = 2 + rwBLENDSRCCOLOR = 3 + rwBLENDINVSRCCOLOR = 4 + rwBLENDSRCALPHA = 5 + rwBLENDINVSRCALPHA = 6 + rwBLENDDESTALPHA = 7 + rwBLENDINVDESTALPHA = 8 + rwBLENDDESTCOLOR = 9 + rwBLENDINVDESTCOLOR = 10 + rwBLENDSRCALPHASAT = 11 + +class RwAlphaTestFunction(Enum): + rwALPHATESTFUNCTIONNAALPHATESTFUNCTION = 0 + rwALPHATESTFUNCTIONNEVER = 1 + rwALPHATESTFUNCTIONLESS = 2 + rwALPHATESTFUNCTIONEQUAL = 3 + rwALPHATESTFUNCTIONLESSEQUAL = 4 + rwALPHATESTFUNCTIONGREATER = 5 + rwALPHATESTFUNCTIONNOTEQUAL = 6 + rwALPHATESTFUNCTIONGREATEREQUAL = 7 + rwALPHATESTFUNCTIONALWAYS = 8 + + +# Render state to type mapping +RwRenderState_To_Type = { + # None - Not yet implemented + # Any other type means that the value has to be of that type + + 'rwRENDERSTATENARENDERSTATE': cint, + 'rwRENDERSTATETEXTURERASTER': str, # pointer in reality + 'rwRENDERSTATETEXTUREADDRESS': cenum(RwTextureAddressMode), + 'rwRENDERSTATETEXTUREADDRESSU': cenum(RwTextureAddressMode), + 'rwRENDERSTATETEXTUREADDRESSV': cenum(RwTextureAddressMode), + 'rwRENDERSTATETEXTUREPERSPECTIVE': None, + 'rwRENDERSTATEZTESTENABLE': cbool, + 'rwRENDERSTATESHADEMODE': None, + 'rwRENDERSTATEZWRITEENABLE': cbool, + 'rwRENDERSTATETEXTUREFILTER': None, + 'rwRENDERSTATESRCBLEND': cenum(RwBlendFunction), + 'rwRENDERSTATEDESTBLEND': cenum(RwBlendFunction), + 'rwRENDERSTATEVERTEXALPHAENABLE': cbool, + 'rwRENDERSTATEBORDERCOLOR': cint, + 'rwRENDERSTATEFOGENABLE': cbool, + 'rwRENDERSTATEFOGCOLOR': cbool, + 'rwRENDERSTATEFOGTYPE': None, + 'rwRENDERSTATEFOGDENSITY': int, + 'rwRENDERSTATECULLMODE': None, + 'rwRENDERSTATESTENCILENABLE': cbool, + 'rwRENDERSTATESTENCILFAIL': None, + 'rwRENDERSTATESTENCILZFAIL': None, + 'rwRENDERSTATESTENCILPASS': None, + 'rwRENDERSTATESTENCILFUNCTION': None, + 'rwRENDERSTATESTENCILFUNCTIONREF': str, + 'rwRENDERSTATESTENCILFUNCTIONMASK': None, + 'rwRENDERSTATESTENCILFUNCTIONWRITEMASK': None, + 'rwRENDERSTATEALPHATESTFUNCTION': cenum(RwAlphaTestFunction), + 'rwRENDERSTATEALPHATESTFUNCTIONREF': None, +} + +input("Make sure to have copied the code to the clipboard!") + +# Example user input +# RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATEZWRITEENABLE, 0); +# RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATEZTESTENABLE, 1u); +# RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, 1u); +# RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATEFOGENABLE, 0); +# RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATESRCBLEND, 5u); +# RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATEDESTBLEND, 6u); +# RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATETEXTURERASTER, (unsigned int)gpCloudMaskTex->raster); + +# Tuples of (state_name, state_value); [Ex.: ("rwRENDERSTATEZWRITEENABLE", "0")] +input_values : list[tuple[str, str]] = [ + re.search(r'\((\w+), (.+)\)', line).groups() + for line in pyc.paste().splitlines() +] + +# Find longest name +longest = max(len(n) for (n, v) in input_values) + +# Format it +output = [] +for n, v in input_values: + value_type = RwRenderState_To_Type[n] + if value_type is None: + raise NotImplementedError(f'Value type for state {n} is not yet implemented!') + output.append( + f'RwRenderStateSet({n}, {" " * (longest - len(n))}RWRSTATE({value_type(v)}));' + ) +pyc.copy('\n'.join(output)) From 548d0b7eca7203454c2754afabcd1629b5f1515d Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 4 Jun 2023 21:13:41 +0200 Subject: [PATCH 10/15] Fix `Render_MaybeRenderStreaks` - For real now... --- source/game_sa/Clouds.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index ab3eb0b3eb..ba508f05ce 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -610,8 +610,8 @@ void CClouds::Render_MaybeRenderRainbows() { // From `CClouds::Render` [0x714387 - 0x714640] void CClouds::Render_MaybeRenderStreaks() { - constexpr auto REPEAT_INTERVAL_MS = 8192; // Use power-of-2 numbers here if possible - constexpr auto VISIBILE_TIME_MS = 800; + constexpr auto REPEAT_INTERVAL_MS = 8192u; // Use power-of-2 numbers here if possible + constexpr auto VISIBILE_TIME_MS = 800u; static_assert(REPEAT_INTERVAL_MS >= VISIBILE_TIME_MS); RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDSRCALPHA)); @@ -630,47 +630,47 @@ void CClouds::Render_MaybeRenderStreaks() { } } + const auto timeMS = CTimer::GetTimeInMS(); + // This must always be checked, otherwise code breaks - const auto repeatDelta = CTimer::GetTimeInMS() % REPEAT_INTERVAL_MS; + const auto repeatDelta = timeMS % REPEAT_INTERVAL_MS; if (repeatDelta >= VISIBILE_TIME_MS) { return; } - const auto timeMs = CTimer::GetTimeInMS(); - const auto repeat64 = (timeMs / REPEAT_INTERVAL_MS) % 64; + const auto repeat64 = (timeMS / REPEAT_INTERVAL_MS) % 64; //> 0x714464 const auto size = CVector{ - (float)(repeat64 % 7 - 3) * 0.1f, - (float)((timeMs & 0xFFFF) / REPEAT_INTERVAL_MS - 4) * 0.1f, + (float)((int32)(repeat64 % 7) - 3) * 0.1f, + (float)((int32)((timeMS & 0xFFFF) / REPEAT_INTERVAL_MS) - 4) * 0.1f, 1.f }.Normalized(); //> 0x7144C7 const auto offsetDir = CVector{ - (float)(repeat64 % 9 - 5), - (float)(repeat64 % 10 - 5), + (float)((int32)(repeat64 % 9) - 5), + (float)((int32)(repeat64 % 10) - 5), 0.1f }.Normalized(); - const auto basePos = offsetDir * 1000.f + TheCamera.GetPosition(); - - const auto v0Scale = (float)((VISIBILE_TIME_MS / 2 - repeatDelta) * 2); - const auto v1Scale = v0Scale + 50.f; - RenderBuffer::ClearRenderBuffer(); - const auto PushVertex = [=](float scale, CRGBA color) { + const auto PushVertex = [ + basePos = offsetDir * 1000.f + TheCamera.GetPosition(), + size + ](float scale, CRGBA color) { RenderBuffer::PushVertex( basePos + size * scale, color ); }; - PushVertex(v0Scale, { 255, 255, 255, 225 }); - PushVertex(v1Scale, { 255, 255, 255, 0 }); + const auto scale = (float)((VISIBILE_TIME_MS / 2 - (int32)repeatDelta) * 2); + PushVertex(scale, { 255, 255, 255, 225 }); + PushVertex(scale + 50.f, { 255, 255, 255, 0 }); - RenderBuffer::PushIndices({ 0, 1 }, true); + RenderBuffer::PushIndices({ 1, 0 }, false); RenderBuffer::Render(rwPRIMTYPEPOLYLINE, nullptr, rwIM3D_VERTEXRGBA | rwIM3D_VERTEXXYZ); } From c3755d847be9ac8658faf4ecb3b813a2b754d7fe Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 4 Jun 2023 21:14:46 +0200 Subject: [PATCH 11/15] Finish --- source/game_sa/Clouds.cpp | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index ba508f05ce..5ca99a1f9d 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -24,8 +24,6 @@ RwTexture*& gpMoonMask = *reinterpret_cast(0xC6AA74); RwTexture*& gpCloudTex = *reinterpret_cast(0xC6AA78); RwTexture*& gpCloudMaskTex = *reinterpret_cast(0xC6AA78 + 0x4); -float& flt_C6E954 = *reinterpret_cast(0xC6E954); // see CClouds::RenderBottomFromHeight, CClouds::MovingFogRender - void CClouds::InjectHooks() { RH_ScopedClass(CClouds); RH_ScopedCategoryGlobal(); @@ -857,22 +855,41 @@ void CClouds::RenderSkyPolys() { // 0x7154B0 void CClouds::RenderBottomFromHeight() { + /**** + * Code below should be good + * but it isn't complete... + *****\ + const auto camPos = TheCamera.GetPosition(); - if (camPos.z < -90.f) { // 0x71557D + if (camPos.z < -90.f) { // 0x71557D [Moved up here] return; } - const auto& cc = CTimeCycle::m_CurrentColours; + const auto& cc = CTimeCycle::m_CurrentColours; // cc = color component const auto ClampClr = [](float clr) { - return (uint8)std::min(255.f, clr); + return std::min(clr, 255.f); }; - const auto fcClr = CRGBA{ - ClampClr(cc.m_nFluffyCloudsBottomRed * 2.f + 20.f), - ClampClr(cc.m_nFluffyCloudsBottomGreen * 1.5f), - ClampClr(cc.m_nFluffyCloudsBottomBlue * 1.5f), - 255 + const auto fcClr = CRGBA{ // fc = fluffy clouds + (uint8)ClampClr(cc.m_nFluffyCloudsBottomRed * 2.f + 20.f), + (uint8)ClampClr(cc.m_nFluffyCloudsBottomGreen * 1.5f), + (uint8)ClampClr(cc.m_nFluffyCloudsBottomBlue * 1.5f), + (uint8)255 }; + auto lowZ = 160.f, highZ = 190.f; + + auto& windShift = StaticRef(); + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, RWRSTATE(TRUE)); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, RWRSTATE(TRUE)); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, RWRSTATE(TRUE)); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, RWRSTATE(TRUE)); + RwRenderStateSet(rwRENDERSTATESRCBLEND, RWRSTATE(rwBLENDSRCALPHA)); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, RWRSTATE(rwBLENDINVSRCALPHA)); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(gpCloudMaskTex))); + + // TODO.... + */ } // From 1b69ae6df3097451116083106a66e2ef1460b750 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Mon, 17 Jul 2023 00:08:48 +0200 Subject: [PATCH 12/15] Fix the build --- source/game_sa/Clouds.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index a3c2762535..9a27df5d87 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -477,8 +477,8 @@ void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { starSizeScr *= STARS_SIZES[posIdx] * 0.8f; CSprite::RenderBufferedOneXLUSprite( - starPosScr.x, starPosScr.y, starPosScr.z, - starSizeScr.x, starSizeScr.y, + starPosScr, + starSizeScr, cc, cc, cc, 255, 1.f / starPosScr.z, 255 @@ -496,8 +496,8 @@ void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { lastStarSizeScr *= 5.f; CSprite::RenderBufferedOneXLUSprite( - lastStarPosScr.x, lastStarPosScr.y, lastStarPosScr.z, - lastStarSizeScr.x, lastStarSizeScr.y, + lastStarPosScr, + lastStarSizeScr, cc, cc, cc, 255, 1.f / lastStarPosScr.z, 255 @@ -596,8 +596,8 @@ void CClouds::Render_MaybeRenderRainbows() { rblineSizeScr *= CVector2D{ 2.f, 50.f }; CSprite::RenderBufferedOneXLUSprite( - rblinePosScr.x, rblinePosScr.y, rblinePosScr.z, - rblineSizeScr.x, rblineSizeScr.y, + rblinePosScr, + rblineSizeScr, (uint8)((float)RAINBOW_LINES_COLOR_RED[i] * CWeather::Rainbow), (uint8)((float)RAINBOW_LINES_COLOR_GREEN[i] * CWeather::Rainbow), (uint8)((float)RAINBOW_LINES_COLOR_BLUE[i] * CWeather::Rainbow), From 2b13bebc81b49743e969762aa4a36644ac7f3ef8 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Mon, 17 Jul 2023 00:29:28 +0200 Subject: [PATCH 13/15] Refactor code [apply some suggestions] --- source/game_sa/Clouds.cpp | 53 ++++++++++++++++++++++----------------- source/game_sa/Sprite.cpp | 5 ++-- source/game_sa/Sprite.h | 2 +- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index 9a27df5d87..1a3578c65d 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -512,10 +512,20 @@ void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { // From `CClouds::Render` [0x714019 - 0x71422A] void CClouds::Render_RenderLowClouds(float colorBalance) { - constexpr size_t NUM_LOW_CLOUDS = 12u; - constexpr float LOW_CLOUDS_X_COORDS[NUM_LOW_CLOUDS]{ 1.0f, 0.7f, 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, 0.8f, -0.8f, 0.4f, 0.4f }; // 0x8D5394 - constexpr float LOW_CLOUDS_Y_COORDS[NUM_LOW_CLOUDS]{ 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, 1.0f, 0.7f, 0.4f, 0.4f, -0.8f, -0.8f }; // 0x8D53C4 - constexpr float LOW_CLOUDS_Z_COORDS[NUM_LOW_CLOUDS]{ 0.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.3f, 0.9f, 0.4f, 1.3f, 1.4f, 1.2f, 1.7f }; // 0x8D53F4 + constexpr CVector LOW_CLOUDS_COORDS[]{ + {1.0f, 0.0f, 0.0f}, + {0.7f, -0.7f, 1.0f}, + {0.0f, -1.0f, 0.5f}, + {-0.7f, -0.7f, 0.0f}, + {-1.0f, 0.0f, 1.0f}, + {-0.7f, 0.7f, 0.3f}, + {0.0f, 1.0f, 0.9f}, + {0.7f, 0.7f, 0.4f}, + {0.8f, 0.4f, 1.3f}, + {-0.8f, 0.4f, 1.4f}, + {0.4f, -0.8f, 1.2f}, + {0.4f, -0.8f, 1.7f}, + }; const auto colorR = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsRed, colorBalance); const auto colorG = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsGreen, colorBalance); @@ -532,24 +542,15 @@ void CClouds::Render_RenderLowClouds(float colorBalance) { // Render clouds const auto camPos = TheCamera.GetPosition(); - for (auto i = 0u; i < NUM_LOW_CLOUDS; i++) { - // Offset from camera - const auto offset = CVector{ - LOW_CLOUDS_X_COORDS[i] * 800.f, - LOW_CLOUDS_Y_COORDS[i] * 800.f, - LOW_CLOUDS_Z_COORDS[i] * 60.f + 40.f - }; - + for (const auto& offset : LOW_CLOUDS_COORDS) { CVector cloudPosScr; CVector2D cloudSizeScr; if (!CSprite::CalcScreenCoors(camPos + offset, &cloudPosScr, &cloudSizeScr.x, &cloudSizeScr.y, false, true)) { continue; } - cloudSizeScr *= CVector2D{ 40.f, 320.f }; - CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension( - cloudPosScr.x, cloudPosScr.y, cloudPosScr.z, - cloudSizeScr.x, cloudSizeScr.y, + cloudPosScr, + cloudSizeScr * CVector2D{ 40.f, 320.f }, colorR, colorG, colorB, 255, 1.f / cloudPosScr.z, ms_cameraRoll, @@ -563,9 +564,14 @@ void CClouds::Render_RenderLowClouds(float colorBalance) { // From `CClouds::Render` [0x71422A - 0x714387] void CClouds::Render_MaybeRenderRainbows() { constexpr size_t NUM_RAINBOW_LINES = 6; - constexpr uint8 RAINBOW_LINES_COLOR_RED[NUM_RAINBOW_LINES]{ 30, 30, 30, 10, 0, 15 }; - constexpr uint8 RAINBOW_LINES_COLOR_GREEN[NUM_RAINBOW_LINES]{ 0, 15, 30, 30, 0, 0 }; - constexpr uint8 RAINBOW_LINES_COLOR_BLUE[NUM_RAINBOW_LINES]{ 0, 0, 0, 10, 30, 30 }; + const CRGBA RAINBOW_LINES_COLOR[]{ + {30, 0, 0, 255}, + {30, 15, 0, 255}, + {30, 30, 0, 255}, + {10, 30, 10, 255}, + {0, 0, 30, 255}, + {15, 0, 30, 255} + }; if (!s_DebugSettings.Rainbow.Enabled) { return; @@ -595,13 +601,14 @@ void CClouds::Render_MaybeRenderRainbows() { } rblineSizeScr *= CVector2D{ 2.f, 50.f }; + const auto& clr = RAINBOW_LINES_COLOR[i]; CSprite::RenderBufferedOneXLUSprite( rblinePosScr, rblineSizeScr, - (uint8)((float)RAINBOW_LINES_COLOR_RED[i] * CWeather::Rainbow), - (uint8)((float)RAINBOW_LINES_COLOR_GREEN[i] * CWeather::Rainbow), - (uint8)((float)RAINBOW_LINES_COLOR_BLUE[i] * CWeather::Rainbow), - 255, + (uint8)((float)clr.r * CWeather::Rainbow), + (uint8)((float)clr.g * CWeather::Rainbow), + (uint8)((float)clr.b * CWeather::Rainbow), + clr.a, 1.f / rblinePosScr.z, 255 ); diff --git a/source/game_sa/Sprite.cpp b/source/game_sa/Sprite.cpp index b00307d6ac..e668e45792 100644 --- a/source/game_sa/Sprite.cpp +++ b/source/game_sa/Sprite.cpp @@ -157,9 +157,8 @@ void CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect(float x, float y, float z plugin::Call<0x70E780, float, float, float, float, float, uint8, uint8, uint8, int16, float, float, uint8>(x, y, z, w, h, r, g, b, intensity, recipNearZ, angle, a12); } -// 0x70EAB0 -void CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(float, float, float, float, float, uint8, uint8, uint8, int16, float, float, uint8) { - assert(false); +void CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(CVector pos, CVector2D size, uint8 r, uint8 g, uint8 b, int16 intensity, float rz, float rotation, uint8 a) { + plugin::Call<0x70EAB0>(pos, size, r, g, b, intensity, rz, rotation, a); } // 0x70EDE0 diff --git a/source/game_sa/Sprite.h b/source/game_sa/Sprite.h index a705bdc19c..1116b8d84f 100644 --- a/source/game_sa/Sprite.h +++ b/source/game_sa/Sprite.h @@ -41,7 +41,7 @@ class CSprite { static void RenderBufferedOneXLUSprite(CVector pos, CVector2D size, uint8 r, uint8 g, uint8 b, int16 intensity, float recipNearZ, uint8 a11); static void RenderBufferedOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intensity, float recipNearZ, float angle, uint8 a12); - static void RenderBufferedOneXLUSprite_Rotate_Dimension(float, float, float, float, float, uint8, uint8, uint8, int16, float, float, uint8); + static void RenderBufferedOneXLUSprite_Rotate_Dimension(CVector pos, CVector2D size, uint8 r, uint8 g, uint8 b, int16 intensity, float rz, float rotation, uint8 a); static void RenderBufferedOneXLUSprite_Rotate_2Colours(float, float, float, float, float, uint8, uint8, uint8, uint8, uint8, uint8, float, float, float, float, uint8); static void RenderBufferedOneXLUSprite2D(CVector2D pos, CVector2D size, const RwRGBA& color, int16 intensity, uint8 alpha); static void RenderBufferedOneXLUSprite2D_Rotate_Dimension(float, float, float, float, const RwRGBA&, int16, float, uint8); From b49d0de6c19a3313e6a45866f6f9d522063f4d8f Mon Sep 17 00:00:00 2001 From: Pirulax Date: Mon, 17 Jul 2023 00:34:25 +0200 Subject: [PATCH 14/15] Fix the build --- source/game_sa/Clouds.cpp | 14 +++++++------- source/game_sa/Hud.cpp | 19 ++++++++++++++----- source/game_sa/Sprite.cpp | 4 ++-- source/game_sa/Sprite.h | 2 +- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index 1a3578c65d..f9f6f6b8ee 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -362,8 +362,8 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { const auto moonSz = scrSize * ((float)CCoronas::MoonSize * 2.f + 4.f); CSprite::RenderOneXLUSprite( - moonPosScr.x, moonPosScr.y, z, - moonSz.x, moonSz.y, + { moonPosScr.x, moonPosScr.y, z }, + moonSz, 0, 0, 0, 255, rhw, 255, @@ -384,9 +384,9 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { 5.4f * (((float)CClock::GetGameClockDays() / 31.f - 0.5f)) // Slowly glide on the X axis according to current game day }; CSprite::RenderOneXLUSprite( - moonMaskPosScr.x, moonMaskPosScr.y, z, - moonMaskSz.x, moonMaskSz.y, - 0, 0, 0, 0, // NOTE/TODO: Alpha 0? + { moonMaskPosScr.x, moonMaskPosScr.y, z }, + moonMaskSz, + 0, 0, 0, 0, rhw, 255, 0, @@ -402,8 +402,8 @@ void CClouds::Render_MaybeRenderMoon(float colorBalance) { RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, RWRSTATE(FALSE)); CSprite::RenderOneXLUSprite( - moonPosScr.x, moonPosScr.y, z, - moonSz.x, moonSz.y, + { moonPosScr.x, moonPosScr.y, z }, + moonSz, colorRG, colorRG, (uint8)((float)colorB * 0.85f), 255, rhw, 255, diff --git a/source/game_sa/Hud.cpp b/source/game_sa/Hud.cpp index d4fccbfd81..1918fa8253 100644 --- a/source/game_sa/Hud.cpp +++ b/source/game_sa/Hud.cpp @@ -788,10 +788,12 @@ void CHud::DrawCrossHairs() { const auto RenderOneXLUSprite = [=](float x, float y, auto u, auto v) { CSprite::RenderOneXLUSprite( - x, y, - 1.0f, - screenStretchCrossHairX / 2.0f, screenStretchCrossHairY / 2.0f, - 255, 255, 255, 255, 0.01f, 255, u, v + { x, y, 1.0f } , + { screenStretchCrossHairX / 2.0f, screenStretchCrossHairY / 2.0f }, + 255, 255, 255, 255, + 0.01f, + 255, + u, v ); }; @@ -1574,7 +1576,14 @@ void CHud::DrawWeaponIcon(CPed* ped, int32 x, int32 y, float alpha) { RwRenderStateSet(rwRENDERSTATEZTESTENABLE, RWRSTATE(NULL)); RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RWRSTATE(RwTextureGetRaster(texture))); - CSprite::RenderOneXLUSprite(x0 + halfWidth, y0 + halfHeight, 1.0f, halfWidth, halfHeight, 255u, 255u, 255u, 255, 1.0f, 255, 0, 0); + CSprite::RenderOneXLUSprite( + { x0 + halfWidth, y0 + halfHeight, 1.0f }, + { halfWidth, halfHeight }, + 255u, 255u, 255u, 255, + 1.0f, + 255, + 0, 0 + ); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, RWRSTATE(FALSE)); } diff --git a/source/game_sa/Sprite.cpp b/source/game_sa/Sprite.cpp index e668e45792..7d4d8fe8de 100644 --- a/source/game_sa/Sprite.cpp +++ b/source/game_sa/Sprite.cpp @@ -110,8 +110,8 @@ void CSprite::Set4Vertices2D(RwD3D9Vertex*, float, float, float, float, float, f /* --- XLU Sprite --- */ // 0x70D000 -void CSprite::RenderOneXLUSprite(float x, float y, float z, float halfWidth, float halfHeight, uint8 r, uint8 g, uint8 b, int16 a, float rhw, uint8 intensity, uint8 udir, uint8 vdir) { - plugin::Call<0x70D000, float, float, float, float, float, uint8, uint8, uint8, int16, float, uint8, uint8, uint8>(x, y, z, halfWidth, halfHeight, r, g, b, a, rhw, intensity, udir, vdir); +void CSprite::RenderOneXLUSprite(CVector pos, CVector2D halfSize, uint8 r, uint8 g, uint8 b, int16 intensity, float rhw, uint8 a, uint8 udir, uint8 vdir) { + plugin::Call<0x70D000>(pos, halfSize, r, g, b, intensity, rhw, a, udir, vdir); } // 0x70D320 diff --git a/source/game_sa/Sprite.h b/source/game_sa/Sprite.h index 1116b8d84f..585e2dcb7c 100644 --- a/source/game_sa/Sprite.h +++ b/source/game_sa/Sprite.h @@ -31,7 +31,7 @@ class CSprite { static void Set4Vertices2D(RwD3D9Vertex*, const CRect&, const CRGBA&, const CRGBA&, const CRGBA&, const CRGBA&); static void Set4Vertices2D(RwD3D9Vertex*, float, float, float, float, float, float, float, float, const CRGBA&, const CRGBA&, const CRGBA&, const CRGBA&); - static void RenderOneXLUSprite(float x, float y, float z, float halfWidth, float halfHeight, uint8 r, uint8 g, uint8 b, int16 a, float rhw, uint8 intensity, uint8 udir, uint8 vdir); + static void RenderOneXLUSprite(CVector pos, CVector2D halfSize, uint8 r, uint8 g, uint8 b, int16 intensity, float rhw, uint8 a, uint8 udir, uint8 vdir); static void RenderOneXLUSprite_Triangle(float, float, float, float, float, float, float, uint8, uint8, uint8, int16, float, uint8); static void RenderOneXLUSprite_Rotate_Aspect(CVector pos, CVector2D size, uint8 r, uint8 g, uint8 b, int16 intensity, float rz, float rotation, uint8 alpha); static void RenderOneXLUSprite_Rotate_Dimension(float, float, float, float, float, uint8, uint8, uint8, int16, float, float, uint8); From 73c1e8e2bd20d39d92e0a72e7d7743c2f9089cb5 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Mon, 17 Jul 2023 00:36:14 +0200 Subject: [PATCH 15/15] Fix broken code --- source/game_sa/Clouds.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/game_sa/Clouds.cpp b/source/game_sa/Clouds.cpp index f9f6f6b8ee..39279bf3e5 100644 --- a/source/game_sa/Clouds.cpp +++ b/source/game_sa/Clouds.cpp @@ -513,18 +513,18 @@ void CClouds::Render_MaybeRenderRockstarLogo(float colorBalance) { // From `CClouds::Render` [0x714019 - 0x71422A] void CClouds::Render_RenderLowClouds(float colorBalance) { constexpr CVector LOW_CLOUDS_COORDS[]{ - {1.0f, 0.0f, 0.0f}, - {0.7f, -0.7f, 1.0f}, - {0.0f, -1.0f, 0.5f}, + {1.0f, 0.0f, 0.0f}, + {0.7f, -0.7f, 1.0f}, + {0.0f, -1.0f, 0.5f}, {-0.7f, -0.7f, 0.0f}, - {-1.0f, 0.0f, 1.0f}, - {-0.7f, 0.7f, 0.3f}, - {0.0f, 1.0f, 0.9f}, - {0.7f, 0.7f, 0.4f}, - {0.8f, 0.4f, 1.3f}, - {-0.8f, 0.4f, 1.4f}, - {0.4f, -0.8f, 1.2f}, - {0.4f, -0.8f, 1.7f}, + {-1.0f, 0.0f, 1.0f}, + {-0.7f, 0.7f, 0.3f}, + {0.0f, 1.0f, 0.9f}, + {0.7f, 0.7f, 0.4f}, + {0.8f, 0.4f, 1.3f}, + {-0.8f, 0.4f, 1.4f}, + {0.4f, -0.8f, 1.2f}, + {0.4f, -0.8f, 1.7f}, }; const auto colorR = CalculateColorWithBalance((uint8)CTimeCycle::m_CurrentColours.m_nLowCloudsRed, colorBalance); @@ -545,7 +545,7 @@ void CClouds::Render_RenderLowClouds(float colorBalance) { for (const auto& offset : LOW_CLOUDS_COORDS) { CVector cloudPosScr; CVector2D cloudSizeScr; - if (!CSprite::CalcScreenCoors(camPos + offset, &cloudPosScr, &cloudSizeScr.x, &cloudSizeScr.y, false, true)) { + if (!CSprite::CalcScreenCoors(camPos + offset * CVector{800.f, 800.f, 60.f} + CVector{0.f, 0.f, 40.f}, &cloudPosScr, &cloudSizeScr.x, &cloudSizeScr.y, false, true)) { continue; } CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(