new background for main screen
This commit is contained in:
149
src/graphics/effects/SpaceWarp.cpp
Normal file
149
src/graphics/effects/SpaceWarp.cpp
Normal 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);
|
||||
}
|
||||
69
src/graphics/effects/SpaceWarp.h
Normal file
69
src/graphics/effects/SpaceWarp.h
Normal 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;
|
||||
};
|
||||
Reference in New Issue
Block a user