1
0
mirror of synced 2024-11-14 19:17:42 +01:00

refactor: separate loop and frame logic (#1300)

This commit is contained in:
iTrooz 2023-09-07 20:33:49 +02:00 committed by GitHub
parent 4e7c3817ed
commit c07842d7ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 167 additions and 137 deletions

View File

@ -12,6 +12,14 @@ namespace hex::init {
using TaskFunction = std::function<bool()>;
enum FrameResult{ success, failure, wait };
struct Highlight {
ImVec2 start;
size_t count;
ImColor color;
};
class WindowSplash {
public:
WindowSplash();
@ -19,6 +27,9 @@ namespace hex::init {
bool loop();
FrameResult fullFrame();
void startStartupTasks();
void addStartupTask(const std::string &taskName, const TaskFunction &task, bool async) {
this->m_tasks.emplace_back(taskName, task, async);
}
@ -31,6 +42,7 @@ namespace hex::init {
void initGLFW();
void initImGui();
void initMyself();
void exitGLFW();
void exitImGui();
@ -40,6 +52,12 @@ namespace hex::init {
std::vector<std::tuple<std::string, TaskFunction, bool>> m_tasks;
std::string m_gpuVendor;
ImGui::Texture splashBackgroundTexture;
ImGui::Texture splashTextTexture;
std::future<bool> tasksSucceeded;
std::array<Highlight, 3> highlights;
float progressLerp = 0.0F;
};
}

View File

@ -24,6 +24,7 @@ namespace hex {
~Window();
void loop();
void fullFrame();
static void initNative();

View File

@ -43,6 +43,7 @@ namespace hex::init {
WindowSplash::WindowSplash() : m_window(nullptr) {
this->initGLFW();
this->initImGui();
this->initMyself();
ImHexApi::System::impl::setGPUVendor(reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
}
@ -111,60 +112,7 @@ namespace hex::init {
});
}
bool WindowSplash::loop() {
// Load splash screen image from romfs
ImGui::Texture splashBackgroundTexture = ImGui::Texture(romfs::get("splash_background.png").span());
ImGui::Texture splashTextTexture = ImGui::Texture(romfs::get("splash_text.png").span());
// If the image couldn't be loaded correctly, something went wrong during the build process
// Close the application since this would lead to errors later on anyway.
if (!splashBackgroundTexture.isValid() || !splashTextTexture.isValid()) {
log::fatal("Could not load splash screen image!");
std::exit(EXIT_FAILURE);
}
// Launch init tasks in background
auto tasksSucceeded = processTasksAsync();
auto scale = ImHexApi::System::getGlobalScale();
struct Highlight {
ImVec2 start;
size_t count;
ImColor color;
};
std::array<Highlight, 3> highlights;
std::mt19937 rng(std::random_device{}());
u32 lastPos = 0;
u32 lastCount = 0;
for (auto &highlight : highlights) {
auto newPos = lastPos + lastCount + (rng() % 40);
auto newCount = (rng() % 7) + 3;
highlight.start.x = newPos % 13;
highlight.start.y = newPos / 13;
highlight.count = newCount;
{
float r, g, b;
ImGui::ColorConvertHSVtoRGB(
(rng() % 360) / 100.0F,
(25 + rng() % 70) / 100.0F,
(85 + rng() % 10) / 100.0F,
r, g, b);
highlight.color = ImColor(r, g, b, 0x50 / 255.0F);
}
lastPos = newPos;
lastCount = newCount;
}
// Splash window rendering loop
float progressLerp = 0.0F;
while (!glfwWindowShouldClose(this->m_window)) {
FrameResult WindowSplash::fullFrame() {
glfwPollEvents();
// Start a new ImGui frame
@ -172,11 +120,13 @@ namespace hex::init {
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
auto scale = ImHexApi::System::getGlobalScale();
// Draw the splash screen background
auto drawList = ImGui::GetBackgroundDrawList();
{
drawList->AddImage(splashBackgroundTexture, ImVec2(0, 0), splashBackgroundTexture.getSize() * scale);
drawList->AddImage(this->splashBackgroundTexture, ImVec2(0, 0), this->splashBackgroundTexture.getSize() * scale);
{
const auto highlightBytes = [&](ImVec2 start, size_t count, ImColor color, float opacity) {
@ -215,13 +165,13 @@ namespace hex::init {
}
};
for (const auto &highlight : highlights)
highlightBytes(highlight.start, highlight.count, highlight.color, progressLerp);
for (const auto &highlight : this->highlights)
highlightBytes(highlight.start, highlight.count, highlight.color, this->progressLerp);
}
progressLerp += (this->m_progress - progressLerp) * 0.1F;
this->progressLerp += (this->m_progress - this->progressLerp) * 0.1F;
drawList->AddImage(splashTextTexture, ImVec2(0, 0), splashTextTexture.getSize() * scale);
drawList->AddImage(this->splashTextTexture, ImVec2(0, 0), this->splashTextTexture.getSize() * scale);
drawList->AddText(ImVec2(35, 85) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv\n2020 - {0}", &__DATE__[7]).c_str());
@ -231,7 +181,7 @@ namespace hex::init {
const static auto VersionInfo = hex::format("{0}", ImHexApi::System::getImHexVersion());
#endif
drawList->AddText(ImVec2((splashBackgroundTexture.getSize().x * scale - ImGui::CalcTextSize(VersionInfo.c_str()).x) / 2, 105 * scale), ImColor(0xFF, 0xFF, 0xFF, 0xFF), VersionInfo.c_str());
drawList->AddText(ImVec2((this->splashBackgroundTexture.getSize().x * scale - ImGui::CalcTextSize(VersionInfo.c_str()).x) / 2, 105 * scale), ImColor(0xFF, 0xFF, 0xFF, 0xFF), VersionInfo.c_str());
}
// Draw the task progress bar
@ -264,12 +214,20 @@ namespace hex::init {
glfwSwapBuffers(this->m_window);
// Check if all background tasks have finished so the splash screen can be closed
if (tasksSucceeded.wait_for(0s) == std::future_status::ready) {
return tasksSucceeded.get();
}
if (this->tasksSucceeded.wait_for(0s) == std::future_status::ready) {
return this->tasksSucceeded.get() ? FrameResult::success : FrameResult::failure;
}
return false;
return FrameResult::wait;
}
bool WindowSplash::loop() {
// Splash window rendering loop
while (true) {
auto res = this->fullFrame();
if (res == FrameResult::success) return true;
else if (res == FrameResult::failure) return false;
}
}
static void centerWindow(GLFWwindow *window) {
@ -414,6 +372,55 @@ namespace hex::init {
io.IniFilename = nullptr;
}
/**
* @brief Initialize resources for the splash window
*/
void WindowSplash::initMyself() {
// Load splash screen image from romfs
this->splashBackgroundTexture = ImGui::Texture(romfs::get("splash_background.png").span());
this->splashTextTexture = ImGui::Texture(romfs::get("splash_text.png").span());
// If the image couldn't be loaded correctly, something went wrong during the build process
// Close the application since this would lead to errors later on anyway.
if (!this->splashBackgroundTexture.isValid() || !this->splashTextTexture.isValid()) {
log::fatal("Could not load splash screen image!");
std::exit(EXIT_FAILURE);
}
std::mt19937 rng(std::random_device{}());
u32 lastPos = 0;
u32 lastCount = 0;
for (auto &highlight : this->highlights) {
auto newPos = lastPos + lastCount + (rng() % 40);
auto newCount = (rng() % 7) + 3;
highlight.start.x = newPos % 13;
highlight.start.y = newPos / 13;
highlight.count = newCount;
{
float r, g, b;
ImGui::ColorConvertHSVtoRGB(
(rng() % 360) / 100.0F,
(25 + rng() % 70) / 100.0F,
(85 + rng() % 10) / 100.0F,
r, g, b);
highlight.color = ImColor(r, g, b, 0x50 / 255.0F);
}
lastPos = newPos;
lastCount = newCount;
}
}
void WindowSplash::startStartupTasks() {
// Launch init tasks in background
this->tasksSucceeded = processTasksAsync();
}
void WindowSplash::exitGLFW() {
glfwDestroyWindow(this->m_window);
glfwTerminate();

View File

@ -76,6 +76,8 @@ namespace {
for (const auto &[name, task, async] : init::getInitTasks())
splashWindow.addStartupTask(name, task, async);
splashWindow.startStartupTasks();
// Draw the splash window while tasks are running
if (!splashWindow.loop())
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });

View File

@ -155,6 +155,15 @@ namespace hex {
});
}
void Window::fullFrame() {
glfwPollEvents();
// Render frame
this->frameBegin();
this->frame();
this->frameEnd();
}
void Window::loop() {
while (!glfwWindowShouldClose(this->m_window)) {
this->m_lastFrameTime = glfwGetTime();
@ -163,8 +172,6 @@ namespace hex {
// If the application is minimized or not visible, don't render anything
glfwWaitEvents();
} else {
glfwPollEvents();
// If no events have been received in a while, lower the frame rate
{
// If the mouse is down, the mouse is moving or a popup is open, we don't want to lower the frame rate
@ -197,12 +204,7 @@ namespace hex {
}
}
// Render frame
this->frameBegin();
this->frame();
this->frameEnd();
glfwSwapInterval(0);
this->fullFrame();
// Limit frame rate
// If the target FPS are below 15, use the monitor refresh rate, if it's above 200, don't limit the frame rate