mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-30 20:51:06 +01:00 
			
		
		
		
	Android: Amend backend and examples with minor consistency tweaks. (#3446)
This commit is contained in:
		| @@ -3,9 +3,13 @@ | ||||
|  | ||||
| // Implemented features: | ||||
| //  [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). | ||||
| // Missing features: | ||||
| //  [ ] Platform: Clipboard support. | ||||
| //  [ ] 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. | ||||
| // 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. | ||||
| // 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 | ||||
| // (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) | ||||
| //  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 | ||||
| //  2021-03-04: Initial version. | ||||
|  | ||||
| #include "imgui.h" | ||||
| #include "imgui_impl_android.h" | ||||
| #include <time.h> | ||||
| #include <map> | ||||
| #include <queue> | ||||
|  | ||||
| // Android | ||||
| #include <android/native_window.h> | ||||
| #include <android/input.h> | ||||
| #include <android/keycodes.h> | ||||
| #include <android/log.h> | ||||
|  | ||||
| // Android data | ||||
| static double                                   g_Time = 0.0; | ||||
| 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. | ||||
|  | ||||
| int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent) | ||||
| int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) | ||||
| { | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     int32_t event_type = AInputEvent_getType(inputEvent); | ||||
|     int32_t event_type = AInputEvent_getType(input_event); | ||||
|     switch (event_type) | ||||
|     { | ||||
|     case AINPUT_EVENT_TYPE_KEY: | ||||
|     { | ||||
|         int32_t event_key_code = AKeyEvent_getKeyCode(inputEvent); | ||||
|         int32_t event_action = AKeyEvent_getAction(inputEvent); | ||||
|         int32_t event_meta_state = AKeyEvent_getMetaState(inputEvent); | ||||
|         int32_t event_key_code = AKeyEvent_getKeyCode(input_event); | ||||
|         int32_t event_action = AKeyEvent_getAction(input_event); | ||||
|         int32_t event_meta_state = AKeyEvent_getMetaState(input_event); | ||||
|  | ||||
|         io.KeyCtrl = ((event_meta_state & AMETA_CTRL_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) | ||||
|         { | ||||
|         // FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once | ||||
|         // as soon as a touch pointer goes up from a key. We use a simple key event queue | ||||
|         // and process one event per key per ImGui frame in ImGui_ImplAndroid_NewFrame(). | ||||
|         // ...or consider ImGui IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787 | ||||
|         // FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer | ||||
|         // goes up from a key. We use a simple key event queue/ and process one event per key per frame in | ||||
|         // ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787 | ||||
|         case AKEY_EVENT_ACTION_DOWN: | ||||
|         case AKEY_EVENT_ACTION_UP: | ||||
|             g_KeyEventQueues[event_key_code].push(event_action); | ||||
| @@ -68,7 +67,7 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent) | ||||
|     } | ||||
|     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; | ||||
|         event_action &= AMOTION_EVENT_ACTION_MASK; | ||||
|         switch (event_action) | ||||
| @@ -78,19 +77,17 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent) | ||||
|             // 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 | ||||
|             // 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) | ||||
|             || (AMotionEvent_getToolType(inputEvent, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) | ||||
|             if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER) | ||||
|             || (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) | ||||
|             { | ||||
|                 io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN) ? true : false; | ||||
|                 io.MousePos = ImVec2( | ||||
|                         AMotionEvent_getX(inputEvent, event_pointer_index), | ||||
|                         AMotionEvent_getY(inputEvent, event_pointer_index)); | ||||
|                 io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); | ||||
|             } | ||||
|             break; | ||||
|         case AMOTION_EVENT_ACTION_BUTTON_PRESS: | ||||
|         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[1] = (button_state & AMOTION_EVENT_BUTTON_SECONDARY) ? true : false; | ||||
|                 io.MouseDown[2] = (button_state & AMOTION_EVENT_BUTTON_TERTIARY) ? true : false; | ||||
| @@ -98,13 +95,11 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent) | ||||
|             break; | ||||
|         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 | ||||
|             io.MousePos = ImVec2( | ||||
|                 AMotionEvent_getX(inputEvent, event_pointer_index), | ||||
|                 AMotionEvent_getY(inputEvent, event_pointer_index)); | ||||
|             io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); | ||||
|             break; | ||||
|         case AMOTION_EVENT_ACTION_SCROLL: | ||||
|             io.MouseWheel = AMotionEvent_getAxisValue(inputEvent, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index); | ||||
|             io.MouseWheelH = AMotionEvent_getAxisValue(inputEvent, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index); | ||||
|             io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index); | ||||
|             io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
| @@ -123,11 +118,11 @@ bool ImGui_ImplAndroid_Init(ANativeWindow* window) | ||||
|     g_Window = window; | ||||
|     g_Time = 0.0; | ||||
|  | ||||
|     // Setup back-end capabilities flags | ||||
|     // Setup backend capabilities flags | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     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_LeftArrow] = AKEYCODE_DPAD_LEFT;   // 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() | ||||
| { | ||||
|     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 | ||||
|     // 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) | ||||
|     { | ||||
|         if (key_queue.second.empty()) | ||||
|   | ||||
| @@ -3,9 +3,13 @@ | ||||
|  | ||||
| // Implemented features: | ||||
| //  [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). | ||||
| // Missing features: | ||||
| //  [ ] Platform: Clipboard support. | ||||
| //  [ ] 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. | ||||
| // 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. | ||||
| // 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 AInputEvent; | ||||
|  | ||||
| IMGUI_IMPL_API int32_t  ImGui_ImplAndroid_HandleInputEvent(AInputEvent* inputEvent); | ||||
| 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_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.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_LeftArrow] = GLFW_KEY_LEFT; | ||||
|     io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; | ||||
|   | ||||
| @@ -220,7 +220,8 @@ bool    ImGui_Marmalade_Init(bool install_callbacks) | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     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_RightArrow] = s3eKeyRight; | ||||
|     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.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_LeftArrow] = SDL_SCANCODE_LEFT; | ||||
|     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) | ||||
| { | ||||
|     // Setup back-end capabilities flags | ||||
|     // Setup backend capabilities flags | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     io.BackendRendererName = "imgui_impl_webgpu"; | ||||
|     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.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_LeftArrow] = VK_LEFT; | ||||
|     io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; | ||||
|   | ||||
| @@ -58,6 +58,7 @@ Other Changes: | ||||
| - 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] | ||||
| - 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  | ||||
|   alpha compositing and transparent windows. (#2766, #3447 etc.). | ||||
| - 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] | ||||
| - 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) | ||||
| - Examples: Android: Added Android + GL ES2 example. (#3446) [@duddel] | ||||
| - 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 | ||||
|   scheduled builds builds are not required. [@rokups] | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| cmake_minimum_required(VERSION 3.6) | ||||
|  | ||||
| project(ImguiExample) | ||||
| project(ImGuiExample) | ||||
|  | ||||
| set(CMAKE_CXX_STANDARD 11) | ||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
|     package="imgui.example.android"> | ||||
|  | ||||
|     <application | ||||
|         android:label="ImguiExample" | ||||
|         android:label="ImGuiExample" | ||||
|         android:allowBackup="false" | ||||
|         android:fullBackupContent="false" | ||||
|         android:hasCode="true"> | ||||
| @@ -13,7 +13,7 @@ | ||||
|             android:theme="@android:style/Theme.NoTitleBar.Fullscreen" | ||||
|             android:configChanges="orientation|keyboardHidden|screenSize"> | ||||
|             <meta-data android:name="android.app.lib_name" | ||||
|                 android:value="ImguiExample" /> | ||||
|                 android:value="ImGuiExample" /> | ||||
|  | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.MAIN" /> | ||||
|   | ||||
| @@ -10,98 +10,18 @@ | ||||
| #include <EGL/egl.h> | ||||
| #include <GLES3/gl3.h> | ||||
|  | ||||
| // Data | ||||
| static EGLDisplay           g_EglDisplay = EGL_NO_DISPLAY; | ||||
| static EGLSurface           g_EglSurface = EGL_NO_SURFACE; | ||||
| static EGLContext           g_EglContext = EGL_NO_CONTEXT; | ||||
| static struct android_app*  g_App = NULL; | ||||
| 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. | ||||
| // Therefore, we call showSoftInput() of the main activity implemented in MainActivity.kt via JNI. | ||||
| static int showSoftInput() | ||||
| { | ||||
|     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; | ||||
| } | ||||
| // Forward declarations of helper functions | ||||
| static int ShowSoftKeyboardInput(); | ||||
| static int PollUnicodeChars(); | ||||
| static int GetAssetData(const char* filename, void** out_data); | ||||
|  | ||||
| void init(struct android_app* app) | ||||
| { | ||||
| @@ -113,30 +33,22 @@ void init(struct android_app* app) | ||||
|  | ||||
|     // Initialize EGL | ||||
|     // This is mostly boilerplate code for EGL... | ||||
|     { | ||||
|         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 (eglInitialize(g_EglDisplay, 0, 0) != EGL_TRUE) | ||||
|         __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglInitialize(..) returned with an error"); | ||||
|  | ||||
|     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"); | ||||
|  | ||||
|         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 }; | ||||
|         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"); | ||||
|  | ||||
|             __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 configs"); | ||||
|             __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", "eglChooseConfig() returned 0 matching config"); | ||||
|  | ||||
|     // Get the (first) matching config | ||||
|         // Get the first matching config | ||||
|         EGLConfig egl_config; | ||||
|         eglChooseConfig(g_EglDisplay, egl_attributes, &egl_config, 1, &num_configs); | ||||
|         EGLint egl_format; | ||||
| @@ -147,31 +59,40 @@ void init(struct android_app* app) | ||||
|         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"); | ||||
|             __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 | ||||
|     // Setup Dear ImGui context | ||||
|     IMGUI_CHECKVERSION(); | ||||
|     ImGui::CreateContext(); | ||||
|     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; | ||||
|  | ||||
|     // Setup Dear ImGui style | ||||
|     ImGui::StyleColorsDark(); | ||||
|     //ImGui::StyleColorsClassic(); | ||||
|  | ||||
|     // Setup Platform/Renderer backends | ||||
|     ImGui_ImplAndroid_Init(g_App->window); | ||||
|     ImGui_ImplOpenGL3_Init("#version 300 es"); | ||||
|  | ||||
|     // 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. | ||||
|     // - 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). | ||||
|     // - 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. | ||||
|     // - 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. | ||||
|     // 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; | ||||
|     font_cfg.SizePixels = 22.0f; | ||||
|     io.Fonts->AddFontDefault(&font_cfg); | ||||
| @@ -179,19 +100,19 @@ void init(struct android_app* app) | ||||
|     //int font_data_size; | ||||
|     //ImFont* font; | ||||
|     //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); | ||||
|     //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); | ||||
|     //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); | ||||
|     //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); | ||||
|     //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); | ||||
|  | ||||
|     // Arbitrary scale-up | ||||
| @@ -203,23 +124,23 @@ void init(struct android_app* app) | ||||
|  | ||||
| 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_another_window = false; | ||||
|     static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); | ||||
|  | ||||
|     if (g_EglDisplay != EGL_NO_DISPLAY) | ||||
|     { | ||||
|         ImGuiIO& io = ImGui::GetIO(); | ||||
|  | ||||
|     // Poll Unicode characters via JNI | ||||
|     // FIXME: do not call this every frame because of JNI overhead | ||||
|         pollUnicodeChars(); | ||||
|     PollUnicodeChars(); | ||||
|  | ||||
|         // Open on-screen (soft) input if demanded by Dear ImGui | ||||
|     // Open on-screen (soft) input if requested by Dear ImGui | ||||
|     static bool WantTextInputLast = false; | ||||
|     if (io.WantTextInput && !WantTextInputLast) | ||||
|             showSoftInput(); | ||||
|         ShowSoftKeyboardInput(); | ||||
|     WantTextInputLast = io.WantTextInput; | ||||
|  | ||||
|     // Start the Dear ImGui frame | ||||
| @@ -267,19 +188,18 @@ void tick() | ||||
|     // 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); | ||||
|     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() | ||||
| { | ||||
|     if (!g_Initialized) | ||||
|         return; | ||||
|  | ||||
|     // Cleanup (Dear Imgui) | ||||
|     // Cleanup | ||||
|     ImGui_ImplOpenGL3_Shutdown(); | ||||
|     ImGui_ImplAndroid_Shutdown(); | ||||
|     ImGui::DestroyContext(); | ||||
| @@ -362,3 +282,88 @@ void android_main(struct android_app* app) | ||||
|         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 | ||||
| { | ||||
|     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              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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user