157 lines
5.0 KiB
C++
157 lines
5.0 KiB
C++
#include <chrono>
|
|
#include <thread>
|
|
#include <destrum/App.h>
|
|
|
|
#include <destrum/FS/AssetFS.h>
|
|
|
|
#include "glm/gtx/transform.hpp"
|
|
#include "spdlog/spdlog.h"
|
|
|
|
App::App() {}
|
|
|
|
void App::init(const AppParams& params) {
|
|
m_params = params;
|
|
|
|
AssetFS::GetInstance().Init(params.exeDir);
|
|
// AssetFS::GetInstance().Mount("engine", params.exeDir / "assets" / "engine");
|
|
// AssetFS::GetInstance().Mount("game", params.exeDir / "assets" / "game");
|
|
|
|
window = SDL_CreateWindow(
|
|
params.windowTitle.c_str(),
|
|
// pos
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
// size
|
|
params.windowSize.x,
|
|
params.windowSize.y,
|
|
SDL_WINDOW_VULKAN);
|
|
|
|
SDL_SetWindowResizable(window, SDL_TRUE);
|
|
if (!window) {
|
|
spdlog::error("Failed to create window. SDL Error: {}", SDL_GetError());
|
|
std::exit(1);
|
|
}
|
|
|
|
gfxDevice.init(window, params.appName, false);
|
|
|
|
InputManager::GetInstance().Init();
|
|
|
|
customInit();
|
|
}
|
|
|
|
void App::run() {
|
|
using clock = std::chrono::steady_clock;
|
|
|
|
const float targetHz = 60.0f;
|
|
const float dt = 1.0f / targetHz;
|
|
const float maxFrameTime = 0.25f; // clamp big hitches
|
|
const int maxSteps = 5; // prevent spiral of death
|
|
|
|
auto prevTime = clock::now();
|
|
float accumulator = 0.0f;
|
|
|
|
isRunning = true;
|
|
while (isRunning) {
|
|
const auto frameStart = clock::now();
|
|
float frameTimeSec = std::chrono::duration<float>(frameStart - prevTime).count();
|
|
prevTime = frameStart;
|
|
|
|
if (frameTimeSec > 0.07f && frameTimeSec < 5.f) {
|
|
spdlog::warn("Frame drop detected, time: {:.4f}s", frameTimeSec);
|
|
}
|
|
|
|
if (frameTimeSec > maxFrameTime) frameTimeSec = maxFrameTime;
|
|
if (frameTimeSec < 0.0f) frameTimeSec = 0.0f;
|
|
|
|
accumulator += frameTimeSec;
|
|
|
|
if (frameTimeSec > 0.0f) {
|
|
const float newFPS = 1.0f / frameTimeSec;
|
|
avgFPS = std::lerp(avgFPS, newFPS, 0.1f);
|
|
}
|
|
|
|
InputManager::GetInstance().BeginFrame();
|
|
camera.Update(dt);
|
|
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event)) {
|
|
if (event.type == SDL_QUIT) {
|
|
isRunning = false;
|
|
break;
|
|
}
|
|
if (event.type == SDL_WINDOWEVENT) {
|
|
switch (event.window.event) {
|
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
|
case SDL_WINDOWEVENT_RESIZED:
|
|
m_params.windowSize = { event.window.data1, event.window.data2 };
|
|
break;
|
|
}
|
|
}
|
|
if (InputManager::GetInstance().ProcessEvent(event)) {
|
|
isRunning = false;
|
|
}
|
|
}
|
|
if (!isRunning) break;
|
|
customUpdate(dt);
|
|
|
|
// ---- Swapchain resize check once per frame ----
|
|
if (gfxDevice.needsSwapchainRecreate()) {
|
|
spdlog::info("Recreating swapchain to size: {}x{}", m_params.windowSize.x, m_params.windowSize.y);
|
|
gfxDevice.recreateSwapchain(m_params.windowSize.x, m_params.windowSize.y);
|
|
onWindowResize(m_params.windowSize.x, m_params.windowSize.y);
|
|
}
|
|
|
|
// ---- Fixed updates (no event polling inside) ----
|
|
int steps = 0;
|
|
while (accumulator >= dt && steps < maxSteps) {
|
|
//Set window title to fps
|
|
SDL_SetWindowTitle(
|
|
window,
|
|
fmt::format("{} - FPS: {:.2f}", m_params.windowTitle, avgFPS).c_str());
|
|
accumulator -= dt;
|
|
steps++;
|
|
}
|
|
// If we hit the step cap, drop leftover time to recover smoothly
|
|
if (steps == maxSteps) accumulator = 0.0f;
|
|
|
|
// Optional interpolation factor for rendering
|
|
const float alpha = accumulator / dt;
|
|
|
|
// ---- Render ----
|
|
if (!gfxDevice.needsSwapchainRecreate()) {
|
|
// glm::mat4 objMatrix = glm::translate(glm::mat4(1.f), glm::vec3(0.f, -3.0f, 0.f));
|
|
//
|
|
// renderer.beginDrawing(gfxDevice);
|
|
// renderer.drawMesh(testMeshID, glm::mat4(1.f), testMaterialID);
|
|
// renderer.drawMesh(testMeshID, objMatrix, 0);
|
|
// renderer.endDrawing();
|
|
//
|
|
// const auto cmd = gfxDevice.beginFrame();
|
|
// const auto& drawImage = renderer.getDrawImage(gfxDevice);
|
|
//
|
|
// renderer.draw(cmd, gfxDevice, camera, GameRenderer::SceneData{
|
|
// camera, glm::vec3(0.1f), 0.5f, glm::vec3(0.5f), 0.01f
|
|
// });
|
|
//
|
|
// gfxDevice.endFrame(cmd, drawImage, {
|
|
// .clearColor = {{0.f, 0.f, 0.5f, 1.f}},
|
|
// .drawImageBlitRect = glm::ivec4{}
|
|
// });
|
|
customDraw();
|
|
}
|
|
|
|
// ---- Frame cap (if you still want it) ----
|
|
if (frameLimit) {
|
|
const auto targetEnd = frameStart + std::chrono::duration_cast<clock::duration>(
|
|
std::chrono::duration<float>(dt)
|
|
);
|
|
std::this_thread::sleep_until(targetEnd);
|
|
|
|
}
|
|
}
|
|
gfxDevice.waitIdle();
|
|
}
|
|
|
|
void App::cleanup() {
|
|
}
|