Re-added SDL_Texture wrapper and render utils

These were from the last attempt at accelerated rendering. We might be getting somewhere this time...
This commit is contained in:
Charles Dang 2022-04-30 16:53:45 -04:00
parent fe69a7f501
commit 0a265d1c51
4 changed files with 369 additions and 0 deletions

View File

@ -1,6 +1,7 @@
sdl/exception.cpp
sdl/rect.cpp
sdl/surface.cpp
sdl/texture.cpp
sdl/utils.cpp
sdl/window.cpp
tracer.cpp

160
src/sdl/render_utils.hpp Normal file
View File

@ -0,0 +1,160 @@
/*
Copyright (C) 2017 - 2022
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
#include "sdl/rect.hpp"
#include "sdl/texture.hpp"
#include "video.hpp"
#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
#include <cassert>
#include <functional>
/**
* Sets the renderer output target to the specified texture.
*/
class render_target_setter
{
public:
explicit render_target_setter(texture& t)
: renderer_(CVideo::get_singleton().get_renderer())
, last_target_(nullptr)
{
if(renderer_) {
// Validate we can render to this texture.
assert(t.get_info().access == SDL_TEXTUREACCESS_TARGET);
last_target_ = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, t);
}
}
~render_target_setter()
{
if(renderer_) {
SDL_SetRenderTarget(renderer_, last_target_);
}
}
private:
SDL_Renderer* renderer_;
SDL_Texture* last_target_; // TODO: use the texture wrapper?
};
using sdl_rect_getter = void (*)(SDL_Renderer*, SDL_Rect*);
using sdl_rect_setter = int (*)(SDL_Renderer*, const SDL_Rect*);
/**
* Base class for renderer RAII helpers that operate on SDL_Rects.
*
* @tparam G Getter function. Will fetch the current applicable rect.
* That will be restored as the applicable state once this object is destroyed.
* @tparam S Setter function.
*/
template<sdl_rect_getter G, sdl_rect_setter S>
class render_raii_rect_setter_base
{
public:
explicit render_raii_rect_setter_base(SDL_Rect* rect)
: operate_(rect != nullptr)
, last_rect_()
, renderer_(CVideo::get_singleton().get_renderer())
{
if(renderer_ && operate_) {
std::invoke(G, renderer_, &last_rect_);
std::invoke(S, renderer_, rect);
}
}
~render_raii_rect_setter_base()
{
if(renderer_ && operate_) {
if(last_rect_ != sdl::empty_rect) {
std::invoke(S, renderer_, &last_rect_);
} else {
std::invoke(S, renderer_, nullptr);
}
}
}
private:
const bool operate_;
SDL_Rect last_rect_;
SDL_Renderer* renderer_;
};
/**
* Sets the renderer clip rect.
*/
using render_clip_rect_setter = render_raii_rect_setter_base<
&SDL_RenderGetClipRect,
&SDL_RenderSetClipRect>;
/**
* Sets the renderer viewport rect.
*/
using render_viewport_setter = render_raii_rect_setter_base<
&SDL_RenderGetViewport,
&SDL_RenderSetViewport>;
/**
* Set renderer drawing color.
*/
inline void set_draw_color(SDL_Renderer* renderer, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
SDL_SetRenderDrawColor(renderer, r, g, b, a);
}
/**
* Set renderer drawing color.
*/
inline void set_draw_color(SDL_Renderer* renderer, color_t color)
{
set_draw_color(renderer, color.r, color.g, color.b, color.a);
}
/*
* TEXTURE SETTERS =========================================================================
* Need to decide if these need their own file.
*/
inline void set_texture_alpha(texture& t, uint8_t amount)
{
SDL_SetTextureAlphaMod(t, amount);
}
inline void set_texture_blend_color(texture& t, uint8_t r, uint8_t g, uint8_t b)
{
SDL_SetTextureColorMod(t, r, g, b);
}
inline void set_texture_blend_mode(texture& t, SDL_BlendMode mode)
{
SDL_SetTextureBlendMode(t, mode);
}
/**
* Sets the texture scale quality. Note this should be called *before* a texture
* is created, since the hint has no effect on existing textures or render ops.
*
* @param value The scaling mode. Use either 'linear' or 'nearest'.
*/
inline void set_texture_scale_quality(const std::string& value)
{
SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, value.c_str(), SDL_HINT_OVERRIDE);
}

119
src/sdl/texture.cpp Normal file
View File

@ -0,0 +1,119 @@
/*
Copyright (C) 2017 - 2022
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "sdl/texture.hpp"
#include "log.hpp"
#include "sdl/render_utils.hpp"
#include "sdl/surface.hpp"
#include "video.hpp"
static lg::log_domain log_sdl("SDL");
#define ERR_SDL LOG_STREAM(err, log_sdl)
namespace
{
// The default pixel format to create textures with.
const int default_texture_format = SDL_PIXELFORMAT_ARGB8888;
void cleanup_texture(SDL_Texture* t)
{
if(t != nullptr) {
SDL_DestroyTexture(t);
;
}
}
} // namespace
texture::texture()
: texture_(nullptr)
{
}
texture::texture(SDL_Texture* txt)
: texture_(txt, &cleanup_texture)
{
finalize();
}
texture::texture(const surface& surf)
: texture_(nullptr)
{
SDL_Renderer* renderer = CVideo::get_singleton().get_renderer();
if(!renderer) {
return;
}
texture_.reset(SDL_CreateTextureFromSurface(renderer, surf), &cleanup_texture);
if(!texture_) {
ERR_SDL << "When creating texture from surface: " << SDL_GetError() << std::endl;
}
}
texture::texture(int w, int h, SDL_TextureAccess access)
: texture_(nullptr)
{
reset(w, h, access);
}
void texture::finalize()
{
set_texture_blend_mode(*this, SDL_BLENDMODE_BLEND);
}
void texture::reset()
{
if(texture_) {
texture_.reset();
}
}
void texture::reset(int w, int h, SDL_TextureAccess access)
{
// No-op if texture is null.
reset();
SDL_Renderer* renderer = CVideo::get_singleton().get_renderer();
if(!renderer) {
return;
}
texture_.reset(SDL_CreateTexture(renderer, default_texture_format, access, w, h), &cleanup_texture);
if(!texture_) {
ERR_SDL << "When creating texture: " << SDL_GetError() << std::endl;
}
finalize();
}
void texture::assign(SDL_Texture* t)
{
texture_.reset(t, &cleanup_texture);
}
texture& texture::operator=(texture&& t)
{
texture_ = std::move(t.texture_);
return *this;
}
texture::info::info(SDL_Texture* t)
: format(0)
, access(0)
, w(0)
, h(0)
{
SDL_QueryTexture(t, &format, &access, &w, &h);
}

89
src/sdl/texture.hpp Normal file
View File

@ -0,0 +1,89 @@
/*
Copyright (C) 2017 - 2022
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
#include <SDL2/SDL_render.h>
#include <memory>
class surface;
/**
* Wrapper class to encapsulate creation and management of an SDL_Texture.
* Supports free creation and creation from a surface.
*/
class texture
{
public:
/** Default ctor. Texture will be a nullptr. */
texture();
texture(const texture&) = default;
/** Assigns the given texture to this one. */
explicit texture(SDL_Texture* txt);
/** Construct a texture from a surface. */
explicit texture(const surface& surf);
/** Construct a texture of the specified size and access type. */
texture(int w, int h, SDL_TextureAccess access);
/** Small wrapper that queries metadata about the provided texture. */
struct info
{
explicit info(SDL_Texture* t);
uint32_t format;
int access;
int w;
int h;
};
/** Queries metadata about the texture, such as its dimensions. */
const info get_info() const
{
return info(*this);
}
/** Releases ownership of the managed texture and resets the ptr to null. */
void reset();
/** Releases ownership of the managed texture and creates a new one. */
void reset(int w, int h, SDL_TextureAccess access);
/** Replaces ownership of the managed texture with the given one. */
void assign(SDL_Texture* t);
texture& operator=(const texture& t) = default;
/** Move assignment. Releases ownership of the managed texture from the passed object. */
texture& operator=(texture&& t);
operator SDL_Texture*() const
{
return texture_.get();
}
bool null() const
{
return texture_ == nullptr;
}
private:
void finalize();
std::shared_ptr<SDL_Texture> texture_;
};