Refactor Bitmap class to improve texture management and memory tracking; implement custom allocators for SDL_Surface and SDL_Texture, enhance bitmap constructors, and add utility functions for tile extraction and pixel manipulation.
This commit is contained in:
@@ -8,17 +8,18 @@
|
||||
#include <cstdint>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/platform/renderer.h"
|
||||
#include "app/core/platform/memory_tracker.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/texture_pool.h"
|
||||
#include "util/macro.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace gfx {
|
||||
|
||||
using core::SDL_Surface_Deleter;
|
||||
using core::SDL_Texture_Deleter;
|
||||
|
||||
#if YAZE_LIB_PNG == 1
|
||||
|
||||
@@ -183,15 +184,9 @@ void ConvertPngToSurface(const std::vector<uint8_t> &png_data,
|
||||
SDL_Log("Successfully created SDL_Surface from PNG data");
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Bitmap::GetPngData() {
|
||||
std::vector<uint8_t> png_data;
|
||||
ConvertSurfaceToPng(surface_.get(), png_data);
|
||||
return png_data;
|
||||
}
|
||||
|
||||
#endif // YAZE_LIB_PNG
|
||||
|
||||
namespace {
|
||||
// Utility functions
|
||||
Uint32 GetSnesPixelFormat(int format) {
|
||||
switch (format) {
|
||||
case 0:
|
||||
@@ -205,7 +200,50 @@ Uint32 GetSnesPixelFormat(int format) {
|
||||
}
|
||||
return SDL_PIXELFORMAT_INDEX8;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Custom allocator for SDL_Surface
|
||||
SDL_Surface* AllocateSurface(int width, int height, int depth, Uint32 format) {
|
||||
SDL_Surface *surface =
|
||||
SDL_CreateRGBSurfaceWithFormat(0, width, height, depth, format);
|
||||
if (surface) {
|
||||
core::MemoryTracker::GetInstance().TrackAllocation(
|
||||
surface, width * height * (depth / 8), "SDL_Surface");
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
// Custom allocator for SDL_Texture
|
||||
SDL_Texture* AllocateTexture(SDL_Renderer *renderer, Uint32 format, int access,
|
||||
int width, int height) {
|
||||
SDL_Texture *texture =
|
||||
SDL_CreateTexture(renderer, format, access, width, height);
|
||||
if (texture) {
|
||||
// Estimate size (this is approximate)
|
||||
size_t estimated_size = width * height * 4; // Assume 4 bytes per pixel
|
||||
core::MemoryTracker::GetInstance().TrackAllocation(texture, estimated_size,
|
||||
"SDL_Texture");
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Bitmap class implementation
|
||||
Bitmap::Bitmap(int width, int height, int depth, const std::vector<uint8_t> &data)
|
||||
: width_(width), height_(height), depth_(depth), data_(data) {
|
||||
Create(width, height, depth, data);
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(int width, int height, int depth, const std::vector<uint8_t> &data,
|
||||
const SnesPalette &palette)
|
||||
: width_(width),
|
||||
height_(height),
|
||||
depth_(depth),
|
||||
data_(data),
|
||||
palette_(palette) {
|
||||
Create(width, height, depth, data);
|
||||
if (!SetPalette(palette).ok()) {
|
||||
std::cerr << "Error applying palette in bitmap constructor." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::SaveSurfaceToFile(std::string_view filename) {
|
||||
SDL_SaveBMP(surface_.get(), filename.data());
|
||||
@@ -226,7 +264,7 @@ void Bitmap::Create(int width, int height, int depth, std::span<uint8_t> data) {
|
||||
|
||||
void Bitmap::Create(int width, int height, int depth,
|
||||
const std::vector<uint8_t> &data) {
|
||||
Create(width, height, depth, kIndexed, data);
|
||||
Create(width, height, depth, static_cast<int>(BitmapFormat::kIndexed), data);
|
||||
}
|
||||
|
||||
void Bitmap::Create(int width, int height, int depth, int format,
|
||||
@@ -249,8 +287,7 @@ void Bitmap::Create(int width, int height, int depth, int format,
|
||||
data_ = data;
|
||||
pixel_data_ = data_.data();
|
||||
surface_ = std::shared_ptr<SDL_Surface>{
|
||||
SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_,
|
||||
GetSnesPixelFormat(format)),
|
||||
AllocateSurface(width_, height_, depth_, GetSnesPixelFormat(format)),
|
||||
SDL_Surface_Deleter{}};
|
||||
if (surface_ == nullptr) {
|
||||
SDL_Log("Bitmap::Create.SDL_CreateRGBSurfaceWithFormat failed: %s\n",
|
||||
@@ -264,8 +301,7 @@ void Bitmap::Create(int width, int height, int depth, int format,
|
||||
|
||||
void Bitmap::Reformat(int format) {
|
||||
surface_ = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
|
||||
SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_,
|
||||
GetSnesPixelFormat(format)),
|
||||
AllocateSurface(width_, height_, depth_, GetSnesPixelFormat(format)),
|
||||
SDL_Surface_Deleter());
|
||||
surface_->pixels = pixel_data_;
|
||||
active_ = true;
|
||||
@@ -276,39 +312,6 @@ void Bitmap::Reformat(int format) {
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::CreateTexture(SDL_Renderer *renderer) {
|
||||
if (width_ <= 0 || height_ <= 0) {
|
||||
SDL_Log("Invalid texture dimensions: width=%d, height=%d\n", width_,
|
||||
height_);
|
||||
return;
|
||||
}
|
||||
|
||||
texture_ = std::shared_ptr<SDL_Texture>{
|
||||
SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888,
|
||||
SDL_TEXTUREACCESS_STREAMING, width_, height_),
|
||||
SDL_Texture_Deleter{}};
|
||||
if (texture_ == nullptr) {
|
||||
SDL_Log("Bitmap::CreateTexture.SDL_CreateTextureFromSurface failed: %s\n",
|
||||
SDL_GetError());
|
||||
}
|
||||
texture_pixels = data_.data();
|
||||
|
||||
auto converted_surface_ = std::shared_ptr<SDL_Surface>{
|
||||
SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
|
||||
SDL_Surface_Deleter{}};
|
||||
if (converted_surface_ == nullptr) {
|
||||
SDL_Log("Bitmap::CreateTexture.SDL_ConvertSurfaceFormat failed: %s\n",
|
||||
SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_LockTexture(texture_.get(), nullptr, (void **)&texture_pixels,
|
||||
&converted_surface_->pitch);
|
||||
memcpy(texture_pixels, converted_surface_->pixels,
|
||||
converted_surface_->h * converted_surface_->pitch);
|
||||
SDL_UnlockTexture(texture_.get());
|
||||
}
|
||||
|
||||
void Bitmap::UpdateTexture(SDL_Renderer *renderer) {
|
||||
auto converted_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
|
||||
SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
|
||||
@@ -324,6 +327,86 @@ void Bitmap::UpdateTexture(SDL_Renderer *renderer) {
|
||||
SDL_UnlockTexture(texture_.get());
|
||||
}
|
||||
|
||||
void Bitmap::CreateTexture(SDL_Renderer *renderer) {
|
||||
if (!renderer) {
|
||||
SDL_Log("Invalid renderer passed to CreateTexture");
|
||||
return;
|
||||
}
|
||||
|
||||
if (width_ <= 0 || height_ <= 0) {
|
||||
SDL_Log("Invalid texture dimensions: width=%d, height=%d\n", width_,
|
||||
height_);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we already have a texture, don't create a new one
|
||||
if (texture_) {
|
||||
texture_in_use_ = true;
|
||||
last_used_time_ = SDL_GetTicks64();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a texture from the pool
|
||||
SDL_Texture *raw_texture = TexturePool::GetInstance().GetTexture(
|
||||
renderer, width_, height_, SDL_PIXELFORMAT_RGB888);
|
||||
|
||||
if (!raw_texture) {
|
||||
SDL_Log("Bitmap::CreateTexture failed to get texture from pool: %s\n",
|
||||
SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a shared_ptr with a custom deleter that returns the texture to the
|
||||
// pool
|
||||
texture_ = std::shared_ptr<SDL_Texture>(raw_texture, [this](SDL_Texture *t) {
|
||||
if (t) {
|
||||
TexturePool::GetInstance().ReturnTexture(t, width_, height_,
|
||||
SDL_PIXELFORMAT_RGB888);
|
||||
}
|
||||
});
|
||||
|
||||
texture_in_use_ = true;
|
||||
last_used_time_ = SDL_GetTicks64();
|
||||
|
||||
UpdateTextureData();
|
||||
}
|
||||
|
||||
void Bitmap::UpdateTextureData() {
|
||||
if (!texture_ || !surface_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto converted_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
|
||||
SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
|
||||
SDL_Surface_Deleter());
|
||||
|
||||
if (converted_surface == nullptr) {
|
||||
SDL_Log("SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
void *pixels;
|
||||
int pitch;
|
||||
if (SDL_LockTexture(texture_.get(), nullptr, &pixels, &pitch) != 0) {
|
||||
SDL_Log("SDL_LockTexture failed: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(pixels, converted_surface->pixels,
|
||||
converted_surface->h * converted_surface->pitch);
|
||||
|
||||
SDL_UnlockTexture(texture_.get());
|
||||
modified_ = false;
|
||||
}
|
||||
|
||||
void Bitmap::CleanupUnusedTexture(uint64_t current_time, uint64_t timeout) {
|
||||
if (texture_ && !texture_in_use_ &&
|
||||
(current_time - last_used_time_ > timeout)) {
|
||||
// Release the texture back to the pool
|
||||
texture_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status Bitmap::SetPalette(const SnesPalette &palette) {
|
||||
if (surface_ == nullptr) {
|
||||
return absl::FailedPreconditionError(
|
||||
@@ -349,7 +432,6 @@ absl::Status Bitmap::SetPalette(const SnesPalette &palette) {
|
||||
sdl_palette->colors[i].a = pal_color.rgb().w;
|
||||
}
|
||||
SDL_LockSurface(surface_.get());
|
||||
// SDL_RETURN_IF_ERROR()
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
@@ -373,7 +455,6 @@ absl::Status Bitmap::SetPaletteFromPaletteGroup(const SnesPalette &palette,
|
||||
}
|
||||
}
|
||||
SDL_LockSurface(surface_.get());
|
||||
// SDL_RETURN_IF_ERROR()
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
@@ -415,7 +496,6 @@ absl::Status Bitmap::SetPaletteWithTransparent(const SnesPalette &palette,
|
||||
i++;
|
||||
}
|
||||
SDL_LockSurface(surface_.get());
|
||||
// SDL_RETURN_IF_ERROR()
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
@@ -430,6 +510,33 @@ void Bitmap::SetPalette(const std::vector<SDL_Color> &palette) {
|
||||
SDL_LockSurface(surface_.get());
|
||||
}
|
||||
|
||||
void Bitmap::WriteToPixel(int position, uint8_t value) {
|
||||
if (pixel_data_ == nullptr) {
|
||||
pixel_data_ = data_.data();
|
||||
}
|
||||
pixel_data_[position] = value;
|
||||
modified_ = true;
|
||||
}
|
||||
|
||||
void Bitmap::WriteColor(int position, const ImVec4 &color) {
|
||||
// Convert ImVec4 (RGBA) to SDL_Color (RGBA)
|
||||
SDL_Color sdl_color;
|
||||
sdl_color.r = static_cast<Uint8>(color.x * 255);
|
||||
sdl_color.g = static_cast<Uint8>(color.y * 255);
|
||||
sdl_color.b = static_cast<Uint8>(color.z * 255);
|
||||
sdl_color.a = static_cast<Uint8>(color.w * 255);
|
||||
|
||||
// Map SDL_Color to the nearest color index in the surface's palette
|
||||
Uint8 index =
|
||||
SDL_MapRGB(surface_->format, sdl_color.r, sdl_color.g, sdl_color.b);
|
||||
|
||||
// Write the color index to the pixel data
|
||||
pixel_data_[position] = index;
|
||||
data_[position] = ConvertRgbToSnes(color);
|
||||
|
||||
modified_ = true;
|
||||
}
|
||||
|
||||
void Bitmap::Get8x8Tile(int tile_index, int x, int y,
|
||||
std::vector<uint8_t> &tile_data,
|
||||
int &tile_data_offset) {
|
||||
@@ -463,23 +570,84 @@ void Bitmap::Get16x16Tile(int tile_x, int tile_y,
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::WriteColor(int position, const ImVec4 &color) {
|
||||
// Convert ImVec4 (RGBA) to SDL_Color (RGBA)
|
||||
SDL_Color sdl_color;
|
||||
sdl_color.r = static_cast<Uint8>(color.x * 255);
|
||||
sdl_color.g = static_cast<Uint8>(color.y * 255);
|
||||
sdl_color.b = static_cast<Uint8>(color.z * 255);
|
||||
sdl_color.a = static_cast<Uint8>(color.w * 255);
|
||||
void Bitmap::Cleanup() {
|
||||
active_ = false;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
depth_ = 0;
|
||||
data_size_ = 0;
|
||||
palette_.clear();
|
||||
}
|
||||
|
||||
// Map SDL_Color to the nearest color index in the surface's palette
|
||||
Uint8 index =
|
||||
SDL_MapRGB(surface_->format, sdl_color.r, sdl_color.g, sdl_color.b);
|
||||
void Bitmap::Clear() {
|
||||
active_ = false;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
depth_ = 0;
|
||||
data_size_ = 0;
|
||||
data_.clear();
|
||||
pixel_data_ = nullptr;
|
||||
texture_pixels = nullptr;
|
||||
}
|
||||
|
||||
// Write the color index to the pixel data
|
||||
pixel_data_[position] = index;
|
||||
data_[position] = ConvertRgbToSnes(color);
|
||||
#if YAZE_LIB_PNG == 1
|
||||
std::vector<uint8_t> Bitmap::GetPngData() {
|
||||
std::vector<uint8_t> png_data;
|
||||
ConvertSurfaceToPng(surface_.get(), png_data);
|
||||
return png_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
modified_ = true;
|
||||
std::vector<gfx::Bitmap> ExtractTile8Bitmaps(const gfx::Bitmap &source_bmp,
|
||||
const gfx::SnesPalette &palette,
|
||||
uint8_t palette_index) {
|
||||
constexpr int kTileCount = 1024;
|
||||
constexpr int kTileSize = 8;
|
||||
std::vector<gfx::Bitmap> tile_bitmaps;
|
||||
tile_bitmaps.reserve(kTileCount);
|
||||
|
||||
std::vector<std::future<gfx::Bitmap>> futures;
|
||||
|
||||
for (int index = 0; index < kTileCount; ++index) {
|
||||
futures.emplace_back(std::async(std::launch::async, [&source_bmp, &palette,
|
||||
palette_index,
|
||||
index]() {
|
||||
std::array<uint8_t, 0x40> tile_data;
|
||||
|
||||
int num_columns = source_bmp.width() / kTileSize;
|
||||
|
||||
for (int ty = 0; ty < kTileSize; ++ty) {
|
||||
for (int tx = 0; tx < kTileSize; ++tx) {
|
||||
int tile_data_pos = tx + (ty * kTileSize);
|
||||
int src_x = (index % num_columns) * kTileSize + tx;
|
||||
int src_y = (index / num_columns) * kTileSize + ty;
|
||||
int gfx_position = src_x + (src_y * 0x100);
|
||||
|
||||
uint8_t value = source_bmp.data()[gfx_position];
|
||||
|
||||
if (value & 0x80) {
|
||||
value -= 0x88;
|
||||
}
|
||||
|
||||
tile_data[tile_data_pos] = value;
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Bitmap tile_bitmap;
|
||||
tile_bitmap.Create(kTileSize, kTileSize, 8, tile_data);
|
||||
if (!tile_bitmap.SetPaletteWithTransparent(palette, palette_index).ok()) {
|
||||
SDL_Log("Failed to set palette for tile %d\n", index);
|
||||
throw std::runtime_error("Failed to set palette for tile");
|
||||
}
|
||||
return tile_bitmap;
|
||||
}));
|
||||
}
|
||||
|
||||
for (auto &future : futures) {
|
||||
tile_bitmaps.push_back(future.get());
|
||||
}
|
||||
|
||||
return tile_bitmaps;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/platform/sdl_deleter.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "util/macro.h"
|
||||
|
||||
namespace yaze {
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace yaze {
|
||||
*/
|
||||
namespace gfx {
|
||||
|
||||
// Same as SDL_PIXELFORMAT_INDEX8 for reference
|
||||
// Pixel format constants
|
||||
constexpr Uint32 SNES_PIXELFORMAT_INDEXED =
|
||||
SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX8, 0, 0, 8, 1);
|
||||
|
||||
@@ -66,39 +66,53 @@ void ConvertPngToSurface(const std::vector<uint8_t> &png_data,
|
||||
*/
|
||||
class Bitmap {
|
||||
public:
|
||||
// Constructors
|
||||
Bitmap() = default;
|
||||
Bitmap(int width, int height, int depth, const std::vector<uint8_t> &data)
|
||||
: width_(width), height_(height), depth_(depth), data_(data) {
|
||||
Create(width, height, depth, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a bitmap with the given dimensions and data
|
||||
*/
|
||||
Bitmap(int width, int height, int depth, const std::vector<uint8_t> &data);
|
||||
|
||||
/**
|
||||
* @brief Create a bitmap with the given dimensions, data, and palette
|
||||
*/
|
||||
Bitmap(int width, int height, int depth, const std::vector<uint8_t> &data,
|
||||
const SnesPalette &palette)
|
||||
: width_(width),
|
||||
height_(height),
|
||||
depth_(depth),
|
||||
data_(data),
|
||||
palette_(palette) {
|
||||
Create(width, height, depth, data);
|
||||
if (!SetPalette(palette).ok()) {
|
||||
std::cerr << "Error applying palette in bitmap constructor." << std::endl;
|
||||
}
|
||||
}
|
||||
const SnesPalette &palette);
|
||||
|
||||
/**
|
||||
* @brief Initialize the bitmap with the given dimensions and data
|
||||
*/
|
||||
void Initialize(int width, int height, int depth, std::span<uint8_t> &data);
|
||||
|
||||
#if YAZE_LIB_PNG == 1
|
||||
std::vector<uint8_t> GetPngData();
|
||||
#endif
|
||||
|
||||
void SaveSurfaceToFile(std::string_view filename);
|
||||
|
||||
/**
|
||||
* @brief Create a bitmap with the given dimensions and data
|
||||
*/
|
||||
void Create(int width, int height, int depth, std::span<uint8_t> data);
|
||||
|
||||
/**
|
||||
* @brief Create a bitmap with the given dimensions and data
|
||||
*/
|
||||
void Create(int width, int height, int depth,
|
||||
const std::vector<uint8_t> &data);
|
||||
|
||||
/**
|
||||
* @brief Create a bitmap with the given dimensions, format, and data
|
||||
*/
|
||||
void Create(int width, int height, int depth, int format,
|
||||
const std::vector<uint8_t> &data);
|
||||
|
||||
/**
|
||||
* @brief Reformat the bitmap to use a different pixel format
|
||||
*/
|
||||
void Reformat(int format);
|
||||
|
||||
/**
|
||||
* @brief Save the bitmap surface to a file
|
||||
*/
|
||||
void SaveSurfaceToFile(std::string_view filename);
|
||||
|
||||
// Texture management
|
||||
/**
|
||||
* @brief Creates the underlying SDL_Texture to be displayed.
|
||||
*
|
||||
@@ -113,60 +127,97 @@ class Bitmap {
|
||||
void UpdateTexture(SDL_Renderer *renderer);
|
||||
|
||||
/**
|
||||
* @brief Copy color data from the SnesPalette into the SDL_Palette
|
||||
* @brief Updates the texture data from the surface
|
||||
*/
|
||||
void UpdateTextureData();
|
||||
|
||||
/**
|
||||
* @brief Clean up unused textures after a timeout
|
||||
*/
|
||||
void CleanupUnusedTexture(uint64_t current_time, uint64_t timeout);
|
||||
|
||||
// Palette management
|
||||
/**
|
||||
* @brief Set the palette for the bitmap
|
||||
*/
|
||||
absl::Status SetPalette(const SnesPalette &palette);
|
||||
|
||||
/**
|
||||
* @brief Set the palette with a transparent color
|
||||
*/
|
||||
absl::Status SetPaletteWithTransparent(const SnesPalette &palette,
|
||||
size_t index, int length = 7);
|
||||
void SetPalette(const std::vector<SDL_Color> &palette);
|
||||
|
||||
/**
|
||||
* @brief Set the palette from a palette group
|
||||
*/
|
||||
absl::Status SetPaletteFromPaletteGroup(const SnesPalette &palette,
|
||||
int palette_id);
|
||||
|
||||
/**
|
||||
* @brief Set the palette using SDL colors
|
||||
*/
|
||||
void SetPalette(const std::vector<SDL_Color> &palette);
|
||||
|
||||
// Pixel operations
|
||||
/**
|
||||
* @brief Write a value to a pixel at the given position
|
||||
*/
|
||||
void WriteToPixel(int position, uint8_t value);
|
||||
|
||||
/**
|
||||
* @brief Write a color to a pixel at the given position
|
||||
*/
|
||||
void WriteColor(int position, const ImVec4 &color);
|
||||
|
||||
// Tile operations
|
||||
/**
|
||||
* @brief Extract an 8x8 tile from the bitmap
|
||||
*/
|
||||
void Get8x8Tile(int tile_index, int x, int y, std::vector<uint8_t> &tile_data,
|
||||
int &tile_data_offset);
|
||||
|
||||
/**
|
||||
* @brief Extract a 16x16 tile from the bitmap
|
||||
*/
|
||||
void Get16x16Tile(int tile_x, int tile_y, std::vector<uint8_t> &tile_data,
|
||||
int &tile_data_offset);
|
||||
|
||||
void WriteToPixel(int position, uint8_t value) {
|
||||
if (pixel_data_ == nullptr) {
|
||||
pixel_data_ = data_.data();
|
||||
}
|
||||
pixel_data_[position] = value;
|
||||
modified_ = true;
|
||||
}
|
||||
|
||||
void WriteColor(int position, const ImVec4 &color);
|
||||
|
||||
void Cleanup() {
|
||||
active_ = false;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
depth_ = 0;
|
||||
data_size_ = 0;
|
||||
palette_.clear();
|
||||
}
|
||||
|
||||
auto palette() const { return palette_; }
|
||||
auto mutable_palette() { return &palette_; }
|
||||
/**
|
||||
* @brief Clean up the bitmap resources
|
||||
*/
|
||||
void Cleanup();
|
||||
|
||||
/**
|
||||
* @brief Clear the bitmap data
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
const SnesPalette& palette() const { return palette_; }
|
||||
SnesPalette* mutable_palette() { return &palette_; }
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
auto depth() const { return depth_; }
|
||||
auto size() const { return data_size_; }
|
||||
auto data() const { return data_.data(); }
|
||||
auto &mutable_data() { return data_; }
|
||||
auto surface() const { return surface_.get(); }
|
||||
|
||||
auto vector() const { return data_; }
|
||||
auto at(int i) const { return data_[i]; }
|
||||
auto texture() const { return texture_.get(); }
|
||||
auto modified() const { return modified_; }
|
||||
auto is_active() const { return active_; }
|
||||
int depth() const { return depth_; }
|
||||
int size() const { return data_size_; }
|
||||
const uint8_t* data() const { return data_.data(); }
|
||||
std::vector<uint8_t>& mutable_data() { return data_; }
|
||||
SDL_Surface* surface() const { return surface_.get(); }
|
||||
SDL_Texture* texture() const { return texture_.get(); }
|
||||
const std::vector<uint8_t>& vector() const { return data_; }
|
||||
uint8_t at(int i) const { return data_[i]; }
|
||||
bool modified() const { return modified_; }
|
||||
bool is_active() const { return active_; }
|
||||
void set_active(bool active) { active_ = active; }
|
||||
void set_data(const std::vector<uint8_t> &data) { data_ = data; }
|
||||
void set_modified(bool modified) { modified_ = modified; }
|
||||
|
||||
#if YAZE_LIB_PNG == 1
|
||||
/**
|
||||
* @brief Get the bitmap data as PNG
|
||||
*/
|
||||
std::vector<uint8_t> GetPngData();
|
||||
#endif
|
||||
|
||||
private:
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
@@ -175,18 +226,59 @@ class Bitmap {
|
||||
|
||||
bool active_ = false;
|
||||
bool modified_ = false;
|
||||
|
||||
// Track if this texture is currently in use
|
||||
bool texture_in_use_ = false;
|
||||
|
||||
// Track the last time this texture was used
|
||||
uint64_t last_used_time_ = 0;
|
||||
|
||||
// Pointer to the texture pixels
|
||||
void *texture_pixels = nullptr;
|
||||
|
||||
// Pointer to the pixel data
|
||||
uint8_t *pixel_data_ = nullptr;
|
||||
std::vector<uint8_t> data_;
|
||||
|
||||
// Palette for the bitmap
|
||||
gfx::SnesPalette palette_;
|
||||
std::shared_ptr<SDL_Texture> texture_ = nullptr;
|
||||
|
||||
// Data for the bitmap
|
||||
std::vector<uint8_t> data_;
|
||||
|
||||
// Surface for the bitmap
|
||||
std::shared_ptr<SDL_Surface> surface_ = nullptr;
|
||||
|
||||
// Texture for the bitmap
|
||||
std::shared_ptr<SDL_Texture> texture_ = nullptr;
|
||||
};
|
||||
|
||||
// Type alias for a table of bitmaps
|
||||
using BitmapTable = std::unordered_map<int, gfx::Bitmap>;
|
||||
|
||||
// Utility functions that operate on Bitmap objects
|
||||
/**
|
||||
* @brief Extract 8x8 tiles from a source bitmap
|
||||
*/
|
||||
std::vector<gfx::Bitmap> ExtractTile8Bitmaps(const gfx::Bitmap &source_bmp,
|
||||
const gfx::SnesPalette &palette,
|
||||
uint8_t palette_index);
|
||||
|
||||
/**
|
||||
* @brief Get the SDL pixel format for a given bitmap format
|
||||
*/
|
||||
Uint32 GetSnesPixelFormat(int format);
|
||||
|
||||
/**
|
||||
* @brief Allocate an SDL surface with the given dimensions and format
|
||||
*/
|
||||
SDL_Surface* AllocateSurface(int width, int height, int depth, Uint32 format);
|
||||
|
||||
/**
|
||||
* @brief Allocate an SDL texture with the given dimensions and format
|
||||
*/
|
||||
SDL_Texture* AllocateTexture(SDL_Renderer *renderer, Uint32 format, int access,
|
||||
int width, int height);
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
Reference in New Issue
Block a user