diff --git a/src/app/gfx/arena.cc b/src/app/gfx/arena.cc new file mode 100644 index 00000000..3b08348a --- /dev/null +++ b/src/app/gfx/arena.cc @@ -0,0 +1,117 @@ +#include "app/gfx/arena.h" + +#include + +#include "app/core/platform/sdl_deleter.h" + +namespace yaze { +namespace gfx { + +Arena& Arena::Get() { + static Arena instance; + return instance; +} + +Arena::Arena() { + layer1_buffer_.fill(0); + layer2_buffer_.fill(0); +} + +Arena::~Arena() { + textures_.clear(); + surfaces_.clear(); +} + +SDL_Texture* Arena::AllocateTexture(SDL_Renderer* renderer, int width, + int height) { + if (!renderer) { + SDL_Log("Invalid renderer passed to AllocateTexture"); + return nullptr; + } + + if (width <= 0 || height <= 0) { + SDL_Log("Invalid texture dimensions: width=%d, height=%d", width, height); + return nullptr; + } + + SDL_Texture* texture = + SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STREAMING, width, height); + if (!texture) { + SDL_Log("Failed to create texture: %s", SDL_GetError()); + return nullptr; + } + + textures_[texture] = + std::unique_ptr(texture); + return texture; +} + +void Arena::FreeTexture(SDL_Texture* texture) { + if (!texture) return; + + auto it = textures_.find(texture); + if (it != textures_.end()) { + textures_.erase(it); + } +} + +void Arena::UpdateTexture(SDL_Texture* texture, SDL_Surface* surface) { + if (!texture || !surface) { + SDL_Log("Invalid texture or surface passed to UpdateTexture"); + return; + } + + if (surface->pixels == nullptr) { + SDL_Log("Surface pixels are nullptr"); + return; + } + + auto converted_surface = + std::unique_ptr( + SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA8888, 0), + core::SDL_Surface_Deleter()); + + if (!converted_surface) { + SDL_Log("SDL_ConvertSurfaceFormat failed: %s", SDL_GetError()); + return; + } + + void* pixels; + int pitch; + if (SDL_LockTexture(texture, nullptr, &pixels, &pitch) != 0) { + SDL_Log("SDL_LockTexture failed: %s", SDL_GetError()); + return; + } + + memcpy(pixels, converted_surface->pixels, + converted_surface->h * converted_surface->pitch); + + SDL_UnlockTexture(texture); +} + +SDL_Surface* Arena::AllocateSurface(int width, int height, int depth, + int format) { + SDL_Surface* surface = + SDL_CreateRGBSurfaceWithFormat(0, width, height, depth, format); + if (!surface) { + SDL_Log("Failed to create surface: %s", SDL_GetError()); + return nullptr; + } + + surfaces_[surface] = + std::unique_ptr(surface); + return surface; +} + +void Arena::FreeSurface(SDL_Surface* surface) { + if (!surface) return; + + auto it = surfaces_.find(surface); + if (it != surfaces_.end()) { + surfaces_.erase(it); + } +} + +} // namespace gfx +} // namespace yaze \ No newline at end of file diff --git a/src/app/gfx/arena.h b/src/app/gfx/arena.h new file mode 100644 index 00000000..d25642fe --- /dev/null +++ b/src/app/gfx/arena.h @@ -0,0 +1,57 @@ +#ifndef YAZE_APP_GFX_ARENA_H +#define YAZE_APP_GFX_ARENA_H + +#include +#include +#include +#include + +#include "app/core/platform/sdl_deleter.h" +#include "app/gfx/background_buffer.h" + +namespace yaze { +namespace gfx { + +// Arena is a class that manages a collection of textures and surfaces +class Arena { + public: + static Arena& Get(); + + ~Arena(); + + SDL_Texture* AllocateTexture(SDL_Renderer* renderer, int width, int height); + void FreeTexture(SDL_Texture* texture); + void UpdateTexture(SDL_Texture* texture, SDL_Surface* surface); + + SDL_Surface* AllocateSurface(int width, int height, int depth, int format); + void FreeSurface(SDL_Surface* surface); + + auto& bg1() { return bg1_; } + auto& bg2() { return bg2_; } + + private: + Arena(); + + BackgroundBuffer bg1_; + BackgroundBuffer bg2_; + + static constexpr int kTilesPerRow = 64; + static constexpr int kTilesPerColumn = 64; + static constexpr int kTotalTiles = kTilesPerRow * kTilesPerColumn; + + std::array layer1_buffer_; + std::array layer2_buffer_; + + std::unordered_map> + textures_; + + std::unordered_map> + surfaces_; +}; + +} // namespace gfx +} // namespace yaze + +#endif // YAZE_APP_GFX_ARENA_H