20 using std::runtime_error::runtime_error;
36 return SDL_PIXELFORMAT_INDEX8;
42 return SDL_PIXELFORMAT_RGBA32;
44 return SDL_PIXELFORMAT_INDEX8;
49 const std::vector<uint8_t>& data)
50 : width_(width), height_(height), depth_(depth), data_(data) {
55 const std::vector<uint8_t>& data,
const SnesPalette& palette)
66 : width_(other.width_),
67 height_(other.height_),
69 active_(other.active_),
70 modified_(other.modified_),
71 palette_(other.palette_),
72 metadata_(other.metadata_),
131 : width_(other.width_),
132 height_(other.height_),
133 depth_(other.depth_),
134 active_(other.active_),
135 modified_(other.modified_),
136 generation_(other.generation_),
137 texture_pixels(other.texture_pixels),
138 pixel_data_(other.pixel_data_),
139 palette_(std::move(other.palette_)),
140 metadata_(std::move(other.metadata_)),
141 data_(std::move(other.data_)),
142 surface_(other.surface_),
143 texture_(other.texture_) {
148 other.active_ =
false;
149 other.modified_ =
false;
150 other.generation_ = 0;
151 other.texture_pixels =
nullptr;
152 other.pixel_data_ =
nullptr;
153 other.surface_ =
nullptr;
154 other.texture_ =
nullptr;
158 if (
this != &other) {
169 width_ = other.width_;
170 height_ = other.height_;
171 depth_ = other.depth_;
172 active_ = other.active_;
173 modified_ = other.modified_;
174 generation_ = other.generation_;
175 texture_pixels = other.texture_pixels;
176 pixel_data_ = other.pixel_data_;
177 palette_ = std::move(other.palette_);
178 metadata_ = std::move(other.metadata_);
179 data_ = std::move(other.data_);
180 surface_ = other.surface_;
181 texture_ = other.texture_;
187 other.active_ =
false;
188 other.modified_ =
false;
189 other.generation_ = 0;
190 other.texture_pixels =
nullptr;
191 other.pixel_data_ =
nullptr;
192 other.surface_ =
nullptr;
193 other.texture_ =
nullptr;
204 const std::vector<uint8_t>& data) {
224 const std::vector<uint8_t>& data) {
246 SDL_Log(
"Bitmap data is empty\n");
253 SDL_Log(
"Bitmap::Create.SDL_CreateRGBSurfaceWithFormat failed: %s\n",
333 SDL_Log(
"Warning: Bitmap surface has no palette (non-indexed format?)\n");
379 for (
int y = 0; y <
height_; ++y) {
380 const size_t offset =
static_cast<size_t>(y) *
row_bytes;
381 if (offset >=
data_.size())
384 data_.data() + offset,
385 std::min({row_bytes, data_.size() - offset,
386 static_cast<size_t>(surface_->pitch)}));
417 const size_t pixel =
static_cast<size_t>(y) *
width_ + x;
419 const size_t offset =
pixel * 4;
420 if (offset + 3 >=
data_.size())
438 std::vector<uint8_t> result(
static_cast<size_t>(
width_) *
height_ * 4);
439 for (
int y = 0; y <
height_; ++y) {
440 for (
int x = 0; x <
width_; ++x) {
442 const size_t i = (
static_cast<size_t>(y) *
width_ + x) * 4;
444 result[i + 1] = color.g;
445 result[i + 2] = color.b;
446 result[i + 3] = color.a;
481 int sub_palette_index) {
536 throw std::invalid_argument(
"Invalid palette index");
540 throw std::invalid_argument(
541 "Invalid palette length (must be 0-15 for SNES palettes)");
545 throw std::invalid_argument(
"Palette index + length exceeds size");
549 std::vector<ImVec4> colors;
552 colors.push_back(
ImVec4(0, 0, 0, 0));
567 while (colors.size() <
static_cast<size_t>(length + 1)) {
568 colors.push_back(
ImVec4(0, 0, 0, 1.0f));
578 SDL_Log(
"Warning: Bitmap surface has no palette (non-indexed format?)\n");
582 const int num_colors =
static_cast<int>(colors.size());
583 for (
int color_index = 0; color_index <
num_colors; ++color_index) {
586 static_cast<Uint8>(colors[color_index].x * 255.0f);
588 static_cast<Uint8>(colors[color_index].y * 255.0f);
590 static_cast<Uint8>(colors[color_index].z * 255.0f);
592 static_cast<Uint8>(colors[color_index].w * 255.0f);
618 SDL_Log(
"Warning: SetPalette - surface has no palette!");
628 "Warning: SetPalette - SDL palette has %d colors, trying to set %d. "
629 "Colors above %d may not display correctly.",
655 SDL_Log(
"ERROR: WriteToPixel - position %d out of bounds (size: %zu)",
656 position,
data_.size());
663 "ERROR: WriteToPixel - bitmap not active or data empty (active=%s, "
676 "ERROR: WriteToPixel - surface or pixels are null (surface=%p, "
684 SDL_Log(
"ERROR: WriteToPixel - pixel_data_ is null after assignment");
689 data_[position] = value;
697 position %
width_] = value;
712 static_cast<Uint8>(color.y * 255),
static_cast<Uint8>(color.z * 255)));
717 std::vector<uint8_t>& tile_data,
718 int& tile_data_offset) {
720 int tile_x = (x * 8) %
width_;
721 int tile_y = (y * 8) %
height_;
722 for (
int i = 0; i < 8; i++) {
723 for (
int j = 0;
j < 8;
j++) {
733 std::vector<uint8_t>& tile_data,
734 int& tile_data_offset) {
735 for (
int ty = 0;
ty < 16;
ty++) {
736 for (
int tx = 0;
tx < 16;
tx++) {
738 int pixel_x = tile_x +
tx;
739 int pixel_y = tile_y +
ty;
774 int position = y *
width_ + x;
775 if (position >= 0 && position <
static_cast<int>(
data_.size())) {
777 data_[position] = color_index;
808 if (!
data_.empty()) {
822 data_ = std::move(new_data);
860 return (r << 24) | (g << 16) | (b << 8) | a;
904 SDL_Log(
"Warning: set_data called with empty data vector");
918 SDL_Log(
"ValidateDataSurfaceSync: surface or data is null/empty");
926 for (
int y = 0; y <
height_; ++y) {
SDL_Surface * AllocateSurface(int width, int height, int depth, int format)
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
void FreeSurface(SDL_Surface *surface)
Represents a bitmap image optimized for SNES ROM hacking.
const uint8_t * data() const
const SnesPalette & palette() const
SDL_Surface * surface_
SDL surface for rendering (contains the authoritative palette)
Bitmap & operator=(const Bitmap &other)
Copy assignment operator.
void WriteToPixel(int position, uint8_t value)
Write a value to a pixel at the given position.
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
bool ValidateDataSurfaceSync()
Validate that bitmap data and surface pixels are synchronized.
const std::vector< uint8_t > & vector() const
void UpdateSurfacePixels()
Update SDL surface with current pixel data from data_ vector Call this after modifying pixel data via...
std::unordered_map< uint32_t, uint8_t > color_to_index_cache_
void Reformat(int format)
Reformat the bitmap to use a different pixel format.
static uint32_t HashColor(const ImVec4 &color)
Hash a color for cache lookup.
void CopySurfaceState(const Bitmap &other)
void Get8x8Tile(int tile_index, int x, int y, std::vector< uint8_t > &tile_data, int &tile_data_offset)
Extract an 8x8 tile from the bitmap (SNES standard tile size)
void CreateTexture()
Creates the underlying SDL_Texture to be displayed.
void WriteColor(int position, const ImVec4 &color)
Write a color to a pixel at the given position.
void set_data(const std::vector< uint8_t > &data)
void Resize(int new_width, int new_height)
Resize the bitmap to new dimensions (preserves existing data)
static uint32_t next_generation_
void SetPixel(int x, int y, const SnesColor &color)
Set a pixel at the given x,y coordinates with SNES color.
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
SDL_Color ReadColor(int x, int y) const
void ApplyStoredPalette()
Apply the stored palette to the surface (internal helper)
std::vector< uint8_t > data_
void InvalidatePaletteCache()
Invalidate the palette lookup cache (call when palette changes)
void SetPaletteWithTransparent(const SnesPalette &palette, size_t index, int length=7)
Set the palette with a transparent color.
struct yaze::gfx::Bitmap::DirtyRegion dirty_region_
void ApplyPaletteByMetadata(const SnesPalette &palette, int sub_palette_index=0)
Apply palette using metadata-driven strategy Chooses between SetPalette and SetPaletteWithTransparent...
void Get16x16Tile(int tile_x, int tile_y, std::vector< uint8_t > &tile_data, int &tile_data_offset)
Extract a 16x16 tile from the bitmap (SNES metatile size)
uint8_t FindColorIndex(const SnesColor &color)
Find color index in palette using optimized hash map lookup.
void UpdateTexture()
Updates the underlying SDL_Texture when it already exists.
gfx::SnesPalette palette_
Internal SNES palette storage (may be empty!)
std::vector< uint8_t > ToRgba() const
RAII timer for automatic timing management.
constexpr ImVec4 rgb() const
Get RGB values (WARNING: stored as 0-255 in ImVec4)
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
constexpr Uint32 SNES_PIXELFORMAT_8BPP
constexpr Uint32 SNES_PIXELFORMAT_4BPP
Uint32 GetSnesPixelFormat(int format)
Convert bitmap format enum to SDL pixel format.
SDL2/SDL3 compatibility layer.
void AddPoint(int x, int y)