141 lines
4.7 KiB
C++
141 lines
4.7 KiB
C++
// starfield_parallax.cpp - Implementació del starfield 2D amb parallax
|
|
// © 2026 JailDesigner
|
|
|
|
#include "core/graphics/starfield_parallax.hpp"
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "core/defaults.hpp"
|
|
#include "core/rendering/line_renderer.hpp"
|
|
|
|
namespace Graphics {
|
|
|
|
namespace {
|
|
|
|
auto randUniform(float min_v, float max_v) -> float {
|
|
const float NORM = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
|
|
return min_v + (NORM * (max_v - min_v));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
StarfieldParallax::StarfieldParallax(Rendering::Renderer* renderer)
|
|
: renderer_(renderer) {
|
|
buildStars();
|
|
}
|
|
|
|
void StarfieldParallax::buildStars() {
|
|
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
|
const float MIN_X = zona.x;
|
|
const float MAX_X = zona.x + zona.w;
|
|
const float MIN_Y = zona.y;
|
|
const float MAX_Y = zona.y + zona.h;
|
|
|
|
// Color únic per a totes les estrelles: el mateix blanc-blau gel
|
|
// del starfield del títol (Defaults::Title::Colors::STARFIELD).
|
|
const auto FILL_LAYER = [&](int layer, int count, int& idx) {
|
|
for (int i = 0; i < count; i++) {
|
|
stars_[idx++] = Star{
|
|
.x = randUniform(MIN_X, MAX_X),
|
|
.y = randUniform(MIN_Y, MAX_Y),
|
|
.layer = layer,
|
|
.color = Defaults::Title::Colors::STARFIELD};
|
|
}
|
|
};
|
|
|
|
int idx = 0;
|
|
FILL_LAYER(0, Defaults::StarfieldParallax::Far::COUNT, idx);
|
|
FILL_LAYER(1, Defaults::StarfieldParallax::Mid::COUNT, idx);
|
|
FILL_LAYER(2, Defaults::StarfieldParallax::Near::COUNT, idx);
|
|
}
|
|
|
|
auto StarfieldParallax::layerBrightness(int layer) -> float {
|
|
switch (layer) {
|
|
case 0:
|
|
return Defaults::StarfieldParallax::Far::BRIGHTNESS;
|
|
case 1:
|
|
return Defaults::StarfieldParallax::Mid::BRIGHTNESS;
|
|
case 2:
|
|
return Defaults::StarfieldParallax::Near::BRIGHTNESS;
|
|
default:
|
|
return 0.0F;
|
|
}
|
|
}
|
|
|
|
auto StarfieldParallax::layerParallax(int layer) -> float {
|
|
switch (layer) {
|
|
case 0:
|
|
return Defaults::StarfieldParallax::Far::PARALLAX_FACTOR;
|
|
case 1:
|
|
return Defaults::StarfieldParallax::Mid::PARALLAX_FACTOR;
|
|
case 2:
|
|
return Defaults::StarfieldParallax::Near::PARALLAX_FACTOR;
|
|
default:
|
|
return 0.0F;
|
|
}
|
|
}
|
|
|
|
auto StarfieldParallax::layerSize(int layer) -> int {
|
|
switch (layer) {
|
|
case 0:
|
|
return Defaults::StarfieldParallax::Far::SIZE_PX;
|
|
case 1:
|
|
return Defaults::StarfieldParallax::Mid::SIZE_PX;
|
|
case 2:
|
|
return Defaults::StarfieldParallax::Near::SIZE_PX;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void StarfieldParallax::update(float delta_time, Vec2 world_velocity) {
|
|
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
|
const float MIN_X = zona.x;
|
|
const float MAX_X = zona.x + zona.w;
|
|
const float MIN_Y = zona.y;
|
|
const float MAX_Y = zona.y + zona.h;
|
|
const float W = zona.w;
|
|
const float H = zona.h;
|
|
|
|
for (auto& star : stars_) {
|
|
const float FACTOR = layerParallax(star.layer);
|
|
star.x += world_velocity.x * FACTOR * delta_time;
|
|
star.y += world_velocity.y * FACTOR * delta_time;
|
|
|
|
// Wraparound (PLAYAREA torica).
|
|
while (star.x < MIN_X) {
|
|
star.x += W;
|
|
}
|
|
while (star.x > MAX_X) {
|
|
star.x -= W;
|
|
}
|
|
while (star.y < MIN_Y) {
|
|
star.y += H;
|
|
}
|
|
while (star.y > MAX_Y) {
|
|
star.y -= H;
|
|
}
|
|
}
|
|
}
|
|
|
|
void StarfieldParallax::draw() const {
|
|
for (const auto& star : stars_) {
|
|
const float B = layerBrightness(star.layer);
|
|
const int SIZE = layerSize(star.layer);
|
|
const int X = static_cast<int>(star.x);
|
|
const int Y = static_cast<int>(star.y);
|
|
|
|
if (SIZE <= 1) {
|
|
// Punt d'1 px: línia degenerada horitzontal de 1 px.
|
|
Rendering::linea(renderer_, X, Y, X + 1, Y, B, 0.0F, star.color);
|
|
} else {
|
|
// Creu "+" amb extensió HALF des del centre en cada direcció.
|
|
const int HALF = SIZE - 1; // SIZE=2 → ±1 (creu 3x3); SIZE=3 → ±2 (creu 5x5)
|
|
Rendering::linea(renderer_, X - HALF, Y, X + HALF + 1, Y, B, 0.0F, star.color);
|
|
Rendering::linea(renderer_, X, Y - HALF, X, Y + HALF + 1, B, 0.0F, star.color);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace Graphics
|