Files
aee-arcade/source/core/rendering/surface.hpp
T

83 lines
3.4 KiB
C++

#pragma once
#include <SDL3/SDL.h>
#include <array>
#include <cstdint>
#include <memory>
#include <numeric>
#include <string>
// Cada Surface manté la seua propia paleta (256 colors ARGB). El destí del
// render es l'ARGB framebuffer del joc, mantingut per Screen, així que
// l'arquitectura és: sprites paletats → imatge final ARGB (>256 colors).
using Palette = std::array<Uint32, 256>;
using SubPalette = std::array<Uint8, 256>;
auto loadPaletteFromGif(const std::string& file_path) -> Palette;
struct SurfaceData {
std::shared_ptr<Uint8[]> data;
int width{0};
int height{0};
SurfaceData() = default;
SurfaceData(int w, int h)
: data(std::shared_ptr<Uint8[]>(new Uint8[static_cast<std::size_t>(w) * static_cast<std::size_t>(h)](), std::default_delete<Uint8[]>())),
width(w),
height(h) {}
SurfaceData(int w, int h, std::shared_ptr<Uint8[]> pixels)
: data(std::move(pixels)),
width(w),
height(h) {}
SurfaceData(SurfaceData&&) noexcept = default;
auto operator=(SurfaceData&&) noexcept -> SurfaceData& = default;
SurfaceData(const SurfaceData&) = delete;
auto operator=(const SurfaceData&) -> SurfaceData& = delete;
};
class Surface {
public:
// Crea una surface buida (paleta a zero) amb les dimensions donades.
Surface(int w, int h);
// Carrega pixels + paleta des d'un fitxer GIF.
explicit Surface(const std::string& file_path);
~Surface() = default;
// Vobla la regió indicada al framebuffer ARGB del joc usant la paleta propia.
void render(int x, int y, const SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE) const;
// Igual que render() però substituint els píxels amb valor source_color per
// target_color abans d'aplicar la paleta. Útil per a la classe Text: els
// glifs guarden "tinta" amb un únic índex i es recoloren per paràmetre.
void renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 target_color, const SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE) const;
void clear(Uint8 color);
void putPixel(int x, int y, Uint8 color);
[[nodiscard]] auto getPixel(int x, int y) const -> Uint8;
[[nodiscard]] auto getWidth() const -> int { return surface_data_->width; }
[[nodiscard]] auto getHeight() const -> int { return surface_data_->height; }
[[nodiscard]] auto getTransparentColor() const -> Uint8 { return transparent_color_; }
void setTransparentColor(Uint8 color = 0) { transparent_color_ = color; }
void setPalette(const Palette& palette) { palette_ = palette; }
[[nodiscard]] auto getPaletteColor(Uint8 index) const -> Uint32 { return palette_[index]; }
// Accés de lectura a la paleta sencera. L'usen consumidors que volen
// fer save/restore (p.ex. el blink d'immunitat del Player, que aplica
// una paleta plana abans del render i restaura la normal després).
[[nodiscard]] auto getPalette() const -> const Palette& { return palette_; }
static void initializeSubPalette(SubPalette& palette) { std::iota(palette.begin(), palette.end(), 0); }
private:
std::shared_ptr<SurfaceData> surface_data_;
Palette palette_{};
SubPalette sub_palette_{};
// Convenció de tots els GIFs del projecte (sprites i fonts): l'índex 0
// és el color de fons/transparent. Els tilesets que usen un altre índex
// han de cridar setTransparentColor() explícitament.
Uint8 transparent_color_{0};
};