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