fixed
This commit is contained in:
@ -105,10 +105,22 @@ void SpaceWarp::spawnComet() {
|
|||||||
float shade = randomRange(0.85f, 1.0f);
|
float shade = randomRange(0.85f, 1.0f);
|
||||||
Uint8 c = static_cast<Uint8>(std::clamp(220.0f + shade * 35.0f, 0.0f, 255.0f));
|
Uint8 c = static_cast<Uint8>(std::clamp(220.0f + shade * 35.0f, 0.0f, 255.0f));
|
||||||
comet.color = SDL_Color{c, Uint8(std::min(255.0f, c * 0.95f)), 255, 255};
|
comet.color = SDL_Color{c, Uint8(std::min(255.0f, c * 0.95f)), 255, 255};
|
||||||
comet.prevScreenX = centerX;
|
// Initialize screen positions based on projection so the comet is not stuck at center
|
||||||
comet.prevScreenY = centerY;
|
float sx = 0.0f, sy = 0.0f;
|
||||||
comet.screenX = centerX;
|
if (projectPoint(comet.x, comet.y, comet.z, sx, sy)) {
|
||||||
comet.screenY = centerY;
|
comet.screenX = sx;
|
||||||
|
comet.screenY = sy;
|
||||||
|
// Place prev slightly behind the head so the first frame shows motion/trail
|
||||||
|
float jitter = std::max(4.0f, comet.trailLength * 0.08f);
|
||||||
|
float ang = randomRange(0.0f, 6.28318530718f);
|
||||||
|
comet.prevScreenX = comet.screenX - std::cos(ang) * jitter;
|
||||||
|
comet.prevScreenY = comet.screenY - std::sin(ang) * jitter;
|
||||||
|
} else {
|
||||||
|
comet.prevScreenX = centerX;
|
||||||
|
comet.prevScreenY = centerY;
|
||||||
|
comet.screenX = centerX;
|
||||||
|
comet.screenY = centerY;
|
||||||
|
}
|
||||||
comets.push_back(comet);
|
comets.push_back(comet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,10 +147,22 @@ void SpaceWarp::respawn(WarpStar& star, bool randomDepth) {
|
|||||||
static constexpr Uint8 GRAY_SHADES[] = {160, 180, 200, 220, 240};
|
static constexpr Uint8 GRAY_SHADES[] = {160, 180, 200, 220, 240};
|
||||||
int idx = randomIntInclusive(rng, 0, int(std::size(GRAY_SHADES)) - 1);
|
int idx = randomIntInclusive(rng, 0, int(std::size(GRAY_SHADES)) - 1);
|
||||||
star.baseShade = GRAY_SHADES[idx];
|
star.baseShade = GRAY_SHADES[idx];
|
||||||
star.prevScreenX = centerX;
|
// Compute initial projected screen position so newly spawned stars aren't frozen at center
|
||||||
star.prevScreenY = centerY;
|
float sx = 0.0f, sy = 0.0f;
|
||||||
star.screenX = centerX;
|
if (projectPoint(star.x, star.y, star.z, sx, sy)) {
|
||||||
star.screenY = centerY;
|
star.screenX = sx;
|
||||||
|
star.screenY = sy;
|
||||||
|
// give a small previous offset so trails and motion are visible immediately
|
||||||
|
float jitter = std::max(1.0f, settings.maxTrailLength * 0.06f);
|
||||||
|
float ang = randomRange(0.0f, 6.28318530718f);
|
||||||
|
star.prevScreenX = star.screenX - std::cos(ang) * jitter;
|
||||||
|
star.prevScreenY = star.screenY - std::sin(ang) * jitter;
|
||||||
|
} else {
|
||||||
|
star.prevScreenX = centerX;
|
||||||
|
star.prevScreenY = centerY;
|
||||||
|
star.screenX = centerX;
|
||||||
|
star.screenY = centerY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpaceWarp::project(const WarpStar& star, float& outX, float& outY) const {
|
bool SpaceWarp::project(const WarpStar& star, float& outX, float& outY) const {
|
||||||
|
|||||||
@ -26,6 +26,77 @@
|
|||||||
#include "../graphics/renderers/GameRenderer.h"
|
#include "../graphics/renderers/GameRenderer.h"
|
||||||
#include <SDL3_image/SDL_image.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) {}
|
MenuState::MenuState(StateContext& ctx) : State(ctx) {}
|
||||||
|
|
||||||
void MenuState::onEnter() {
|
void MenuState::onEnter() {
|
||||||
@ -72,6 +143,8 @@ void MenuState::renderMainButtonTop(SDL_Renderer* renderer, float logicalScale,
|
|||||||
|
|
||||||
float spacing = isSmall ? btnW * 1.2f : btnW * 1.15f;
|
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)
|
// Draw semi-transparent background panel behind the full button group (draw first so text sits on top)
|
||||||
{
|
{
|
||||||
float groupCenterX = btnX;
|
float groupCenterX = btnX;
|
||||||
@ -81,13 +154,13 @@ void MenuState::renderMainButtonTop(SDL_Renderer* renderer, float logicalScale,
|
|||||||
float panelTop = btnY - btnH * 0.5f - 12.0f;
|
float panelTop = btnY - btnH * 0.5f - 12.0f;
|
||||||
float panelH = btnH + 24.0f;
|
float panelH = btnH + 24.0f;
|
||||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
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
|
// Brighter, less-opaque background to increase contrast
|
||||||
SDL_SetRenderDrawColor(renderer, 28, 36, 46, 180);
|
SDL_SetRenderDrawColor(renderer, 28, 36, 46, 180);
|
||||||
// Fill full-width background so edges are covered in fullscreen
|
// Fill full-width background so edges are covered in fullscreen
|
||||||
float viewportLogicalW = (float)logicalVP.w / logicalScale;
|
float viewportLogicalW = (float)logicalVP.w / logicalScale;
|
||||||
float fullLeft = 0.0f;
|
SDL_FRect fullPanel{ 0.0f, panelTop, viewportLogicalW, panelH };
|
||||||
float fullW = viewportLogicalW;
|
|
||||||
SDL_FRect fullPanel{ fullLeft, panelTop, fullW, panelH };
|
|
||||||
SDL_RenderFillRect(renderer, &fullPanel);
|
SDL_RenderFillRect(renderer, &fullPanel);
|
||||||
// Also draw the central strip to keep visual center emphasis
|
// Also draw the central strip to keep visual center emphasis
|
||||||
SDL_FRect panelRect{ panelLeft, panelTop, panelRight - panelLeft, panelH };
|
SDL_FRect panelRect{ panelLeft, panelTop, panelRight - panelLeft, panelH };
|
||||||
@ -95,9 +168,7 @@ void MenuState::renderMainButtonTop(SDL_Renderer* renderer, float logicalScale,
|
|||||||
// brighter full-width border
|
// brighter full-width border
|
||||||
SDL_SetRenderDrawColor(renderer, 120, 140, 160, 200);
|
SDL_SetRenderDrawColor(renderer, 120, 140, 160, 200);
|
||||||
// Expand border to cover full window width (use actual viewport)
|
// Expand border to cover full window width (use actual viewport)
|
||||||
float fullLeftTop = 0.0f;
|
SDL_FRect borderFull{ 0.0f, panelTop, viewportLogicalW, panelH };
|
||||||
float fullWTop = viewportLogicalW;
|
|
||||||
SDL_FRect borderFull{ fullLeftTop, panelTop, fullWTop, panelH };
|
|
||||||
SDL_RenderRect(renderer, &borderFull);
|
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 panelTop = btnY - btnH * 0.5f - 12.0f;
|
||||||
float panelH = btnH + 24.0f;
|
float panelH = btnH + 24.0f;
|
||||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
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)
|
// Brighter, less-opaque background to increase contrast (match top path)
|
||||||
SDL_SetRenderDrawColor(renderer, 28, 36, 46, 180);
|
SDL_SetRenderDrawColor(renderer, 28, 36, 46, 180);
|
||||||
// Fill full-width background so edges are covered in fullscreen
|
// Fill full-width background so edges are covered in fullscreen
|
||||||
float viewportLogicalW = (float)logicalVP.w / logicalScale;
|
float viewportLogicalW = (float)logicalVP.w / logicalScale;
|
||||||
float fullLeft = 0.0f;
|
SDL_FRect fullPanel{ 0.0f, panelTop, viewportLogicalW, panelH };
|
||||||
float fullW = viewportLogicalW;
|
|
||||||
SDL_FRect fullPanel{ fullLeft, panelTop, fullW, panelH };
|
|
||||||
SDL_RenderFillRect(renderer, &fullPanel);
|
SDL_RenderFillRect(renderer, &fullPanel);
|
||||||
// Also draw the central strip to keep visual center emphasis
|
// Also draw the central strip to keep visual center emphasis
|
||||||
SDL_FRect panelRect{ panelLeft, panelTop, panelRight - panelLeft, panelH };
|
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
|
// subtle border across full logical width
|
||||||
SDL_SetRenderDrawColor(renderer, 120, 140, 160, 200);
|
SDL_SetRenderDrawColor(renderer, 120, 140, 160, 200);
|
||||||
// Expand border to cover full window width (use actual viewport)
|
// Expand border to cover full window width (use actual viewport)
|
||||||
float fullLeftNormal = 0.0f;
|
SDL_FRect borderFull{ 0.0f, panelTop, viewportLogicalW, panelH };
|
||||||
float fullWNormal = viewportLogicalW;
|
|
||||||
SDL_FRect borderFull{ fullLeftNormal, panelTop, fullWNormal, panelH };
|
|
||||||
SDL_RenderRect(renderer, &borderFull);
|
SDL_RenderRect(renderer, &borderFull);
|
||||||
}
|
}
|
||||||
// Button 0 - PLAY
|
// 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 };
|
SDL_FRect rc{ area.x + c * (cellW + gapX), area.y + r * (cellH + gapY), cellW, cellH };
|
||||||
bool hovered = (levelSelected == i) || (levelHovered == i);
|
bool hovered = (levelSelected == i) || (levelHovered == i);
|
||||||
bool selected = (ctx.startLevelSelection && *ctx.startLevelSelection == 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_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||||
SDL_SetRenderDrawColor(renderer, fill.r, fill.g, fill.b, fill.a);
|
SDL_SetRenderDrawColor(renderer, fill.r, fill.g, fill.b, fill.a);
|
||||||
SDL_RenderFillRect(renderer, &rc);
|
SDL_RenderFillRect(renderer, &rc);
|
||||||
|
|||||||
@ -253,9 +253,12 @@ void OptionsState::toggleSmoothScroll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OptionsState::exitToMenu() {
|
void OptionsState::exitToMenu() {
|
||||||
|
// Try a graceful fade transition if available, but always ensure we
|
||||||
|
// return to the Menu state so the UI is responsive to the user's action.
|
||||||
if (ctx.requestFadeTransition) {
|
if (ctx.requestFadeTransition) {
|
||||||
ctx.requestFadeTransition(AppState::Menu);
|
ctx.requestFadeTransition(AppState::Menu);
|
||||||
} else if (ctx.stateManager) {
|
}
|
||||||
|
if (ctx.stateManager) {
|
||||||
ctx.stateManager->setState(AppState::Menu);
|
ctx.stateManager->setState(AppState::Menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,10 @@ struct StateContext {
|
|||||||
SDL_Texture* mainScreenTex = nullptr;
|
SDL_Texture* mainScreenTex = nullptr;
|
||||||
int mainScreenW = 0;
|
int mainScreenW = 0;
|
||||||
int mainScreenH = 0;
|
int mainScreenH = 0;
|
||||||
|
// Captured full-scene texture (used by menu for backdrop blur effects)
|
||||||
|
SDL_Texture* sceneTex = nullptr;
|
||||||
|
int sceneW = 0;
|
||||||
|
int sceneH = 0;
|
||||||
|
|
||||||
// Audio / SFX - forward declared types in main
|
// Audio / SFX - forward declared types in main
|
||||||
// Pointers to booleans/flags used by multiple states
|
// Pointers to booleans/flags used by multiple states
|
||||||
|
|||||||
Reference in New Issue
Block a user