1 // Copyright (C) 2006, 2007 Ulf Lorenz
2 // Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
3 // Copyright (C) 2007 Ole Laursen
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Library General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #include "gui/image-helpers.h"
25 #include "overviewmap.h"
26 #include "stacklist.h"
29 #include "templelist.h"
33 #include "playerlist.h"
36 #include "GraphicsCache.h"
38 #include "GameScenarioOptions.h"
40 OverviewMap::OverviewMap()
45 OverviewMap::~OverviewMap()
49 bool OverviewMap::isShadowed(guint32 type, int i, int j)
51 GameMap *gm = GameMap::getInstance();
52 int x = int(i / pixels_per_tile);
53 int y = int(j / pixels_per_tile);
60 //if the tile above us or beside us is land then this might be a shadow pixel
62 if (gm->getTile(x,y)->getType() != type)
64 if (x > 0 && gm->getTile(x-1,y)->getType() != type)
66 x2 = int((i-1) / pixels_per_tile);
67 y2 = int(j / pixels_per_tile);
68 if (gm->getTile(x-1,y) == gm->getTile(x2,y2))
71 if (y > 0 && gm->getTile(x,y-1)->getType() != type)
73 x2 = int(i / pixels_per_tile);
74 y2 = int((j-1) / pixels_per_tile);
75 if (gm->getTile(x,y-1) == gm->getTile(x2,y2))
78 if (y > 0 && x > 0 && gm->getTile(x-1,y-1)->getType() != type)
80 x2 = int((i-1) / pixels_per_tile);
81 y2 = int((j-1) / pixels_per_tile);
82 if (gm->getTile(x-1,y-1) == gm->getTile(x2,y2))
98 return (i + 1) ^ (j + 1);
99 //return i + j + (i*j) + (i*100) + (j*43) / 43;
105 float f = i / 43 * j / 43;
107 return (int) roundf(f) | (i + i + j);
111 void OverviewMap::choose_surface(bool front, Glib::RefPtr<Gdk::Pixmap> &surf,
112 Glib::RefPtr<Gdk::GC> &gc)
121 gc = static_surface_gc;
122 surf = static_surface;
126 OverviewMap::draw_pixel(Glib::RefPtr<Gdk::Pixmap> surf, Glib::RefPtr<Gdk::GC> gc, int x, int y, Gdk::Color color)
128 gc->set_rgb_fg_color(color);
129 surf->draw_point(gc, x, y);
134 OverviewMap::draw_filled_rect(int x, int y, int width, int height, Gdk::Color color)
136 draw_filled_rect(true, x, y, width, height, color);
140 OverviewMap::draw_filled_rect(bool front, int x, int y, int width, int height, Gdk::Color color)
142 Glib::RefPtr<Gdk::Pixmap> surf;
143 Glib::RefPtr<Gdk::GC> gc;
144 choose_surface (front, surf, gc);
145 gc->set_rgb_fg_color(color);
146 surf->draw_rectangle(gc, true, x, y, width, height);
150 OverviewMap::draw_line(int src_x, int src_y, int dst_x, int dst_y, Gdk::Color color)
152 draw_line(true, src_x, src_y, dst_x, dst_y, color);
156 OverviewMap::draw_line(bool front, int src_x, int src_y, int dst_x, int dst_y, Gdk::Color color)
158 Glib::RefPtr<Gdk::Pixmap> surf;
159 Glib::RefPtr<Gdk::GC> gc;
160 choose_surface (front, surf, gc);
161 gc->set_rgb_fg_color(color);
162 surf->draw_line(gc, src_x, src_y, dst_x, dst_y);
166 OverviewMap::draw_rect(int x, int y, int width, int height, Gdk::Color color)
168 draw_rect (true, x, y, width, height, color);
172 OverviewMap::draw_rect(bool front, int x, int y, int width, int height, Gdk::Color color)
174 Glib::RefPtr<Gdk::Pixmap> surf;
175 Glib::RefPtr<Gdk::GC> gc;
176 choose_surface (front, surf, gc);
177 gc->set_rgb_fg_color(color);
178 surf->draw_rectangle(gc, false, x, y, width, height);
181 void OverviewMap::draw_terrain_tile(Glib::RefPtr<Gdk::Pixmap> surf,
182 Glib::RefPtr<Gdk::GC> gc,
183 SmallTile::Pattern pattern,
187 int i, int j, bool shadowed)
192 case SmallTile::SOLID:
193 draw_pixel(surf, gc, i, j, first);
195 case SmallTile::STIPPLED:
198 draw_pixel(surf, gc, i, j, first);
200 draw_pixel(surf, gc, i, j, second);
203 case SmallTile::RANDOMIZED:
205 int num = prand(i, j) % 3;
207 draw_pixel(surf, gc, i, j, first);
209 draw_pixel(surf, gc, i, j, second);
211 draw_pixel(surf, gc, i, j, third);
214 case SmallTile::DIAGONAL:
216 int num = drand(i, j) % 3;
218 draw_pixel(surf, gc, i, j, first);
220 draw_pixel(surf, gc, i, j, second);
222 draw_pixel(surf, gc, i, j, third);
225 case SmallTile::CROSSHATCH:
227 int num = crand(i, j) % 3;
229 draw_pixel(surf, gc, i, j, first);
231 draw_pixel(surf, gc , i, j, second);
233 draw_pixel(surf, gc, i, j, third);
236 case SmallTile::SUNKEN:
237 if (shadowed == false)
238 draw_pixel(surf, gc, i, j, first);
241 draw_pixel(surf, gc, i, j, second);
244 case SmallTile::SUNKEN_STRIPED:
245 if (shadowed == false)
248 draw_pixel(surf, gc, i, j, first);
250 draw_pixel(surf, gc, i, j, third);
254 draw_pixel(surf, gc, i, j, second);
257 case SmallTile::TABLECLOTH:
259 if (i % 4 == 0 && j % 4 == 0)
260 draw_pixel(surf, gc, i, j, first);
261 else if (i % 4 == 0 && j % 4 == 1)
262 draw_pixel(surf, gc, i, j, second);
263 else if (i % 4 == 0 && j % 4 == 2)
264 draw_pixel(surf, gc, i, j, first);
265 else if (i % 4 == 0 && j % 4 == 3)
266 draw_pixel(surf, gc, i, j, second);
267 else if (i % 4 == 1 && j % 4 == 0)
268 draw_pixel(surf, gc, i, j, second);
269 else if (i % 4 == 1 && j % 4 == 1)
270 draw_pixel(surf, gc, i, j, third);
271 else if (i % 4 == 1 && j % 4 == 2)
272 draw_pixel(surf, gc, i, j, second);
273 else if (i % 4 == 1 && j % 4 == 3)
274 draw_pixel(surf, gc, i, j, third);
275 else if (i % 4 == 2 && j % 4 == 0)
276 draw_pixel(surf, gc, i, j, first);
277 else if (i % 4 == 2 && j % 4 == 1)
278 draw_pixel(surf, gc, i, j, second);
279 else if (i % 4 == 2 && j % 4 == 2)
280 draw_pixel(surf, gc, i, j, first);
281 else if (i % 4 == 2 && j % 4 == 3)
282 draw_pixel(surf, gc, i, j, second);
283 else if (i % 4 == 3 && j % 4 == 0)
284 draw_pixel(surf, gc, i, j, second);
285 else if (i % 4 == 3 && j % 4 == 1)
286 draw_pixel(surf, gc, i, j, third);
287 else if (i % 4 == 3 && j % 4 == 2)
288 draw_pixel(surf, gc, i, j, second);
289 else if (i % 4 == 3 && j % 4 == 3)
290 draw_pixel(surf, gc, i, j, third);
296 void OverviewMap::draw_terrain_tile(Maptile *t, int i, int j)
298 bool shadowed = isShadowed(t->getType(), i, j);
299 draw_terrain_tile (static_surface, static_surface_gc, t->getPattern(),
306 int OverviewMap::calculateResizeFactor()
308 if (GameMap::getWidth() <= (int)MAP_SIZE_TINY_WIDTH &&
309 GameMap::getHeight() <= (int)MAP_SIZE_TINY_HEIGHT)
311 else if (GameMap::getWidth() <= (int)MAP_SIZE_SMALL_WIDTH &&
312 GameMap::getHeight() <= (int)MAP_SIZE_SMALL_HEIGHT)
318 void OverviewMap::resize()
320 int factor = calculateResizeFactor();
321 resize(GameMap::get_dim() * factor);
324 void OverviewMap::resize(Vector<int> max_dimensions)
328 // calculate the width and height relations between pixels and maptiles
329 Vector<int> bigmap_dim = GameMap::get_dim();
332 // first try scaling to horizontal size
333 pixels_per_tile = max_dimensions.x / double(bigmap_dim.x);
334 d.x = max_dimensions.x;
335 d.y = int(round(bigmap_dim.y * pixels_per_tile));
337 if (d.y > max_dimensions.y)
339 // if too big, scale to vertical
340 pixels_per_tile = max_dimensions.y / double(bigmap_dim.y);
341 d.x = int(round(bigmap_dim.x * pixels_per_tile));
342 d.y = max_dimensions.y;
346 static_surface = Gdk::Pixmap::create(Glib::RefPtr<Gdk::Drawable>(0), d.x, d.y, 24);
347 static_surface_gc = Gdk::GC::create(static_surface);
349 draw_terrain_tiles(Rectangle(0, 0, d.x, d.y));
350 surface = Gdk::Pixmap::create(static_surface, d.x, d.y, 24);
351 surface_gc = Gdk::GC::create(surface);
355 void OverviewMap::redraw_tiles(Rectangle tiles)
357 if (tiles.w > 0 && tiles.h > 0)
359 tiles.pos -= Vector<int>(1, 1);
360 tiles.dim += Vector<int>(2, 2);
362 // translate to pixel coordinates
363 Vector<int> pos(int(round(tiles.x * pixels_per_tile)),
364 int(round(tiles.y * pixels_per_tile)));
365 Vector<int> dim(int(round(tiles.w * pixels_per_tile)),
366 int(round(tiles.h * pixels_per_tile)));
370 static_surface->get_size(width, height);
371 // ensure we're within bounds
372 pos = clip(Vector<int>(0, 0), pos,
373 Vector<int>(width, height) - Vector<int>(1, 1));
375 if (pos.x + dim.x >= int(GameMap::getWidth() * pixels_per_tile))
376 dim.x = int(GameMap::getWidth() * pixels_per_tile) - pos.x;
378 if (pos.y + dim.y >= int(GameMap::getHeight() * pixels_per_tile))
379 dim.y = int(GameMap::getHeight() * pixels_per_tile) - pos.y;
381 draw_terrain_tiles(Rectangle(pos, dim));
383 draw(Playerlist::getViewingplayer());
386 void OverviewMap::draw_terrain_tiles(Rectangle r)
388 GameMap *gm = GameMap::getInstance();
389 unsigned int oldrand = rand();
391 Gdk::Color rd = GameMap::getInstance()->getTileset()->getRoadColor();
392 for (int i = r.x; i < r.x + r.w; ++i)
393 for (int j = r.y; j < r.y + r.h; ++j)
395 int x = int(i / pixels_per_tile);
396 int y = int(j / pixels_per_tile);
398 if (gm->getTile(x,y)->getBuilding() == Maptile::ROAD ||
399 gm->getTile(x,y)->getBuilding() == Maptile::BRIDGE)
400 draw_pixel(static_surface, static_surface_gc, i, j, rd);
403 draw_terrain_tile (GameMap::getInstance()->getTile(x,y), i, j);
409 void OverviewMap::after_draw()
413 void OverviewMap::draw(Player *player)
415 Playerlist::getInstance()->setViewingplayer(player);
416 int size = int(pixels_per_tile) > 1 ? int(pixels_per_tile) : 1;
420 // During the whole drawing stuff, ALWAYS consider that
421 // there is an offset of 1 between map coordinates and coordinates
422 // of the surface when drawing. I will implcitely assume this during this
425 //Gdk::Color black = Gdk::Color();
426 //black.set_rgb_p(0,0,0);
427 //surface_gc->set_rgb_fg_color(black);
428 //surface->draw_rectangle(surface_gc, true, 0, 0, -1, -1);
429 //Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(static_surface, 0, 0, -1, -1);
430 surface->draw_drawable(surface_gc, static_surface, 0, 0, 0, 0, -1, -1);
432 // Draw ruins as a white dot
434 Gdk::Color ruindotcolor = Gdk::Color();
435 ruindotcolor.set_rgb_p(100,100,100);
436 for (Ruinlist::iterator it = Ruinlist::getInstance()->begin();
437 it != Ruinlist::getInstance()->end(); it++)
440 if (r->isHidden() == true &&
441 r->getOwner() != Playerlist::getViewingplayer())
443 if (r->isVisible(Playerlist::getViewingplayer()) == false)
445 Vector<int> pos = r->getPos();
446 pos = mapToSurface(pos);
448 draw_filled_rect(true, pos.x, pos.y, size, size, ruindotcolor);
451 // Draw temples as a white dot
452 Gdk::Color templedotcolor = Gdk::Color();
453 templedotcolor.set_rgb_p(100,100,100);
454 for (Templelist::iterator it = Templelist::getInstance()->begin();
455 it != Templelist::getInstance()->end(); it++)
458 if (t->isVisible(Playerlist::getViewingplayer()) == false)
460 Vector<int> pos = t->getPos();
461 pos = mapToSurface(pos);
463 draw_filled_rect(true, pos.x, pos.y, size, size, templedotcolor);
467 Gdk::Color fog_color = Gdk::Color();
468 fog_color.set_rgb_p(0,0,0);
469 for (int i = 0; i < GameMap::getWidth(); i++)
470 for (int j = 0; j < GameMap::getHeight(); j++)
475 if (Playerlist::getViewingplayer()->getFogMap()->isFogged(pos) == true)
477 pos = mapToSurface(pos);
478 draw_filled_rect(true, pos.x, pos.y, size, size, fog_color);
482 //the idea here is that we want to show what happens when an AI-owned
483 //stack moves through our area. so we block the view of computer
484 //players after the fact.
485 if (Playerlist::getViewingplayer()->getType() != Player::HUMAN &&
486 GameScenarioOptions::s_hidden_map == true)
490 surface->get_size(width, height);
491 draw_filled_rect(true, 0, 0, width, height, fog_color);
496 Gdk::Color fog_color = Gdk::Color();
497 fog_color.set_rgb_p(0.0,0.0,0.0);
500 surface->get_size(width, height);
501 surface_gc->set_rgb_fg_color(fog_color);
502 surface->draw_rectangle(surface_gc, true, 0,0,width, height);
504 // let derived classes do their job
509 Glib::RefPtr<Gdk::Pixmap> OverviewMap::get_surface()
514 Vector<int> OverviewMap::mapFromScreen(Vector<int> pos)
516 int x = int(pos.x / pixels_per_tile);
517 int y = int(pos.y / pixels_per_tile);
519 if (x >= GameMap::getWidth())
520 x = GameMap::getWidth() - 1;
522 if (y >= GameMap::getHeight())
523 y = GameMap::getHeight() - 1;
525 return Vector<int>(x,y);
528 Vector<int> OverviewMap::mapToSurface(Vector<int> pos)
530 if (pos.x < 0 || pos.y < 0
531 || pos.x >= GameMap::getWidth() || pos.y >= GameMap::getHeight())
533 printf ("pos.x is %d, pos.y is %d\n", pos.x, pos.y);
534 printf ("width is %d, height is %d\n", GameMap::getWidth(),
535 GameMap::getHeight());
537 assert(pos.x >= 0 && pos.y >= 0
538 && pos.x < GameMap::getWidth() && pos.y < GameMap::getHeight());
540 int x = int(round(pos.x * pixels_per_tile));
541 int y = int(round(pos.y * pixels_per_tile));
543 if (pixels_per_tile > 2)
544 // try to take the center position of the pixel
545 x += int(0.5 * pixels_per_tile);
547 if (pixels_per_tile > 2)
548 y += int(0.5 * pixels_per_tile);
550 return Vector<int>(x, y);
553 void OverviewMap::draw_cities (bool all_razed)
555 GraphicsCache *gc = GraphicsCache::getInstance();
557 // Draw all cities as shields over the city location, in the colors of
559 for (Citylist::iterator it = Citylist::getInstance()->begin();
560 it != Citylist::getInstance()->end(); it++)
564 if (c->isVisible(Playerlist::getViewingplayer()) == false)
566 if (c->isBurnt() == true || all_razed == true)
567 tmp = gc->getSmallRuinedCityPic();
569 tmp = gc->getShieldPic(0, c->getOwner());
571 Vector<int> pos = c->getPos();
572 pos = mapToSurface(pos);
573 tmp->blit_centered(surface, pos);
578 void OverviewMap::blank(bool on)
581 draw(Playerlist::getViewingplayer());