[nostalgia] Break part of core out into Turbine and TeaGBA libraries
This commit is contained in:
12
src/turbine/glfw/CMakeLists.txt
Normal file
12
src/turbine/glfw/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
target_sources(
|
||||
Turbine PRIVATE
|
||||
clipboard.cpp
|
||||
gfx.cpp
|
||||
turbine.cpp
|
||||
)
|
||||
target_link_libraries(
|
||||
Turbine PUBLIC
|
||||
glad
|
||||
glfw
|
||||
imgui
|
||||
)
|
27
src/turbine/glfw/clipboard.cpp
Normal file
27
src/turbine/glfw/clipboard.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <ox/std/string.hpp>
|
||||
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace turbine {
|
||||
|
||||
ox::String getClipboardText(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
return glfwGetClipboardString(gctx.window);
|
||||
}
|
||||
|
||||
void setClipboardText(Context &ctx, ox::CRStringView text) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
auto cstr = ox_malloca(text.bytes() + 1, char);
|
||||
ox_strncpy(cstr.get(), text.data(), text.bytes());
|
||||
glfwSetClipboardString(gctx.window, cstr);
|
||||
}
|
||||
|
||||
}
|
25
src/turbine/glfw/context.hpp
Normal file
25
src/turbine/glfw/context.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
namespace turbine {
|
||||
|
||||
struct GlfwContext: public turbine::Context {
|
||||
int uninterruptedRefreshes = 3;
|
||||
ox::UPtr<BaseClipboardObject> clipboard;
|
||||
struct GLFWwindow *window = nullptr;
|
||||
// sets screen refresh to constant instead of only on event
|
||||
bool constantRefresh = true;
|
||||
ox::Vector<gl::Drawer*, 5> drawers;
|
||||
int64_t startTime = 0;
|
||||
uint64_t wakeupTime = 0;
|
||||
uint64_t keysDown = 0;
|
||||
uint64_t prevFpsCheckTime = 0;
|
||||
uint64_t draws = 0;
|
||||
};
|
||||
|
||||
}
|
274
src/turbine/glfw/gfx.cpp
Normal file
274
src/turbine/glfw/gfx.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
|
||||
#include <ox/std/defines.hpp>
|
||||
|
||||
#include <turbine/config.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace turbine {
|
||||
|
||||
namespace gl {
|
||||
|
||||
void addDrawer(Context &ctx, Drawer *cd) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
gctx.drawers.emplace_back(cd);
|
||||
}
|
||||
|
||||
void removeDrawer(Context &ctx, Drawer *cd) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
for (auto i = 0u; i < gctx.drawers.size(); ++i) {
|
||||
if (gctx.drawers[i] == cd) {
|
||||
oxIgnoreError(gctx.drawers.erase(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
constexpr auto Scale = 5;
|
||||
|
||||
static void handleGlfwError(int err, const char *desc) noexcept {
|
||||
oxErrf("GLFW error ({}): {}\n", err, desc);
|
||||
}
|
||||
|
||||
static auto setKeyDownStatus(GlfwContext *gctx, Key key, bool down) noexcept {
|
||||
if (down) {
|
||||
gctx->keysDown |= 1llu << static_cast<int>(key);
|
||||
} else {
|
||||
gctx->keysDown &= ~(1llu << static_cast<int>(key));
|
||||
}
|
||||
}
|
||||
|
||||
static void handleKeyPress(Context *ctx, int key, bool down) noexcept {
|
||||
static constexpr auto keyMap = [] {
|
||||
ox::Array<Key, GLFW_KEY_LAST> map = {};
|
||||
for (auto i = 0u; i < 26; ++i) {
|
||||
map[GLFW_KEY_A + i] = static_cast<Key>(static_cast<unsigned>(Key::Alpha_A) + i);
|
||||
}
|
||||
for (auto i = 0u; i < 10; ++i) {
|
||||
map[GLFW_KEY_0 + i] = static_cast<Key>(static_cast<unsigned>(Key::Num_0) + i);
|
||||
}
|
||||
map[GLFW_KEY_LEFT_ALT] = Key::Mod_Alt;
|
||||
map[GLFW_KEY_RIGHT_ALT] = Key::Mod_Alt;
|
||||
map[GLFW_KEY_LEFT_CONTROL] = Key::Mod_Ctrl;
|
||||
map[GLFW_KEY_RIGHT_CONTROL] = Key::Mod_Ctrl;
|
||||
map[GLFW_KEY_LEFT_SUPER] = Key::Mod_Super;
|
||||
map[GLFW_KEY_RIGHT_SUPER] = Key::Mod_Super;
|
||||
map[GLFW_KEY_ESCAPE] = Key::Escape;
|
||||
return map;
|
||||
}();
|
||||
const auto eventHandler = keyEventHandler(*ctx);
|
||||
auto &gctx = static_cast<GlfwContext&>(*ctx);
|
||||
const auto k = keyMap[static_cast<std::size_t>(key)];
|
||||
setKeyDownStatus(&gctx, k, down);
|
||||
if (eventHandler) {
|
||||
eventHandler(*ctx, k, down);
|
||||
}
|
||||
//if constexpr(ox::defines::Debug) {
|
||||
// switch (key) {
|
||||
// case GLFW_KEY_ESCAPE:
|
||||
// case GLFW_KEY_Q:
|
||||
// oxIgnoreError(requestShutdown(ctx));
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
static void handleGlfwCursorPosEvent(GLFWwindow*, double, double) noexcept {
|
||||
}
|
||||
|
||||
static void handleGlfwMouseButtonEvent(GLFWwindow *window, int, int, int) noexcept {
|
||||
const auto ctx = static_cast<GlfwContext*>(glfwGetWindowUserPointer(window));
|
||||
ctx->uninterruptedRefreshes = 25;
|
||||
}
|
||||
|
||||
static void handleGlfwWindowResize(GLFWwindow*, int, int) noexcept {
|
||||
}
|
||||
|
||||
static void handleGlfwKeyEvent(GLFWwindow *window, int key, int, int action, int) noexcept {
|
||||
const auto ctx = static_cast<GlfwContext*>(glfwGetWindowUserPointer(window));
|
||||
ctx->uninterruptedRefreshes = 25;
|
||||
if (action == GLFW_PRESS) {
|
||||
handleKeyPress(ctx, key, true);
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
handleKeyPress(ctx, key, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void themeImgui() noexcept {
|
||||
// Dark Ruda style by Raikiri from ImThemes
|
||||
auto &style = ImGui::GetStyle();
|
||||
style.Alpha = 1.0;
|
||||
style.DisabledAlpha = 0.6000000238418579;
|
||||
style.WindowPadding = ImVec2(8.0, 8.0);
|
||||
style.WindowRounding = 0.0;
|
||||
style.WindowBorderSize = 1.0;
|
||||
style.WindowMinSize = ImVec2(32.0, 32.0);
|
||||
style.WindowTitleAlign = ImVec2(0.0, 0.5);
|
||||
style.WindowMenuButtonPosition = ImGuiDir_Left;
|
||||
style.ChildRounding = 0.0;
|
||||
style.ChildBorderSize = 1.0;
|
||||
style.PopupRounding = 0.0;
|
||||
style.PopupBorderSize = 1.0;
|
||||
style.FramePadding = ImVec2(4.0, 3.0);
|
||||
// custom value
|
||||
style.FrameRounding = 3.0;
|
||||
style.FrameBorderSize = 0.0;
|
||||
style.ItemSpacing = ImVec2(8.0, 4.0);
|
||||
style.ItemInnerSpacing = ImVec2(4.0, 4.0);
|
||||
style.CellPadding = ImVec2(4.0, 2.0);
|
||||
style.IndentSpacing = 21.0;
|
||||
style.ColumnsMinSpacing = 6.0;
|
||||
style.ScrollbarSize = 14.0;
|
||||
style.ScrollbarRounding = 9.0;
|
||||
style.GrabMinSize = 10.0;
|
||||
style.GrabRounding = 4.0;
|
||||
style.TabRounding = 4.0;
|
||||
style.TabBorderSize = 0.0;
|
||||
style.TabMinWidthForCloseButton = 0.0;
|
||||
style.ColorButtonPosition = ImGuiDir_Right;
|
||||
style.ButtonTextAlign = ImVec2(0.5, 0.5);
|
||||
style.SelectableTextAlign = ImVec2(0.0, 0.0);
|
||||
// colors
|
||||
style.Colors[ImGuiCol_Text] = ImVec4(0.9490196108818054, 0.95686274766922, 0.9764705896377563, 1.0);
|
||||
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.3568627536296844, 0.4196078479290009, 0.4666666686534882, 1.0);
|
||||
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.1490196138620377, 0.1764705926179886, 0.2196078449487686, 1.0);
|
||||
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.0784313753247261, 0.0784313753247261, 0.0784313753247261, 0.9399999976158142);
|
||||
style.Colors[ImGuiCol_Border] = ImVec4(0.0784313753247261, 0.09803921729326248, 0.1176470592617989, 1.0);
|
||||
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.0, 0.0, 0.0, 0.0);
|
||||
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.1176470592617989, 0.2000000029802322, 0.2784313857555389, 1.0);
|
||||
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.08627451211214066, 0.1176470592617989, 0.1372549086809158, 1.0);
|
||||
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.08627451211214066, 0.1176470592617989, 0.1372549086809158, 0.6499999761581421);
|
||||
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.0784313753247261, 0.09803921729326248, 0.1176470592617989, 1.0);
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.0, 0.0, 0.0, 0.5099999904632568);
|
||||
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.1490196138620377, 0.1764705926179886, 0.2196078449487686, 1.0);
|
||||
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.01960784383118153, 0.01960784383118153, 0.01960784383118153, 0.3899999856948853);
|
||||
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.1764705926179886, 0.2196078449487686, 0.2470588237047195, 1.0);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.08627451211214066, 0.2078431397676468, 0.3098039329051971, 1.0);
|
||||
style.Colors[ImGuiCol_CheckMark] = ImVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.3686274588108063, 0.6078431606292725, 1.0, 1.0);
|
||||
style.Colors[ImGuiCol_Button] = ImVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.05882352963089943, 0.529411792755127, 0.9764705896377563, 1.0);
|
||||
// custom value
|
||||
style.Colors[ImGuiCol_Header] = ImVec4(0.4000000029802322, 0.4470588237047195, 0.4862745225429535, 0.550000011920929);
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.800000011920929);
|
||||
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 1.0);
|
||||
style.Colors[ImGuiCol_Separator] = ImVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.09803921729326248, 0.4000000059604645, 0.7490196228027344, 0.7799999713897705);
|
||||
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.09803921729326248, 0.4000000059604645, 0.7490196228027344, 1.0);
|
||||
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.25);
|
||||
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.6700000166893005);
|
||||
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.949999988079071);
|
||||
style.Colors[ImGuiCol_Tab] = ImVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
style.Colors[ImGuiCol_TabHovered] = ImVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.800000011920929);
|
||||
style.Colors[ImGuiCol_TabActive] = ImVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.6078431606292725, 0.6078431606292725, 0.6078431606292725, 1.0);
|
||||
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.0, 0.4274509847164154, 0.3490196168422699, 1.0);
|
||||
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.8980392217636108, 0.6980392336845398, 0.0, 1.0);
|
||||
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.0, 0.6000000238418579, 0.0, 1.0);
|
||||
style.Colors[ImGuiCol_TableHeaderBg] = ImVec4(0.1882352977991104, 0.1882352977991104, 0.2000000029802322, 1.0);
|
||||
style.Colors[ImGuiCol_TableBorderStrong] = ImVec4(0.3098039329051971, 0.3098039329051971, 0.3490196168422699, 1.0);
|
||||
style.Colors[ImGuiCol_TableBorderLight] = ImVec4(0.2274509817361832, 0.2274509817361832, 0.2470588237047195, 1.0);
|
||||
style.Colors[ImGuiCol_TableRowBg] = ImVec4(0.0, 0.0, 0.0, 0.0);
|
||||
style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.0, 1.0, 1.0, 0.05999999865889549);
|
||||
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.3499999940395355);
|
||||
style.Colors[ImGuiCol_DragDropTarget] = ImVec4(1.0, 1.0, 0.0, 0.8999999761581421);
|
||||
style.Colors[ImGuiCol_NavHighlight] = ImVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 1.0);
|
||||
style.Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.0, 1.0, 1.0, 0.699999988079071);
|
||||
style.Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.800000011920929, 0.800000011920929, 0.800000011920929, 0.2000000029802322);
|
||||
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.800000011920929, 0.800000011920929, 0.800000011920929, 0.3499999940395355);
|
||||
}
|
||||
|
||||
ox::Error initGfx(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
glfwSetErrorCallback(handleGlfwError);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
if constexpr(ox::defines::OS == ox::OS::Darwin) {
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||
}
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
auto cstr = ox_malloca(ctx.appName.bytes() + 1, char);
|
||||
ox_strncpy(cstr.get(), ctx.appName.data(), ctx.appName.bytes());
|
||||
gctx.window = glfwCreateWindow(240 * Scale, 160 * Scale, cstr, nullptr, nullptr);
|
||||
if (gctx.window == nullptr) {
|
||||
return OxError(1, "Could not open GLFW window");
|
||||
}
|
||||
glfwSetCursorPosCallback(gctx.window, handleGlfwCursorPosEvent);
|
||||
glfwSetMouseButtonCallback(gctx.window, handleGlfwMouseButtonEvent);
|
||||
glfwSetWindowSizeCallback(gctx.window, handleGlfwWindowResize);
|
||||
glfwSetKeyCallback(gctx.window, handleGlfwKeyEvent);
|
||||
glfwSetWindowUserPointer(gctx.window, &ctx);
|
||||
glfwMakeContextCurrent(gctx.window);
|
||||
if (!gladLoadGLES2Loader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress))) {
|
||||
return OxError(2, "Could not init Glad");
|
||||
}
|
||||
if constexpr(config::ImGuiEnabled) {
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
auto &io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
//io.MouseDrawCursor = true;
|
||||
ImGui_ImplGlfw_InitForOpenGL(gctx.window, true);
|
||||
themeImgui();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void setWindowTitle(Context &ctx, ox::CRStringView title) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
auto cstr = ox_malloca(title.bytes() + 1, char);
|
||||
ox_strncpy(cstr.get(), title.data(), title.bytes());
|
||||
glfwSetWindowTitle(gctx.window, cstr);
|
||||
}
|
||||
|
||||
void focusWindow(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
glfwFocusWindow(gctx.window);
|
||||
}
|
||||
|
||||
int getScreenWidth(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(gctx.window, &w, &h);
|
||||
return w;
|
||||
}
|
||||
|
||||
int getScreenHeight(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(gctx.window, &w, &h);
|
||||
return h;
|
||||
}
|
||||
|
||||
ox::Size getScreenSize(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(gctx.window, &w, &h);
|
||||
return {w, h};
|
||||
}
|
||||
|
||||
void setConstantRefresh(Context &ctx, bool r) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
gctx.constantRefresh = r;
|
||||
}
|
||||
|
||||
}
|
109
src/turbine/glfw/turbine.cpp
Normal file
109
src/turbine/glfw/turbine.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
|
||||
#include <keel/keel.hpp>
|
||||
#include <turbine/gfx.hpp>
|
||||
|
||||
#include "../config.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace turbine {
|
||||
|
||||
ox::Result<ox::UPtr<Context>> init(ox::UPtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept {
|
||||
oxRequireM(ctx, keel::init<GlfwContext>(std::move(fs), appName));
|
||||
using namespace std::chrono;
|
||||
ctx->startTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
glfwInit();
|
||||
oxReturnError(initGfx(*ctx));
|
||||
return ox::UPtr<Context>(ctx.release());
|
||||
}
|
||||
|
||||
static void tickFps(GlfwContext &gctx, uint64_t nowMs) noexcept {
|
||||
++gctx.draws;
|
||||
if (gctx.draws >= 500) {
|
||||
const auto duration = static_cast<double>(nowMs - gctx.prevFpsCheckTime) / 1000.0;
|
||||
const auto fps = static_cast<int>(static_cast<double>(gctx.draws) / duration);
|
||||
if constexpr(config::GlFpsPrint) {
|
||||
oxOutf("FPS: {}\n", fps);
|
||||
}
|
||||
oxTracef("turbine::fps", "FPS: {}", fps);
|
||||
gctx.prevFpsCheckTime = nowMs;
|
||||
gctx.draws = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error run(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
int sleepTime = 0;
|
||||
while (!glfwWindowShouldClose(gctx.window)) {
|
||||
glfwPollEvents();
|
||||
const auto ticks = ticksMs(gctx);
|
||||
if (gctx.wakeupTime <= ticks) {
|
||||
sleepTime = gctx.updateHandler(gctx);
|
||||
if (sleepTime >= 0) {
|
||||
gctx.wakeupTime = ticks + static_cast<unsigned>(sleepTime);
|
||||
} else {
|
||||
gctx.wakeupTime = ~uint64_t(0);
|
||||
}
|
||||
} else {
|
||||
sleepTime = 10;
|
||||
}
|
||||
tickFps(gctx, ticks);
|
||||
// draw start
|
||||
if constexpr(turbine::config::ImGuiEnabled) {
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
for (auto d : gctx.drawers) {
|
||||
d->draw(gctx);
|
||||
}
|
||||
if constexpr(turbine::config::ImGuiEnabled) {
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
// draw end
|
||||
glfwSwapBuffers(gctx.window);
|
||||
if (!gctx.constantRefresh) {
|
||||
if (gctx.uninterruptedRefreshes) {
|
||||
--gctx.uninterruptedRefreshes;
|
||||
} else {
|
||||
glfwWaitEventsTimeout(sleepTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
shutdown(gctx);
|
||||
return {};
|
||||
}
|
||||
|
||||
void shutdown(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
if (gctx.window) {
|
||||
glfwDestroyWindow(gctx.window);
|
||||
gctx.window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ticksMs(const Context &ctx) noexcept {
|
||||
using namespace std::chrono;
|
||||
auto &gctx = static_cast<const GlfwContext&>(ctx);
|
||||
const auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
return static_cast<uint64_t>(now - gctx.startTime);
|
||||
}
|
||||
|
||||
bool buttonDown(const Context &ctx, Key key) noexcept {
|
||||
auto &gctx = static_cast<const GlfwContext&>(ctx);
|
||||
return (gctx.keysDown >> static_cast<int>(key)) & 1;
|
||||
}
|
||||
|
||||
void requestShutdown(Context &ctx) noexcept {
|
||||
auto &gctx = static_cast<GlfwContext&>(ctx);
|
||||
glfwSetWindowShouldClose(gctx.window, true);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user