mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-01-23 21:18:42 -06:00
* add glm to arch deps
After running got `None of the required 'glm' found`. This fixes that
* dist/fedora: Include file magic headers
Due to differences in package names between Deb based systems, Arch
Linux, and RPM based systems the package containing the development
headers for file were missing from the Fedora dependencies script.
This includes the package `file-devel`, which is the package which
resolves the issue.
In Fedora, one can identify the package providing a specific file using
the verb "whatprovides" with the command dnf, e.g.:
[~]$ dnf whatprovides /usr/include/magic.h
Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST.
file-devel-5.39-3.fc33.i686 : Libraries and header files for file development
Repo : fedora
Matched from:
Filename : /usr/include/magic.h
file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development
Repo : @System
Matched from:
Filename : /usr/include/magic.h
file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development
Repo : fedora
Matched from:
Filename : /usr/include/magic.h
If one is unsure of the specific path, globbing may be used (but must be
quoted):
dnf whatprovides "*/magic.h"
Resolves #48
* dist: Prevent already installed packages in ArchLinux and MSYS2.
Use --needed option with pacman to prevent it.
* Add script to install dependencies on Debian/Ubuntu.
Tested with Xubuntu 20.04 and Debian testing
(in today's Docker image bitnami/minideb).
Update README.md.
* ci: rework (#31)
* Support non standard LLVM library names (#86)
This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138.
(tested on openSUSE tumbleweed via Docker)
I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``.
* Implement proper DPI handling
* Implement basic custom font support
* Fix building on windows
* Hopefully fix fonts on Windows
* Fix several scaling issues
* Replace font renderer with freetype
* Updated CI and dependency scripts
* Rebuild default font atlas
* Correct platform detection macro for mingw
* Fixed PKGBUILD
Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com>
Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org>
Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com>
Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr>
Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com>
Co-authored-by: Mary <me@thog.eu>
Co-authored-by: WerWolv <werwolv98@gmail.com>
328 lines
11 KiB
C++
328 lines
11 KiB
C++
#include "hex.hpp"
|
|
#include "window.hpp"
|
|
|
|
#include <iostream>
|
|
#include <numeric>
|
|
|
|
#include "imgui.h"
|
|
#include "imgui_internal.h"
|
|
#include "imgui_impl_glfw.h"
|
|
#include "imgui_impl_opengl3.h"
|
|
#include "imgui_freetype.h"
|
|
|
|
#include <glad/glad.h>
|
|
#include <GLFW/glfw3.h>
|
|
|
|
namespace hex {
|
|
|
|
constexpr auto MenuBarItems = { "File", "Edit", "View", "Help" };
|
|
|
|
void *ImHexSettingsHandler_ReadOpenFn(ImGuiContext *ctx, ImGuiSettingsHandler *, const char *) {
|
|
return ctx; // Unused, but the return value has to be non-null
|
|
}
|
|
|
|
void ImHexSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler *handler, void *, const char* line) {
|
|
auto *window = reinterpret_cast<Window *>(handler->UserData);
|
|
|
|
for (auto &view : window->m_views) {
|
|
std::string format = view->getName() + "=%d";
|
|
sscanf(line, format.c_str(), &view->getWindowOpenState());
|
|
}
|
|
}
|
|
|
|
void ImHexSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf) {
|
|
auto *window = reinterpret_cast<Window *>(handler->UserData);
|
|
|
|
buf->reserve(buf->size() + 0x20); // Ballpark reserve
|
|
|
|
buf->appendf("[%s][General]\n", handler->TypeName);
|
|
|
|
for (auto &view : window->m_views) {
|
|
buf->appendf("%s=%d\n", view->getName().c_str(), view->getWindowOpenState());
|
|
}
|
|
|
|
buf->append("\n");
|
|
}
|
|
|
|
Window::Window() {
|
|
this->initGLFW();
|
|
this->initImGui();
|
|
}
|
|
|
|
Window::~Window() {
|
|
this->deinitImGui();
|
|
this->deinitGLFW();
|
|
|
|
for (auto &view : this->m_views)
|
|
delete view;
|
|
}
|
|
|
|
void Window::loop() {
|
|
while (!glfwWindowShouldClose(this->m_window)) {
|
|
this->frameBegin();
|
|
|
|
for (const auto &call : View::getDeferedCalls())
|
|
call();
|
|
View::getDeferedCalls().clear();
|
|
|
|
for (auto &view : this->m_views) {
|
|
if (!view->getWindowOpenState())
|
|
continue;
|
|
|
|
ImGui::SetNextWindowSizeConstraints(ImVec2(480, 720), ImVec2(FLT_MAX, FLT_MAX));
|
|
view->createView();
|
|
}
|
|
|
|
View::drawCommonInterfaces();
|
|
|
|
#ifdef DEBUG
|
|
if (this->m_demoWindowOpen)
|
|
ImGui::ShowDemoWindow(&this->m_demoWindowOpen);
|
|
#endif
|
|
|
|
this->frameEnd();
|
|
}
|
|
}
|
|
|
|
bool Window::setFont(const std::filesystem::path &path) {
|
|
if (!std::filesystem::exists(path))
|
|
return false;
|
|
|
|
auto &io = ImGui::GetIO();
|
|
|
|
// If we have a custom font, then rescaling is unnecessary and will make it blurry
|
|
io.FontGlobalScale = 1.0f;
|
|
|
|
// Load font data & build atlas
|
|
std::uint8_t *px;
|
|
int w, h;
|
|
io.Fonts->AddFontFromFileTTF(path.string().c_str(), std::floor(14.0f * this->m_fontScale)); // Needs conversion to char for Windows
|
|
ImGuiFreeType::BuildFontAtlas(io.Fonts, ImGuiFreeType::Monochrome);
|
|
io.Fonts->GetTexDataAsRGBA32(&px, &w, &h);
|
|
|
|
// Create new font atlas
|
|
GLuint tex;
|
|
glGenTextures(1, &tex);
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA8, GL_UNSIGNED_INT, px);
|
|
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(tex));
|
|
|
|
return true;
|
|
}
|
|
|
|
void Window::frameBegin() {
|
|
glfwPollEvents();
|
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
ImGui_ImplGlfw_NewFrame();
|
|
ImGui::NewFrame();
|
|
|
|
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
|
ImGui::SetNextWindowPos(viewport->GetWorkPos());
|
|
ImGui::SetNextWindowSize(viewport->GetWorkSize());
|
|
ImGui::SetNextWindowViewport(viewport->ID);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
|
|
|
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking
|
|
| ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse
|
|
| ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize
|
|
| ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBringToFrontOnFocus;
|
|
|
|
if (ImGui::Begin("DockSpace", nullptr, windowFlags)) {
|
|
ImGui::PopStyleVar(2);
|
|
ImGui::DockSpace(ImGui::GetID("MainDock"), ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None);
|
|
|
|
if (ImGui::BeginMenuBar()) {
|
|
|
|
for (auto menu : MenuBarItems)
|
|
if (ImGui::BeginMenu(menu)) ImGui::EndMenu();
|
|
|
|
if (ImGui::BeginMenu("View")) {
|
|
for (auto &view : this->m_views) {
|
|
if (view->hasViewMenuItemEntry())
|
|
ImGui::MenuItem((view->getName() + " View").c_str(), "", &view->getWindowOpenState());
|
|
}
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
for (auto &view : this->m_views) {
|
|
view->createMenu();
|
|
}
|
|
|
|
if (ImGui::BeginMenu("View")) {
|
|
ImGui::Separator();
|
|
ImGui::MenuItem("Display FPS", "", &this->m_fpsVisible);
|
|
#ifdef DEBUG
|
|
ImGui::MenuItem("Demo View", "", &this->m_demoWindowOpen);
|
|
#endif
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
if (this->m_fpsVisible) {
|
|
char buffer[0x20];
|
|
snprintf(buffer, 0x20, "%.1f FPS", ImGui::GetIO().Framerate);
|
|
|
|
ImGui::SameLine(ImGui::GetWindowWidth() - ImGui::GetFontSize() * strlen(buffer) + 20);
|
|
ImGui::TextUnformatted(buffer);
|
|
}
|
|
|
|
ImGui::EndMenuBar();
|
|
}
|
|
|
|
if (auto &[key, mods] = Window::s_currShortcut; key != -1) {
|
|
for (auto &view : this->m_views) {
|
|
if (view->getWindowOpenState()) {
|
|
if (view->handleShortcut(key, mods))
|
|
break;
|
|
}
|
|
}
|
|
|
|
Window::s_currShortcut = { -1, -1 };
|
|
}
|
|
|
|
}
|
|
ImGui::End();
|
|
|
|
}
|
|
|
|
void Window::frameEnd() {
|
|
ImGui::Render();
|
|
|
|
int displayWidth, displayHeight;
|
|
glfwGetFramebufferSize(this->m_window, &displayWidth, &displayHeight);
|
|
glViewport(0, 0, displayWidth, displayHeight);
|
|
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
|
|
GLFWwindow* backup_current_context = glfwGetCurrentContext();
|
|
ImGui::UpdatePlatformWindows();
|
|
ImGui::RenderPlatformWindowsDefault();
|
|
glfwMakeContextCurrent(backup_current_context);
|
|
|
|
glfwSwapBuffers(this->m_window);
|
|
}
|
|
|
|
void Window::initGLFW() {
|
|
glfwSetErrorCallback([](int error, const char* desc) {
|
|
fprintf(stderr, "Glfw Error %d: %s\n", error, desc);
|
|
});
|
|
|
|
if (!glfwInit())
|
|
throw std::runtime_error("Failed to initialize GLFW!");
|
|
|
|
#ifdef __APPLE__
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
#endif
|
|
|
|
if (auto *monitor = glfwGetPrimaryMonitor(); monitor) {
|
|
float xscale, yscale;
|
|
glfwGetMonitorContentScale(monitor, &xscale, &yscale);
|
|
|
|
// In case the horizontal and vertical scale are different, fall back on the average
|
|
this->m_globalScale = this->m_fontScale = std::midpoint(xscale, yscale);
|
|
}
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
|
|
this->m_window = glfwCreateWindow(1280 * this->m_globalScale, 720 * this->m_globalScale, "ImHex", nullptr, nullptr);
|
|
|
|
|
|
if (this->m_window == nullptr)
|
|
throw std::runtime_error("Failed to create window!");
|
|
|
|
glfwMakeContextCurrent(this->m_window);
|
|
glfwSwapInterval(1);
|
|
|
|
glfwSetKeyCallback(this->m_window, [](GLFWwindow *window, int key, int scancode, int action, int mods) {
|
|
if (action == GLFW_PRESS)
|
|
Window::s_currShortcut = { key, mods };
|
|
});
|
|
|
|
glfwSetDropCallback(this->m_window, [](GLFWwindow *window, int count, const char **paths) {
|
|
if (count != 1)
|
|
return;
|
|
|
|
View::postEvent(Events::FileDropped, paths[0]);
|
|
});
|
|
|
|
glfwSetWindowCloseCallback(this->m_window, [](GLFWwindow *window) {
|
|
View::postEvent(Events::WindowClosing, window);
|
|
});
|
|
|
|
|
|
glfwSetWindowSizeLimits(this->m_window, 720, 480, GLFW_DONT_CARE, GLFW_DONT_CARE);
|
|
|
|
if (gladLoadGL() == 0)
|
|
throw std::runtime_error("Failed to initialize OpenGL loader!");
|
|
}
|
|
|
|
void Window::initImGui() {
|
|
IMGUI_CHECKVERSION();
|
|
auto *ctx = ImGui::CreateContext();
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
ImGuiStyle& style = ImGui::GetStyle();
|
|
|
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_ViewportsEnable;
|
|
io.ConfigViewportsNoTaskBarIcon = true;
|
|
|
|
if (this->m_globalScale != 0.0f)
|
|
style.ScaleAllSizes(this->m_globalScale);
|
|
|
|
#ifdef __MINGW32__
|
|
std::filesystem::path resourcePath = std::filesystem::path(mainArgv[0]).parent_path();
|
|
#elif defined(__linux__)
|
|
std::filesystem::path resourcePath = "/usr/share/ImHex";
|
|
#else
|
|
std::filesystem::path resourcePath = "";
|
|
# warning "Unsupported OS for custom font support"
|
|
#endif
|
|
|
|
if (!resourcePath.empty() && this->setFont(resourcePath / "font.ttf"))
|
|
;
|
|
else if ((this->m_fontScale != 0.0f) && (this->m_fontScale != 1.0f)) {
|
|
io.Fonts->Clear();
|
|
|
|
ImFontConfig cfg;
|
|
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
|
cfg.SizePixels = 13.0f * this->m_fontScale;
|
|
io.Fonts->AddFontDefault(&cfg);
|
|
}
|
|
|
|
style.WindowMenuButtonPosition = ImGuiDir_None;
|
|
style.IndentSpacing = 10.0F;
|
|
|
|
// Install custom settings handler
|
|
ImGuiSettingsHandler handler;
|
|
handler.TypeName = "ImHex";
|
|
handler.TypeHash = ImHashStr("ImHex");
|
|
handler.ReadOpenFn = ImHexSettingsHandler_ReadOpenFn;
|
|
handler.ReadLineFn = ImHexSettingsHandler_ReadLine;
|
|
handler.WriteAllFn = ImHexSettingsHandler_WriteAll;
|
|
handler.UserData = this;
|
|
ctx->SettingsHandlers.push_back(handler);
|
|
|
|
ImGui::StyleColorsDark();
|
|
|
|
ImGui_ImplGlfw_InitForOpenGL(this->m_window, true);
|
|
ImGui_ImplOpenGL3_Init("#version 150");
|
|
}
|
|
|
|
void Window::deinitGLFW() {
|
|
glfwDestroyWindow(this->m_window);
|
|
glfwTerminate();
|
|
}
|
|
|
|
void Window::deinitImGui() {
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
ImGui_ImplGlfw_Shutdown();
|
|
ImGui::DestroyContext();
|
|
}
|
|
|
|
} |