#include "Pixels.hpp" Pixels::Pixels(SDL_Renderer* renderer, SDL_Texture* texture, const Box& box) : texture(texture), renderer(renderer) { Uint32 format_enum; int w, h; if (texture == nullptr) { SDL_SetRenderTarget(renderer, nullptr); SDL_DisplayMode display_mode; if (SDL_GetCurrentDisplayMode(0, &display_mode) < 0) { sb::Log::sdl_error("could not get current display mode"); } if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) { sb::Log::sdl_error("could not get renderer output size"); } format_enum = display_mode.format; texture_access = TEXTURE_ACCESS_SCREEN; } else { SDL_QueryTexture(texture, &format_enum, &texture_access, &w, &h); } format = SDL_AllocFormat(format_enum); if (box.fits({{0, 0}, {w, h}})) { rect = box; } else { Box cropped = box; cropped.crop({{0, 0}, {w, h}}); rect = cropped; } if (texture == nullptr || texture_access == SDL_TEXTUREACCESS_STATIC || texture_access == SDL_TEXTUREACCESS_TARGET) { bool is_duplicate = false; SDL_Texture* base; if (texture == nullptr) { base = nullptr; } else if (texture_access == SDL_TEXTUREACCESS_STATIC) { base = sb::duplicate_texture(renderer, texture); is_duplicate = true; } else { base = texture; } SDL_SetRenderTarget(renderer, base); int bytes_total = get_bytes_per_row() * rect.h; source = operator new(bytes_total); if (SDL_RenderReadPixels(renderer, &rect, format->format, source, format->BytesPerPixel * rect.w) < 0) { sb::Log::sdl_error("could not read pixels"); operator delete(source); } else { allocated = true; } if (is_duplicate) { SDL_DestroyTexture(base); } } else if (texture_access == SDL_TEXTUREACCESS_STREAMING) { int pitch; if (SDL_LockTexture(texture, &rect, &source, &pitch) < 0) { sb::Log::sdl_error("could not lock texture"); } } else { sb::Log::log("unknown texture format for loading pixels", sb::Log::Level::ERR); } } Pixels::Pixels(SDL_Renderer* renderer, SDL_Texture* texture) : Pixels(renderer, texture, sb::get_texture_box(texture)) {} int Pixels::get_bytes_per_row() const { return format->BytesPerPixel * rect.w; } Color Pixels::get(int x, int y) { std::uint32_t* pixel = operator()(x, y); Color color; SDL_GetRGBA(*pixel, const_cast(format), &color.r, &color.g, &color.b, &color.a); return color; } void Pixels::set(const SDL_Color& color, int x, int y) { std::uint32_t pixel = SDL_MapRGBA(const_cast(format), color.r, color.g, color.b, color.a); if (format->BytesPerPixel == 1) { *operator()(x, y) = pixel; } else if (format->BytesPerPixel == 2) { *operator()(x, y) = pixel; } else { *operator()(x, y) = pixel; } } void Pixels::apply() { if (texture_access == TEXTURE_ACCESS_SCREEN) { SDL_SetRenderTarget(renderer, nullptr); for (int x = rect.x; x < rect.x + rect.w; x++) { for (int y = rect.y; y < rect.y + rect.h; y++) { SDL_SetRenderDrawColor(renderer, get(x, y)); SDL_RenderDrawPoint(renderer, x, y); } } } else if (texture_access == SDL_TEXTUREACCESS_STATIC || texture_access == SDL_TEXTUREACCESS_TARGET) { SDL_UpdateTexture(texture, &rect, source, get_bytes_per_row()); } else { SDL_UnlockTexture(texture); } } Pixels::~Pixels() { if (allocated) { operator delete(source); } if (texture_access == SDL_TEXTUREACCESS_STREAMING) { SDL_UnlockTexture(texture); } SDL_FreeFormat(format); }