00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019
00020 #include "color_range.hpp"
00021 #include "config.hpp"
00022 #include "filesystem.hpp"
00023 #include "game_config.hpp"
00024 #include "image.hpp"
00025 #include "log.hpp"
00026 #include "sdl_utils.hpp"
00027 #include "util.hpp"
00028 #include "serialization/string_utils.hpp"
00029
00030 #include "SDL_image.h"
00031
00032 #include <cassert>
00033 #include <iostream>
00034 #include <map>
00035 #include <string>
00036
00037 #define ERR_DP LOG_STREAM(err, display)
00038
00039 namespace {
00040
00041 typedef std::map<image::locator::value, int> locator_finder_t;
00042 typedef std::pair<image::locator::value, int> locator_finder_pair;
00043 locator_finder_t locator_finder;
00044
00045
00046 image::image_cache images_,hexed_images_,scaled_to_hex_images_,scaled_to_zoom_,unmasked_images_;
00047 image::image_cache brightened_images_,semi_brightened_images_;
00048
00049
00050
00051 std::map<image::locator,bool> image_existance_map;
00052
00053 std::map<surface, surface> reversed_images_;
00054
00055 int red_adjust = 0, green_adjust = 0, blue_adjust = 0;
00056
00057
00058 std::vector<std::string> team_colors;
00059
00060 std::string image_mask;
00061
00062 int zoom = image::tile_size;
00063 int cached_zoom = 0;
00064
00065
00066
00067
00068
00069
00070 template<typename T>
00071 void reset_cache(std::vector<image::cache_item<T> >& cache)
00072 {
00073 typename std::vector<image::cache_item<T> >::iterator beg = cache.begin();
00074 typename std::vector<image::cache_item<T> >::iterator end = cache.end();
00075
00076 for(; beg != end; ++beg) {
00077 beg->loaded = false;
00078 beg->item = T();
00079 }
00080 }
00081 }
00082
00083 namespace image {
00084
00085 mini_terrain_cache_map mini_terrain_cache;
00086 mini_terrain_cache_map mini_fogged_terrain_cache;
00087
00088 void flush_cache()
00089 {
00090 reset_cache(images_);
00091 reset_cache(hexed_images_);
00092 reset_cache(scaled_to_hex_images_);
00093 reset_cache(scaled_to_zoom_);
00094 reset_cache(unmasked_images_);
00095 reset_cache(brightened_images_);
00096 reset_cache(semi_brightened_images_);
00097 mini_terrain_cache.clear();
00098 mini_fogged_terrain_cache.clear();
00099 reversed_images_.clear();
00100 image_existance_map.clear();
00101 }
00102
00103 int locator::last_index_ = 0;
00104
00105 void locator::init_index()
00106 {
00107 locator_finder_t::iterator i = locator_finder.find(val_);
00108
00109 if(i == locator_finder.end()) {
00110 index_ = last_index_++;
00111 locator_finder.insert(locator_finder_pair(val_, index_));
00112
00113 images_.push_back(cache_item<surface>());
00114 hexed_images_.push_back(cache_item<surface>());
00115 scaled_to_hex_images_.push_back(cache_item<surface>());
00116 scaled_to_zoom_.push_back(cache_item<surface>());
00117 unmasked_images_.push_back(cache_item<surface>());
00118 brightened_images_.push_back(cache_item<surface>());
00119 semi_brightened_images_.push_back(cache_item<surface>());
00120
00121 } else {
00122 index_ = i->second;
00123 }
00124 }
00125
00126 void locator::parse_arguments()
00127 {
00128 std::string& fn = val_.filename_;
00129 if(fn.empty()) {
00130 return;
00131 }
00132 size_t markup_field = fn.find('~');
00133
00134 if(markup_field != std::string::npos) {
00135 val_.type_ = SUB_FILE;
00136 val_.modifications_ = fn.substr(markup_field, fn.size() - markup_field);
00137 fn = fn.substr(0,markup_field);
00138 }
00139 }
00140
00141 locator::locator() :
00142 index_(-1)
00143 {
00144 }
00145
00146 locator::locator(const locator &a, const std::string& mods):
00147 val_(a.val_)
00148 {
00149 if(mods.size()){
00150 val_.modifications_ += mods;
00151 val_.type_=SUB_FILE;
00152 init_index();
00153 }
00154 else index_=a.index_;
00155 }
00156
00157 locator::locator(const char *filename) :
00158 val_(filename)
00159 {
00160 parse_arguments();
00161 init_index();
00162 }
00163
00164 locator::locator(const std::string &filename) :
00165 val_(filename)
00166 {
00167 parse_arguments();
00168 init_index();
00169 }
00170
00171 locator::locator(const char *filename, const std::string& modifications) :
00172 val_(filename, modifications)
00173 {
00174 init_index();
00175 }
00176
00177 locator::locator(const std::string &filename, const std::string& modifications) :
00178 val_(filename, modifications)
00179 {
00180 init_index();
00181 }
00182
00183 locator::locator(const std::string &filename, const gamemap::location &loc, const std::string& modifications) :
00184 val_(filename, loc, modifications)
00185 {
00186 init_index();
00187 }
00188
00189 locator::locator(const std::string &filename, const gamemap::location &loc, int center_x, int center_y, const std::string& modifications) :
00190 val_(filename, loc, center_x, center_y, modifications)
00191 {
00192 init_index();
00193 }
00194
00195 locator& locator::operator=(const locator &a)
00196 {
00197 index_ = a.index_;
00198 val_ = a.val_;
00199
00200 return *this;
00201 }
00202
00203 locator::value::value(const locator::value& a) :
00204 type_(a.type_), filename_(a.filename_), loc_(a.loc_),
00205 modifications_(a.modifications_),
00206 center_x_(a.center_x_), center_y_(a.center_y_)
00207 {
00208 }
00209
00210 locator::value::value() :
00211 type_(NONE)
00212 {}
00213
00214 locator::value::value(const char *filename) :
00215 type_(FILE), filename_(filename)
00216 {
00217 }
00218
00219
00220 locator::value::value(const char *filename, const std::string& modifications) :
00221 type_(SUB_FILE), filename_(filename), modifications_(modifications)
00222 {
00223 }
00224
00225 locator::value::value(const std::string& filename) :
00226 type_(FILE), filename_(filename)
00227 {
00228 }
00229
00230 locator::value::value(const std::string& filename, const std::string& modifications) :
00231 type_(SUB_FILE), filename_(filename), modifications_(modifications)
00232 {
00233 }
00234
00235 locator::value::value(const std::string& filename, const gamemap::location& loc, const std::string& modifications) :
00236 type_(SUB_FILE), filename_(filename), loc_(loc), modifications_(modifications)
00237 {
00238 }
00239
00240 locator::value::value(const std::string& filename, const gamemap::location& loc, int center_x, int center_y, const std::string& modifications) :
00241 type_(SUB_FILE), filename_(filename), loc_(loc), modifications_(modifications), center_x_(center_x), center_y_(center_y)
00242 {
00243 }
00244
00245 bool locator::value::operator==(const value& a) const
00246 {
00247 if(a.type_ != type_) {
00248 return false;
00249 } else if(type_ == FILE) {
00250 return filename_ == a.filename_;
00251 } else if(type_ == SUB_FILE) {
00252 return filename_ == a.filename_ && loc_ == a.loc_ && modifications_ == a.modifications_
00253 && center_x_ == a.center_x_ && center_y_ == a.center_y_;
00254 } else {
00255 return false;
00256 }
00257 }
00258
00259 bool locator::value::operator<(const value& a) const
00260 {
00261 if(type_ != a.type_) {
00262 return type_ < a.type_;
00263 } else if(type_ == FILE) {
00264 return filename_ < a.filename_;
00265 } else if(type_ == SUB_FILE) {
00266 if(filename_ != a.filename_)
00267 return filename_ < a.filename_;
00268 if(loc_ != a.loc_)
00269 return loc_ < a.loc_;
00270 if(center_x_ != a.center_x_)
00271 return center_x_ < a.center_x_;
00272 if(center_y_ != a.center_y_)
00273 return center_y_ < a.center_y_;
00274
00275 return(modifications_ < a.modifications_);
00276 } else {
00277 return false;
00278 }
00279 }
00280
00281 surface locator::load_image_file() const
00282 {
00283 surface res;
00284
00285 std::string location = get_binary_file_location("images", val_.filename_);
00286
00287 bool try_units = false;
00288
00289 do {
00290 if (!location.empty()) {
00291 res = IMG_Load(location.c_str());
00292 }
00293 if (res.null() && (!try_units)) {
00294 try_units = true;
00295 location = get_binary_file_location("images", "units/" + val_.filename_);
00296 } else {
00297 try_units = false;
00298 }
00299 } while (try_units);
00300
00301 if (res.null()) {
00302 ERR_DP << "could not open image '" << val_.filename_ << "'\n";
00303 }
00304
00305 return res;
00306 }
00307
00308 surface locator::load_image_sub_file() const
00309 {
00310 const surface mother_surface(get_image(val_.filename_, UNSCALED));
00311 const surface mask(get_image(game_config::terrain_mask_image, UNSCALED));
00312
00313 if(mother_surface == NULL)
00314 return surface(NULL);
00315 if(mask == NULL)
00316 return surface(NULL);
00317
00318 surface surf=mother_surface;
00319 if(val_.loc_.x>-1 && val_.loc_.y>-1 && val_.center_x_>-1 && val_.center_y_>-1){
00320 int offset_x = mother_surface->w/2 - val_.center_x_;
00321 int offset_y = mother_surface->h/2 - val_.center_y_;
00322 SDL_Rect srcrect = {
00323 ((tile_size*3) / 4) * val_.loc_.x + offset_x,
00324 tile_size * val_.loc_.y + (tile_size/2) * (val_.loc_.x % 2) + offset_y,
00325 tile_size, tile_size
00326 };
00327
00328 surface tmp(cut_surface(mother_surface, srcrect));
00329 surf=mask_surface(tmp, mask);
00330 }
00331 else if(val_.loc_.x>-1 && val_.loc_.y>-1 ){
00332 SDL_Rect srcrect = {
00333 ((tile_size*3) / 4) * val_.loc_.x,
00334 tile_size * val_.loc_.y + (tile_size/2) * (val_.loc_.x % 2),
00335 tile_size, tile_size
00336 };
00337
00338 surface tmp(cut_surface(mother_surface, srcrect));
00339 surf=mask_surface(tmp, mask);
00340 }
00341
00342
00343 if(val_.modifications_.size()){
00344 bool xflip = false;
00345 bool yflip = false;
00346 std::map<Uint32, Uint32> recolor_map;
00347 std::vector<std::string> modlist = utils::paranthetical_split(val_.modifications_,'~');
00348 for(std::vector<std::string>::const_iterator i=modlist.begin();
00349 i!= modlist.end();i++){
00350 std::vector<std::string> tmpmod = utils::paranthetical_split(*i);
00351 std::vector<std::string>::const_iterator j=tmpmod.begin();
00352 while(j!= tmpmod.end()){
00353 std::string function=*j++;
00354 if(j==tmpmod.end()){
00355 if(function.size()){
00356 ERR_DP << "error parsing image modifications: "
00357 << val_.modifications_<< "\n";
00358 }
00359 break;
00360 }
00361 std::string field = *j++;
00362
00363 if("TC" == function){
00364 std::vector<std::string> param = utils::split(field,',');
00365 if(param.size() < 2)
00366 break;
00367
00368 int side_n = lexical_cast_default<int>(param[0], -1);
00369 std::string team_color;
00370 if (side_n < 1) {
00371 break;
00372 } else if (side_n < static_cast<int>(team_colors.size())) {
00373 team_color = team_colors[side_n - 1];
00374 } else {
00375
00376 team_color = lexical_cast<std::string>(side_n);
00377 }
00378
00379 if(game_config::tc_info(param[1]).size()){
00380 function="RC";
00381 field = param[1] + ">" + team_color;
00382 }
00383 }
00384
00385 if("RC" == function){
00386 std::vector<std::string> recolor=utils::split(field,'>');
00387 if(recolor.size()>1){
00388 std::map<Uint32, Uint32> tmp_map;
00389 try {
00390 color_range const& new_color = game_config::color_info(recolor[1]);
00391 std::vector<Uint32> const& old_color = game_config::tc_info(recolor[0]);
00392 tmp_map = recolor_range(new_color,old_color);
00393 } catch (config::error& e) {
00394 ERR_DP << "caught config::error... " << e.message << std::endl;
00395 }
00396 for(std::map<Uint32, Uint32>::const_iterator tmp = tmp_map.begin(); tmp!= tmp_map.end(); tmp++){
00397 recolor_map[tmp->first] = tmp->second;
00398 }
00399 }
00400 }
00401 if("FL" == function){
00402 if(field.empty() || field.find("horiz") != std::string::npos) {
00403 xflip = !xflip;
00404 }
00405 if(field.find("vert") != std::string::npos) {
00406 yflip = !yflip;
00407 }
00408 }
00409 }
00410 }
00411 surf = recolor_image(surf,recolor_map);
00412 if(xflip) {
00413 surf = flip_surface(surf);
00414 }
00415 if(yflip) {
00416 surf = flop_surface(surf);
00417 }
00418 }
00419 return surf;
00420 }
00421
00422 surface locator::load_from_disk() const
00423 {
00424 switch(val_.type_) {
00425 case FILE:
00426 return load_image_file();
00427 case SUB_FILE:
00428 return load_image_sub_file();
00429 default:
00430 return surface(NULL);
00431 }
00432 }
00433
00434 #if 0
00435 template<typename T>
00436 bool locator::in_cache(const std::vector<cache_item<T> >& cache) const
00437 {
00438 if(index_ == -1)
00439 return false;
00440
00441 return cache[index_].loaded;
00442 }
00443
00444 template<typename T>
00445 T locator::locate_in_cache(const std::vector<cache_item<T> >& cache) const
00446 {
00447 if(index_ == -1)
00448 return T();
00449
00450 return cache[index_].item;
00451 }
00452
00453 template<typename T>
00454 void locator::add_to_cache(std::vector<cache_item<T> >& cache, const T& item) const
00455 {
00456 if(index_ == -1)
00457 return;
00458
00459 cache[index_] = cache_item<T>(item);
00460 }
00461 #endif
00462
00463 manager::manager() {}
00464
00465 manager::~manager()
00466 {
00467 flush_cache();
00468 }
00469
00470 void set_wm_icon()
00471 {
00472 #if !(defined(__APPLE__))
00473 surface icon(get_image(game_config::game_icon,UNSCALED));
00474 if(icon != NULL) {
00475 ::SDL_WM_SetIcon(icon,NULL);
00476 }
00477 #endif
00478 }
00479
00480 SDL_PixelFormat* pixel_format = NULL;
00481
00482 void set_pixel_format(SDL_PixelFormat* format)
00483 {
00484 pixel_format = format;
00485 flush_cache();
00486 }
00487
00488 void set_colour_adjustment(int r, int g, int b)
00489 {
00490 if(r != red_adjust || g != green_adjust || b != blue_adjust) {
00491 red_adjust = r;
00492 green_adjust = g;
00493 blue_adjust = b;
00494 reset_cache(scaled_to_hex_images_);
00495 reset_cache(brightened_images_);
00496 reset_cache(semi_brightened_images_);
00497 reversed_images_.clear();
00498 }
00499 }
00500
00501 void set_team_colors(const std::vector<std::string>* colors)
00502 {
00503 if (colors == NULL)
00504 team_colors.clear();
00505 else {
00506 team_colors = *colors;
00507 }
00508 }
00509
00510 void set_image_mask(const std::string& )
00511 {
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525 }
00526
00527 void set_zoom(int amount)
00528 {
00529 if(amount != zoom) {
00530 zoom = amount;
00531 reset_cache(scaled_to_hex_images_);
00532 reset_cache(brightened_images_);
00533 reset_cache(semi_brightened_images_);
00534 reversed_images_.clear();
00535
00536
00537
00538
00539 if (zoom != tile_size && zoom != cached_zoom) {
00540 reset_cache(scaled_to_zoom_);
00541 reset_cache(unmasked_images_);
00542 cached_zoom = zoom;
00543 }
00544 }
00545 }
00546
00547 static surface get_hexed(const locator i_locator)
00548 {
00549
00550
00551 surface image(get_image(i_locator, UNSCALED, false));
00552
00553 const surface hex(get_image(game_config::terrain_mask_image,
00554 UNSCALED));
00555 return mask_surface(image, hex);
00556 }
00557
00558 static surface get_unmasked(const locator i_locator)
00559 {
00560
00561
00562 surface image(get_image(i_locator, HEXED));
00563 if (zoom != tile_size)
00564 return scale_surface(image, zoom, zoom);
00565 else
00566 return image;
00567 }
00568
00569 static surface get_scaled_to_hex(const locator i_locator)
00570 {
00571 surface res(get_image(i_locator, UNMASKED));
00572
00573
00574 if (red_adjust != 0 ||
00575 green_adjust != 0 || blue_adjust != 0) {
00576 res = surface(adjust_surface_colour(res,
00577 red_adjust, green_adjust, blue_adjust));
00578 }
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588 return res;
00589 }
00590
00591 static surface get_scaled_to_zoom(const locator i_locator)
00592 {
00593 assert(zoom != tile_size);
00594 assert(tile_size != 0);
00595
00596 surface res(get_image(i_locator, UNSCALED));
00597
00598 if(!res.null()) {
00599 return scale_surface(res, ((res.get()->w * zoom) / tile_size), ((res.get()->h * zoom) / tile_size));
00600 } else {
00601 return surface(NULL);
00602 }
00603 }
00604
00605 static surface get_brightened(const locator i_locator)
00606 {
00607 surface image(get_image(i_locator, SCALED_TO_HEX));
00608 return surface(brighten_image(image, ftofxp(1.5)));
00609 }
00610
00611 static surface get_semi_brightened(const locator i_locator)
00612 {
00613 surface image(get_image(i_locator, SCALED_TO_HEX));
00614 return surface(brighten_image(image, ftofxp(1.25)));
00615 }
00616
00617 surface get_image(const image::locator& i_locator, TYPE type, bool add_to_cache )
00618 {
00619 surface res(NULL);
00620 image_cache *imap;
00621
00622 if(i_locator.is_void())
00623 return surface(NULL);
00624
00625 bool is_unscaled = false;
00626
00627 switch(type) {
00628 case UNSCALED:
00629 is_unscaled = true;
00630 imap = &images_;
00631 break;
00632 case SCALED_TO_HEX:
00633 imap = &scaled_to_hex_images_;
00634 break;
00635 case SCALED_TO_ZOOM:
00636
00637 if(zoom != tile_size) {
00638 imap = &scaled_to_zoom_;
00639 } else {
00640 is_unscaled = true;
00641 imap = &images_;
00642 }
00643 break;
00644 case HEXED:
00645 imap = &hexed_images_;
00646 break;
00647 case UNMASKED:
00648
00649 if(zoom != tile_size) {
00650 imap = &unmasked_images_;
00651 } else {
00652 imap = &hexed_images_;
00653 }
00654 break;
00655 case BRIGHTENED:
00656 imap = &brightened_images_;
00657 break;
00658 case SEMI_BRIGHTENED:
00659 imap = &semi_brightened_images_;
00660 break;
00661 default:
00662 return surface(NULL);
00663 }
00664
00665 if(i_locator.in_cache(*imap))
00666 return i_locator.locate_in_cache(*imap);
00667
00668
00669
00670 if(is_unscaled) {
00671 res = i_locator.load_from_disk();
00672
00673 if(res == NULL) {
00674 if(add_to_cache) i_locator.add_to_cache(*imap, surface(NULL));
00675 return surface(NULL);
00676 }
00677 } else {
00678
00679
00680
00681 switch(type) {
00682 case SCALED_TO_HEX:
00683 res = get_scaled_to_hex(i_locator);
00684 break;
00685 case SCALED_TO_ZOOM:
00686 res = get_scaled_to_zoom(i_locator);
00687 break;
00688 case HEXED:
00689 res = get_hexed(i_locator);
00690 break;
00691 case UNMASKED:
00692 res = get_unmasked(i_locator);
00693 break;
00694 case BRIGHTENED:
00695 res = get_brightened(i_locator);
00696 break;
00697 case SEMI_BRIGHTENED:
00698 res = get_semi_brightened(i_locator);
00699 break;
00700 default:
00701 return surface(NULL);
00702 }
00703 }
00704
00705
00706 res = create_optimized_surface(res);
00707 if(add_to_cache) i_locator.add_to_cache(*imap, res);
00708 return res;
00709 }
00710
00711 surface reverse_image(const surface& surf)
00712 {
00713 if(surf == NULL) {
00714 return surface(NULL);
00715 }
00716
00717 const std::map<surface,surface>::iterator itor = reversed_images_.find(surf);
00718 if(itor != reversed_images_.end()) {
00719
00720 return itor->second;
00721 }
00722
00723 const surface rev(flip_surface(surf));
00724 if(rev == NULL) {
00725 return surface(NULL);
00726 }
00727
00728 reversed_images_.insert(std::pair<surface,surface>(surf,rev));
00729
00730 return rev;
00731 }
00732
00733 bool exists(const image::locator& i_locator)
00734 {
00735 typedef image::locator loc;
00736 loc::type type = i_locator.get_type();
00737 if (type != loc::FILE && type != loc::SUB_FILE)
00738 return false;
00739
00740
00741 std::pair< std::map< image::locator, bool >::iterator, bool >
00742 it = image_existance_map.insert(std::make_pair(i_locator, false));
00743 bool &cache = it.first->second;
00744 if (it.second)
00745 cache = !get_binary_file_location("images", i_locator.get_filename()).empty();
00746 return cache;
00747 }
00748
00749
00750 }
00751