82 lines
3.4 KiB
C++
82 lines
3.4 KiB
C++
#pragma once
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <array>
|
|
#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};
|
|
};
|