Skip to content

Commit

Permalink
GUI2: refactored viewport setting and re-added clip rect setting
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Vultraz committed Mar 8, 2018
1 parent b7fa0a4 commit 4910d13
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 26 deletions.
19 changes: 12 additions & 7 deletions src/gui/core/canvas.cpp
Expand Up @@ -1474,17 +1474,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_) {
/*
Expand All @@ -1503,6 +1505,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)
Expand Down
8 changes: 3 additions & 5 deletions src/gui/core/canvas.hpp
Expand Up @@ -104,12 +104,10 @@ class canvas
/**
* 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.
Expand Down
8 changes: 4 additions & 4 deletions src/gui/widgets/panel.cpp
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/gui/widgets/styled_widget.cpp
Expand Up @@ -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*/)
Expand Down
62 changes: 58 additions & 4 deletions src/gui/widgets/widget.cpp
Expand Up @@ -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
{
Expand Down Expand Up @@ -346,28 +347,77 @@ 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;
result.y += y_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;
result.y += y_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);
}
Expand All @@ -376,13 +426,17 @@ 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);
}

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);
}

Expand Down
6 changes: 2 additions & 4 deletions src/gui/widgets/widget.hpp
Expand Up @@ -530,8 +530,7 @@ class widget : public event_executor, public event::dispatcher
*
* @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.
Expand All @@ -545,8 +544,7 @@ class widget : public event_executor, public event::dispatcher
*
* @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.
Expand Down

0 comments on commit 4910d13

Please sign in to comment.