spacebox/src/Pixels.cpp

110 lines
2.9 KiB
C++

#include "Pixels.hpp"
Pixels::Pixels(SDL_Renderer* renderer, SDL_Texture* texture) : Pixels(renderer, texture, sfw::get_texture_box(texture)) {}
Pixels::Pixels(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect& rect) : texture(texture), rect(rect)
{
Uint32 format_enum;
int w, h;
SDL_QueryTexture(texture, &format_enum, &texture_access, &w, &h);
format = SDL_AllocFormat(format_enum);
if (texture_access == SDL_TEXTUREACCESS_STATIC || texture_access == SDL_TEXTUREACCESS_TARGET)
{
bool is_duplicate;
SDL_Texture* base;
if (texture_access == SDL_TEXTUREACCESS_STATIC)
{
base = sfw::duplicate_texture(renderer, texture);
is_duplicate = true;
}
else
{
base = texture;
is_duplicate = false;
}
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)
{
sfw::print_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)
{
sfw::print_sdl_error("could not lock texture");
}
}
else
{
sfw::print_error("unknown texture format for loading pixels");
}
}
int Pixels::get_bytes_per_row() const
{
return format->BytesPerPixel * rect.w;
}
Color Pixels::get(int x, int y)
{
std::uint32_t* pixel = operator()<std::uint32_t*>(x, y);
Color color;
SDL_GetRGBA(*pixel, const_cast<SDL_PixelFormat*>(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<SDL_PixelFormat*>(format), color.r, color.g, color.b, color.a);
if (format->BytesPerPixel == 1)
{
*operator()<std::uint8_t*>(x, y) = pixel;
}
else if (format->BytesPerPixel == 2)
{
*operator()<std::uint16_t*>(x, y) = pixel;
}
else
{
*operator()<std::uint32_t*>(x, y) = pixel;
}
}
void Pixels::apply()
{
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);
}