# Conflicts: # cmake/CompileFlags.cmake # src/aircraft_cmd.cpp # src/blitter/32bpp_anim.cpp # src/cargopacket.cpp # src/cheat_gui.cpp # src/company_cmd.cpp # src/company_gui.cpp # src/core/pool_func.hpp # src/date.cpp # src/economy.cpp # src/error_gui.cpp # src/ground_vehicle.cpp # src/ground_vehicle.hpp # src/group_gui.cpp # src/industry_cmd.cpp # src/lang/dutch.txt # src/lang/french.txt # src/lang/german.txt # src/linkgraph/linkgraph_gui.cpp # src/linkgraph/mcf.cpp # src/network/network_content.cpp # src/network/network_server.cpp # src/network/network_udp.cpp # src/newgrf_engine.cpp # src/newgrf_station.cpp # src/order_cmd.cpp # src/order_gui.cpp # src/pathfinder/follow_track.hpp # src/pathfinder/yapf/yapf_common.hpp # src/saveload/saveload.cpp # src/settings_gui.cpp # src/station_cmd.cpp # src/station_kdtree.h # src/string_func.h # src/table/settings.ini # src/tgp.cpp # src/timetable_cmd.cpp # src/timetable_gui.cpp # src/toolbar_gui.cpp # src/town_cmd.cpp # src/train_cmd.cpp # src/train_gui.cpp # src/tree_gui.cpp # src/tunnelbridge_cmd.cpp # src/vehicle.cpp # src/vehicle_gui.cpp # src/video/sdl2_v.cpp # src/video/sdl_v.cpp # src/video/win32_v.cpp # src/viewport.cpp # src/viewport_sprite_sorter_sse4.cpp # src/window.cpp
		
			
				
	
	
		
			552 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			552 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * 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 allegro_v.cpp Implementation of the Allegro video driver.
 | 
						|
 * @note Implementing threaded pushing of data to the display is
 | 
						|
 *       not faster (it's a few percent slower) in contrast to the
 | 
						|
 *       results gained with threading it for SDL.
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef WITH_ALLEGRO
 | 
						|
 | 
						|
#include "../stdafx.h"
 | 
						|
#include "../openttd.h"
 | 
						|
#include "../gfx_func.h"
 | 
						|
#include "../rev.h"
 | 
						|
#include "../blitter/factory.hpp"
 | 
						|
#include "../network/network.h"
 | 
						|
#include "../core/random_func.hpp"
 | 
						|
#include "../core/math_func.hpp"
 | 
						|
#include "../framerate_type.h"
 | 
						|
#include "../thread.h"
 | 
						|
#include "allegro_v.h"
 | 
						|
#include <allegro.h>
 | 
						|
 | 
						|
#include "../safeguards.h"
 | 
						|
 | 
						|
#ifdef _DEBUG
 | 
						|
/* Allegro replaces SEGV/ABRT signals meaning that the debugger will never
 | 
						|
 * be triggered, so rereplace the signals and make the debugger useful. */
 | 
						|
#include <signal.h>
 | 
						|
#endif
 | 
						|
 | 
						|
static FVideoDriver_Allegro iFVideoDriver_Allegro;
 | 
						|
 | 
						|
static BITMAP *_allegro_screen;
 | 
						|
 | 
						|
#define MAX_DIRTY_RECTS 100
 | 
						|
static PointDimension _dirty_rects[MAX_DIRTY_RECTS];
 | 
						|
static int _num_dirty_rects;
 | 
						|
 | 
						|
void VideoDriver_Allegro::MakeDirty(int left, int top, int width, int height)
 | 
						|
{
 | 
						|
	if (_num_dirty_rects < MAX_DIRTY_RECTS) {
 | 
						|
		_dirty_rects[_num_dirty_rects].x = left;
 | 
						|
		_dirty_rects[_num_dirty_rects].y = top;
 | 
						|
		_dirty_rects[_num_dirty_rects].width = width;
 | 
						|
		_dirty_rects[_num_dirty_rects].height = height;
 | 
						|
	}
 | 
						|
	_num_dirty_rects++;
 | 
						|
}
 | 
						|
 | 
						|
static void DrawSurfaceToScreen()
 | 
						|
{
 | 
						|
	PerformanceMeasurer framerate(PFE_VIDEO);
 | 
						|
 | 
						|
	int n = _num_dirty_rects;
 | 
						|
	if (n == 0) return;
 | 
						|
 | 
						|
	_num_dirty_rects = 0;
 | 
						|
	if (n > MAX_DIRTY_RECTS) {
 | 
						|
		blit(_allegro_screen, screen, 0, 0, 0, 0, _allegro_screen->w, _allegro_screen->h);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	for (int i = 0; i < n; i++) {
 | 
						|
		blit(_allegro_screen, screen, _dirty_rects[i].x, _dirty_rects[i].y, _dirty_rects[i].x, _dirty_rects[i].y, _dirty_rects[i].width, _dirty_rects[i].height);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void UpdatePalette(uint start, uint count)
 | 
						|
{
 | 
						|
	static PALETTE pal;
 | 
						|
 | 
						|
	uint end = start + count;
 | 
						|
	for (uint i = start; i != end; i++) {
 | 
						|
		pal[i].r = _cur_palette.palette[i].r / 4;
 | 
						|
		pal[i].g = _cur_palette.palette[i].g / 4;
 | 
						|
		pal[i].b = _cur_palette.palette[i].b / 4;
 | 
						|
		pal[i].filler = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	set_palette_range(pal, start, end - 1, 1);
 | 
						|
}
 | 
						|
 | 
						|
static void InitPalette()
 | 
						|
{
 | 
						|
	UpdatePalette(0, 256);
 | 
						|
}
 | 
						|
 | 
						|
static void CheckPaletteAnim()
 | 
						|
{
 | 
						|
	if (_cur_palette.count_dirty != 0) {
 | 
						|
		Blitter *blitter = BlitterFactory::GetCurrentBlitter();
 | 
						|
 | 
						|
		switch (blitter->UsePaletteAnimation()) {
 | 
						|
			case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
 | 
						|
				UpdatePalette(_cur_palette.first_dirty, _cur_palette.count_dirty);
 | 
						|
				break;
 | 
						|
 | 
						|
			case Blitter::PALETTE_ANIMATION_BLITTER:
 | 
						|
				blitter->PaletteAnimate(_cur_palette);
 | 
						|
				break;
 | 
						|
 | 
						|
			case Blitter::PALETTE_ANIMATION_NONE:
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				NOT_REACHED();
 | 
						|
		}
 | 
						|
		_cur_palette.count_dirty = 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static const Dimension default_resolutions[] = {
 | 
						|
	{ 640,  480},
 | 
						|
	{ 800,  600},
 | 
						|
	{1024,  768},
 | 
						|
	{1152,  864},
 | 
						|
	{1280,  800},
 | 
						|
	{1280,  960},
 | 
						|
	{1280, 1024},
 | 
						|
	{1400, 1050},
 | 
						|
	{1600, 1200},
 | 
						|
	{1680, 1050},
 | 
						|
	{1920, 1200}
 | 
						|
};
 | 
						|
 | 
						|
static void GetVideoModes()
 | 
						|
{
 | 
						|
	/* Need to set a gfx_mode as there is NO other way to autodetect for
 | 
						|
	 * cards ourselves... and we need a card to get the modes. */
 | 
						|
	set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
 | 
						|
 | 
						|
	_resolutions.clear();
 | 
						|
 | 
						|
	GFX_MODE_LIST *mode_list = get_gfx_mode_list(gfx_driver->id);
 | 
						|
	if (mode_list == nullptr) {
 | 
						|
		_resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	GFX_MODE *modes = mode_list->mode;
 | 
						|
 | 
						|
	for (int i = 0; modes[i].bpp != 0; i++) {
 | 
						|
		uint w = modes[i].width;
 | 
						|
		uint h = modes[i].height;
 | 
						|
		if (w < 640 || h < 480) continue;
 | 
						|
		if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(w, h)) != _resolutions.end()) continue;
 | 
						|
		_resolutions.emplace_back(w, h);
 | 
						|
	}
 | 
						|
 | 
						|
	SortResolutions();
 | 
						|
 | 
						|
	destroy_gfx_mode_list(mode_list);
 | 
						|
}
 | 
						|
 | 
						|
static void GetAvailableVideoMode(uint *w, uint *h)
 | 
						|
{
 | 
						|
	/* No video modes, so just try it and see where it ends */
 | 
						|
	if (_resolutions.empty()) return;
 | 
						|
 | 
						|
	/* is the wanted mode among the available modes? */
 | 
						|
	if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(*w, *h)) != _resolutions.end()) return;
 | 
						|
 | 
						|
	/* use the closest possible resolution */
 | 
						|
	uint best = 0;
 | 
						|
	uint delta = Delta(_resolutions[0].width, *w) * Delta(_resolutions[0].height, *h);
 | 
						|
	for (uint i = 1; i != _resolutions.size(); ++i) {
 | 
						|
		uint newdelta = Delta(_resolutions[i].width, *w) * Delta(_resolutions[i].height, *h);
 | 
						|
		if (newdelta < delta) {
 | 
						|
			best = i;
 | 
						|
			delta = newdelta;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	*w = _resolutions[best].width;
 | 
						|
	*h = _resolutions[best].height;
 | 
						|
}
 | 
						|
 | 
						|
static bool CreateMainSurface(uint w, uint h)
 | 
						|
{
 | 
						|
	int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 | 
						|
	if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals");
 | 
						|
	set_color_depth(bpp);
 | 
						|
 | 
						|
	GetAvailableVideoMode(&w, &h);
 | 
						|
	if (set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, w, h, 0, 0) != 0) {
 | 
						|
		DEBUG(driver, 0, "Allegro: Couldn't allocate a window to draw on '%s'", allegro_error);
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	/* The size of the screen might be bigger than the part we can actually draw on!
 | 
						|
	 * So calculate the size based on the top, bottom, left and right */
 | 
						|
	_allegro_screen = create_bitmap_ex(bpp, screen->cr - screen->cl, screen->cb - screen->ct);
 | 
						|
	_screen.width = _allegro_screen->w;
 | 
						|
	_screen.height = _allegro_screen->h;
 | 
						|
	_screen.pitch = ((byte*)screen->line[1] - (byte*)screen->line[0]) / (bpp / 8);
 | 
						|
	_screen.dst_ptr = _allegro_screen->line[0];
 | 
						|
 | 
						|
	/* Initialise the screen so we don't blit garbage to the screen */
 | 
						|
	memset(_screen.dst_ptr, 0, _screen.height * _screen.pitch);
 | 
						|
 | 
						|
	/* Set the mouse at the place where we expect it */
 | 
						|
	poll_mouse();
 | 
						|
	_cursor.pos.x = mouse_x;
 | 
						|
	_cursor.pos.y = mouse_y;
 | 
						|
 | 
						|
	BlitterFactory::GetCurrentBlitter()->PostResize();
 | 
						|
 | 
						|
	InitPalette();
 | 
						|
 | 
						|
	char caption[32];
 | 
						|
	seprintf(caption, lastof(caption), "OpenTTD %s", _openttd_revision);
 | 
						|
	set_window_title(caption);
 | 
						|
 | 
						|
	enable_hardware_cursor();
 | 
						|
	select_mouse_cursor(MOUSE_CURSOR_ARROW);
 | 
						|
	show_mouse(_allegro_screen);
 | 
						|
 | 
						|
	GameSizeChanged();
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
bool VideoDriver_Allegro::ClaimMousePointer()
 | 
						|
{
 | 
						|
	select_mouse_cursor(MOUSE_CURSOR_NONE);
 | 
						|
	show_mouse(nullptr);
 | 
						|
	disable_hardware_cursor();
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
struct VkMapping {
 | 
						|
	uint16 vk_from;
 | 
						|
	byte vk_count;
 | 
						|
	byte map_to;
 | 
						|
};
 | 
						|
 | 
						|
#define AS(x, z) {x, 0, z}
 | 
						|
#define AM(x, y, z, w) {x, y - x, z}
 | 
						|
 | 
						|
static const VkMapping _vk_mapping[] = {
 | 
						|
	/* Pageup stuff + up/down */
 | 
						|
	AM(KEY_PGUP, KEY_PGDN, WKC_PAGEUP, WKC_PAGEDOWN),
 | 
						|
	AS(KEY_UP,     WKC_UP),
 | 
						|
	AS(KEY_DOWN,   WKC_DOWN),
 | 
						|
	AS(KEY_LEFT,   WKC_LEFT),
 | 
						|
	AS(KEY_RIGHT,  WKC_RIGHT),
 | 
						|
 | 
						|
	AS(KEY_HOME,   WKC_HOME),
 | 
						|
	AS(KEY_END,    WKC_END),
 | 
						|
 | 
						|
	AS(KEY_INSERT, WKC_INSERT),
 | 
						|
	AS(KEY_DEL,    WKC_DELETE),
 | 
						|
 | 
						|
	/* Map letters & digits */
 | 
						|
	AM(KEY_A, KEY_Z, 'A', 'Z'),
 | 
						|
	AM(KEY_0, KEY_9, '0', '9'),
 | 
						|
 | 
						|
	AS(KEY_ESC,       WKC_ESC),
 | 
						|
	AS(KEY_PAUSE,     WKC_PAUSE),
 | 
						|
	AS(KEY_BACKSPACE, WKC_BACKSPACE),
 | 
						|
 | 
						|
	AS(KEY_SPACE,     WKC_SPACE),
 | 
						|
	AS(KEY_ENTER,     WKC_RETURN),
 | 
						|
	AS(KEY_TAB,       WKC_TAB),
 | 
						|
 | 
						|
	/* Function keys */
 | 
						|
	AM(KEY_F1, KEY_F12, WKC_F1, WKC_F12),
 | 
						|
 | 
						|
	/* Numeric part. */
 | 
						|
	AM(KEY_0_PAD, KEY_9_PAD, '0', '9'),
 | 
						|
	AS(KEY_SLASH_PAD,   WKC_NUM_DIV),
 | 
						|
	AS(KEY_ASTERISK,    WKC_NUM_MUL),
 | 
						|
	AS(KEY_MINUS_PAD,   WKC_NUM_MINUS),
 | 
						|
	AS(KEY_PLUS_PAD,    WKC_NUM_PLUS),
 | 
						|
	AS(KEY_ENTER_PAD,   WKC_NUM_ENTER),
 | 
						|
	AS(KEY_DEL_PAD,     WKC_DELETE),
 | 
						|
 | 
						|
	/* Other non-letter keys */
 | 
						|
	AS(KEY_SLASH,        WKC_SLASH),
 | 
						|
	AS(KEY_SEMICOLON,    WKC_SEMICOLON),
 | 
						|
	AS(KEY_EQUALS,       WKC_EQUALS),
 | 
						|
	AS(KEY_OPENBRACE,    WKC_L_BRACKET),
 | 
						|
	AS(KEY_BACKSLASH,    WKC_BACKSLASH),
 | 
						|
	AS(KEY_CLOSEBRACE,   WKC_R_BRACKET),
 | 
						|
 | 
						|
	AS(KEY_QUOTE,   WKC_SINGLEQUOTE),
 | 
						|
	AS(KEY_COMMA,   WKC_COMMA),
 | 
						|
	AS(KEY_MINUS,   WKC_MINUS),
 | 
						|
	AS(KEY_STOP,    WKC_PERIOD),
 | 
						|
	AS(KEY_TILDE,   WKC_BACKQUOTE),
 | 
						|
};
 | 
						|
 | 
						|
static uint32 ConvertAllegroKeyIntoMy(WChar *character)
 | 
						|
{
 | 
						|
	int scancode;
 | 
						|
	int unicode = ureadkey(&scancode);
 | 
						|
 | 
						|
	const VkMapping *map;
 | 
						|
	uint key = 0;
 | 
						|
 | 
						|
	for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
 | 
						|
		if ((uint)(scancode - map->vk_from) <= map->vk_count) {
 | 
						|
			key = scancode - map->vk_from + map->map_to;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (key_shifts & KB_SHIFT_FLAG) key |= WKC_SHIFT;
 | 
						|
	if (key_shifts & KB_CTRL_FLAG)  key |= WKC_CTRL;
 | 
						|
	if (key_shifts & KB_ALT_FLAG)   key |= WKC_ALT;
 | 
						|
#if 0
 | 
						|
	DEBUG(driver, 0, "Scancode character pressed %u", scancode);
 | 
						|
	DEBUG(driver, 0, "Unicode character pressed %u", unicode);
 | 
						|
#endif
 | 
						|
 | 
						|
	*character = unicode;
 | 
						|
	return key;
 | 
						|
}
 | 
						|
 | 
						|
static const uint LEFT_BUTTON  = 0;
 | 
						|
static const uint RIGHT_BUTTON = 1;
 | 
						|
 | 
						|
static void PollEvent()
 | 
						|
{
 | 
						|
	poll_mouse();
 | 
						|
 | 
						|
	bool mouse_action = false;
 | 
						|
 | 
						|
	/* Mouse buttons */
 | 
						|
	static int prev_button_state;
 | 
						|
	if (prev_button_state != mouse_b) {
 | 
						|
		uint diff = prev_button_state ^ mouse_b;
 | 
						|
		while (diff != 0) {
 | 
						|
			uint button = FindFirstBit(diff);
 | 
						|
			ClrBit(diff, button);
 | 
						|
			if (HasBit(mouse_b, button)) {
 | 
						|
				/* Pressed mouse button */
 | 
						|
				if (_rightclick_emulate && (key_shifts & KB_CTRL_FLAG)) {
 | 
						|
					button = RIGHT_BUTTON;
 | 
						|
					ClrBit(diff, RIGHT_BUTTON);
 | 
						|
				}
 | 
						|
				switch (button) {
 | 
						|
					case LEFT_BUTTON:
 | 
						|
						_left_button_down = true;
 | 
						|
						break;
 | 
						|
 | 
						|
					case RIGHT_BUTTON:
 | 
						|
						_right_button_down = true;
 | 
						|
						_right_button_clicked = true;
 | 
						|
						break;
 | 
						|
 | 
						|
					default:
 | 
						|
						/* ignore rest */
 | 
						|
						break;
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				/* Released mouse button */
 | 
						|
				if (_rightclick_emulate) {
 | 
						|
					_right_button_down = false;
 | 
						|
					_left_button_down = false;
 | 
						|
					_left_button_clicked = false;
 | 
						|
				} else if (button == LEFT_BUTTON) {
 | 
						|
					_left_button_down = false;
 | 
						|
					_left_button_clicked = false;
 | 
						|
				} else if (button == RIGHT_BUTTON) {
 | 
						|
					_right_button_down = false;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		prev_button_state = mouse_b;
 | 
						|
		mouse_action = true;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Mouse movement */
 | 
						|
	if (_cursor.UpdateCursorPosition(mouse_x, mouse_y, false)) {
 | 
						|
		position_mouse(_cursor.pos.x, _cursor.pos.y);
 | 
						|
	}
 | 
						|
	if (_cursor.delta.x != 0 || _cursor.delta.y) mouse_action = true;
 | 
						|
 | 
						|
	static int prev_mouse_z = 0;
 | 
						|
	if (prev_mouse_z != mouse_z) {
 | 
						|
		_cursor.wheel = (prev_mouse_z - mouse_z) < 0 ? -1 : 1;
 | 
						|
		prev_mouse_z = mouse_z;
 | 
						|
		mouse_action = true;
 | 
						|
	}
 | 
						|
 | 
						|
	if (mouse_action) HandleMouseEvents();
 | 
						|
 | 
						|
	poll_keyboard();
 | 
						|
	if ((key_shifts & KB_ALT_FLAG) && (key[KEY_ENTER] || key[KEY_F])) {
 | 
						|
		ToggleFullScreen(!_fullscreen);
 | 
						|
	} else if (keypressed()) {
 | 
						|
		WChar character;
 | 
						|
		uint keycode = ConvertAllegroKeyIntoMy(&character);
 | 
						|
		HandleKeypress(keycode, character);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * There are multiple modules that might be using Allegro and
 | 
						|
 * Allegro can only be initiated once.
 | 
						|
 */
 | 
						|
int _allegro_instance_count = 0;
 | 
						|
 | 
						|
const char *VideoDriver_Allegro::Start(const StringList &parm)
 | 
						|
{
 | 
						|
	if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) {
 | 
						|
		DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error);
 | 
						|
		return "Failed to set up Allegro";
 | 
						|
	}
 | 
						|
	_allegro_instance_count++;
 | 
						|
 | 
						|
	install_timer();
 | 
						|
	install_mouse();
 | 
						|
	install_keyboard();
 | 
						|
 | 
						|
#if defined _DEBUG
 | 
						|
/* Allegro replaces SEGV/ABRT signals meaning that the debugger will never
 | 
						|
 * be triggered, so rereplace the signals and make the debugger useful. */
 | 
						|
	signal(SIGABRT, nullptr);
 | 
						|
	signal(SIGSEGV, nullptr);
 | 
						|
#endif
 | 
						|
 | 
						|
	GetVideoModes();
 | 
						|
	if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height)) {
 | 
						|
		return "Failed to set up Allegro video";
 | 
						|
	}
 | 
						|
	MarkWholeScreenDirty();
 | 
						|
	set_close_button_callback(HandleExitGameRequest);
 | 
						|
 | 
						|
	return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void VideoDriver_Allegro::Stop()
 | 
						|
{
 | 
						|
	if (--_allegro_instance_count == 0) allegro_exit();
 | 
						|
}
 | 
						|
 | 
						|
#if defined(UNIX) || defined(__OS2__)
 | 
						|
# include <sys/time.h> /* gettimeofday */
 | 
						|
 | 
						|
static uint32 GetTime()
 | 
						|
{
 | 
						|
	struct timeval tim;
 | 
						|
 | 
						|
	gettimeofday(&tim, nullptr);
 | 
						|
	return tim.tv_usec / 1000 + tim.tv_sec * 1000;
 | 
						|
}
 | 
						|
#else
 | 
						|
static uint32 GetTime()
 | 
						|
{
 | 
						|
	return GetTickCount();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
void VideoDriver_Allegro::MainLoop()
 | 
						|
{
 | 
						|
	uint32 cur_ticks = GetTime();
 | 
						|
	uint32 last_cur_ticks = cur_ticks;
 | 
						|
	uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK;
 | 
						|
 | 
						|
	CheckPaletteAnim();
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
 | 
						|
		InteractiveRandom(); // randomness
 | 
						|
 | 
						|
		PollEvent();
 | 
						|
		if (_exit_game) return;
 | 
						|
 | 
						|
#if defined(_DEBUG)
 | 
						|
		if (_shift_pressed)
 | 
						|
#else
 | 
						|
		/* Speedup when pressing tab, except when using ALT+TAB
 | 
						|
		 * to switch to another application */
 | 
						|
		if (key[KEY_TAB] && (key_shifts & KB_ALT_FLAG) == 0)
 | 
						|
#endif
 | 
						|
		{
 | 
						|
			if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
 | 
						|
		} else if (_fast_forward & 2) {
 | 
						|
			_fast_forward = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		cur_ticks = GetTime();
 | 
						|
		if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) {
 | 
						|
			_realtime_tick += cur_ticks - last_cur_ticks;
 | 
						|
			last_cur_ticks = cur_ticks;
 | 
						|
			next_tick = cur_ticks + MILLISECONDS_PER_TICK;
 | 
						|
 | 
						|
			bool old_ctrl_pressed = _ctrl_pressed;
 | 
						|
			bool old_shift_pressed = _shift_pressed;
 | 
						|
 | 
						|
			_ctrl_pressed  = !!(key_shifts & KB_CTRL_FLAG) != _invert_ctrl;
 | 
						|
			_shift_pressed = !!(key_shifts & KB_SHIFT_FLAG) != _invert_shift;
 | 
						|
 | 
						|
			/* determine which directional keys are down */
 | 
						|
			_dirkeys =
 | 
						|
				(key[KEY_LEFT]  ? 1 : 0) |
 | 
						|
				(key[KEY_UP]    ? 2 : 0) |
 | 
						|
				(key[KEY_RIGHT] ? 4 : 0) |
 | 
						|
				(key[KEY_DOWN]  ? 8 : 0);
 | 
						|
 | 
						|
			if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
 | 
						|
			if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
 | 
						|
 | 
						|
			GameLoop();
 | 
						|
			GameLoopPaletteAnimations();
 | 
						|
 | 
						|
			UpdateWindows();
 | 
						|
			CheckPaletteAnim();
 | 
						|
			DrawSurfaceToScreen();
 | 
						|
		} else {
 | 
						|
			CSleep(1);
 | 
						|
			NetworkDrawChatMessage();
 | 
						|
			DrawMouseCursor();
 | 
						|
			DrawSurfaceToScreen();
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
bool VideoDriver_Allegro::ChangeResolution(int w, int h)
 | 
						|
{
 | 
						|
	return CreateMainSurface(w, h);
 | 
						|
}
 | 
						|
 | 
						|
bool VideoDriver_Allegro::ToggleFullscreen(bool fullscreen)
 | 
						|
{
 | 
						|
	_fullscreen = fullscreen;
 | 
						|
	GetVideoModes(); // get the list of available video modes
 | 
						|
	if (_resolutions.empty() || !this->ChangeResolution(_cur_resolution.width, _cur_resolution.height)) {
 | 
						|
		/* switching resolution failed, put back full_screen to original status */
 | 
						|
		_fullscreen ^= true;
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
bool VideoDriver_Allegro::AfterBlitterChange()
 | 
						|
{
 | 
						|
	return CreateMainSurface(_screen.width, _screen.height);
 | 
						|
}
 | 
						|
 | 
						|
#endif /* WITH_ALLEGRO */
 |