// Based on Dear ImGui GLFW + OpenGL 3 standalone example #include "ESPReader.h" #include "imgui.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" #include #include #undef NDEBUG #include #define NDEBUG #include // Will drag system OpenGL headers const float BASE_FONT_SIZE = 13; const ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings; MetaTree ReadESP(const char *filename); GLFWwindow *Setup(void); void NewFrame(void); void Fullscreen(void); void Render(GLFWwindow *window, const ImVec4 clear_color); void Cleanup(GLFWwindow *window); void ChangeScale(bool *scale_update, const float scale); void ScalingWidget(bool *scale_update, float *scale); void ESPTreeWalk(MetaNode *m); static void glfw_error_callback(int error, const char *description) { fprintf(stderr, "Glfw Error %d: %s\n", error, description); } int main(int, char **) { GLFWwindow *window = Setup(); if (!window) return 1; MetaTree m = ReadESP("Skyrim.esm"); m.root->user = (void *)true; // Our state ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); bool scale_update = false; float scale = 1.0f; // Main loop while (!glfwWindowShouldClose(window)) { // Poll and handle events (inputs, window resize, etc.) // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. glfwPollEvents(); // Interface scaling ChangeScale(&scale_update, scale); // Start the Dear ImGui frame NewFrame(); // Setup for fullscreen Fullscreen(); // Begin window ImGui::Begin("ESP Browser", NULL, window_flags); ScalingWidget(&scale_update, &scale); ESPTreeWalk(m.root); // End window ImGui::End(); Render(window, clear_color); } free(m.esp.data); free(m.tree.data); Cleanup(window); return 0; } MetaTree ReadESP(const char *filename) { errno_t ret = 0; SizedBuf esp_buf = { 0 }; ESPStats stats = { 0 }; SizedBuf tree_buf = { 0 }; MetaTree tree = { 0 }; // Read in the esp file { FILE *fp; ret = fopen_s(&fp, "Skyrim.esm", "rb"); assert(fp && !ret); fseek(fp, 0L, SEEK_END); esp_buf.size = ftell(fp); rewind(fp); esp_buf.data = (char *)malloc(esp_buf.size); assert(esp_buf.data); size_t read = fread(esp_buf.data, sizeof(char), esp_buf.size, fp); fclose(fp); assert(read == esp_buf.size); } // Calculate esp stats stats = espr_stats(esp_buf); // Construct the meta tree { tree_buf.size = espr_tree_size(stats); tree_buf.data = (char *)malloc(tree_buf.size); assert(tree_buf.data); tree = espr_create_tree(esp_buf, tree_buf); } // lazy file pointer cleanup _fcloseall(); return tree; } GLFWwindow *Setup(void) { // Setup window glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) return NULL; // GL 3.0 + GLSL 130 const char *glsl_version = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Create window with graphics context GLFWwindow *window = glfwCreateWindow(1920, 1080, "Dear ImGui GLFW+OpenGL3 example", NULL, NULL); if (window == NULL) return NULL; glfwMakeContextCurrent(window); glfwSwapInterval(1); // Enable vsync // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO &io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows //io.ConfigViewportsNoAutoMerge = true; //io.ConfigViewportsNoTaskBarIcon = true; // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. ImGuiStyle &style = ImGui::GetStyle(); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { style.WindowRounding = 0.0f; style.Colors[ImGuiCol_WindowBg].w = 1.0f; } // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init(glsl_version); return window; } void NewFrame(void) { ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); } void Fullscreen(void) { const ImGuiViewport *viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(viewport->WorkPos); ImGui::SetNextWindowSize(viewport->WorkSize); } void Render(GLFWwindow * window, const ImVec4 clear_color) { ImGuiIO &io = ImGui::GetIO(); ImGui::Render(); int display_w, display_h; glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); 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()); // Update and Render additional Platform Windows // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. // For this specific demo app we could also call glfwMakeContextCurrent(window) directly) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { GLFWwindow *backup_current_context = glfwGetCurrentContext(); ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); glfwMakeContextCurrent(backup_current_context); } glfwSwapBuffers(window); } void Cleanup(GLFWwindow *window) { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); glfwDestroyWindow(window); glfwTerminate(); } void ChangeScale(bool *scale_update, const float scale) { static ImGuiStyle reference_style(ImGui::GetStyle()); ImGuiIO &io = ImGui::GetIO(); ImGuiStyle &style = ImGui::GetStyle(); if (*scale_update) { ImFontConfig font_config; // Truncate to 2 decimal places font_config.SizePixels = ((float)(int)(BASE_FONT_SIZE * scale * 100)) / 100; io.Fonts->Clear(); io.Fonts->AddFontDefault(&font_config); ImGui_ImplOpenGL3_UpdateFontsTexture(); style = reference_style; style.ScaleAllSizes(scale); *scale_update = false; } } void ScalingWidget(bool *scale_update, float *scale) { ImGuiIO &io = ImGui::GetIO(); ImGuiStyle &style = ImGui::GetStyle(); const float MIN_SCALE = 0.3f; const float MAX_SCALE = 3.0f; ImGui::PushItemWidth(ImGui::GetFontSize() * 20); if (ImGui::DragFloat("scale", scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) { *scale_update = true; } ImGui::PopItemWidth(); } void ESPTreeWalk(MetaNode *m) { char buf[1024] = { 0 }; SizedBuf sb = { buf, 1024 }; espr_meta_string(m, sb); if (m->n.type == NT_RECORD) { ImGui::BulletText(buf); } else { if (ImGui::TreeNode(buf)) { MetaNode *c = m->first_child; while (c) { ESPTreeWalk(c); c = c->next; } ImGui::TreePop(); } } }