mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 05:01:05 +01:00 
			
		
		
		
	Android: Amend backend and examples with minor consistency tweaks. (#3446)
This commit is contained in:
		| @@ -3,9 +3,13 @@ | |||||||
|  |  | ||||||
| // Implemented features: | // Implemented features: | ||||||
| //  [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). | //  [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). | ||||||
|  | // Missing features: | ||||||
| //  [ ] Platform: Clipboard support. | //  [ ] Platform: Clipboard support. | ||||||
| //  [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | //  [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | ||||||
| //  [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. | //  [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. | ||||||
|  | // Important: | ||||||
|  | //  - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) | ||||||
|  | //  - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446) | ||||||
|  |  | ||||||
| // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | ||||||
| // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. | ||||||
| @@ -13,39 +17,35 @@ | |||||||
|  |  | ||||||
| // CHANGELOG | // CHANGELOG | ||||||
| // (minor and older changes stripped away, please see git history for details) | // (minor and older changes stripped away, please see git history for details) | ||||||
| //  2021-03-02: Support for physical pointer device input (such as physical mouse) | //  2021-03-04: Initial version. | ||||||
| //  2020-09-13: Support for Unicode characters |  | ||||||
| //  2020-08-31: On-screen and physical keyboard input (ASCII characters only) |  | ||||||
| //  2020-03-02: basic draft, touch input |  | ||||||
|  |  | ||||||
| #include "imgui.h" | #include "imgui.h" | ||||||
| #include "imgui_impl_android.h" | #include "imgui_impl_android.h" | ||||||
| #include <time.h> | #include <time.h> | ||||||
| #include <map> | #include <map> | ||||||
| #include <queue> | #include <queue> | ||||||
|  |  | ||||||
| // Android |  | ||||||
| #include <android/native_window.h> | #include <android/native_window.h> | ||||||
| #include <android/input.h> | #include <android/input.h> | ||||||
| #include <android/keycodes.h> | #include <android/keycodes.h> | ||||||
| #include <android/log.h> | #include <android/log.h> | ||||||
|  |  | ||||||
|  | // Android data | ||||||
| static double                                   g_Time = 0.0; | static double                                   g_Time = 0.0; | ||||||
| static ANativeWindow*                           g_Window; | static ANativeWindow*                           g_Window; | ||||||
| static char                                     g_LogTag[] = "ImguiExample"; | static char                                     g_LogTag[] = "ImGuiExample"; | ||||||
| static std::map<int32_t, std::queue<int32_t>>   g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue. | static std::map<int32_t, std::queue<int32_t>>   g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue. | ||||||
|  |  | ||||||
| int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent) | int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) | ||||||
| { | { | ||||||
|     ImGuiIO& io = ImGui::GetIO(); |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|     int32_t event_type = AInputEvent_getType(inputEvent); |     int32_t event_type = AInputEvent_getType(input_event); | ||||||
|     switch (event_type) |     switch (event_type) | ||||||
|     { |     { | ||||||
|     case AINPUT_EVENT_TYPE_KEY: |     case AINPUT_EVENT_TYPE_KEY: | ||||||
|     { |     { | ||||||
|         int32_t event_key_code = AKeyEvent_getKeyCode(inputEvent); |         int32_t event_key_code = AKeyEvent_getKeyCode(input_event); | ||||||
|         int32_t event_action = AKeyEvent_getAction(inputEvent); |         int32_t event_action = AKeyEvent_getAction(input_event); | ||||||
|         int32_t event_meta_state = AKeyEvent_getMetaState(inputEvent); |         int32_t event_meta_state = AKeyEvent_getMetaState(input_event); | ||||||
|  |  | ||||||
|         io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0); |         io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0); | ||||||
|         io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0); |         io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0); | ||||||
| @@ -53,10 +53,9 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent) | |||||||
|  |  | ||||||
|         switch (event_action) |         switch (event_action) | ||||||
|         { |         { | ||||||
|         // FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once |         // FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer | ||||||
|         // as soon as a touch pointer goes up from a key. We use a simple key event queue |         // goes up from a key. We use a simple key event queue/ and process one event per key per frame in | ||||||
|         // and process one event per key per ImGui frame in ImGui_ImplAndroid_NewFrame(). |         // ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787 | ||||||
|         // ...or consider ImGui IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787 |  | ||||||
|         case AKEY_EVENT_ACTION_DOWN: |         case AKEY_EVENT_ACTION_DOWN: | ||||||
|         case AKEY_EVENT_ACTION_UP: |         case AKEY_EVENT_ACTION_UP: | ||||||
|             g_KeyEventQueues[event_key_code].push(event_action); |             g_KeyEventQueues[event_key_code].push(event_action); | ||||||
| @@ -68,7 +67,7 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent) | |||||||
|     } |     } | ||||||
|     case AINPUT_EVENT_TYPE_MOTION: |     case AINPUT_EVENT_TYPE_MOTION: | ||||||
|     { |     { | ||||||
|         int32_t event_action = AMotionEvent_getAction(inputEvent); |         int32_t event_action = AMotionEvent_getAction(input_event); | ||||||
|         int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; |         int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; | ||||||
|         event_action &= AMOTION_EVENT_ACTION_MASK; |         event_action &= AMOTION_EVENT_ACTION_MASK; | ||||||
|         switch (event_action) |         switch (event_action) | ||||||
| @@ -78,33 +77,29 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent) | |||||||
|             // Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP, |             // Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP, | ||||||
|             // but we have to process them separately to identify the actual button pressed. This is done below via |             // but we have to process them separately to identify the actual button pressed. This is done below via | ||||||
|             // AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback). |             // AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback). | ||||||
|             if((AMotionEvent_getToolType(inputEvent, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER) |             if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER) | ||||||
|             || (AMotionEvent_getToolType(inputEvent, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) |             || (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) | ||||||
|             { |             { | ||||||
|                 io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN) ? true : false; |                 io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN) ? true : false; | ||||||
|                 io.MousePos = ImVec2( |                 io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); | ||||||
|                         AMotionEvent_getX(inputEvent, event_pointer_index), |  | ||||||
|                         AMotionEvent_getY(inputEvent, event_pointer_index)); |  | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case AMOTION_EVENT_ACTION_BUTTON_PRESS: |         case AMOTION_EVENT_ACTION_BUTTON_PRESS: | ||||||
|         case AMOTION_EVENT_ACTION_BUTTON_RELEASE: |         case AMOTION_EVENT_ACTION_BUTTON_RELEASE: | ||||||
|             { |             { | ||||||
|                 int32_t button_state = AMotionEvent_getButtonState(inputEvent); |                 int32_t button_state = AMotionEvent_getButtonState(input_event); | ||||||
|                 io.MouseDown[0] = (button_state & AMOTION_EVENT_BUTTON_PRIMARY) ? true : false; |                 io.MouseDown[0] = (button_state & AMOTION_EVENT_BUTTON_PRIMARY) ? true : false; | ||||||
|                 io.MouseDown[1] = (button_state & AMOTION_EVENT_BUTTON_SECONDARY) ? true : false; |                 io.MouseDown[1] = (button_state & AMOTION_EVENT_BUTTON_SECONDARY) ? true : false; | ||||||
|                 io.MouseDown[2] = (button_state & AMOTION_EVENT_BUTTON_TERTIARY) ? true : false; |                 io.MouseDown[2] = (button_state & AMOTION_EVENT_BUTTON_TERTIARY) ? true : false; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse) |         case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse) | ||||||
|         case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN |         case AMOTION_EVENT_ACTION_MOVE:       // Touch pointer moves while DOWN | ||||||
|             io.MousePos = ImVec2( |             io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); | ||||||
|                 AMotionEvent_getX(inputEvent, event_pointer_index), |  | ||||||
|                 AMotionEvent_getY(inputEvent, event_pointer_index)); |  | ||||||
|             break; |             break; | ||||||
|         case AMOTION_EVENT_ACTION_SCROLL: |         case AMOTION_EVENT_ACTION_SCROLL: | ||||||
|             io.MouseWheel = AMotionEvent_getAxisValue(inputEvent, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index); |             io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index); | ||||||
|             io.MouseWheelH = AMotionEvent_getAxisValue(inputEvent, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index); |             io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index); | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|             break; |             break; | ||||||
| @@ -123,11 +118,11 @@ bool ImGui_ImplAndroid_Init(ANativeWindow* window) | |||||||
|     g_Window = window; |     g_Window = window; | ||||||
|     g_Time = 0.0; |     g_Time = 0.0; | ||||||
|  |  | ||||||
|     // Setup back-end capabilities flags |     // Setup backend capabilities flags | ||||||
|     ImGuiIO& io = ImGui::GetIO(); |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|     io.BackendPlatformName = "imgui_impl_android"; |     io.BackendPlatformName = "imgui_impl_android"; | ||||||
|  |  | ||||||
|     // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. |     // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. | ||||||
|     io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB; |     io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB; | ||||||
|     io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT;   // also covers physical keyboard arrow key |     io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT;   // also covers physical keyboard arrow key | ||||||
|     io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key |     io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key | ||||||
| @@ -161,10 +156,10 @@ void ImGui_ImplAndroid_Shutdown() | |||||||
| void ImGui_ImplAndroid_NewFrame() | void ImGui_ImplAndroid_NewFrame() | ||||||
| { | { | ||||||
|     ImGuiIO& io = ImGui::GetIO(); |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|     IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); |     IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); | ||||||
|  |  | ||||||
|     // Process queued key events |     // Process queued key events | ||||||
|     // FIXME: This is a workaround for multiple key event actions occuring at once (see above) and can be removed once we use upcoming input queue. |     // FIXME: This is a workaround for multiple key event actions occurring at once (see above) and can be removed once we use upcoming input queue. | ||||||
|     for (auto& key_queue : g_KeyEventQueues) |     for (auto& key_queue : g_KeyEventQueues) | ||||||
|     { |     { | ||||||
|         if (key_queue.second.empty()) |         if (key_queue.second.empty()) | ||||||
|   | |||||||
| @@ -3,9 +3,13 @@ | |||||||
|  |  | ||||||
| // Implemented features: | // Implemented features: | ||||||
| //  [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). | //  [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). | ||||||
|  | // Missing features: | ||||||
| //  [ ] Platform: Clipboard support. | //  [ ] Platform: Clipboard support. | ||||||
| //  [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | //  [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | ||||||
| //  [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. | //  [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. | ||||||
|  | // Important: | ||||||
|  | //  - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) | ||||||
|  | //  - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446) | ||||||
|  |  | ||||||
| // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | ||||||
| // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. | ||||||
| @@ -16,7 +20,7 @@ | |||||||
| struct ANativeWindow; | struct ANativeWindow; | ||||||
| struct AInputEvent; | struct AInputEvent; | ||||||
|  |  | ||||||
| IMGUI_IMPL_API int32_t  ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent); |  | ||||||
| IMGUI_IMPL_API bool     ImGui_ImplAndroid_Init(ANativeWindow* window); | IMGUI_IMPL_API bool     ImGui_ImplAndroid_Init(ANativeWindow* window); | ||||||
|  | IMGUI_IMPL_API int32_t  ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event); | ||||||
| IMGUI_IMPL_API void     ImGui_ImplAndroid_Shutdown(); | IMGUI_IMPL_API void     ImGui_ImplAndroid_Shutdown(); | ||||||
| IMGUI_IMPL_API void     ImGui_ImplAndroid_NewFrame(); | IMGUI_IMPL_API void     ImGui_ImplAndroid_NewFrame(); | ||||||
|   | |||||||
| @@ -149,7 +149,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw | |||||||
|     io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;          // We can honor io.WantSetMousePos requests (optional, rarely used) |     io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;          // We can honor io.WantSetMousePos requests (optional, rarely used) | ||||||
|     io.BackendPlatformName = "imgui_impl_glfw"; |     io.BackendPlatformName = "imgui_impl_glfw"; | ||||||
|  |  | ||||||
|     // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. |     // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. | ||||||
|     io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; |     io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; | ||||||
|     io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; |     io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; | ||||||
|     io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; |     io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; | ||||||
|   | |||||||
| @@ -220,7 +220,8 @@ bool    ImGui_Marmalade_Init(bool install_callbacks) | |||||||
|     ImGuiIO& io = ImGui::GetIO(); |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|     io.BackendPlatformName = io.BackendRendererName = "imgui_impl_marmalade"; |     io.BackendPlatformName = io.BackendRendererName = "imgui_impl_marmalade"; | ||||||
|  |  | ||||||
|     io.KeyMap[ImGuiKey_Tab] = s3eKeyTab;                     // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. |     // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. | ||||||
|  |     io.KeyMap[ImGuiKey_Tab] = s3eKeyTab | ||||||
|     io.KeyMap[ImGuiKey_LeftArrow] = s3eKeyLeft; |     io.KeyMap[ImGuiKey_LeftArrow] = s3eKeyLeft; | ||||||
|     io.KeyMap[ImGuiKey_RightArrow] = s3eKeyRight; |     io.KeyMap[ImGuiKey_RightArrow] = s3eKeyRight; | ||||||
|     io.KeyMap[ImGuiKey_UpArrow] = s3eKeyUp; |     io.KeyMap[ImGuiKey_UpArrow] = s3eKeyUp; | ||||||
|   | |||||||
| @@ -138,7 +138,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window) | |||||||
|     io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;        // We can honor io.WantSetMousePos requests (optional, rarely used) |     io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;        // We can honor io.WantSetMousePos requests (optional, rarely used) | ||||||
|     io.BackendPlatformName = "imgui_impl_sdl"; |     io.BackendPlatformName = "imgui_impl_sdl"; | ||||||
|  |  | ||||||
|     // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. |     // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. | ||||||
|     io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB; |     io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB; | ||||||
|     io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; |     io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; | ||||||
|     io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; |     io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; | ||||||
|   | |||||||
| @@ -731,7 +731,7 @@ void ImGui_ImplWGPU_InvalidateDeviceObjects() | |||||||
|  |  | ||||||
| bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format) | bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format) | ||||||
| { | { | ||||||
|     // Setup back-end capabilities flags |     // Setup backend capabilities flags | ||||||
|     ImGuiIO& io = ImGui::GetIO(); |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|     io.BackendRendererName = "imgui_impl_webgpu"; |     io.BackendRendererName = "imgui_impl_webgpu"; | ||||||
|     io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |     io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. | ||||||
|   | |||||||
| @@ -91,7 +91,7 @@ bool    ImGui_ImplWin32_Init(void* hwnd) | |||||||
|     io.BackendPlatformName = "imgui_impl_win32"; |     io.BackendPlatformName = "imgui_impl_win32"; | ||||||
|     io.ImeWindowHandle = hwnd; |     io.ImeWindowHandle = hwnd; | ||||||
|  |  | ||||||
|     // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. |     // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. | ||||||
|     io.KeyMap[ImGuiKey_Tab] = VK_TAB; |     io.KeyMap[ImGuiKey_Tab] = VK_TAB; | ||||||
|     io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; |     io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; | ||||||
|     io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; |     io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; | ||||||
|   | |||||||
| @@ -58,6 +58,7 @@ Other Changes: | |||||||
| - ImDrawList: AddCircle, AddCircleFilled(): Tweaked default segment count calculation to honor MaxError | - ImDrawList: AddCircle, AddCircleFilled(): Tweaked default segment count calculation to honor MaxError | ||||||
|   with more accuracy. Made default segment count always even for better looking result. (#3808) [@thedmd] |   with more accuracy. Made default segment count always even for better looking result. (#3808) [@thedmd] | ||||||
| - ImDrawList: AddCircle, AddCircleFilled(): New default for style. | - ImDrawList: AddCircle, AddCircleFilled(): New default for style. | ||||||
|  | - Backends: Android: Added native Android backend. (#3446) [@duddel] | ||||||
| - Backends: Win32: Added ImGui_ImplWin32_EnableAlphaCompositing() to facilitate experimenting with  | - Backends: Win32: Added ImGui_ImplWin32_EnableAlphaCompositing() to facilitate experimenting with  | ||||||
|   alpha compositing and transparent windows. (#2766, #3447 etc.). |   alpha compositing and transparent windows. (#2766, #3447 etc.). | ||||||
| - Backends: OpenGL, Vulkan, DX9, DX10, DX11, DX12, Metal, WebGPU, Allegro: Rework blending equation to | - Backends: OpenGL, Vulkan, DX9, DX10, DX11, DX12, Metal, WebGPU, Allegro: Rework blending equation to | ||||||
| @@ -66,6 +67,7 @@ Other Changes: | |||||||
|   (#2693, #2764, #2766, #2873, #3447, #3813, #3816) [@ocornut, @thedmd, @ShawnM427, @Ubpa, @aiekick] |   (#2693, #2764, #2766, #2873, #3447, #3813, #3816) [@ocornut, @thedmd, @ShawnM427, @Ubpa, @aiekick] | ||||||
| - Backends: DX9: Fix to support IMGUI_USE_BGRA_PACKED_COLOR. (#3844) [@Xiliusha] | - Backends: DX9: Fix to support IMGUI_USE_BGRA_PACKED_COLOR. (#3844) [@Xiliusha] | ||||||
| - Backends: DX9: Fix to support colored glyphs, using newly introduced 'TexPixelsUseColors' info. (#3844) | - Backends: DX9: Fix to support colored glyphs, using newly introduced 'TexPixelsUseColors' info. (#3844) | ||||||
|  | - Examples: Android: Added Android + GL ES2 example. (#3446) [@duddel] | ||||||
| - Examples: Reworked setup of clear color to be compatible with transparent values. | - Examples: Reworked setup of clear color to be compatible with transparent values. | ||||||
| - CI: Use a dedicated "scheduled" workflow to trigger scheduled builds. Forks may disable this workflow if | - CI: Use a dedicated "scheduled" workflow to trigger scheduled builds. Forks may disable this workflow if | ||||||
|   scheduled builds builds are not required. [@rokups] |   scheduled builds builds are not required. [@rokups] | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| cmake_minimum_required(VERSION 3.6) | cmake_minimum_required(VERSION 3.6) | ||||||
|  |  | ||||||
| project(ImguiExample) | project(ImGuiExample) | ||||||
|  |  | ||||||
| set(CMAKE_CXX_STANDARD 11) | set(CMAKE_CXX_STANDARD 11) | ||||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
|     package="imgui.example.android"> |     package="imgui.example.android"> | ||||||
|  |  | ||||||
|     <application |     <application | ||||||
|         android:label="ImguiExample" |         android:label="ImGuiExample" | ||||||
|         android:allowBackup="false" |         android:allowBackup="false" | ||||||
|         android:fullBackupContent="false" |         android:fullBackupContent="false" | ||||||
|         android:hasCode="true"> |         android:hasCode="true"> | ||||||
| @@ -13,7 +13,7 @@ | |||||||
|             android:theme="@android:style/Theme.NoTitleBar.Fullscreen" |             android:theme="@android:style/Theme.NoTitleBar.Fullscreen" | ||||||
|             android:configChanges="orientation|keyboardHidden|screenSize"> |             android:configChanges="orientation|keyboardHidden|screenSize"> | ||||||
|             <meta-data android:name="android.app.lib_name" |             <meta-data android:name="android.app.lib_name" | ||||||
|                 android:value="ImguiExample" /> |                 android:value="ImGuiExample" /> | ||||||
|  |  | ||||||
|             <intent-filter> |             <intent-filter> | ||||||
|                 <action android:name="android.intent.action.MAIN" /> |                 <action android:name="android.intent.action.MAIN" /> | ||||||
|   | |||||||
| @@ -10,98 +10,18 @@ | |||||||
| #include <EGL/egl.h> | #include <EGL/egl.h> | ||||||
| #include <GLES3/gl3.h> | #include <GLES3/gl3.h> | ||||||
|  |  | ||||||
|  | // Data | ||||||
| static EGLDisplay           g_EglDisplay = EGL_NO_DISPLAY; | static EGLDisplay           g_EglDisplay = EGL_NO_DISPLAY; | ||||||
| static EGLSurface           g_EglSurface = EGL_NO_SURFACE; | static EGLSurface           g_EglSurface = EGL_NO_SURFACE; | ||||||
| static EGLContext           g_EglContext = EGL_NO_CONTEXT; | static EGLContext           g_EglContext = EGL_NO_CONTEXT; | ||||||
| static struct android_app*  g_App = NULL; | static struct android_app*  g_App = NULL; | ||||||
| static bool                 g_Initialized = false; | static bool                 g_Initialized = false; | ||||||
| static char                 g_LogTag[] = "ImguiExample"; | static char                 g_LogTag[] = "ImGuiExample"; | ||||||
|  |  | ||||||
| // Unfortunately, there is no way to show the on-screen input from native code. | // Forward declarations of helper functions | ||||||
| // Therefore, we call showSoftInput() of the main activity implemented in MainActivity.kt via JNI. | static int ShowSoftKeyboardInput(); | ||||||
| static int showSoftInput() | static int PollUnicodeChars(); | ||||||
| { | static int GetAssetData(const char* filename, void** out_data); | ||||||
|     JavaVM* java_vm = g_App->activity->vm; |  | ||||||
|     JNIEnv* java_env = NULL; |  | ||||||
|  |  | ||||||
|     jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6); |  | ||||||
|     if (jni_return == JNI_ERR) |  | ||||||
|         return -1; |  | ||||||
|  |  | ||||||
|     jni_return = java_vm->AttachCurrentThread(&java_env, NULL); |  | ||||||
|     if (jni_return != JNI_OK) |  | ||||||
|         return -2; |  | ||||||
|  |  | ||||||
|     jclass native_activity_clazz = java_env->GetObjectClass(g_App->activity->clazz); |  | ||||||
|     if (native_activity_clazz == NULL) |  | ||||||
|         return -3; |  | ||||||
|  |  | ||||||
|     jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "showSoftInput", "()V"); |  | ||||||
|     if (method_id == NULL) |  | ||||||
|         return -4; |  | ||||||
|  |  | ||||||
|     java_env->CallVoidMethod(g_App->activity->clazz, method_id); |  | ||||||
|  |  | ||||||
|     jni_return = java_vm->DetachCurrentThread(); |  | ||||||
|     if (jni_return != JNI_OK) |  | ||||||
|         return -5; |  | ||||||
|  |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Unfortunately, the native KeyEvent implementation has no getUnicodeChar() function. |  | ||||||
| // Therefore, we implement the processing of KeyEvents in MainActivity.kt and poll |  | ||||||
| // the resulting Unicode characters here via JNI and send them to Dear ImGui. |  | ||||||
| static int pollUnicodeChars() |  | ||||||
| { |  | ||||||
|     JavaVM* java_vm = g_App->activity->vm; |  | ||||||
|     JNIEnv* java_env = NULL; |  | ||||||
|  |  | ||||||
|     jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6); |  | ||||||
|     if (jni_return == JNI_ERR) |  | ||||||
|         return -1; |  | ||||||
|  |  | ||||||
|     jni_return = java_vm->AttachCurrentThread(&java_env, NULL); |  | ||||||
|     if (jni_return != JNI_OK) |  | ||||||
|         return -2; |  | ||||||
|  |  | ||||||
|     jclass native_activity_clazz = java_env->GetObjectClass(g_App->activity->clazz); |  | ||||||
|     if (native_activity_clazz == NULL) |  | ||||||
|         return -3; |  | ||||||
|  |  | ||||||
|     jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "pollUnicodeChar", "()I"); |  | ||||||
|     if (method_id == NULL) |  | ||||||
|         return -4; |  | ||||||
|  |  | ||||||
|     // Send the actual characters to Dear ImGui |  | ||||||
|     ImGuiIO& io = ImGui::GetIO(); |  | ||||||
|     jint unicode_character; |  | ||||||
|     while ((unicode_character = java_env->CallIntMethod(g_App->activity->clazz, method_id)) != 0) |  | ||||||
|     { |  | ||||||
|         io.AddInputCharacter(unicode_character); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     jni_return = java_vm->DetachCurrentThread(); |  | ||||||
|     if (jni_return != JNI_OK) |  | ||||||
|         return -5; |  | ||||||
|  |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int GetAssetData(const char* filename, void** outData) |  | ||||||
| { |  | ||||||
|     int num_bytes = 0; |  | ||||||
|     AAsset* asset_descriptor = AAssetManager_open(g_App->activity->assetManager, filename, AASSET_MODE_BUFFER); |  | ||||||
|     if(asset_descriptor) |  | ||||||
|     { |  | ||||||
|         num_bytes = AAsset_getLength(asset_descriptor); |  | ||||||
|         *outData = IM_ALLOC(num_bytes); |  | ||||||
|         int64_t num_bytes_read = AAsset_read(asset_descriptor, *outData, num_bytes); |  | ||||||
|         AAsset_close(asset_descriptor); |  | ||||||
|         IM_ASSERT(num_bytes_read == num_bytes); |  | ||||||
|     } |  | ||||||
|     return num_bytes; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void init(struct android_app* app) | void init(struct android_app* app) | ||||||
| { | { | ||||||
| @@ -113,65 +33,66 @@ void init(struct android_app* app) | |||||||
|  |  | ||||||
|     // Initialize EGL |     // Initialize EGL | ||||||
|     // This is mostly boilerplate code for EGL... |     // This is mostly boilerplate code for EGL... | ||||||
|     g_EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); |     { | ||||||
|  |         g_EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); | ||||||
|  |         if (g_EglDisplay == EGL_NO_DISPLAY) | ||||||
|  |             __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglGetDisplay(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY"); | ||||||
|  |  | ||||||
|     if (g_EglDisplay == EGL_NO_DISPLAY) |         if (eglInitialize(g_EglDisplay, 0, 0) != EGL_TRUE) | ||||||
|         __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglGetDisplay(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY"); |             __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglInitialize() returned with an error"); | ||||||
|  |  | ||||||
|     if (eglInitialize(g_EglDisplay, 0, 0) != EGL_TRUE) |         const EGLint egl_attributes[] = { EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; | ||||||
|         __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglInitialize(..) returned with an error"); |         EGLint num_configs = 0; | ||||||
|  |         if (eglChooseConfig(g_EglDisplay, egl_attributes, nullptr, 0, &num_configs) != EGL_TRUE) | ||||||
|  |             __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglChooseConfig() returned with an error"); | ||||||
|  |         if (num_configs == 0) | ||||||
|  |             __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglChooseConfig() returned 0 matching config"); | ||||||
|  |  | ||||||
|     const EGLint egl_attributes[] = { |         // Get the first matching config | ||||||
|         EGL_BLUE_SIZE, 8, |         EGLConfig egl_config; | ||||||
|         EGL_GREEN_SIZE, 8, |         eglChooseConfig(g_EglDisplay, egl_attributes, &egl_config, 1, &num_configs); | ||||||
|         EGL_RED_SIZE, 8, |         EGLint egl_format; | ||||||
|         EGL_DEPTH_SIZE, 24, |         eglGetConfigAttrib(g_EglDisplay, egl_config, EGL_NATIVE_VISUAL_ID, &egl_format); | ||||||
|         EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |         ANativeWindow_setBuffersGeometry(g_App->window, 0, 0, egl_format); | ||||||
|         EGL_NONE}; |  | ||||||
|  |  | ||||||
|     EGLint num_configs = 0; |         const EGLint egl_context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; | ||||||
|     if (eglChooseConfig(g_EglDisplay, egl_attributes, nullptr, 0, &num_configs) != EGL_TRUE) |         g_EglContext = eglCreateContext(g_EglDisplay, egl_config, EGL_NO_CONTEXT, egl_context_attributes); | ||||||
|         __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglChooseConfig(..) returned with an error"); |  | ||||||
|  |  | ||||||
|     if (num_configs == 0) |         if (g_EglContext == EGL_NO_CONTEXT) | ||||||
|         __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglChooseConfig(..) returned 0 matching configs"); |             __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglCreateContext() returned EGL_NO_CONTEXT"); | ||||||
|  |  | ||||||
|     // Get the (first) matching config |         g_EglSurface = eglCreateWindowSurface(g_EglDisplay, egl_config, g_App->window, NULL); | ||||||
|     EGLConfig egl_config; |         eglMakeCurrent(g_EglDisplay, g_EglSurface, g_EglSurface, g_EglContext); | ||||||
|     eglChooseConfig(g_EglDisplay, egl_attributes, &egl_config, 1, &num_configs); |     } | ||||||
|     EGLint egl_format; |  | ||||||
|     eglGetConfigAttrib(g_EglDisplay, egl_config, EGL_NATIVE_VISUAL_ID, &egl_format); |  | ||||||
|     ANativeWindow_setBuffersGeometry(g_App->window, 0, 0, egl_format); |  | ||||||
|  |  | ||||||
|     const EGLint egl_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; |     // Setup Dear ImGui context | ||||||
|     g_EglContext = eglCreateContext(g_EglDisplay, egl_config, EGL_NO_CONTEXT, egl_context_attributes); |  | ||||||
|  |  | ||||||
|     if (g_EglContext == EGL_NO_CONTEXT) |  | ||||||
|         __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglCreateContext(..) returned EGL_NO_CONTEXT"); |  | ||||||
|  |  | ||||||
|     g_EglSurface = eglCreateWindowSurface(g_EglDisplay, egl_config, g_App->window, NULL); |  | ||||||
|     eglMakeCurrent(g_EglDisplay, g_EglSurface, g_EglSurface, g_EglContext); |  | ||||||
|  |  | ||||||
|     // Dear Imgui |  | ||||||
|     IMGUI_CHECKVERSION(); |     IMGUI_CHECKVERSION(); | ||||||
|     ImGui::CreateContext(); |     ImGui::CreateContext(); | ||||||
|     ImGuiIO& io = ImGui::GetIO(); |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |  | ||||||
|  |     // Disable loading/saving of .ini file from disk. | ||||||
|  |     // FIXME: Consider using LoadIniSettingsFromMemory() / SaveIniSettingsToMemory() to save in appropriate location for Android. | ||||||
|     io.IniFilename = NULL; |     io.IniFilename = NULL; | ||||||
|  |  | ||||||
|  |     // Setup Dear ImGui style | ||||||
|     ImGui::StyleColorsDark(); |     ImGui::StyleColorsDark(); | ||||||
|  |     //ImGui::StyleColorsClassic(); | ||||||
|  |  | ||||||
|  |     // Setup Platform/Renderer backends | ||||||
|     ImGui_ImplAndroid_Init(g_App->window); |     ImGui_ImplAndroid_Init(g_App->window); | ||||||
|     ImGui_ImplOpenGL3_Init("#version 300 es"); |     ImGui_ImplOpenGL3_Init("#version 300 es"); | ||||||
|  |  | ||||||
|     // Load Fonts |     // Load Fonts | ||||||
|     // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. |     // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. | ||||||
|     // - add_font_from_assets_ttf() will return the ImFont* so you can store it if you need to select the font among multiple. |  | ||||||
|     // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). |     // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). | ||||||
|     // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. |     // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. | ||||||
|     // - Read 'docs/FONTS.md' for more instructions and details. |     // - Read 'docs/FONTS.md' for more instructions and details. | ||||||
|     // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! |     // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! | ||||||
|     // - The TTF files have to be placed into the assets/ directory (android/app/src/main/assets). |     // - Android: The TTF files have to be placed into the assets/ directory (android/app/src/main/assets), we use our GetAssetData() helper to retrieve them. | ||||||
|  |  | ||||||
|     // We load the default font with increased size to improve readability on many devices with "high" DPI. |     // We load the default font with increased size to improve readability on many devices with "high" DPI. | ||||||
|     // FIXME: Put some effort into DPI awareness |     // FIXME: Put some effort into DPI awareness. | ||||||
|  |     // Important: when calling AddFontFromMemoryTTF(), ownership of font_data is transfered by Dear ImGui by default (deleted is handled by Dear ImGui), unless we set FontDataOwnedByAtlas=false in ImFontConfig | ||||||
|     ImFontConfig font_cfg; |     ImFontConfig font_cfg; | ||||||
|     font_cfg.SizePixels = 22.0f; |     font_cfg.SizePixels = 22.0f; | ||||||
|     io.Fonts->AddFontDefault(&font_cfg); |     io.Fonts->AddFontDefault(&font_cfg); | ||||||
| @@ -179,19 +100,19 @@ void init(struct android_app* app) | |||||||
|     //int font_data_size; |     //int font_data_size; | ||||||
|     //ImFont* font; |     //ImFont* font; | ||||||
|     //font_data_size = GetAssetData("Roboto-Medium.ttf", &font_data); |     //font_data_size = GetAssetData("Roboto-Medium.ttf", &font_data); | ||||||
|     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 16.0f); // Ownership of font_data is transfered to ImGui. Deletion is handled by ImGui. |     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 16.0f); | ||||||
|     //IM_ASSERT(font != NULL); |     //IM_ASSERT(font != NULL); | ||||||
|     //font_data_size = GetAssetData("Cousine-Regular.ttf", &font_data); |     //font_data_size = GetAssetData("Cousine-Regular.ttf", &font_data); | ||||||
|     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 15.0f); // Ownership of font_data is transfered to ImGui. Deletion is handled by ImGui. |     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 15.0f); | ||||||
|     //IM_ASSERT(font != NULL); |     //IM_ASSERT(font != NULL); | ||||||
|     //font_data_size = GetAssetData("DroidSans.ttf", &font_data); |     //font_data_size = GetAssetData("DroidSans.ttf", &font_data); | ||||||
|     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 16.0f); // Ownership of font_data is transfered to ImGui. Deletion is handled by ImGui. |     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 16.0f); | ||||||
|     //IM_ASSERT(font != NULL); |     //IM_ASSERT(font != NULL); | ||||||
|     //font_data_size = GetAssetData("ProggyTiny.ttf", &font_data); |     //font_data_size = GetAssetData("ProggyTiny.ttf", &font_data); | ||||||
|     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 10.0f); // Ownership of font_data is transfered to ImGui. Deletion is handled by ImGui. |     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 10.0f); | ||||||
|     //IM_ASSERT(font != NULL); |     //IM_ASSERT(font != NULL); | ||||||
|     //font_data_size = GetAssetData("ArialUni.ttf", &font_data); |     //font_data_size = GetAssetData("ArialUni.ttf", &font_data); | ||||||
|     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); // Ownership of font_data is transfered to ImGui. Deletion is handled by ImGui. |     //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); | ||||||
|     //IM_ASSERT(font != NULL); |     //IM_ASSERT(font != NULL); | ||||||
|  |  | ||||||
|     // Arbitrary scale-up |     // Arbitrary scale-up | ||||||
| @@ -203,75 +124,74 @@ void init(struct android_app* app) | |||||||
|  |  | ||||||
| void tick() | void tick() | ||||||
| { | { | ||||||
|     // Our state (Dear Imgui) |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     if (g_EglDisplay == EGL_NO_DISPLAY) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     // Our state | ||||||
|     static bool show_demo_window = true; |     static bool show_demo_window = true; | ||||||
|     static bool show_another_window = false; |     static bool show_another_window = false; | ||||||
|     static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); |     static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); | ||||||
|  |  | ||||||
|     if (g_EglDisplay != EGL_NO_DISPLAY) |     // Poll Unicode characters via JNI | ||||||
|  |     // FIXME: do not call this every frame because of JNI overhead | ||||||
|  |     PollUnicodeChars(); | ||||||
|  |  | ||||||
|  |     // Open on-screen (soft) input if requested by Dear ImGui | ||||||
|  |     static bool WantTextInputLast = false; | ||||||
|  |     if (io.WantTextInput && !WantTextInputLast) | ||||||
|  |         ShowSoftKeyboardInput(); | ||||||
|  |     WantTextInputLast = io.WantTextInput; | ||||||
|  |  | ||||||
|  |     // Start the Dear ImGui frame | ||||||
|  |     ImGui_ImplOpenGL3_NewFrame(); | ||||||
|  |     ImGui_ImplAndroid_NewFrame(); | ||||||
|  |     ImGui::NewFrame(); | ||||||
|  |  | ||||||
|  |     // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). | ||||||
|  |     if (show_demo_window) | ||||||
|  |         ImGui::ShowDemoWindow(&show_demo_window); | ||||||
|  |  | ||||||
|  |     // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. | ||||||
|     { |     { | ||||||
|         ImGuiIO& io = ImGui::GetIO(); |         static float f = 0.0f; | ||||||
|  |         static int counter = 0; | ||||||
|  |  | ||||||
|         // Poll Unicode characters via JNI |         ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. | ||||||
|         // FIXME: do not call this every frame because of JNI overhead |  | ||||||
|         pollUnicodeChars(); |  | ||||||
|  |  | ||||||
|         // Open on-screen (soft) input if demanded by Dear ImGui |         ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too) | ||||||
|         static bool WantTextInputLast = false; |         ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state | ||||||
|         if (io.WantTextInput && !WantTextInputLast) |         ImGui::Checkbox("Another Window", &show_another_window); | ||||||
|             showSoftInput(); |  | ||||||
|         WantTextInputLast = io.WantTextInput; |  | ||||||
|  |  | ||||||
|         // Start the Dear ImGui frame |         ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f | ||||||
|         ImGui_ImplOpenGL3_NewFrame(); |         ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color | ||||||
|         ImGui_ImplAndroid_NewFrame(); |  | ||||||
|         ImGui::NewFrame(); |  | ||||||
|  |  | ||||||
|         // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). |         if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated) | ||||||
|         if (show_demo_window) |             counter++; | ||||||
|             ImGui::ShowDemoWindow(&show_demo_window); |         ImGui::SameLine(); | ||||||
|  |         ImGui::Text("counter = %d", counter); | ||||||
|  |  | ||||||
|         // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. |         ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); | ||||||
|         { |         ImGui::End(); | ||||||
|             static float f = 0.0f; |  | ||||||
|             static int counter = 0; |  | ||||||
|  |  | ||||||
|             ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. |  | ||||||
|  |  | ||||||
|             ImGui::Text("This is some useful text.");          // Display some text (you can use a format strings too) |  | ||||||
|             ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state |  | ||||||
|             ImGui::Checkbox("Another Window", &show_another_window); |  | ||||||
|  |  | ||||||
|             ImGui::SliderFloat("float", &f, 0.0f, 1.0f);             // Edit 1 float using a slider from 0.0f to 1.0f |  | ||||||
|             ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color |  | ||||||
|  |  | ||||||
|             if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) |  | ||||||
|                 counter++; |  | ||||||
|             ImGui::SameLine(); |  | ||||||
|             ImGui::Text("counter = %d", counter); |  | ||||||
|  |  | ||||||
|             ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); |  | ||||||
|             ImGui::End(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 3. Show another simple window. |  | ||||||
|         if (show_another_window) |  | ||||||
|         { |  | ||||||
|             ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) |  | ||||||
|             ImGui::Text("Hello from another window!"); |  | ||||||
|             if (ImGui::Button("Close Me")) |  | ||||||
|                 show_another_window = false; |  | ||||||
|             ImGui::End(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Rendering |  | ||||||
|         ImGui::Render(); |  | ||||||
|         glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); |  | ||||||
|         glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); |  | ||||||
|         glClear(GL_COLOR_BUFFER_BIT); |  | ||||||
|         ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); |  | ||||||
|         eglSwapBuffers(g_EglDisplay, g_EglSurface); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // 3. Show another simple window. | ||||||
|  |     if (show_another_window) | ||||||
|  |     { | ||||||
|  |         ImGui::Begin("Another Window", &show_another_window);   // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) | ||||||
|  |         ImGui::Text("Hello from another window!"); | ||||||
|  |         if (ImGui::Button("Close Me")) | ||||||
|  |             show_another_window = false; | ||||||
|  |         ImGui::End(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Rendering | ||||||
|  |     ImGui::Render(); | ||||||
|  |     glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); | ||||||
|  |     glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); | ||||||
|  |     glClear(GL_COLOR_BUFFER_BIT); | ||||||
|  |     ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); | ||||||
|  |     eglSwapBuffers(g_EglDisplay, g_EglSurface); | ||||||
| } | } | ||||||
|  |  | ||||||
| void shutdown() | void shutdown() | ||||||
| @@ -279,7 +199,7 @@ void shutdown() | |||||||
|     if (!g_Initialized) |     if (!g_Initialized) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|     // Cleanup (Dear Imgui) |     // Cleanup | ||||||
|     ImGui_ImplOpenGL3_Shutdown(); |     ImGui_ImplOpenGL3_Shutdown(); | ||||||
|     ImGui_ImplAndroid_Shutdown(); |     ImGui_ImplAndroid_Shutdown(); | ||||||
|     ImGui::DestroyContext(); |     ImGui::DestroyContext(); | ||||||
| @@ -362,3 +282,88 @@ void android_main(struct android_app* app) | |||||||
|         tick(); |         tick(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Unfortunately, there is no way to show the on-screen input from native code. | ||||||
|  | // Therefore, we call ShowSoftKeyboardInput() of the main activity implemented in MainActivity.kt via JNI. | ||||||
|  | static int ShowSoftKeyboardInput() | ||||||
|  | { | ||||||
|  |     JavaVM* java_vm = g_App->activity->vm; | ||||||
|  |     JNIEnv* java_env = NULL; | ||||||
|  |  | ||||||
|  |     jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6); | ||||||
|  |     if (jni_return == JNI_ERR) | ||||||
|  |         return -1; | ||||||
|  |  | ||||||
|  |     jni_return = java_vm->AttachCurrentThread(&java_env, NULL); | ||||||
|  |     if (jni_return != JNI_OK) | ||||||
|  |         return -2; | ||||||
|  |  | ||||||
|  |     jclass native_activity_clazz = java_env->GetObjectClass(g_App->activity->clazz); | ||||||
|  |     if (native_activity_clazz == NULL) | ||||||
|  |         return -3; | ||||||
|  |  | ||||||
|  |     jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "showSoftInput", "()V"); | ||||||
|  |     if (method_id == NULL) | ||||||
|  |         return -4; | ||||||
|  |  | ||||||
|  |     java_env->CallVoidMethod(g_App->activity->clazz, method_id); | ||||||
|  |  | ||||||
|  |     jni_return = java_vm->DetachCurrentThread(); | ||||||
|  |     if (jni_return != JNI_OK) | ||||||
|  |         return -5; | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Unfortunately, the native KeyEvent implementation has no getUnicodeChar() function. | ||||||
|  | // Therefore, we implement the processing of KeyEvents in MainActivity.kt and poll | ||||||
|  | // the resulting Unicode characters here via JNI and send them to Dear ImGui. | ||||||
|  | static int PollUnicodeChars() | ||||||
|  | { | ||||||
|  |     JavaVM* java_vm = g_App->activity->vm; | ||||||
|  |     JNIEnv* java_env = NULL; | ||||||
|  |  | ||||||
|  |     jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6); | ||||||
|  |     if (jni_return == JNI_ERR) | ||||||
|  |         return -1; | ||||||
|  |  | ||||||
|  |     jni_return = java_vm->AttachCurrentThread(&java_env, NULL); | ||||||
|  |     if (jni_return != JNI_OK) | ||||||
|  |         return -2; | ||||||
|  |  | ||||||
|  |     jclass native_activity_clazz = java_env->GetObjectClass(g_App->activity->clazz); | ||||||
|  |     if (native_activity_clazz == NULL) | ||||||
|  |         return -3; | ||||||
|  |  | ||||||
|  |     jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "pollUnicodeChar", "()I"); | ||||||
|  |     if (method_id == NULL) | ||||||
|  |         return -4; | ||||||
|  |  | ||||||
|  |     // Send the actual characters to Dear ImGui | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     jint unicode_character; | ||||||
|  |     while ((unicode_character = java_env->CallIntMethod(g_App->activity->clazz, method_id)) != 0) | ||||||
|  |         io.AddInputCharacter(unicode_character); | ||||||
|  |  | ||||||
|  |     jni_return = java_vm->DetachCurrentThread(); | ||||||
|  |     if (jni_return != JNI_OK) | ||||||
|  |         return -5; | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Helper to retrieve data placed into the assets/ directory (android/app/src/main/assets) | ||||||
|  | static int GetAssetData(const char* filename, void** outData) | ||||||
|  | { | ||||||
|  |     int num_bytes = 0; | ||||||
|  |     AAsset* asset_descriptor = AAssetManager_open(g_App->activity->assetManager, filename, AASSET_MODE_BUFFER); | ||||||
|  |     if (asset_descriptor) | ||||||
|  |     { | ||||||
|  |         num_bytes = AAsset_getLength(asset_descriptor); | ||||||
|  |         *outData = IM_ALLOC(num_bytes); | ||||||
|  |         int64_t num_bytes_read = AAsset_read(asset_descriptor, *outData, num_bytes); | ||||||
|  |         AAsset_close(asset_descriptor); | ||||||
|  |         IM_ASSERT(num_bytes_read == num_bytes); | ||||||
|  |     } | ||||||
|  |     return num_bytes; | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								imgui.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								imgui.h
									
									
									
									
									
								
							| @@ -2767,7 +2767,7 @@ enum ImGuiViewportFlags_ | |||||||
| struct ImGuiViewport | struct ImGuiViewport | ||||||
| { | { | ||||||
|     ImGuiViewportFlags  Flags;                  // See ImGuiViewportFlags_ |     ImGuiViewportFlags  Flags;                  // See ImGuiViewportFlags_ | ||||||
|     ImVec2              Pos;                    // Main Area: Position of the viewport (Dear Imgui coordinates are the same as OS desktop/native coordinates) |     ImVec2              Pos;                    // Main Area: Position of the viewport (Dear ImGui coordinates are the same as OS desktop/native coordinates) | ||||||
|     ImVec2              Size;                   // Main Area: Size of the viewport. |     ImVec2              Size;                   // Main Area: Size of the viewport. | ||||||
|     ImVec2              WorkPos;                // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) |     ImVec2              WorkPos;                // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) | ||||||
|     ImVec2              WorkSize;               // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) |     ImVec2              WorkSize;               // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user