Changeset - r21756:3aa58b81dfa9
[Not reviewed]
master
0 2 0
rubidium - 10 years ago 2014-09-21 17:27:37
rubidium@openttd.org
(svn r26899) -Codechange: reduce the amount of tiles that needs to be drawn by taking the height of tiles into account instead of drawing way too many (ic111)
2 files changed with 506 insertions and 67 deletions:
0 comments (0 inline, 0 general)
src/viewport.cpp
Show inline comments
 
@@ -26,6 +26,48 @@
 
 * \endverbatim
 
 */
 

	
 
/**
 
 * @defgroup vp_column_row Rows and columns in the viewport
 
 *
 
 * Columns are vertical sections of the viewport that are half a tile wide.
 
 * The origin, i.e. column 0, is through the northern and southern most tile.
 
 * This means that the column of e.g. Tile(0, 0) and Tile(100, 100) are in
 
 * column number 0. The negative columns are towards the left of the screen,
 
 * or towards the west, whereas the positive ones are towards respectively
 
 * the right and east.
 
 * With half a tile wide is meant that the next column of tiles directly west
 
 * or east of the centre line are respectively column -1 and 1. Their tile
 
 * centers are only half a tile from the center of their adjoining tile when
 
 * looking only at the X-coordinate.
 
 *
 
 * \verbatim
 
 *        ╳        *
 
 *       ╱ ╲       *
 
 *      ╳ 0 ╳      *
 
 *     ╱ ╲ ╱ ╲     *
 
 *    ╳-1 ╳ 1 ╳    *
 
 *   ╱ ╲ ╱ ╲ ╱ ╲   *
 
 *  ╳-2 ╳ 0 ╳ 2 ╳  *
 
 *   ╲ ╱ ╲ ╱ ╲ ╱   *
 
 *    ╳-1 ╳ 1 ╳    *
 
 *     ╲ ╱ ╲ ╱     *
 
 *      ╳ 0 ╳      *
 
 *       ╲ ╱       *
 
 *        ╳        *
 
 * \endverbatim
 
 *
 
 *
 
 * Rows are horizontal sections of the viewport, also half a tile wide.
 
 * This time the nothern most tile on the map at height level 0 defines 0 and
 
 * everything south of that has a positive number. In theory this works the
 
 * same as for columns with the massive difference that due to the isometric
 
 * projection the actual row where the tile is visible differs from the row
 
 * where the tile would be if it were at height level 0. Strictly speaking,
 
 * if you know the row of the tile at height level 0, then the row number
 
 * where it is actually drawn is tile height / 2 lower than the row number
 
 * of the same tile at height level 0.
 
 */
 

	
 
#include "stdafx.h"
 
#include "landscape.h"
 
#include "viewport_func.h"
 
@@ -47,6 +89,9 @@
 
#include "window_gui.h"
 
#include "linkgraph/linkgraph_gui.h"
 
#include "viewport_sprite_sorter.h"
 
#include "bridge_map.h"
 

	
 
#include <map>
 

	
 
#include "table/strings.h"
 
#include "table/palettes.h"
 
@@ -1022,81 +1067,473 @@ draw_inner:
 
	}
 
}
 

	
 
static void ViewportAddLandscape()
 
/**
 
 * Given a screen coordinate (x,y) as e.g. stored in _vd.dpi, this function
 
 * returns the tile coordinate of the tile which would be painted at (x,y)
 
 * if one assumes height zero at that position.
 
 * @param x Some x screen coordinate
 
 * @param y Some y screen coordinate
 
 * @return Tile coordinate assuming height zero as described
 
 */
 
static inline Point GetTileCoordFromScreenCoord(int x, int y)
 
{
 
	/* First convert from the screen coordinate system (where the width of tiles
 
	 * is twice their height) to the tile coordinate system. That means, turn
 
	 * around by 45 degrees and make the tiles quadratic. */
 
	Point tile_coord = InverseRemapCoords(x, y);
 

	
 
	/* Scale from a 16x16-grid to a 1x1-grid as returned by TileX/TileY. */
 
	tile_coord.x /= (int)TILE_SIZE;
 
	tile_coord.y /= (int)TILE_SIZE;
 

	
 
	return tile_coord;
 
}
 

	
 
/**
 
 * Assume a region, given by screen coordinates (x1,y1,x2,y2), as defined in _vd.dpi.
 
 * This function basically takes (x1,y1) (i.e. the upper left corner of that region)
 
 * and returns the tile coordinate of the tile, which would be painted at (x1,y1)
 
 * if one assumes height zero at that position.
 
 *
 
 * However, in detail: Imagine tiles being split up into their upper left,upper right,
 
 * etc. isometric sections.  We return a tile where the upper left corner of the
 
 * mentioned region is either in its lower right section or in a neighbor tile
 
 * below / right of that section. By doing so, we want to enforce that we can
 
 * travel to east or south from that point without leaving the region again.
 
 *
 
 * @param x Some x screen coordinate, x1 in terms of the description above
 
 * @param y Some y screen coordinate, y1 in terms of the description above
 
 * @return Upper left corner of the region as tile coordinates.
 
 */
 
static Point GetMinTileCoordsIgnoringHeight(int x, int y)
 
{
 
	Point tile_coord = GetTileCoordFromScreenCoord(x, y);
 

	
 
	/* Expand area to be painted in order to avoid situations
 
	 * where south or east of the to be painted point in dpi are tiles
 
	 * which will not be painted. */
 
	tile_coord.y--;
 

	
 
	return tile_coord;
 
}
 

	
 
/**
 
 * Assume a region, given by screen coordinates (x1,y1,x2,y2), as defined in _vd.dpi.
 
 * This function basically takes (x2,y2) (i.e. the lower right corner of that region)
 
 * and returns the tile coordinate of the tile, which would be painted at (x2,y2)
 
 * if one assumes height zero at that position.
 
 *
 
 * However, in detail: Imagine tiles being split up into their upper left,upper right,
 
 * etc. isometric sections.  We return a tile where the lower right corner of the
 
 * mentioned region is either in its upper left section or in a neighbor tile
 
 * above / left of that section. By doing so, we want to enforce that we can
 
 * travel to north or west from that point without leaving the region again.
 
 *
 
 * @param x Some x screen coordinate, x2 in terms of the description above
 
 * @param y Some y screen coordinate, y2 in terms of the description above
 
 * @return Upper left corner of the region as tile coordinates.
 
 */
 
static Point GetMaxTileCoordsIgnoringHeight(int x, int y)
 
{
 
	Point tile_coord = GetTileCoordFromScreenCoord(x, y);
 

	
 
	/* Expand area to be painted to southeast in order to avoid situations
 
	 * where north or east of the given to be painted point in dpi are
 
	 * tiles which will not be repainted. */
 
	tile_coord.y++;
 

	
 
	return tile_coord;
 
}
 

	
 
/**
 
 * Returns the y coordinate in the viewport coordinate system where the given
 
 * tile is painted.
 
 * @param tile Any tile.
 
 * @return The viewport y coordinate where the tile is painted.
 
 */
 
static int GetViewportY(Point tile)
 
{
 
	return (tile.y * TILE_SIZE + tile.x * TILE_SIZE - GetTileMaxPixelZOutsideMap(tile.x, tile.y)) << ZOOM_LVL_SHIFT;
 
}
 

	
 
/**
 
 * Given a tile coordinate as returned by TileX / TileY, this returns its column.
 
 *
 
 * @param tile_coord The coordinate of the tile.
 
 * @return The column index.
 
 * @ingroup vp_column_row
 
 */
 
static int GetTileColumnFromTileCoord(Point tile_coord)
 
{
 
	return tile_coord.y - tile_coord.x;
 
}
 

	
 
/**
 
 * Returns the position of the tile at the northern end of the column of the
 
 * given tile.
 
 * @param tile Any tile.
 
 * @return Position of the tile at the northern end of the column as described.
 
 * @ingroup vp_column_row
 
 */
 
static Point GetNorthernEndOfColumn(Point tile)
 
{
 
	int x, y, width, height;
 
	TileInfo ti;
 
	bool direction;
 

	
 
	_cur_ti = &ti;
 

	
 
	/* Transform into tile coordinates and round to closest full tile */
 
	x = ((_vd.dpi.top >> (1 + ZOOM_LVL_SHIFT)) - (_vd.dpi.left >> (2 + ZOOM_LVL_SHIFT))) & ~TILE_UNIT_MASK;
 
	y = ((_vd.dpi.top >> (1 + ZOOM_LVL_SHIFT)) + (_vd.dpi.left >> (2 + ZOOM_LVL_SHIFT)) - TILE_SIZE) & ~TILE_UNIT_MASK;
 

	
 
	/* determine size of area */
 
	{
 
		Point pt = RemapCoords(x, y, 241);
 
		width = (_vd.dpi.left + _vd.dpi.width - pt.x + 96 * ZOOM_LVL_BASE - 1) >> (6 + ZOOM_LVL_SHIFT);
 
		height = (_vd.dpi.top + _vd.dpi.height - pt.y) >> (5 + ZOOM_LVL_SHIFT) << 1;
 
	Point northern_end;
 

	
 
	if (tile.x < tile.y) {
 
		northern_end.x = 0;
 
		northern_end.y = tile.y - tile.x;
 
	} else {
 
		northern_end.x = tile.x - tile.y;
 
		northern_end.y = 0;
 
	}
 

	
 
	return northern_end;
 
}
 

	
 
/**
 
 * Returns the position of the tile at the southern end of the column of the
 
 * given tile, if it is within the given limit expressed in number of tiles
 
 * @param tile Any tile.
 
 * @param limit Number of tiles to go to south at most, if the southern end is
 
 *              further away, stop after that number of tiles
 
 * @return Position of the tile at the soutern end of the column as described.
 
 * @ingroup vp_column_row
 
 */
 
static Point GetSouthernEndOfColumnWithLimit(Point tile, uint limit)
 
{
 
	Point distance_to_end;
 
	distance_to_end.x = (int)MapMaxX() - tile.x;
 
	distance_to_end.y = (int)MapMaxY() - tile.y;
 

	
 
	Point southern_end;
 
	if (distance_to_end.x < distance_to_end.y) {
 
		int number_of_steps = min(limit, distance_to_end.x);
 
		southern_end.x = tile.x + number_of_steps;
 
		southern_end.y = tile.y + number_of_steps;
 
	} else {
 
		int number_of_steps = min(limit, distance_to_end.y);
 
		southern_end.x = tile.x + number_of_steps;
 
		southern_end.y = tile.y + number_of_steps;
 
	}
 

	
 
	assert(width > 0);
 
	assert(height > 0);
 

	
 
	direction = false;
 

	
 
	int min_xy = _settings_game.construction.freeform_edges ? TILE_SIZE : 0;
 
	return southern_end;
 
}
 

	
 
/**
 
 * Returns the position of the tile at the southern end of the column of the
 
 * given tile.
 
 * @param tile Any tile.
 
 * @return Position of the tile at the soutern end of the column as described.
 
 * @ingroup vp_column_row
 
 */
 
static Point GetSouthernEndOfColumn(Point tile)
 
{
 
	return GetSouthernEndOfColumnWithLimit(tile, UINT32_MAX);
 
}
 

	
 
/**
 
 * Returns the tile exactly in the middle between two given tiles.
 
 *
 
 * @param tile Point upper_tile, any tile.
 
 * @param tile Point lower_tile, any tile.
 
 * @return The tile in the middle of Point upper_tile and Point lower_tile.
 
 */
 
static Point GetMiddleTile(Point upper_tile, Point lower_tile)
 
{
 
	Point middle_tile;
 
	middle_tile.x = (lower_tile.x + upper_tile.x) / 2;
 
	middle_tile.y = (lower_tile.y + upper_tile.y) / 2;
 
	return middle_tile;
 
}
 

	
 
/**
 
 * Given a tile coordinate assuming height zero, this returns the row actually
 
 * painted at this tile coordinate if one recognizes height.
 
 *
 
 * The problem concerning this calculation is that we have not enough
 
 * information to calculate this in one closed formula. Which row we
 
 * search rather depends on the height distribution on the map. So
 
 * we have to search.
 
 *
 
 * First, the searched tile may be located outside map. Then, we know
 
 * that we are not too far outside map, so we can step tile by tile,
 
 * starting at the given tile, until we have passed the searched tile.
 
 *
 
 * If the searched tile is inside map, searching is more difficult. A
 
 * linear search on some thousand tiles would be not that efficient. But,
 
 * we can solve the problem by interval intersection. We know for sure,
 
 * that the searched tile is south of the given tile, simply because
 
 * mountains of height > 0 (and we have only such mountains) are always
 
 * painted north of their tile. So we choose a tile half way between the
 
 * given tile and the southern end of the map, have a look whether it is
 
 * north or south of the given position, and intersect again. Until
 
 * our interval has length 1, then we take the upper one.
 
 *
 
 * @param viewport_y The viewport y corresponding to tile, if one assumes height zero for that tile
 
 * @param tile Some tile coordinate assuming height zero.
 
 * @param bridge_correct If true, consider bridges south of the calculated tile, and if the bridge
 
 *                       visually intersect the calculated tile, shift it southwards.
 
 * @return The row which is painted at this coordinate, according to the discussion above.
 
 * @ingroup vp_column_row
 
 */
 
int GetRowAtTile(int viewport_y, Point tile, bool bridge_correct)
 
{
 
	Point northern_tile = GetNorthernEndOfColumn(tile);
 
	Point southern_tile = GetSouthernEndOfColumn(tile);
 

	
 
	int northern_tile_viewport_y = GetViewportY(northern_tile);
 
	int southern_tile_viewport_y = GetViewportY(southern_tile);
 

	
 
	if (northern_tile_viewport_y >= viewport_y) {
 
		/* We are north of the map, search tile by tile with direction north. */
 
		while (northern_tile_viewport_y >= viewport_y) {
 
			northern_tile.x--;
 
			northern_tile.y--;
 
			northern_tile_viewport_y = GetViewportY(northern_tile);
 
		}
 
		return northern_tile.x + northern_tile.y;
 
	}
 

	
 
	if (southern_tile_viewport_y <= viewport_y) {
 
		/* We are south of the map, search tile by tile with direction south. */
 
		while (southern_tile_viewport_y <= viewport_y) {
 
			southern_tile.x++;
 
			southern_tile.y++;
 
			southern_tile_viewport_y = GetViewportY(southern_tile);
 
		}
 
		return southern_tile.x + southern_tile.y;
 
	}
 

	
 
	/*
 
	 * We are inside the map.  The searched tile is at most
 
	 * <maximum heightlevel / 4> tiles south of the given tile (as one tile
 
	 * painted on the screen needs as much vertical space as painting a tile
 
	 * by 4 heightlevels ascended).  Add one to avoid rounding errors to the
 
	 * wrong side.
 
	 *
 
	 * Invariant in the code below: The searched tile shown at viewport_y
 
	 * always is between upper_tile and lower_tile.
 
	 */
 
	Point upper_tile = tile;
 
	Point lower_tile = GetSouthernEndOfColumnWithLimit(upper_tile, _settings_game.construction.max_heightlevel / 4 + 1);
 
	int middle_bound;
 

	
 
	do {
 
		int width_cur = width;
 
		int x_cur = x;
 
		int y_cur = y;
 

	
 
		do {
 
			TileType tt;
 
			ti.x = x_cur;
 
			ti.y = y_cur;
 

	
 
			if (IsInsideMM(x_cur, min_xy, MapMaxX() * TILE_SIZE) &&
 
					IsInsideMM(y_cur, min_xy, MapMaxY() * TILE_SIZE)) {
 
				ti.tile = TileVirtXY(x_cur, y_cur);
 
				ti.tileh = GetTilePixelSlope(ti.tile, &ti.z);
 
				tt = GetTileType(ti.tile);
 
			} else {
 
				/* We are outside the map => paint black. */
 
				ti.tile = 0;
 
				ti.tileh = GetTilePixelSlopeOutsideMap(x_cur / (int)TILE_SIZE, y_cur / (int)TILE_SIZE, &ti.z);
 
				tt = MP_VOID;
 
		Point middle_tile = GetMiddleTile(upper_tile, lower_tile);
 
		middle_bound = GetViewportY(middle_tile);
 

	
 
		if (middle_bound >= viewport_y) {
 
			/* The tile shown at viewport_y is somewhere in the upper half of
 
			 * the currently observed section. */
 
			lower_tile = middle_tile;
 
		} else {
 
			/* The tile shown at viewport_y is somewhere in the lower half of
 
			 * the currently observed section. */
 
			upper_tile = middle_tile;
 
		}
 
	}
 
	while (lower_tile.y - upper_tile.y > 1);
 

	
 
	/* Now our interval has length 1, so only contains two tiles, and we take the upper one.
 
	 * However, there is one problem left: Tiles being located southwards, containing a high bridge.
 
	 * They may, though not high enough in terms of landscape, intersect the drawing area with parts
 
	 * of the bridge.
 
	 * Luckily, there is a guaranteed upper bound for bridge height, thus we know how far we have to
 
	 * search southwards whether such a bridge exists.
 
	 */
 
	int correction_step = 0;
 
	if (bridge_correct) {
 
		/* Calculate, how many tiles below upper_tile, a worst case bridge intersecting upper_tile in
 
		 * terms of painting can be located.  Lets inspect that formula in detail:
 
		 * ... - 5: The magic constant near the beginning of ViewportAddLandscape accounts for 5 harmless heightlevels a bridge can have.  Thus subtract them.
 
		 * ... / 2: Four heightlevels account for one tile height.  On the other hand, if landscape ascends from upper_tile southwards, this can account for
 
		 *           as many additional heightlevels as we step southwards.  In combination: A division by two gains the number of tiles to step southwards.
 
		 * ... + 1: Avoid rounding errors, and fall back to the safe side.
 
		 */
 
		int worst_case_steps_southwards = max(0, ((int)_settings_game.construction.max_bridge_height - 5) / 2 + 1);
 
		for (int n = 0; n < worst_case_steps_southwards; n++) {
 
			TileIndex potential_bridge_tile = TileXY(upper_tile.x + n, upper_tile.y + n);
 
			if (IsValidTile(potential_bridge_tile) && IsBridgeAbove(potential_bridge_tile)) {
 
				/* There is a bridge. */
 
				TileIndex bridge_start = GetNorthernBridgeEnd(potential_bridge_tile);
 
				int bridge_height = GetBridgeHeight(bridge_start);
 
				int upper_tile_height = GetTileZ(TileXY(upper_tile.x, upper_tile.y));
 

	
 
				/* Start at the bridge level, descend by the number of heightlevels equivalent to our steps southwards (in worst case), subtract the harmless
 
				 * bridge heightlevels, and compare whether we are still above the height of the upper_tile.  If yes, we need to paint that tile, to avoid glitches.
 
				 */
 
				if (bridge_height - 2 * n - 1 > upper_tile_height) {
 
					correction_step = n;
 
				}
 
			}
 

	
 
			_vd.foundation_part = FOUNDATION_PART_NONE;
 
			_vd.foundation[0] = -1;
 
			_vd.foundation[1] = -1;
 
			_vd.last_foundation_child[0] = NULL;
 
			_vd.last_foundation_child[1] = NULL;
 

	
 
			_tile_type_procs[tt]->draw_tile_proc(&ti);
 

	
 
			if (((uint)x_cur == MapMaxX() * TILE_SIZE && IsInsideMM(y_cur, 0, MapMaxY() * TILE_SIZE + 1)) ||
 
					((uint)y_cur == MapMaxY() * TILE_SIZE && IsInsideMM(x_cur, 0, MapMaxX() * TILE_SIZE + 1))) {
 
				TileIndex tile = TileVirtXY(x_cur, y_cur);
 
				ti.tile = tile;
 
				ti.tileh = GetTilePixelSlope(tile, &ti.z);
 
				tt = GetTileType(tile);
 
		}
 
	}
 

	
 
	/* The biggest recorded correction_step defines, which tile we actually return. */
 
	upper_tile.x += correction_step;
 
	upper_tile.y += correction_step;
 

	
 
	/* Returns its row. */
 
	return upper_tile.x + upper_tile.y;
 
}
 

	
 
/**
 
 * Returns the bottom tile of the column of upper_tile shown on the viewport,
 
 * given upper_tile and the lower right tile shown on the viewport.
 
 *
 
 * @param upper_tile Sny tile inside the map.
 
 * @param lower_right_tile The tile shown at the southeast edge of the viewport
 
 *                          (ignoring height). Note that this tile may be located
 
 *                          northeast of the upper_tile, because upper_tile is usually
 
 *                          calculated by shifting a tile southwards until we reach
 
 *                          the northern map border.
 
 * @return The lowest existing tile located in the column defined by upper_tile,
 
 *                 which is in the same row as lower_right_tile or above that row
 
 *                 If lower_right_tile was northeast of upper_tile, (-1,-1) is returned.
 
 * @ingroup vp_column_row
 
 */
 
static Point GetBottomTileOfColumn(Point upper_tile, Point lower_right_tile)
 
{
 
	int upper_row = upper_tile.x + upper_tile.y;
 
	int lower_row = lower_right_tile.x + lower_right_tile.y;
 

	
 
	assert(upper_row <= lower_row);
 

	
 
	int number_of_rows = lower_row - upper_row;
 

	
 
	if (number_of_rows % 2 != 0) {
 
		/* Avoid 0.5 being rounded down to zero; painting too much is better than
 
		 * painting too little. */
 
		number_of_rows++;
 
	}
 

	
 
	Point bottom_tile;
 
	bottom_tile.x = upper_tile.x + number_of_rows / 2;
 
	bottom_tile.y = upper_tile.y + number_of_rows / 2;
 

	
 
	int bottom_row = bottom_tile.x + bottom_tile.y;
 

	
 
	assert(bottom_row >= lower_row);
 

	
 
	return bottom_tile;
 
}
 

	
 
/**
 
 * Add the landscape to the viewport, i.e. all ground tiles and buildings.
 
 */
 
static void ViewportAddLandscape()
 
{
 
	assert(_vd.dpi.top <= _vd.dpi.top + _vd.dpi.height);
 
	assert(_vd.dpi.left <= _vd.dpi.left + _vd.dpi.width);
 

	
 
	/* The upper and lower edge of the viewport part to paint. Add some number
 
	 * of pixels to the lower end in order to ensure that we also take tiles
 
	 * south of the given area, but with high buildings intersecting the area.
 
	 * Subtract some pixels from the upper end in order to avoid glitches at the
 
	 * upper end of the top be painted area. */
 
	int viewport_top = _vd.dpi.top - 16;
 
	int viewport_bottom = _vd.dpi.top + _vd.dpi.height + 116;
 

	
 
	/* First get the position of the tile at the upper left / lower right edge,
 
	 * for now ignoring the height. (i.e. assuming height zero.) */
 
	Point upper_left_tile = GetMinTileCoordsIgnoringHeight(_vd.dpi.left, viewport_top);
 
	Point lower_right_tile = GetMaxTileCoordsIgnoringHeight(_vd.dpi.left + _vd.dpi.width, viewport_bottom);
 

	
 
	/* Calculate the bounding columns. We won't need to draw anything
 
	 * left / right of them. */
 
	int left_column = GetTileColumnFromTileCoord(upper_left_tile);
 
	/* Correction to avoid glitches when approaching the left edge of the map. */
 
	left_column--;
 
	int right_column = GetTileColumnFromTileCoord(lower_right_tile);
 
	right_column++;
 

	
 
	/* For each column, calculate the top and the bottom row. These are the
 
	 * bounding rows for that specific column. */
 
	int *top_row = AllocaM(int, right_column - left_column + 1); // Pre-allocate memory for visual studio/express to be able to compile.
 
	int *bottom_row = AllocaM(int, right_column - left_column + 1); // Pre-allocate memory for visual studio/express to be able to compile.
 
	int min_top_row = MapMaxX() + MapMaxY();
 
	int max_bottom_row = 0;
 
	Point top_tile_of_column = upper_left_tile;
 

	
 
	/* And now for each column, determine the top and the bottom row we must paint. */
 
	bool south_east_direction = false;
 
	for (int x = left_column; x <= right_column; x++) {
 
		Point bottom_tile_of_column = GetBottomTileOfColumn(top_tile_of_column, lower_right_tile);
 

	
 
		/* And then actually find out the top and the bottom row. Note that
 
		 * top_tile_of_column and bottom_tile_of_column may be outside the map here.
 
		 * This possibility is needed, otherwise we couldn't paint the black area
 
		 * outside the map (and in particular the edge of map) properly.
 
		 * Subtract three / add one to avoid glitches. */
 
		top_row[x - left_column] = GetRowAtTile(viewport_top, top_tile_of_column, false);
 

	
 
		top_row[x - left_column] -= 3;
 
		bottom_row[x - left_column] = GetRowAtTile(viewport_bottom, bottom_tile_of_column, true);
 
		bottom_row[x - left_column]++;
 

	
 
		/* We never paint things in rows < min_top_row or > max_bottom_row. */
 
		min_top_row = min(min_top_row, top_row[x - left_column]);
 
		max_bottom_row = max(max_bottom_row, bottom_row[x - left_column]);
 

	
 
		/* Go to next column in the east. */
 
		if (south_east_direction) {
 
			top_tile_of_column.y++;
 
		} else {
 
			top_tile_of_column.x--;
 
		}
 

	
 
		/* Switch between directions southeast and northeast. */
 
		south_east_direction = !south_east_direction;
 
	}
 

	
 
	for (int row = min_top_row; row <= max_bottom_row; row++) {
 
		for (int column = left_column; column <= right_column; column++) {
 
			/* For each column, we only paint the interval top_row .. bottom_row.
 
			 * Due to the division by two below, even and odd values of row + column map to
 
			 * the same (x,y) combinations. Thus, we only paint one of them. */
 
			if (((row + column) % 2 == 0) &&
 
					(top_row[column - left_column] <= row) &&
 
					(row <= bottom_row[column - left_column])) {
 
				TileType tile_type;
 
				TileInfo tile_info;
 
				_cur_ti = &tile_info;
 

	
 
				/* column = y - x; row = x + y; now solve the equation system
 
				 * for x and y. */
 
				int x = (row - column) / 2;
 
				int y = (row + column) / 2;
 
				tile_info.x = x;
 
				tile_info.y = y;
 

	
 
				/* For some strange reason, those fields inside tile_info are uints. However,
 
				 * in the old code their copies in an int variable where compared against zero. */
 
				if (0 < x && x < (int)MapMaxX() && 0 < y && y < (int)MapMaxY()) {
 
					/* We are inside the map => paint landscape. */
 
					tile_info.tile = TileXY(tile_info.x, tile_info.y);
 
					tile_info.tileh = GetTilePixelSlope(tile_info.tile, &tile_info.z);
 
					tile_type = GetTileType(tile_info.tile);
 
				} else {
 
					/* We are outside the map => paint black. */
 
					tile_info.tile = INVALID_TILE;
 
					tile_info.tileh = GetTilePixelSlopeOutsideMap(tile_info.x, tile_info.y, &tile_info.z);
 
					tile_type = MP_VOID;
 
				}
 

	
 
				/* Scale to 16x16 tiles, needed for the drawing procedures called below. */
 
				tile_info.x *= TILE_SIZE;
 
				tile_info.y *= TILE_SIZE;
 

	
 
				_vd.foundation_part = FOUNDATION_PART_NONE;
 
				_vd.foundation[0] = -1;
 
				_vd.foundation[1] = -1;
 
				_vd.last_foundation_child[0] = NULL;
 
				_vd.last_foundation_child[1] = NULL;
 

	
 
				_tile_type_procs[tile_type]->draw_tile_proc(&tile_info);
 
				DrawTileSelection(&tile_info);
 
			}
 
			if (ti.tile != INVALID_TILE) DrawTileSelection(&ti);
 

	
 
			y_cur += 0x10;
 
			x_cur -= 0x10;
 
		} while (--width_cur);
 

	
 
		if ((direction ^= 1) != 0) {
 
			y += 0x10;
 
		} else {
 
			x += 0x10;
 
		}
 
	} while (--height);
 
	}
 
}
 

	
 
/**
src/viewport_func.h
Show inline comments
 
@@ -79,6 +79,8 @@ extern Point _tile_fract_coords;
 

	
 
void MarkTileDirtyByTile(TileIndex tile);
 

	
 
int GetRowAtTile(int viewport_y, Point tile, bool bridge_correct);
 

	
 
Point GetViewportStationMiddle(const ViewPort *vp, const Station *st);
 

	
 
#endif /* VIEWPORT_FUNC_H */
0 comments (0 inline, 0 general)