new background for main screen

This commit is contained in:
2025-12-01 20:52:26 +01:00
parent cfbb4e4c86
commit 383b2e48ec
11 changed files with 417 additions and 85 deletions

View File

@ -0,0 +1,149 @@
#include "SpaceWarp.h"
#include <algorithm>
#include <array>
#include <cmath>
namespace {
constexpr float MIN_ASPECT = 0.001f;
}
SpaceWarp::SpaceWarp() {
std::random_device rd;
rng.seed(rd());
}
void SpaceWarp::init(int w, int h, int starCount) {
resize(w, h);
stars.resize(std::max(8, starCount));
for (auto& star : stars) {
respawn(star, true);
}
}
void SpaceWarp::resize(int w, int h) {
width = std::max(1, w);
height = std::max(1, h);
centerX = width * 0.5f;
centerY = height * 0.5f;
warpFactor = std::max(width, height) * settings.warpFactorScale;
}
void SpaceWarp::setSettings(const SpaceWarpSettings& newSettings) {
settings = newSettings;
warpFactor = std::max(width, height) * settings.warpFactorScale;
}
float SpaceWarp::randomRange(float min, float max) {
std::uniform_real_distribution<float> dist(min, max);
return dist(rng);
}
static int randomIntInclusive(std::mt19937& rng, int min, int max) {
std::uniform_int_distribution<int> dist(min, max);
return dist(rng);
}
void SpaceWarp::respawn(WarpStar& star, bool randomDepth) {
float aspect = static_cast<float>(width) / static_cast<float>(std::max(1, height));
float normalizedAspect = std::max(aspect, MIN_ASPECT);
float xRange = settings.baseSpawnRange * (aspect >= 1.0f ? aspect : 1.0f);
float yRange = settings.baseSpawnRange * (aspect >= 1.0f ? 1.0f : (1.0f / normalizedAspect));
star.x = randomRange(-xRange, xRange);
star.y = randomRange(-yRange, yRange);
star.z = randomDepth ? randomRange(minDepth, maxDepth) : maxDepth;
star.speed = randomRange(settings.minSpeed, settings.maxSpeed);
star.shade = randomRange(settings.minShade, settings.maxShade);
static constexpr Uint8 GRAY_SHADES[] = {160, 180, 200, 220, 240};
int idx = randomIntInclusive(rng, 0, int(std::size(GRAY_SHADES)) - 1);
star.baseShade = GRAY_SHADES[idx];
star.prevScreenX = centerX;
star.prevScreenY = centerY;
star.screenX = centerX;
star.screenY = centerY;
}
bool SpaceWarp::project(const WarpStar& star, float& outX, float& outY) const {
if (star.z <= minDepth) {
return false;
}
float perspective = warpFactor / (star.z + 0.001f);
outX = centerX + star.x * perspective;
outY = centerY + star.y * perspective;
const float margin = settings.spawnMargin;
return outX >= -margin && outX <= width + margin && outY >= -margin && outY <= height + margin;
}
void SpaceWarp::update(float deltaSeconds) {
if (stars.empty()) {
return;
}
for (auto& star : stars) {
star.z -= star.speed * deltaSeconds;
if (star.z <= minDepth) {
respawn(star, true);
continue;
}
float sx = 0.0f;
float sy = 0.0f;
if (!project(star, sx, sy)) {
respawn(star, true);
continue;
}
star.prevScreenX = star.screenX;
star.prevScreenY = star.screenY;
star.screenX = sx;
star.screenY = sy;
float dx = star.screenX - star.prevScreenX;
float dy = star.screenY - star.prevScreenY;
float lenSq = dx * dx + dy * dy;
float maxStreak = std::max(settings.maxTrailLength, 0.0f);
if (maxStreak > 0.0f && lenSq > maxStreak * maxStreak) {
float len = std::sqrt(lenSq);
float scale = maxStreak / len;
star.prevScreenX = star.screenX - dx * scale;
star.prevScreenY = star.screenY - dy * scale;
}
}
}
void SpaceWarp::draw(SDL_Renderer* renderer, float alphaScale) {
if (stars.empty()) {
return;
}
SDL_BlendMode previous = SDL_BLENDMODE_NONE;
SDL_GetRenderDrawBlendMode(renderer, &previous);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_ADD);
for (const auto& star : stars) {
float depthFactor = 1.0f - std::clamp(star.z / maxDepth, 0.0f, 1.0f);
float alphaBase = std::clamp(settings.minAlpha + depthFactor * settings.alphaDepthBoost, 0.0f, 255.0f);
Uint8 alpha = static_cast<Uint8>(std::clamp(alphaBase * alphaScale, 0.0f, 255.0f));
float colorValue = std::clamp(
star.baseShade * (settings.baseShadeScale + depthFactor * settings.depthColorScale) * star.shade,
settings.minColor,
settings.maxColor);
Uint8 color = static_cast<Uint8>(colorValue);
if (settings.drawTrails) {
float trailAlphaFloat = alpha * settings.trailAlphaScale;
Uint8 trailAlpha = static_cast<Uint8>(std::clamp(trailAlphaFloat, 0.0f, 255.0f));
SDL_SetRenderDrawColor(renderer, color, color, color, trailAlpha);
SDL_RenderLine(renderer, star.prevScreenX, star.prevScreenY, star.screenX, star.screenY);
}
float dotSize = std::clamp(settings.minDotSize + depthFactor * (settings.maxDotSize - settings.minDotSize),
settings.minDotSize,
settings.maxDotSize);
SDL_FRect dot{star.screenX - dotSize * 0.5f, star.screenY - dotSize * 0.5f, dotSize, dotSize};
SDL_SetRenderDrawColor(renderer, color, color, color, alpha);
SDL_RenderFillRect(renderer, &dot);
}
SDL_SetRenderDrawBlendMode(renderer, previous);
}

View File

@ -0,0 +1,69 @@
#pragma once
#include <SDL3/SDL.h>
#include <random>
#include <vector>
struct SpaceWarpSettings {
float baseSpawnRange = 1.45f; // logical radius for initial star positions
float warpFactorScale = 122.85f; // scales perspective factor so stars spread faster or slower
float spawnMargin = 60.0f; // how far offscreen a star can travel before respawn
float minShade = 0.85f; // lower bound for per-star brightness multiplier
float maxShade = 1.15f; // upper bound for per-star brightness multiplier
float minSpeed = 120.0f; // slowest warp velocity (higher feels faster motion)
float maxSpeed = 280.0f; // fastest warp velocity
float minDotSize = 2.5f; // smallest star size in pixels
float maxDotSize = 4.5f; // largest star size in pixels
float minAlpha = 70.0f; // base opacity even for distant stars
float alphaDepthBoost = 160.0f; // extra opacity applied as stars approach the camera
float minColor = 180.0f; // clamp for minimum grayscale value
float maxColor = 205.0f; // clamp for maximum grayscale value
float baseShadeScale = 0.75f; // baseline multiplier applied to the sampled grayscale shade
float depthColorScale = 0.55f; // how much depth affects the grayscale brightness
bool drawTrails = true; // when true, also render streak lines for hyper-speed look
float trailAlphaScale = 0.75f; // relative opacity for streak lines vs dots
float maxTrailLength = 36.0f; // clamp length of each streak in pixels
};
class SpaceWarp {
public:
SpaceWarp();
void init(int width, int height, int starCount = 320);
void resize(int width, int height);
void update(float deltaSeconds);
void draw(SDL_Renderer* renderer, float alphaScale = 1.0f);
void setSettings(const SpaceWarpSettings& newSettings);
const SpaceWarpSettings& getSettings() const { return settings; }
private:
struct WarpStar {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
float speed = 0.0f;
float prevScreenX = 0.0f;
float prevScreenY = 0.0f;
float screenX = 0.0f;
float screenY = 0.0f;
float shade = 1.0f;
Uint8 baseShade = 220;
};
void respawn(WarpStar& star, bool randomDepth = true);
bool project(const WarpStar& star, float& outX, float& outY) const;
float randomRange(float min, float max);
std::vector<WarpStar> stars;
std::mt19937 rng;
int width = 0;
int height = 0;
float centerX = 0.0f;
float centerY = 0.0f;
float warpFactor = 520.0f;
SpaceWarpSettings settings{};
float minDepth = 2.0f;
float maxDepth = 320.0f;
};