map.cpp

Go to the documentation of this file.
00001 /* $Id: map.cpp 11961 2008-01-23 17:08:35Z belugas $ */
00002 
00005 #include "stdafx.h"
00006 #include "debug.h"
00007 #include "direction_func.h"
00008 #include "core/bitmath_func.hpp"
00009 #include "core/alloc_func.hpp"
00010 #include "core/math_func.hpp"
00011 #include "map_func.h"
00012 
00013 #if defined(_MSC_VER) && _MSC_VER >= 1400 /* VStudio 2005 is stupid! */
00014 /* Why the hell is that not in all MSVC headers?? */
00015 extern "C" _CRTIMP void __cdecl _assert(void *, void *, unsigned);
00016 #endif
00017 
00018 uint _map_log_x;     
00019 uint _map_log_y;     
00020 uint _map_size_x;    
00021 uint _map_size_y;    
00022 uint _map_size;      
00023 uint _map_tile_mask; 
00024 
00025 Tile *_m = NULL;          
00026 TileExtended *_me = NULL; 
00027 
00028 
00034 void AllocateMap(uint size_x, uint size_y)
00035 {
00036   /* Make sure that the map size is within the limits and that
00037    * the x axis size is a power of 2. */
00038   if (size_x < 64 || size_x > 2048 ||
00039       size_y < 64 || size_y > 2048 ||
00040       (size_x & (size_x - 1)) != 0 ||
00041       (size_y & (size_y - 1)) != 0)
00042     error("Invalid map size");
00043 
00044   DEBUG(map, 1, "Allocating map of size %dx%d", size_x, size_y);
00045 
00046   _map_log_x = FindFirstBit(size_x);
00047   _map_log_y = FindFirstBit(size_y);
00048   _map_size_x = size_x;
00049   _map_size_y = size_y;
00050   _map_size = size_x * size_y;
00051   _map_tile_mask = _map_size - 1;
00052 
00053   free(_m);
00054   free(_me);
00055 
00056   /* XXX @todo handle memory shortage more gracefully
00057    * CallocT does the out-of-memory check
00058    * Maybe some attemps could be made to try with smaller maps down to 64x64
00059    * Maybe check for available memory before doing the calls, after all, we know how big
00060    * the map is */
00061   _m = CallocT<Tile>(_map_size);
00062   _me = CallocT<TileExtended>(_map_size);
00063 }
00064 
00065 
00066 #ifdef _DEBUG
00067 TileIndex TileAdd(TileIndex tile, TileIndexDiff add,
00068   const char *exp, const char *file, int line)
00069 {
00070   int dx;
00071   int dy;
00072   uint x;
00073   uint y;
00074 
00075   dx = add & MapMaxX();
00076   if (dx >= (int)MapSizeX() / 2) dx -= MapSizeX();
00077   dy = (add - dx) / (int)MapSizeX();
00078 
00079   x = TileX(tile) + dx;
00080   y = TileY(tile) + dy;
00081 
00082   if (x >= MapSizeX() || y >= MapSizeY()) {
00083     char buf[512];
00084 
00085     snprintf(buf, lengthof(buf), "TILE_ADD(%s) when adding 0x%.4X and 0x%.4X failed",
00086       exp, tile, add);
00087 #if !defined(_MSC_VER) || defined(WINCE)
00088     fprintf(stderr, "%s:%d %s\n", file, line, buf);
00089 #else
00090     _assert(buf, (char*)file, line);
00091 #endif
00092   }
00093 
00094   assert(TileXY(x, y) == TILE_MASK(tile + add));
00095 
00096   return TileXY(x, y);
00097 }
00098 #endif
00099 
00106 uint ScaleByMapSize(uint n)
00107 {
00108   /* First shift by 12 to prevent integer overflow for large values of n.
00109    * >>12 is safe since the min mapsize is 64x64
00110    * Add (1<<4)-1 to round upwards. */
00111   return (n * (MapSize() >> 12) + (1 << 4) - 1) >> 4;
00112 }
00113 
00114 
00121 uint ScaleByMapSize1D(uint n)
00122 {
00123   /* Normal circumference for the X+Y is 256+256 = 1<<9
00124    * Note, not actually taking the full circumference into account,
00125    * just half of it.
00126    * (1<<9) - 1 is there to scale upwards. */
00127   return (n * (MapSizeX() + MapSizeY()) + (1 << 9) - 1) >> 9;
00128 }
00129 
00130 
00144 TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
00145 {
00146   uint x = TileX(tile) + addx;
00147   uint y = TileY(tile) + addy;
00148 
00149   /* Are we about to wrap? */
00150   if (x < MapMaxX() && y < MapMaxY())
00151     return tile + TileDiffXY(addx, addy);
00152 
00153   return INVALID_TILE;
00154 }
00155 
00157 extern const TileIndexDiffC _tileoffs_by_diagdir[] = {
00158   {-1,  0}, 
00159   { 0,  1}, 
00160   { 1,  0}, 
00161   { 0, -1}  
00162 };
00163 
00165 extern const TileIndexDiffC _tileoffs_by_dir[] = {
00166   {-1, -1}, 
00167   {-1,  0}, 
00168   {-1,  1}, 
00169   { 0,  1}, 
00170   { 1,  1}, 
00171   { 1,  0}, 
00172   { 1, -1}, 
00173   { 0, -1}  
00174 };
00175 
00185 uint DistanceManhattan(TileIndex t0, TileIndex t1)
00186 {
00187   const uint dx = Delta(TileX(t0), TileX(t1));
00188   const uint dy = Delta(TileY(t0), TileY(t1));
00189   return dx + dy;
00190 }
00191 
00192 
00202 uint DistanceSquare(TileIndex t0, TileIndex t1)
00203 {
00204   const int dx = TileX(t0) - TileX(t1);
00205   const int dy = TileY(t0) - TileY(t1);
00206   return dx * dx + dy * dy;
00207 }
00208 
00209 
00217 uint DistanceMax(TileIndex t0, TileIndex t1)
00218 {
00219   const uint dx = Delta(TileX(t0), TileX(t1));
00220   const uint dy = Delta(TileY(t0), TileY(t1));
00221   return max(dx, dy);
00222 }
00223 
00224 
00233 uint DistanceMaxPlusManhattan(TileIndex t0, TileIndex t1)
00234 {
00235   const uint dx = Delta(TileX(t0), TileX(t1));
00236   const uint dy = Delta(TileY(t0), TileY(t1));
00237   return dx > dy ? 2 * dx + dy : 2 * dy + dx;
00238 }
00239 
00245 uint DistanceFromEdge(TileIndex tile)
00246 {
00247   const uint xl = TileX(tile);
00248   const uint yl = TileY(tile);
00249   const uint xh = MapSizeX() - 1 - xl;
00250   const uint yh = MapSizeY() - 1 - yl;
00251   const uint minl = min(xl, yl);
00252   const uint minh = min(xh, yh);
00253   return min(minl, minh);
00254 }
00255 
00269 bool CircularTileSearch(TileIndex tile, uint size, TestTileOnSearchProc proc, uint32 data)
00270 {
00271   uint n, x, y;
00272   DiagDirection dir;
00273 
00274   assert(proc != NULL);
00275   assert(size > 0);
00276 
00277   x = TileX(tile);
00278   y = TileY(tile);
00279 
00280   if (size % 2 == 1) {
00281     /* If the length of the side is uneven, the center has to be checked
00282      * separately, as the pattern of uneven sides requires to go around the center */
00283     n = 2;
00284     if (proc(TileXY(x, y), data)) return true;
00285 
00286     /* If tile test is not successful, get one tile down and left,
00287      * ready for a test in first circle around center tile */
00288     x += _tileoffs_by_dir[DIR_W].x;
00289     y += _tileoffs_by_dir[DIR_W].y;
00290   } else {
00291     n = 1;
00292     /* To use _tileoffs_by_diagdir's order, we must relocate to
00293      * another tile, as we now first go 'up', 'right', 'down', 'left'
00294      * instead of 'right', 'down', 'left', 'up', which the calling
00295      * function assume. */
00296     x++;
00297   }
00298 
00299   for (; n < size; n += 2) {
00300     for (dir = DIAGDIR_NE; dir < DIAGDIR_END; dir++) {
00301       uint j;
00302       for (j = n; j != 0; j--) {
00303         if (x <= MapMaxX() && y <= MapMaxY() && 
00304             proc(TileXY(x, y), data)) {     
00305           return true;                        
00306         }
00307 
00308         /* Step to the next 'neighbour' in the circular line */
00309         x += _tileoffs_by_diagdir[dir].x;
00310         y += _tileoffs_by_diagdir[dir].y;
00311       }
00312     }
00313     /* Jump to next circle to test */
00314     x += _tileoffs_by_dir[DIR_W].x;
00315     y += _tileoffs_by_dir[DIR_W].y;
00316   }
00317   return false;
00318 }

Generated on Wed Oct 1 17:03:21 2008 for openttd by  doxygen 1.5.6