This commit is contained in:
2025-12-06 17:51:54 +01:00
parent f086ed3021
commit 12110bd8b4
4 changed files with 124 additions and 22 deletions

View File

@ -26,6 +26,77 @@
#include "../graphics/renderers/GameRenderer.h"
#include <SDL3_image/SDL_image.h>
// Frosted tint helper: draw a safe, inexpensive frosted overlay for the panel area.
// This avoids renderer readback / surface APIs which aren't portable across SDL3 builds.
static void renderBackdropBlur(SDL_Renderer* renderer, const SDL_Rect& logicalVP, float logicalScale, float panelTop, float panelH, SDL_Texture* sceneTex, int sceneW, int sceneH) {
if (!renderer) return;
// If we don't have a captured scene texture, fall back to the frosted tint.
if (!sceneTex || sceneW <= 0 || sceneH <= 0) {
float viewportLogicalW = (float)logicalVP.w / logicalScale;
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 200, 210, 220, 48);
SDL_FRect base{ 0.0f, panelTop, viewportLogicalW, panelH };
SDL_RenderFillRect(renderer, &base);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 24);
SDL_FRect highlight{ 0.0f, panelTop, viewportLogicalW, std::max(2.0f, panelH * 0.06f) };
SDL_RenderFillRect(renderer, &highlight);
SDL_SetRenderDrawColor(renderer, 16, 24, 32, 12);
SDL_FRect shadow{ 0.0f, panelTop + panelH - std::max(2.0f, panelH * 0.06f), viewportLogicalW, std::max(2.0f, panelH * 0.06f) };
SDL_RenderFillRect(renderer, &shadow);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
return;
}
// Compute source rect in scene texture pixels for the panel area
int panelWinX = 0;
int panelWinY = static_cast<int>(std::floor(panelTop * logicalScale + logicalVP.y));
int panelWinW = sceneW; // full width of captured scene
int panelWinH = static_cast<int>(std::ceil(panelH * logicalScale));
if (panelWinW <= 0 || panelWinH <= 0) return;
// Downsample size (cheap Gaussian-ish blur via scale).
int blurW = std::max(8, panelWinW / 6);
int blurH = std::max(4, panelWinH / 6);
// Create a small render target to draw the downsampled region into
SDL_Texture* small = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, blurW, blurH);
if (!small) {
// Fall back to tint if we can't allocate
float viewportLogicalW = (float)logicalVP.w / logicalScale;
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 200, 210, 220, 48);
SDL_FRect base{ 0.0f, panelTop, viewportLogicalW, panelH };
SDL_RenderFillRect(renderer, &base);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
return;
}
// Source rectangle in the scene texture (pixel coords) as floats
SDL_FRect srcRectF{ (float)panelWinX, (float)panelWinY, (float)panelWinW, (float)panelWinH };
// Render the sub-region of the scene into the small texture
SDL_SetRenderTarget(renderer, small);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_FRect smallDst{ 0.0f, 0.0f, (float)blurW, (float)blurH };
SDL_RenderTexture(renderer, sceneTex, &srcRectF, &smallDst);
// Reset target
SDL_SetRenderTarget(renderer, nullptr);
// Render the small texture scaled up to the panel area with linear filtering
SDL_SetTextureBlendMode(small, SDL_BLENDMODE_BLEND);
SDL_SetTextureScaleMode(small, SDL_SCALEMODE_LINEAR);
float viewportLogicalW = (float)logicalVP.w / logicalScale;
SDL_FRect dst{ 0.0f, panelTop, viewportLogicalW, panelH };
SDL_RenderTexture(renderer, small, nullptr, &dst);
// Cleanup
SDL_DestroyTexture(small);
}
MenuState::MenuState(StateContext& ctx) : State(ctx) {}
void MenuState::onEnter() {
@ -72,6 +143,8 @@ void MenuState::renderMainButtonTop(SDL_Renderer* renderer, float logicalScale,
float spacing = isSmall ? btnW * 1.2f : btnW * 1.15f;
// Draw semi-transparent background panel behind the full button group (draw first so text sits on top)
{
float groupCenterX = btnX;
@ -81,13 +154,13 @@ void MenuState::renderMainButtonTop(SDL_Renderer* renderer, float logicalScale,
float panelTop = btnY - btnH * 0.5f - 12.0f;
float panelH = btnH + 24.0f;
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
// Backdrop blur pass before tint (use captured scene texture if available)
renderBackdropBlur(renderer, logicalVP, logicalScale, panelTop, panelH, ctx.sceneTex, ctx.sceneW, ctx.sceneH);
// Brighter, less-opaque background to increase contrast
SDL_SetRenderDrawColor(renderer, 28, 36, 46, 180);
// Fill full-width background so edges are covered in fullscreen
float viewportLogicalW = (float)logicalVP.w / logicalScale;
float fullLeft = 0.0f;
float fullW = viewportLogicalW;
SDL_FRect fullPanel{ fullLeft, panelTop, fullW, panelH };
SDL_FRect fullPanel{ 0.0f, panelTop, viewportLogicalW, panelH };
SDL_RenderFillRect(renderer, &fullPanel);
// Also draw the central strip to keep visual center emphasis
SDL_FRect panelRect{ panelLeft, panelTop, panelRight - panelLeft, panelH };
@ -95,9 +168,7 @@ void MenuState::renderMainButtonTop(SDL_Renderer* renderer, float logicalScale,
// brighter full-width border
SDL_SetRenderDrawColor(renderer, 120, 140, 160, 200);
// Expand border to cover full window width (use actual viewport)
float fullLeftTop = 0.0f;
float fullWTop = viewportLogicalW;
SDL_FRect borderFull{ fullLeftTop, panelTop, fullWTop, panelH };
SDL_FRect borderFull{ 0.0f, panelTop, viewportLogicalW, panelH };
SDL_RenderRect(renderer, &borderFull);
}
@ -792,13 +863,13 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
float panelTop = btnY - btnH * 0.5f - 12.0f;
float panelH = btnH + 24.0f;
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
// Backdrop blur pass before tint (use captured scene texture if available)
renderBackdropBlur(renderer, logicalVP, logicalScale, panelTop, panelH, ctx.sceneTex, ctx.sceneW, ctx.sceneH);
// Brighter, less-opaque background to increase contrast (match top path)
SDL_SetRenderDrawColor(renderer, 28, 36, 46, 180);
// Fill full-width background so edges are covered in fullscreen
float viewportLogicalW = (float)logicalVP.w / logicalScale;
float fullLeft = 0.0f;
float fullW = viewportLogicalW;
SDL_FRect fullPanel{ fullLeft, panelTop, fullW, panelH };
SDL_FRect fullPanel{ 0.0f, panelTop, viewportLogicalW, panelH };
SDL_RenderFillRect(renderer, &fullPanel);
// Also draw the central strip to keep visual center emphasis
SDL_FRect panelRect{ panelLeft, panelTop, panelRight - panelLeft, panelH };
@ -806,9 +877,7 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
// subtle border across full logical width
SDL_SetRenderDrawColor(renderer, 120, 140, 160, 200);
// Expand border to cover full window width (use actual viewport)
float fullLeftNormal = 0.0f;
float fullWNormal = viewportLogicalW;
SDL_FRect borderFull{ fullLeftNormal, panelTop, fullWNormal, panelH };
SDL_FRect borderFull{ 0.0f, panelTop, viewportLogicalW, panelH };
SDL_RenderRect(renderer, &borderFull);
}
// Button 0 - PLAY
@ -1048,7 +1117,9 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
SDL_FRect rc{ area.x + c * (cellW + gapX), area.y + r * (cellH + gapY), cellW, cellH };
bool hovered = (levelSelected == i) || (levelHovered == i);
bool selected = (ctx.startLevelSelection && *ctx.startLevelSelection == i);
SDL_Color fill = selected ? SDL_Color{255,140,40,160} : (hovered ? SDL_Color{60,80,100,120} : SDL_Color{30,40,60,110});
// Use the project's gold/yellow tone for selected level to match UI accents
SDL_Color selectedFill = SDL_Color{255,204,0,160};
SDL_Color fill = selected ? selectedFill : (hovered ? SDL_Color{60,80,100,120} : SDL_Color{30,40,60,110});
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, fill.r, fill.g, fill.b, fill.a);
SDL_RenderFillRect(renderer, &rc);