engine/src/application.cpp

213 lines
6.8 KiB
C++
Raw Normal View History

2022-11-30 10:36:50 +00:00
#include "application.hpp"
2022-09-13 18:25:18 +00:00
2022-10-27 16:58:30 +00:00
#include "log.hpp"
2022-10-04 10:54:23 +00:00
#include "window.hpp"
2022-10-27 16:58:30 +00:00
#include "gfx_device.hpp"
2022-11-29 14:22:03 +00:00
#include "input_manager.hpp"
#include "scene_manager.hpp"
2022-09-17 00:22:35 +00:00
2022-11-30 10:36:50 +00:00
#include "scene.hpp"
2023-01-20 16:30:35 +00:00
#include "resources/mesh.hpp"
#include "resources/material.hpp"
#include "resources/shader.hpp"
#include "resources/texture.hpp"
2023-03-23 19:07:10 +00:00
#include <glm/mat4x4.hpp>
2023-03-13 17:10:46 +00:00
// To allow the FPS-limiter to put the thread to sleep
#include <thread>
2022-12-15 15:54:11 +00:00
#ifdef _MSC_VER
#include <windows.h>
#include <direct.h>
#define MAX_PATH 260
#endif
2023-03-13 17:10:46 +00:00
namespace engine {
static std::filesystem::path getResourcesPath()
{
std::filesystem::path resourcesPath{};
2022-12-15 15:54:11 +00:00
#ifdef _MSC_VER
2023-03-13 17:10:46 +00:00
CHAR exeDirBuf[MAX_PATH + 1];
GetModuleFileNameA(NULL, exeDirBuf, MAX_PATH + 1);
std::filesystem::path cwd = std::filesystem::path(exeDirBuf).parent_path();
(void)_chdir((const char*)std::filesystem::absolute(cwd).c_str());
2022-12-15 15:54:11 +00:00
#else
2023-03-13 17:10:46 +00:00
std::filesystem::path cwd = std::filesystem::current_path();
2022-12-15 15:54:11 +00:00
#endif
2023-03-13 17:10:46 +00:00
if (std::filesystem::is_directory(cwd / "res")) {
resourcesPath = cwd / "res";
}
else {
resourcesPath = cwd.parent_path() / "share" / "sdltest";
}
2022-12-15 15:54:11 +00:00
2023-03-13 17:10:46 +00:00
if (std::filesystem::is_directory(resourcesPath) == false) {
resourcesPath = cwd.root_path() / "usr" / "local" / "share" / "sdltest";
}
2022-12-15 15:54:11 +00:00
2023-03-13 17:10:46 +00:00
if (std::filesystem::is_directory(resourcesPath) == false) {
throw std::runtime_error("Unable to determine resources location. CWD: " + cwd.string());
}
2022-12-15 15:54:11 +00:00
2023-03-13 17:10:46 +00:00
return resourcesPath;
}
2022-09-13 18:25:18 +00:00
2023-02-19 13:55:08 +00:00
Application::Application(const char* appName, const char* appVersion, gfx::GraphicsSettings graphicsSettings)
2022-10-04 10:54:23 +00:00
{
2022-11-30 10:36:50 +00:00
m_window = std::make_unique<Window>(appName, true, false);
2022-11-29 14:22:03 +00:00
m_inputManager = std::make_unique<InputManager>(window());
2022-12-20 23:51:04 +00:00
m_sceneManager = std::make_unique<SceneManager>(this);
2022-12-15 15:54:11 +00:00
// get base path for resources
m_resourcesPath = getResourcesPath();
2023-01-20 16:30:35 +00:00
// register resource managers
2023-01-26 21:17:07 +00:00
registerResourceManager<resources::Texture>();
registerResourceManager<resources::Shader>();
registerResourceManager<resources::Material>();
registerResourceManager<resources::Mesh>();
2023-01-20 16:30:35 +00:00
2023-03-13 17:10:46 +00:00
// initialise the render data
renderData.gfxdev = std::make_unique<GFXDevice>(appName, appVersion, m_window->getHandle(), graphicsSettings);
2023-03-23 19:07:10 +00:00
std::vector<gfx::DescriptorSetLayoutBinding> globalSetBindings;
{
2023-03-23 19:07:10 +00:00
auto& binding0 = globalSetBindings.emplace_back();
binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER;
binding0.stageFlags = gfx::ShaderStageFlags::VERTEX;
}
2023-03-23 19:07:10 +00:00
renderData.globalSetLayout = gfx()->createDescriptorSetLayout(globalSetBindings);
renderData.globalSet = gfx()->allocateDescriptorSet(renderData.globalSetLayout);
RenderData::GlobalSetUniformBuffer globalSetUniformBufferData{
.proj = glm::mat4{ 1.0f },
2023-03-13 17:10:46 +00:00
};
2023-03-23 19:07:10 +00:00
renderData.globalSetUniformBuffer = gfx()->createUniformBuffer(sizeof(RenderData::GlobalSetUniformBuffer), &globalSetUniformBufferData);
gfx()->updateDescriptorUniformBuffer(renderData.globalSet, 0, renderData.globalSetUniformBuffer, 0, sizeof(RenderData::GlobalSetUniformBuffer));
2023-03-13 17:10:46 +00:00
2023-03-23 19:07:10 +00:00
std::vector<gfx::DescriptorSetLayoutBinding> frameSetBindings;
2023-03-21 23:52:52 +00:00
{
2023-03-23 19:07:10 +00:00
auto& binding0 = frameSetBindings.emplace_back();
2023-03-21 23:52:52 +00:00
binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER;
binding0.stageFlags = gfx::ShaderStageFlags::VERTEX;
}
2023-03-23 19:07:10 +00:00
renderData.frameSetLayout = gfx()->createDescriptorSetLayout(frameSetBindings);
renderData.frameSet = gfx()->allocateDescriptorSet(renderData.frameSetLayout);
RenderData::FrameSetUniformBuffer initialSetOneData{
2023-03-15 23:11:24 +00:00
.view = glm::mat4{ 1.0f },
};
2023-03-23 19:07:10 +00:00
renderData.frameSetUniformBuffer = gfx()->createUniformBuffer(sizeof(RenderData::FrameSetUniformBuffer), &initialSetOneData);
gfx()->updateDescriptorUniformBuffer(renderData.frameSet, 0, renderData.frameSetUniformBuffer, 0, sizeof(RenderData::FrameSetUniformBuffer));
std::vector<gfx::DescriptorSetLayoutBinding> materialSetBindings;
{
auto& binding0 = materialSetBindings.emplace_back();
binding0.descriptorType = gfx::DescriptorType::COMBINED_IMAGE_SAMPLER;
binding0.stageFlags = gfx::ShaderStageFlags::FRAGMENT;
}
renderData.materialSetLayout = gfx()->createDescriptorSetLayout(materialSetBindings);
2023-03-15 23:11:24 +00:00
// default resources
{
resources::Shader::VertexParams vertParams{};
vertParams.hasNormal = true;
vertParams.hasUV0 = true;
2023-01-26 21:17:07 +00:00
auto texturedShader = std::make_unique<resources::Shader>(
2023-03-13 17:10:46 +00:00
&renderData,
getResourcePath("engine/shaders/standard.vert").c_str(),
getResourcePath("engine/shaders/standard.frag").c_str(),
vertParams,
false,
true
);
getResourceManager<resources::Shader>()->addPersistent("builtin.standard", std::move(texturedShader));
}
2023-03-23 19:07:10 +00:00
{
2023-02-02 17:32:19 +00:00
resources::Shader::VertexParams vertParams{};
vertParams.hasNormal = true;
vertParams.hasUV0 = true;
2023-03-23 19:07:10 +00:00
auto skyboxShader = std::make_unique<resources::Shader>(
2023-03-13 17:10:46 +00:00
&renderData,
2023-02-02 17:32:19 +00:00
getResourcePath("engine/shaders/skybox.vert").c_str(),
getResourcePath("engine/shaders/skybox.frag").c_str(),
vertParams,
false,
true
);
2023-03-23 19:07:10 +00:00
getResourceManager<resources::Shader>()->addPersistent("builtin.skybox", std::move(skyboxShader));
2023-02-02 17:32:19 +00:00
}
{
2023-01-26 21:17:07 +00:00
auto whiteTexture = std::make_unique<resources::Texture>(
renderData,
2023-01-26 21:17:07 +00:00
getResourcePath("engine/textures/white.png"),
resources::Texture::Filtering::OFF
);
getResourceManager<resources::Texture>()->addPersistent("builtin.white", std::move(whiteTexture));
}
2022-10-04 10:54:23 +00:00
}
2023-03-13 17:10:46 +00:00
Application::~Application()
{
for (const auto& [info, sampler] : renderData.samplers) {
gfx()->destroySampler(sampler);
}
2023-03-23 19:07:10 +00:00
gfx()->destroyDescriptorSetLayout(renderData.materialSetLayout);
gfx()->destroyUniformBuffer(renderData.frameSetUniformBuffer);
gfx()->destroyDescriptorSetLayout(renderData.frameSetLayout);
2023-03-21 23:52:52 +00:00
2023-03-23 19:07:10 +00:00
gfx()->destroyUniformBuffer(renderData.globalSetUniformBuffer);
gfx()->destroyDescriptorSetLayout(renderData.globalSetLayout);
2023-03-13 17:10:46 +00:00
}
2022-10-04 10:54:23 +00:00
void Application::gameLoop()
{
LOG_TRACE("Begin game loop...");
2022-10-22 12:15:25 +00:00
constexpr int FPS_LIMIT = 240;
constexpr auto FRAMETIME_LIMIT = std::chrono::nanoseconds(1000000000 / FPS_LIMIT);
auto beginFrame = std::chrono::steady_clock::now();
auto endFrame = beginFrame + FRAMETIME_LIMIT;
2023-01-05 13:21:33 +00:00
auto lastTick = m_window->getNanos();
2022-10-04 10:54:23 +00:00
// single-threaded game loop
2022-11-29 14:22:03 +00:00
while (m_window->isRunning()) {
2022-10-04 10:54:23 +00:00
/* logic */
2022-12-15 10:07:22 +00:00
m_sceneManager->updateActiveScene(m_window->dt());
2022-10-22 12:15:25 +00:00
2023-01-06 16:45:39 +00:00
if(m_window->getKeyPress(inputs::Key::K_F)) [[unlikely]] {
2023-01-02 21:11:29 +00:00
m_window->infoBox("fps", std::to_string(m_window->getFPS()) + " fps " + std::to_string(m_window->dt() * 1000.0f) + " ms");
2022-12-20 23:51:04 +00:00
}
2023-01-06 16:45:39 +00:00
uint64_t now = m_window->getNanos();
if (now - lastTick >= 1000000000LL * 5LL) [[unlikely]] {
lastTick = now;
LOG_INFO("fps: {}", m_window->getAvgFPS());
gfx()->logPerformanceInfo();
2023-01-06 16:45:39 +00:00
m_window->resetAvgFPS();
}
2022-10-04 10:54:23 +00:00
/* poll events */
2022-11-29 14:22:03 +00:00
m_window->getInputAndEvents();
2022-10-04 10:54:23 +00:00
/* fps limiter */
2022-12-20 23:51:04 +00:00
if (m_enableFrameLimiter) {
std::this_thread::sleep_until(endFrame);
}
beginFrame = endFrame;
endFrame = beginFrame + FRAMETIME_LIMIT;
2022-10-04 10:54:23 +00:00
}
2023-03-13 17:10:46 +00:00
gfx()->waitIdle();
2022-09-13 18:25:18 +00:00
}
}