2021-04-20 19:46:48 +00:00
|
|
|
#include "init/splash_window.hpp"
|
2021-04-17 13:46:26 +00:00
|
|
|
|
2022-02-01 17:09:40 +00:00
|
|
|
#include <hex/api/imhex_api.hpp>
|
2021-04-17 13:46:26 +00:00
|
|
|
#include <hex/helpers/utils.hpp>
|
2021-08-29 20:15:18 +00:00
|
|
|
#include <hex/helpers/fmt.hpp>
|
|
|
|
#include <hex/helpers/logger.hpp>
|
2021-12-22 14:06:16 +00:00
|
|
|
|
|
|
|
#include <romfs/romfs.hpp>
|
2021-04-17 13:46:26 +00:00
|
|
|
|
|
|
|
#include <imgui.h>
|
2021-08-04 16:57:53 +00:00
|
|
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
2021-04-17 13:46:26 +00:00
|
|
|
#include <imgui_internal.h>
|
2021-12-31 00:10:06 +00:00
|
|
|
#include <hex/ui/imgui_imhex_extensions.h>
|
2021-04-17 13:46:26 +00:00
|
|
|
#include <imgui_impl_glfw.h>
|
|
|
|
#include <imgui_impl_opengl3.h>
|
2021-04-21 17:27:05 +00:00
|
|
|
#include <fontawesome_font.h>
|
2021-04-17 13:46:26 +00:00
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <chrono>
|
2021-08-29 12:18:45 +00:00
|
|
|
#include <future>
|
|
|
|
#include <numeric>
|
2021-04-17 13:46:26 +00:00
|
|
|
|
|
|
|
using namespace std::literals::chrono_literals;
|
|
|
|
|
2021-04-20 19:46:48 +00:00
|
|
|
namespace hex::init {
|
2021-04-17 13:46:26 +00:00
|
|
|
|
2021-12-30 22:21:32 +00:00
|
|
|
WindowSplash::WindowSplash() : m_window(nullptr) {
|
2021-04-17 13:46:26 +00:00
|
|
|
this->initGLFW();
|
|
|
|
this->initImGui();
|
2022-02-15 21:36:36 +00:00
|
|
|
|
|
|
|
this->m_gpuVendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
|
2021-04-17 13:46:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WindowSplash::~WindowSplash() {
|
2022-01-17 23:10:10 +00:00
|
|
|
this->exitImGui();
|
|
|
|
this->exitGLFW();
|
2021-04-17 13:46:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::future<bool> WindowSplash::processTasksAsync() {
|
|
|
|
return std::async(std::launch::async, [this] {
|
|
|
|
bool status = true;
|
|
|
|
|
2021-04-18 18:24:42 +00:00
|
|
|
for (const auto &[name, task] : this->m_tasks) {
|
|
|
|
{
|
|
|
|
std::lock_guard guard(this->m_progressMutex);
|
|
|
|
this->m_currTaskName = name;
|
|
|
|
}
|
|
|
|
|
2021-05-21 21:46:36 +00:00
|
|
|
try {
|
2022-02-01 22:33:42 +00:00
|
|
|
if (!task())
|
|
|
|
status = false;
|
2022-01-17 19:06:00 +00:00
|
|
|
} catch (std::exception &e) {
|
2022-01-23 20:52:24 +00:00
|
|
|
log::error("Init task '{}' threw an exception: {}", name, e.what());
|
2021-05-21 21:46:36 +00:00
|
|
|
status = false;
|
|
|
|
}
|
2021-04-17 13:46:26 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard guard(this->m_progressMutex);
|
2021-09-23 20:56:49 +00:00
|
|
|
this->m_progress += 1.0F / this->m_tasks.size();
|
2021-04-17 13:46:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Small extra delay so the last progress step is visible
|
|
|
|
std::this_thread::sleep_for(200ms);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-04-18 18:24:42 +00:00
|
|
|
bool WindowSplash::loop() {
|
2022-02-01 21:09:44 +00:00
|
|
|
auto splash = romfs::get("splash.png");
|
2022-01-24 19:53:17 +00:00
|
|
|
ImGui::Texture splashTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
|
2021-04-17 13:46:26 +00:00
|
|
|
|
2021-04-20 19:46:48 +00:00
|
|
|
if (splashTexture == nullptr) {
|
|
|
|
log::fatal("Could not load splash screen image!");
|
2021-04-17 13:46:26 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2021-04-20 19:46:48 +00:00
|
|
|
}
|
2021-04-17 13:46:26 +00:00
|
|
|
|
2021-04-18 18:24:42 +00:00
|
|
|
ON_SCOPE_EXIT { ImGui::UnloadImage(splashTexture); };
|
|
|
|
|
2021-04-20 19:46:48 +00:00
|
|
|
auto tasksSucceeded = processTasksAsync();
|
2021-04-17 13:46:26 +00:00
|
|
|
|
2022-02-01 17:09:40 +00:00
|
|
|
auto scale = ImHexApi::System::getGlobalScale();
|
2021-08-31 13:22:00 +00:00
|
|
|
|
2021-04-17 13:46:26 +00:00
|
|
|
while (!glfwWindowShouldClose(this->m_window)) {
|
|
|
|
glfwPollEvents();
|
|
|
|
|
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
|
|
ImGui_ImplGlfw_NewFrame();
|
|
|
|
ImGui::NewFrame();
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard guard(this->m_progressMutex);
|
2021-04-18 18:24:42 +00:00
|
|
|
|
2021-08-20 22:52:11 +00:00
|
|
|
auto drawList = ImGui::GetForegroundDrawList();
|
2021-04-18 18:24:42 +00:00
|
|
|
|
2021-08-31 13:22:00 +00:00
|
|
|
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.size() * scale);
|
2021-08-04 16:57:53 +00:00
|
|
|
|
2021-08-31 13:22:00 +00:00
|
|
|
drawList->AddText(ImVec2(15, 120) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv 2020 - {0}", &__DATE__[7]).c_str());
|
2021-04-21 17:27:05 +00:00
|
|
|
|
2022-02-06 12:52:51 +00:00
|
|
|
#if defined(DEBUG) && defined(GIT_BRANCH) && defined(GIT_COMMIT_HASH)
|
2022-01-24 19:53:17 +00:00
|
|
|
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0} : {1} {2}@{3}", IMHEX_VERSION, ICON_FA_CODE_BRANCH, GIT_BRANCH, GIT_COMMIT_HASH).c_str());
|
|
|
|
#else
|
|
|
|
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str());
|
|
|
|
#endif
|
2021-08-04 16:57:53 +00:00
|
|
|
|
2021-08-31 13:22:00 +00:00
|
|
|
drawList->AddRectFilled(ImVec2(0, splashTexture.size().y - 5) * scale, ImVec2(splashTexture.size().x * this->m_progress, splashTexture.size().y) * scale, 0xFFFFFFFF);
|
2022-01-24 19:53:17 +00:00
|
|
|
drawList->AddText(ImVec2(15, splashTexture.size().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
|
2021-04-17 13:46:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Render();
|
|
|
|
int display_w, display_h;
|
|
|
|
glfwGetFramebufferSize(this->m_window, &display_w, &display_h);
|
|
|
|
glViewport(0, 0, display_w, display_h);
|
|
|
|
glClearColor(0, 0, 0, 0);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
|
|
|
|
|
|
glfwSwapBuffers(this->m_window);
|
|
|
|
|
2021-04-20 19:46:48 +00:00
|
|
|
if (tasksSucceeded.wait_for(0s) == std::future_status::ready) {
|
|
|
|
return tasksSucceeded.get();
|
2021-04-17 13:46:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-18 18:24:42 +00:00
|
|
|
return false;
|
2021-04-17 13:46:26 +00:00
|
|
|
}
|
|
|
|
|
2021-04-20 19:46:48 +00:00
|
|
|
static void centerWindow(GLFWwindow *window) {
|
|
|
|
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
|
|
|
if (!monitor)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
|
|
|
|
if (!mode)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int monitorX, monitorY;
|
|
|
|
glfwGetMonitorPos(monitor, &monitorX, &monitorY);
|
|
|
|
|
|
|
|
int windowWidth, windowHeight;
|
|
|
|
glfwGetWindowSize(window, &windowWidth, &windowHeight);
|
|
|
|
|
|
|
|
glfwSetWindowPos(window, monitorX + (mode->width - windowWidth) / 2, monitorY + (mode->height - windowHeight) / 2);
|
|
|
|
}
|
|
|
|
|
2021-04-17 13:46:26 +00:00
|
|
|
void WindowSplash::initGLFW() {
|
2021-08-29 20:17:43 +00:00
|
|
|
glfwSetErrorCallback([](int error, const char *desc) {
|
2021-08-29 20:15:18 +00:00
|
|
|
log::error("GLFW Error [{}] : {}", error, desc);
|
2021-04-17 13:46:26 +00:00
|
|
|
});
|
|
|
|
|
2021-04-20 19:46:48 +00:00
|
|
|
if (!glfwInit()) {
|
|
|
|
log::fatal("Failed to initialize GLFW!");
|
2021-04-17 13:46:26 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2021-04-20 19:46:48 +00:00
|
|
|
}
|
2021-04-17 13:46:26 +00:00
|
|
|
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
2021-04-21 18:06:48 +00:00
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
|
|
|
2021-04-18 18:24:42 +00:00
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
2021-04-17 13:46:26 +00:00
|
|
|
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
|
|
|
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
|
2022-01-22 21:08:25 +00:00
|
|
|
glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
|
2021-04-17 13:46:26 +00:00
|
|
|
|
2021-08-04 16:57:53 +00:00
|
|
|
if (GLFWmonitor *monitor = glfwGetPrimaryMonitor(); monitor != nullptr) {
|
2021-09-23 20:56:49 +00:00
|
|
|
float xScale = 0, yScale = 0;
|
|
|
|
glfwGetMonitorContentScale(monitor, &xScale, &yScale);
|
|
|
|
|
2022-02-01 17:09:40 +00:00
|
|
|
auto meanScale = std::midpoint(xScale, yScale);
|
2021-08-04 16:57:53 +00:00
|
|
|
|
2022-02-01 21:09:44 +00:00
|
|
|
// On Macs with a retina display (basically all modern ones we care about), the OS reports twice
|
|
|
|
// the actual monitor scale for some obscure reason. Get rid of this here so ImHex doesn't look
|
2022-02-05 21:19:32 +00:00
|
|
|
// extremely huge with native scaling on macOS.
|
2022-02-01 21:09:44 +00:00
|
|
|
#if defined(OS_MACOS)
|
|
|
|
meanScale /= 2;
|
|
|
|
#endif
|
2022-01-17 19:20:37 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
if (meanScale <= 0.0) {
|
2022-02-01 17:09:40 +00:00
|
|
|
meanScale = 1.0;
|
2021-09-23 20:56:49 +00:00
|
|
|
}
|
2022-02-01 17:09:40 +00:00
|
|
|
|
|
|
|
ImHexApi::System::impl::setGlobalScale(meanScale);
|
2021-08-04 16:57:53 +00:00
|
|
|
}
|
|
|
|
|
2022-01-11 22:48:18 +00:00
|
|
|
this->m_window = glfwCreateWindow(640_scaled, 400_scaled, "Starting ImHex...", nullptr, nullptr);
|
2021-04-20 19:46:48 +00:00
|
|
|
if (this->m_window == nullptr) {
|
|
|
|
log::fatal("Failed to create GLFW window!");
|
2021-04-17 13:46:26 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2021-04-20 19:46:48 +00:00
|
|
|
}
|
2021-04-17 13:46:26 +00:00
|
|
|
|
|
|
|
centerWindow(this->m_window);
|
|
|
|
|
|
|
|
glfwMakeContextCurrent(this->m_window);
|
|
|
|
glfwSwapInterval(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WindowSplash::initImGui() {
|
|
|
|
IMGUI_CHECKVERSION();
|
|
|
|
GImGui = ImGui::CreateContext();
|
|
|
|
ImGui::StyleColorsDark();
|
|
|
|
|
|
|
|
ImGui_ImplGlfw_InitForOpenGL(this->m_window, true);
|
2021-10-09 21:07:58 +00:00
|
|
|
ImGui_ImplOpenGL3_Init("#version 150");
|
2021-04-21 17:27:05 +00:00
|
|
|
|
|
|
|
auto &io = ImGui::GetIO();
|
|
|
|
|
2022-02-01 17:09:40 +00:00
|
|
|
ImGui::GetStyle().ScaleAllSizes(ImHexApi::System::getGlobalScale());
|
2021-08-04 16:57:53 +00:00
|
|
|
|
2021-04-21 17:27:05 +00:00
|
|
|
io.Fonts->Clear();
|
|
|
|
|
|
|
|
ImFontConfig cfg;
|
|
|
|
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
2022-01-11 22:48:18 +00:00
|
|
|
cfg.SizePixels = 13.0_scaled;
|
2021-04-21 17:27:05 +00:00
|
|
|
io.Fonts->AddFontDefault(&cfg);
|
|
|
|
|
|
|
|
cfg.MergeMode = true;
|
|
|
|
|
|
|
|
ImWchar fontAwesomeRange[] = {
|
2022-01-24 19:53:17 +00:00
|
|
|
ICON_MIN_FA, ICON_MAX_FA, 0
|
2021-04-21 17:27:05 +00:00
|
|
|
};
|
|
|
|
std::uint8_t *px;
|
|
|
|
int w, h;
|
2022-01-11 22:48:18 +00:00
|
|
|
io.Fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 11.0_scaled, &cfg, fontAwesomeRange);
|
2021-04-21 17:27:05 +00:00
|
|
|
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));
|
2022-03-13 16:36:50 +00:00
|
|
|
io.IniFilename = nullptr;
|
2021-04-17 13:46:26 +00:00
|
|
|
}
|
|
|
|
|
2022-01-17 23:10:10 +00:00
|
|
|
void WindowSplash::exitGLFW() {
|
2021-04-17 13:46:26 +00:00
|
|
|
glfwDestroyWindow(this->m_window);
|
|
|
|
glfwTerminate();
|
|
|
|
}
|
|
|
|
|
2022-01-17 23:10:10 +00:00
|
|
|
void WindowSplash::exitImGui() {
|
2021-04-17 13:46:26 +00:00
|
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
|
|
ImGui_ImplGlfw_Shutdown();
|
|
|
|
ImGui::DestroyContext();
|
|
|
|
}
|
|
|
|
|
2021-12-22 12:16:51 +00:00
|
|
|
}
|