void floating_label::draw(surface screen) { if(!visible_) { buf_.assign(nullptr); return; } if(screen == nullptr) { return; } create_surface(); if(surf_ == nullptr) { return; } if(buf_ == nullptr) { buf_.assign(create_compatible_surface(screen, surf_->w, surf_->h)); if(buf_ == nullptr) { return; } } SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h); const clip_rect_setter clip_setter(screen, &clip_rect_); sdl_copy_portion(screen,&rect,buf_,nullptr); sdl_blit(surf_,nullptr,screen,&rect); }
void textbox::append_text(const std::string& text, bool auto_scroll, const SDL_Color& color) { if(text_image_.get() == NULL) { set_text(text, color); return; } //disallow adding multi-line text to a single-line text box if(wrap_ == false && std::find_if(text.begin(),text.end(),utils::isnewline) != text.end()) { return; } const bool is_at_bottom = get_position() == get_max_position(); const wide_string& wtext = utils::string_to_wstring(text); const surface new_text = add_text_line(wtext, color); const surface new_surface = create_compatible_surface(text_image_,std::max<size_t>(text_image_->w,new_text->w),text_image_->h+new_text->h); SDL_SetAlpha(new_text.get(),0,0); SDL_SetAlpha(text_image_.get(),0,0); SDL_BlitSurface(text_image_,NULL,new_surface,NULL); SDL_Rect target = {0,text_image_->h,new_text->w,new_text->h}; SDL_BlitSurface(new_text,NULL,new_surface,&target); text_image_.assign(new_surface); text_.resize(text_.size() + wtext.size()); std::copy(wtext.begin(),wtext.end(),text_.end()-wtext.size()); set_dirty(true); update_text_cache(false); if(auto_scroll && is_at_bottom) scroll_to_bottom(); handle_text_changed(text_); }
void mouse_action::set_terrain_mouse_overlay(editor_display& disp, t_translation::t_terrain fg, t_translation::t_terrain bg) { surface image_fg(image::get_image("terrain/" + disp.get_map().get_terrain_info(fg).editor_image() + ".png")); surface image_bg(image::get_image("terrain/" + disp.get_map().get_terrain_info(bg).editor_image() + ".png")); if (image_fg == NULL || image_bg == NULL) { ERR_ED << "Missing terrain icon\n"; disp.set_mouseover_hex_overlay(NULL); return; } // Create a transparent surface of the right size. surface image = create_compatible_surface(image_fg, image_fg->w, image_fg->h); SDL_FillRect(image,NULL,SDL_MapRGBA(image->format,0,0,0, 0)); // For efficiency the size of the tile is cached. // We assume all tiles are of the same size. // The zoom factor can change, so it's not cached. // NOTE: when zooming and not moving the mouse, there are glitches. // Since the optimal alpha factor is unknown, it has to be calculated // on the fly, and caching the surfaces makes no sense yet. static const Uint8 alpha = 196; static const int size = image_fg->w; static const int half_size = size / 2; static const int quarter_size = size / 4; static const int offset = 2; static const int new_size = half_size - 2; const int zoom = static_cast<int>(size * disp.get_zoom_factor()); // Blit left side image_fg = scale_surface(image_fg, new_size, new_size); SDL_Rect rcDestLeft = { offset, quarter_size, 0, 0 }; SDL_BlitSurface ( image_fg, NULL, image, &rcDestLeft ); // Blit left side image_bg = scale_surface(image_bg, new_size, new_size); SDL_Rect rcDestRight = { half_size, quarter_size, 0, 0 }; SDL_BlitSurface ( image_bg, NULL, image, &rcDestRight ); //apply mask so the overlay is contained within the mouseover hex surface mask(image::get_image("terrain/alphamask.png")); image = mask_surface(image, mask); // Add the alpha factor and scale the image image = scale_surface(adjust_surface_alpha(image, alpha), zoom, zoom); // Set as mouseover disp.set_mouseover_hex_overlay(image); }
void fill_rect_alpha(SDL_Rect &rect, Uint32 color, Uint8 alpha, surface target) { if(alpha == SDL_ALPHA_OPAQUE) { sdl::fill_rect(target,&rect,color); return; } else if(alpha == SDL_ALPHA_TRANSPARENT) { return; } surface tmp(create_compatible_surface(target,rect.w,rect.h)); if(tmp == NULL) { return; } SDL_Rect r = {0,0,rect.w,rect.h}; sdl::fill_rect(tmp,&r,color); SDL_SetAlpha(tmp,SDL_SRCALPHA,alpha); sdl_blit(tmp,NULL,target,&rect); }
void draw(surface screen) { if(use_color_cursors() == false) { return; } if(current_cursor == NUM_CURSORS) { current_cursor = NORMAL; } if(have_focus == false) { cursor_buf = NULL; return; } if (!color_ready) { // Display start to draw cursor // so it can now display color cursor color_ready = true; // Reset the cursor to be sure that we hide the b&w set(); } /** @todo FIXME: don't parse the file path every time */ const surface surf(image::get_image("cursors/" + color_images[current_cursor])); if(surf == NULL) { // Fall back to b&w cursors std::cerr << "could not load color cursors. Falling back to hardware cursors\n"; preferences::set_color_cursors(false); return; } if(cursor_buf != NULL && (cursor_buf->w != surf->w || cursor_buf->h != surf->h)) { cursor_buf = NULL; } if(cursor_buf == NULL) { cursor_buf = create_compatible_surface(surf); if(cursor_buf == NULL) { std::cerr << "Could not allocate surface for mouse cursor\n"; return; } } int new_cursor_x, new_cursor_y; SDL_GetMouseState(&new_cursor_x,&new_cursor_y); const bool must_update = new_cursor_x != cursor_x || new_cursor_y != cursor_y; cursor_x = new_cursor_x; cursor_y = new_cursor_y; // Save the screen area where the cursor is being drawn onto the back buffer SDL_Rect area = create_rect(cursor_x - shift_x[current_cursor] , cursor_y - shift_y[current_cursor] , surf->w , surf->h); sdl_blit(screen,&area,cursor_buf,NULL); // Blit the surface sdl_blit(surf,NULL,screen,&area); if(must_update) { update_rect(area); } }
static surface render_text(const std::string& text, int fontsize, const SDL_Color& colour, int style, bool use_markup) { // we keep blank lines and spaces (may be wanted for indentation) const std::vector<std::string> lines = utils::split(text, '\n', 0); std::vector<std::vector<surface> > surfaces; surfaces.reserve(lines.size()); size_t width = 0, height = 0; for(std::vector< std::string >::const_iterator ln = lines.begin(), ln_end = lines.end(); ln != ln_end; ++ln) { int sz = fontsize; int text_style = style; std::string::const_iterator after_markup = use_markup ? parse_markup(ln->begin(), ln->end(), &sz, NULL, &text_style) : ln->begin(); text_surface txt_surf(sz, colour, text_style); if (after_markup == ln->end() && (ln+1 != ln_end || lines.begin()+1 == ln_end)) { // we replace empty line by a space (to have a line height) // except for the last line if we have several txt_surf.set_text(" "); } else if (after_markup == ln->begin()) { // simple case, no markup to skip txt_surf.set_text(*ln); } else { const std::string line(after_markup,ln->end()); txt_surf.set_text(line); } const text_surface& cached_surf = text_cache::find(txt_surf); const std::vector<surface>&res = cached_surf.get_surfaces(); if (!res.empty()) { surfaces.push_back(res); width = std::max<size_t>(cached_surf.width(), width); height += cached_surf.height(); } } if (surfaces.empty()) { return surface(); } else if (surfaces.size() == 1 && surfaces.front().size() == 1) { surface surf = surfaces.front().front(); SDL_SetAlpha(surf, SDL_SRCALPHA | SDL_RLEACCEL, SDL_ALPHA_OPAQUE); return surf; } else { surface res(create_compatible_surface(surfaces.front().front(),width,height)); if (res.null()) return res; size_t ypos = 0; for(std::vector< std::vector<surface> >::const_iterator i = surfaces.begin(), i_end = surfaces.end(); i != i_end; ++i) { size_t xpos = 0; size_t height = 0; for(std::vector<surface>::const_iterator j = i->begin(), j_end = i->end(); j != j_end; ++j) { SDL_SetAlpha(*j, 0, 0); // direct blit without alpha blending SDL_Rect dstrect = {xpos, ypos, 0, 0}; SDL_BlitSurface(*j, NULL, res, &dstrect); xpos += (*j)->w; height = std::max<size_t>((*j)->h, height); } ypos += height; } return res; } }
//TODO: proper SDL_gpu implementation void unit_drawer::draw_bar(const std::string& image, int xpos, int ypos, const map_location& loc, size_t height, double filled, const SDL_Color& col, fixed_t alpha) const { filled = std::min<double>(std::max<double>(filled,0.0),1.0); height = static_cast<size_t>(height*zoom_factor); surface surf(image::get_image(image,image::SCALED_TO_HEX)); // We use UNSCALED because scaling (and bilinear interpolation) // is bad for calculate_energy_bar. // But we will do a geometric scaling later. surface bar_surf(image::get_image(image)); if(surf == nullptr || bar_surf == nullptr) { return; } // calculate_energy_bar returns incorrect results if the surface colors // have changed (for example, due to bilinear interpolation) const SDL_Rect& unscaled_bar_loc = calculate_energy_bar(bar_surf); SDL_Rect bar_loc; if (surf->w == bar_surf->w && surf->h == bar_surf->h) bar_loc = unscaled_bar_loc; else { const fixed_t xratio = fxpdiv(surf->w,bar_surf->w); const fixed_t yratio = fxpdiv(surf->h,bar_surf->h); const SDL_Rect scaled_bar_loc = sdl::create_rect( fxptoi(unscaled_bar_loc. x * xratio) , fxptoi(unscaled_bar_loc. y * yratio + 127) , fxptoi(unscaled_bar_loc. w * xratio + 255) , fxptoi(unscaled_bar_loc. h * yratio + 255)); bar_loc = scaled_bar_loc; } if(height > static_cast<size_t>(bar_loc.h)) { height = bar_loc.h; } //if(alpha != ftofxp(1.0)) { // surf.assign(adjust_surface_alpha(surf,alpha)); // if(surf == nullptr) { // return; // } //} const size_t skip_rows = bar_loc.h - height; SDL_Rect top = sdl::create_rect(0, 0, surf->w, bar_loc.y); SDL_Rect bot = sdl::create_rect(0, bar_loc.y + skip_rows, surf->w, 0); bot.h = surf->w - bot.y; #ifdef SDL_GPU sdl::timage img(surf); img.set_clip(top); disp.drawing_buffer_add(display::LAYER_UNIT_BAR, loc, xpos, ypos, surf); img.set_clip(bot); disp.drawing_buffer_add(display::LAYER_UNIT_BAR, loc, xpos, ypos + top.h, surf); #else disp.drawing_buffer_add(display::LAYER_UNIT_BAR, loc, xpos, ypos, surf, top); disp.drawing_buffer_add(display::LAYER_UNIT_BAR, loc, xpos, ypos + top.h, surf, bot); #endif size_t unfilled = static_cast<size_t>(height * (1.0 - filled)); if(unfilled < height && alpha >= ftofxp(0.3)) { const Uint8 r_alpha = std::min<unsigned>(unsigned(fxpmult(alpha,255)),255); surface filled_surf = create_compatible_surface(bar_surf, bar_loc.w, height - unfilled); SDL_Rect filled_area = sdl::create_rect(0, 0, bar_loc.w, height-unfilled); sdl::fill_rect(filled_surf,&filled_area,SDL_MapRGBA(bar_surf->format,col.r,col.g,col.b, r_alpha)); #ifdef SDL_GPU disp.drawing_buffer_add(display::LAYER_UNIT_BAR, loc, xpos + bar_loc.x, ypos + bar_loc.y + unfilled, sdl::timage(filled_surf)); #else disp.drawing_buffer_add(display::LAYER_UNIT_BAR, loc, xpos + bar_loc.x, ypos + bar_loc.y + unfilled, filled_surf); #endif } }
int main(int argc, char* argv[]) { std::string src; std::string dest_dir; cutter cut; // Parse arguments that shouldn't require a display device int arg; for(arg = 1; arg != argc; ++arg) { const std::string val(argv[arg]); if(val.empty()) { continue; } if(val == "--help" || val == "-h") { print_usage(argv[0]); return 0; } else if(val == "--verbose" || val == "-v") { cut.set_verbose(true); } else if(val == "--directory" || val == "-d" ) { game_config::path = argv[++arg]; } else { if(src.empty()) { src = val; } else if(dest_dir.empty()) { dest_dir = val; } else { print_usage(argv[0]); return 1; } } } if(src.empty() || dest_dir.empty()) { print_usage(argv[0]); return 1; } try { const config conf = cut.load_config(src); cut.load_masks(conf); const surface src_surface(make_neutral_surface(IMG_Load(src.c_str()))); if(src_surface == NULL) throw exploder_failure("Unable to load the source image " + src); const cutter::surface_map surfaces = cut.cut_surface(src_surface, conf); for(cutter::surface_map::const_iterator itor = surfaces.begin(); itor != surfaces.end(); ++itor) { const cutter::mask &mask = itor->second.mask; surface surf = create_compatible_surface( itor->second.image , mask.cut.w , mask.cut.h); masked_overwrite_surface(surf, itor->second.image, mask.image, mask.cut.x - mask.shift.x, mask.cut.y - mask.shift.y); save_image(surf, dest_dir + "/" + mask.name + ".png"); } } catch(exploder_failure& err) { std::cerr << "Failed: " << err.message << "\n"; return 1; } return 0; }
surface getMinimap(int w, int h, const gamemap &map, const display* disp) { const size_t map_width = map.w() * scale_ratio_w; const size_t map_height = map.h() * scale_ratio_h; if (map_width == 0 || map_height == 0) { return surface(NULL); } surface minimap(create_neutral_surface(map_width, map_height)); if (minimap == NULL) { return surface(NULL); } typedef mini_terrain_cache_map cache_map; cache_map *normal_cache = &mini_terrain_cache; cache_map *fog_cache = &mini_fogged_terrain_cache; SDL_Rect tilerect = empty_rect; for (int y = 0; y != map.total_height(); ++y) { for (int x = 0; x != map.total_width(); ++x) { surface surf(NULL); const map_location loc(x,y); if(map.on_board(loc)) { bool shrouded = false; bool fogged = false; if (disp) { disp->shrouded_and_fogged(loc, shrouded, fogged); } const t_translation::t_terrain terrain = shrouded ? t_translation::VOID_TERRAIN : map[loc]; const terrain_type& terrain_info = map.get_terrain_info(terrain); bool need_fogging = false; cache_map* cache = fogged ? fog_cache : normal_cache; cache_map::iterator i = cache->find(terrain); if (fogged && i == cache->end()) { // we don't have the fogged version in cache // try the normal cache and ask fogging the image cache = normal_cache; i = cache->find(terrain); need_fogging = true; } if(i == cache->end()) { std::string base_file = image::terrain_prefix + terrain_info.minimap_image() + ".png"; // surface tile = get_image(base_file,image::HEXED); surface tile = get_hexed(base_file); //Compose images of base and overlay if necessary // NOTE we also skip overlay when base is missing (to avoid hiding the error) if(tile != NULL && map.get_terrain_info(terrain).is_combined()) { std::string overlay_file = image::terrain_prefix + terrain_info.minimap_image_overlay() + ".png"; // surface overlay = get_image(overlay_file,image::HEXED); surface overlay = get_hexed(overlay_file); if(overlay != NULL && overlay != tile) { surface combined = create_compatible_surface(tile, tile->w, tile->h); SDL_Rect r = create_rect(0,0,0,0); sdl_blit(tile, NULL, combined, &r); r.x = std::max(0, (tile->w - overlay->w)/2); r.y = std::max(0, (tile->h - overlay->h)/2); //blit_surface needs neutral surface surface overlay_neutral = make_neutral_surface(overlay); blit_surface(overlay_neutral, NULL, combined, &r); tile = combined; } } surf = scale_surface_blended(tile, scale_ratio, scale_ratio); i = normal_cache->insert(cache_map::value_type(terrain,surf)).first; } surf = i->second; if (need_fogging) { surf = adjust_surface_color(surf,-50,-50,-50); fog_cache->insert(cache_map::value_type(terrain,surf)); } // we need a balanced shift up and down of the hexes. // if not, only the bottom half-hexes are clipped // and it looks asymmetrical. // also do 1-pixel shift because the scaling // function seems to do it with its rounding tilerect.x = x; tilerect.y = y; minimap_tile_dst(tilerect.x, tilerect.y); if (surf != NULL) { sdl_blit(surf, NULL, minimap, &tilerect); } } } } double wratio = w*1.0 / minimap->w; double hratio = h*1.0 / minimap->h; double ratio = std::min<double>(wratio, hratio); minimap = scale_surface(minimap, static_cast<int>(minimap->w * ratio), static_cast<int>(minimap->h * ratio)); DBG_DP << "done generating minimap\n"; return minimap; }
/** * Show credits with list of contributors. * * Names of people are shown scrolling up like in movie-credits.\n * Uses map from wesnoth or campaign as background. */ void show_about(CVideo &video, const std::string &campaign) { boost::scoped_ptr<cursor::setter> cur(new cursor::setter(cursor::WAIT)); surface& screen = video.getSurface(); if (screen == nullptr) return; // If the title is multi-line, we need to split it accordingly or we // get slight scrolling glitches in the credits screen. std::vector<std::string> text = about::get_text(campaign, true); SDL_Rect screen_rect = sdl::create_rect(0, 0, screen->w, screen->h); const surface_restorer restorer(&video, screen_rect); cur.reset(); std::vector<std::string> image_list; if(campaign.size() && !images[campaign].empty()){ image_list = utils::parenthetical_split(images[campaign], ','); } else{ image_list = utils::parenthetical_split(images_default, ','); } surface map_image, map_image_scaled; if(!image_list.empty()) { map_image = image::get_image(image_list[0]); } else { image_list.push_back(""); } if(!map_image){ image_list[0]=game_config::images::game_title_background; map_image=image::get_image(image_list[0]); } gui::button close(video,_("Close")); close.set_location((screen->w/2)-(close.width()/2), screen->h - 30); const int def_size = font::SIZE_XLARGE; const SDL_Color def_color = font::NORMAL_COLOR; //substitute in the correct control characters for '+' and '-' std::string before_header(2, ' '); before_header[0] = font::LARGE_TEXT; for(unsigned i = 0; i < text.size(); ++i) { std::string &s = text[i]; if (s.empty()) continue; char &first = s[0]; if (first == '-') first = font::SMALL_TEXT; else if (first == '+') { first = font::LARGE_TEXT; text.insert(text.begin() + i, before_header); ++i; } } text.insert(text.begin(), 10, before_header); int startline = 0; //TODO: use values proportional to screen ? // distance from top of map image to top of scrolling text const int top_margin = 60; // distance from bottom of scrolling text to bottom of map image const int bottom_margin = 40; // distance from left of scrolling text to the frame border const int text_left_padding = screen->w/32; int offset = 0; bool is_new_line = true; int first_line_height = 0; SDL_Rect frame_area; // we use a dialog to contains the text. Strange idea but at least the style // will be consistent with the titlescreen gui::dialog_frame f(video, "", gui::dialog_frame::titlescreen_style, false); // the text area's dimensions SDL_Rect text_rect = { 0, 0, 0, 0 }; // we'll retain a copy to prevent SDL_blit to change its w and h SDL_Rect text_rect_blit; surface text_surf; CKey key; bool last_escape; int image_count = 0; int scroll_speed = 4; // scroll_speed*50 = speed of scroll in pixel per second // Initially redraw all bool redraw_mapimage = true; bool update_dimensions = true; int max_text_width = 0; do { last_escape = key[SDLK_ESCAPE] != 0; // check to see if background image has changed if(text.size() && (image_count < ((startline * static_cast<int>(image_list.size())) / static_cast<int>(text.size())))){ image_count++; surface temp=image::get_image(image_list[image_count]); map_image=temp?temp:map_image; redraw_mapimage = true; } if (update_dimensions) { // rescale the background map_image_scaled = scale_surface(map_image, screen->w, screen->h); screen_rect = sdl::create_rect(0, 0, screen->w, screen->h); redraw_mapimage = true; // update the frame frame_area = sdl::create_rect( screen->w * 3 / 32 , top_margin , screen->w * 13 / 16 , screen->h - top_margin - bottom_margin); text_rect = f.layout(frame_area).interior; // update the text area text_rect.x += text_left_padding; text_rect.w -= text_left_padding; text_rect_blit = text_rect; text_surf = create_compatible_surface(screen, text_rect.w, text_rect.h); SDL_SetAlpha(text_surf, SDL_RLEACCEL, SDL_ALPHA_OPAQUE); // relocate the close button close.set_location((screen->w/2)-(close.width()/2), screen->h - 30); update_dimensions = false; } if (redraw_mapimage) { // draw map to screen, thus erasing all text sdl_blit(map_image_scaled, nullptr, screen, nullptr); update_rect(screen_rect); // redraw the dialog f.draw_background(); f.draw_border(); // cache the dialog background (alpha blending + blurred map) sdl_blit(screen, &text_rect, text_surf, nullptr); redraw_mapimage = false; } else { // redraw the saved part of the dialog where text scrolled // thus erasing all text SDL_Rect modified = sdl::create_rect(0, 0, max_text_width, text_rect.h); sdl_blit(text_surf, &modified, screen, &text_rect_blit); update_rect(text_rect); } int y = text_rect.y - offset; int line = startline; max_text_width = 0; { // clip to keep text into the frame (thus the new code block) clip_rect_setter set_clip_rect(screen, &text_rect); const int line_spacing = 5; do { // draw the text (with ellipsis if needed) // update the max_text_width for future cleaning int w = font::draw_text(&video, text_rect, def_size, def_color, text[line], text_rect.x, y).w; max_text_width = std::max<int>(max_text_width, w); // since the real drawing on screen is clipped, // we do a dummy one to get the height of the not clipped line. // (each time because special format characters may change it) const int line_height = font::draw_text(nullptr, text_rect, def_size, def_color, text[line], 0,0).h; if(is_new_line) { is_new_line = false; first_line_height = line_height + line_spacing; } line++; if(size_t(line) > text.size()-1) line = 0; y += line_height + line_spacing; } while(y < text_rect.y + text_rect.h); } // performs the actual scrolling offset += scroll_speed; if (offset>=first_line_height) { offset -= first_line_height; is_new_line = true; startline++; if(size_t(startline) == text.size()){ startline = 0; image_count = -1; } } // handle events if (key[SDLK_UP] && scroll_speed < 20) { ++scroll_speed; } if (key[SDLK_DOWN] && scroll_speed > 0) { --scroll_speed; } if (screen->w != screen_rect.w || screen->h != screen_rect.h) { update_dimensions = true; } events::pump(); events::raise_process_event(); events::raise_draw_event(); // flip screen and wait, so the text does not scroll too fast video.flip(); CVideo::delay(20); } while(!close.pressed() && (last_escape || !key[SDLK_ESCAPE])); }
surface getMinimap(int w, int h, const gamemap &map, const team *vw) { const int scale = 8; DBG_DP << "creating minimap " << int(map.w()*scale*0.75) << "," << int(map.h()*scale) << "\n"; const size_t map_width = map.w()*scale*3/4; const size_t map_height = map.h()*scale; if(map_width == 0 || map_height == 0) { return surface(NULL); } surface minimap(create_neutral_surface(map_width, map_height)); if(minimap == NULL) return surface(NULL); typedef mini_terrain_cache_map cache_map; cache_map *normal_cache = &mini_terrain_cache; cache_map *fog_cache = &mini_fogged_terrain_cache; for(int y = 0; y != map.total_height(); ++y) { for(int x = 0; x != map.total_width(); ++x) { surface surf(NULL); const map_location loc(x,y); if(map.on_board(loc)) { const bool shrouded = vw != NULL && vw->shrouded(loc); // shrouded hex are not considered fogged (no need to fog a black image) const bool fogged = vw != NULL && !shrouded && vw->fogged(loc); const t_translation::t_terrain terrain = shrouded ? t_translation::VOID_TERRAIN : map[loc]; bool need_fogging = false; cache_map* cache = fogged ? fog_cache : normal_cache; cache_map::iterator i = cache->find(terrain); if (fogged && i == cache->end()) { // we don't have the fogged version in cache // try the normal cache and ask fogging the image cache = normal_cache; i = cache->find(terrain); need_fogging = true; } if(i == cache->end()) { surface tile(get_image("terrain/" + map.get_terrain_info(terrain).minimap_image() + ".png",image::HEXED)); if(tile == 0) { utils::string_map symbols; symbols["terrain"] = t_translation::write_terrain_code(terrain); const std::string msg = vgettext("Could not get image for terrain: $terrain.", symbols); VALIDATE(false, msg); } //Compose images of base and overlay if neccessary if(map.get_terrain_info(terrain).is_combined()) { surface overlay(get_image("terrain/" + map.get_terrain_info(terrain).minimap_image_overlay() + ".png", image::HEXED)); if(overlay != 0 && overlay != tile) { surface combined = create_compatible_surface(tile, tile->w, tile->h); SDL_Rect r; r.x = 0; r.y = 0; SDL_BlitSurface(tile, NULL, combined, &r); r.x = std::max(0, (tile->w - overlay->w)/2); r.y = std::max(0, (tile->h - overlay->h)/2); if ((overlay->flags & SDL_RLEACCEL) == 0) { blit_surface(overlay, NULL, combined, &r); } else { WRN_DP << map.get_terrain_info(terrain).minimap_image_overlay() << ".png overlay is RLE-encoded, creating a neutral surface\n"; surface overlay_neutral = make_neutral_surface(overlay); blit_surface(overlay_neutral, NULL, combined, &r); } tile = combined; } } surf = surface(scale_surface_blended(tile,scale,scale)); VALIDATE(surf != NULL, _("Error creating or aquiring an image.")); i = normal_cache->insert(cache_map::value_type(terrain,surf)).first; } surf = i->second; if (need_fogging) { surf = surface(adjust_surface_colour(surf,-50,-50,-50)); fog_cache->insert(cache_map::value_type(terrain,surf)); } VALIDATE(surf != NULL, _("Error creating or aquiring an image.")); // we need a balanced shift up and down of the hexes. // if not, only the bottom half-hexes are clipped // and it looks asymmetrical. // also do 1-pixel shift because the scaling // function seems to do it with its rounding SDL_Rect maprect = {x * scale*3/4 - 1, y*scale + scale/4 * (is_odd(x) ? 1 : -1) - 1, 0, 0}; SDL_BlitSurface(surf, NULL, minimap, &maprect); } } } double wratio = w*1.0 / minimap->w; double hratio = h*1.0 / minimap->h; double ratio = std::min<double>(wratio, hratio); minimap = scale_surface(minimap, static_cast<int>(minimap->w * ratio), static_cast<int>(minimap->h * ratio)); DBG_DP << "done generating minimap\n"; return minimap; }