154 lines
4.1 KiB
C++
154 lines
4.1 KiB
C++
#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()<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 == 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);
|
|
}
|