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);
231 select_mouse_cursor(MOUSE_CURSOR_NONE);
233 disable_hardware_cursor();
238 std::vector<int> rates = {};
240 int refresh_rate = get_refresh_rate();
241 if (refresh_rate != 0) rates.push_back(refresh_rate);
246struct AllegroVkMapping {
252#define AS(x, z) {x, 1, z}
253#define AM(x, y, z, w) {x, y - x + 1, z}
255static const AllegroVkMapping _vk_mapping[] = {
257 AM(KEY_PGUP, KEY_PGDN, WKC_PAGEUP, WKC_PAGEDOWN),
259 AS(KEY_DOWN, WKC_DOWN),
260 AS(KEY_LEFT, WKC_LEFT),
261 AS(KEY_RIGHT, WKC_RIGHT),
263 AS(KEY_HOME, WKC_HOME),
264 AS(KEY_END, WKC_END),
266 AS(KEY_INSERT, WKC_INSERT),
267 AS(KEY_DEL, WKC_DELETE),
270 AM(KEY_A, KEY_Z,
'A',
'Z'),
271 AM(KEY_0, KEY_9,
'0',
'9'),
273 AS(KEY_ESC, WKC_ESC),
274 AS(KEY_PAUSE, WKC_PAUSE),
275 AS(KEY_BACKSPACE, WKC_BACKSPACE),
277 AS(KEY_SPACE, WKC_SPACE),
278 AS(KEY_ENTER, WKC_RETURN),
279 AS(KEY_TAB, WKC_TAB),
282 AM(KEY_F1, KEY_F12, WKC_F1, WKC_F12),
285 AM(KEY_0_PAD, KEY_9_PAD,
'0',
'9'),
286 AS(KEY_SLASH_PAD, WKC_NUM_DIV),
287 AS(KEY_ASTERISK, WKC_NUM_MUL),
288 AS(KEY_MINUS_PAD, WKC_NUM_MINUS),
289 AS(KEY_PLUS_PAD, WKC_NUM_PLUS),
290 AS(KEY_ENTER_PAD, WKC_NUM_ENTER),
291 AS(KEY_DEL_PAD, WKC_DELETE),
305 AS(KEY_TILDE, WKC_BACKQUOTE),
308static uint32_t ConvertAllegroKeyIntoMy(
char32_t *character)
311 int unicode = ureadkey(&scancode);
315 for (
const auto &map : _vk_mapping) {
316 if (
IsInsideBS(scancode, map.vk_from, map.vk_count)) {
317 key = scancode - map.vk_from + map.map_to;
322 if (key_shifts & KB_SHIFT_FLAG) key |= WKC_SHIFT;
323 if (key_shifts & KB_CTRL_FLAG) key |= WKC_CTRL;
324 if (key_shifts & KB_ALT_FLAG) key |= WKC_ALT;
326 Debug(driver, 0,
"Scancode character pressed {}", scancode);
327 Debug(driver, 0,
"Unicode character pressed {}", unicode);
330 *character = unicode;
334static const uint LEFT_BUTTON = 0;
335static const uint RIGHT_BUTTON = 1;
341 bool mouse_action =
false;
344 static int prev_button_state;
345 if (prev_button_state != mouse_b) {
346 uint diff = prev_button_state ^ mouse_b;
350 if (
HasBit(mouse_b, button)) {
353 button = RIGHT_BUTTON;
354 ClrBit(diff, RIGHT_BUTTON);
376 }
else if (button == LEFT_BUTTON) {
379 }
else if (button == RIGHT_BUTTON) {
384 prev_button_state = mouse_b;
390 position_mouse(_cursor.
pos.
x, _cursor.
pos.
y);
392 if (_cursor.
delta.
x != 0 || _cursor.
delta.
y) mouse_action =
true;
394 static int prev_mouse_z = 0;
395 if (prev_mouse_z != mouse_z) {
396 _cursor.
wheel = (prev_mouse_z - mouse_z) < 0 ? -1 : 1;
397 prev_mouse_z = mouse_z;
404 if ((key_shifts & KB_ALT_FLAG) && (key[KEY_ENTER] || key[KEY_F])) {
405 ToggleFullScreen(!_fullscreen);
406 }
else if (keypressed()) {
408 uint keycode = ConvertAllegroKeyIntoMy(&character);
419int _allegro_instance_count = 0;
423 if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno,
nullptr)) {
424 Debug(driver, 0,
"allegro: install_allegro failed '{}'", allegro_error);
425 return "Failed to set up Allegro";
427 _allegro_instance_count++;
438 signal(SIGABRT,
nullptr);
439 signal(SIGSEGV,
nullptr);
444 return "Failed to set up Allegro video";
447 set_close_button_callback(HandleExitGameRequest);
456 if (--_allegro_instance_count == 0) allegro_exit();
472 (key[KEY_LEFT] ? 1 : 0) |
473 (key[KEY_UP] ? 2 : 0) |
474 (key[KEY_RIGHT] ? 4 : 0) |
475 (key[KEY_DOWN] ? 8 : 0);
485 if (_exit_game)
break;
496 return CreateMainSurface(w, h);
501 _fullscreen = fullscreen;
513 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.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
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).
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.
void ClaimMousePointer() override
Claim the exclusive rights for the mouse pointer.
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.
static Palette _local_palette
Current palette to use for drawing.
#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.
Error reporting related functions.
Factory to 'query' all available blitters.
Types for recording game performance data.
@ 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?
Functions related to the gfx engine.
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.
Functions related to modal progress.
Pseudo random number generator.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
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.
int first_dirty
The first dirty element.
int count_dirty
The number of dirty elements.
Specification of a rectangle with an absolute top-left coordinate and a (relative) width/height.
Window functions not directly related to making/drawing windows.