24namespace png_internal {
26void PngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
27 std::vector<uint8_t> *p = (std::vector<uint8_t> *)png_get_io_ptr(png_ptr);
28 p->insert(p->end(), data, data + length);
31void PngReadCallback(png_structp png_ptr, png_bytep outBytes,
32 png_size_t byteCountToRead) {
33 png_voidp io_ptr = png_get_io_ptr(png_ptr);
36 std::vector<uint8_t> *png_data =
37 reinterpret_cast<std::vector<uint8_t> *
>(io_ptr);
38 static size_t pos = 0;
40 if (pos + byteCountToRead <= png_data->size()) {
41 memcpy(outBytes, png_data->data() + pos, byteCountToRead);
42 pos += byteCountToRead;
44 png_error(png_ptr,
"Read error in PngReadCallback");
50bool ConvertSurfaceToPng(SDL_Surface *surface, std::vector<uint8_t> &buffer) {
51 png_structp png_ptr = png_create_write_struct(
"1.6.40", NULL, NULL, NULL);
53 SDL_Log(
"Failed to create PNG write struct");
57 png_infop info_ptr = png_create_info_struct(png_ptr);
59 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
60 SDL_Log(
"Failed to create PNG info struct");
64 if (setjmp(png_jmpbuf(png_ptr))) {
65 png_destroy_write_struct(&png_ptr, &info_ptr);
66 SDL_Log(
"Error during PNG write");
70 png_set_write_fn(png_ptr, &buffer, png_internal::PngWriteCallback, NULL);
75 int colortype = PNG_COLOR_MASK_COLOR;
78 if (surface->format->BytesPerPixel > 0 &&
79 surface->format->BytesPerPixel <= 8 && (pal = surface->format->palette)) {
80 SDL_Log(
"Writing PNG image with palette");
81 colortype |= PNG_COLOR_MASK_PALETTE;
82 pal_ptr = (png_colorp)malloc(pal->ncolors *
sizeof(png_color));
83 for (i = 0; i < pal->ncolors; i++) {
84 pal_ptr[i].red = pal->colors[i].r;
85 pal_ptr[i].green = pal->colors[i].g;
86 pal_ptr[i].blue = pal->colors[i].b;
88 png_set_PLTE(png_ptr, info_ptr, pal_ptr, pal->ncolors);
92 if (surface->format->Amask) {
93 colortype |= PNG_COLOR_MASK_ALPHA;
96 auto depth = surface->format->BitsPerPixel;
99 png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, depth, colortype,
100 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
101 PNG_FILTER_TYPE_DEFAULT);
103 png_set_bgr(png_ptr);
106 std::vector<png_bytep> row_pointers(surface->h);
107 for (
int y = 0; y < surface->h; ++y) {
108 row_pointers[y] = (png_bytep)(surface->pixels) + y * surface->pitch;
111 png_set_rows(png_ptr, info_ptr, row_pointers.data());
113 SDL_Log(
"Writing PNG image...");
114 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
115 SDL_Log(
"PNG image write complete");
117 png_destroy_write_struct(&png_ptr, &info_ptr);
122void ConvertPngToSurface(
const std::vector<uint8_t> &png_data,
123 SDL_Surface **outSurface) {
124 std::vector<uint8_t> data(png_data);
125 png_structp png_ptr = png_create_read_struct(
"1.6.40", NULL, NULL, NULL);
127 throw std::runtime_error(
"Failed to create PNG read struct");
130 png_infop info_ptr = png_create_info_struct(png_ptr);
132 png_destroy_read_struct(&png_ptr, NULL, NULL);
133 throw std::runtime_error(
"Failed to create PNG info struct");
136 if (setjmp(png_jmpbuf(png_ptr))) {
137 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
138 throw std::runtime_error(
"Error during PNG read");
142 png_set_read_fn(png_ptr, &data, png_internal::PngReadCallback);
145 png_read_info(png_ptr, info_ptr);
147 uint32_t width = png_get_image_width(png_ptr, info_ptr);
148 uint32_t height = png_get_image_height(png_ptr, info_ptr);
149 png_byte color_type = png_get_color_type(png_ptr, info_ptr);
150 png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
156 png_read_update_info(png_ptr, info_ptr);
159 std::vector<uint8_t> raw_data(width * height *
161 std::vector<png_bytep> row_pointers(height);
162 for (
size_t y = 0; y < height; y++) {
163 row_pointers[y] = raw_data.data() + y * width * 4;
166 png_read_image(png_ptr, row_pointers.data());
167 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
170 *outSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32,
171 SDL_PIXELFORMAT_RGBA32);
172 if (*outSurface ==
nullptr) {
173 SDL_Log(
"SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError());
178 SDL_LockSurface(*outSurface);
179 memcpy((*outSurface)->pixels, raw_data.data(), raw_data.size());
180 SDL_UnlockSurface(*outSurface);
182 SDL_Log(
"Successfully created SDL_Surface from PNG data");
191 return SDL_PIXELFORMAT_INDEX8;
199 return SDL_PIXELFORMAT_INDEX8;
204 SDL_Surface *surface =
205 SDL_CreateRGBSurfaceWithFormat(0, width, height, depth, format);
208 surface, width * height * (depth / 8),
"SDL_Surface");
215 int width,
int height) {
216 SDL_Texture *texture =
217 SDL_CreateTexture(renderer, format, access, width, height);
220 size_t estimated_size = width * height * 4;
229 const std::vector<uint8_t> &
data)
246 SDL_SaveBMP(
surface_.get(), filename.data());
250 std::span<uint8_t> &
data) {
263 const std::vector<uint8_t> &
data) {
268 const std::vector<uint8_t> &
data) {
270 SDL_Log(
"Bitmap data is empty\n");
280 SDL_Log(
"Data provided to Bitmap is empty.\n");
286 surface_ = std::shared_ptr<SDL_Surface>{
290 SDL_Log(
"Bitmap::Create.SDL_CreateRGBSurfaceWithFormat failed: %s\n",
300 surface_ = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
309 auto converted_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
310 SDL_ConvertSurfaceFormat(
surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
312 if (converted_surface ==
nullptr) {
313 SDL_Log(
"SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError());
317 &converted_surface->pitch);
319 converted_surface->h * converted_surface->pitch);
325 SDL_Log(
"Invalid renderer passed to CreateTexture");
330 SDL_Log(
"Invalid texture dimensions: width=%d, height=%d\n",
width_,
347 SDL_Log(
"Bitmap::CreateTexture failed to get texture from pool: %s\n",
354 texture_ = std::shared_ptr<SDL_Texture>(raw_texture, [
this](SDL_Texture *t) {
357 SDL_PIXELFORMAT_RGB888);
372 auto converted_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
373 SDL_ConvertSurfaceFormat(
surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
376 if (converted_surface ==
nullptr) {
377 SDL_Log(
"SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError());
383 if (SDL_LockTexture(
texture_.get(),
nullptr, &pixels, &pitch) != 0) {
384 SDL_Log(
"SDL_LockTexture failed: %s\n", SDL_GetError());
388 memcpy(pixels, converted_surface->pixels,
389 converted_surface->h * converted_surface->pitch);
405 throw std::runtime_error(
"Surface is null. Palette not applied");
408 throw std::runtime_error(
409 "Surface format or palette is null. Palette not applied.");
413 SDL_Palette *sdl_palette =
surface_->format->palette;
414 if (sdl_palette ==
nullptr) {
415 throw std::runtime_error(
"Failed to get SDL palette");
419 for (
size_t i = 0; i <
palette.size(); ++i) {
421 sdl_palette->colors[i].r = pal_color.rgb().x;
422 sdl_palette->colors[i].g = pal_color.rgb().y;
423 sdl_palette->colors[i].b = pal_color.rgb().z;
424 sdl_palette->colors[i].a = pal_color.rgb().w;
431 auto start_index = palette_id * 8;
434 for (
size_t i = 0; i <
palette_.size(); ++i) {
436 if (pal_color.is_transparent()) {
437 surface_->format->palette->colors[i].r = 0;
438 surface_->format->palette->colors[i].g = 0;
439 surface_->format->palette->colors[i].b = 0;
440 surface_->format->palette->colors[i].a = 0;
442 surface_->format->palette->colors[i].r = pal_color.rgb().x;
443 surface_->format->palette->colors[i].g = pal_color.rgb().y;
444 surface_->format->palette->colors[i].b = pal_color.rgb().z;
445 surface_->format->palette->colors[i].a = pal_color.rgb().w;
453 if (index < 0 || index >=
palette.size()) {
454 throw std::invalid_argument(
"Invalid palette index");
457 if (length < 0 || length >
palette.size()) {
458 throw std::invalid_argument(
"Invalid palette length");
461 if (index + length >
palette.size()) {
462 throw std::invalid_argument(
"Palette index + length exceeds size");
466 throw std::runtime_error(
"Surface is null. Palette not applied");
469 auto start_index = index * 7;
471 std::vector<ImVec4> colors;
472 colors.push_back(ImVec4(0, 0, 0, 0));
473 for (
int i = start_index; i < start_index + 7; ++i) {
475 colors.push_back(pal_color.rgb());
480 for (
auto &each : colors) {
481 surface_->format->palette->colors[i].r = each.x;
482 surface_->format->palette->colors[i].g = each.y;
483 surface_->format->palette->colors[i].b = each.z;
484 surface_->format->palette->colors[i].a = each.w;
492 for (
size_t i = 0; i <
palette.size(); ++i) {
512 sdl_color.r =
static_cast<Uint8
>(color.x * 255);
513 sdl_color.g =
static_cast<Uint8
>(color.y * 255);
514 sdl_color.b =
static_cast<Uint8
>(color.z * 255);
515 sdl_color.a =
static_cast<Uint8
>(color.w * 255);
519 SDL_MapRGB(
surface_->format, sdl_color.r, sdl_color.g, sdl_color.b);
529 std::vector<uint8_t> &tile_data,
530 int &tile_data_offset) {
532 int tile_x = (x * 8) %
width_;
533 int tile_y = (y * 8) %
height_;
534 for (
int i = 0; i < 8; i++) {
535 for (
int j = 0; j < 8; j++) {
536 int pixel_offset = tile_offset + (tile_y + i) *
width_ + tile_x + j;
537 int pixel_value =
data_[pixel_offset];
538 tile_data[tile_data_offset] = pixel_value;
545 std::vector<uint8_t> &tile_data,
546 int &tile_data_offset) {
547 for (
int ty = 0; ty < 16; ty++) {
548 for (
int tx = 0; tx < 16; tx++) {
550 int pixel_x = tile_x + tx;
551 int pixel_y = tile_y + ty;
552 int pixel_offset = (pixel_y *
width_) + pixel_x;
553 int pixel_value =
data_[pixel_offset];
556 tile_data[tile_data_offset++] = pixel_value;
582std::vector<uint8_t> Bitmap::GetPngData() {
583 std::vector<uint8_t> png_data;
584 ConvertSurfaceToPng(
surface_.get(), png_data);
591 uint8_t palette_index) {
592 constexpr int kTileCount = 1024;
593 constexpr int kTileSize = 8;
594 std::vector<gfx::Bitmap> tile_bitmaps;
595 tile_bitmaps.reserve(kTileCount);
597 std::vector<std::future<gfx::Bitmap>> futures;
599 for (
int index = 0; index < kTileCount; ++index) {
600 futures.emplace_back(std::async(
601 std::launch::async, [&source_bmp, &palette, palette_index, index]() {
602 std::array<uint8_t, 0x40> tile_data;
604 int num_columns = source_bmp.
width() / kTileSize;
606 for (
int ty = 0; ty < kTileSize; ++ty) {
607 for (
int tx = 0; tx < kTileSize; ++tx) {
608 int tile_data_pos = tx + (ty * kTileSize);
609 int src_x = (index % num_columns) * kTileSize + tx;
610 int src_y = (index / num_columns) * kTileSize + ty;
611 int gfx_position = src_x + (src_y * 0x100);
613 uint8_t value = source_bmp.
data()[gfx_position];
619 tile_data[tile_data_pos] = value;
624 tile_bitmap.
Create(kTileSize, kTileSize, 8, tile_data);
630 for (
auto &future : futures) {
631 tile_bitmaps.push_back(future.get());
SDL_Texture * GetTexture(SDL_Renderer *renderer, int width, int height, Uint32 format)
void ReturnTexture(SDL_Texture *texture, int width, int height, Uint32 format)