mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-04 11:21:20 +00:00
Fix FR / bug #9999: Preserve aspect ratio of the minimap.
- Try to correct a maximum of little 1-2 pixels imprecisions of the previous system (but those are probably only visible with magnifing tools). - Clean/simplify the related functions TODO: center minimaps in all remaining dialogs (currently only in create_game)
This commit is contained in:
parent
16f52f0e3c
commit
a83efa6dba
109
src/display.cpp
109
src/display.cpp
@ -69,7 +69,8 @@ display::display(CVideo& video, const gamemap& map, const config& theme_cfg, con
|
||||
theme_(theme_cfg,screen_area()),
|
||||
zoom_(DefaultZoom), last_zoom_(SmallZoom),
|
||||
builder_(cfg, level, map, theme_.border().tile_image),
|
||||
minimap_(NULL), redrawMinimap_(false), redraw_background_(true),
|
||||
minimap_(NULL), minimap_location_(empty_rect),
|
||||
redrawMinimap_(false), redraw_background_(true),
|
||||
invalidateAll_(true), grid_(false),
|
||||
diagnostic_label_(0), panelsDrawn_(false),
|
||||
turbo_speed_(2), turbo_(false),
|
||||
@ -322,17 +323,21 @@ int display::get_location_y(const gamemap::location& loc) const
|
||||
|
||||
gamemap::location display::minimap_location_on(int x, int y)
|
||||
{
|
||||
const SDL_Rect rect = minimap_area();
|
||||
//TODO: don't return location for this,
|
||||
// instead directly scroll to the clicked pixel position
|
||||
|
||||
if(x < rect.x || y < rect.y ||
|
||||
x >= rect.x + rect.w || y >= rect.y + rect.h) {
|
||||
if (!point_in_rect(x, y, minimap_location_)) {
|
||||
return gamemap::location();
|
||||
}
|
||||
|
||||
const double xdiv = double(rect.w) / double(map_.w());
|
||||
const double ydiv = double(rect.h) / double(map_.h());
|
||||
// we transfom the coordinates from minimap to the full map image
|
||||
// probably more adjustements to do (border, minimap shift...)
|
||||
// but the mouse and human capacity to evaluate the rectangle center
|
||||
// is not pixel precise.
|
||||
int px = (x - minimap_location_.x) * map_.w()*hex_width() / minimap_location_.w;
|
||||
int py = (y - minimap_location_.y) * map_.h()*hex_size() / minimap_location_.h;
|
||||
|
||||
return gamemap::location(int((x - rect.x)/xdiv),int((y-rect.y)/ydiv));
|
||||
return pixel_position_to_hex(px, py);
|
||||
}
|
||||
|
||||
void display::get_visible_hex_bounds(gamemap::location &topleft, gamemap::location &bottomright) const
|
||||
@ -962,8 +967,7 @@ void display::draw_wrap(bool update,bool force,bool changed)
|
||||
|
||||
if(redrawMinimap_) {
|
||||
redrawMinimap_ = false;
|
||||
const SDL_Rect area = minimap_area();
|
||||
draw_minimap(area.x,area.y,area.w,area.h);
|
||||
draw_minimap();
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@ -1067,19 +1071,6 @@ void display::announce(const std::string message, const SDL_Color& colour)
|
||||
font::CENTER_ALIGN);
|
||||
}
|
||||
|
||||
surface display::get_minimap(int w, int h)
|
||||
{
|
||||
if(minimap_ != NULL && (minimap_->w != w || minimap_->h != h)) {
|
||||
minimap_ = NULL;
|
||||
}
|
||||
|
||||
if(minimap_ == NULL) {
|
||||
minimap_ = image::getMinimap(w, h, map_, viewpoint_);
|
||||
}
|
||||
|
||||
return minimap_;
|
||||
}
|
||||
|
||||
void display::draw_border(const gamemap::location& loc, const int xpos, const int ypos)
|
||||
{
|
||||
/**
|
||||
@ -1172,42 +1163,46 @@ void display::draw_border(const gamemap::location& loc, const int xpos, const in
|
||||
}
|
||||
}
|
||||
|
||||
void display::draw_minimap(int x, int y, int w, int h)
|
||||
void display::draw_minimap()
|
||||
{
|
||||
const surface surf(get_minimap(w,h));
|
||||
if(surf == NULL) {
|
||||
return;
|
||||
const SDL_Rect& area = minimap_area();
|
||||
if(minimap_ == NULL || minimap_->w > area.w || minimap_->h > area.h) {
|
||||
minimap_ = image::getMinimap(area.w, area.h, map_, viewpoint_);
|
||||
}
|
||||
|
||||
SDL_Rect minimap_location = {x,y,w,h};
|
||||
|
||||
clip_rect_setter clip_setter(video().getSurface(),minimap_location);
|
||||
|
||||
SDL_Rect loc = minimap_location;
|
||||
SDL_BlitSurface(surf,NULL,video().getSurface(),&loc);
|
||||
|
||||
int map_w = map_.w(), map_h = map_.h();
|
||||
|
||||
draw_minimap_units(x, y, w, h);
|
||||
|
||||
const double xscaling = double(surf->w) / map_w;
|
||||
const double yscaling = double(surf->h) / map_h;
|
||||
|
||||
const int tile_width = hex_width();
|
||||
|
||||
const int xbox = static_cast<int>(xscaling*(xpos_-tile_width)/tile_width);
|
||||
const int ybox = static_cast<int>(yscaling*(ypos_-zoom_)/zoom_);
|
||||
|
||||
// The magic numbers experimentally determined, like in display::map_area()
|
||||
const int wbox = static_cast<int>(xscaling*(map_area().w+(4.0/3.0)*tile_width)/tile_width - xscaling);
|
||||
const int hbox = static_cast<int>(yscaling*(map_area().h+1.5*zoom_)/zoom_ - yscaling);
|
||||
|
||||
const Uint32 boxcolour = SDL_MapRGB(surf->format,0xFF,0xFF,0xFF);
|
||||
const surface screen(screen_.getSurface());
|
||||
clip_rect_setter clip_setter(screen, area);
|
||||
|
||||
draw_rectangle(x+xbox,y+ybox,wbox,hbox,boxcolour,screen);
|
||||
SDL_Color back_color = {0,0,0,255};
|
||||
draw_centered_on_background(minimap_, area, back_color, screen);
|
||||
|
||||
update_rect(minimap_location);
|
||||
//update the minimap location for mouse and units functions
|
||||
minimap_location_.x = area.x + (area.w - minimap_->w) / 2;
|
||||
minimap_location_.y = area.y + (area.h - minimap_->h) / 2;
|
||||
minimap_location_.w = minimap_->w;
|
||||
minimap_location_.h = minimap_->h;
|
||||
|
||||
draw_minimap_units();
|
||||
|
||||
// calculate the visible portion of the map:
|
||||
// scaling between minimap and full map images
|
||||
double xscaling = 1.0*minimap_->w / (map_.w()*hex_width());
|
||||
double yscaling = 1.0*minimap_->h / (map_.h()*hex_size());
|
||||
|
||||
// we need to shift with the border size
|
||||
// and the 0.25 from the minimap balanced drawing
|
||||
double border = theme_.border().size;
|
||||
|
||||
int view_x = static_cast<int>((xpos_ - border*hex_width()) * xscaling);
|
||||
int view_y = static_cast<int>((ypos_ - (border+0.25)*hex_size()) * yscaling);
|
||||
int view_w = static_cast<int>(map_outside_area().w * xscaling);
|
||||
int view_h = static_cast<int>(map_outside_area().h * yscaling);
|
||||
|
||||
const Uint32 box_color = SDL_MapRGB(minimap_->format,0xFF,0xFF,0xFF);
|
||||
draw_rectangle(minimap_location_.x + view_x - 1,
|
||||
minimap_location_.y + view_y - 1,
|
||||
view_w + 2, view_h + 2,
|
||||
box_color, screen);
|
||||
}
|
||||
|
||||
void display::scroll(int xmove, int ymove)
|
||||
@ -1574,16 +1569,6 @@ void display::draw_image_for_report(surface& img, SDL_Rect& rect)
|
||||
}
|
||||
}
|
||||
|
||||
void display::recalculate_minimap()
|
||||
{
|
||||
if(minimap_ != NULL) {
|
||||
minimap_.assign(NULL);
|
||||
}
|
||||
|
||||
redraw_minimap();
|
||||
// Remove unit after invalidating...
|
||||
}
|
||||
|
||||
void display:: set_report_content(const reports::TYPE which_report, const std::string &content) {
|
||||
report_[which_report] = content;
|
||||
}
|
||||
|
@ -179,9 +179,7 @@ public:
|
||||
|
||||
// Will be overridden in the display subclass
|
||||
virtual void invalidate(const gamemap::location& loc) {invalidated_.insert(loc);};
|
||||
virtual void draw_minimap_units(int /* x */, int /* y */, int /* w */, int /* h */) {};
|
||||
// this surface must be freed by the caller
|
||||
surface get_minimap(int w, int h);
|
||||
virtual void draw_minimap_units() {};
|
||||
|
||||
const gamemap& get_map()const { return map_;}
|
||||
|
||||
@ -325,7 +323,7 @@ public:
|
||||
|
||||
//! Schedule the minimap for recalculation.
|
||||
//! Useful if any terrain in the map has changed.
|
||||
void recalculate_minimap();
|
||||
void recalculate_minimap() {minimap_ = NULL; redrawMinimap_ = true; };
|
||||
|
||||
//! Schedule the minimap to be redrawn.
|
||||
//! Useful if units have moved about on the map.
|
||||
@ -354,7 +352,7 @@ protected:
|
||||
virtual void draw_border(const gamemap::location& loc,
|
||||
const int xpos, const int ypos);
|
||||
|
||||
void draw_minimap(int x, int y, int w, int h);
|
||||
void draw_minimap();
|
||||
|
||||
virtual void zoom_redraw_hook() {};
|
||||
|
||||
@ -378,6 +376,7 @@ protected:
|
||||
int last_zoom_;
|
||||
terrain_builder builder_;
|
||||
surface minimap_;
|
||||
SDL_Rect minimap_location_;
|
||||
bool redrawMinimap_;
|
||||
bool redraw_background_;
|
||||
bool invalidateAll_;
|
||||
|
@ -529,8 +529,11 @@ void game_display::draw_sidebar()
|
||||
}
|
||||
}
|
||||
|
||||
void game_display::draw_minimap_units(int x, int y, int w, int h)
|
||||
void game_display::draw_minimap_units()
|
||||
{
|
||||
double xscaling = 1.0 * minimap_location_.w / map_.w();
|
||||
double yscaling = 1.0 * minimap_location_.h / map_.h();
|
||||
|
||||
for(unit_map::const_iterator u = units_.begin(); u != units_.end(); ++u) {
|
||||
if(fogged(u->first) ||
|
||||
(teams_[currentTeam_].is_enemy(u->second.side()) &&
|
||||
@ -541,10 +544,18 @@ void game_display::draw_minimap_units(int x, int y, int w, int h)
|
||||
const int side = u->second.side();
|
||||
const SDL_Color col = team::get_minimap_colour(side);
|
||||
const Uint32 mapped_col = SDL_MapRGB(video().getSurface()->format,col.r,col.g,col.b);
|
||||
SDL_Rect rect = { x + (u->first.x * w) / map_.w(),
|
||||
y + (u->first.y * h + (is_odd(u->first.x) ? h / 2 : 0)) / map_.h(),
|
||||
w / map_.w(), h / map_.h() };
|
||||
SDL_FillRect(video().getSurface(),&rect,mapped_col);
|
||||
|
||||
double u_x = u->first.x * xscaling;
|
||||
double u_y = (u->first.y + (is_odd(u->first.x) ? 1 : -1)/4.0) * yscaling;
|
||||
// use 4/3 to compensate the horizontal hexes imbrication
|
||||
double u_w = 4.0 / 3.0 * xscaling;
|
||||
double u_h = yscaling;
|
||||
|
||||
SDL_Rect r = { minimap_location_.x + round_double(u_x),
|
||||
minimap_location_.y + round_double(u_y),
|
||||
round_double(u_w), round_double(u_h) };
|
||||
|
||||
SDL_FillRect(video().getSurface(), &r, mapped_col);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ private:
|
||||
//! Function to invalidate animated terrains which may have changed.
|
||||
void invalidate_animations();
|
||||
|
||||
virtual void draw_minimap_units(int x, int y, int w, int h);
|
||||
virtual void draw_minimap_units();
|
||||
|
||||
public:
|
||||
//! Temporarily place a unit on map (moving: can overlap others).
|
||||
|
@ -98,34 +98,26 @@ surface getMinimap(int w, int h, const gamemap& map, const viewpoint* vw)
|
||||
|
||||
wassert(surf != NULL);
|
||||
|
||||
SDL_Rect maprect = {x*scale*3/4,y*scale + (is_odd(x) ? scale/2 : 0),0,0};
|
||||
// we need a balanced shift up and down of the hexes.
|
||||
// if not, only the bottom half-hexes are clipped
|
||||
// and it looks asymetrical.
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((minimap->w != w || minimap->h != h) && w != 0 && h != 0) {
|
||||
const surface surf(minimap);
|
||||
|
||||
#if 0
|
||||
// preserve the aspect ratio of the original map rather than
|
||||
// distorting it to fit the minimap window.
|
||||
//
|
||||
// This needs more work. There are at least two issues:
|
||||
// (1) the part of the minimap window outside the scaled map
|
||||
// needs to be blacked out/invalidated.
|
||||
// (2) the rather nasty code in draw_minimap_units needs to
|
||||
// change.
|
||||
float sw = 1.0, sh = 1.0;
|
||||
|
||||
if (minimap->h < minimap->w) sh = (minimap->h*1.0)/minimap->w;
|
||||
if (minimap->w < minimap->h) sw = (minimap->w*1.0)/minimap->h;
|
||||
w = int(w * sw);
|
||||
h = int(h * sh);
|
||||
#endif
|
||||
|
||||
minimap = surface(scale_surface(surf,w,h));
|
||||
}
|
||||
double wratio = w*1.0 / minimap->w;
|
||||
double hratio = h*1.0 / minimap->h;
|
||||
double ratio = minimum<double>(wratio, hratio);
|
||||
|
||||
minimap = scale_surface(minimap,
|
||||
static_cast<int>(minimap->w * ratio), static_cast<int>(minimap->h * ratio));
|
||||
|
||||
LOG_DP << "done generating minimap\n";
|
||||
|
||||
|
@ -486,11 +486,8 @@ void create::process_event()
|
||||
#ifndef USE_TINY_GUI
|
||||
if(map.get() != NULL) {
|
||||
const surface mini(image::getMinimap(minimap_rect_.w,minimap_rect_.h,*map,0));
|
||||
if(mini != NULL) {
|
||||
SDL_Rect rect = minimap_rect_;
|
||||
SDL_BlitSurface(mini, NULL, video().getSurface(), &rect);
|
||||
update_rect(rect);
|
||||
}
|
||||
SDL_Color back_color = {0,0,0,255};
|
||||
draw_centered_on_background(mini, minimap_rect_, back_color, video().getSurface());
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -619,11 +616,8 @@ void create::hide_children(bool hide)
|
||||
|
||||
#ifndef USE_TINY_GUI
|
||||
const surface mini(image::getMinimap(minimap_rect_.w,minimap_rect_.h,map,0));
|
||||
if(mini != NULL) {
|
||||
SDL_Rect rect = minimap_rect_;
|
||||
SDL_BlitSurface(mini, NULL, video().getSurface(), &rect);
|
||||
update_rect(rect);
|
||||
}
|
||||
SDL_Color back_color = {0,0,0,255};
|
||||
draw_centered_on_background(mini, minimap_rect_, back_color, video().getSurface());
|
||||
#endif
|
||||
} catch(gamemap::incorrect_format_exception& e) {
|
||||
LOG_STREAM(err,general) << "map could not be loaded: " << e.msg_ << "\n";
|
||||
|
@ -1343,3 +1343,20 @@ void draw_solid_tinted_rectangle(int x, int y, int w, int h,
|
||||
SDL_Rect rect = {x,y,w,h};
|
||||
fill_rect_alpha(rect,SDL_MapRGB(target->format,r,g,b),Uint8(alpha*255),target);
|
||||
}
|
||||
|
||||
void draw_centered_on_background(surface surf, const SDL_Rect& rect, const SDL_Color& color, surface target)
|
||||
{
|
||||
clip_rect_setter clip_setter(target, rect);
|
||||
|
||||
Uint32 col = SDL_MapRGBA(target->format, color.r, color.g, color.b, color.unused);
|
||||
//TODO: only draw background outside the image
|
||||
SDL_Rect r = rect;
|
||||
SDL_FillRect(target, &r, col);
|
||||
|
||||
if (surf != NULL) {
|
||||
r.x = rect.x + (rect.w-surf->w)/2;
|
||||
r.y = rect.y + (rect.h-surf->h)/2;
|
||||
SDL_BlitSurface(surf, NULL, target, &r);
|
||||
}
|
||||
update_rect(rect);
|
||||
}
|
||||
|
@ -248,4 +248,10 @@ void draw_rectangle(int x, int y, int w, int h, Uint32 colour, surface tg);
|
||||
void draw_solid_tinted_rectangle(int x, int y, int w, int h,
|
||||
int r, int g, int b,
|
||||
double alpha, surface target);
|
||||
|
||||
// blit the image on the center of the rectangle
|
||||
// and a add a colored background
|
||||
void draw_centered_on_background(surface surf, const SDL_Rect& rect,
|
||||
const SDL_Color& color, surface target);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user