18#include "../openttd.h"
19#include "../error_func.h"
20#include "../gfx_func.h"
21#include "../blitter/factory.hpp"
22#include "../core/random_func.hpp"
23#include "../core/math_func.hpp"
24#include "../framerate_type.h"
25#include "../progress.h"
27#include "../window_func.h"
31#include "../safeguards.h"
41static BITMAP *_allegro_screen;
43#define MAX_DIRTY_RECTS 100
45static int _num_dirty_rects;
50 if (_num_dirty_rects < MAX_DIRTY_RECTS) {
51 _dirty_rects[_num_dirty_rects].x = left;
52 _dirty_rects[_num_dirty_rects].y = top;
53 _dirty_rects[_num_dirty_rects].width = width;
54 _dirty_rects[_num_dirty_rects].height = height;
63 int n = _num_dirty_rects;
67 if (n > MAX_DIRTY_RECTS) {
68 blit(_allegro_screen, screen, 0, 0, 0, 0, _allegro_screen->w, _allegro_screen->h);
72 for (
int i = 0; i < n; i++) {
73 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);
78static void UpdatePalette(uint start, uint count)
82 uint end = start + count;
83 for (uint i = start; i != end; i++) {
84 pal[i].r = _local_palette.
palette[i].r / 4;
85 pal[i].g = _local_palette.
palette[i].g / 4;
86 pal[i].b = _local_palette.
palette[i].
b / 4;
90 set_palette_range(pal, start, end - 1, 1);
93static void InitPalette()
95 UpdatePalette(0, 256);
121static const Dimension default_resolutions[] = {
135static void GetVideoModes()
139 set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
143 GFX_MODE_LIST *mode_list = get_gfx_mode_list(gfx_driver->id);
144 if (mode_list ==
nullptr) {
145 _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
149 GFX_MODE *modes = mode_list->mode;
151 for (
int i = 0; modes[i].bpp != 0; i++) {
152 uint w = modes[i].width;
153 uint h = modes[i].height;
154 if (w < 640 || h < 480)
continue;
161 destroy_gfx_mode_list(mode_list);
164static void GetAvailableVideoMode(uint *w, uint *h)
177 if (newdelta < delta) {
186static bool CreateMainSurface(uint w, uint h)
189 if (bpp == 0) UserError(
"Can't use a blitter that blits 0 bpp for normal visuals");
190 set_color_depth(bpp);
192 GetAvailableVideoMode(&w, &h);
193 if (set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, w, h, 0, 0) != 0) {
194 Debug(driver, 0,
"Allegro: Couldn't allocate a window to draw on '{}'", allegro_error);
200 _allegro_screen = create_bitmap_ex(bpp, screen->cr - screen->cl, screen->cb - screen->ct);
201 _screen.width = _allegro_screen->w;
202 _screen.height = _allegro_screen->h;
203 _screen.pitch = ((uint8_t*)screen->line[1] - (uint8_t*)screen->line[0]) / (bpp / 8);
204 _screen.dst_ptr = _allegro_screen->line[0];
207 memset(_screen.dst_ptr, 0,
static_cast<size_t>(_screen.height) * _screen.pitch);
211 _cursor.
pos.x = mouse_x;
212 _cursor.
pos.y = mouse_y;
219 set_window_title(caption.c_str());
221 enable_hardware_cursor();
222 select_mouse_cursor(MOUSE_CURSOR_ARROW);
223 show_mouse(_allegro_screen);
230bool VideoDriver_Allegro::ClaimMousePointer()
232 select_mouse_cursor(MOUSE_CURSOR_NONE);
234 disable_hardware_cursor();
240 std::vector<int> rates = {};
242 int refresh_rate = get_refresh_rate();
243 if (refresh_rate != 0) rates.push_back(refresh_rate);
248struct AllegroVkMapping {
254#define AS(x, z) {x, 1, z}
255#define AM(x, y, z, w) {x, y - x + 1, z}
257static const AllegroVkMapping _vk_mapping[] = {
259 AM(KEY_PGUP, KEY_PGDN, WKC_PAGEUP, WKC_PAGEDOWN),
261 AS(KEY_DOWN, WKC_DOWN),
262 AS(KEY_LEFT, WKC_LEFT),
263 AS(KEY_RIGHT, WKC_RIGHT),
265 AS(KEY_HOME, WKC_HOME),
266 AS(KEY_END, WKC_END),
268 AS(KEY_INSERT, WKC_INSERT),
269 AS(KEY_DEL, WKC_DELETE),
272 AM(KEY_A, KEY_Z,
'A',
'Z'),
273 AM(KEY_0, KEY_9,
'0',
'9'),
275 AS(KEY_ESC, WKC_ESC),
276 AS(KEY_PAUSE, WKC_PAUSE),
277 AS(KEY_BACKSPACE, WKC_BACKSPACE),
279 AS(KEY_SPACE, WKC_SPACE),
280 AS(KEY_ENTER, WKC_RETURN),
281 AS(KEY_TAB, WKC_TAB),
284 AM(KEY_F1, KEY_F12, WKC_F1, WKC_F12),
287 AM(KEY_0_PAD, KEY_9_PAD,
'0',
'9'),
288 AS(KEY_SLASH_PAD, WKC_NUM_DIV),
289 AS(KEY_ASTERISK, WKC_NUM_MUL),
290 AS(KEY_MINUS_PAD, WKC_NUM_MINUS),
291 AS(KEY_PLUS_PAD, WKC_NUM_PLUS),
292 AS(KEY_ENTER_PAD, WKC_NUM_ENTER),
293 AS(KEY_DEL_PAD, WKC_DELETE),
307 AS(KEY_TILDE, WKC_BACKQUOTE),
310static uint32_t ConvertAllegroKeyIntoMy(
char32_t *character)
313 int unicode = ureadkey(&scancode);
317 for (
const auto &map : _vk_mapping) {
318 if (
IsInsideBS(scancode, map.vk_from, map.vk_count)) {
319 key = scancode - map.vk_from + map.map_to;
324 if (key_shifts & KB_SHIFT_FLAG) key |= WKC_SHIFT;
325 if (key_shifts & KB_CTRL_FLAG) key |= WKC_CTRL;
326 if (key_shifts & KB_ALT_FLAG) key |= WKC_ALT;
328 Debug(driver, 0,
"Scancode character pressed {}", scancode);
329 Debug(driver, 0,
"Unicode character pressed {}", unicode);
332 *character = unicode;
336static const uint LEFT_BUTTON = 0;
337static const uint RIGHT_BUTTON = 1;
343 bool mouse_action =
false;
346 static int prev_button_state;
347 if (prev_button_state != mouse_b) {
348 uint diff = prev_button_state ^ mouse_b;
352 if (
HasBit(mouse_b, button)) {
355 button = RIGHT_BUTTON;
356 ClrBit(diff, RIGHT_BUTTON);
378 }
else if (button == LEFT_BUTTON) {
381 }
else if (button == RIGHT_BUTTON) {
386 prev_button_state = mouse_b;
392 position_mouse(_cursor.
pos.x, _cursor.
pos.y);
394 if (_cursor.
delta.x != 0 || _cursor.
delta.y) mouse_action =
true;
396 static int prev_mouse_z = 0;
397 if (prev_mouse_z != mouse_z) {
398 _cursor.
wheel = (prev_mouse_z - mouse_z) < 0 ? -1 : 1;
399 prev_mouse_z = mouse_z;
406 if ((key_shifts & KB_ALT_FLAG) && (key[KEY_ENTER] || key[KEY_F])) {
407 ToggleFullScreen(!_fullscreen);
408 }
else if (keypressed()) {
410 uint keycode = ConvertAllegroKeyIntoMy(&character);
421int _allegro_instance_count = 0;
425 if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno,
nullptr)) {
426 Debug(driver, 0,
"allegro: install_allegro failed '{}'", allegro_error);
427 return "Failed to set up Allegro";
429 _allegro_instance_count++;
440 signal(SIGABRT,
nullptr);
441 signal(SIGSEGV,
nullptr);
446 return "Failed to set up Allegro video";
449 set_close_button_callback(HandleExitGameRequest);
458 if (--_allegro_instance_count == 0) allegro_exit();
474 (key[KEY_LEFT] ? 1 : 0) |
475 (key[KEY_UP] ? 2 : 0) |
476 (key[KEY_RIGHT] ? 4 : 0) |
477 (key[KEY_DOWN] ? 8 : 0);
487 if (_exit_game)
break;
498 return CreateMainSurface(w, h);
503 _fullscreen = fullscreen;
515 return CreateMainSurface(_screen.width, _screen.height);
#define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview)
AirportSpec definition for airports with at least one depot.
Base of the Allegro video driver.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
How all blitters should look like.
virtual uint8_t GetScreenDepth()=0
Get the screen depth this blitter works for.
virtual Blitter::PaletteAnimation UsePaletteAnimation()=0
Check if the blitter uses palette animation at all.
@ PALETTE_ANIMATION_NONE
No palette animation.
@ PALETTE_ANIMATION_VIDEO_BACKEND
Palette animation should be done by video backend (8bpp only!)
@ PALETTE_ANIMATION_BLITTER
The blitter takes care of the palette animation.
virtual void PaletteAnimate(const Palette &palette)=0
Called when the 8bpp palette is changed; you should redraw all pixels on the screen that are equal to...
virtual void PostResize()
Post resize event.
Factory for the allegro video driver.
void MainLoop() override
Perform the actual drawing.
bool ToggleFullscreen(bool fullscreen) override
Change the full screen setting.
bool PollEvent() override
Process a single system event.
bool ChangeResolution(int w, int h) override
Change the resolution of the window.
void InputLoop() override
Handle input logic, is CTRL pressed, should we fast-forward, etc.
void MakeDirty(int left, int top, int width, int height) override
Mark a particular area dirty.
void Paint() override
Paint the window.
std::optional< std::string_view > Start(const StringList ¶m) override
Start this driver.
void Stop() override
Stop this driver.
void CheckPaletteAnim() override
Process any pending palette animation.
std::vector< int > GetListOfMonitorRefreshRates() override
Get a list of refresh rates of each available monitor.
bool AfterBlitterChange() override
Callback invoked after the blitter was changed.
bool fast_forward_key_pressed
The fast-forward key is being pressed.
void Tick()
Give the video-driver a tick.
void SleepTillNextTick()
Sleep till the next tick is about to happen.
void StartGameThread()
Start the loop for game-tick.
static std::string GetCaption()
Get the caption to use for the game's title bar.
void StopGameThread()
Stop the loop for the game-tick.
void UpdateAutoResolution()
Apply resolution auto-detection and clamp to sensible defaults.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
std::vector< Dimension > _resolutions
List of resolutions.
Dimension _cur_resolution
The current resolution.
bool _rightclick_emulate
Whether right clicking is emulated.
bool GetDriverParamBool(const StringList &parm, const char *name)
Get a boolean parameter the list of parameters.
@ PFE_VIDEO
Speed of painting drawn video buffer.
bool _shift_pressed
Is Shift pressed?
bool _left_button_down
Is left mouse button pressed?
bool _ctrl_pressed
Is Ctrl pressed?
uint8_t _dirkeys
1 = left, 2 = up, 4 = right, 8 = down
bool _left_button_clicked
Is left mouse button clicked?
bool _right_button_clicked
Is right mouse button clicked?
bool _right_button_down
Is right mouse button pressed?
void HandleCtrlChanged()
State of CONTROL key has changed.
void GameSizeChanged()
Size of the application screen changed.
void HandleMouseEvents()
Handle a mouse event from the video driver.
void HandleKeypress(uint keycode, char32_t key)
Handle keyboard input.
@ WKC_BACKSLASH
\ Backslash
@ WKC_SLASH
/ Forward slash
@ WKC_SINGLEQUOTE
' Single quote
@ WKC_R_BRACKET
] Right square bracket
@ WKC_L_BRACKET
[ Left square bracket
@ WKC_SEMICOLON
; Semicolon
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
bool CopyPalette(Palette &local_palette, bool force_copy)
Copy the current palette if the palette was updated.
std::vector< std::string > StringList
Type for a list of strings.
bool UpdateCursorPosition(int x, int y)
Update cursor position on mouse movement.
Point pos
logical mouse position
int wheel
mouse wheel movement
Point delta
relative mouse movement in this tick
Dimensions (a width and height) of a rectangle in 2D.
Information about the currently used palette.
int first_dirty
The first dirty element.
int count_dirty
The number of dirty elements.
Colour palette[256]
Current palette. Entry 0 has to be always fully transparent!
Specification of a rectangle with an absolute top-left coordinate and a (relative) width/height.
uint8_t b
colour channels in BE order