Rewrote the halo render engine...
...which solves a few minor glitches but most importantly speeds up the drawing of the halos.
This commit is contained in:
parent
6438df7d23
commit
7d4cc5638b
7 changed files with 203 additions and 73 deletions
|
@ -15,7 +15,9 @@ Version 1.3.1+svn:
|
|||
* added new experimental new unit location in the hex
|
||||
* tiles with overlays are also properly shown if compiled with
|
||||
--enable-tinygui (bug #8720 patch #697)
|
||||
* language and i18n:
|
||||
* rewrote the halo render engine which solves a few minor glitches but
|
||||
most importantly speeds up the drawing of the halos.
|
||||
* language and i18n:
|
||||
* updated translations: Bulgarian, Czech, Danish, Dutch, French, German,
|
||||
Hungarian, Italian, Norwegian, Portuguese (Brazil)
|
||||
* new translations: Indonesian
|
||||
|
|
|
@ -13,7 +13,8 @@ Version 1.3.1+svn:
|
|||
* Improved the look of the main menu and tips of the day boxes in the title
|
||||
screen.
|
||||
* Added new experimental new unit location in the hex.
|
||||
* Units changes and balancing:
|
||||
* Added some more speed optimizations.
|
||||
* Units changes and balancing:
|
||||
* Converted the cold resistance of the Elvish Sorceress line to a holy
|
||||
resistance.
|
||||
* Decreased the holy resistance of the Orcish Assassin line to 0%.
|
||||
|
|
|
@ -710,7 +710,6 @@ void display::flip()
|
|||
|
||||
const surface frameBuffer = get_video_surface();
|
||||
|
||||
halo::render();
|
||||
font::draw_floating_labels(frameBuffer);
|
||||
events::raise_volatile_draw_event();
|
||||
cursor::draw(frameBuffer);
|
||||
|
@ -720,7 +719,6 @@ void display::flip()
|
|||
cursor::undraw(frameBuffer);
|
||||
events::raise_volatile_undraw_event();
|
||||
font::undraw_floating_labels(frameBuffer);
|
||||
halo::unrender();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -851,6 +849,8 @@ void display::draw(bool update,bool force)
|
|||
|
||||
if(!map_.empty() && !invalidated_.empty()) {
|
||||
changed = true;
|
||||
|
||||
halo::unrender(invalidated_);
|
||||
|
||||
// Units can overlap multiple hexes, so we need to (1) redraw
|
||||
// them last, and (2) redraw them if they are adjacent existing hexes.
|
||||
|
@ -879,7 +879,16 @@ void display::draw(bool update,bool force)
|
|||
if (temp_unit_ && invalidated_.find(temp_unit_loc_) != invalidated_.end()) {
|
||||
temp_unit_->redraw_unit(*this, temp_unit_loc_);
|
||||
}
|
||||
|
||||
halo::render();
|
||||
|
||||
invalidated_.clear();
|
||||
} else if (!map_.empty()) {
|
||||
// if no hexes are invalidated we still need to update the haloes since
|
||||
// there might be animated or expired haloes
|
||||
wassert(invalidated_.empty());
|
||||
halo::unrender(invalidated_);
|
||||
halo::render();
|
||||
}
|
||||
|
||||
if(redrawMinimap_) {
|
||||
|
@ -909,6 +918,7 @@ void display::draw(bool update,bool force)
|
|||
}
|
||||
update_display();
|
||||
}
|
||||
|
||||
// set the theortical next draw time
|
||||
nextDraw_ += time_between_draws;
|
||||
|
||||
|
|
|
@ -417,6 +417,8 @@ public:
|
|||
bool in_game() const { return in_game_; }
|
||||
void draw_bar(const std::string& image, int xpos, int ypos, size_t height, double filled, const SDL_Color& col, fixed_t alpha);
|
||||
|
||||
void get_rect_hex_bounds(SDL_Rect rect, gamemap::location &topleft, gamemap::location &bottomright) const;
|
||||
|
||||
private:
|
||||
display(const display&);
|
||||
void operator=(const display&);
|
||||
|
@ -434,8 +436,6 @@ private:
|
|||
|
||||
void bounds_check_position();
|
||||
|
||||
void get_rect_hex_bounds(SDL_Rect rect, gamemap::location &topleft, gamemap::location &bottomright) const;
|
||||
|
||||
// std::vector<surface> getAdjacentTerrain(int x, int y, image::TYPE type, ADJACENT_TERRAIN_TYPE terrain_type);
|
||||
std::vector<surface> get_terrain_images(int x, int y, image::TYPE type, ADJACENT_TERRAIN_TYPE terrain_type);
|
||||
std::vector<std::string> get_fog_shroud_graphics(const gamemap::location& loc);
|
||||
|
|
231
src/halo.cpp
231
src/halo.cpp
|
@ -40,13 +40,18 @@ public:
|
|||
|
||||
void set_location(int x, int y);
|
||||
|
||||
void render();
|
||||
bool render();
|
||||
void unrender();
|
||||
|
||||
bool expired() const;
|
||||
bool expired() const { return images_.animation_finished(); }
|
||||
bool need_update() const { return images_.need_update(); }
|
||||
bool does_change() const { return !images_.does_not_change(); }
|
||||
bool on_location(const std::set<gamemap::location>& locations) const;
|
||||
|
||||
void add_overlay_location(std::set<gamemap::location>& locations);
|
||||
private:
|
||||
|
||||
const std::string& current_image();
|
||||
const std::string& current_image() { return images_.get_current_frame(); }
|
||||
void rezoom();
|
||||
|
||||
animated<std::string> images_;
|
||||
|
@ -59,15 +64,36 @@ private:
|
|||
double origzoom_, zoom_;
|
||||
surface surf_, buffer_;
|
||||
SDL_Rect rect_;
|
||||
|
||||
// the location of the center of the halo
|
||||
gamemap::location loc_;
|
||||
|
||||
// all location over which the halo lies
|
||||
std::vector<gamemap::location> overlayed_hexes_;
|
||||
};
|
||||
|
||||
std::map<int,effect> haloes;
|
||||
std::map<int, effect> haloes;
|
||||
int halo_id = 1;
|
||||
|
||||
bool hide_halo = false;
|
||||
// Upon unrendering an invalidation list is send. All haloes in that area and the
|
||||
// other invalidated haloes are stored in this set. Then there'll be tested which
|
||||
// haloes overlap and they're also stored in this set.
|
||||
std::set<int> invalidated_haloes;
|
||||
|
||||
// A newly added halo will be added to this list, these haloes don't need to
|
||||
// be unrendered but do not to be rendered regardless which tiles are invalidated.
|
||||
// These haloes will stay in this set until there're really rendered.
|
||||
// (rendering won't happen if for example the halo is offscreen)
|
||||
std::set<int> new_haloes;
|
||||
|
||||
// Upon deleting a halo isn't deleted but added to this set, upon unrendering the
|
||||
// image is unrendered and deleted.
|
||||
std::set<int> deleted_haloes;
|
||||
|
||||
// Haloes that have an animation or expiration time need to be checked every frame
|
||||
// and are stored in this set.
|
||||
std::set<int> changing_haloes;
|
||||
|
||||
effect::effect(int xpos, int ypos, const animated<std::string>::anim_description& img,
|
||||
const gamemap::location& loc, ORIENTATION orientation, bool infinite) :
|
||||
images_(img), orientation_(orientation), origx_(xpos), origy_(ypos),
|
||||
|
@ -75,7 +101,6 @@ effect::effect(int xpos, int ypos, const animated<std::string>::anim_description
|
|||
surf_(NULL), buffer_(NULL), rect_(empty_rect), loc_(loc)
|
||||
{
|
||||
wassert(disp != NULL);
|
||||
// std::cerr << "Constructing halo sequence from image " << img << "\n";
|
||||
|
||||
set_location(xpos,ypos);
|
||||
|
||||
|
@ -101,15 +126,6 @@ void effect::set_location(int x, int y)
|
|||
}
|
||||
}
|
||||
|
||||
const std::string& effect::current_image()
|
||||
{
|
||||
static const std::string r = "";
|
||||
|
||||
const std::string& res = images_.get_current_frame();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void effect::rezoom()
|
||||
{
|
||||
zoom_ = disp->zoom();
|
||||
|
@ -129,14 +145,14 @@ void effect::rezoom()
|
|||
}
|
||||
}
|
||||
|
||||
void effect::render()
|
||||
bool effect::render()
|
||||
{
|
||||
if(disp == NULL) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(loc_.x != -1 && loc_.y != -1 && disp->shrouded(loc_.x, loc_.y)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
images_.update_last_draw_time();
|
||||
|
@ -147,7 +163,7 @@ void effect::render()
|
|||
}
|
||||
|
||||
if(surf_ == NULL) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const gamemap::location zero_loc(0,0);
|
||||
|
@ -162,7 +178,19 @@ void effect::render()
|
|||
SDL_Rect clip_rect = disp->map_area();
|
||||
if(rects_overlap(rect,clip_rect) == false) {
|
||||
buffer_.assign(NULL);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if rendered the first time need to detemine the area affected, if a halo
|
||||
// changes size it's not updated.
|
||||
if(overlayed_hexes_.empty()) {
|
||||
gamemap::location topleft, bottomright;
|
||||
disp->get_rect_hex_bounds(rect, topleft, bottomright);
|
||||
for (int x = topleft.x; x <= bottomright.x; ++x) {
|
||||
for (int y = topleft.y; y <= bottomright.y; ++y) {
|
||||
overlayed_hexes_.push_back(gamemap::location(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
surface const screen = disp->video().getSurface();
|
||||
|
@ -179,6 +207,8 @@ void effect::render()
|
|||
SDL_BlitSurface(surf_,NULL,screen,&rect);
|
||||
|
||||
update_rect(rect_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void effect::unrender()
|
||||
|
@ -191,18 +221,42 @@ void effect::unrender()
|
|||
|
||||
SDL_Rect clip_rect = disp->map_area();
|
||||
const clip_rect_setter clip_setter(screen,clip_rect);
|
||||
SDL_Rect rect = rect_;
|
||||
|
||||
// due to scrolling the location of the rendered halo might have changed; recalculate
|
||||
const gamemap::location zero_loc(0,0);
|
||||
const int screenx = disp->get_location_x(zero_loc);
|
||||
const int screeny = disp->get_location_y(zero_loc);
|
||||
|
||||
const int xpos = x_ + screenx - surf_->w/2;
|
||||
const int ypos = y_ + screeny - surf_->h/2;
|
||||
|
||||
SDL_Rect rect = {xpos,ypos,surf_->w,surf_->h};
|
||||
SDL_BlitSurface(buffer_,NULL,screen,&rect);
|
||||
update_rect(rect_);
|
||||
}
|
||||
|
||||
bool effect::expired() const
|
||||
bool effect::on_location(const std::set<gamemap::location>& locations) const
|
||||
{
|
||||
return images_.animation_finished();
|
||||
for(std::vector<gamemap::location>::const_iterator itor = overlayed_hexes_.begin();
|
||||
itor != overlayed_hexes_.end(); ++itor) {
|
||||
if(locations.find(*itor) != locations.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void effect::add_overlay_location(std::set<gamemap::location>& locations)
|
||||
{
|
||||
for(std::vector<gamemap::location>::const_iterator itor = overlayed_hexes_.begin();
|
||||
itor != overlayed_hexes_.end(); ++itor) {
|
||||
|
||||
locations.insert(*itor);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
manager::manager(display& screen) : old(disp)
|
||||
{
|
||||
disp = &screen;
|
||||
|
@ -214,20 +268,8 @@ manager::~manager()
|
|||
disp = old;
|
||||
}
|
||||
|
||||
halo_hider::halo_hider() : old(hide_halo)
|
||||
{
|
||||
render();
|
||||
hide_halo = true;
|
||||
}
|
||||
|
||||
halo_hider::~halo_hider()
|
||||
{
|
||||
hide_halo = old;
|
||||
unrender();
|
||||
}
|
||||
|
||||
int add(int x, int y, const std::string& image, const gamemap::location& loc,
|
||||
ORIENTATION orientation, bool infinite)
|
||||
ORIENTATION orientation, bool infinite)
|
||||
{
|
||||
const int id = halo_id++;
|
||||
animated<std::string>::anim_description image_vector;
|
||||
|
@ -249,6 +291,10 @@ int add(int x, int y, const std::string& image, const gamemap::location& loc,
|
|||
|
||||
}
|
||||
haloes.insert(std::pair<int,effect>(id,effect(x,y,image_vector,loc,orientation,infinite)));
|
||||
new_haloes.insert(id);
|
||||
if(haloes.find(id)->second.does_change() || !infinite) {
|
||||
changing_haloes.insert(id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -262,34 +308,111 @@ void set_location(int handle, int x, int y)
|
|||
|
||||
void remove(int handle)
|
||||
{
|
||||
haloes.erase(handle);
|
||||
deleted_haloes.insert(handle);
|
||||
}
|
||||
|
||||
void unrender(std::set<gamemap::location> invalidated_locations)
|
||||
{
|
||||
wassert(invalidated_haloes.size() == 0);
|
||||
if(preferences::show_haloes() == false || haloes.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove expired haloes
|
||||
std::map<int, effect>::iterator itor = haloes.begin();
|
||||
for(; itor != haloes.end(); ++itor ) {
|
||||
if(itor->second.expired()) {
|
||||
deleted_haloes.insert(itor->first);
|
||||
}
|
||||
}
|
||||
|
||||
// add the haloes marked for deletion to the invalidation set
|
||||
std::set<int>::const_iterator set_itor = deleted_haloes.begin();
|
||||
for(;set_itor != deleted_haloes.end(); ++set_itor) {
|
||||
invalidated_haloes.insert(*set_itor);
|
||||
haloes.find(*set_itor)->second.add_overlay_location(invalidated_locations);
|
||||
}
|
||||
|
||||
// test the multi-frame haloes whether they need an update
|
||||
for(set_itor = changing_haloes.begin();
|
||||
set_itor != changing_haloes.end(); ++set_itor) {
|
||||
if(haloes.find(*set_itor)->second.need_update()) {
|
||||
invalidated_haloes.insert(*set_itor);
|
||||
haloes.find(*set_itor)->second.add_overlay_location(invalidated_locations);
|
||||
}
|
||||
}
|
||||
|
||||
// find all halo's in a the invalidated area
|
||||
size_t halo_count;
|
||||
|
||||
// repeat until of haloes in the invalidated area didn't change (including none found)
|
||||
// or all exisiting haloes are found
|
||||
do {
|
||||
halo_count = invalidated_haloes.size();
|
||||
for(itor = haloes.begin(); itor != haloes.end(); ++itor) {
|
||||
// test all haloes not yet in the set which match one of the locations
|
||||
if(invalidated_haloes.find(itor->first) == invalidated_haloes.end() &&
|
||||
itor->second.on_location(invalidated_locations)) {
|
||||
|
||||
// if found add all locations which the halo invalidates
|
||||
// and add it to the set
|
||||
itor->second.add_overlay_location(invalidated_locations);
|
||||
invalidated_haloes.insert(itor->first);
|
||||
}
|
||||
}
|
||||
} while (halo_count != invalidated_haloes.size() && halo_count != haloes.size());
|
||||
|
||||
if(halo_count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// render the haloes iterate through all the haloes and invalidate if in set
|
||||
for(std::map<int, effect>::reverse_iterator ritor = haloes.rbegin(); ritor != haloes.rend(); ++ritor) {
|
||||
if(invalidated_haloes.find(ritor->first) != invalidated_haloes.end()) {
|
||||
ritor->second.unrender();
|
||||
}
|
||||
}
|
||||
|
||||
// realy delete the haloes marked for deletion
|
||||
for(set_itor = deleted_haloes.begin(); set_itor != deleted_haloes.end(); ++set_itor) {
|
||||
// it can happen a delete halo hasn't been rendered yet, invalidate them as well
|
||||
new_haloes.erase(*set_itor);
|
||||
|
||||
changing_haloes.erase(*set_itor);
|
||||
invalidated_haloes.erase(*set_itor);
|
||||
haloes.erase(*set_itor);
|
||||
}
|
||||
|
||||
deleted_haloes.clear();
|
||||
}
|
||||
|
||||
void render()
|
||||
{
|
||||
if(hide_halo || preferences::show_haloes() == false) {
|
||||
|
||||
if(preferences::show_haloes() == false || haloes.size() == 0 ||
|
||||
(new_haloes.size() == 0 && invalidated_haloes.size() == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(std::map<int,effect>::iterator i = haloes.begin(); i != haloes.end(); ) {
|
||||
if(i->second.expired()) {
|
||||
haloes.erase(i++);
|
||||
} else {
|
||||
i->second.render();
|
||||
++i;
|
||||
// keep track of not rendered new images they have to be kept scheduled for rendering
|
||||
// otherwise the invalidation area is never properly set
|
||||
std::set<int> unrendered_new_haloes;
|
||||
|
||||
// render the haloes iterate through all the haloes and draw if in either set
|
||||
for(std::map<int, effect>::iterator itor = haloes.begin();
|
||||
itor != haloes.end(); ++itor) {
|
||||
|
||||
if(new_haloes.find(itor->first) != new_haloes.end() &&
|
||||
! itor->second.render()) {
|
||||
|
||||
unrendered_new_haloes.insert(itor->first);
|
||||
} else if(invalidated_haloes.find(itor->first) != invalidated_haloes.end()) {
|
||||
itor->second.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unrender()
|
||||
{
|
||||
if(hide_halo || preferences::show_haloes() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(std::map<int,effect>::reverse_iterator i = haloes.rbegin(); i != haloes.rend(); ++i) {
|
||||
i->second.unrender();
|
||||
}
|
||||
invalidated_haloes.clear();
|
||||
new_haloes = unrendered_new_haloes;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
16
src/halo.hpp
16
src/halo.hpp
|
@ -17,6 +17,7 @@
|
|||
class display;
|
||||
|
||||
#include "map.hpp"
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace halo
|
||||
|
@ -31,14 +32,6 @@ private:
|
|||
display* const old;
|
||||
};
|
||||
|
||||
struct halo_hider
|
||||
{
|
||||
halo_hider();
|
||||
~halo_hider();
|
||||
private:
|
||||
bool old;
|
||||
};
|
||||
|
||||
enum ORIENTATION { NORMAL, HREVERSE, VREVERSE, HVREVERSE };
|
||||
|
||||
///function to add a haloing effect using 'image'
|
||||
|
@ -64,10 +57,11 @@ struct remover
|
|||
void operator()(int handle) const { remove(handle); }
|
||||
};
|
||||
|
||||
///functions to render and unrender all haloes. Should
|
||||
///be called immediately before/after flipping the screen
|
||||
///functions to render and unrender haloes. Which haloes are rendered
|
||||
// is determined by invalidated_locations and the internal state in
|
||||
// the control sets (in halo.cpp)
|
||||
void unrender(std::set<gamemap::location> invalidated_locations);
|
||||
void render();
|
||||
void unrender();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
|
||||
class config;
|
||||
class CVideo;
|
||||
class display;
|
||||
|
||||
#include "cursor.hpp"
|
||||
#include "font.hpp"
|
||||
#include "halo.hpp"
|
||||
#include "network.hpp"
|
||||
#include "tooltips.hpp"
|
||||
|
||||
|
@ -46,7 +46,7 @@ enum DIALOG_RESULT {
|
|||
|
||||
bool in_dialog();
|
||||
|
||||
struct dialog_manager : private cursor::setter, private font::floating_label_context, private halo::halo_hider {
|
||||
struct dialog_manager : private cursor::setter, private font::floating_label_context {
|
||||
dialog_manager();
|
||||
~dialog_manager();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue