26 #include <SDL2/SDL_rect.h>
27 #include <SDL2/SDL_timer.h>
34 #define ERR_DM LOG_STREAM(err, log_draw_man)
35 #define WRN_DM LOG_STREAM(warn, log_draw_man)
36 #define LOG_DM LOG_STREAM(info, log_draw_man)
37 #define DBG_DM LOG_STREAM(debug, log_draw_man)
46 std::vector<top_level_drawable*> top_level_drawables_;
47 std::vector<rect> invalidated_regions_;
48 bool drawing_ =
false;
49 bool tlds_need_tidying_ =
false;
50 uint32_t last_sparkle_ = 0;
65 ERR_DM <<
"Attempted to invalidate region " << region
71 rect progressive_cover = region;
72 int64_t cumulative_area = 0;
73 for (
auto& r : invalidated_regions_) {
74 if (r.contains(region)) {
84 DBG_DM <<
"superceding previous invalidation " << r
85 <<
" with " << region;
92 if (m.
area() <= r.area() + region.
area()) {
95 DBG_DM <<
"merging " << region <<
" with " << r
96 <<
" to invalidate " << m;
103 cumulative_area += r.
area();
104 if (progressive_cover.
area() <= cumulative_area) {
105 DBG_DM <<
"conglomerating invalidations to "
106 << progressive_cover;
109 invalidated_regions_[0] = progressive_cover;
115 DBG_DM <<
"invalidating region " << region;
117 invalidated_regions_.push_back(region);
129 ERR_DM <<
"Draw recursion detected";
134 if (tlds_need_tidying_) {
136 tlds_need_tidying_ =
false;
148 invalidated_regions_.clear();
163 last_sparkle_ = SDL_GetTicks();
174 int vsync_delay = (1000 / rr) - 1;
182 if (time_to_wait > 0) {
184 SDL_Delay(std::min(time_to_wait, 1000));
190 for (
size_t i = 0;
i < top_level_drawables_.size(); ++
i) {
192 if (tld) { tld->
update(); }
198 for (
size_t i = 0;
i < top_level_drawables_.size(); ++
i) {
200 if (tld) { tld->
layout(); }
206 for (
size_t i = 0;
i < top_level_drawables_.size(); ++
i) {
208 if (tld) { tld->
render(); }
219 while (!invalidated_regions_.empty()) {
220 rect r = invalidated_regions_.back();
221 invalidated_regions_.pop_back();
223 for (
auto& other : invalidated_regions_) {
225 if (other.contains(r)) {
226 DBG_DM <<
"skipping redundant draw " << r;
231 if (m.
area() <= r.
area() + other.area()) {
232 DBG_DM <<
"merging inefficient draws " << r;
238 DBG_DM <<
"drawing " << r;
241 for (
auto tld : top_level_drawables_) {
242 if (!tld) {
continue; }
249 DBG_DM <<
" to " <<
static_cast<void*
>(tld);
252 drawn |= tld->expose(
i);
255 <<
" thrown during expose " <<
static_cast<void*
>(tld);
269 DBG_DM <<
"registering TLD " <<
static_cast<void*
>(tld);
270 auto& vec = top_level_drawables_;
271 if (std::find(vec.begin(), vec.end(), tld) != vec.end()) {
274 top_level_drawables_.push_back(tld);
280 DBG_DM <<
"deregistering TLD " <<
static_cast<void*
>(tld);
281 auto& vec = top_level_drawables_;
282 auto it = std::find(vec.begin(), vec.end(), tld);
284 if (it == vec.end()) {
285 WRN_DM <<
"attempted to deregister nonexistant TLD "
286 <<
static_cast<void*
>(tld);
292 tlds_need_tidying_ =
true;
297 DBG_DM <<
"raising TLD " <<
static_cast<void*
>(tld);
298 auto& vec = top_level_drawables_;
299 auto it = std::find(vec.begin(), vec.end(), tld);
301 if (it == vec.end()) {
302 ERR_DM <<
"attempted to raise nonexistant TLD "
303 <<
static_cast<void*
>(tld);
307 for ( ; it != vec.end(); it = std::find(it, vec.end(), tld)) {
312 tlds_need_tidying_ =
true;
318 DBG_DM <<
"tidying " << top_level_drawables_.size() <<
" drawables";
319 auto& vec = top_level_drawables_;
320 vec.erase(
std::remove(vec.begin(), vec.end(),
nullptr), vec.end());
321 DBG_DM << top_level_drawables_.size() <<
" after tidying";
A top-level drawable item (TLD), such as a window.
virtual void render()
Perform any internal rendering necessary to prepare the drawable.
virtual void layout()
Finalize the size and position of the drawable and its children, and invalidate any regions requiring...
virtual void update()
Update state and any parameters that may effect layout, or any of the later stages.
Drawing functions, for drawing things on the screen.
static lg::log_domain log_draw_man("draw/manager")
Standard logging facilities (interface).
A global draw management interface.
void invalidate_region(const rect ®ion)
Mark a region of the screen as requiring redraw.
static void tidy_drawables()
void register_drawable(top_level_drawable *tld)
Register a top-level drawable.
int get_frame_length()
Returns the length of one display frame, in milliseconds.
void deregister_drawable(top_level_drawable *tld)
Remove a top-level drawable from the drawing stack.
void invalidate_all()
Mark the entire screen as requiring redraw.
void sparkle()
Ensure that everything which needs to be drawn is drawn.
void raise_drawable(top_level_drawable *tld)
Raise a TLD to the top of the drawing stack.
static void wait_for_vsync()
clip_setter override_clip(const SDL_Rect &clip)
Override the clipping area.
void remove()
Removes a tip.
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
bool headless()
The game is running headless.
bool testing()
The game is running unit tests.
rect game_canvas()
The game canvas area, in drawing coordinates.
int current_refresh_rate()
The refresh rate of the screen.
Contains the SDL_Rect helper code.
Base class for all the errors encountered by the engine.
An abstract description of a rectangle with integer coordinates.
rect & expand_to_cover(const SDL_Rect &r)
Minimally expand this rect to fully contain another.
rect minimal_cover(const SDL_Rect &r) const
Calculates the minimal rectangle that completely contains both this rectangle and the given rectangle...
bool contains(int x, int y) const
Whether the given point lies within the rectangle.
constexpr int area() const
The area of this rectangle, in square pixels.
rect intersect(const SDL_Rect &r) const
Calculates the intersection of this rectangle and another; that is, the maximal rectangle that is con...