Files
aee-arcade/source/core/rendering/surface.hpp
T
JailDesignerandClaude Opus 4.7 be94a4390e refactor(core/rendering): neteja del parser GIF i construcció de Surface (DUP-01/-06 + HC-03/-10 + PATCH-05)
- DUP-01: les tres branques del switch d'extensions que saltaven el
  mateix (bloc fix + sub-blocs) es substitueixen per una crida a
  skipExtensionBlock(); com que totes les extensions comparteixen
  layout, el switch desapareix i el codi es redueix a una línia.
- DUP-06: el constructor Surface(file_path) llegia el fitxer dues
  voltes (una via loadSurface per pixels i una altra via
  loadPaletteFromGif per la paleta); ara carrega el buffer una sola
  vegada i n'extrau pixels + paleta en passades separades sobre la
  memòria. Surface::loadSurface passa a no existir públicament (no
  tenia callers externs).
- HC-03: les màscares i talls màgics del decoder LZW i del Screen
  Descriptor passen a constants nominals (LZW_MIN/MAX_CODE_LENGTH,
  LZW_MASK_INITIAL, LZW_MASK_OVERFLOW, SCREEN_GCT_FLAG,
  SCREEN_GCT_SIZE_MASK, GCT_BYTES_PER_ENTRY).
- HC-10: processImageDescriptor tenia gct i resolution_bits
  [[maybe_unused]] vestigials; se'n treu la signatura. L'struct RGB,
  que només servia per a aquests args, també s'elimina.
- PATCH-05: el comentari "reemplaçar macro READ" (migració parcial des
  de C) passa a ser un comentari neutre sobre el que fa readBytes.

Build + smoke 5s xvfb OK (exit 124).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 09:53:43 +02:00

79 lines
3.1 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]; }
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};
};