23namespace png_internal {
25void PngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
26 std::vector<uint8_t> *p = (std::vector<uint8_t> *)png_get_io_ptr(png_ptr);
27 p->insert(p->end(), data, data + length);
30void PngReadCallback(png_structp png_ptr, png_bytep outBytes,
31 png_size_t byteCountToRead) {
32 png_voidp io_ptr = png_get_io_ptr(png_ptr);
35 std::vector<uint8_t> *png_data =
36 reinterpret_cast<std::vector<uint8_t> *
>(io_ptr);
37 static size_t pos = 0;
39 if (pos + byteCountToRead <= png_data->size()) {
40 memcpy(outBytes, png_data->data() + pos, byteCountToRead);
41 pos += byteCountToRead;
43 png_error(png_ptr,
"Read error in PngReadCallback");
49bool ConvertSurfaceToPng(SDL_Surface *surface, std::vector<uint8_t> &buffer) {
50 png_structp png_ptr = png_create_write_struct(
"1.6.40", NULL, NULL, NULL);
52 SDL_Log(
"Failed to create PNG write struct");
56 png_infop info_ptr = png_create_info_struct(png_ptr);
58 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
59 SDL_Log(
"Failed to create PNG info struct");
63 if (setjmp(png_jmpbuf(png_ptr))) {
64 png_destroy_write_struct(&png_ptr, &info_ptr);
65 SDL_Log(
"Error during PNG write");
69 png_set_write_fn(png_ptr, &buffer, png_internal::PngWriteCallback, NULL);
74 int colortype = PNG_COLOR_MASK_COLOR;
77 if (surface->format->BytesPerPixel > 0 &&
78 surface->format->BytesPerPixel <= 8 && (pal = surface->format->palette)) {
79 SDL_Log(
"Writing PNG image with palette");
80 colortype |= PNG_COLOR_MASK_PALETTE;
81 pal_ptr = (png_colorp)malloc(pal->ncolors *
sizeof(png_color));
82 for (i = 0; i < pal->ncolors; i++) {
83 pal_ptr[i].red = pal->colors[i].r;
84 pal_ptr[i].green = pal->colors[i].g;
85 pal_ptr[i].blue = pal->colors[i].b;
87 png_set_PLTE(png_ptr, info_ptr, pal_ptr, pal->ncolors);
91 if (surface->format->Amask) {
92 colortype |= PNG_COLOR_MASK_ALPHA;
95 auto depth = surface->format->BitsPerPixel;
98 png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, depth, colortype,
99 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
100 PNG_FILTER_TYPE_DEFAULT);
102 png_set_bgr(png_ptr);
105 std::vector<png_bytep> row_pointers(surface->h);
106 for (
int y = 0; y < surface->h; ++y) {
107 row_pointers[y] = (png_bytep)(surface->pixels) + y * surface->pitch;
110 png_set_rows(png_ptr, info_ptr, row_pointers.data());
112 SDL_Log(
"Writing PNG image...");
113 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
114 SDL_Log(
"PNG image write complete");
116 png_destroy_write_struct(&png_ptr, &info_ptr);
121void ConvertPngToSurface(
const std::vector<uint8_t> &png_data,
122 SDL_Surface **outSurface) {
123 std::vector<uint8_t> data(png_data);
124 png_structp png_ptr = png_create_read_struct(
"1.6.40", NULL, NULL, NULL);
126 throw std::runtime_error(
"Failed to create PNG read struct");
129 png_infop info_ptr = png_create_info_struct(png_ptr);
131 png_destroy_read_struct(&png_ptr, NULL, NULL);
132 throw std::runtime_error(
"Failed to create PNG info struct");
135 if (setjmp(png_jmpbuf(png_ptr))) {
136 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
137 throw std::runtime_error(
"Error during PNG read");
141 png_set_read_fn(png_ptr, &data, png_internal::PngReadCallback);
144 png_read_info(png_ptr, info_ptr);
146 uint32_t width = png_get_image_width(png_ptr, info_ptr);
147 uint32_t height = png_get_image_height(png_ptr, info_ptr);
148 png_byte color_type = png_get_color_type(png_ptr, info_ptr);
149 png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
155 png_read_update_info(png_ptr, info_ptr);
158 std::vector<uint8_t> raw_data(width * height *
160 std::vector<png_bytep> row_pointers(height);
161 for (
size_t y = 0; y < height; y++) {
162 row_pointers[y] = raw_data.data() + y * width * 4;
165 png_read_image(png_ptr, row_pointers.data());
166 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
169 *outSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32,
170 SDL_PIXELFORMAT_RGBA32);
171 if (*outSurface ==
nullptr) {
172 SDL_Log(
"SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError());
177 SDL_LockSurface(*outSurface);
178 memcpy((*outSurface)->pixels, raw_data.data(), raw_data.size());
179 SDL_UnlockSurface(*outSurface);
181 SDL_Log(
"Successfully created SDL_Surface from PNG data");
184std::vector<uint8_t> Bitmap::GetPngData() {
185 std::vector<uint8_t> png_data;
186 ConvertSurfaceToPng(
surface_.get(), png_data);
196 return SDL_PIXELFORMAT_INDEX8;
204 return SDL_PIXELFORMAT_INDEX8;
209 SDL_SaveBMP(
surface_.get(), filename.data());
217 std::span<uint8_t> &
data) {
230 const std::vector<uint8_t> &
data) {
235 const std::vector<uint8_t> &
data) {
237 SDL_Log(
"Bitmap data is empty\n");
247 SDL_Log(
"Data provided to Bitmap is empty.\n");
253 surface_ = std::shared_ptr<SDL_Surface>{
255 GetSnesPixelFormat(format)),
258 SDL_Log(
"Bitmap::Create.SDL_CreateRGBSurfaceWithFormat failed: %s\n",
268 surface_ = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
270 GetSnesPixelFormat(format)),
275 if (!apply_palette.ok()) {
276 SDL_Log(
"Failed to apply palette: %s\n", apply_palette.message().data());
283 SDL_Log(
"Invalid texture dimensions: width=%d, height=%d\n",
width_,
288 texture_ = std::shared_ptr<SDL_Texture>{
289 SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888,
293 SDL_Log(
"Bitmap::CreateTexture.SDL_CreateTextureFromSurface failed: %s\n",
298 auto converted_surface_ = std::shared_ptr<SDL_Surface>{
299 SDL_ConvertSurfaceFormat(
surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
301 if (converted_surface_ ==
nullptr) {
302 SDL_Log(
"Bitmap::CreateTexture.SDL_ConvertSurfaceFormat failed: %s\n",
308 &converted_surface_->pitch);
310 converted_surface_->h * converted_surface_->pitch);
315 auto converted_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
316 SDL_ConvertSurfaceFormat(
surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
318 if (converted_surface ==
nullptr) {
319 SDL_Log(
"SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError());
323 &converted_surface->pitch);
325 converted_surface->h * converted_surface->pitch);
331 return absl::FailedPreconditionError(
332 "Surface is null. Palette not applied");
335 return absl::FailedPreconditionError(
336 "Surface format or palette is null. Palette not applied.");
340 SDL_Palette *sdl_palette =
surface_->format->palette;
341 if (sdl_palette ==
nullptr) {
342 return absl::InternalError(
"Failed to get SDL palette");
346 for (
size_t i = 0; i <
palette.size(); ++i) {
348 sdl_palette->colors[i].r = pal_color.
rgb().x;
349 sdl_palette->colors[i].g = pal_color.
rgb().y;
350 sdl_palette->colors[i].b = pal_color.
rgb().z;
351 sdl_palette->colors[i].a = pal_color.
rgb().w;
355 return absl::OkStatus();
360 auto start_index = palette_id * 8;
363 for (
size_t i = 0; i <
palette_.size(); ++i) {
365 if (pal_color.is_transparent()) {
366 surface_->format->palette->colors[i].r = 0;
367 surface_->format->palette->colors[i].g = 0;
368 surface_->format->palette->colors[i].b = 0;
369 surface_->format->palette->colors[i].a = 0;
371 surface_->format->palette->colors[i].r = pal_color.rgb().x;
372 surface_->format->palette->colors[i].g = pal_color.rgb().y;
373 surface_->format->palette->colors[i].b = pal_color.rgb().z;
374 surface_->format->palette->colors[i].a = pal_color.rgb().w;
379 return absl::OkStatus();
383 size_t index,
int length) {
384 if (index < 0 || index >=
palette.size()) {
385 return absl::InvalidArgumentError(
"Invalid palette index");
388 if (length < 0 || length >
palette.size()) {
389 return absl::InvalidArgumentError(
"Invalid palette length");
392 if (index + length >
palette.size()) {
393 return absl::InvalidArgumentError(
"Palette index + length exceeds size");
397 return absl::FailedPreconditionError(
398 "Surface is null. Palette not applied");
401 auto start_index = index * 7;
403 std::vector<ImVec4> colors;
404 colors.push_back(ImVec4(0, 0, 0, 0));
405 for (
int i = start_index; i < start_index + 7; ++i) {
407 colors.push_back(pal_color.rgb());
412 for (
auto &each : colors) {
413 surface_->format->palette->colors[i].r = each.x;
414 surface_->format->palette->colors[i].g = each.y;
415 surface_->format->palette->colors[i].b = each.z;
416 surface_->format->palette->colors[i].a = each.w;
421 return absl::OkStatus();
426 for (
size_t i = 0; i <
palette.size(); ++i) {
436 std::vector<uint8_t> &tile_data,
437 int &tile_data_offset) {
439 int tile_x = (x * 8) %
width_;
440 int tile_y = (y * 8) %
height_;
441 for (
int i = 0; i < 8; i++) {
442 for (
int j = 0; j < 8; j++) {
443 int pixel_offset = tile_offset + (tile_y + i) *
width_ + tile_x + j;
444 int pixel_value =
data_[pixel_offset];
445 tile_data[tile_data_offset] = pixel_value;
452 std::vector<uint8_t> &tile_data,
453 int &tile_data_offset) {
454 for (
int ty = 0; ty < 16; ty++) {
455 for (
int tx = 0; tx < 16; tx++) {
457 int pixel_x = tile_x + tx;
458 int pixel_y = tile_y + ty;
459 int pixel_offset = (pixel_y *
width_) + pixel_x;
460 int pixel_value =
data_[pixel_offset];
463 tile_data[tile_data_offset++] = pixel_value;
471 sdl_color.r =
static_cast<Uint8
>(color.x * 255);
472 sdl_color.g =
static_cast<Uint8
>(color.y * 255);
473 sdl_color.b =
static_cast<Uint8
>(color.z * 255);
474 sdl_color.a =
static_cast<Uint8
>(color.w * 255);
478 SDL_MapRGB(
surface_->format, sdl_color.r, sdl_color.g, sdl_color.b);