Move clip and render target setters from CVideo to draw.

CVideo::set_clip -> draw::set_clip
CVideo::set_render_target -> draw::set_render_target
etc.
This commit is contained in:
Tommy 2022-06-03 13:48:26 +12:00
parent 9f1ef7b344
commit c1fa2bed0b
16 changed files with 198 additions and 179 deletions

View File

@ -804,8 +804,8 @@ surface display::screenshot(bool map_screenshot)
LOG_DP << "creating " << area.w << " by " << area.h
<< " texture for map screenshot" << std::endl;
texture output_texture(area.w, area.h, SDL_TEXTUREACCESS_TARGET);
auto target_setter = video().set_render_target(output_texture);
auto clipper = video().set_clip(area);
auto target_setter = draw::set_render_target(output_texture);
auto clipper = draw::set_clip(area);
map_screenshot_ = true;
dirty_ = true;
@ -1274,7 +1274,7 @@ void display::drawing_buffer_commit()
// std::list::sort() is a stable sort
drawing_buffer_.sort();
auto clipper = screen_.set_clip(map_area());
auto clipper = draw::set_clip(map_area());
/*
* Info regarding the rendering algorithm.
@ -1754,7 +1754,7 @@ void display::draw_minimap()
}
// TODO: highdpi - does this really need to set a clipping area?
auto clipper = screen_.set_clip(area);
auto clipper = draw::set_clip(area);
// Draw the minimap background.
draw::fill(area, 31, 31, 23);
@ -2479,7 +2479,7 @@ const SDL_Rect& display::get_clip_rect()
void display::draw_invalidated() {
// log_scope("display::draw_invalidated");
SDL_Rect clip_rect = get_clip_rect();
auto clipper = screen_.set_clip(clip_rect);
auto clipper = draw::set_clip(clip_rect);
for (const map_location& loc : invalidated_) {
int xpos = get_location_x(loc);
int ypos = get_location_y(loc);

View File

@ -15,6 +15,7 @@
#include "draw.hpp"
#include "color.hpp"
#include "sdl/rect.hpp"
#include "sdl/surface.hpp"
#include "sdl/texture.hpp"
#include "video.hpp"
@ -276,7 +277,7 @@ void draw::tiled(const texture& tex, const SDL_Rect& dst, bool centered,
// TODO: highdpi - should this draw at full res? Or game res? For now it's using game res. To draw in higher res, width and height would have to be specified.
// Reduce clip to dst.
auto clipper = CVideo::get_singleton().reduce_clip(dst);
auto clipper = draw::reduce_clip(dst);
const int xoff = centered ? (dst.w - tex.w()) / 2 : 0;
const int yoff = centered ? (dst.h - tex.h()) / 2 : 0;
@ -295,3 +296,80 @@ void draw::tiled(const texture& tex, const SDL_Rect& dst, bool centered,
}
}
}
/***************************/
/* RAII state manipulation */
/***************************/
draw::clip_setter::clip_setter(const SDL_Rect& clip)
: c_()
{
c_ = draw::get_clip();
draw::force_clip(clip);
}
draw::clip_setter::~clip_setter()
{
draw::force_clip(c_);
}
draw::clip_setter draw::set_clip(const SDL_Rect& clip)
{
return draw::clip_setter(clip);
}
draw::clip_setter draw::reduce_clip(const SDL_Rect& clip)
{
SDL_Rect c = draw::get_clip();
if (c == sdl::empty_rect) {
return draw::clip_setter(clip);
} else {
return draw::clip_setter(sdl::intersect_rects(clip, c));
}
}
void draw::force_clip(const SDL_Rect& clip)
{
// TODO: highdpi - fix whatever reason there is for this guard (CI fail)
if (!renderer()) { return; }
SDL_RenderSetClipRect(renderer(), &clip);
}
SDL_Rect draw::get_clip()
{
// TODO: highdpi - fix whatever reason there is for this guard (CI fail)
if (!renderer()) {
return sdl::empty_rect;
}
SDL_Rect clip;
SDL_RenderGetClipRect(renderer(), &clip);
if (clip == sdl::empty_rect) {
// TODO: highdpi - fix this in the case of render to texture
return CVideo::get_singleton().draw_area();
}
return clip;
}
draw::render_target_setter::render_target_setter(const texture& t)
: t_(nullptr)
{
// Validate we can render to this texture.
assert(t.get_info().access == SDL_TEXTUREACCESS_TARGET);
t_ = CVideo::get_singleton().get_render_target();
CVideo::get_singleton().force_render_target(t);
}
draw::render_target_setter::~render_target_setter()
{
CVideo::get_singleton().force_render_target(t_);
}
draw::render_target_setter draw::set_render_target(const texture& t)
{
return draw::render_target_setter(t);
}

View File

@ -35,6 +35,7 @@
struct color_t;
class surface;
class texture;
struct SDL_Texture;
namespace draw
{
@ -256,4 +257,91 @@ void tiled(const texture& tex,
);
/***************************/
/* RAII state manipulation */
/***************************/
/** A class to manage automatic restoration of the clipping region.
*
* While this can be constructed on its own, it is usually easier to
* use the draw::set_clip() utility function.
*/
class clip_setter
{
public:
explicit clip_setter(const SDL_Rect& clip);
~clip_setter();
private:
SDL_Rect c_;
};
/**
* Set the clipping area. All draw calls will be clipped to this region.
*
* The clipping area is specified in draw-space coordinates.
*
* The returned object will reset the clipping area when it is destroyed,
* so it should be kept in scope until drawing is complete.
*
* @param clip The clipping region in draw-space coordinates.
* @returns A clip_setter object. When this object is destroyed
* the clipping region will be restored to whatever
* it was before this call.
*/
clip_setter set_clip(const SDL_Rect& clip);
/**
* Set the clipping area to the intersection of the current clipping
* area and the given rectangle.
*
* Otherwise acts as set_clip().
*/
clip_setter reduce_clip(const SDL_Rect& clip);
/**
* Set the clipping area, without any provided way of setting it back.
*
* @param clip The clipping area, in draw-space coordinates.
*/
void force_clip(const SDL_Rect& clip);
/** Get the current clipping area, in draw coordinates. */
SDL_Rect get_clip();
/** A class to manage automatic restoration of the render target.
*
* While this can be constructed on its own, it is usually easier to
* use the draw::set_render_target() utility function.
*/
class render_target_setter
{
public:
explicit render_target_setter(const texture& t);
~render_target_setter();
private:
SDL_Texture* t_;
};
/**
* Set the given texture as the active render target.
*
* All draw calls will draw to this texture until the returned object
* goes out of scope. Do not retain the render_target_setter longer
* than necessary.
*
* The provided texture must have been created with the
* SDL_TEXTUREACCESS_TARGET access mode.
*
* @param t The new render target. This must be a texture created
* with SDL_TEXTUREACCESS_TARGET.
* @returns A render_target_setter object. When this object is
* destroyed the render target will be restored to
* whatever it was before this call.
*/
render_target_setter set_render_target(const texture& t);
} // namespace draw

View File

@ -192,12 +192,12 @@ void floating_label::draw(int time)
SDL_Rect draw_rect = {pos.x, pos.y, draw_size_.x, draw_size_.y};
buf_pos_ = draw_rect;
CVideo& video = CVideo::get_singleton();
auto clipper = video.set_clip(clip_rect_);
auto clipper = draw::set_clip(clip_rect_);
// Read buf_ back from the screen.
// buf_pos_ will be intersected with the drawing area,
// so might not match draw_rect after this.
CVideo& video = CVideo::get_singleton();
buf_ = video.read_texture(&buf_pos_);
// Fade the label out according to the time.
@ -247,8 +247,7 @@ void floating_label::undraw()
return;
}
CVideo& video = CVideo::get_singleton();
auto clipper = video.set_clip(clip_rect_);
auto clipper = draw::set_clip(clip_rect_);
draw::blit(buf_, buf_pos_);
}

View File

@ -376,7 +376,7 @@ void widget::draw_background(int x_offset, int y_offset)
if(redraw_action_ == redraw_action::partly) {
const SDL_Rect clipping_rectangle
= calculate_clipping_rectangle(x_offset, y_offset);
auto clipper = CVideo::get_singleton().set_clip(clipping_rectangle);
auto clipper = draw::set_clip(clipping_rectangle);
draw_debug_border(x_offset, y_offset);
impl_draw_background(x_offset, y_offset);
} else {
@ -392,7 +392,7 @@ void widget::draw_children(int x_offset, int y_offset)
if(redraw_action_ == redraw_action::partly) {
const SDL_Rect clipping_rectangle
= calculate_clipping_rectangle(x_offset, y_offset);
auto clipper = CVideo::get_singleton().set_clip(clipping_rectangle);
auto clipper = draw::set_clip(clipping_rectangle);
impl_draw_children(x_offset, y_offset);
} else {
impl_draw_children(x_offset, y_offset);
@ -406,7 +406,7 @@ void widget::draw_foreground(int x_offset, int y_offset)
if(redraw_action_ == redraw_action::partly) {
const SDL_Rect clipping_rectangle
= calculate_clipping_rectangle(x_offset, y_offset);
auto clipper = CVideo::get_singleton().set_clip(clipping_rectangle);
auto clipper = draw::set_clip(clipping_rectangle);
impl_draw_foreground(x_offset, y_offset);
} else {
impl_draw_foreground(x_offset, y_offset);

View File

@ -684,7 +684,7 @@ void window::draw()
dirty_list_.clear();
dirty_list_.emplace_back(1, this);
#else
auto clipper = video_.set_clip(dirty_rect);
auto clipper = draw::set_clip(dirty_rect);
#endif
/*

View File

@ -230,7 +230,7 @@ bool halo_impl::effect::render()
return false;
}
auto clipper = disp->video().set_clip(clip_rect);
auto clipper = draw::set_clip(clip_rect);
buffer_pos_ = rect_;
buffer_ = disp->video().read_texture(&buffer_pos_);
@ -262,7 +262,7 @@ void halo_impl::effect::unrender()
}
SDL_Rect clip_rect = disp->map_outside_area();
auto clipper = disp->video().set_clip(clip_rect);
auto clipper = draw::set_clip(clip_rect);
// Due to scrolling, the location of the rendered halo
// might have changed; recalculate

View File

@ -545,7 +545,7 @@ void help_text_area::draw_contents()
{
const SDL_Rect& loc = inner_location();
bg_restore();
auto clipper = video().set_clip(loc);
auto clipper = draw::set_clip(loc);
for(std::list<item>::const_iterator it = items_.begin(), end = items_.end(); it != end; ++it) {
SDL_Rect dst = it->rect;
dst.y -= get_position();

View File

@ -24,8 +24,8 @@
#include <cassert>
#include <functional>
// The render_target_setter class has been moved to CVideo.
// To obtain one, use CVideo::set_render_target().
// The render_target_setter class has been moved to draw.hpp.
// To obtain one, use draw::set_render_target().
//class render_target_setter
using sdl_rect_getter = void (*)(SDL_Renderer*, SDL_Rect*);

View File

@ -331,7 +331,7 @@ void dialog_frame::draw_background()
return;
}
auto clipper = video_.set_clip(dim_.interior);
auto clipper = draw::set_clip(dim_.interior);
for(int i = 0; i < dim_.interior.w; i += bg_.w()) {
for(int j = 0; j < dim_.interior.h; j += bg_.h()) {
SDL_Rect src {0,0,0,0};

View File

@ -519,11 +519,6 @@ void CVideo::delay(unsigned int milliseconds)
}
}
CVideo::render_target_setter CVideo::set_render_target(const texture& t)
{
return CVideo::render_target_setter(*this, t);
}
void CVideo::force_render_target(SDL_Texture* t)
{
SDL_SetRenderTarget(get_renderer(), t);
@ -545,49 +540,6 @@ SDL_Texture* CVideo::get_render_target()
return SDL_GetRenderTarget(get_renderer());
}
// TODO: highdpi - separate drawing interface should also handle clipping
CVideo::clip_setter CVideo::set_clip(const SDL_Rect& clip)
{
return CVideo::clip_setter(*this, clip);
}
CVideo::clip_setter CVideo::reduce_clip(const SDL_Rect& clip)
{
SDL_Rect c = get_clip();
if (c == sdl::empty_rect) {
return CVideo::clip_setter(*this, clip);
} else {
return CVideo::clip_setter(*this, sdl::intersect_rects(clip, c));
}
}
void CVideo::force_clip(const SDL_Rect& clip)
{
if (!window) {
return;
}
if (SDL_RenderSetClipRect(get_renderer(), &clip)) {
throw error("Failed to set render clip rect");
}
}
SDL_Rect CVideo::get_clip() const
{
if (!window) {
return sdl::empty_rect;
}
SDL_Rect clip;
SDL_RenderGetClipRect(*window, &clip);
if (clip == sdl::empty_rect) {
return draw_area();
}
return clip;
}
SDL_Rect CVideo::clip_to_draw_area(const SDL_Rect* r) const
{
if (r) {

View File

@ -303,6 +303,8 @@ public:
*/
texture read_texture(SDL_Rect* r = nullptr);
/***** ***** ***** ***** State management ***** ***** ****** *****/
/**
* Stop the screen being redrawn. Anything that happens while the updates are locked will
* be hidden from the user's view.
@ -317,114 +319,13 @@ public:
void lock_flips(bool);
/***** ***** ***** ***** State management ***** ***** ****** *****/
/** A class to manage automatic restoration of the clipping region.
*
* While this can be constructed on its own, it is usually easier to
* use the CVideo::set_clip() member function.
*/
class clip_setter
{
public:
clip_setter(CVideo& video, const SDL_Rect& clip)
: video_(video), old_clip_()
{
old_clip_ = video_.get_clip();
video_.force_clip(clip);
}
~clip_setter()
{
video_.force_clip(old_clip_);
}
private:
CVideo& video_;
SDL_Rect old_clip_;
};
/**
* Set the clipping area. All draw calls will be clipped to this region.
*
* The clipping area is specified in draw-space coordinates.
*
* The returned object will reset the clipping area when it is destroyed,
* so it should be kept in scope until drawing is complete.
*
* @param clip The clipping region in draw-space coordinates.
* @returns A clip_setter object. When this object is destroyed
* the clipping region will be restored to whatever
* it was before this call.
*/
clip_setter set_clip(const SDL_Rect& clip);
/**
* Set the clipping area to the intersection of the current clipping
* area and the given rectangle.
*
* Otherwise acts as set_clip().
*/
clip_setter reduce_clip(const SDL_Rect& clip);
/**
* Set the clipping area, without any provided way of setting it back.
*
* @param clip The clipping area, in draw-space coordinates.
*/
void force_clip(const SDL_Rect& clip);
/** Get the current clipping area, in draw coordinates. */
SDL_Rect get_clip() const;
/** A class to manage automatic restoration of the render target.
*
* While this can be constructed on its own, it is usually easier to
* use the CVideo::set_render_target() member function.
*/
class render_target_setter
{
public:
explicit render_target_setter(CVideo& video, const texture& t)
: video_(video), last_target_(nullptr)
{
// Validate we can render to this texture.
assert(t.get_info().access == SDL_TEXTUREACCESS_TARGET);
last_target_ = video_.get_render_target();
video_.force_render_target(t);
}
~render_target_setter()
{
video_.force_render_target(last_target_);
}
private:
CVideo& video_;
SDL_Texture* last_target_;
};
/**
* Set the given texture as the active render target.
*
* All draw calls will draw to this texture until the returned object
* goes out of scope. Do not retain the render_target_setter longer
* than necessary.
*
* The provided texture must have been created with the
* SDL_TEXTUREACCESS_TARGET access mode.
*
* @param t The new render target. This must be a texture created
* with SDL_TEXTUREACCESS_TARGET.
* @returns A render_target_setter object. When this object is
* destroyed the render target will be restored to
* whatever it was before this call.
*/
render_target_setter set_render_target(const texture& t);
/**
* Set the render target, without any provided way of setting it back.
*
* End-users should not use this function directly. In stead use
* draw::set_render_target(), which returns a setter object which
* will automatically restore the render target upon leaving scope.
*
* @param t The new render target. This must be a texture created
* with SDL_TEXTUREACCESS_TARGET, or NULL to indicate
* the underlying window.

View File

@ -1003,7 +1003,7 @@ void menu::draw()
const SDL_Rect* clip = clip_rect();
if (clip) {
auto clipper = video().set_clip(*clip);
auto clipper = draw::set_clip(*clip);
draw_contents();
} else {
draw_contents();

View File

@ -155,7 +155,7 @@ void menu::imgsel_style::draw_row(menu& menu_ref, const std::size_t row_index, c
texture image;
SDL_Rect area;
// TODO: highdpi - move clip API to draw.cpp, this is the last usage of video here
auto clipper = menu_ref.video().set_clip(rect);
auto clipper = draw::set_clip(rect);
area.x = rect.x;
area.y = rect.y;

View File

@ -218,7 +218,7 @@ void textbox::draw_contents()
, line_height_);
// TODO: highdpi - this seems excessive
auto clipper = video().set_clip(loc);
auto clipper = draw::set_clip(loc);
draw::fill(rect, 0, 0, 160, 140);

View File

@ -15,6 +15,7 @@
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "draw.hpp" // for set_clip
#include "widgets/widget.hpp"
#include "video.hpp"
#include "sdl/rect.hpp"
@ -240,7 +241,7 @@ void widget::bg_update()
void widget::bg_restore() const
{
auto clipper = video().set_clip(clip_ ? clip_rect_ : video().draw_area());
auto clipper = draw::set_clip(clip_ ? clip_rect_ : video().draw_area());
if (needs_restore_) {
for(std::vector< surface_restorer >::const_iterator i = restorer_.begin(),
@ -252,7 +253,7 @@ void widget::bg_restore() const
void widget::bg_restore(const SDL_Rect& rect) const
{
auto clipper = video().set_clip(clip_ ? clip_rect_ : video().draw_area());
auto clipper = draw::set_clip(clip_ ? clip_rect_ : video().draw_area());
for(std::vector< surface_restorer >::const_iterator i = restorer_.begin(),
i_end = restorer_.end(); i != i_end; ++i)
@ -274,7 +275,7 @@ void widget::draw()
bg_restore();
if (clip_) {
auto clipper = video().set_clip(clip_rect_);
auto clipper = draw::set_clip(clip_rect_);
draw_contents();
} else {
draw_contents();