mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-07 01:59:57 +00:00
Reduced amount of overlapping rectangles sent to SDL. (Patch #1141.)
This commit is contained in:
parent
4e7a4becc9
commit
58c7896b99
162
src/video.cpp
162
src/video.cpp
@ -19,13 +19,17 @@
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
|
||||
#include "font.hpp"
|
||||
#include "foreach.hpp"
|
||||
#include "image.hpp"
|
||||
#include "log.hpp"
|
||||
#include "preferences_display.hpp"
|
||||
#include "video.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
static lg::log_domain log_display("display");
|
||||
#define LOG_DP LOG_STREAM(info, log_display)
|
||||
#define ERR_DP LOG_STREAM(err, log_display)
|
||||
@ -66,12 +70,129 @@ static unsigned int get_flags(unsigned int flags)
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::vector<SDL_Rect> update_rects;
|
||||
bool update_all = false;
|
||||
struct event {
|
||||
int x, y, w, h;
|
||||
bool in;
|
||||
event(const SDL_Rect& rect, bool i) : x(i ? rect.x : rect.x + rect.w), y(rect.y), w(rect.w), h(rect.h), in(i) { }
|
||||
};
|
||||
bool operator<(const event& a, const event& b) {
|
||||
if (a.x != b.x) return a.x < b.x;
|
||||
if (a.in != b.in) return a.in;
|
||||
if (a.y != b.y) return a.y < b.y;
|
||||
if (a.h != b.h) return a.h < b.h;
|
||||
if (a.w != b.w) return a.w < b.w;
|
||||
return false;
|
||||
}
|
||||
bool operator==(const event& a, const event& b) {
|
||||
return a.x == b.x && a.y == b.y && a.w == b.w && a.h == b.h && a.in == b.in;
|
||||
}
|
||||
|
||||
static bool rect_contains(const SDL_Rect& a, const SDL_Rect& b) {
|
||||
return a.x <= b.x && a.y <= b.y && a.x+a.w >= b.x+b.w && a.y+a.h >= b.y+b.h;
|
||||
struct segment {
|
||||
int x, count;
|
||||
segment() : x(0), count(0) { }
|
||||
segment(int x, int count) : x(x), count(count) { }
|
||||
};
|
||||
|
||||
|
||||
std::vector<SDL_Rect> update_rects;
|
||||
std::vector<event> events;
|
||||
std::map<int, segment> segments;
|
||||
|
||||
static void calc_rects()
|
||||
{
|
||||
events.clear();
|
||||
|
||||
foreach (SDL_Rect const &rect, update_rects) {
|
||||
events.push_back(event(rect, true));
|
||||
events.push_back(event(rect, false));
|
||||
}
|
||||
|
||||
std::sort(events.begin(), events.end());
|
||||
std::vector<event>::iterator events_end = std::unique(events.begin(), events.end());
|
||||
|
||||
segments.clear();
|
||||
update_rects.clear();
|
||||
|
||||
for (std::vector<event>::iterator iter = events.begin(); iter != events_end; ++iter) {
|
||||
std::map<int, segment>::iterator lower = segments.find(iter->y);
|
||||
if (lower == segments.end()) {
|
||||
lower = segments.insert(std::make_pair(iter->y, segment())).first;
|
||||
if (lower != segments.begin()) {
|
||||
std::map<int, segment>::iterator prev = lower;
|
||||
--prev;
|
||||
lower->second = prev->second;
|
||||
}
|
||||
}
|
||||
|
||||
if (lower->second.count == 0) {
|
||||
lower->second.x = iter->x;
|
||||
}
|
||||
|
||||
std::map<int, segment>::iterator upper = segments.find(iter->y + iter->h);
|
||||
if (upper == segments.end()) {
|
||||
upper = segments.insert(std::make_pair(iter->y + iter->h, segment())).first;
|
||||
std::map<int, segment>::iterator prev = upper;
|
||||
--prev;
|
||||
upper->second = prev->second;
|
||||
}
|
||||
|
||||
if (iter->in) {
|
||||
while (lower != upper) {
|
||||
++lower->second.count;
|
||||
++lower;
|
||||
}
|
||||
} else {
|
||||
while (lower != upper) {
|
||||
lower->second.count--;
|
||||
if (lower->second.count == 0) {
|
||||
std::map<int, segment>::iterator next = lower;
|
||||
++next;
|
||||
|
||||
int x = lower->second.x, y = lower->first;
|
||||
unsigned w = iter->x - x;
|
||||
unsigned h = next->first - y;
|
||||
SDL_Rect a = {x, y, w, h};
|
||||
|
||||
if (update_rects.size() == 0) {
|
||||
update_rects.push_back(a);
|
||||
} else {
|
||||
SDL_Rect& p = update_rects.back(), n;
|
||||
int pa = p.w * p.h, aa = w * h, s = pa + aa;
|
||||
int thresh = 51;
|
||||
|
||||
n.w = std::max<int>(x + w, p.x + p.w);
|
||||
n.x = std::min<int>(p.x, x);
|
||||
n.w -= n.x;
|
||||
n.h = std::max<int>(y + h, p.y + p.h);
|
||||
n.y = std::min<int>(p.y, y);
|
||||
n.h -= n.y;
|
||||
|
||||
if (s * 100 < thresh * n.w * n.h) {
|
||||
update_rects.push_back(a);
|
||||
} else {
|
||||
p = n;
|
||||
}
|
||||
}
|
||||
|
||||
if (lower == segments.begin()) {
|
||||
segments.erase(lower);
|
||||
} else {
|
||||
std::map<int, segment>::iterator prev = lower;
|
||||
--prev;
|
||||
if (prev->second.count == 0) segments.erase(lower);
|
||||
}
|
||||
|
||||
lower = next;
|
||||
} else {
|
||||
++lower;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool update_all = false;
|
||||
}
|
||||
|
||||
static void clear_updates()
|
||||
@ -162,24 +283,6 @@ void update_rect(const SDL_Rect& rect_value)
|
||||
}
|
||||
}
|
||||
|
||||
for(std::vector<SDL_Rect>::iterator i = update_rects.begin();
|
||||
i != update_rects.end(); ++i) {
|
||||
if(rect_contains(*i,rect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(rect_contains(rect,*i)) {
|
||||
*i = rect;
|
||||
for(++i; i != update_rects.end(); ++i) {
|
||||
if(rect_contains(rect,*i)) {
|
||||
i->w = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
update_rects.push_back(rect);
|
||||
}
|
||||
|
||||
@ -302,17 +405,8 @@ void CVideo::flip()
|
||||
if(update_all) {
|
||||
::SDL_Flip(frameBuffer);
|
||||
} else if(update_rects.empty() == false) {
|
||||
size_t sum = 0;
|
||||
for(size_t n = 0; n != update_rects.size(); ++n) {
|
||||
sum += update_rects[n].w*update_rects[n].h;
|
||||
}
|
||||
|
||||
const size_t redraw_whole_screen_threshold = 80;
|
||||
if(sum > ((getx()*gety())*redraw_whole_screen_threshold)/100) {
|
||||
::SDL_Flip(frameBuffer);
|
||||
} else {
|
||||
SDL_UpdateRects(frameBuffer,update_rects.size(),&update_rects[0]);
|
||||
}
|
||||
calc_rects();
|
||||
SDL_UpdateRects(frameBuffer, update_rects.size(), &update_rects[0]);
|
||||
}
|
||||
|
||||
clear_updates();
|
||||
|
Loading…
x
Reference in New Issue
Block a user