GUI2: refactored viewport setting and re-added clip rect setting

It turns out I had removed the clip rect setting in error; it prevented items in, say, a listbox from drawing
outside the widget's boundaries. I've re-added that now.

I've also moved viewport setting to the same place. It turns out it didn't need to be set every canvas draw.
The only reason the old code was passing the blitting rect to the canvas was it was needed for the sdl_blit call.
Since I can now set the viewport independent of a canvas state, there's no longer a need to set the viewport in
the canvas.
This commit is contained in:
Charles Dang 2017-06-02 14:07:27 +11:00
parent 78271d2302
commit 48d072a02e
6 changed files with 81 additions and 26 deletions

View file

@ -1476,17 +1476,19 @@ void canvas::draw(const bool force)
is_dirty_ = false;
}
void canvas::render(SDL_Rect rect)
void canvas::render()
{
SDL_RenderSetViewport(renderer_, &rect);
/**
* @note Both the clip rect and viewport should be set before this function is called.
* The clip rect ensures the canvas texture is cropped appropriately, and the viewport sets the
* origin for all the drawing operations, as well as specifying the area of the screen to which
* this canvas applies.
*/
// Update the canvas texture, if necessary.
draw();
SDL_RenderCopy(renderer_, texture_, nullptr, nullptr);
SDL_RenderSetViewport(renderer_, nullptr);
// TODO: reenable
// TODO: reenable. Need a shader.
#if 0
if(blur_depth_) {
/*
@ -1505,6 +1507,9 @@ void canvas::render(SDL_Rect rect)
}
}
#endif
// Copy the entire texture to the full viewport.
SDL_RenderCopy(renderer_, texture_, nullptr, nullptr);
}
void canvas::parse_cfg(const config& cfg)

View file

@ -104,12 +104,10 @@ public:
/**
* Copies the canvas texture to the screen renderer.
*
* It makes sure the image on the canvas is up to date. Also executes the
* pre-blitting functions.
*
* @param rect The place to blit to.
* This will re-render the canvas texture if necessary (ie, if marked dirty).
* It also executes the pre-commit functions such as blurring (@todo: reenable).
*/
void render(SDL_Rect rect);
void render();
/**
* Sets the config.

View file

@ -64,18 +64,18 @@ unsigned panel::get_state() const
return 0;
}
void panel::impl_draw_background(int x_offset, int y_offset)
void panel::impl_draw_background(int /*x_offset*/, int /*y_offset*/)
{
DBG_GUI_D << LOG_HEADER << " size " << get_rectangle() << ".\n";
get_canvas(0).render(calculate_blitting_rectangle(x_offset, y_offset));
get_canvas(0).render();
}
void panel::impl_draw_foreground(int x_offset, int y_offset)
void panel::impl_draw_foreground(int /*x_offset*/, int /*y_offset*/)
{
DBG_GUI_D << LOG_HEADER << " size " << get_rectangle() << ".\n";
get_canvas(1).render(calculate_blitting_rectangle(x_offset, y_offset));
get_canvas(1).render();
}
point panel::border_space() const

View file

@ -408,12 +408,12 @@ int styled_widget::get_text_maximum_height() const
return get_height() - config_->text_extra_height;
}
void styled_widget::impl_draw_background(int x_offset, int y_offset)
void styled_widget::impl_draw_background(int /*x_offset*/, int /*y_offset*/)
{
DBG_GUI_D << LOG_HEADER << " label '" << debug_truncate(label_) << "' size "
<< get_rectangle() << ".\n";
get_canvas(get_state()).render(calculate_blitting_rectangle(x_offset, y_offset));
get_canvas(get_state()).render();
}
void styled_widget::impl_draw_foreground(int /*x_offset*/, int /*y_offset*/)

View file

@ -21,6 +21,7 @@
#include "gui/core/log.hpp"
#include "gui/core/window_builder/helper.hpp"
#include "sdl/rect.hpp"
#include "video.hpp"
namespace gui2
{
@ -340,8 +341,7 @@ void widget::set_linked_group(const std::string& linked_group)
/***** ***** ***** ***** Drawing functions. ***** ***** ***** *****/
SDL_Rect widget::calculate_blitting_rectangle(const int x_offset,
const int y_offset)
SDL_Rect widget::calculate_blitting_rectangle(const int x_offset, const int y_offset) const
{
SDL_Rect result = get_rectangle();
result.x += x_offset;
@ -349,8 +349,7 @@ SDL_Rect widget::calculate_blitting_rectangle(const int x_offset,
return result;
}
SDL_Rect widget::calculate_clipping_rectangle(const int x_offset,
const int y_offset)
SDL_Rect widget::calculate_clipping_rectangle(const int x_offset, const int y_offset) const
{
SDL_Rect result = clipping_rectangle_;
result.x += x_offset;
@ -358,10 +357,61 @@ SDL_Rect widget::calculate_clipping_rectangle(const int x_offset,
return result;
}
namespace
{
/**
* Small RAII helper class to set the renderer viewport and clip rect for the drawing routines.
*/
class viewport_and_clip_rect_setter
{
public:
viewport_and_clip_rect_setter(const widget& widget, int x_offset, int y_offset)
: renderer_(*CVideo::get_singleton().get_window())
{
// Set viewport.
const SDL_Rect dst_rect = widget.calculate_blitting_rectangle(x_offset, y_offset);
SDL_RenderSetViewport(renderer_, &dst_rect);
// Set clip rect, if appropriate.
if(widget.get_drawing_action() != widget::redraw_action::partly) {
return;
}
SDL_Rect clip_rect = widget.calculate_clipping_rectangle(x_offset, y_offset);
// Adjust clip rect origin to match the viewport origin. Currently, the both rects are mapped to
// absolute screen coordinates. However, setting the viewport essentially moves the screen origin,
// meaning if both the viewport rect and clip rect have x = 100, then clipping will actually
// happen at x = 200.
clip_rect.x -= dst_rect.x;
clip_rect.y -= dst_rect.y;
SDL_RenderSetClipRect(renderer_, &clip_rect);
}
~viewport_and_clip_rect_setter()
{
SDL_RenderSetClipRect(renderer_, nullptr);
SDL_RenderSetViewport(renderer_, nullptr);
}
private:
SDL_Renderer* renderer_;
};
} // anon namespace
/**
* @todo remove the offset arguments from these functions.
* Currently they're only needed by the minimap.
*/
void widget::draw_background(int x_offset, int y_offset)
{
assert(visible_ == visibility::visible);
viewport_and_clip_rect_setter setter(*this, x_offset, y_offset);
draw_debug_border(x_offset, y_offset);
impl_draw_background(x_offset, y_offset);
}
@ -370,6 +420,8 @@ void widget::draw_children(int x_offset, int y_offset)
{
assert(visible_ == visibility::visible);
viewport_and_clip_rect_setter setter(*this, x_offset, y_offset);
impl_draw_children(x_offset, y_offset);
}
@ -377,6 +429,8 @@ void widget::draw_foreground(int x_offset, int y_offset)
{
assert(visible_ == visibility::visible);
viewport_and_clip_rect_setter setter(*this, x_offset, y_offset);
impl_draw_foreground(x_offset, y_offset);
}

View file

@ -513,8 +513,7 @@ public:
*
* @returns The drawing rectangle.
*/
SDL_Rect calculate_blitting_rectangle(const int x_offset,
const int y_offset);
SDL_Rect calculate_blitting_rectangle(const int x_offset, const int y_offset) const;
/**
* Calculates the clipping rectangle of the widget.
@ -528,8 +527,7 @@ public:
*
* @returns The clipping rectangle.
*/
SDL_Rect calculate_clipping_rectangle(const int x_offset,
const int y_offset);
SDL_Rect calculate_clipping_rectangle(const int x_offset, const int y_offset) const;
/**
* Draws the background of a widget.