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;
44static size_t _num_dirty_rects;
49 if (_num_dirty_rects < std::size(_dirty_rects)) {
50 _dirty_rects[_num_dirty_rects].x = left;
51 _dirty_rects[_num_dirty_rects].y = top;
52 _dirty_rects[_num_dirty_rects].width = width;
53 _dirty_rects[_num_dirty_rects].height = height;
62 size_t n = _num_dirty_rects;
66 if (n > std::size(_dirty_rects)) {
67 blit(_allegro_screen, screen, 0, 0, 0, 0, _allegro_screen->w, _allegro_screen->h);
71 for (
size_t i = 0; i < n; i++) {
72 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);
77static void UpdatePalette(uint start, uint count)
81 uint end = start + count;
82 for (uint i = start; i != end; i++) {
89 set_palette_range(pal, start, end - 1, 1);
92static void InitPalette()
94 UpdatePalette(0, 256);
120static const Dimension default_resolutions[] = {
134static void GetVideoModes()
138 set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
142 GFX_MODE_LIST *mode_list = get_gfx_mode_list(gfx_driver->id);
143 if (mode_list ==
nullptr) {
144 _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
148 GFX_MODE *modes = mode_list->mode;
150 for (
int i = 0; modes[i].bpp != 0; i++) {
151 uint w = modes[i].width;
152 uint h = modes[i].height;
153 if (w < 640 || h < 480)
continue;
160 destroy_gfx_mode_list(mode_list);
163static void GetAvailableVideoMode(uint *w, uint *h)
176 if (newdelta < delta) {
185static bool CreateMainSurface(uint w, uint h)
188 if (bpp == 0) UserError(
"Can't use a blitter that blits 0 bpp for normal visuals");
189 set_color_depth(bpp);
191 GetAvailableVideoMode(&w, &h);
192 if (set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, w, h, 0, 0) != 0) {
193 Debug(driver, 0,
"Allegro: Couldn't allocate a window to draw on '{}'", allegro_error);
199 _allegro_screen = create_bitmap_ex(bpp, screen->cr - screen->cl, screen->cb - screen->ct);
200 _screen.width = _allegro_screen->w;
201 _screen.height = _allegro_screen->h;
202 _screen.pitch = ((uint8_t*)screen->line[1] - (uint8_t*)screen->line[0]) / (bpp / 8);
203 _screen.dst_ptr = _allegro_screen->line[0];
206 std::fill_n(
static_cast<std::byte *
>(_screen.dst_ptr),
static_cast<size_t>(_screen.height) * _screen.pitch,
static_cast<std::byte
>(0));
210 _cursor.
pos.x = mouse_x;
211 _cursor.
pos.y = mouse_y;
218 set_window_title(caption.c_str());
220 enable_hardware_cursor();
221 select_mouse_cursor(MOUSE_CURSOR_ARROW);
222 show_mouse(_allegro_screen);
229bool VideoDriver_Allegro::ClaimMousePointer()
231 select_mouse_cursor(MOUSE_CURSOR_NONE);
233 disable_hardware_cursor();
239 std::vector<int> rates = {};
241 int refresh_rate = get_refresh_rate();
242 if (refresh_rate != 0) rates.push_back(refresh_rate);
247struct AllegroVkMapping {
253#define AS(x, z) {x, 1, z}
254#define AM(x, y, z, w) {x, y - x + 1, z}
256static const AllegroVkMapping _vk_mapping[] = {
258 AM(KEY_PGUP, KEY_PGDN, WKC_PAGEUP, WKC_PAGEDOWN),
260 AS(KEY_DOWN, WKC_DOWN),
261 AS(KEY_LEFT, WKC_LEFT),
262 AS(KEY_RIGHT, WKC_RIGHT),
264 AS(KEY_HOME, WKC_HOME),
265 AS(KEY_END, WKC_END),
267 AS(KEY_INSERT, WKC_INSERT),
268 AS(KEY_DEL, WKC_DELETE),
271 AM(KEY_A, KEY_Z,
'A',
'Z'),
272 AM(KEY_0, KEY_9,
'0',
'9'),
274 AS(KEY_ESC, WKC_ESC),
275 AS(KEY_PAUSE, WKC_PAUSE),
276 AS(KEY_BACKSPACE, WKC_BACKSPACE),
278 AS(KEY_SPACE, WKC_SPACE),
279 AS(KEY_ENTER, WKC_RETURN),
280 AS(KEY_TAB, WKC_TAB),
283 AM(KEY_F1, KEY_F12, WKC_F1, WKC_F12),
286 AM(KEY_0_PAD, KEY_9_PAD,
'0',
'9'),
287 AS(KEY_SLASH_PAD, WKC_NUM_DIV),
288 AS(KEY_ASTERISK, WKC_NUM_MUL),
289 AS(KEY_MINUS_PAD, WKC_NUM_MINUS),
290 AS(KEY_PLUS_PAD, WKC_NUM_PLUS),
291 AS(KEY_ENTER_PAD, WKC_NUM_ENTER),
292 AS(KEY_DEL_PAD, WKC_DELETE),
306 AS(KEY_TILDE, WKC_BACKQUOTE),
309static uint32_t ConvertAllegroKeyIntoMy(
char32_t *character)
312 int unicode = ureadkey(&scancode);
316 for (
const auto &map : _vk_mapping) {
317 if (
IsInsideBS(scancode, map.vk_from, map.vk_count)) {
318 key = scancode - map.vk_from + map.map_to;
323 if (key_shifts & KB_SHIFT_FLAG) key |= WKC_SHIFT;
324 if (key_shifts & KB_CTRL_FLAG) key |= WKC_CTRL;
325 if (key_shifts & KB_ALT_FLAG) key |= WKC_ALT;
327 Debug(driver, 0,
"Scancode character pressed {}", scancode);
328 Debug(driver, 0,
"Unicode character pressed {}", unicode);
331 *character = unicode;
335static const uint LEFT_BUTTON = 0;
336static const uint RIGHT_BUTTON = 1;
342 bool mouse_action =
false;
345 static int prev_button_state;
346 if (prev_button_state != mouse_b) {
347 uint diff = prev_button_state ^ mouse_b;
351 if (
HasBit(mouse_b, button)) {
354 button = RIGHT_BUTTON;
355 ClrBit(diff, RIGHT_BUTTON);
377 }
else if (button == LEFT_BUTTON) {
380 }
else if (button == RIGHT_BUTTON) {
385 prev_button_state = mouse_b;
391 position_mouse(_cursor.
pos.x, _cursor.
pos.y);
393 if (_cursor.
delta.x != 0 || _cursor.
delta.y) mouse_action =
true;
395 static int prev_mouse_z = 0;
396 if (prev_mouse_z != mouse_z) {
397 _cursor.
wheel = (prev_mouse_z - mouse_z) < 0 ? -1 : 1;
398 prev_mouse_z = mouse_z;
405 if ((key_shifts & KB_ALT_FLAG) && (key[KEY_ENTER] || key[KEY_F])) {
406 ToggleFullScreen(!_fullscreen);
407 }
else if (keypressed()) {
409 uint keycode = ConvertAllegroKeyIntoMy(&character);
420int _allegro_instance_count = 0;
424 if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno,
nullptr)) {
425 Debug(driver, 0,
"allegro: install_allegro failed '{}'", allegro_error);
426 return "Failed to set up Allegro";
428 _allegro_instance_count++;
439 signal(SIGABRT,
nullptr);
440 signal(SIGSEGV,
nullptr);
445 return "Failed to set up Allegro video";
448 set_close_button_callback(HandleExitGameRequest);
457 if (--_allegro_instance_count == 0) allegro_exit();
473 (key[KEY_LEFT] ? 1 : 0) |
474 (key[KEY_UP] ? 2 : 0) |
475 (key[KEY_RIGHT] ? 4 : 0) |
476 (key[KEY_DOWN] ? 8 : 0);
486 if (_exit_game)
break;
497 return CreateMainSurface(w, h);
502 _fullscreen = fullscreen;
514 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.
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...
@ None
No palette animation.
@ Blitter
The blitter takes care of the palette animation.
@ VideoBackend
Palette animation should be done by video backend (8bpp only!)
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,...)
Output a line of debugging information.
bool GetDriverParamBool(const StringList &parm, std::string_view name)
Get a boolean parameter the list of parameters.
std::vector< Dimension > _resolutions
List of resolutions.
Dimension _cur_resolution
The current resolution.
bool _rightclick_emulate
Whether right clicking is emulated.
@ 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.
static Palette _local_palette
Current palette to use for drawing.