File diff r15609:02b794721f9c → r15610:623a23fb6560
src/viewport.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file viewport.cpp Handling of all viewports.
 
/**
 
 * @file viewport.cpp Handling of all viewports.
 
 *
 
 * \verbatim
 
 * The in-game coordinate system looks like this *
 
 *                                               *
 
 *                    ^ Z                        *
 
 *                    |                          *
 
 *                    |                          *
 
 *                    |                          *
 
 *                    |                          *
 
 *                 /     \                       *
 
 *              /           \                    *
 
 *           /                 \                 *
 
@@ -99,25 +100,26 @@ struct ParentSpriteToDraw {
 
	int first_child;                ///< the first child to draw.
 
	bool comparison_done;           ///< Used during sprite sorting: true if sprite has been compared with all other sprites
 
};
 

	
 
/** Enumeration of multi-part foundations */
 
enum FoundationPart {
 
	FOUNDATION_PART_NONE     = 0xFF,  ///< Neither foundation nor groundsprite drawn yet.
 
	FOUNDATION_PART_NORMAL   = 0,     ///< First part (normal foundation or no foundation)
 
	FOUNDATION_PART_HALFTILE = 1,     ///< Second part (halftile foundation)
 
	FOUNDATION_PART_END
 
};
 

	
 
/** Mode of "sprite combining"
 
/**
 
 * Mode of "sprite combining"
 
 * @see StartSpriteCombine
 
 */
 
enum SpriteCombineMode {
 
	SPRITE_COMBINE_NONE,     ///< Every #AddSortableSpriteToDraw start its own bounding box
 
	SPRITE_COMBINE_PENDING,  ///< %Sprite combining will start with the next unclipped sprite.
 
	SPRITE_COMBINE_ACTIVE,   ///< %Sprite combining is active. #AddSortableSpriteToDraw outputs child sprites.
 
};
 

	
 
typedef SmallVector<TileSpriteToDraw, 64> TileSpriteToDrawVector;
 
typedef SmallVector<StringSpriteToDraw, 4> StringSpriteToDrawVector;
 
typedef SmallVector<ParentSpriteToDraw, 64> ParentSpriteToDrawVector;
 
typedef SmallVector<ParentSpriteToDraw*, 64> ParentSpriteToSortVector;
 
@@ -439,25 +441,26 @@ Point GetTileZoomCenterWindow(bool in, W
 

	
 
	if (in) {
 
		x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2);
 
		y = ((_cursor.pos.y - vp->top) >> 1) + (vp->height >> 2);
 
	} else {
 
		x = vp->width - (_cursor.pos.x - vp->left);
 
		y = vp->height - (_cursor.pos.y - vp->top);
 
	}
 
	/* Get the tile below the cursor and center on the zoomed-out center */
 
	return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top);
 
}
 

	
 
/** Update the status of the zoom-buttons according to the zoom-level
 
/**
 
 * Update the status of the zoom-buttons according to the zoom-level
 
 * of the viewport. This will update their status and invalidate accordingly
 
 * @param w Window pointer to the window that has the zoom buttons
 
 * @param vp pointer to the viewport whose zoom-level the buttons represent
 
 * @param widget_zoom_in widget index for window with zoom-in button
 
 * @param widget_zoom_out widget index for window with zoom-out button */
 
void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out)
 
{
 
	w->SetWidgetDisabledState(widget_zoom_in, vp->zoom == ZOOM_LVL_MIN);
 
	w->SetWidgetDirty(widget_zoom_in);
 

	
 
	w->SetWidgetDisabledState(widget_zoom_out, vp->zoom == ZOOM_LVL_MAX);
 
	w->SetWidgetDirty(widget_zoom_out);
 
@@ -602,25 +605,26 @@ static void AddCombinedSprite(SpriteID i
 
	const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL);
 

	
 
	if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width ||
 
			pt.x + spr->x_offs + spr->width <= _vd.dpi.left ||
 
			pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height ||
 
			pt.y + spr->y_offs + spr->height <= _vd.dpi.top)
 
		return;
 

	
 
	const ParentSpriteToDraw *pstd = _vd.parent_sprites_to_draw.End() - 1;
 
	AddChildSpriteScreen(image, pal, pt.x - pstd->left, pt.y - pstd->top, false, sub);
 
}
 

	
 
/** Draw a (transparent) sprite at given coordinates with a given bounding box.
 
/**
 
 * Draw a (transparent) sprite at given coordinates with a given bounding box.
 
 * The bounding box extends from (x + bb_offset_x, y + bb_offset_y, z + bb_offset_z) to (x + w - 1, y + h - 1, z + dz - 1), both corners included.
 
 * Bounding boxes with bb_offset_x == w or bb_offset_y == h or bb_offset_z == dz are allowed and produce thin slices.
 
 *
 
 * @note Bounding boxes are normally specified with bb_offset_x = bb_offset_y = bb_offset_z = 0. The extent of the bounding box in negative direction is
 
 *       defined by the sprite offset in the grf file.
 
 *       However if modifying the sprite offsets is not suitable (e.g. when using existing graphics), the bounding box can be tuned by bb_offset.
 
 *
 
 * @pre w >= bb_offset_x, h >= bb_offset_y, dz >= bb_offset_z. Else w, h or dz are ignored.
 
 *
 
 * @param image the image to combine and draw,
 
 * @param pal the provided palette,
 
 * @param x position X (world) of the sprite,
 
@@ -1411,25 +1415,26 @@ void ViewportDoDraw(const ViewPort *vp, 
 

	
 
	if (_vd.string_sprites_to_draw.Length() != 0) ViewportDrawStrings(&_vd.dpi, &_vd.string_sprites_to_draw);
 

	
 
	_cur_dpi = old_dpi;
 

	
 
	_vd.string_sprites_to_draw.Clear();
 
	_vd.tile_sprites_to_draw.Clear();
 
	_vd.parent_sprites_to_draw.Clear();
 
	_vd.parent_sprites_to_sort.Clear();
 
	_vd.child_screen_sprites_to_draw.Clear();
 
}
 

	
 
/** Make sure we don't draw a too big area at a time.
 
/**
 
 * Make sure we don't draw a too big area at a time.
 
 * If we do, the sprite memory will overflow. */
 
static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
 
{
 
	if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > 180000) {
 
		if ((bottom - top) > (right - left)) {
 
			int t = (top + bottom) >> 1;
 
			ViewportDrawChk(vp, left, top, right, t);
 
			ViewportDrawChk(vp, left, t, right, bottom);
 
		} else {
 
			int t = (left + right) >> 1;
 
			ViewportDrawChk(vp, left, top, t, bottom);
 
			ViewportDrawChk(vp, t, top, right, bottom);
 
@@ -1850,25 +1855,26 @@ void PlaceObject()
 
		pt.x += 8;
 
		pt.y += 8;
 
	}
 

	
 
	_tile_fract_coords.x = pt.x & TILE_UNIT_MASK;
 
	_tile_fract_coords.y = pt.y & TILE_UNIT_MASK;
 

	
 
	w = GetCallbackWnd();
 
	if (w != NULL) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y));
 
}
 

	
 

	
 
/** Scrolls the viewport in a window to a given location.
 
/**
 
 * Scrolls the viewport in a window to a given location.
 
 * @param x       Desired x location of the map to scroll to (world coordinate).
 
 * @param y       Desired y location of the map to scroll to (world coordinate).
 
 * @param z       Desired z location of the map to scroll to (world coordinate). Use \c -1 to scroll to the height of the map at the \a x, \a y location.
 
 * @param w       %Window containing the viewport.
 
 * @param instant Jump to the location instead of slowly moving to it.
 
 * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position).
 
 */
 
bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant)
 
{
 
	/* The slope cannot be acquired outside of the map, so make sure we are always within the map. */
 
	if (z == -1) z = GetSlopeZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1));
 

	
 
@@ -1896,25 +1902,26 @@ void SetRedErrorSquare(TileIndex tile)
 
{
 
	TileIndex old;
 

	
 
	old = _thd.redsq;
 
	_thd.redsq = tile;
 

	
 
	if (tile != old) {
 
		if (tile != INVALID_TILE) MarkTileDirtyByTile(tile);
 
		if (old  != INVALID_TILE) MarkTileDirtyByTile(old);
 
	}
 
}
 

	
 
/** Highlight \a w by \a h tiles at the cursor.
 
/**
 
 * Highlight \a w by \a h tiles at the cursor.
 
 * @param w Width of the highlighted tiles rectangle.
 
 * @param h Height of the highlighted tiles rectangle.
 
 */
 
void SetTileSelectSize(int w, int h)
 
{
 
	_thd.new_size.x = w * TILE_SIZE;
 
	_thd.new_size.y = h * TILE_SIZE;
 
	_thd.new_outersize.x = 0;
 
	_thd.new_outersize.y = 0;
 
}
 

	
 
void SetTileSelectBigSize(int ox, int oy, int sx, int sy)
 
@@ -2020,25 +2027,26 @@ void UpdateTileSelection()
 

	
 
		_thd.drawstyle = _thd.new_drawstyle;
 
		_thd.pos = _thd.new_pos;
 
		_thd.size = _thd.new_size;
 
		_thd.outersize = _thd.new_outersize;
 
		_thd.dirty = 0xff;
 

	
 
		/* draw the new selection? */
 
		if (_thd.new_drawstyle) SetSelectionTilesDirty();
 
	}
 
}
 

	
 
/** Displays the measurement tooltips when selecting multiple tiles
 
/**
 
 * Displays the measurement tooltips when selecting multiple tiles
 
 * @param str String to be displayed
 
 * @param paramcount number of params to deal with
 
 * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip
 
 */
 
static inline void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[])
 
{
 
	if (!_settings_client.gui.measure_tooltip) return;
 
	GuiShowTooltips(str, paramcount, params, TCC_LEFT_CLICK);
 
}
 

	
 
/** highlighting tiles while only going over them with the mouse */
 
void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process)
 
@@ -2093,25 +2101,26 @@ void VpSetPresizeRange(TileIndex from, T
 
	_thd.next_drawstyle = HT_RECT;
 

	
 
	/* show measurement only if there is any length to speak of */
 
	if (distance > 1) ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1, &distance);
 
}
 

	
 
static void VpStartPreSizing()
 
{
 
	_thd.selend.x = -1;
 
	_special_mouse_mode = WSM_PRESIZE;
 
}
 

	
 
/** returns information about the 2x1 piece to be build.
 
/**
 
 * returns information about the 2x1 piece to be build.
 
 * The lower bits (0-3) are the track type. */
 
static HighLightStyle Check2x1AutoRail(int mode)
 
{
 
	int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
 
	int sxpy = (_thd.selend.x & TILE_UNIT_MASK) + (_thd.selend.y & TILE_UNIT_MASK);
 
	int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
 
	int sxmy = (_thd.selend.x & TILE_UNIT_MASK) - (_thd.selend.y & TILE_UNIT_MASK);
 

	
 
	switch (mode) {
 
		default: NOT_REACHED();
 
		case 0: // end piece is lower right
 
			if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL;
 
@@ -2126,25 +2135,26 @@ static HighLightStyle Check2x1AutoRail(i
 
		case 2:
 
			if (fxmy > 3 && sxmy < -3) return HT_DIR_VL;
 
			if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL;
 
			return HT_DIR_X;
 

	
 
		case 3:
 
			if (fxmy < -3 && sxmy > 3) return HT_DIR_VR;
 
			if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU;
 
			return HT_DIR_X;
 
	}
 
}
 

	
 
/** Check if the direction of start and end tile should be swapped based on
 
/**
 
 * Check if the direction of start and end tile should be swapped based on
 
 * the dragging-style. Default directions are:
 
 * in the case of a line (HT_RAIL, HT_LINE):  DIR_NE, DIR_NW, DIR_N, DIR_E
 
 * in the case of a rect (HT_RECT, HT_POINT): DIR_S, DIR_E
 
 * For example dragging a rectangle area from south to north should be swapped to
 
 * north-south (DIR_S) to obtain the same results with less code. This is what
 
 * the return value signifies.
 
 * @param style HighLightStyle dragging style
 
 * @param start_tile start tile of drag
 
 * @param end_tile end tile of drag
 
 * @return boolean value which when true means start/end should be swapped */
 
static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
 
{
 
@@ -2156,25 +2166,26 @@ static bool SwapDirection(HighLightStyle
 
	switch (style & HT_DRAG_MASK) {
 
		case HT_RAIL:
 
		case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y));
 

	
 
		case HT_RECT:
 
		case HT_POINT: return (end_x != start_x && end_y < start_y);
 
		default: NOT_REACHED();
 
	}
 

	
 
	return false;
 
}
 

	
 
/** Calculates height difference between one tile and another.
 
/**
 
 * Calculates height difference between one tile and another.
 
 * Multiplies the result to suit the standard given by #TILE_HEIGHT_STEP.
 
 *
 
 * To correctly get the height difference we need the direction we are dragging
 
 * in, as well as with what kind of tool we are dragging. For example a horizontal
 
 * autorail tool that starts in bottom and ends at the top of a tile will need the
 
 * maximum of SW, S and SE, N corners respectively. This is handled by the lookup table below
 
 * See #_tileoffs_by_dir in map.cpp for the direction enums if you can't figure out the values yourself.
 
 * @param style      Highlighting style of the drag. This includes direction and style (autorail, rect, etc.)
 
 * @param distance   Number of tiles dragged, important for horizontal/vertical drags, ignored for others.
 
 * @param start_tile Start tile of the drag operation.
 
 * @param end_tile   End tile of the drag operation.
 
 * @return Height difference between two tiles. The tile measurement tool utilizes this value in its tooltip.