This is the AMP version of this page.
If you want to load the real page instead, click this text.

Help! ImGui cannot be touched when implement into UnityGame (Emulator)

Shawn Dao

Platinian
As the title, when i implement the ImGui into UnityGame, the ImGui cannot be touched.
If i implement the ImGui into Cocos2d, it just works.

ImGui implementations in UnityGame and Cocos2d are identical.

The first game in the below VIdeo is Cocos2d, the 2 others are Unity

Note: Everything works just fine on real device. Issue only happen in Emulators




Main.cpp
Code:
// Global menu instance
Menu * g_menu = nullptr;
bool g_menuInitialized = false;

void DrawMenu() {
  if (g_menu == nullptr) {
    LOGI(OBFUSCATE("[DEBUG] Creating new Menu instance"));
    g_menu = new Menu();
  }

  // Initialize on first draw (which happens on main thread)
  if (!g_menuInitialized && g_menu != nullptr) {
    LOGI(OBFUSCATE("[DEBUG] Initializing menu for first time"));
    g_menu -> Initialize();
    g_menuInitialized = true;
    LOGI(OBFUSCATE("[DEBUG] Menu initialization complete"));
  }

  if (g_menu != nullptr) {
    g_menu -> Draw();
  } else {
    LOGE(OBFUSCATE("[ERROR] Menu pointer is null in DrawMenu()"));
  }
}

void * thread(void * ) {
  LOGI(OBFUSCATE("[DEBUG] Initializing Menu"));
  initModMenu((void * ) DrawMenu);

  LOGI(OBFUSCATE("[DEBUG] Main thread exiting"));
  pthread_exit(0);
}

__attribute__((constructor))
void init() {
  LOGI(OBFUSCATE("[DEBUG] init() called - Loading Mod Menu"));

  pthread_t t;
  if (pthread_create( & t, nullptr, thread, nullptr) != 0) {
    LOGE(OBFUSCATE("[ERROR] Failed to create thread"));
    return;
  }
  LOGI(OBFUSCATE("[DEBUG] Thread created successfully"));

  //Don't leave any traces, remap the loader lib as well
  RemapTools::RemapLibrary("libLoader.so");
}

ImGui.h
Code:
void menuStyle();
void( * menuAddress)();

using swapbuffers_orig = EGLBoolean( * )(EGLDisplay dpy, EGLSurface surf);
EGLBoolean swapbuffers_hook(EGLDisplay dpy, EGLSurface surf);
swapbuffers_orig o_swapbuffers = nullptr;

bool isInitialized = false;
int glWidth = 0;
int glHeight = 0;

//This menu_addr is used to allow for multiple game support in the future
void * initModMenu(void * menu_addr) {
  LOGI(OBFUSCATE("[DEBUG] initModMenu started with menu_addr: %p"), menu_addr);
  menuAddress = (void( * )()) menu_addr;
  do {
    sleep(1);
  } while (!isLibraryLoaded(OBFUSCATE("libEGL.so")));
  LOGI(OBFUSCATE("[DEBUG] libEGL.so loaded successfully"));

  auto swapBuffers = ((uintptr_t) DobbySymbolResolver(OBFUSCATE("libEGL.so"), OBFUSCATE("eglSwapBuffers")));
  LOGI(OBFUSCATE("[DEBUG] SwapBuffers address resolved: %p"), (void * ) swapBuffers);

  KittyMemory::setAddressProtection((void * ) swapBuffers, sizeof(swapBuffers), PROT_READ | PROT_WRITE | PROT_EXEC);
  LOGI(OBFUSCATE("[DEBUG] Memory protection set for SwapBuffers"));

  DobbyHook((void * ) swapBuffers, (void * ) swapbuffers_hook, (void ** ) & o_swapbuffers);
  LOGI(OBFUSCATE("[DEBUG] SwapBuffers hook installed"));

  return nullptr;
}

void setupMenu() {
  if (isInitialized) return;

  auto ctx = ImGui::CreateContext();
  if (!ctx) {
    return;
  }

  ImGuiIO & io = ImGui::GetIO();
  io.DisplaySize = ImVec2((float) glWidth, (float) glHeight);
  io.ConfigWindowsMoveFromTitleBarOnly = true;
  io.IniFilename = nullptr;

  // Setup Platform/Renderer backends
  ImGui_ImplAndroid_Init();

  ImGui_ImplOpenGL3_Init("#version 300 es");

  int systemScale = (1.0 / glWidth) * glWidth;
  ImFontConfig font_cfg;
  font_cfg.SizePixels = systemScale * 22.0 f;
  io.Fonts -> AddFontFromMemoryTTF(CustomFont, systemScale * 25.0, 35.0 f);

  ImGui::GetStyle().ScaleAllSizes(2);

  isInitialized = true;
}

void internalDrawMenu(int width, int height) {
  if (!isInitialized) {
    return;
  }

  ImGuiIO & io = ImGui::GetIO();

  ImGui_ImplOpenGL3_NewFrame();
  ImGui_ImplAndroid_NewFrame(width, height);
  ImGui::NewFrame();

  menuAddress();

  ImGui::Render();

  ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}

EGLBoolean swapbuffers_hook(EGLDisplay dpy, EGLSurface surf) {
  EGLint w, h;
  eglQuerySurface(dpy, surf, EGL_WIDTH, & w);
  eglQuerySurface(dpy, surf, EGL_HEIGHT, & h);
  glWidth = w;
  glHeight = h;

  setupMenu();
  internalDrawMenu(w, h);

  return o_swapbuffers(dpy, surf);
}
 
Last edited: