2015-07-08 17:34:36 +00:00
// ImGui Allegro 5 bindings
2016-03-24 10:00:47 +00:00
// In this binding, ImTextureID is used to store a 'ALLEGRO_BITMAP*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
2016-10-15 09:36:43 +00:00
// TODO:
// - Clipboard is not supported.
2015-11-29 11:19:30 +00:00
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
2015-10-13 15:53:43 +00:00
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
2015-11-29 11:19:30 +00:00
// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
2015-07-08 17:34:36 +00:00
// https://github.com/ocornut/imgui
2015-07-08 23:25:56 +00:00
// by @birthggd
2015-07-08 17:34:36 +00:00
# include <stdint.h> // uint64_t
# include <cstring> // memcpy
# include <imgui.h>
# include "imgui_impl_a5.h"
# include <allegro5/allegro.h>
# include <allegro5/allegro_primitives.h>
# ifdef _WIN32
# include <allegro5/allegro_windows.h>
# endif
2015-07-08 17:53:30 +00:00
// Data
2015-07-08 18:16:50 +00:00
static ALLEGRO_DISPLAY * g_Display = NULL ;
2015-07-08 18:41:09 +00:00
static ALLEGRO_BITMAP * g_Texture = NULL ;
2015-07-08 18:16:50 +00:00
static double g_Time = 0.0 ;
static ALLEGRO_MOUSE_CURSOR * g_MouseCursorInvisible = NULL ;
2015-07-08 18:41:09 +00:00
static ALLEGRO_VERTEX_DECL * g_VertexDecl = NULL ;
2015-07-08 17:34:36 +00:00
2015-07-08 18:41:09 +00:00
# define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
2015-07-08 17:53:30 +00:00
2015-07-08 18:41:09 +00:00
struct ImDrawVertAllegro
{
ImVec2 pos ;
ImVec2 uv ;
ALLEGRO_COLOR col ;
} ;
2015-07-08 17:53:30 +00:00
2015-09-07 13:58:26 +00:00
void ImGui_ImplA5_RenderDrawLists ( ImDrawData * draw_data )
2015-07-08 18:41:09 +00:00
{
2015-07-08 17:53:30 +00:00
int op , src , dst ;
al_get_blender ( & op , & src , & dst ) ;
al_set_blender ( ALLEGRO_ADD , ALLEGRO_ALPHA , ALLEGRO_INVERSE_ALPHA ) ;
2016-03-26 14:43:45 +00:00
for ( int n = 0 ; n < draw_data - > CmdListsCount ; n + + )
2015-07-08 17:53:30 +00:00
{
2015-07-08 18:55:40 +00:00
const ImDrawList * cmd_list = draw_data - > CmdLists [ n ] ;
2015-07-08 18:41:09 +00:00
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 floats
static ImVector < ImDrawVertAllegro > vertices ;
2016-09-03 17:24:57 +00:00
vertices . resize ( cmd_list - > VtxBuffer . Size ) ;
for ( int i = 0 ; i < cmd_list - > VtxBuffer . Size ; + + i )
2015-07-08 17:53:30 +00:00
{
2015-07-08 18:55:40 +00:00
const ImDrawVert & dv = cmd_list - > VtxBuffer [ i ] ;
2015-07-08 18:41:09 +00:00
ImDrawVertAllegro v ;
v . pos = dv . pos ;
v . uv = dv . uv ;
2015-07-08 17:53:30 +00:00
unsigned char * c = ( unsigned char * ) & dv . col ;
2015-07-08 18:41:09 +00:00
v . col = al_map_rgba ( c [ 0 ] , c [ 1 ] , c [ 2 ] , c [ 3 ] ) ;
vertices [ i ] = v ;
2015-07-08 17:53:30 +00:00
}
2015-07-08 18:41:09 +00:00
2015-11-08 11:00:31 +00:00
// FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices
// You can also use '#define ImDrawIdx unsigned int' in imconfig.h and request ImGui to output 32-bit indices
2015-07-08 18:55:40 +00:00
static ImVector < int > indices ;
2016-09-03 17:24:57 +00:00
indices . resize ( cmd_list - > IdxBuffer . Size ) ;
for ( int i = 0 ; i < cmd_list - > IdxBuffer . Size ; + + i )
2015-07-08 18:55:40 +00:00
indices [ i ] = ( int ) cmd_list - > IdxBuffer . Data [ i ] ;
int idx_offset = 0 ;
2016-09-03 17:24:57 +00:00
for ( int cmd_i = 0 ; cmd_i < cmd_list - > CmdBuffer . Size ; cmd_i + + )
2015-07-08 17:53:30 +00:00
{
2015-07-08 18:55:40 +00:00
const ImDrawCmd * pcmd = & cmd_list - > CmdBuffer [ cmd_i ] ;
2016-03-26 14:43:45 +00:00
if ( pcmd - > UserCallback )
2015-07-08 17:53:30 +00:00
{
2015-07-08 18:55:40 +00:00
pcmd - > UserCallback ( cmd_list , pcmd ) ;
2015-07-08 17:53:30 +00:00
}
2016-03-26 14:43:45 +00:00
else
2015-07-08 17:53:30 +00:00
{
2015-07-08 18:55:40 +00:00
ALLEGRO_BITMAP * texture = ( ALLEGRO_BITMAP * ) pcmd - > TextureId ;
al_set_clipping_rectangle ( pcmd - > ClipRect . x , pcmd - > ClipRect . y , pcmd - > ClipRect . z - pcmd - > ClipRect . x , pcmd - > ClipRect . w - pcmd - > ClipRect . y ) ;
al_draw_indexed_prim ( & vertices [ 0 ] , g_VertexDecl , texture , & indices [ idx_offset ] , pcmd - > ElemCount , ALLEGRO_PRIM_TRIANGLE_LIST ) ;
2015-07-08 17:53:30 +00:00
}
2015-07-08 18:55:40 +00:00
idx_offset + = pcmd - > ElemCount ;
2015-07-08 17:53:30 +00:00
}
2015-07-08 17:34:36 +00:00
}
2015-07-08 18:41:09 +00:00
// Restore modified state
2015-07-08 17:53:30 +00:00
al_set_blender ( op , src , dst ) ;
al_set_clipping_rectangle ( 0 , 0 , al_get_display_width ( g_Display ) , al_get_display_height ( g_Display ) ) ;
2015-07-08 17:34:36 +00:00
}
bool Imgui_ImplA5_CreateDeviceObjects ( )
{
2015-11-29 14:54:05 +00:00
// Build texture atlas
2015-07-08 17:53:30 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
unsigned char * pixels ;
int width , height ;
io . Fonts - > GetTexDataAsRGBA32 ( & pixels , & width , & height ) ;
// Create texture
int flags = al_get_new_bitmap_flags ( ) ;
int fmt = al_get_new_bitmap_format ( ) ;
al_set_new_bitmap_flags ( ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR ) ;
al_set_new_bitmap_format ( ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE ) ;
ALLEGRO_BITMAP * img = al_create_bitmap ( width , height ) ;
al_set_new_bitmap_flags ( flags ) ;
al_set_new_bitmap_format ( fmt ) ;
2016-03-26 14:43:45 +00:00
if ( ! img )
2015-07-08 17:53:30 +00:00
return false ;
ALLEGRO_LOCKED_REGION * locked_img = al_lock_bitmap ( img , al_get_bitmap_format ( img ) , ALLEGRO_LOCK_WRITEONLY ) ;
2016-03-26 14:43:45 +00:00
if ( ! locked_img )
2015-07-08 17:53:30 +00:00
{
al_destroy_bitmap ( img ) ;
return false ;
}
memcpy ( locked_img - > data , pixels , sizeof ( int ) * width * height ) ;
al_unlock_bitmap ( img ) ;
// Convert software texture to hardware texture.
ALLEGRO_BITMAP * cloned_img = al_clone_bitmap ( img ) ;
2015-07-08 17:34:36 +00:00
al_destroy_bitmap ( img ) ;
2016-03-26 14:43:45 +00:00
if ( ! cloned_img )
2015-07-08 17:53:30 +00:00
return false ;
2015-07-08 17:34:36 +00:00
2015-07-08 17:53:30 +00:00
// Store our identifier
io . Fonts - > TexID = ( void * ) cloned_img ;
2015-07-08 18:41:09 +00:00
g_Texture = cloned_img ;
2015-07-08 17:34:36 +00:00
2015-07-08 18:16:50 +00:00
// Create an invisible mouse cursor
// Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
ALLEGRO_BITMAP * mouse_cursor = al_create_bitmap ( 8 , 8 ) ;
g_MouseCursorInvisible = al_create_mouse_cursor ( mouse_cursor , 0 , 0 ) ;
al_destroy_bitmap ( mouse_cursor ) ;
2015-07-08 17:53:30 +00:00
return true ;
2015-07-08 17:34:36 +00:00
}
void ImGui_ImplA5_InvalidateDeviceObjects ( )
{
2016-03-26 14:43:45 +00:00
if ( g_Texture )
2015-07-08 17:53:30 +00:00
{
2015-07-08 18:41:09 +00:00
al_destroy_bitmap ( g_Texture ) ;
2015-07-08 17:53:30 +00:00
ImGui : : GetIO ( ) . Fonts - > TexID = NULL ;
2015-07-08 18:41:09 +00:00
g_Texture = NULL ;
2015-07-08 17:53:30 +00:00
}
2015-07-08 18:16:50 +00:00
if ( g_MouseCursorInvisible )
{
al_destroy_mouse_cursor ( g_MouseCursorInvisible ) ;
g_MouseCursorInvisible = NULL ;
}
2015-07-08 17:34:36 +00:00
}
2015-07-08 17:53:30 +00:00
bool ImGui_ImplA5_Init ( ALLEGRO_DISPLAY * display )
2015-07-08 17:34:36 +00:00
{
2015-07-08 17:53:30 +00:00
g_Display = display ;
2016-03-26 14:43:45 +00:00
// Create custom vertex declaration.
2015-07-08 18:41:09 +00:00
// Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 floats.
// 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.
2016-03-26 14:43:45 +00:00
ALLEGRO_VERTEX_ELEMENT elems [ ] =
2015-07-08 18:41:09 +00:00
{
{ ALLEGRO_PRIM_POSITION , ALLEGRO_PRIM_FLOAT_2 , OFFSETOF ( ImDrawVertAllegro , pos ) } ,
{ ALLEGRO_PRIM_TEX_COORD , ALLEGRO_PRIM_FLOAT_2 , OFFSETOF ( ImDrawVertAllegro , uv ) } ,
{ ALLEGRO_PRIM_COLOR_ATTR , 0 , OFFSETOF ( ImDrawVertAllegro , col ) } ,
{ 0 , 0 , 0 }
} ;
g_VertexDecl = al_create_vertex_decl ( elems , sizeof ( ImDrawVertAllegro ) ) ;
2015-07-08 17:53:30 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
io . KeyMap [ ImGuiKey_Tab ] = ALLEGRO_KEY_TAB ;
io . KeyMap [ ImGuiKey_LeftArrow ] = ALLEGRO_KEY_LEFT ;
io . KeyMap [ ImGuiKey_RightArrow ] = ALLEGRO_KEY_RIGHT ;
io . KeyMap [ ImGuiKey_UpArrow ] = ALLEGRO_KEY_UP ;
io . KeyMap [ ImGuiKey_DownArrow ] = ALLEGRO_KEY_DOWN ;
2015-07-08 18:04:13 +00:00
io . KeyMap [ ImGuiKey_PageUp ] = ALLEGRO_KEY_PGUP ;
io . KeyMap [ ImGuiKey_PageDown ] = ALLEGRO_KEY_PGDN ;
2015-07-08 17:53:30 +00:00
io . KeyMap [ ImGuiKey_Home ] = ALLEGRO_KEY_HOME ;
io . KeyMap [ ImGuiKey_End ] = ALLEGRO_KEY_END ;
io . KeyMap [ ImGuiKey_Delete ] = ALLEGRO_KEY_DELETE ;
io . KeyMap [ ImGuiKey_Backspace ] = ALLEGRO_KEY_BACKSPACE ;
io . KeyMap [ ImGuiKey_Enter ] = ALLEGRO_KEY_ENTER ;
io . KeyMap [ ImGuiKey_Escape ] = ALLEGRO_KEY_ESCAPE ;
io . KeyMap [ ImGuiKey_A ] = ALLEGRO_KEY_A ;
io . KeyMap [ ImGuiKey_C ] = ALLEGRO_KEY_C ;
io . KeyMap [ ImGuiKey_V ] = ALLEGRO_KEY_V ;
io . KeyMap [ ImGuiKey_X ] = ALLEGRO_KEY_X ;
io . KeyMap [ ImGuiKey_Y ] = ALLEGRO_KEY_Y ;
io . KeyMap [ ImGuiKey_Z ] = ALLEGRO_KEY_Z ;
2015-09-07 13:58:26 +00:00
io . RenderDrawListsFn = ImGui_ImplA5_RenderDrawLists ; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer.
2015-07-08 17:34:36 +00:00
# ifdef _WIN32
2015-07-08 17:53:30 +00:00
io . ImeWindowHandle = al_get_win_window_handle ( g_Display ) ;
2015-07-08 17:34:36 +00:00
# endif
2015-07-08 17:53:30 +00:00
return true ;
2015-07-08 17:34:36 +00:00
}
void ImGui_ImplA5_Shutdown ( )
{
2015-07-08 17:53:30 +00:00
ImGui_ImplA5_InvalidateDeviceObjects ( ) ;
ImGui : : Shutdown ( ) ;
2015-07-08 17:34:36 +00:00
}
2015-07-08 17:53:30 +00:00
bool ImGui_ImplA5_ProcessEvent ( ALLEGRO_EVENT * ev )
2015-07-08 17:34:36 +00:00
{
2015-07-08 17:53:30 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2016-03-26 14:43:45 +00:00
switch ( ev - > type )
2015-07-08 17:53:30 +00:00
{
case ALLEGRO_EVENT_MOUSE_AXES :
io . MouseWheel + = ev - > mouse . dz ;
return true ;
case ALLEGRO_EVENT_KEY_CHAR :
2016-03-26 14:43:45 +00:00
if ( ev - > keyboard . display = = g_Display )
2015-07-08 17:53:30 +00:00
if ( ev - > keyboard . unichar > 0 & & ev - > keyboard . unichar < 0x10000 )
io . AddInputCharacter ( ( unsigned short ) ev - > keyboard . unichar ) ;
return true ;
2015-07-08 18:04:13 +00:00
case ALLEGRO_EVENT_KEY_DOWN :
2015-07-08 17:53:30 +00:00
case ALLEGRO_EVENT_KEY_UP :
if ( ev - > keyboard . display = = g_Display )
2015-07-08 18:04:13 +00:00
io . KeysDown [ ev - > keyboard . keycode ] = ( ev - > type = = ALLEGRO_EVENT_KEY_DOWN ) ;
2015-07-08 17:53:30 +00:00
return true ;
2015-07-08 17:34:36 +00:00
}
2015-07-08 17:53:30 +00:00
return false ;
2015-07-08 17:34:36 +00:00
}
void ImGui_ImplA5_NewFrame ( )
{
2016-03-26 14:43:45 +00:00
if ( ! g_Texture )
2015-07-08 17:53:30 +00:00
Imgui_ImplA5_CreateDeviceObjects ( ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
// Setup display size (every frame to accommodate for window resizing)
int w , h ;
w = al_get_display_width ( g_Display ) ;
h = al_get_display_height ( g_Display ) ;
io . DisplaySize = ImVec2 ( ( float ) w , ( float ) h ) ;
// Setup time step
double current_time = al_get_time ( ) ;
io . DeltaTime = g_Time > 0.0 ? ( float ) ( current_time - g_Time ) : ( float ) ( 1.0f / 60.0f ) ;
g_Time = current_time ;
// Setup inputs
ALLEGRO_KEYBOARD_STATE keys ;
al_get_keyboard_state ( & keys ) ;
2015-07-08 18:04:13 +00:00
io . KeyCtrl = al_key_down ( & keys , ALLEGRO_KEY_LCTRL ) | | al_key_down ( & keys , ALLEGRO_KEY_RCTRL ) ;
io . KeyShift = al_key_down ( & keys , ALLEGRO_KEY_LSHIFT ) | | al_key_down ( & keys , ALLEGRO_KEY_RSHIFT ) ;
io . KeyAlt = al_key_down ( & keys , ALLEGRO_KEY_ALT ) | | al_key_down ( & keys , ALLEGRO_KEY_ALTGR ) ;
2016-04-02 16:22:40 +00:00
io . KeySuper = al_key_down ( & keys , ALLEGRO_KEY_LWIN ) | | al_key_down ( & keys , ALLEGRO_KEY_RWIN ) ;
2015-07-08 17:53:30 +00:00
ALLEGRO_MOUSE_STATE mouse ;
2016-03-26 14:43:45 +00:00
if ( keys . display = = g_Display )
2015-07-08 17:53:30 +00:00
{
al_get_mouse_state ( & mouse ) ;
io . MousePos = ImVec2 ( ( float ) mouse . x , ( float ) mouse . y ) ;
}
2016-03-26 14:43:45 +00:00
else
2015-07-08 17:53:30 +00:00
{
2017-08-25 08:43:25 +00:00
io . MousePos = ImVec2 ( - FLT_MAX , - FLT_MAX ) ;
2015-07-08 17:53:30 +00:00
}
2015-07-08 17:34:36 +00:00
al_get_mouse_state ( & mouse ) ;
2015-07-08 17:53:30 +00:00
io . MouseDown [ 0 ] = mouse . buttons & ( 1 < < 0 ) ;
io . MouseDown [ 1 ] = mouse . buttons & ( 1 < < 1 ) ;
io . MouseDown [ 2 ] = mouse . buttons & ( 1 < < 2 ) ;
2015-07-08 18:16:50 +00:00
// Hide OS mouse cursor if ImGui is drawing it
if ( io . MouseDrawCursor )
{
al_set_mouse_cursor ( g_Display , g_MouseCursorInvisible ) ;
}
else
{
ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT ;
switch ( ImGui : : GetMouseCursor ( ) )
{
case ImGuiMouseCursor_TextInput : cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT ; break ;
case ImGuiMouseCursor_Move : cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE ; break ;
case ImGuiMouseCursor_ResizeNS : cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N ; break ;
case ImGuiMouseCursor_ResizeEW : cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E ; break ;
case ImGuiMouseCursor_ResizeNESW : cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE ; break ;
case ImGuiMouseCursor_ResizeNWSE : cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW ; break ;
}
al_set_system_mouse_cursor ( g_Display , cursor_id ) ;
}
2015-07-08 17:53:30 +00:00
// Start the frame
ImGui : : NewFrame ( ) ;
2015-07-08 17:34:36 +00:00
}