00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "builder.hpp"
00022 #include "cursor.hpp"
00023 #include "display.hpp"
00024 #include "foreach.hpp"
00025 #include "game_preferences.hpp"
00026 #include "gettext.hpp"
00027 #include "halo.hpp"
00028 #include "hotkeys.hpp"
00029 #include "language.hpp"
00030 #include "log.hpp"
00031 #include "marked-up_text.hpp"
00032 #include "map.hpp"
00033 #include "map_label.hpp"
00034 #include "minimap.hpp"
00035 #include "text.hpp"
00036 #include "time_of_day.hpp"
00037 #include "tooltips.hpp"
00038 #include "arrow.hpp"
00039 #include "tod_manager.hpp"
00040 #include "resources.hpp"
00041
00042 #include "SDL_image.h"
00043
00044 #ifdef __SUNPRO_CC
00045
00046 #include <math.h>
00047 #endif
00048 #include <cmath>
00049
00050
00051 #if defined(__GLIBC__)
00052 #include <gnu/libc-version.h>
00053 #include <cstdio>
00054 #endif
00055
00056 static lg::log_domain log_display("display");
00057 #define ERR_DP LOG_STREAM(err, log_display)
00058 #define LOG_DP LOG_STREAM(info, log_display)
00059 #define DBG_DP LOG_STREAM(debug, log_display)
00060
00061 namespace {
00062 const int DefaultZoom = 72;
00063 const int SmallZoom = DefaultZoom / 2;
00064
00065 const int MinZoom = 4;
00066 const int MaxZoom = 200;
00067 size_t sunset_delay = 0;
00068
00069 bool benchmark = false;
00070
00071 bool debug_foreground = false;
00072 }
00073
00074 int display::last_zoom_ = SmallZoom;
00075
00076 display::display(unit_map* units, CVideo& video, const gamemap* map, const std::vector<team>* t,const config& theme_cfg, const config& level) :
00077 units_(units),
00078 exclusive_unit_draw_requests_(),
00079 screen_(video),
00080 map_(map),
00081 currentTeam_(0),
00082 teams_(t),
00083 viewpoint_(NULL),
00084 energy_bar_rects_(),
00085 xpos_(0),
00086 ypos_(0),
00087 theme_(theme_cfg, screen_area()),
00088 zoom_(DefaultZoom),
00089 builder_(new terrain_builder(level, map, theme_.border().tile_image)),
00090 minimap_(NULL),
00091 minimap_location_(empty_rect),
00092 redrawMinimap_(false),
00093 redraw_background_(true),
00094 invalidateAll_(true),
00095 grid_(false),
00096 diagnostic_label_(0),
00097 panelsDrawn_(false),
00098 turbo_speed_(2),
00099 turbo_(false),
00100 invalidateGameStatus_(true),
00101 map_labels_(new map_labels(*this, 0)),
00102 scroll_event_("scrolled"),
00103 complete_redraw_event_("completely_redrawn"),
00104 nextDraw_(0),
00105 reportRects_(),
00106 reportSurfaces_(),
00107 reports_(),
00108 buttons_(),
00109 invalidated_(),
00110 previous_invalidated_(),
00111 mouseover_hex_overlay_(NULL),
00112 tod_hex_mask1(NULL),
00113 tod_hex_mask2(NULL),
00114 fog_images_(),
00115 shroud_images_(),
00116 selectedHex_(),
00117 mouseoverHex_(),
00118 keys_(),
00119 animate_map_(true),
00120 local_tod_light_(false),
00121 activeTeam_(0),
00122 drawing_buffer_(),
00123 map_screenshot_(false),
00124 fps_handle_(0),
00125 invalidated_hexes_(0),
00126 drawn_hexes_(0),
00127 idle_anim_(preferences::idle_anim()),
00128 idle_anim_rate_(1.0),
00129 map_screenshot_surf_(NULL),
00130 redraw_observers_(),
00131 draw_coordinates_(false),
00132 draw_terrain_codes_(false),
00133 arrows_map_(),
00134 color_adjust_()
00135 #if defined(__GLIBC__)
00136 , do_reverse_memcpy_workaround_(false)
00137 #endif
00138 {
00139 singleton_ = this;
00140
00141 read(level.child_or_empty("display"));
00142
00143 if(non_interactive()
00144 && (get_video_surface() != NULL
00145 && video.faked())) {
00146 screen_.lock_updates(true);
00147 }
00148
00149 fill_images_list(game_config::fog_prefix, fog_images_);
00150 fill_images_list(game_config::shroud_prefix, shroud_images_);
00151
00152 set_idle_anim_rate(preferences::idle_anim_rate());
00153
00154 image::set_zoom(zoom_);
00155
00156 #if defined(__GLIBC__)
00157
00158
00159 int glibc, glibc_minor;
00160 sscanf(gnu_get_libc_version(), "%d.%d", &glibc, &glibc_minor);
00161
00162
00163 const SDL_version* v = SDL_Linked_Version();
00164
00165 do_reverse_memcpy_workaround_ = (glibc > 2 || (glibc == 2 && glibc_minor >= 13)) &&
00166 (v->major < 1 || (v->major == 1 && v->minor < 2) ||
00167 (v->major == 1 && v->minor == 2 && v->patch < 15) );
00168 #endif
00169 }
00170
00171 display::~display()
00172 {
00173 singleton_ = NULL;
00174 }
00175
00176 struct is_energy_color {
00177 bool operator()(Uint32 color) const { return (color&0xFF000000) > 0x10000000 &&
00178 (color&0x00FF0000) < 0x00100000 &&
00179 (color&0x0000FF00) < 0x00001000 &&
00180 (color&0x000000FF) < 0x00000010; }
00181 };
00182
00183
00184 const SDL_Rect& display::calculate_energy_bar(surface surf)
00185 {
00186 const std::map<surface,SDL_Rect>::const_iterator i = energy_bar_rects_.find(surf);
00187 if(i != energy_bar_rects_.end()) {
00188 return i->second;
00189 }
00190
00191 int first_row = -1, last_row = -1, first_col = -1, last_col = -1;
00192
00193 surface image(make_neutral_surface(surf));
00194
00195 const_surface_lock image_lock(image);
00196 const Uint32* const begin = image_lock.pixels();
00197
00198 for(int y = 0; y != image->h; ++y) {
00199 const Uint32* const i1 = begin + image->w*y;
00200 const Uint32* const i2 = i1 + image->w;
00201 const Uint32* const itor = std::find_if(i1,i2,is_energy_color());
00202 const int count = std::count_if(itor,i2,is_energy_color());
00203
00204 if(itor != i2) {
00205 if(first_row == -1) {
00206 first_row = y;
00207 }
00208
00209 first_col = itor - i1;
00210 last_col = first_col + count;
00211 last_row = y;
00212 }
00213 }
00214
00215 const SDL_Rect res = create_rect(first_col
00216 , first_row
00217 , last_col-first_col
00218 , last_row+1-first_row);
00219 energy_bar_rects_.insert(std::pair<surface,SDL_Rect>(surf,res));
00220 return calculate_energy_bar(surf);
00221 }
00222
00223
00224
00225 void display::draw_bar(const std::string& image, int xpos, int ypos,
00226 const map_location& loc, size_t height, double filled,
00227 const SDL_Color& col, fixed_t alpha)
00228 {
00229
00230 filled = std::min<double>(std::max<double>(filled,0.0),1.0);
00231 height = static_cast<size_t>(height*get_zoom_factor());
00232
00233 surface surf(image::get_image(image,image::SCALED_TO_HEX));
00234
00235
00236
00237
00238 surface bar_surf(image::get_image(image));
00239 if(surf == NULL || bar_surf == NULL) {
00240 return;
00241 }
00242
00243
00244
00245 const SDL_Rect& unscaled_bar_loc = calculate_energy_bar(bar_surf);
00246
00247 SDL_Rect bar_loc;
00248 if (surf->w == bar_surf->w && surf->h == bar_surf->h)
00249 bar_loc = unscaled_bar_loc;
00250 else {
00251 const fixed_t xratio = fxpdiv(surf->w,bar_surf->w);
00252 const fixed_t yratio = fxpdiv(surf->h,bar_surf->h);
00253 const SDL_Rect scaled_bar_loc = create_rect(
00254 fxptoi(unscaled_bar_loc. x * xratio)
00255 , fxptoi(unscaled_bar_loc. y * yratio + 127)
00256 , fxptoi(unscaled_bar_loc. w * xratio + 255)
00257 , fxptoi(unscaled_bar_loc. h * yratio + 255));
00258 bar_loc = scaled_bar_loc;
00259 }
00260
00261 if(height > bar_loc.h) {
00262 height = bar_loc.h;
00263 }
00264
00265
00266
00267
00268
00269
00270
00271
00272 const size_t skip_rows = bar_loc.h - height;
00273
00274 SDL_Rect top = create_rect(0, 0, surf->w, bar_loc.y);
00275 SDL_Rect bot = create_rect(0, bar_loc.y + skip_rows, surf->w, 0);
00276 bot.h = surf->w - bot.y;
00277
00278 drawing_buffer_add(LAYER_UNIT_BAR, loc, xpos, ypos, surf, top);
00279 drawing_buffer_add(LAYER_UNIT_BAR, loc, xpos, ypos + top.h, surf, bot);
00280
00281 size_t unfilled = static_cast<size_t>(height * (1.0 - filled));
00282
00283 if(unfilled < height && alpha >= ftofxp(0.3)) {
00284 const Uint8 r_alpha = std::min<unsigned>(unsigned(fxpmult(alpha,255)),255);
00285 surface filled_surf = create_compatible_surface(bar_surf, bar_loc.w, height - unfilled);
00286 SDL_Rect filled_area = create_rect(0, 0, bar_loc.w, height-unfilled);
00287 sdl_fill_rect(filled_surf,&filled_area,SDL_MapRGBA(bar_surf->format,col.r,col.g,col.b, r_alpha));
00288 drawing_buffer_add(LAYER_UNIT_BAR, loc, xpos + bar_loc.x, ypos + bar_loc.y + unfilled, filled_surf);
00289 }
00290 }
00291
00292
00293 bool display::add_exclusive_draw(const map_location& loc, unit& unit)
00294 {
00295 if (loc.valid() && exclusive_unit_draw_requests_.find(loc) == exclusive_unit_draw_requests_.end())
00296 {
00297 exclusive_unit_draw_requests_[loc] = unit.id();
00298 return true;
00299 }
00300 else
00301 {
00302 return false;
00303 }
00304 }
00305
00306 std::string display::remove_exclusive_draw(const map_location& loc)
00307 {
00308 std::string id = "";
00309 if(loc.valid())
00310 {
00311 id = exclusive_unit_draw_requests_[loc];
00312
00313 exclusive_unit_draw_requests_.erase(loc);
00314 }
00315 return id;
00316 }
00317
00318 const time_of_day & display::get_time_of_day(const map_location& ) const
00319 {
00320 static time_of_day tod;
00321 return tod;
00322 }
00323
00324 void display::update_tod() {
00325 const time_of_day& tod = get_time_of_day();
00326 tod_color col = color_adjust_ + tod.color;
00327 image::set_color_adjustment(col.r, col.g, col.b);
00328 }
00329
00330 void display::adjust_color_overlay(int r, int g, int b) {
00331 color_adjust_ = tod_color(r, g, b);
00332 update_tod();
00333 }
00334
00335
00336 void display::fill_images_list(const std::string& prefix, std::vector<std::string>& images)
00337 {
00338
00339 for(int i=0; ; ++i){
00340 std::ostringstream s;
00341 s << prefix;
00342 if(i != 0)
00343 s << i;
00344 s << ".png";
00345 if(image::exists(s.str()))
00346 images.push_back(s.str());
00347 else if(i>0)
00348 break;
00349 }
00350 if (images.empty())
00351 images.push_back("");
00352 }
00353
00354 const std::string& display::get_variant(const std::vector<std::string>& variants, const map_location &loc) const
00355 {
00356
00357 return variants[abs(loc.x + loc.y) % variants.size()];
00358 }
00359
00360 void display::rebuild_all()
00361 {
00362 builder_->rebuild_all();
00363 }
00364
00365 void display::reload_map()
00366 {
00367 redraw_background_ = true;
00368 builder_->reload_map();
00369 }
00370
00371 void display::change_map(const gamemap* m)
00372 {
00373 map_ = m;
00374 builder_->change_map(m);
00375 }
00376
00377 void display::change_units(unit_map* umap)
00378 {
00379 units_ = umap;
00380 }
00381
00382 void display::change_teams(const std::vector<team>* teams)
00383 {
00384 teams_ = teams;
00385 }
00386
00387
00388 const SDL_Rect& display::max_map_area() const
00389 {
00390 static SDL_Rect max_area = {0, 0, 0, 0};
00391
00392
00393
00394
00395
00396
00397
00398
00399 max_area.w = static_cast<int>((get_map().w() + 2 * theme_.border().size + 1.0/3.0) * hex_width());
00400 max_area.h = static_cast<int>((get_map().h() + 2 * theme_.border().size + 0.5) * hex_size());
00401
00402 return max_area;
00403 }
00404
00405 const SDL_Rect& display::map_area() const
00406 {
00407 static SDL_Rect max_area;
00408 max_area = max_map_area();
00409
00410
00411 if (map_screenshot_) {
00412 return max_area;
00413 }
00414
00415 static SDL_Rect res;
00416 res = map_outside_area();
00417
00418 if(max_area.w < res.w) {
00419
00420 res.x += (res.w - max_area.w)/2;
00421 res.w = max_area.w;
00422 }
00423
00424 if(max_area.h < res.h) {
00425
00426 res.y += (res.h - max_area.h)/2;
00427 res.h = max_area.h;
00428 }
00429
00430 return res;
00431 }
00432
00433 bool display::outside_area(const SDL_Rect& area, const int x, const int y) const
00434 {
00435 const int x_thresh = hex_size();
00436 const int y_thresh = hex_size();
00437 return (x < area.x || x > area.x + area.w - x_thresh ||
00438 y < area.y || y > area.y + area.h - y_thresh);
00439 }
00440
00441
00442 const map_location display::hex_clicked_on(int xclick, int yclick) const
00443 {
00444 const SDL_Rect& rect = map_area();
00445 if(point_in_rect(xclick,yclick,rect) == false) {
00446 return map_location();
00447 }
00448
00449 xclick -= rect.x;
00450 yclick -= rect.y;
00451
00452 return pixel_position_to_hex(xpos_ + xclick, ypos_ + yclick);
00453 }
00454
00455
00456
00457 const map_location display::pixel_position_to_hex(int x, int y) const
00458 {
00459
00460 x -= static_cast<int>(theme_.border().size * hex_width());
00461 y -= static_cast<int>(theme_.border().size * hex_size());
00462
00463
00464
00465 const int offset = y < 0 ? 1 : 0;
00466 if(offset) {
00467 x += hex_width();
00468 y += hex_size();
00469 }
00470 const int s = hex_size();
00471 const int tesselation_x_size = hex_width() * 2;
00472 const int tesselation_y_size = s;
00473 const int x_base = x / tesselation_x_size * 2;
00474 const int x_mod = x % tesselation_x_size;
00475 const int y_base = y / tesselation_y_size;
00476 const int y_mod = y % tesselation_y_size;
00477
00478 int x_modifier = 0;
00479 int y_modifier = 0;
00480
00481 if (y_mod < tesselation_y_size / 2) {
00482 if ((x_mod * 2 + y_mod) < (s / 2)) {
00483 x_modifier = -1;
00484 y_modifier = -1;
00485 } else if ((x_mod * 2 - y_mod) < (s * 3 / 2)) {
00486 x_modifier = 0;
00487 y_modifier = 0;
00488 } else {
00489 x_modifier = 1;
00490 y_modifier = -1;
00491 }
00492
00493 } else {
00494 if ((x_mod * 2 - (y_mod - s / 2)) < 0) {
00495 x_modifier = -1;
00496 y_modifier = 0;
00497 } else if ((x_mod * 2 + (y_mod - s / 2)) < s * 2) {
00498 x_modifier = 0;
00499 y_modifier = 0;
00500 } else {
00501 x_modifier = 1;
00502 y_modifier = 0;
00503 }
00504 }
00505
00506 return map_location(x_base + x_modifier - offset, y_base + y_modifier - offset);
00507 }
00508
00509 display::rect_of_hexes::iterator& display::rect_of_hexes::iterator::operator++()
00510 {
00511 if (loc_.y < rect_.bottom[loc_.x & 1])
00512 ++loc_.y;
00513 else {
00514 ++loc_.x;
00515 loc_.y = rect_.top[loc_.x & 1];
00516 }
00517
00518 return *this;
00519 }
00520
00521
00522 display::rect_of_hexes::iterator display::rect_of_hexes::begin() const
00523 {
00524 return iterator(map_location(left, top[left & 1]), *this);
00525 }
00526 display::rect_of_hexes::iterator display::rect_of_hexes::end() const
00527 {
00528 return iterator(map_location(right+1, top[(right+1) & 1]), *this);
00529 }
00530
00531 const display::rect_of_hexes display::hexes_under_rect(const SDL_Rect& r) const
00532 {
00533 rect_of_hexes res;
00534
00535 if (r.w<=0 || r.h<=0) {
00536
00537 res.left = 0;
00538 res.right = -1;
00539 res.top[0] = 0;
00540 res.top[1] = 0;
00541 res.bottom[0] = 0;
00542 res.bottom[1] = 0;
00543 return res;
00544 }
00545
00546 SDL_Rect map_rect = map_area();
00547
00548 int x = xpos_ - map_rect.x + r.x;
00549 int y = ypos_ - map_rect.y + r.y;
00550
00551
00552 double tile_width = hex_width();
00553 double tile_size = hex_size();
00554 double border = theme_.border().size;
00555
00556
00557
00558
00559 res.left = static_cast<int>(std::floor(-border + x / tile_width - 0.3333333));
00560
00561
00562 res.right = static_cast<int>(std::floor(-border + (x + r.w-1) / tile_width));
00563
00564
00565
00566 res.top[0] = static_cast<int>(std::floor(-border + y / tile_size));
00567 res.top[1] = static_cast<int>(std::floor(-border + y / tile_size - 0.5));
00568 res.bottom[0] = static_cast<int>(std::floor(-border + (y + r.h-1) / tile_size));
00569 res.bottom[1] = static_cast<int>(std::floor(-border + (y + r.h-1) / tile_size - 0.5));
00570
00571
00572
00573
00574
00575 return res;
00576 }
00577
00578 int display::get_location_x(const map_location& loc) const
00579 {
00580 return static_cast<int>(map_area().x + (loc.x + theme_.border().size) * hex_width() - xpos_);
00581 }
00582
00583 int display::get_location_y(const map_location& loc) const
00584 {
00585 return static_cast<int>(map_area().y + (loc.y + theme_.border().size) * zoom_ - ypos_ + (is_odd(loc.x) ? zoom_/2 : 0));
00586 }
00587
00588 map_location display::minimap_location_on(int x, int y)
00589 {
00590
00591
00592
00593 if (!point_in_rect(x, y, minimap_area())) {
00594 return map_location();
00595 }
00596
00597
00598
00599
00600
00601 int px = (x - minimap_location_.x) * get_map().w()*hex_width() / minimap_location_.w;
00602 int py = (y - minimap_location_.y) * get_map().h()*hex_size() / minimap_location_.h;
00603
00604 map_location loc = pixel_position_to_hex(px, py);
00605 if (loc.x < 0)
00606 loc.x = 0;
00607 else if (loc.x >= get_map().w())
00608 loc.x = get_map().w() - 1;
00609
00610 if (loc.y < 0)
00611 loc.y = 0;
00612 else if (loc.y >= get_map().h())
00613 loc.y = get_map().h() - 1;
00614
00615 return loc;
00616 }
00617
00618 int display::screenshot(std::string filename, bool map_screenshot)
00619 {
00620 int size = 0;
00621 if (!map_screenshot) {
00622 surface screenshot_surf = screen_.getSurface();
00623 SDL_SaveBMP(screenshot_surf, filename.c_str());
00624 size = screenshot_surf->w * screenshot_surf->h;
00625 } else {
00626 if (get_map().empty()) {
00627
00628 std::cerr << "No map, can't do a Map Screenshot. If it was not wanted, check your hotkey.\n";
00629 return -1;
00630 }
00631
00632 SDL_Rect area = max_map_area();
00633 map_screenshot_surf_ = create_compatible_surface(screen_.getSurface(), area.w, area.h);
00634
00635 if (map_screenshot_surf_ == NULL) {
00636
00637 std::cerr << "Can't create the screenshot surface. Maybe too big, try dezooming.\n";
00638 return -1;
00639 }
00640 size = map_screenshot_surf_->w * map_screenshot_surf_->h;
00641
00642
00643 int old_xpos = xpos_;
00644 int old_ypos = ypos_;
00645 xpos_ = 0;
00646 ypos_ = 0;
00647
00648
00649 map_screenshot_= true ;
00650 invalidateAll_ = true;
00651 DBG_DP << "draw() with map_screenshot\n";
00652 draw(true,true);
00653
00654
00655 SDL_SaveBMP(map_screenshot_surf_, filename.c_str());
00656
00657
00658 map_screenshot_surf_ = NULL;
00659
00660
00661 map_screenshot_= false;
00662 xpos_ = old_xpos;
00663 ypos_ = old_ypos;
00664
00665
00666 redraw_everything();
00667 }
00668
00669
00670 size = (2048 + size*3);
00671 return size;
00672 }
00673
00674 gui::button* display::find_button(const std::string& id)
00675 {
00676 for (size_t i = 0; i < buttons_.size(); ++i) {
00677 if(buttons_[i].id() == id) {
00678 return &buttons_[i];
00679 }
00680 }
00681 return NULL;
00682 }
00683
00684 void display::create_buttons()
00685 {
00686 std::vector<gui::button> work;
00687
00688 DBG_DP << "creating buttons...\n";
00689 const std::vector<theme::menu>& buttons = theme_.menus();
00690 for(std::vector<theme::menu>::const_iterator i = buttons.begin(); i != buttons.end(); ++i) {
00691 gui::button b(screen_,i->title(),string_to_button_type(i->type()),i->image());
00692 DBG_DP << "drawing button " << i->get_id() << "\n";
00693 b.set_id(i->get_id());
00694 const SDL_Rect& loc = i->location(screen_area());
00695 b.set_location(loc.x,loc.y);
00696 if (!i->tooltip().empty()){
00697 tooltips::add_tooltip(loc, i->tooltip());
00698 }
00699 if(rects_overlap(b.location(),map_outside_area())) {
00700 b.set_volatile(true);
00701 }
00702
00703 gui::button* b_prev = find_button(b.id());
00704 if(b_prev) b.enable(b_prev->enabled());
00705
00706 work.push_back(b);
00707 }
00708
00709 buttons_.swap(work);
00710 DBG_DP << "buttons created\n";
00711 }
00712
00713 gui::button::TYPE display::string_to_button_type(std::string type)
00714 {
00715 gui::button::TYPE res = gui::button::TYPE_PRESS;
00716 if (type == "checkbox") { res = gui::button::TYPE_CHECK; }
00717 else if (type == "image") { res = gui::button::TYPE_IMAGE; }
00718 return res;
00719 }
00720
00721 static const std::string& get_direction(size_t n)
00722 {
00723 static std::string const dirs[6] = { "-n", "-ne", "-se", "-s", "-sw", "-nw" };
00724 return dirs[n >= sizeof(dirs)/sizeof(*dirs) ? 0 : n];
00725 }
00726
00727 std::vector<surface> display::get_fog_shroud_images(const map_location& loc, image::TYPE image_type)
00728 {
00729 std::vector<std::string> names;
00730
00731 map_location adjacent[6];
00732 get_adjacent_tiles(loc,adjacent);
00733
00734 enum visibility {FOG=0, SHROUD=1, CLEAR=2};
00735 visibility tiles[6];
00736
00737 const std::string* image_prefix[] =
00738 { &game_config::fog_prefix, &game_config::shroud_prefix};
00739
00740 for(int i = 0; i != 6; ++i) {
00741 if(shrouded(adjacent[i])) {
00742 tiles[i] = SHROUD;
00743 } else if(!fogged(loc) && fogged(adjacent[i])) {
00744 tiles[i] = FOG;
00745 } else {
00746 tiles[i] = CLEAR;
00747 }
00748 }
00749
00750 for(int v = FOG; v != CLEAR; ++v) {
00751
00752 int start;
00753 for(start = 0; start != 6; ++start) {
00754 if(tiles[start] != v) {
00755 break;
00756 }
00757 }
00758
00759 if(start == 6) {
00760 start = 0;
00761 }
00762
00763
00764 for(int i = (start+1)%6, n = 0; i != start && n != 6; ++n) {
00765 if(tiles[i] == v) {
00766 std::ostringstream stream;
00767 std::string name;
00768 stream << *image_prefix[v];
00769
00770 for(int n = 0; v == tiles[i] && n != 6; i = (i+1)%6, ++n) {
00771 stream << get_direction(i);
00772
00773 if(!image::exists(stream.str() + ".png")) {
00774
00775
00776 if(name.empty()) {
00777 i = (i+1)%6;
00778 }
00779 break;
00780 } else {
00781 name = stream.str();
00782 }
00783 }
00784
00785 if(!name.empty()) {
00786 names.push_back(name + ".png");
00787 }
00788 } else {
00789 i = (i+1)%6;
00790 }
00791 }
00792 }
00793
00794
00795 std::vector<surface> res;
00796
00797 foreach(std::string& name, names) {
00798 const surface surf(image::get_image(name, image_type));
00799 if (surf)
00800 res.push_back(surf);
00801 }
00802
00803 return res;
00804 }
00805
00806 std::vector<surface> display::get_terrain_images(const map_location &loc,
00807 const std::string& timeid,
00808 image::TYPE image_type,
00809 TERRAIN_TYPE terrain_type)
00810 {
00811 std::vector<surface> res;
00812
00813 terrain_builder::TERRAIN_TYPE builder_terrain_type =
00814 (terrain_type == FOREGROUND ?
00815 terrain_builder::FOREGROUND : terrain_builder::BACKGROUND);
00816
00817 const terrain_builder::imagelist* const terrains = builder_->get_terrain_at(loc,
00818 timeid, builder_terrain_type);
00819
00820 image::light_string lt;
00821 bool use_local_light = local_tod_light_;
00822 if(use_local_light){
00823 const time_of_day& tod = get_time_of_day(loc);
00824
00825
00826 map_location adjs[6];
00827 get_adjacent_tiles(loc,adjs);
00828 for(int d=0; d<6; ++d){
00829 const time_of_day& atod = get_time_of_day(adjs[d]);
00830 if(atod.color == tod.color)
00831 continue;
00832
00833 if(lt.empty()) {
00834
00835 tod_color col = tod.color + color_adjust_;
00836 lt = image::get_light_string(6, col.r, col.g, col.b);
00837 }
00838
00839
00840 tod_color acol = atod.color + color_adjust_;
00841 lt += image::get_light_string(d, acol.r, acol.g, acol.b);
00842 }
00843
00844 if(lt.empty()){
00845 if(tod.color == get_time_of_day().color) {
00846 use_local_light = false;
00847 } else {
00848 tod_color col = tod.color + color_adjust_;
00849 if(!col.is_zero()){
00850
00851 lt = image::get_light_string(-1, col.r, col.g, col.b);
00852 }
00853 }
00854 }
00855 }
00856
00857 if(terrains != NULL) {
00858
00859
00860
00861 const std::string off_map_name = "terrain/" + theme_.border().tile_image;
00862 for(std::vector<animated<image::locator> >::const_iterator it =
00863 terrains->begin(); it != terrains->end(); ++it) {
00864
00865 const image::locator &image = animate_map_ ?
00866 it->get_current_frame() : it->get_first_frame();
00867
00868
00869
00870
00871
00872
00873 surface surf;
00874 const bool off_map = image.get_filename() == off_map_name;
00875 if(!use_local_light || off_map) {
00876 surf = image::get_image(image, off_map ? image::SCALED_TO_HEX : image_type);
00877 } else if(lt.empty()) {
00878 surf = image::get_image(image, image::SCALED_TO_HEX);
00879 } else {
00880 surf = image::get_lighted_image(image, lt, image::SCALED_TO_HEX);
00881 }
00882
00883 if (!surf.null()) {
00884 res.push_back(surf);
00885 }
00886 }
00887 }
00888
00889 return res;
00890 }
00891
00892 void display::drawing_buffer_add(const tdrawing_layer layer,
00893 const map_location& loc, int x, int y, const surface& surf,
00894 const SDL_Rect &clip)
00895 {
00896 drawing_buffer_.push_back(tblit(layer, loc, x, y, surf, clip));
00897 }
00898
00899 void display::drawing_buffer_add(const tdrawing_layer layer,
00900 const map_location& loc, int x, int y,
00901 const std::vector<surface> &surf,
00902 const SDL_Rect &clip)
00903 {
00904 drawing_buffer_.push_back(tblit(layer, loc, x, y, surf, clip));
00905 }
00906
00907
00908
00909
00910
00911 const display::tdrawing_layer display::drawing_buffer_key::layer_groups[] = {
00912 LAYER_TERRAIN_BG,
00913 LAYER_UNIT_FIRST,
00914 LAYER_UNIT_MOVE_DEFAULT,
00915
00916 LAYER_REACHMAP,
00917 LAYER_LAST_LAYER
00918 };
00919
00920
00921 const unsigned int display::drawing_buffer_key::max_layer_group = sizeof(display::drawing_buffer_key::layer_groups) / sizeof(display::tdrawing_layer) - 2;
00922
00923 enum {
00924
00925
00926
00927 MAX_BORDER = 3,
00928
00929
00930
00931 BITS_FOR_LAYER_GROUP = 4,
00932
00933
00934 BITS_FOR_Y = 10,
00935
00936
00937 BITS_FOR_X_PARITY = 1,
00938
00939
00940 BITS_FOR_LAYER = 8,
00941
00942
00943 BITS_FOR_X_OVER_2 = 9
00944 };
00945
00946 inline display::drawing_buffer_key::drawing_buffer_key(const map_location &loc, tdrawing_layer layer)
00947 : key_(0)
00948 {
00949
00950
00951 unsigned int g = max_layer_group;
00952 while (layer < layer_groups[g]) {
00953 --g;
00954 }
00955
00956 enum {
00957 SHIFT_LAYER = BITS_FOR_X_OVER_2,
00958 SHIFT_X_PARITY = BITS_FOR_LAYER + SHIFT_LAYER,
00959 SHIFT_Y = BITS_FOR_X_PARITY + SHIFT_X_PARITY,
00960 SHIFT_LAYER_GROUP = BITS_FOR_Y + SHIFT_Y
00961 };
00962 BOOST_STATIC_ASSERT(SHIFT_LAYER_GROUP + BITS_FOR_LAYER_GROUP == sizeof(key_) * 8);
00963
00964
00965
00966
00967
00968 const unsigned int x_parity = static_cast<unsigned int>(loc.x) & 1;
00969 key_ = (g << SHIFT_LAYER_GROUP) | (static_cast<unsigned int>(loc.y + MAX_BORDER) << SHIFT_Y);
00970 key_ |= (x_parity << SHIFT_X_PARITY);
00971 key_ |= (static_cast<unsigned int>(layer) << SHIFT_LAYER) | static_cast<unsigned int>(loc.x + MAX_BORDER) / 2;
00972 }
00973
00974 void display::drawing_buffer_commit()
00975 {
00976
00977 drawing_buffer_.sort();
00978
00979 SDL_Rect clip_rect = map_area();
00980 surface screen = get_screen_surface();
00981 clip_rect_setter set_clip_rect(screen, &clip_rect);
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996 foreach(const tblit &blit, drawing_buffer_) {
00997 foreach(const surface& surf, blit.surf()) {
00998
00999
01000
01001 SDL_Rect dstrect = create_rect(blit.x(), blit.y(), 0, 0);
01002 SDL_Rect srcrect = blit.clip();
01003 SDL_Rect *srcrectArg = (srcrect.x | srcrect.y | srcrect.w | srcrect.h)
01004 ? &srcrect : NULL;
01005 sdl_blit(surf, srcrectArg, screen, &dstrect);
01006
01007 }
01008 }
01009 drawing_buffer_clear();
01010 }
01011
01012 void display::drawing_buffer_clear()
01013 {
01014 drawing_buffer_.clear();
01015 }
01016
01017 void display::sunset(const size_t delay)
01018 {
01019
01020 sunset_delay = (sunset_delay == 0 && delay == 0) ? 3 : delay;
01021 }
01022
01023 void display::toggle_benchmark()
01024 {
01025 benchmark = !benchmark;
01026 }
01027
01028 void display::toggle_debug_foreground()
01029 {
01030 debug_foreground = !debug_foreground;
01031 }
01032
01033 void display::flip()
01034 {
01035 if(video().faked()) {
01036 return;
01037 }
01038
01039 surface frameBuffer = get_video_surface();
01040
01041
01042 static size_t sunset_timer = 0;
01043 if (sunset_delay && ++sunset_timer > sunset_delay) {
01044 sunset_timer = 0;
01045 SDL_Rect r = map_outside_area();
01046 const Uint32 color = SDL_MapRGBA(video().getSurface()->format,0,0,0,255);
01047
01048 fill_rect_alpha(r, color, 1, frameBuffer);
01049 update_rect(r);
01050 }
01051
01052 font::draw_floating_labels(frameBuffer);
01053 events::raise_volatile_draw_event();
01054 cursor::draw(frameBuffer);
01055
01056 video().flip();
01057
01058 cursor::undraw(frameBuffer);
01059 events::raise_volatile_undraw_event();
01060 font::undraw_floating_labels(frameBuffer);
01061 }
01062
01063 void display::update_display()
01064 {
01065 if (screen_.update_locked()) {
01066 return;
01067 }
01068
01069 if(preferences::show_fps() || benchmark) {
01070 static int last_sample = SDL_GetTicks();
01071 static int frames = 0;
01072 ++frames;
01073 const int sample_freq = 10;
01074 if(frames == sample_freq) {
01075 const int this_sample = SDL_GetTicks();
01076
01077 const int fps = (frames*1000)/(this_sample - last_sample);
01078 last_sample = this_sample;
01079 frames = 0;
01080
01081 if(fps_handle_ != 0) {
01082 font::remove_floating_label(fps_handle_);
01083 fps_handle_ = 0;
01084 }
01085 std::ostringstream stream;
01086 stream << "fps: " << fps;
01087 if (game_config::debug) {
01088 stream << "\nhex: " << drawn_hexes_*1.0/sample_freq;
01089 if (drawn_hexes_ != invalidated_hexes_)
01090 stream << " (" << (invalidated_hexes_-drawn_hexes_)*1.0/sample_freq << ")";
01091 }
01092 drawn_hexes_ = 0;
01093 invalidated_hexes_ = 0;
01094
01095 font::floating_label flabel(stream.str());
01096 flabel.set_font_size(12);
01097 flabel.set_color(benchmark ? font::BAD_COLOR : font::NORMAL_COLOR);
01098 flabel.set_position(10, 100);
01099 flabel.set_alignment(font::LEFT_ALIGN);
01100
01101 fps_handle_ = font::add_floating_label(flabel);
01102 }
01103 } else if(fps_handle_ != 0) {
01104 font::remove_floating_label(fps_handle_);
01105 fps_handle_ = 0;
01106 drawn_hexes_ = 0;
01107 invalidated_hexes_ = 0;
01108 }
01109
01110 flip();
01111 }
01112
01113 static void draw_panel(CVideo& video, const theme::panel& panel, std::vector<gui::button>& buttons)
01114 {
01115
01116 DBG_DP << "drawing panel " << panel.get_id() << "\n";
01117
01118 surface surf(image::get_image(panel.image()));
01119
01120 const SDL_Rect screen = screen_area();
01121 SDL_Rect& loc = panel.location(screen);
01122
01123 DBG_DP << "panel location: x=" << loc.x << ", y=" << loc.y
01124 << ", w=" << loc.w << ", h=" << loc.h << "\n";
01125
01126 if(!surf.null()) {
01127 if(surf->w != loc.w || surf->h != loc.h) {
01128 surf.assign(scale_surface(surf,loc.w,loc.h));
01129 }
01130
01131 video.blit_surface(loc.x,loc.y,surf);
01132 update_rect(loc);
01133 }
01134
01135 static bool first_time = true;
01136 for(std::vector<gui::button>::iterator b = buttons.begin(); b != buttons.end(); ++b) {
01137 if(rects_overlap(b->location(),loc)) {
01138 b->set_dirty(true);
01139 if (first_time){
01140
01141
01142
01143
01144
01145
01146
01147
01148 b->hide(true);
01149 b->hide(false);
01150 }
01151 }
01152 }
01153 }
01154
01155 static void draw_label(CVideo& video, surface target, const theme::label& label)
01156 {
01157
01158
01159 std::stringstream temp;
01160 Uint32 RGB=label.font_rgb();
01161 int red = (RGB & 0x00FF0000)>>16;
01162 int green = (RGB & 0x0000FF00)>>8;
01163 int blue = (RGB & 0x000000FF);
01164
01165 std::string c_start="<";
01166 std::string c_sep=",";
01167 std::string c_end=">";
01168 std::stringstream color;
01169 color<< c_start << red << c_sep << green << c_sep << blue << c_end;
01170 std::string text = label.text();
01171
01172 if(label.font_rgb_set()) {
01173 color<<text;
01174 text = color.str();
01175 }
01176 const std::string& icon = label.icon();
01177 SDL_Rect& loc = label.location(screen_area());
01178
01179 if(icon.empty() == false) {
01180 surface surf(image::get_image(icon));
01181 if(!surf.null()) {
01182 if(surf->w > loc.w || surf->h > loc.h) {
01183 surf.assign(scale_surface(surf,loc.w,loc.h));
01184 }
01185
01186 sdl_blit(surf,NULL,target,&loc);
01187 }
01188
01189 if(text.empty() == false) {
01190 tooltips::add_tooltip(loc,text);
01191 }
01192 } else if(text.empty() == false) {
01193 font::draw_text(&video,loc,label.font_size(),font::NORMAL_COLOR,text,loc.x,loc.y);
01194 }
01195
01196 update_rect(loc);
01197 }
01198
01199 void display::draw_all_panels()
01200 {
01201 surface const screen(screen_.getSurface());
01202
01203 const std::vector<theme::panel>& panels = theme_.panels();
01204 for(std::vector<theme::panel>::const_iterator p = panels.begin(); p != panels.end(); ++p) {
01205 draw_panel(video(),*p,buttons_);
01206 }
01207
01208 const std::vector<theme::label>& labels = theme_.labels();
01209 for(std::vector<theme::label>::const_iterator i = labels.begin(); i != labels.end(); ++i) {
01210 draw_label(video(),screen,*i);
01211 }
01212
01213 create_buttons();
01214 }
01215
01216 static void draw_background(surface screen, const SDL_Rect& area, const std::string& image)
01217 {
01218 const surface background(image::get_image(image));
01219 if(background.null()) {
01220 return;
01221 }
01222 const unsigned int width = background->w;
01223 const unsigned int height = background->h;
01224
01225 const unsigned int w_count = static_cast<int>(std::ceil(static_cast<double>(area.w) / static_cast<double>(width)));
01226 const unsigned int h_count = static_cast<int>(std::ceil(static_cast<double>(area.h) / static_cast<double>(height)));
01227
01228 for(unsigned int w = 0, w_off = area.x; w < w_count; ++w, w_off += width) {
01229 for(unsigned int h = 0, h_off = area.y; h < h_count; ++h, h_off += height) {
01230 SDL_Rect clip = create_rect(w_off, h_off, 0, 0);
01231 sdl_blit(background, NULL, screen, &clip);
01232 }
01233 }
01234 }
01235
01236 void display::draw_text_in_hex(const map_location& loc,
01237 const tdrawing_layer layer, const std::string& text,
01238 size_t font_size, SDL_Color color, double x_in_hex, double y_in_hex)
01239 {
01240 if (text.empty()) return;
01241
01242 const size_t font_sz = static_cast<size_t>(font_size * get_zoom_factor()
01243 );
01244
01245 surface text_surf = font::get_rendered_text(text, font_sz, color);
01246 surface back_surf = font::get_rendered_text(text, font_sz, font::BLACK_COLOR);
01247 const int x = get_location_x(loc) - text_surf->w/2
01248 + static_cast<int>(x_in_hex* hex_size());
01249 const int y = get_location_y(loc) - text_surf->h/2
01250 + static_cast<int>(y_in_hex* hex_size());
01251
01252 for (int dy=-1; dy <= 1; ++dy) {
01253 for (int dx=-1; dx <= 1; ++dx) {
01254 if (dx!=0 || dy!=0) {
01255 drawing_buffer_add(layer, loc, x + dx, y + dy, back_surf);
01256 }
01257 }
01258 }
01259 drawing_buffer_add(layer, loc, x, y, text_surf);
01260 }
01261
01262 void display::render_image(int x, int y, const display::tdrawing_layer drawing_layer,
01263 const map_location& loc, surface image,
01264 bool hreverse, bool greyscale, fixed_t alpha,
01265 Uint32 blendto, double blend_ratio, double submerged, bool vreverse)
01266 {
01267
01268 if (image==NULL)
01269 return;
01270
01271 SDL_Rect image_rect = create_rect(x, y, image->w, image->h);
01272 SDL_Rect clip_rect = map_area();
01273 if (!rects_overlap(image_rect, clip_rect))
01274 return;
01275
01276 surface surf(image);
01277
01278 if(hreverse) {
01279 surf = image::reverse_image(surf);
01280 }
01281 if(vreverse) {
01282 surf = flop_surface(surf, false);
01283 }
01284
01285 if(greyscale) {
01286 surf = greyscale_image(surf, false);
01287 }
01288
01289 if(blend_ratio != 0) {
01290 surf = blend_surface(surf, blend_ratio, blendto, false);
01291 }
01292 if(alpha > ftofxp(1.0)) {
01293 surf = brighten_image(surf, alpha, false);
01294
01295
01296 } else if(alpha != ftofxp(1.0)) {
01297 surf = adjust_surface_alpha(surf, alpha, false);
01298 }
01299
01300 if(surf == NULL) {
01301 ERR_DP << "surface lost...\n";
01302 return;
01303 }
01304
01305 if(submerged > 0.0) {
01306
01307 const int submerge_height = std::max<int>(0, surf->h*(1.0-submerged));
01308 const int depth = surf->h - submerge_height;
01309 SDL_Rect srcrect = create_rect(0, 0, surf->w, submerge_height);
01310 drawing_buffer_add(drawing_layer, loc, x, y, surf, srcrect);
01311
01312 if(submerge_height != surf->h) {
01313
01314 float alpha_base = 0.3f;
01315 float alpha_delta = 0.015f;
01316 alpha_delta *= zoom_ / DefaultZoom;
01317 surf = submerge_alpha(surf, depth, alpha_base, alpha_delta, false);
01318
01319 srcrect.y = submerge_height;
01320 srcrect.h = surf->h-submerge_height;
01321 y += submerge_height;
01322
01323 drawing_buffer_add(drawing_layer, loc, x, y, surf, srcrect);
01324 }
01325 } else {
01326
01327 drawing_buffer_add(drawing_layer, loc, x, y, surf);
01328 }
01329
01330 }
01331
01332 void display::select_hex(map_location hex)
01333 {
01334 invalidate(selectedHex_);
01335 selectedHex_ = hex;
01336 invalidate(selectedHex_);
01337 }
01338
01339 void display::highlight_hex(map_location hex)
01340 {
01341 invalidate(mouseoverHex_);
01342 mouseoverHex_ = hex;
01343 invalidate(mouseoverHex_);
01344 }
01345
01346 void display::set_diagnostic(const std::string& msg)
01347 {
01348 if(diagnostic_label_ != 0) {
01349 font::remove_floating_label(diagnostic_label_);
01350 diagnostic_label_ = 0;
01351 }
01352
01353 if(msg != "") {
01354 font::floating_label flabel(msg);
01355 flabel.set_font_size(font::SIZE_PLUS);
01356 flabel.set_color(font::YELLOW_COLOR);
01357 flabel.set_position(300, 50);
01358 flabel.set_clip_rect(map_outside_area());
01359
01360 diagnostic_label_ = font::add_floating_label(flabel);
01361 }
01362 }
01363
01364 void display::draw_init()
01365 {
01366 if (get_map().empty()) {
01367 return;
01368 }
01369
01370 if(benchmark) {
01371 invalidateAll_ = true;
01372 }
01373
01374 if(!panelsDrawn_) {
01375 draw_all_panels();
01376 panelsDrawn_ = true;
01377 }
01378
01379 if(redraw_background_) {
01380
01381 const SDL_Rect clip_rect = map_outside_area();
01382 const surface screen = get_screen_surface();
01383 clip_rect_setter set_clip_rect(screen, &clip_rect);
01384 draw_background(screen, clip_rect, theme_.border().background_image);
01385 update_rect(clip_rect);
01386
01387 redraw_background_ = false;
01388
01389
01390 invalidateAll_ = true;
01391 }
01392
01393 if(invalidateAll_) {
01394 DBG_DP << "draw() with invalidateAll\n";
01395
01396
01397 invalidateAll_ = false;
01398 invalidate_locations_in_rect(map_area());
01399
01400 redrawMinimap_ = true;
01401 }
01402 }
01403
01404 void display::draw_wrap(bool update, bool force)
01405 {
01406 static const int time_between_draws = preferences::draw_delay();
01407 const int current_time = SDL_GetTicks();
01408 const int wait_time = nextDraw_ - current_time;
01409
01410 if(redrawMinimap_) {
01411 redrawMinimap_ = false;
01412 draw_minimap();
01413 }
01414
01415 if(update) {
01416 update_display();
01417 if(!force && !benchmark && wait_time > 0) {
01418
01419 SDL_Delay(wait_time);
01420 }
01421
01422
01423 nextDraw_ += time_between_draws;
01424
01425
01426
01427
01428
01429
01430 nextDraw_ = std::max<int>(nextDraw_, SDL_GetTicks());
01431 }
01432 }
01433
01434 void display::delay(unsigned int milliseconds) const
01435 {
01436 if (!game_config::no_delay)
01437 SDL_Delay(milliseconds);
01438 }
01439
01440 const theme::menu* display::menu_pressed()
01441 {
01442 for(std::vector<gui::button>::iterator i = buttons_.begin(); i != buttons_.end(); ++i) {
01443 if(i->pressed()) {
01444 const size_t index = i - buttons_.begin();
01445 if(index >= theme_.menus().size()) {
01446 assert(false);
01447 return 0;
01448 }
01449 return &theme_.menus()[index];
01450 }
01451 }
01452
01453 return 0;
01454 }
01455
01456 void display::enable_menu(const std::string& item, bool enable)
01457 {
01458 for(std::vector<theme::menu>::const_iterator menu = theme_.menus().begin();
01459 menu != theme_.menus().end(); ++menu) {
01460
01461 std::vector<std::string>::const_iterator hasitem =
01462 std::find(menu->items().begin(), menu->items().end(), item);
01463
01464 if(hasitem != menu->items().end()) {
01465 const size_t index = menu - theme_.menus().begin();
01466 if(index >= buttons_.size()) {
01467 assert(false);
01468 return;
01469 }
01470 buttons_[index].enable(enable);
01471 }
01472 }
01473 }
01474
01475 void display::announce(const std::string& message, const SDL_Color& color)
01476 {
01477 font::floating_label flabel(message);
01478 flabel.set_font_size(font::SIZE_XLARGE);
01479 flabel.set_color(color);
01480 flabel.set_position(map_outside_area().w/2, map_outside_area().h/3);
01481 flabel.set_lifetime(100);
01482 flabel.set_clip_rect(map_outside_area());
01483
01484 font::add_floating_label(flabel);
01485 }
01486
01487 void display::draw_border(const map_location& loc, const int xpos, const int ypos)
01488 {
01489
01490
01491
01492
01493
01494
01495
01496 if(loc.x == -1 && loc.y == -1) {
01497 drawing_buffer_add(LAYER_BORDER, loc, xpos + zoom_/4, ypos,
01498 image::get_image(theme_.border().corner_image_top_left, image::SCALED_TO_ZOOM));
01499 } else if(loc.x == get_map().w() && loc.y == -1) {
01500
01501 if(loc.x%2 == 0) {
01502 drawing_buffer_add(LAYER_BORDER, loc, xpos, ypos + zoom_/2,
01503 image::get_image(theme_.border().corner_image_top_right_odd, image::SCALED_TO_ZOOM));
01504 } else {
01505 drawing_buffer_add(LAYER_BORDER, loc, xpos, ypos,
01506 image::get_image(theme_.border().corner_image_top_right_even, image::SCALED_TO_ZOOM));
01507 }
01508 } else if(loc.x == -1 && loc.y == get_map().h()) {
01509 drawing_buffer_add(LAYER_BORDER, loc, xpos + zoom_/4, ypos,
01510 image::get_image(theme_.border().corner_image_bottom_left, image::SCALED_TO_ZOOM));
01511
01512 } else if(loc.x == get_map().w() && loc.y == get_map().h()) {
01513
01514 if(loc.x%2 == 1) {
01515 drawing_buffer_add(LAYER_BORDER, loc, xpos, ypos,
01516 image::get_image(theme_.border().corner_image_bottom_right_even, image::SCALED_TO_ZOOM));
01517 } else {
01518 drawing_buffer_add(LAYER_BORDER, loc, xpos, ypos,
01519 image::get_image(theme_.border().corner_image_bottom_right_odd, image::SCALED_TO_ZOOM));
01520 }
01521
01522
01523 } else if(loc.x == -1) {
01524 drawing_buffer_add(LAYER_BORDER, loc, xpos + zoom_/4, ypos,
01525 image::get_image(theme_.border().border_image_left, image::SCALED_TO_ZOOM));
01526 } else if(loc.x == get_map().w()) {
01527 drawing_buffer_add(LAYER_BORDER, loc, xpos + zoom_/4, ypos,
01528 image::get_image(theme_.border().border_image_right, image::SCALED_TO_ZOOM));
01529 } else if(loc.y == -1) {
01530
01531 if(loc.x%2 == 1) {
01532 drawing_buffer_add(LAYER_BORDER, loc, xpos, ypos,
01533 image::get_image(theme_.border().border_image_top_even, image::SCALED_TO_ZOOM));
01534 } else {
01535 drawing_buffer_add(LAYER_BORDER, loc, xpos, ypos + zoom_/2,
01536 image::get_image(theme_.border().border_image_top_odd, image::SCALED_TO_ZOOM));
01537 }
01538 } else if(loc.y == get_map().h()) {
01539
01540 if(loc.x%2 == 1) {
01541 drawing_buffer_add(LAYER_BORDER, loc, xpos, ypos,
01542 image::get_image(theme_.border().border_image_bottom_even, image::SCALED_TO_ZOOM));
01543 } else {
01544 drawing_buffer_add(LAYER_BORDER, loc, xpos, ypos + zoom_/2,
01545 image::get_image(theme_.border().border_image_bottom_odd, image::SCALED_TO_ZOOM));
01546 }
01547 }
01548 }
01549
01550 void display::draw_minimap()
01551 {
01552 const SDL_Rect& area = minimap_area();
01553
01554 if(area.w == 0 || area.h == 0) {
01555 return;
01556 }
01557
01558 if(minimap_ == NULL || minimap_->w > area.w || minimap_->h > area.h) {
01559 minimap_ = image::getMinimap(area.w, area.h, get_map(), viewpoint_);
01560 if(minimap_ == NULL) {
01561 return;
01562 }
01563 }
01564
01565 const surface screen(screen_.getSurface());
01566 clip_rect_setter clip_setter(screen, &area);
01567
01568 SDL_Color back_color = {31,31,23,255};
01569 draw_centered_on_background(minimap_, area, back_color, screen);
01570
01571
01572 minimap_location_.x = area.x + (area.w - minimap_->w) / 2;
01573 minimap_location_.y = area.y + (area.h - minimap_->h) / 2;
01574 minimap_location_.w = minimap_->w;
01575 minimap_location_.h = minimap_->h;
01576
01577 draw_minimap_units();
01578
01579
01580
01581 double xscaling = 1.0*minimap_->w / (get_map().w()*hex_width());
01582 double yscaling = 1.0*minimap_->h / (get_map().h()*hex_size());
01583
01584
01585
01586
01587 SDL_Rect map_rect = map_area();
01588 SDL_Rect map_out_rect = map_outside_area();
01589 double border = theme_.border().size;
01590 double shift_x = - border*hex_width() - (map_out_rect.w - map_rect.w) / 2;
01591 double shift_y = - (border+0.25)*hex_size() - (map_out_rect.h - map_rect.h) / 2;
01592
01593 int view_x = static_cast<int>((xpos_ + shift_x) * xscaling);
01594 int view_y = static_cast<int>((ypos_ + shift_y) * yscaling);
01595 int view_w = static_cast<int>(map_out_rect.w * xscaling);
01596 int view_h = static_cast<int>(map_out_rect.h * yscaling);
01597
01598 const Uint32 box_color = SDL_MapRGB(minimap_->format,0xFF,0xFF,0xFF);
01599 draw_rectangle(minimap_location_.x + view_x - 1,
01600 minimap_location_.y + view_y - 1,
01601 view_w + 2, view_h + 2,
01602 box_color, screen);
01603 }
01604
01605 void display::draw_minimap_units()
01606 {
01607 double xscaling = 1.0 * minimap_location_.w / get_map().w();
01608 double yscaling = 1.0 * minimap_location_.h / get_map().h();
01609
01610 for(unit_map::const_iterator u = units_->begin(); u != units_->end(); ++u) {
01611 if (fogged(u->get_location()) ||
01612 ((*teams_)[currentTeam_].is_enemy(u->side()) &&
01613 u->invisible(u->get_location())) ||
01614 u->get_hidden()) {
01615 continue;
01616 }
01617
01618 int side = u->side();
01619 const SDL_Color col = team::get_minimap_color(side);
01620 const Uint32 mapped_col = SDL_MapRGB(video().getSurface()->format,col.r,col.g,col.b);
01621
01622 double u_x = u->get_location().x * xscaling;
01623 double u_y = (u->get_location().y + (is_odd(u->get_location().x) ? 1 : -1)/4.0) * yscaling;
01624
01625 double u_w = 4.0 / 3.0 * xscaling;
01626 double u_h = yscaling;
01627
01628 SDL_Rect r = create_rect(minimap_location_.x + round_double(u_x)
01629 , minimap_location_.y + round_double(u_y)
01630 , round_double(u_w)
01631 , round_double(u_h));
01632
01633 sdl_fill_rect(video().getSurface(), &r, mapped_col);
01634 }
01635 }
01636
01637 bool display::scroll(int xmove, int ymove)
01638 {
01639 const int orig_x = xpos_;
01640 const int orig_y = ypos_;
01641 xpos_ += xmove;
01642 ypos_ += ymove;
01643 bounds_check_position();
01644 const int dx = orig_x - xpos_;
01645 const int dy = orig_y - ypos_;
01646
01647
01648 if(dx == 0 && dy == 0)
01649 return false;
01650
01651 font::scroll_floating_labels(dx, dy);
01652
01653 surface screen(screen_.getSurface());
01654
01655 SDL_Rect dstrect = map_area();
01656 dstrect.x += dx;
01657 dstrect.y += dy;
01658 dstrect = intersect_rects(dstrect, map_area());
01659
01660 SDL_Rect srcrect = dstrect;
01661 srcrect.x -= dx;
01662 srcrect.y -= dy;
01663 if (!screen_.update_locked()) {
01664
01665
01666 #if defined(__GLIBC__)
01667 if (do_reverse_memcpy_workaround_) {
01668 surface screen_copy = make_neutral_surface(screen);
01669 SDL_BlitSurface(screen_copy,&srcrect,screen,&dstrect);
01670 } else {
01671 SDL_BlitSurface(screen,&srcrect,screen,&dstrect);
01672 }
01673 #else
01674 SDL_BlitSurface(screen,&srcrect,screen,&dstrect);
01675 #endif
01676 }
01677
01678
01679
01680
01681 #ifdef _MSC_VER
01682 __asm{cld};
01683 #elif defined(__GNUG__) && (defined(__i386__) || defined(__x86_64__))
01684 asm("cld");
01685 #endif
01686
01687
01688
01689 if (dy != 0) {
01690 SDL_Rect r = map_area();
01691 if(dy < 0)
01692 r.y = r.y + r.h + dy;
01693 r.h = abs(dy);
01694 invalidate_locations_in_rect(r);
01695 }
01696 if (dx != 0) {
01697 SDL_Rect r = map_area();
01698 if (dx < 0)
01699 r.x = r.x + r.w + dx;
01700 r.w = abs(dx);
01701 invalidate_locations_in_rect(r);
01702 }
01703 scroll_event_.notify_observers();
01704 update_rect(map_area());
01705
01706 redrawMinimap_ = true;
01707 return true;
01708 }
01709
01710 void display::set_zoom(int amount)
01711 {
01712 int new_zoom = zoom_ + amount;
01713 if (new_zoom < MinZoom) {
01714 new_zoom = MinZoom;
01715 }
01716 if (new_zoom > MaxZoom) {
01717 new_zoom = MaxZoom;
01718 }
01719 if (new_zoom != zoom_) {
01720 SDL_Rect const &area = map_area();
01721 xpos_ += (xpos_ + area.w / 2) * amount / zoom_;
01722 ypos_ += (ypos_ + area.h / 2) * amount / zoom_;
01723
01724 zoom_ = new_zoom;
01725 bounds_check_position();
01726 if (zoom_ != DefaultZoom) {
01727 last_zoom_ = zoom_;
01728 }
01729 image::set_zoom(zoom_);
01730
01731 labels().recalculate_labels();
01732 redraw_background_ = true;
01733 invalidate_all();
01734
01735
01736
01737 draw();
01738 }
01739 }
01740
01741 void display::set_default_zoom()
01742 {
01743 if (zoom_ != DefaultZoom) {
01744 last_zoom_ = zoom_;
01745 set_zoom(DefaultZoom - zoom_ );
01746 } else {
01747
01748
01749 set_zoom(last_zoom_ - zoom_);
01750 }
01751 }
01752
01753 bool display::tile_fully_on_screen(const map_location& loc)
01754 {
01755 int x = get_location_x(loc);
01756 int y = get_location_y(loc);
01757 return !outside_area(map_area(), x, y);
01758 }
01759
01760 bool display::tile_nearly_on_screen(const map_location& loc) const
01761 {
01762 int x = get_location_x(loc);
01763 int y = get_location_y(loc);
01764 const SDL_Rect &area = map_area();
01765 int hw = hex_width(), hs = hex_size();
01766 return x + hs >= area.x - hw && x < area.x + area.w + hw &&
01767 y + hs >= area.y - hs && y < area.y + area.h + hs;
01768 }
01769
01770 void display::scroll_to_xy(int screenxpos, int screenypos, SCROLL_TYPE scroll_type, bool force)
01771 {
01772 if(!force && !preferences::scroll_to_action()) return;
01773 if(screen_.update_locked()) {
01774 return;
01775 }
01776 const SDL_Rect area = map_area();
01777 const int xmove_expected = screenxpos - (area.x + area.w/2);
01778 const int ymove_expected = screenypos - (area.y + area.h/2);
01779
01780 int xpos = xpos_ + xmove_expected;
01781 int ypos = ypos_ + ymove_expected;
01782 bounds_check_position(xpos, ypos);
01783 int xmove = xpos - xpos_;
01784 int ymove = ypos - ypos_;
01785
01786 if(scroll_type == WARP || scroll_type == ONSCREEN_WARP || turbo_speed() > 2.0 || preferences::scroll_speed() > 99) {
01787 scroll(xmove,ymove);
01788 draw();
01789 return;
01790 }
01791
01792
01793
01794 int x_old = 0;
01795 int y_old = 0;
01796
01797 const double dist_total = hypot(xmove, ymove);
01798 double dist_moved = 0.0;
01799
01800 int t_prev = SDL_GetTicks();
01801
01802 double velocity = 0.0;
01803 while (dist_moved < dist_total) {
01804 events::pump();
01805
01806 int t = SDL_GetTicks();
01807 double dt = (t - t_prev) / 1000.0;
01808 if (dt > 0.200) {
01809
01810 dt = 0.200;
01811 }
01812 t_prev = t;
01813
01814 const double accel_time = 0.3 / turbo_speed();
01815 const double decel_time = 0.4 / turbo_speed();
01816
01817 double velocity_max = preferences::scroll_speed() * 60.0;
01818 velocity_max *= turbo_speed();
01819 double accel = velocity_max / accel_time;
01820 double decel = velocity_max / decel_time;
01821
01822
01823 double stop_time = velocity / decel;
01824 double dist_stop = dist_moved + velocity*stop_time - 0.5*decel*stop_time*stop_time;
01825 if (dist_stop > dist_total || velocity > velocity_max) {
01826 velocity -= decel * dt;
01827 if (velocity < 1.0) velocity = 1.0;
01828 } else {
01829 velocity += accel * dt;
01830 if (velocity > velocity_max) velocity = velocity_max;
01831 }
01832
01833 dist_moved += velocity * dt;
01834 if (dist_moved > dist_total) dist_moved = dist_total;
01835
01836 int x_new = round_double(xmove * dist_moved / dist_total);
01837 int y_new = round_double(ymove * dist_moved / dist_total);
01838
01839 int dx = x_new - x_old;
01840 int dy = y_new - y_old;
01841
01842 scroll(dx,dy);
01843 x_old += dx;
01844 y_old += dy;
01845 draw();
01846 }
01847 }
01848
01849 void display::scroll_to_tile(const map_location& loc, SCROLL_TYPE scroll_type, bool check_fogged, bool force)
01850 {
01851 if(get_map().on_board(loc) == false) {
01852 ERR_DP << "Tile at " << loc << " isn't on the map, can't scroll to the tile.\n";
01853 return;
01854 }
01855
01856 std::vector<map_location> locs;
01857 locs.push_back(loc);
01858 scroll_to_tiles(locs, scroll_type, check_fogged,false,0.0,force);
01859 }
01860
01861 void display::scroll_to_tiles(map_location loc1, map_location loc2,
01862 SCROLL_TYPE scroll_type, bool check_fogged,
01863 double add_spacing, bool force)
01864 {
01865 std::vector<map_location> locs;
01866 locs.push_back(loc1);
01867 locs.push_back(loc2);
01868 scroll_to_tiles(locs, scroll_type, check_fogged, false, add_spacing,force);
01869 }
01870
01871 void display::scroll_to_tiles(const std::vector<map_location>& locs,
01872 SCROLL_TYPE scroll_type, bool check_fogged,
01873 bool only_if_possible, double add_spacing, bool force)
01874 {
01875
01876 int minx = 0;
01877 int maxx = 0;
01878 int miny = 0;
01879 int maxy = 0;
01880 bool valid = false;
01881
01882 for(std::vector<map_location>::const_iterator itor = locs.begin(); itor != locs.end() ; ++itor) {
01883 if(get_map().on_board(*itor) == false) continue;
01884 if(check_fogged && fogged(*itor)) continue;
01885
01886 int x = get_location_x(*itor);
01887 int y = get_location_y(*itor);
01888
01889 if (!valid) {
01890 minx = x;
01891 maxx = x;
01892 miny = y;
01893 maxy = y;
01894 valid = true;
01895 } else {
01896 int minx_new = std::min<int>(minx,x);
01897 int miny_new = std::min<int>(miny,y);
01898 int maxx_new = std::max<int>(maxx,x);
01899 int maxy_new = std::max<int>(maxy,y);
01900 SDL_Rect r = map_area();
01901 r.x = minx_new;
01902 r.y = miny_new;
01903 if(outside_area(r, maxx_new, maxy_new)) {
01904
01905 if (only_if_possible) return;
01906 break;
01907 }
01908 minx = minx_new;
01909 miny = miny_new;
01910 maxx = maxx_new;
01911 maxy = maxy_new;
01912 }
01913 }
01914
01915 if(!valid) return;
01916
01917 if (scroll_type == ONSCREEN || ONSCREEN_WARP) {
01918 SDL_Rect r = map_area();
01919 int spacing = round_double(add_spacing*hex_size());
01920 r.x += spacing;
01921 r.y += spacing;
01922 r.w -= 2*spacing;
01923 r.h -= 2*spacing;
01924 if (!outside_area(r, minx,miny) && !outside_area(r, maxx,maxy)) {
01925 return;
01926 }
01927 }
01928
01929
01930 SDL_Rect locs_bbox;
01931 locs_bbox.x = minx;
01932 locs_bbox.y = miny;
01933 locs_bbox.w = maxx - minx + hex_size();
01934 locs_bbox.h = maxy - miny + hex_size();
01935
01936
01937 int target_x = locs_bbox.x + locs_bbox.w/2;
01938 int target_y = locs_bbox.y + locs_bbox.h/2;
01939
01940 if (scroll_type == ONSCREEN || ONSCREEN_WARP) {
01941
01942 SDL_Rect r = map_area();
01943 int map_center_x = r.x + r.w/2;
01944 int map_center_y = r.y + r.h/2;
01945
01946 int h = r.h;
01947 int w = r.w;
01948
01949
01950 double inside_frac = 0.5;
01951 w = static_cast<int>(w * inside_frac);
01952 h = static_cast<int>(h * inside_frac);
01953
01954
01955
01956 w -= locs_bbox.w;
01957 h -= locs_bbox.h;
01958
01959 if (w < 1) w = 1;
01960 if (h < 1) h = 1;
01961
01962 r.x = target_x - w/2;
01963 r.y = target_y - h/2;
01964 r.w = w;
01965 r.h = h;
01966
01967
01968
01969
01970
01971 if (map_center_x < r.x) {
01972 target_x = r.x;
01973 target_y = map_center_y;
01974 if (target_y < r.y) target_y = r.y;
01975 if (target_y > r.y+r.h-1) target_y = r.y+r.h-1;
01976 } else if (map_center_x > r.x+r.w-1) {
01977 target_x = r.x+r.w-1;
01978 target_y = map_center_y;
01979 if (target_y < r.y) target_y = r.y;
01980 if (target_y >= r.y+r.h) target_y = r.y+r.h-1;
01981 } else if (map_center_y < r.y) {
01982 target_y = r.y;
01983 target_x = map_center_x;
01984 if (target_x < r.x) target_x = r.x;
01985 if (target_x > r.x+r.w-1) target_x = r.x+r.w-1;
01986 } else if (map_center_y > r.y+r.h-1) {
01987 target_y = r.y+r.h-1;
01988 target_x = map_center_x;
01989 if (target_x < r.x) target_x = r.x;
01990 if (target_x > r.x+r.w-1) target_x = r.x+r.w-1;
01991 } else {
01992 ERR_DP << "Bug in the scrolling code? Looks like we would not need to scroll after all...\n";
01993
01994 }
01995 }
01996
01997 scroll_to_xy(target_x, target_y,scroll_type,force);
01998 }
01999
02000
02001 void display::bounds_check_position()
02002 {
02003 const int orig_zoom = zoom_;
02004
02005 if(zoom_ < MinZoom) {
02006 zoom_ = MinZoom;
02007 }
02008
02009 if(zoom_ > MaxZoom) {
02010 zoom_ = MaxZoom;
02011 }
02012
02013 bounds_check_position(xpos_, ypos_);
02014
02015 if(zoom_ != orig_zoom) {
02016 image::set_zoom(zoom_);
02017 }
02018 }
02019
02020 void display::bounds_check_position(int& xpos, int& ypos)
02021 {
02022 const int tile_width = hex_width();
02023
02024
02025 const int xend = static_cast<int>(tile_width * (get_map().w() + 2 * theme_.border().size) + tile_width/3);
02026 const int yend = static_cast<int>(zoom_ * (get_map().h() + 2 * theme_.border().size) + zoom_/2);
02027
02028 if(xpos > xend - map_area().w) {
02029 xpos = xend - map_area().w;
02030 }
02031
02032 if(ypos > yend - map_area().h) {
02033 ypos = yend - map_area().h;
02034 }
02035
02036 if(xpos < 0) {
02037 xpos = 0;
02038 }
02039
02040 if(ypos < 0) {
02041 ypos = 0;
02042 }
02043 }
02044
02045 double display::turbo_speed() const
02046 {
02047 bool res = turbo_;
02048 if(keys_[SDLK_LSHIFT] || keys_[SDLK_RSHIFT]) {
02049 res = !res;
02050 }
02051
02052 res |= screen_.faked();
02053 if (res)
02054 return turbo_speed_;
02055 else
02056 return 1.0;
02057 }
02058
02059 void display::set_idle_anim_rate(int rate)
02060 {
02061 idle_anim_rate_ = std::pow(2.0, -rate/10.0);
02062 }
02063
02064 void display::redraw_everything()
02065 {
02066 if(screen_.update_locked())
02067 return;
02068
02069 invalidateGameStatus_ = true;
02070
02071 reportRects_.clear();
02072 reportSurfaces_.clear();
02073 reports_.clear();
02074
02075 bounds_check_position();
02076
02077 tooltips::clear_tooltips();
02078
02079 theme_.set_resolution(screen_area());
02080
02081 if(buttons_.empty() == false) {
02082 create_buttons();
02083 }
02084
02085 panelsDrawn_ = false;
02086
02087 labels().recalculate_labels();
02088
02089 redraw_background_ = true;
02090
02091 int ticks1 = SDL_GetTicks();
02092 invalidate_all();
02093 int ticks2 = SDL_GetTicks();
02094 draw(true,true);
02095 int ticks3 = SDL_GetTicks();
02096 LOG_DP << "invalidate and draw: " << (ticks3 - ticks2) << " and " << (ticks2 - ticks1) << "\n";
02097
02098 foreach (boost::function<void(display&)> f, redraw_observers_) {
02099 f(*this);
02100 }
02101
02102 complete_redraw_event_.notify_observers();
02103 }
02104
02105 void display::add_redraw_observer(boost::function<void(display&)> f)
02106 {
02107 redraw_observers_.push_back(f);
02108 }
02109
02110 void display::clear_redraw_observers()
02111 {
02112 redraw_observers_.clear();
02113 }
02114
02115 void display::draw(bool update,bool force) {
02116
02117 if (screen_.update_locked()) {
02118 return;
02119 }
02120
02121 local_tod_light_ = has_time_area() && preferences::get("local_tod_lighting", true);
02122
02123 draw_init();
02124 pre_draw();
02125
02126 invalidate_animations();
02127
02128
02129
02130
02131 previous_invalidated_.swap(invalidated_);
02132 invalidated_.insert(previous_invalidated_.begin(),previous_invalidated_.end());
02133
02134
02135
02136
02137
02138 if(!get_map().empty()) {
02139
02140
02141
02142
02143
02144
02145 if(!invalidated_.empty() || preferences::show_haloes()) {
02146 draw_invalidated();
02147 invalidated_.clear();
02148 }
02149 drawing_buffer_commit();
02150 post_commit();
02151 draw_sidebar();
02152
02153
02154
02155 }
02156 draw_wrap(update, force);
02157 post_draw();
02158 }
02159
02160 map_labels& display::labels()
02161 {
02162 return *map_labels_;
02163 }
02164
02165 const map_labels& display::labels() const
02166 {
02167 return *map_labels_;
02168 }
02169
02170 void display::clear_screen()
02171 {
02172 surface disp(screen_.getSurface());
02173 SDL_Rect area = screen_area();
02174 sdl_fill_rect(disp, &area, SDL_MapRGB(disp->format, 0, 0, 0));
02175 }
02176
02177 const SDL_Rect& display::get_clip_rect()
02178 {
02179 return map_area();
02180 }
02181
02182 void display::draw_invalidated() {
02183
02184 SDL_Rect clip_rect = get_clip_rect();
02185 surface screen = get_screen_surface();
02186 clip_rect_setter set_clip_rect(screen, &clip_rect);
02187 foreach (const map_location& loc, invalidated_) {
02188 int xpos = get_location_x(loc);
02189 int ypos = get_location_y(loc);
02190
02191 update_rect(xpos, ypos, zoom_, zoom_);
02192
02193 const bool on_map = get_map().on_board(loc);
02194 SDL_Rect hex_rect = create_rect(xpos, ypos, zoom_, zoom_);
02195 if(!rects_overlap(hex_rect,clip_rect)) {
02196 continue;
02197 }
02198 draw_hex(loc);
02199 drawn_hexes_+=1;
02200
02201 if(!on_map) {
02202 draw_border(loc, xpos, ypos);
02203 }
02204 }
02205 invalidated_hexes_ += invalidated_.size();
02206
02207 foreach (const map_location& loc, invalidated_) {
02208 unit_map::iterator u_it = units_->find(loc);
02209 exclusive_unit_draw_requests_t::iterator request = exclusive_unit_draw_requests_.find(loc);
02210 if (u_it != units_->end()
02211 && (request == exclusive_unit_draw_requests_.end() || request->second == u_it->id()))
02212 u_it->redraw_unit();
02213 }
02214
02215 }
02216
02217 void display::draw_hex(const map_location& loc) {
02218 int xpos = get_location_x(loc);
02219 int ypos = get_location_y(loc);
02220 image::TYPE image_type = get_image_type(loc);
02221 const bool on_map = get_map().on_board(loc);
02222 const bool off_map_tile = (get_map().get_terrain(loc) == t_translation::OFF_MAP_USER);
02223 const time_of_day& tod = get_time_of_day(loc);
02224 if(!shrouded(loc)) {
02225
02226 drawing_buffer_add(LAYER_TERRAIN_BG, loc, xpos, ypos,
02227 get_terrain_images(loc,tod.id, image_type, BACKGROUND));
02228
02229 drawing_buffer_add(LAYER_TERRAIN_FG, loc, xpos, ypos,
02230 get_terrain_images(loc,tod.id,image_type, FOREGROUND));
02231
02232
02233 if(grid_ && on_map && !off_map_tile) {
02234 static const image::locator grid_top(game_config::images::grid_top);
02235 drawing_buffer_add(LAYER_GRID_TOP, loc, xpos, ypos,
02236 image::get_image(grid_top, image::TOD_COLORED));
02237 static const image::locator grid_bottom(game_config::images::grid_bottom);
02238 drawing_buffer_add(LAYER_GRID_BOTTOM, loc, xpos, ypos,
02239 image::get_image(grid_bottom, image::TOD_COLORED));
02240 }
02241 }
02242
02243
02244
02245 const std::string& tod_hex_mask = tod.image_mask;
02246 if(tod_hex_mask1 != NULL || tod_hex_mask2 != NULL) {
02247 drawing_buffer_add(LAYER_TERRAIN_FG, loc, xpos, ypos, tod_hex_mask1);
02248 drawing_buffer_add(LAYER_TERRAIN_FG, loc, xpos, ypos, tod_hex_mask2);
02249 } else if(!tod_hex_mask.empty()) {
02250 drawing_buffer_add(LAYER_TERRAIN_FG, loc, xpos, ypos,
02251 image::get_image(tod_hex_mask,image::SCALED_TO_HEX));
02252 }
02253
02254
02255 if(loc == mouseoverHex_ && (on_map || (in_editor() && get_map().on_board_with_border(loc))) && mouseover_hex_overlay_ != NULL) {
02256 drawing_buffer_add(LAYER_MOUSEOVER_OVERLAY, loc, xpos, ypos, mouseover_hex_overlay_);
02257 }
02258
02259
02260 arrows_map_t::const_iterator arrows_in_hex = arrows_map_.find(loc);
02261 if(arrows_in_hex != arrows_map_.end()) {
02262 foreach(arrow* const a, arrows_in_hex->second) {
02263 a->draw_hex(loc);
02264 }
02265 }
02266
02267
02268
02269 if(shrouded(loc)) {
02270
02271
02272 const std::string& shroud_image = get_variant(shroud_images_, loc);
02273 drawing_buffer_add(LAYER_FOG_SHROUD, loc, xpos, ypos,
02274 image::get_image(shroud_image, image_type));
02275 } else if(fogged(loc)) {
02276 const std::string& fog_image = get_variant(fog_images_, loc);
02277 drawing_buffer_add(LAYER_FOG_SHROUD, loc, xpos, ypos,
02278 image::get_image(fog_image, image_type));
02279 }
02280
02281 if(!shrouded(loc)) {
02282 drawing_buffer_add(LAYER_FOG_SHROUD, loc, xpos, ypos, get_fog_shroud_images(loc, image_type));
02283 }
02284
02285 if (on_map) {
02286 if (draw_coordinates_) {
02287 int off_x = xpos + hex_size()/2;
02288 int off_y = ypos + hex_size()/2;
02289 surface text = font::get_rendered_text(lexical_cast<std::string>(loc), font::SIZE_SMALL, font::NORMAL_COLOR);
02290 surface bg = create_neutral_surface(text->w, text->h);
02291 SDL_Rect bg_rect = create_rect(0, 0, text->w, text->h);
02292 sdl_fill_rect(bg, &bg_rect, 0xaa000000);
02293 off_x -= text->w / 2;
02294 if (draw_terrain_codes_) {
02295 off_y -= text->h;
02296 } else {
02297 off_y -= text->h / 2;
02298 }
02299 drawing_buffer_add(LAYER_FOG_SHROUD, loc, off_x, off_y, bg);
02300 drawing_buffer_add(LAYER_FOG_SHROUD, loc, off_x, off_y, text);
02301 }
02302 if (draw_terrain_codes_ && (game_config::debug || !shrouded(loc))) {
02303 int off_x = xpos + hex_size()/2;
02304 int off_y = ypos + hex_size()/2;
02305 surface text = font::get_rendered_text(lexical_cast<std::string>(get_map().get_terrain(loc)), font::SIZE_SMALL, font::NORMAL_COLOR);
02306 surface bg = create_neutral_surface(text->w, text->h);
02307 SDL_Rect bg_rect = create_rect(0, 0, text->w, text->h);
02308 sdl_fill_rect(bg, &bg_rect, 0xaa000000);
02309 off_x -= text->w / 2;
02310 if (!draw_coordinates_) {
02311 off_y -= text->h / 2;
02312 }
02313 drawing_buffer_add(LAYER_FOG_SHROUD, loc, off_x, off_y, bg);
02314 drawing_buffer_add(LAYER_FOG_SHROUD, loc, off_x, off_y, text);
02315 }
02316 }
02317
02318 if(debug_foreground) {
02319 drawing_buffer_add(LAYER_UNIT_DEFAULT, loc, xpos, ypos,
02320 image::get_image("terrain/foreground.png", image_type));
02321 }
02322
02323 }
02324
02325 image::TYPE display::get_image_type(const map_location& ) {
02326 return image::TOD_COLORED;
02327 }
02328
02329 void display::draw_sidebar() {
02330
02331 }
02332
02333 void display::draw_image_for_report(surface& img, SDL_Rect& rect)
02334 {
02335 SDL_Rect visible_area = get_non_transparent_portion(img);
02336 SDL_Rect target = rect;
02337 if(visible_area.x != 0 || visible_area.y != 0 || visible_area.w != img->w || visible_area.h != img->h) {
02338 if(visible_area.w == 0 || visible_area.h == 0) {
02339 return;
02340 }
02341
02342 if(visible_area.w > rect.w || visible_area.h > rect.h) {
02343 img.assign(get_surface_portion(img,visible_area,false));
02344 img.assign(scale_surface(img,rect.w,rect.h));
02345 visible_area.x = 0;
02346 visible_area.y = 0;
02347 visible_area.w = img->w;
02348 visible_area.h = img->h;
02349 } else {
02350 target.x = rect.x + (rect.w - visible_area.w)/2;
02351 target.y = rect.y + (rect.h - visible_area.h)/2;
02352 target.w = visible_area.w;
02353 target.h = visible_area.h;
02354 }
02355
02356 sdl_blit(img,&visible_area,screen_.getSurface(),&target);
02357 } else {
02358 if(img->w != rect.w || img->h != rect.h) {
02359 img.assign(scale_surface(img,rect.w,rect.h));
02360 }
02361
02362 sdl_blit(img,NULL,screen_.getSurface(),&target);
02363 }
02364 }
02365
02366 void display::refresh_report(std::string const &report_name, const config &_report)
02367 {
02368 const theme::status_item *item = theme_.get_status_item(report_name);
02369 if (!item) {
02370 reportSurfaces_[report_name].assign(NULL);
02371 return;
02372 }
02373
02374 SDL_Rect &rect = reportRects_[report_name];
02375 const SDL_Rect &new_rect = item->location(screen_area());
02376 surface &surf = reportSurfaces_[report_name];
02377
02378 config &report = reports_[report_name];
02379
02380
02381 if (surf && rect == new_rect && report == _report) {
02382 return;
02383 }
02384
02385 report = _report;
02386
02387 if (surf) {
02388 sdl_blit(surf, NULL, screen_.getSurface(), &rect);
02389 update_rect(rect);
02390 }
02391
02392
02393 if (!surf || new_rect != rect)
02394 {
02395 surf.assign(NULL);
02396 rect = new_rect;
02397
02398
02399
02400
02401
02402 if (rect.w > 0 && rect.h > 0) {
02403 surf.assign(get_surface_portion(screen_.getSurface(), rect));
02404 if (reportSurfaces_[report_name] == NULL) {
02405 ERR_DP << "Could not backup background for report!\n";
02406 }
02407 }
02408 update_rect(rect);
02409 }
02410
02411 tooltips::clear_tooltips(rect);
02412
02413 if (report.empty()) return;
02414
02415 int x = rect.x, y = rect.y;
02416
02417
02418
02419
02420 std::string str = item->prefix();
02421 if (!str.empty()) {
02422 config &e = report.add_child_at("element", config(), 0);
02423 e["text"] = str;
02424 e["tooltip"] = report.child("element")["tooltip"];
02425 }
02426 str = item->postfix();
02427 if (!str.empty()) {
02428 config &e = report.add_child("element");
02429 e["text"] = str;
02430 e["tooltip"] = report.child("element", -1)["tooltip"];
02431 }
02432
02433
02434 int tallest = 0;
02435 int image_count = 0;
02436 bool used_ellipsis = false;
02437 std::ostringstream ellipsis_tooltip;
02438 SDL_Rect ellipsis_area = rect;
02439
02440 for (config::const_child_itors elements = report.child_range("element");
02441 elements.first != elements.second; ++elements.first)
02442 {
02443 SDL_Rect area = create_rect(x, y, rect.w + rect.x - x, rect.h + rect.y - y);
02444 if (area.h <= 0) break;
02445
02446 std::string t = (*elements.first)["text"];
02447 if (!t.empty())
02448 {
02449 if (used_ellipsis) goto skip_element;
02450
02451
02452 font::ttext text;
02453 if (item->font_rgb_set()) {
02454 text.set_foreground_color(item->font_rgb());
02455 }
02456 bool eol = false;
02457 if (t[t.size() - 1] == '\n') {
02458 eol = true;
02459 t = t.substr(0, t.size() - 1);
02460 }
02461 text.set_font_size(item->font_size());
02462 text.set_text(t, true);
02463 text.set_maximum_width(area.w);
02464 text.set_maximum_height(area.h, false);
02465 surface s = text.render();
02466
02467
02468 const int minimal_text = 12;
02469 config::const_child_iterator ee = elements.first;
02470 if (!eol && rect.w - (x - rect.x + s->w) < minimal_text &&
02471 ++ee != elements.second && !(*ee)["text"].empty())
02472 {
02473
02474
02475
02476 t = t + " ";
02477 text.set_text(t, true);
02478 s = text.render();
02479
02480 used_ellipsis = true;
02481 ellipsis_area.x = x;
02482 ellipsis_area.y = y;
02483 ellipsis_area.w = s->w;
02484 ellipsis_area.h = s->h;
02485 }
02486
02487 screen_.blit_surface(x, y, s);
02488 area.w = s->w;
02489 area.h = s->h;
02490 if (area.h > tallest) {
02491 tallest = area.h;
02492 }
02493 if (eol) {
02494 x = rect.x;
02495 y += tallest;
02496 tallest = 0;
02497 } else {
02498 x += area.w;
02499 }
02500 }
02501 else if (!(t = (*elements.first)["image"].str()).empty())
02502 {
02503 if (used_ellipsis) goto skip_element;
02504
02505
02506 surface img(image::get_image(t));
02507
02508 if (!img) {
02509 ERR_DP << "could not find image for report: '" << t << "'\n";
02510 continue;
02511 }
02512
02513 if (area.w < img->w && image_count) {
02514
02515 img = surface(image::get_image(game_config::images::ellipsis));
02516 used_ellipsis = true;
02517 }
02518
02519 if (img->w < area.w) area.w = img->w;
02520 if (img->h < area.h) area.h = img->h;
02521 draw_image_for_report(img, area);
02522
02523 ++image_count;
02524 if (area.h > tallest) {
02525 tallest = area.h;
02526 }
02527
02528 if (!used_ellipsis) {
02529 x += area.w;
02530 } else {
02531 ellipsis_area = area;
02532 }
02533 }
02534 else
02535 {
02536
02537 continue;
02538 }
02539
02540 skip_element:
02541 t = (*elements.first)["tooltip"].t_str().base_str();
02542 if (!t.empty()) {
02543 if (!used_ellipsis) {
02544 tooltips::add_tooltip(area, t, (*elements.first)["help"].t_str().base_str());
02545 } else {
02546
02547
02548
02549 ellipsis_tooltip << t;
02550 config::const_child_iterator ee = elements.first;
02551 if (++ee != elements.second)
02552 ellipsis_tooltip << "\n _________\n\n";
02553 }
02554 }
02555 }
02556
02557 if (used_ellipsis) {
02558 tooltips::add_tooltip(ellipsis_area, ellipsis_tooltip.str());
02559 }
02560 }
02561
02562 void display::invalidate_all()
02563 {
02564 DBG_DP << "invalidate_all()\n";
02565 invalidateAll_ = true;
02566 #ifdef _OPENMP
02567 #pragma omp critical(invalidated_)
02568 #endif //_OPENMP
02569 invalidated_.clear();
02570 update_rect(map_area());
02571 }
02572
02573 bool display::invalidate(const map_location& loc)
02574 {
02575 if(invalidateAll_)
02576 return false;
02577
02578 bool tmp;
02579 #ifdef _OPENMP
02580 #pragma omp critical(invalidated_)
02581 #endif //_OPENMP
02582 tmp = invalidated_.insert(loc).second;
02583 return tmp;
02584 }
02585
02586 bool display::invalidate(const std::set<map_location>& locs)
02587 {
02588 if(invalidateAll_)
02589 return false;
02590 bool ret = false;
02591 foreach (const map_location& loc, locs) {
02592 #ifdef _OPENMP
02593 #pragma omp critical(invalidated_)
02594 #endif //_OPENMP
02595 ret = invalidated_.insert(loc).second || ret;
02596 }
02597 return ret;
02598 }
02599
02600 bool display::propagate_invalidation(const std::set<map_location>& locs)
02601 {
02602 if(invalidateAll_)
02603 return false;
02604
02605 if(locs.size()<=1)
02606 return false;
02607
02608 bool result = false;
02609 #ifdef _OPENMP
02610 #pragma omp critical(invalidated_)
02611 #endif //_OPENMP
02612 {
02613
02614 std::set<map_location>::const_iterator i = locs.begin();
02615 for(; i != locs.end() && invalidated_.count(*i) == 0 ; ++i) {}
02616
02617 if (i != locs.end()) {
02618
02619
02620
02621
02622 size_t previous_size = invalidated_.size();
02623 invalidated_.insert(locs.begin(), locs.end());
02624 result = previous_size < invalidated_.size();
02625 }
02626 }
02627 return result;
02628 }
02629
02630 bool display::invalidate_visible_locations_in_rect(const SDL_Rect& rect)
02631 {
02632 return invalidate_locations_in_rect(intersect_rects(map_area(),rect));
02633 }
02634
02635 bool display::invalidate_locations_in_rect(const SDL_Rect& rect)
02636 {
02637 if(invalidateAll_)
02638 return false;
02639
02640 bool result = false;
02641 foreach (const map_location &loc, hexes_under_rect(rect)) {
02642 result |= invalidate(loc);
02643 }
02644 return result;
02645 }
02646
02647 void display::invalidate_animations()
02648 {
02649 new_animation_frame();
02650 animate_map_ = preferences::animate_map();
02651 if (animate_map_) {
02652 foreach (const map_location &loc, get_visible_hexes())
02653 {
02654 if (shrouded(loc)) continue;
02655 if (builder_->update_animation(loc)) {
02656 invalidate(loc);
02657 } else {
02658 invalidate_animations_location(loc);
02659 }
02660 }
02661 }
02662 foreach (unit& u, *units_) {
02663 u.refresh();
02664 }
02665 std::vector<unit*> unit_list;
02666 foreach (unit &u, *units_) {
02667 unit_list.push_back(&u);
02668 }
02669 bool new_inval;
02670 do {
02671 new_inval = false;
02672 #ifdef _OPENMP
02673 #pragma omp parallel for reduction(|:new_inval) shared(unit_list) schedule(guided)
02674 #endif //_OPENMP
02675 for(int i=0; i < static_cast<int>(unit_list.size()); i++) {
02676 new_inval |= unit_list[i]->invalidate(unit_list[i]->get_location());
02677 }
02678 }while(new_inval);
02679 }
02680
02681 void display::add_arrow(arrow& arrow)
02682 {
02683 const arrow_path_t & arrow_path = arrow.get_path();
02684 foreach (const map_location& loc, arrow_path)
02685 {
02686 arrows_map_[loc].push_back(&arrow);
02687 }
02688 }
02689
02690 void display::remove_arrow(arrow& arrow)
02691 {
02692 const arrow_path_t & arrow_path = arrow.get_path();
02693 foreach (const map_location& loc, arrow_path)
02694 {
02695 arrows_map_[loc].remove(&arrow);
02696 }
02697 }
02698
02699 void display::update_arrow(arrow & arrow)
02700 {
02701 const arrow_path_t & previous_path = arrow.get_previous_path();
02702 foreach (const map_location& loc, previous_path)
02703 {
02704 arrows_map_[loc].remove(&arrow);
02705 }
02706 const arrow_path_t & arrow_path = arrow.get_path();
02707 foreach (const map_location& loc, arrow_path)
02708 {
02709 arrows_map_[loc].push_back(&arrow);
02710 }
02711 }
02712
02713 void display::write(config& cfg) const
02714 {
02715 cfg["color_adjust_red"] = color_adjust_.r;
02716 cfg["color_adjust_green"] = color_adjust_.g;
02717 cfg["color_adjust_blue_"] = color_adjust_.b;
02718 }
02719
02720 void display::read(const config& cfg)
02721 {
02722 color_adjust_.r = cfg["color_adjust_red"].to_int(0);
02723 color_adjust_.g = cfg["color_adjust_green"].to_int(0);
02724 color_adjust_.b = cfg["color_adjust_blue_"].to_int(0);
02725 }
02726
02727 display *display::singleton_ = NULL;
02728