File diff r6178:fc8bd2bde93a → r6179:c0508e7aefec
src/gfx.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file gfx.cpp */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "functions.h"
 
#include "macros.h"
 
#include "spritecache.h"
 
#include "strings.h"
 
#include "string.h"
 
#include "gfx.h"
 
#include "table/palettes.h"
 
#include "table/sprites.h"
 
#include "hal.h"
 
#include "variables.h"
 
#include "table/control_codes.h"
 
#include "fontcache.h"
 
#include "genworld.h"
 
#include "debug.h"
 

	
 
#ifdef _DEBUG
 
bool _dbg_screen_rect;
 
#endif
 

	
 
byte _dirkeys;        // 1 = left, 2 = up, 4 = right, 8 = down
 
byte _dirkeys;        ///< 1 = left, 2 = up, 4 = right, 8 = down
 
bool _fullscreen;
 
CursorVars _cursor;
 
bool _ctrl_pressed;   // Is Ctrl pressed?
 
bool _shift_pressed;  // Is Shift pressed?
 
bool _ctrl_pressed;   ///< Is Ctrl pressed?
 
bool _shift_pressed;  ///< Is Shift pressed?
 
byte _fast_forward;
 
bool _left_button_down;
 
bool _left_button_clicked;
 
bool _right_button_down;
 
bool _right_button_clicked;
 
DrawPixelInfo _screen;
 
bool _exit_game;
 
bool _networking;         ///< are we in networking mode?
 
byte _game_mode;
 
byte _pause;
 
int _pal_first_dirty;
 
int _pal_last_dirty;
 
@@ -79,76 +81,76 @@ void GfxScroll(int left, int top, int wi
 
	Pixel *dst;
 
	int p;
 
	int ht;
 

	
 
	if (xo == 0 && yo == 0) return;
 

	
 
	if (_cursor.visible) UndrawMouseCursor();
 
	UndrawTextMessage();
 

	
 
	p = _screen.pitch;
 

	
 
	if (yo > 0) {
 
		// Calculate pointers
 
		/*Calculate pointers */
 
		dst = _screen.dst_ptr + (top + height - 1) * p + left;
 
		src = dst - yo * p;
 

	
 
		// Decrease height and increase top
 
		/* Decrease height and increase top */
 
		top += yo;
 
		height -= yo;
 
		assert(height > 0);
 

	
 
		// Adjust left & width
 
		/* Adjust left & width */
 
		if (xo >= 0) {
 
			dst += xo;
 
			left += xo;
 
			width -= xo;
 
		} else {
 
			src -= xo;
 
			width += xo;
 
		}
 

	
 
		for (ht = height; ht > 0; --ht) {
 
			memcpy(dst, src, width);
 
			src -= p;
 
			dst -= p;
 
		}
 
	} else {
 
		// Calculate pointers
 
		/* Calculate pointers */
 
		dst = _screen.dst_ptr + top * p + left;
 
		src = dst - yo * p;
 

	
 
		// Decrese height. (yo is <=0).
 
		/* Decrese height. (yo is <=0). */
 
		height += yo;
 
		assert(height > 0);
 

	
 
		// Adjust left & width
 
		/* Adjust left & width */
 
		if (xo >= 0) {
 
			dst += xo;
 
			left += xo;
 
			width -= xo;
 
		} else {
 
			src -= xo;
 
			width += xo;
 
		}
 

	
 
		// the y-displacement may be 0 therefore we have to use memmove,
 
		// because source and destination may overlap
 
		/* the y-displacement may be 0 therefore we have to use memmove,
 
		 * because source and destination may overlap */
 
		for (ht = height; ht > 0; --ht) {
 
			memmove(dst, src, width);
 
			src += p;
 
			dst += p;
 
		}
 
	}
 
	// This part of the screen is now dirty.
 
	/* This part of the screen is now dirty. */
 
	_video_driver->make_dirty(left, top, width, height);
 
}
 

	
 

	
 
void GfxFillRect(int left, int top, int right, int bottom, int color)
 
{
 
	const DrawPixelInfo* dpi = _cur_dpi;
 
	Pixel *dst;
 
	const int otop = top;
 
	const int oleft = left;
 

	
 
	if (dpi->zoom != 0) return;
 
@@ -203,25 +205,25 @@ static void GfxSetPixel(int x, int y, in
 
		return;
 
	dpi->dst_ptr[y * dpi->pitch + x] = color;
 
}
 

	
 
void GfxDrawLine(int x, int y, int x2, int y2, int color)
 
{
 
	int dy;
 
	int dx;
 
	int stepx;
 
	int stepy;
 
	int frac;
 

	
 
	// Check clipping first
 
	/* Check clipping first */
 
	{
 
		DrawPixelInfo *dpi = _cur_dpi;
 
		int t;
 

	
 
		if (x < dpi->left && x2 < dpi->left) return;
 

	
 
		if (y < dpi->top && y2 < dpi->top) return;
 

	
 
		t = dpi->left + dpi->width;
 
		if (x > t && x2 > t) return;
 

	
 
		t = dpi->top + dpi->height;
 
@@ -283,42 +285,42 @@ static int TruncateString(char *str, int
 
	int ddd, ddd_w;
 

	
 
	WChar c;
 
	char *ddd_pos;
 

	
 
	ddd_w = ddd = GetCharacterWidth(size, '.') * 3;
 

	
 
	for (ddd_pos = str; (c = Utf8Consume((const char **)&str)) != '\0'; ) {
 
		if (IsPrintable(c)) {
 
			w += GetCharacterWidth(size, c);
 

	
 
			if (w >= maxw) {
 
				// string got too big... insert dotdotdot
 
				/* string got too big... insert dotdotdot */
 
				ddd_pos[0] = ddd_pos[1] = ddd_pos[2] = '.';
 
				ddd_pos[3] = 0;
 
				return ddd_w;
 
			}
 
		} else {
 
			if (c == SCC_SETX) str++;
 
			else if (c == SCC_SETXY) str += 2;
 
			else if (c == SCC_TINYFONT) {
 
				size = FS_SMALL;
 
				ddd = GetCharacterWidth(size, '.') * 3;
 
			} else if (c == SCC_BIGFONT) {
 
				size = FS_LARGE;
 
				ddd = GetCharacterWidth(size, '.') * 3;
 
			}
 
		}
 

	
 
		// Remember the last position where three dots fit.
 
		/* Remember the last position where three dots fit. */
 
		if (w + ddd < maxw) {
 
			ddd_w = w + ddd;
 
			ddd_pos = str;
 
		}
 
	}
 

	
 
	return w;
 
}
 

	
 
static inline int TruncateStringID(StringID src, char *dest, int maxw, const char* last)
 
{
 
	GetString(dest, src, last);
 
@@ -1535,103 +1537,103 @@ void DoPaletteAnimations(void)
 
	/* Amount of colors to be rotated.
 
	 * A few more for the DOS palette, because the water colors are
 
	 * 245-254 for DOS and 217-226 for Windows.  */
 
	const ExtraPaletteValues *ev = &_extra_palette_values;
 
	int c = _use_dos_palette ? 38 : 28;
 
	Colour old_val[38]; // max(38, 28)
 
	uint i;
 
	uint j;
 

	
 
	d = &_cur_palette[217];
 
	memcpy(old_val, d, c * sizeof(*old_val));
 

	
 
	// Dark blue water
 
	/* Dark blue water */
 
	s = (_opt.landscape == LT_CANDY) ? ev->ac : ev->a;
 
	j = EXTR(320, 5);
 
	for (i = 0; i != 5; i++) {
 
		*d++ = s[j];
 
		j++;
 
		if (j == 5) j = 0;
 
	}
 

	
 
	// Glittery water
 
	/* Glittery water */
 
	s = (_opt.landscape == LT_CANDY) ? ev->bc : ev->b;
 
	j = EXTR(128, 15);
 
	for (i = 0; i != 5; i++) {
 
		*d++ = s[j];
 
		j += 3;
 
		if (j >= 15) j -= 15;
 
	}
 

	
 
	s = ev->e;
 
	j = EXTR2(512, 5);
 
	for (i = 0; i != 5; i++) {
 
		*d++ = s[j];
 
		j++;
 
		if (j == 5) j = 0;
 
	}
 

	
 
	// Oil refinery fire animation
 
	/* Oil refinery fire animation */
 
	s = ev->oil_ref;
 
	j = EXTR2(512, 7);
 
	for (i = 0; i != 7; i++) {
 
		*d++ = s[j];
 
		j++;
 
		if (j == 7) j = 0;
 
	}
 

	
 
	// Radio tower blinking
 
	/* Radio tower blinking */
 
	{
 
		byte i = (_timer_counter >> 1) & 0x7F;
 
		byte v;
 

	
 
		(v = 255, i < 0x3f) ||
 
		(v = 128, i < 0x4A || i >= 0x75) ||
 
		(v = 20);
 
		d->r = v;
 
		d->g = 0;
 
		d->b = 0;
 
		d++;
 

	
 
		i ^= 0x40;
 
		(v = 255, i < 0x3f) ||
 
		(v = 128, i < 0x4A || i >= 0x75) ||
 
		(v = 20);
 
		d->r = v;
 
		d->g = 0;
 
		d->b = 0;
 
		d++;
 
	}
 

	
 
	// Handle lighthouse and stadium animation
 
	/* Handle lighthouse and stadium animation */
 
	s = ev->lighthouse;
 
	j = EXTR(256, 4);
 
	for (i = 0; i != 4; i++) {
 
		*d++ = s[j];
 
		j++;
 
		if (j == 4) j = 0;
 
	}
 

	
 
	// Animate water for old DOS graphics
 
	/* Animate water for old DOS graphics */
 
	if (_use_dos_palette) {
 
		// Dark blue water DOS
 
		/* Dark blue water DOS */
 
		s = (_opt.landscape == LT_CANDY) ? ev->ac : ev->a;
 
		j = EXTR(320, 5);
 
		for (i = 0; i != 5; i++) {
 
			*d++ = s[j];
 
			j++;
 
			if (j == 5) j = 0;
 
		}
 

	
 
		// Glittery water DOS
 
		/* Glittery water DOS */
 
		s = (_opt.landscape == LT_CANDY) ? ev->bc : ev->b;
 
		j = EXTR(128, 15);
 
		for (i = 0; i != 5; i++) {
 
			*d++ = s[j];
 
			j += 3;
 
			if (j >= 15) j -= 15;
 
		}
 
	}
 

	
 
	if (memcmp(old_val, &_cur_palette[217], c * sizeof(*old_val)) != 0) {
 
		if (_pal_first_dirty > 217) _pal_first_dirty = 217;
 
		if (_pal_last_dirty < 217 + c) _pal_last_dirty = 217 + c;
 
@@ -1661,29 +1663,29 @@ void LoadStringWidthTable(void)
 

	
 

	
 
byte GetCharacterWidth(FontSize size, WChar key)
 
{
 
	if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32];
 

	
 
	return GetGlyphWidth(size, key);
 
}
 

	
 

	
 
void ScreenSizeChanged(void)
 
{
 
	// check the dirty rect
 
	/* check the dirty rect */
 
	if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
 
	if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height;
 

	
 
	// screen size changed and the old bitmap is invalid now, so we don't want to undraw it
 
	/* screen size changed and the old bitmap is invalid now, so we don't want to undraw it */
 
	_cursor.visible = false;
 
}
 

	
 
void UndrawMouseCursor(void)
 
{
 
	if (_cursor.visible) {
 
		_cursor.visible = false;
 
		memcpy_pitch(
 
			_screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch,
 
			_cursor_backup,
 
			_cursor.draw_size.x, _cursor.draw_size.y, _cursor.draw_size.x, _screen.pitch);
 

	
 
@@ -1692,25 +1694,25 @@ void UndrawMouseCursor(void)
 
}
 

	
 
void DrawMouseCursor(void)
 
{
 
	int x;
 
	int y;
 
	int w;
 
	int h;
 

	
 
	/* Redraw mouse cursor but only when it's inside the window */
 
	if (!_cursor.in_window) return;
 

	
 
	// Don't draw the mouse cursor if it's already drawn
 
	/* Don't draw the mouse cursor if it's already drawn */
 
	if (_cursor.visible) {
 
		if (!_cursor.dirty) return;
 
		UndrawMouseCursor();
 
	}
 

	
 
	w = _cursor.size.x;
 
	x = _cursor.pos.x + _cursor.offs.x;
 
	if (x < 0) {
 
		w += x;
 
		x = 0;
 
	}
 
	if (w > _screen.width - x) w = _screen.width - x;
 
@@ -1722,31 +1724,31 @@ void DrawMouseCursor(void)
 
	y = _cursor.pos.y + _cursor.offs.y;
 
	if (y < 0) {
 
		h += y;
 
		y = 0;
 
	}
 
	if (h > _screen.height - y) h = _screen.height - y;
 
	if (h <= 0) return;
 
	_cursor.draw_pos.y = y;
 
	_cursor.draw_size.y = h;
 

	
 
	assert(w * h < (int)sizeof(_cursor_backup));
 

	
 
	// Make backup of stuff below cursor
 
	/* Make backup of stuff below cursor */
 
	memcpy_pitch(
 
		_cursor_backup,
 
		_screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch,
 
		_cursor.draw_size.x, _cursor.draw_size.y, _screen.pitch, _cursor.draw_size.x);
 

	
 
	// Draw cursor on screen
 
	/* Draw cursor on screen */
 
	_cur_dpi = &_screen;
 
	DrawSprite(_cursor.sprite, _cursor.pal, _cursor.pos.x, _cursor.pos.y);
 

	
 
	_video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
 

	
 
	_cursor.visible = true;
 
	_cursor.dirty = false;
 
}
 

	
 
#if defined(_DEBUG)
 
static void DbgScreenRect(int left, int top, int right, int bottom)
 
{
 
@@ -1797,47 +1799,47 @@ void DrawDirtyBlocks(void)
 
	y = 0;
 
	do {
 
		x = 0;
 
		do {
 
			if (*b != 0) {
 
				int left;
 
				int top;
 
				int right = x + 64;
 
				int bottom = y;
 
				byte *p = b;
 
				int h2;
 

	
 
				// First try coalescing downwards
 
				/* First try coalescing downwards */
 
				do {
 
					*p = 0;
 
					p += DIRTY_BYTES_PER_LINE;
 
					bottom += 8;
 
				} while (bottom != h && *p != 0);
 

	
 
				// Try coalescing to the right too.
 
				/* Try coalescing to the right too. */
 
				h2 = (bottom - y) >> 3;
 
				assert(h2 > 0);
 
				p = b;
 

	
 
				while (right != w) {
 
					byte *p2 = ++p;
 
					int h = h2;
 
					// Check if a full line of dirty flags is set.
 
					/* Check if a full line of dirty flags is set. */
 
					do {
 
						if (!*p2) goto no_more_coalesc;
 
						p2 += DIRTY_BYTES_PER_LINE;
 
					} while (--h != 0);
 

	
 
					// Wohoo, can combine it one step to the right!
 
					// Do that, and clear the bits.
 
					/* Wohoo, can combine it one step to the right!
 
					 * Do that, and clear the bits. */
 
					right += 64;
 

	
 
					h = h2;
 
					p2 = p;
 
					do {
 
						*p2 = 0;
 
						p2 += DIRTY_BYTES_PER_LINE;
 
					} while (--h != 0);
 
				}
 
				no_more_coalesc:
 

	
 
				left = x;
 
@@ -1996,27 +1998,27 @@ static void SwitchAnimatedCursor(void)
 
	_cursor.animate_timeout = cur->display_time;
 
	_cursor.animate_cur     = cur + 1;
 
}
 

	
 
void CursorTick(void)
 
{
 
	if (_cursor.animate_timeout != 0 && --_cursor.animate_timeout == 0)
 
		SwitchAnimatedCursor();
 
}
 

	
 
void SetMouseCursor(SpriteID sprite, SpriteID pal)
 
{
 
	// Turn off animation
 
	/* Turn off animation */
 
	_cursor.animate_timeout = 0;
 
	// Set cursor
 
	/* Set cursor */
 
	SetCursorSprite(sprite, pal);
 
}
 

	
 
void SetAnimatedMouseCursor(const AnimCursor *table)
 
{
 
	_cursor.animate_list = table;
 
	_cursor.animate_cur = NULL;
 
	_cursor.pal = PAL_NONE;
 
	SwitchAnimatedCursor();
 
}
 

	
 
bool ChangeResInGame(int w, int h)