00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "global.hpp"
00020
00021 #include "display.hpp"
00022 #include "game_preferences.hpp"
00023 #include "halo.hpp"
00024 #include "image.hpp"
00025 #include "sdl_utils.hpp"
00026 #include "util.hpp"
00027 #include "video.hpp"
00028 #include "serialization/string_utils.hpp"
00029
00030 #include <algorithm>
00031 #include <cassert>
00032 #include <map>
00033
00034 namespace halo
00035 {
00036
00037 namespace {
00038 display* disp = NULL;
00039
00040 class effect
00041 {
00042 public:
00043 effect(int xpos, int ypos, const animated<std::string>::anim_description& img,
00044 const gamemap::location& loc, ORIENTATION, bool infinite);
00045
00046 void set_location(int x, int y);
00047
00048 bool render();
00049 void unrender();
00050
00051 bool expired() const { return !images_.cycles() && images_.animation_finished(); }
00052 bool need_update() const { return images_.need_update(); }
00053 bool does_change() const { return !images_.does_not_change(); }
00054 bool on_location(const std::set<gamemap::location>& locations) const;
00055
00056 void add_overlay_location(std::set<gamemap::location>& locations);
00057 private:
00058
00059 const std::string& current_image() { return images_.get_current_frame(); }
00060
00061 animated<std::string> images_;
00062
00063 ORIENTATION orientation_;
00064
00065 int x_, y_;
00066 surface surf_, buffer_;
00067 SDL_Rect rect_;
00068
00069
00070 gamemap::location loc_;
00071
00072
00073 std::vector<gamemap::location> overlayed_hexes_;
00074 };
00075
00076 std::map<int, effect> haloes;
00077 int halo_id = 1;
00078
00079
00080
00081
00082
00083 std::set<int> invalidated_haloes;
00084
00085
00086
00087
00088
00089 std::set<int> new_haloes;
00090
00091
00092
00093 std::set<int> deleted_haloes;
00094
00095
00096
00097 std::set<int> changing_haloes;
00098
00099 effect::effect(int xpos, int ypos, const animated<std::string>::anim_description& img,
00100 const gamemap::location& loc, ORIENTATION orientation, bool infinite) :
00101 images_(img), orientation_(orientation), x_(xpos), y_(ypos),
00102 surf_(NULL), buffer_(NULL), rect_(empty_rect), loc_(loc)
00103 {
00104 assert(disp != NULL);
00105
00106 set_location(xpos,ypos);
00107
00108 images_.start_animation(0,infinite);
00109
00110 }
00111
00112 void effect::set_location(int x, int y)
00113 {
00114 const gamemap::location zero_loc(0,0);
00115 int new_x = x - disp->get_location_x(zero_loc);
00116 int new_y = y - disp->get_location_y(zero_loc);
00117 if (new_x != x_ || new_y != y_) {
00118 x_ = new_x;
00119 y_ = new_y;
00120 buffer_.assign(NULL);
00121 overlayed_hexes_.clear();
00122 }
00123 }
00124
00125 bool effect::render()
00126 {
00127 if(disp == NULL) {
00128 return false;
00129 }
00130
00131 if(loc_.x != -1 && loc_.y != -1) {
00132 if(disp->shrouded(loc_)) {
00133 return false;
00134 } else {
00135
00136
00137
00138
00139
00140
00141
00142 set_location(
00143 disp->get_location_x(loc_) + disp->hex_size() / 2,
00144 disp->get_location_y(loc_) + disp->hex_size() / 2);
00145 }
00146 }
00147
00148 images_.update_last_draw_time();
00149 surf_.assign(image::get_image(current_image(),image::SCALED_TO_ZOOM));
00150 if(surf_ == NULL) {
00151 return false;
00152 }
00153 if(orientation_ == HREVERSE || orientation_ == HVREVERSE) {
00154 surf_.assign(image::reverse_image(surf_));
00155 }
00156 if(orientation_ == VREVERSE || orientation_ == HVREVERSE) {
00157 surf_.assign(flop_surface(surf_));
00158 }
00159
00160 const gamemap::location zero_loc(0,0);
00161 const int screenx = disp->get_location_x(zero_loc);
00162 const int screeny = disp->get_location_y(zero_loc);
00163
00164 const int xpos = x_ + screenx - surf_->w/2;
00165 const int ypos = y_ + screeny - surf_->h/2;
00166
00167 SDL_Rect rect = {xpos,ypos,surf_->w,surf_->h};
00168 rect_ = rect;
00169 SDL_Rect clip_rect = disp->map_outside_area();
00170
00171
00172
00173 if(overlayed_hexes_.empty()) {
00174 gamemap::location topleft, bottomright;
00175 disp->get_rect_hex_bounds(rect, topleft, bottomright);
00176 for (int x = topleft.x; x <= bottomright.x; ++x) {
00177 for (int y = topleft.y; y <= bottomright.y; ++y) {
00178 overlayed_hexes_.push_back(gamemap::location(x, y));
00179 }
00180 }
00181 }
00182
00183 if(rects_overlap(rect,clip_rect) == false) {
00184 buffer_.assign(NULL);
00185 return false;
00186 }
00187
00188 surface const screen = disp->get_screen_surface();
00189
00190 const clip_rect_setter clip_setter(screen,clip_rect);
00191 if(buffer_ == NULL || buffer_->w != rect.w || buffer_->h != rect.h) {
00192 SDL_Rect rect = rect_;
00193 buffer_.assign(get_surface_portion(screen,rect));
00194 } else {
00195 SDL_Rect rect = rect_;
00196 SDL_BlitSurface(screen,&rect,buffer_,NULL);
00197 }
00198
00199 SDL_BlitSurface(surf_,NULL,screen,&rect);
00200
00201 update_rect(rect_);
00202
00203 return true;
00204 }
00205
00206 void effect::unrender()
00207 {
00208 if(buffer_ == NULL) {
00209 return;
00210 }
00211
00212 surface const screen = disp->get_screen_surface();
00213
00214 SDL_Rect clip_rect = disp->map_outside_area();
00215 const clip_rect_setter clip_setter(screen,clip_rect);
00216
00217
00218
00219 const gamemap::location zero_loc(0,0);
00220 const int screenx = disp->get_location_x(zero_loc);
00221 const int screeny = disp->get_location_y(zero_loc);
00222
00223 const int xpos = x_ + screenx - surf_->w/2;
00224 const int ypos = y_ + screeny - surf_->h/2;
00225
00226 SDL_Rect rect = {xpos,ypos,surf_->w,surf_->h};
00227 SDL_BlitSurface(buffer_,NULL,screen,&rect);
00228 update_rect(rect_);
00229 }
00230
00231 bool effect::on_location(const std::set<gamemap::location>& locations) const
00232 {
00233 for(std::vector<gamemap::location>::const_iterator itor = overlayed_hexes_.begin();
00234 itor != overlayed_hexes_.end(); ++itor) {
00235 if(locations.find(*itor) != locations.end()) {
00236 return true;
00237 }
00238 }
00239 return false;
00240 }
00241
00242 void effect::add_overlay_location(std::set<gamemap::location>& locations)
00243 {
00244 for(std::vector<gamemap::location>::const_iterator itor = overlayed_hexes_.begin();
00245 itor != overlayed_hexes_.end(); ++itor) {
00246
00247 locations.insert(*itor);
00248 }
00249 }
00250
00251 }
00252
00253 manager::manager(display& screen) : old(disp)
00254 {
00255 disp = &screen;
00256 }
00257
00258 manager::~manager()
00259 {
00260 haloes.clear();
00261 invalidated_haloes.clear();
00262 new_haloes.clear();
00263 deleted_haloes.clear();
00264 changing_haloes.clear();
00265
00266 disp = old;
00267 }
00268
00269 int add(int x, int y, const std::string& image, const gamemap::location& loc,
00270 ORIENTATION orientation, bool infinite)
00271 {
00272 const int id = halo_id++;
00273 animated<std::string>::anim_description image_vector;
00274 std::vector<std::string> items = utils::split(image);
00275 std::vector<std::string>::const_iterator itor = items.begin();
00276 for(; itor != items.end(); ++itor) {
00277 const std::vector<std::string>& items = utils::split(*itor, ':');
00278 std::string str;
00279 int time;
00280
00281 if(items.size() > 1) {
00282 str = items.front();
00283 time = atoi(items.back().c_str());
00284 } else {
00285 str = *itor;
00286 time = 100;
00287 }
00288 image_vector.push_back(animated<std::string>::frame_description(time,std::string(str)));
00289
00290 }
00291 haloes.insert(std::pair<int,effect>(id,effect(x,y,image_vector,loc,orientation,infinite)));
00292 new_haloes.insert(id);
00293 if(haloes.find(id)->second.does_change() || !infinite) {
00294 changing_haloes.insert(id);
00295 }
00296 return id;
00297 }
00298
00299 void set_location(int handle, int x, int y)
00300 {
00301 const std::map<int,effect>::iterator itor = haloes.find(handle);
00302 if(itor != haloes.end()) {
00303 itor->second.set_location(x,y);
00304 }
00305 }
00306
00307 void remove(int handle)
00308 {
00309
00310
00311 if(handle == NO_HALO || haloes.find(handle) == haloes.end()) {
00312 return;
00313 }
00314
00315 deleted_haloes.insert(handle);
00316 }
00317
00318 void unrender(std::set<gamemap::location> invalidated_locations)
00319 {
00320 assert(invalidated_haloes.size() == 0);
00321 if(preferences::show_haloes() == false || haloes.size() == 0) {
00322 return;
00323 }
00324
00325
00326 std::map<int, effect>::iterator itor = haloes.begin();
00327 for(; itor != haloes.end(); ++itor ) {
00328 if(itor->second.expired()) {
00329 deleted_haloes.insert(itor->first);
00330 }
00331 }
00332
00333
00334 std::set<int>::const_iterator set_itor = deleted_haloes.begin();
00335 for(;set_itor != deleted_haloes.end(); ++set_itor) {
00336 invalidated_haloes.insert(*set_itor);
00337 haloes.find(*set_itor)->second.add_overlay_location(invalidated_locations);
00338 }
00339
00340
00341 for(set_itor = changing_haloes.begin();
00342 set_itor != changing_haloes.end(); ++set_itor) {
00343 if(haloes.find(*set_itor)->second.need_update()) {
00344 invalidated_haloes.insert(*set_itor);
00345 haloes.find(*set_itor)->second.add_overlay_location(invalidated_locations);
00346 }
00347 }
00348
00349
00350 size_t halo_count;
00351
00352
00353
00354 do {
00355 halo_count = invalidated_haloes.size();
00356 for(itor = haloes.begin(); itor != haloes.end(); ++itor) {
00357
00358
00359 if(invalidated_haloes.find(itor->first) == invalidated_haloes.end() &&
00360 itor->second.on_location(invalidated_locations)) {
00361
00362
00363
00364 itor->second.add_overlay_location(invalidated_locations);
00365 invalidated_haloes.insert(itor->first);
00366 }
00367 }
00368 } while (halo_count != invalidated_haloes.size() && halo_count != haloes.size());
00369
00370 if(halo_count == 0) {
00371 return;
00372 }
00373
00374
00375
00376 for(std::map<int, effect>::reverse_iterator ritor = haloes.rbegin(); ritor != haloes.rend(); ++ritor) {
00377 if(invalidated_haloes.find(ritor->first) != invalidated_haloes.end()) {
00378 ritor->second.unrender();
00379 }
00380 }
00381
00382
00383 for(set_itor = deleted_haloes.begin(); set_itor != deleted_haloes.end(); ++set_itor) {
00384
00385 new_haloes.erase(*set_itor);
00386
00387 changing_haloes.erase(*set_itor);
00388 invalidated_haloes.erase(*set_itor);
00389 haloes.erase(*set_itor);
00390 }
00391
00392 deleted_haloes.clear();
00393 }
00394
00395 void render()
00396 {
00397 if(preferences::show_haloes() == false || haloes.size() == 0 ||
00398 (new_haloes.size() == 0 && invalidated_haloes.size() == 0)) {
00399 return;
00400 }
00401
00402
00403
00404 std::set<int> unrendered_new_haloes;
00405
00406
00407
00408 for(std::map<int, effect>::iterator itor = haloes.begin();
00409 itor != haloes.end(); ++itor) {
00410
00411 if(new_haloes.find(itor->first) != new_haloes.end() &&
00412 ! itor->second.render()) {
00413
00414 unrendered_new_haloes.insert(itor->first);
00415 } else if(invalidated_haloes.find(itor->first) != invalidated_haloes.end()) {
00416 itor->second.render();
00417 }
00418 }
00419
00420 invalidated_haloes.clear();
00421 new_haloes = unrendered_new_haloes;
00422 }
00423
00424 }
00425