space warp fixes

This commit is contained in:
2025-12-10 17:57:32 +01:00
parent 57eac01bcb
commit e8a7b19213
3 changed files with 41 additions and 7 deletions

View File

@ -321,6 +321,15 @@ void SpaceWarp::draw(SDL_Renderer* renderer, float alphaScale) {
return; return;
} }
// Add a small, smooth sub-pixel jitter to the visual center used for
// rendering so a single bright star/comet doesn't permanently sit exactly
// at the pixel-perfect center of the viewport.
const float jitterAmp = 1.6f; // maximum jitter in pixels
const uint32_t now = SDL_GetTicks();
const float tms = static_cast<float>(now) * 0.001f;
const float centerJitterX = std::sin(tms * 1.7f) * jitterAmp + std::cos(tms * 0.9f) * 0.4f;
const float centerJitterY = std::sin(tms * 1.1f + 3.7f) * (jitterAmp * 0.6f);
SDL_BlendMode previous = SDL_BLENDMODE_NONE; SDL_BlendMode previous = SDL_BLENDMODE_NONE;
SDL_GetRenderDrawBlendMode(renderer, &previous); SDL_GetRenderDrawBlendMode(renderer, &previous);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_ADD); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_ADD);
@ -339,13 +348,17 @@ void SpaceWarp::draw(SDL_Renderer* renderer, float alphaScale) {
float trailAlphaFloat = alpha * settings.trailAlphaScale; float trailAlphaFloat = alpha * settings.trailAlphaScale;
Uint8 trailAlpha = static_cast<Uint8>(std::clamp(trailAlphaFloat, 0.0f, 255.0f)); Uint8 trailAlpha = static_cast<Uint8>(std::clamp(trailAlphaFloat, 0.0f, 255.0f));
SDL_SetRenderDrawColor(renderer, color, color, color, trailAlpha); SDL_SetRenderDrawColor(renderer, color, color, color, trailAlpha);
SDL_RenderLine(renderer, star.prevScreenX, star.prevScreenY, star.screenX, star.screenY); SDL_RenderLine(renderer,
star.prevScreenX + centerJitterX, star.prevScreenY + centerJitterY,
star.screenX + centerJitterX, star.screenY + centerJitterY);
} }
float dotSize = std::clamp(settings.minDotSize + depthFactor * (settings.maxDotSize - settings.minDotSize), float dotSize = std::clamp(settings.minDotSize + depthFactor * (settings.maxDotSize - settings.minDotSize),
settings.minDotSize, settings.minDotSize,
settings.maxDotSize); settings.maxDotSize);
SDL_FRect dot{star.screenX - dotSize * 0.5f, star.screenY - dotSize * 0.5f, dotSize, dotSize}; SDL_FRect dot{star.screenX - dotSize * 0.5f + centerJitterX,
star.screenY - dotSize * 0.5f + centerJitterY,
dotSize, dotSize};
SDL_SetRenderDrawColor(renderer, color, color, color, alpha); SDL_SetRenderDrawColor(renderer, color, color, color, alpha);
SDL_RenderFillRect(renderer, &dot); SDL_RenderFillRect(renderer, &dot);
} }
@ -354,10 +367,14 @@ void SpaceWarp::draw(SDL_Renderer* renderer, float alphaScale) {
float lifeNorm = std::clamp(comet.life / comet.maxLife, 0.0f, 1.0f); float lifeNorm = std::clamp(comet.life / comet.maxLife, 0.0f, 1.0f);
Uint8 alpha = static_cast<Uint8>(std::clamp(220.0f * lifeNorm, 0.0f, 255.0f)); Uint8 alpha = static_cast<Uint8>(std::clamp(220.0f * lifeNorm, 0.0f, 255.0f));
SDL_SetRenderDrawColor(renderer, comet.color.r, comet.color.g, comet.color.b, alpha); SDL_SetRenderDrawColor(renderer, comet.color.r, comet.color.g, comet.color.b, alpha);
SDL_RenderLine(renderer, comet.prevScreenX, comet.prevScreenY, comet.screenX, comet.screenY); SDL_RenderLine(renderer,
comet.prevScreenX + centerJitterX, comet.prevScreenY + centerJitterY,
comet.screenX + centerJitterX, comet.screenY + centerJitterY);
float size = comet.size * (0.8f + (1.0f - lifeNorm) * 0.6f); float size = comet.size * (0.8f + (1.0f - lifeNorm) * 0.6f);
SDL_FRect head{comet.screenX - size * 0.5f, comet.screenY - size * 0.5f, size, size}; SDL_FRect head{comet.screenX - size * 0.5f + centerJitterX,
comet.screenY - size * 0.5f + centerJitterY,
size, size};
SDL_RenderFillRect(renderer, &head); SDL_RenderFillRect(renderer, &head);
} }

View File

@ -163,14 +163,22 @@ void Starfield3D::drawStar(SDL_Renderer* renderer, float x, float y, SDL_Color c
} }
void Starfield3D::draw(SDL_Renderer* renderer, float offsetX, float offsetY, float alphaScale, bool grayscale) { void Starfield3D::draw(SDL_Renderer* renderer, float offsetX, float offsetY, float alphaScale, bool grayscale) {
// Small visual jitter applied to the visual center so a single bright star
// doesn't remain perfectly fixed at the exact pixel center of the viewport.
const float jitterAmp = 1.6f; // max pixel offset
const uint32_t now = SDL_GetTicks();
const float tms = static_cast<float>(now) * 0.001f;
const float centerJitterX = std::sin(tms * 1.7f) * jitterAmp + std::cos(tms * 0.9f) * 0.4f;
const float centerJitterY = std::sin(tms * 1.1f + 3.7f) * (jitterAmp * 0.6f);
const bool useMagnet = magnetActive && magnetStrength > 0.0f; const bool useMagnet = magnetActive && magnetStrength > 0.0f;
for (const Star3D& star : stars) { for (const Star3D& star : stars) {
// Calculate perspective projection factor // Calculate perspective projection factor
const float k = DEPTH_FACTOR / star.z; const float k = DEPTH_FACTOR / star.z;
// Calculate screen position with perspective // Calculate screen position with perspective
float px = star.x * k + centerX; float px = star.x * k + centerX + centerJitterX;
float py = star.y * k + centerY; float py = star.y * k + centerY + centerJitterY;
if (useMagnet) { if (useMagnet) {
float dx = magnetX - px; float dx = magnetX - px;

View File

@ -716,7 +716,16 @@ void GameRenderer::renderPlayingState(
SDL_BlendMode oldBlend = SDL_BLENDMODE_NONE; SDL_BlendMode oldBlend = SDL_BLENDMODE_NONE;
SDL_GetRenderDrawBlendMode(renderer, &oldBlend); SDL_GetRenderDrawBlendMode(renderer, &oldBlend);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
s_inGridStarfield.draw(renderer, gridX, gridY, 0.22f, true); // Add a small, smooth sub-pixel jitter to the starfield origin so the
// brightest star doesn't permanently sit exactly at the visual center.
{
const float jitterAmp = 1.6f; // max pixels of jitter
const uint32_t now = SDL_GetTicks();
const float tms = static_cast<float>(now) * 0.001f;
const float jitterX = std::sin(tms * 1.7f) * jitterAmp + std::cos(tms * 0.9f) * 0.4f;
const float jitterY = std::sin(tms * 1.1f + 3.7f) * (jitterAmp * 0.6f);
s_inGridStarfield.draw(renderer, gridX + jitterX, gridY + jitterY, 0.22f, true);
}
// Update and spawn ambient sparkles inside/around the grid // Update and spawn ambient sparkles inside/around the grid
// Use the same RNG and timing values used for impact sparks // Use the same RNG and timing values used for impact sparks