1// dear imgui: Renderer + Platform Backend for Allegro 5
2// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
3
4// Implemented features:
5// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
6// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
7// [X] Platform: Clipboard support (from Allegro 5.1.12).
8// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
9// Missing features or Issues:
10// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
11// [ ] Platform: Missing gamepad support.
12// [ ] Renderer: Multi-viewport support (multiple windows).
13
14// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
15// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
16// Learn about Dear ImGui:
17// - FAQ https://dearimgui.com/faq
18// - Getting Started https://dearimgui.com/getting-started
19// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
20// - Introduction, links and more at the top of imgui.cpp
21
22// CHANGELOG
23// (minor and older changes stripped away, please see git history for details)
24// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
25// 2025-01-06: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256).
26// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
27// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
28// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
29// 2022-11-30: Renderer: Restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5.
30// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
31// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
32// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
33// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
34// 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates.
35// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
36// 2021-12-08: Renderer: Fixed mishandling of the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86.
37// 2021-08-17: Calling io.AddFocusEvent() on ALLEGRO_EVENT_DISPLAY_SWITCH_OUT/ALLEGRO_EVENT_DISPLAY_SWITCH_IN events.
38// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
39// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
40// 2021-02-18: Change blending equation to preserve alpha in output buffer.
41// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
42// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
43// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
44// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter().
45// 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
46// 2018-11-30: Platform: Added touchscreen support.
47// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
48// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
49// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
50// 2018-06-13: Renderer: Stopped using al_draw_indexed_prim() as it is buggy in Allegro's DX9 backend.
51// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
52// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
53// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
54// 2018-04-18: Misc: Added support for 32-bit vertex indices to avoid conversion at runtime. Added imconfig_allegro5.h to enforce 32-bit indices when included from imgui.h.
55// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplAllegro5_RenderDrawData() in the .h file so you can call it yourself.
56// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
57// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
58
59#include "imgui.h"
60#ifndef IMGUI_DISABLE
61#include "imgui_impl_allegro5.h"
62#include <stdint.h> // uint64_t
63#include <cstring> // memcpy
64
65// Allegro
66#include <allegro5/allegro.h>
67#include <allegro5/allegro_primitives.h>
68#ifdef _WIN32
69#include <allegro5/allegro_windows.h>
70#endif
71#define ALLEGRO_HAS_CLIPBOARD ((ALLEGRO_VERSION_INT & ~ALLEGRO_UNSTABLE_BIT) >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
72#define ALLEGRO_HAS_DRAW_INDEXED_PRIM ((ALLEGRO_VERSION_INT & ~ALLEGRO_UNSTABLE_BIT) >= ((5 << 24) | (2 << 16) | ( 5 << 8))) // DX9 implementation of al_draw_indexed_prim() got fixed in Allegro 5.2.5
73
74// Visual Studio warnings
75#ifdef _MSC_VER
76#pragma warning (disable: 4127) // condition expression is constant
77#endif
78
79struct ImDrawVertAllegro
80{
81 ImVec2 pos;
82 ImVec2 uv;
83 ALLEGRO_COLOR col;
84};
85
86// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
87// FIXME-OPT: Consider inlining al_map_rgba()?
88// see https://github.com/liballeg/allegro5/blob/master/src/pixels.c#L554
89// and https://github.com/liballeg/allegro5/blob/master/include/allegro5/internal/aintern_pixels.h
90#define DRAW_VERT_IMGUI_TO_ALLEGRO(DST, SRC) { (DST)->pos = (SRC)->pos; (DST)->uv = (SRC)->uv; unsigned char* c = (unsigned char*)&(SRC)->col; (DST)->col = al_map_rgba(c[0], c[1], c[2], c[3]); }
91
92// Allegro Data
93struct ImGui_ImplAllegro5_Data
94{
95 ALLEGRO_DISPLAY* Display;
96 ALLEGRO_BITMAP* Texture;
97 double Time;
98 ALLEGRO_MOUSE_CURSOR* MouseCursorInvisible;
99 ALLEGRO_VERTEX_DECL* VertexDecl;
100 char* ClipboardTextData;
101 ImGuiMouseCursor LastCursor;
102
103 ImVector<ImDrawVertAllegro> BufVertices;
104 ImVector<int> BufIndices;
105
106 ImGui_ImplAllegro5_Data() { memset(s: (void*)this, c: 0, n: sizeof(*this)); }
107};
108
109// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
110// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
111// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
112static ImGui_ImplAllegro5_Data* ImGui_ImplAllegro5_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplAllegro5_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; }
113
114static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
115{
116 // Setup blending
117 al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
118
119 // Setup orthographic projection matrix
120 // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
121 {
122 float L = draw_data->DisplayPos.x;
123 float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
124 float T = draw_data->DisplayPos.y;
125 float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
126 ALLEGRO_TRANSFORM transform;
127 al_identity_transform(&transform);
128 al_use_transform(&transform);
129 al_orthographic_transform(&transform, L, T, 1.0f, R, B, -1.0f);
130 al_use_projection_transform(&transform);
131 }
132}
133
134// Render function.
135void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
136{
137 // Avoid rendering when minimized
138 if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
139 return;
140
141 // Backup Allegro state that will be modified
142 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
143 ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
144 ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
145 int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
146 al_get_clipping_rectangle(&last_clip_x, &last_clip_y, &last_clip_w, &last_clip_h);
147 int last_blender_op, last_blender_src, last_blender_dst;
148 al_get_blender(&last_blender_op, &last_blender_src, &last_blender_dst);
149
150 // Setup desired render state
151 ImGui_ImplAllegro5_SetupRenderState(draw_data);
152
153 // Render command lists
154 for (int n = 0; n < draw_data->CmdListsCount; n++)
155 {
156 const ImDrawList* draw_list = draw_data->CmdLists[n];
157
158 ImVector<ImDrawVertAllegro>& vertices = bd->BufVertices;
159#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
160 vertices.resize(draw_list->VtxBuffer.Size);
161 for (int i = 0; i < draw_list->VtxBuffer.Size; i++)
162 {
163 const ImDrawVert* src_v = &draw_list->VtxBuffer[i];
164 ImDrawVertAllegro* dst_v = &vertices[i];
165 DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v);
166 }
167 const int* indices = nullptr;
168 if (sizeof(ImDrawIdx) == 2)
169 {
170 // FIXME-OPT: Allegro doesn't support 16-bit indices.
171 // You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
172 // Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
173 bd->BufIndices.resize(draw_list->IdxBuffer.Size);
174 for (int i = 0; i < draw_list->IdxBuffer.Size; ++i)
175 bd->BufIndices[i] = (int)draw_list->IdxBuffer.Data[i];
176 indices = bd->BufIndices.Data;
177 }
178 else if (sizeof(ImDrawIdx) == 4)
179 {
180 indices = (const int*)draw_list->IdxBuffer.Data;
181 }
182#else
183 // Allegro's implementation of al_draw_indexed_prim() for DX9 was broken until 5.2.5. Unindex buffers ourselves while converting vertex format.
184 vertices.resize(new_size: draw_list->IdxBuffer.Size);
185 for (int i = 0; i < draw_list->IdxBuffer.Size; i++)
186 {
187 const ImDrawVert* src_v = &draw_list->VtxBuffer[draw_list->IdxBuffer[i]];
188 ImDrawVertAllegro* dst_v = &vertices[i];
189 DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v);
190 }
191#endif
192
193 // Render command lists
194 ImVec2 clip_off = draw_data->DisplayPos;
195 for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
196 {
197 const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
198 if (pcmd->UserCallback)
199 {
200 // User callback, registered via ImDrawList::AddCallback()
201 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
202 if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
203 ImGui_ImplAllegro5_SetupRenderState(draw_data);
204 else
205 pcmd->UserCallback(draw_list, pcmd);
206 }
207 else
208 {
209 // Project scissor/clipping rectangles into framebuffer space
210 ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
211 ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
212 if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
213 continue;
214
215 // Apply scissor/clipping rectangle, Draw
216 ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
217 al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
218#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
219 al_draw_indexed_prim(&vertices[0], bd->VertexDecl, texture, &indices[pcmd->IdxOffset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
220#else
221 al_draw_prim(&vertices[0], bd->VertexDecl, texture, pcmd->IdxOffset, pcmd->IdxOffset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
222#endif
223 }
224 }
225 }
226
227 // Restore modified Allegro state
228 al_set_blender(last_blender_op, last_blender_src, last_blender_dst);
229 al_set_clipping_rectangle(last_clip_x, last_clip_y, last_clip_w, last_clip_h);
230 al_use_transform(&last_transform);
231 al_use_projection_transform(&last_projection_transform);
232}
233
234bool ImGui_ImplAllegro5_CreateDeviceObjects()
235{
236 // Build texture atlas
237 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
238 ImGuiIO& io = ImGui::GetIO();
239 unsigned char* pixels;
240 int width, height;
241 io.Fonts->GetTexDataAsRGBA32(out_pixels: &pixels, out_width: &width, out_height: &height);
242
243 // Create texture
244 // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
245 int flags = al_get_new_bitmap_flags();
246 int fmt = al_get_new_bitmap_format();
247 al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
248 al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
249 ALLEGRO_BITMAP* img = al_create_bitmap(width, height);
250 al_set_new_bitmap_flags(flags);
251 al_set_new_bitmap_format(fmt);
252 if (!img)
253 return false;
254
255 ALLEGRO_LOCKED_REGION* locked_img = al_lock_bitmap(img, al_get_bitmap_format(img), ALLEGRO_LOCK_WRITEONLY);
256 if (!locked_img)
257 {
258 al_destroy_bitmap(img);
259 return false;
260 }
261 memcpy(locked_img->data, pixels, sizeof(int) * width * height);
262 al_unlock_bitmap(img);
263
264 // Convert software texture to hardware texture.
265 ALLEGRO_BITMAP* cloned_img = al_clone_bitmap(img);
266 al_destroy_bitmap(img);
267 if (!cloned_img)
268 return false;
269
270 // Store our identifier
271 io.Fonts->SetTexID((ImTextureID)(intptr_t)cloned_img);
272 bd->Texture = cloned_img;
273
274 // Create an invisible mouse cursor
275 // Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
276 ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8, 8);
277 bd->MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
278 al_destroy_bitmap(mouse_cursor);
279
280 return true;
281}
282
283void ImGui_ImplAllegro5_InvalidateDeviceObjects()
284{
285 ImGuiIO& io = ImGui::GetIO();
286 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
287 if (bd->Texture)
288 {
289 io.Fonts->SetTexID(0);
290 al_destroy_bitmap(bd->Texture);
291 bd->Texture = nullptr;
292 }
293 if (bd->MouseCursorInvisible)
294 {
295 al_destroy_mouse_cursor(bd->MouseCursorInvisible);
296 bd->MouseCursorInvisible = nullptr;
297 }
298}
299
300#if ALLEGRO_HAS_CLIPBOARD
301static const char* ImGui_ImplAllegro5_GetClipboardText(ImGuiContext*)
302{
303 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
304 if (bd->ClipboardTextData)
305 al_free(bd->ClipboardTextData);
306 bd->ClipboardTextData = al_get_clipboard_text(bd->Display);
307 return bd->ClipboardTextData;
308}
309
310static void ImGui_ImplAllegro5_SetClipboardText(ImGuiContext*, const char* text)
311{
312 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
313 al_set_clipboard_text(bd->Display, text);
314}
315#endif
316
317// Not static to allow third-party code to use that if they want to (but undocumented)
318ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code);
319ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code)
320{
321 switch (key_code)
322 {
323 case ALLEGRO_KEY_TAB: return ImGuiKey_Tab;
324 case ALLEGRO_KEY_LEFT: return ImGuiKey_LeftArrow;
325 case ALLEGRO_KEY_RIGHT: return ImGuiKey_RightArrow;
326 case ALLEGRO_KEY_UP: return ImGuiKey_UpArrow;
327 case ALLEGRO_KEY_DOWN: return ImGuiKey_DownArrow;
328 case ALLEGRO_KEY_PGUP: return ImGuiKey_PageUp;
329 case ALLEGRO_KEY_PGDN: return ImGuiKey_PageDown;
330 case ALLEGRO_KEY_HOME: return ImGuiKey_Home;
331 case ALLEGRO_KEY_END: return ImGuiKey_End;
332 case ALLEGRO_KEY_INSERT: return ImGuiKey_Insert;
333 case ALLEGRO_KEY_DELETE: return ImGuiKey_Delete;
334 case ALLEGRO_KEY_BACKSPACE: return ImGuiKey_Backspace;
335 case ALLEGRO_KEY_SPACE: return ImGuiKey_Space;
336 case ALLEGRO_KEY_ENTER: return ImGuiKey_Enter;
337 case ALLEGRO_KEY_ESCAPE: return ImGuiKey_Escape;
338 case ALLEGRO_KEY_QUOTE: return ImGuiKey_Apostrophe;
339 case ALLEGRO_KEY_COMMA: return ImGuiKey_Comma;
340 case ALLEGRO_KEY_MINUS: return ImGuiKey_Minus;
341 case ALLEGRO_KEY_FULLSTOP: return ImGuiKey_Period;
342 case ALLEGRO_KEY_SLASH: return ImGuiKey_Slash;
343 case ALLEGRO_KEY_SEMICOLON: return ImGuiKey_Semicolon;
344 case ALLEGRO_KEY_EQUALS: return ImGuiKey_Equal;
345 case ALLEGRO_KEY_OPENBRACE: return ImGuiKey_LeftBracket;
346 case ALLEGRO_KEY_BACKSLASH: return ImGuiKey_Backslash;
347 case ALLEGRO_KEY_CLOSEBRACE: return ImGuiKey_RightBracket;
348 case ALLEGRO_KEY_TILDE: return ImGuiKey_GraveAccent;
349 case ALLEGRO_KEY_CAPSLOCK: return ImGuiKey_CapsLock;
350 case ALLEGRO_KEY_SCROLLLOCK: return ImGuiKey_ScrollLock;
351 case ALLEGRO_KEY_NUMLOCK: return ImGuiKey_NumLock;
352 case ALLEGRO_KEY_PRINTSCREEN: return ImGuiKey_PrintScreen;
353 case ALLEGRO_KEY_PAUSE: return ImGuiKey_Pause;
354 case ALLEGRO_KEY_PAD_0: return ImGuiKey_Keypad0;
355 case ALLEGRO_KEY_PAD_1: return ImGuiKey_Keypad1;
356 case ALLEGRO_KEY_PAD_2: return ImGuiKey_Keypad2;
357 case ALLEGRO_KEY_PAD_3: return ImGuiKey_Keypad3;
358 case ALLEGRO_KEY_PAD_4: return ImGuiKey_Keypad4;
359 case ALLEGRO_KEY_PAD_5: return ImGuiKey_Keypad5;
360 case ALLEGRO_KEY_PAD_6: return ImGuiKey_Keypad6;
361 case ALLEGRO_KEY_PAD_7: return ImGuiKey_Keypad7;
362 case ALLEGRO_KEY_PAD_8: return ImGuiKey_Keypad8;
363 case ALLEGRO_KEY_PAD_9: return ImGuiKey_Keypad9;
364 case ALLEGRO_KEY_PAD_DELETE: return ImGuiKey_KeypadDecimal;
365 case ALLEGRO_KEY_PAD_SLASH: return ImGuiKey_KeypadDivide;
366 case ALLEGRO_KEY_PAD_ASTERISK: return ImGuiKey_KeypadMultiply;
367 case ALLEGRO_KEY_PAD_MINUS: return ImGuiKey_KeypadSubtract;
368 case ALLEGRO_KEY_PAD_PLUS: return ImGuiKey_KeypadAdd;
369 case ALLEGRO_KEY_PAD_ENTER: return ImGuiKey_KeypadEnter;
370 case ALLEGRO_KEY_PAD_EQUALS: return ImGuiKey_KeypadEqual;
371 case ALLEGRO_KEY_LCTRL: return ImGuiKey_LeftCtrl;
372 case ALLEGRO_KEY_LSHIFT: return ImGuiKey_LeftShift;
373 case ALLEGRO_KEY_ALT: return ImGuiKey_LeftAlt;
374 case ALLEGRO_KEY_LWIN: return ImGuiKey_LeftSuper;
375 case ALLEGRO_KEY_RCTRL: return ImGuiKey_RightCtrl;
376 case ALLEGRO_KEY_RSHIFT: return ImGuiKey_RightShift;
377 case ALLEGRO_KEY_ALTGR: return ImGuiKey_RightAlt;
378 case ALLEGRO_KEY_RWIN: return ImGuiKey_RightSuper;
379 case ALLEGRO_KEY_MENU: return ImGuiKey_Menu;
380 case ALLEGRO_KEY_0: return ImGuiKey_0;
381 case ALLEGRO_KEY_1: return ImGuiKey_1;
382 case ALLEGRO_KEY_2: return ImGuiKey_2;
383 case ALLEGRO_KEY_3: return ImGuiKey_3;
384 case ALLEGRO_KEY_4: return ImGuiKey_4;
385 case ALLEGRO_KEY_5: return ImGuiKey_5;
386 case ALLEGRO_KEY_6: return ImGuiKey_6;
387 case ALLEGRO_KEY_7: return ImGuiKey_7;
388 case ALLEGRO_KEY_8: return ImGuiKey_8;
389 case ALLEGRO_KEY_9: return ImGuiKey_9;
390 case ALLEGRO_KEY_A: return ImGuiKey_A;
391 case ALLEGRO_KEY_B: return ImGuiKey_B;
392 case ALLEGRO_KEY_C: return ImGuiKey_C;
393 case ALLEGRO_KEY_D: return ImGuiKey_D;
394 case ALLEGRO_KEY_E: return ImGuiKey_E;
395 case ALLEGRO_KEY_F: return ImGuiKey_F;
396 case ALLEGRO_KEY_G: return ImGuiKey_G;
397 case ALLEGRO_KEY_H: return ImGuiKey_H;
398 case ALLEGRO_KEY_I: return ImGuiKey_I;
399 case ALLEGRO_KEY_J: return ImGuiKey_J;
400 case ALLEGRO_KEY_K: return ImGuiKey_K;
401 case ALLEGRO_KEY_L: return ImGuiKey_L;
402 case ALLEGRO_KEY_M: return ImGuiKey_M;
403 case ALLEGRO_KEY_N: return ImGuiKey_N;
404 case ALLEGRO_KEY_O: return ImGuiKey_O;
405 case ALLEGRO_KEY_P: return ImGuiKey_P;
406 case ALLEGRO_KEY_Q: return ImGuiKey_Q;
407 case ALLEGRO_KEY_R: return ImGuiKey_R;
408 case ALLEGRO_KEY_S: return ImGuiKey_S;
409 case ALLEGRO_KEY_T: return ImGuiKey_T;
410 case ALLEGRO_KEY_U: return ImGuiKey_U;
411 case ALLEGRO_KEY_V: return ImGuiKey_V;
412 case ALLEGRO_KEY_W: return ImGuiKey_W;
413 case ALLEGRO_KEY_X: return ImGuiKey_X;
414 case ALLEGRO_KEY_Y: return ImGuiKey_Y;
415 case ALLEGRO_KEY_Z: return ImGuiKey_Z;
416 case ALLEGRO_KEY_F1: return ImGuiKey_F1;
417 case ALLEGRO_KEY_F2: return ImGuiKey_F2;
418 case ALLEGRO_KEY_F3: return ImGuiKey_F3;
419 case ALLEGRO_KEY_F4: return ImGuiKey_F4;
420 case ALLEGRO_KEY_F5: return ImGuiKey_F5;
421 case ALLEGRO_KEY_F6: return ImGuiKey_F6;
422 case ALLEGRO_KEY_F7: return ImGuiKey_F7;
423 case ALLEGRO_KEY_F8: return ImGuiKey_F8;
424 case ALLEGRO_KEY_F9: return ImGuiKey_F9;
425 case ALLEGRO_KEY_F10: return ImGuiKey_F10;
426 case ALLEGRO_KEY_F11: return ImGuiKey_F11;
427 case ALLEGRO_KEY_F12: return ImGuiKey_F12;
428 default: return ImGuiKey_None;
429 }
430}
431
432bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
433{
434 ImGuiIO& io = ImGui::GetIO();
435 IMGUI_CHECKVERSION();
436 IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
437
438 // Setup backend capabilities flags
439 ImGui_ImplAllegro5_Data* bd = IM_NEW(ImGui_ImplAllegro5_Data)();
440 io.BackendPlatformUserData = (void*)bd;
441 io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
442 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
443
444 bd->Display = display;
445 bd->LastCursor = ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE;
446
447 // Create custom vertex declaration.
448 // Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats.
449 // We still use a custom declaration to use 'ALLEGRO_PRIM_TEX_COORD' instead of 'ALLEGRO_PRIM_TEX_COORD_PIXEL' else we can't do a reliable conversion.
450 ALLEGRO_VERTEX_ELEMENT elems[] =
451 {
452 { ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(ImDrawVertAllegro, pos) },
453 { ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, offsetof(ImDrawVertAllegro, uv) },
454 { ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(ImDrawVertAllegro, col) },
455 { 0, 0, 0 }
456 };
457 bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
458
459#if ALLEGRO_HAS_CLIPBOARD
460 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
461 platform_io.Platform_SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
462 platform_io.Platform_GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
463#endif
464
465 return true;
466}
467
468void ImGui_ImplAllegro5_Shutdown()
469{
470 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
471 IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
472 ImGuiIO& io = ImGui::GetIO();
473
474 ImGui_ImplAllegro5_InvalidateDeviceObjects();
475 if (bd->VertexDecl)
476 al_destroy_vertex_decl(bd->VertexDecl);
477 if (bd->ClipboardTextData)
478 al_free(bd->ClipboardTextData);
479
480 io.BackendPlatformName = io.BackendRendererName = nullptr;
481 io.BackendPlatformUserData = nullptr;
482 io.BackendFlags &= ~ImGuiBackendFlags_HasMouseCursors;
483 IM_DELETE(p: bd);
484}
485
486// ev->keyboard.modifiers seems always zero so using that...
487static void ImGui_ImplAllegro5_UpdateKeyModifiers()
488{
489 ImGuiIO& io = ImGui::GetIO();
490 ALLEGRO_KEYBOARD_STATE keys;
491 al_get_keyboard_state(&keys);
492 io.AddKeyEvent(ImGuiMod_Ctrl, al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL));
493 io.AddKeyEvent(ImGuiMod_Shift, al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT));
494 io.AddKeyEvent(ImGuiMod_Alt, al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR));
495 io.AddKeyEvent(ImGuiMod_Super, al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN));
496}
497
498// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
499// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
500// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
501// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
502bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
503{
504 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
505 IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplAllegro5_Init()?");
506 ImGuiIO& io = ImGui::GetIO();
507
508 switch (ev->type)
509 {
510 case ALLEGRO_EVENT_MOUSE_AXES:
511 if (ev->mouse.display == bd->Display)
512 {
513 io.AddMousePosEvent(x: ev->mouse.x, y: ev->mouse.y);
514 io.AddMouseWheelEvent(wheel_x: -ev->mouse.dw, wheel_y: ev->mouse.dz);
515 }
516 return true;
517 case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
518 case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
519 if (ev->mouse.display == bd->Display && ev->mouse.button > 0 && ev->mouse.button <= 5)
520 io.AddMouseButtonEvent(ev->mouse.button - 1, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
521 return true;
522 case ALLEGRO_EVENT_TOUCH_MOVE:
523 if (ev->touch.display == bd->Display)
524 io.AddMousePosEvent(x: ev->touch.x, y: ev->touch.y);
525 return true;
526 case ALLEGRO_EVENT_TOUCH_BEGIN:
527 case ALLEGRO_EVENT_TOUCH_END:
528 case ALLEGRO_EVENT_TOUCH_CANCEL:
529 if (ev->touch.display == bd->Display && ev->touch.primary)
530 io.AddMouseButtonEvent(0, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
531 return true;
532 case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
533 if (ev->mouse.display == bd->Display)
534 io.AddMousePosEvent(x: -FLT_MAX, y: -FLT_MAX);
535 return true;
536 case ALLEGRO_EVENT_KEY_CHAR:
537 if (ev->keyboard.display == bd->Display)
538 if (ev->keyboard.unichar != 0)
539 io.AddInputCharacter(c: (unsigned int)ev->keyboard.unichar);
540 return true;
541 case ALLEGRO_EVENT_KEY_DOWN:
542 case ALLEGRO_EVENT_KEY_UP:
543 if (ev->keyboard.display == bd->Display)
544 {
545 ImGui_ImplAllegro5_UpdateKeyModifiers();
546 ImGuiKey key = ImGui_ImplAllegro5_KeyCodeToImGuiKey(ev->keyboard.keycode);
547 io.AddKeyEvent(key, (ev->type == ALLEGRO_EVENT_KEY_DOWN));
548 io.SetKeyEventNativeData(key, native_keycode: ev->keyboard.keycode, native_scancode: -1); // To support legacy indexing (<1.87 user code)
549 }
550 return true;
551 case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
552 if (ev->display.source == bd->Display)
553 io.AddFocusEvent(focused: false);
554 return true;
555 case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
556 if (ev->display.source == bd->Display)
557 {
558 io.AddFocusEvent(focused: true);
559#if defined(ALLEGRO_UNSTABLE)
560 al_clear_keyboard_state(bd->Display);
561#endif
562 }
563 return true;
564 }
565 return false;
566}
567
568static void ImGui_ImplAllegro5_UpdateMouseCursor()
569{
570 ImGuiIO& io = ImGui::GetIO();
571 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
572 return;
573
574 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
575 ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
576
577 // Hide OS mouse cursor if imgui is drawing it
578 if (io.MouseDrawCursor)
579 imgui_cursor = ImGuiMouseCursor_None;
580
581 if (bd->LastCursor == imgui_cursor)
582 return;
583 bd->LastCursor = imgui_cursor;
584 if (imgui_cursor == ImGuiMouseCursor_None)
585 {
586 al_set_mouse_cursor(bd->Display, bd->MouseCursorInvisible);
587 }
588 else
589 {
590 ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT;
591 switch (imgui_cursor)
592 {
593 case ImGuiMouseCursor_TextInput: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT; break;
594 case ImGuiMouseCursor_ResizeAll: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE; break;
595 case ImGuiMouseCursor_ResizeNS: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N; break;
596 case ImGuiMouseCursor_ResizeEW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E; break;
597 case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break;
598 case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break;
599 case ImGuiMouseCursor_Wait: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY; break;
600 case ImGuiMouseCursor_Progress: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS; break;
601 case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break;
602 }
603 al_set_system_mouse_cursor(bd->Display, cursor_id);
604 }
605}
606
607void ImGui_ImplAllegro5_NewFrame()
608{
609 ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
610 IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplAllegro5_Init()?");
611
612 if (!bd->Texture)
613 ImGui_ImplAllegro5_CreateDeviceObjects();
614
615 ImGuiIO& io = ImGui::GetIO();
616
617 // Setup display size (every frame to accommodate for window resizing)
618 int w, h;
619 w = al_get_display_width(bd->Display);
620 h = al_get_display_height(bd->Display);
621 io.DisplaySize = ImVec2((float)w, (float)h);
622
623 // Setup time step
624 double current_time = al_get_time();
625 io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
626 bd->Time = current_time;
627
628 // Setup mouse cursor shape
629 ImGui_ImplAllegro5_UpdateMouseCursor();
630}
631
632//-----------------------------------------------------------------------------
633
634#endif // #ifndef IMGUI_DISABLE
635

source code of imgui/backends/imgui_impl_allegro5.cpp