2022-11-30 10:36:50 +00:00
|
|
|
#include "application.hpp"
|
2022-09-13 18:25:18 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
#include <filesystem>
|
|
|
|
#include <memory>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <string>
|
|
|
|
#include <thread>
|
2022-10-27 16:58:30 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
#include <glm/mat4x4.hpp>
|
|
|
|
|
|
|
|
#include "gfx.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"
|
2023-04-29 14:22:25 +00:00
|
|
|
#include "log.hpp"
|
2023-01-20 16:30:35 +00:00
|
|
|
#include "resources/material.hpp"
|
2023-04-29 14:22:25 +00:00
|
|
|
#include "resources/mesh.hpp"
|
2023-01-20 16:30:35 +00:00
|
|
|
#include "resources/shader.hpp"
|
|
|
|
#include "resources/texture.hpp"
|
2023-04-29 14:22:25 +00:00
|
|
|
#include "scene.hpp"
|
|
|
|
#include "scene_manager.hpp"
|
|
|
|
#include "window.hpp"
|
2022-11-10 14:12:29 +00:00
|
|
|
|
2022-12-15 15:54:11 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#include <windows.h>
|
|
|
|
#include <direct.h>
|
2023-04-29 14:22:25 +00:00
|
|
|
#define WIN_MAX_PATH 260
|
2022-12-15 15:54:11 +00:00
|
|
|
#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];
|
2023-04-29 14:22:25 +00:00
|
|
|
GetModuleFileNameA(NULL, exeDirBuf, WIN_MAX_PATH + 1);
|
2023-03-13 17:10:46 +00:00
|
|
|
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
|
|
|
{
|
2023-04-29 14:22:25 +00:00
|
|
|
window_ = std::make_unique<Window>(appName, true, false);
|
|
|
|
input_manager_ = std::make_unique<InputManager>(window_.get());
|
|
|
|
scene_manager_ = std::make_unique<SceneManager>(this);
|
2022-12-15 15:54:11 +00:00
|
|
|
|
|
|
|
// get base path for resources
|
2023-04-29 14:22:25 +00:00
|
|
|
resources_path_ = getResourcesPath();
|
2023-01-20 16:30:35 +00:00
|
|
|
|
2023-01-20 20:59:35 +00:00
|
|
|
// register resource managers
|
2023-04-29 14:22:25 +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
|
2023-04-29 14:57:32 +00:00
|
|
|
render_data_.gfxdev = std::make_unique<GFXDevice>(appName, appVersion, window_->GetHandle(), graphicsSettings);
|
2023-03-21 20:10:23 +00:00
|
|
|
|
2023-03-23 19:07:10 +00:00
|
|
|
std::vector<gfx::DescriptorSetLayoutBinding> globalSetBindings;
|
2023-03-21 20:10:23 +00:00
|
|
|
{
|
2023-03-23 19:07:10 +00:00
|
|
|
auto& binding0 = globalSetBindings.emplace_back();
|
2023-04-29 14:22:25 +00:00
|
|
|
binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer;
|
|
|
|
binding0.stage_flags = gfx::ShaderStageFlags::kVertex;
|
2023-03-21 20:10:23 +00:00
|
|
|
}
|
2023-04-29 14:22:25 +00:00
|
|
|
render_data_.global_set_layout = gfxdev()->CreateDescriptorSetLayout(globalSetBindings);
|
|
|
|
render_data_.global_set = gfxdev()->AllocateDescriptorSet(render_data_.global_set_layout);
|
2023-03-23 19:07:10 +00:00
|
|
|
RenderData::GlobalSetUniformBuffer globalSetUniformBufferData{
|
|
|
|
.proj = glm::mat4{ 1.0f },
|
2023-03-13 17:10:46 +00:00
|
|
|
};
|
2023-04-29 14:22:25 +00:00
|
|
|
render_data_.global_set_uniform_buffer = gfxdev()->CreateUniformBuffer(sizeof(RenderData::GlobalSetUniformBuffer), &globalSetUniformBufferData);
|
|
|
|
gfxdev()->UpdateDescriptorUniformBuffer(render_data_.global_set, 0, render_data_.global_set_uniform_buffer, 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-04-29 14:22:25 +00:00
|
|
|
binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer;
|
|
|
|
binding0.stage_flags = gfx::ShaderStageFlags::kVertex;
|
2023-03-21 23:52:52 +00:00
|
|
|
}
|
2023-04-29 14:22:25 +00:00
|
|
|
render_data_.frame_set_layout = gfxdev()->CreateDescriptorSetLayout(frameSetBindings);
|
|
|
|
render_data_.frame_set = gfxdev()->AllocateDescriptorSet(render_data_.frame_set_layout);
|
2023-03-23 19:07:10 +00:00
|
|
|
RenderData::FrameSetUniformBuffer initialSetOneData{
|
2023-03-15 23:11:24 +00:00
|
|
|
.view = glm::mat4{ 1.0f },
|
|
|
|
};
|
2023-04-29 14:22:25 +00:00
|
|
|
render_data_.frame_set_uniform_buffer = gfxdev()->CreateUniformBuffer(sizeof(RenderData::FrameSetUniformBuffer), &initialSetOneData);
|
|
|
|
gfxdev()->UpdateDescriptorUniformBuffer(render_data_.frame_set, 0, render_data_.frame_set_uniform_buffer, 0, sizeof(RenderData::FrameSetUniformBuffer));
|
2023-03-23 19:07:10 +00:00
|
|
|
|
|
|
|
std::vector<gfx::DescriptorSetLayoutBinding> materialSetBindings;
|
|
|
|
{
|
|
|
|
auto& binding0 = materialSetBindings.emplace_back();
|
2023-04-29 14:22:25 +00:00
|
|
|
binding0.descriptor_type = gfx::DescriptorType::kCombinedImageSampler;
|
|
|
|
binding0.stage_flags = gfx::ShaderStageFlags::kFragment;
|
2023-03-23 19:07:10 +00:00
|
|
|
}
|
2023-04-29 14:22:25 +00:00
|
|
|
render_data_.material_set_layout = gfxdev()->CreateDescriptorSetLayout(materialSetBindings);
|
2023-03-15 23:11:24 +00:00
|
|
|
|
2023-01-20 20:59:35 +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-04-29 14:22:25 +00:00
|
|
|
&render_data_,
|
|
|
|
GetResourcePath("engine/shaders/standard.vert").c_str(),
|
|
|
|
GetResourcePath("engine/shaders/standard.frag").c_str(),
|
2023-01-20 20:59:35 +00:00
|
|
|
vertParams,
|
|
|
|
false,
|
|
|
|
true
|
|
|
|
);
|
2023-04-29 14:22:25 +00:00
|
|
|
GetResourceManager<resources::Shader>()->AddPersistent("builtin.standard", std::move(texturedShader));
|
2023-01-20 20:59:35 +00:00
|
|
|
}
|
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-04-29 14:22:25 +00:00
|
|
|
&render_data_,
|
|
|
|
GetResourcePath("engine/shaders/skybox.vert").c_str(),
|
|
|
|
GetResourcePath("engine/shaders/skybox.frag").c_str(),
|
2023-02-02 17:32:19 +00:00
|
|
|
vertParams,
|
|
|
|
false,
|
|
|
|
true
|
|
|
|
);
|
2023-04-29 14:22:25 +00:00
|
|
|
GetResourceManager<resources::Shader>()->AddPersistent("builtin.skybox", std::move(skyboxShader));
|
2023-02-02 17:32:19 +00:00
|
|
|
}
|
2023-01-20 20:59:35 +00:00
|
|
|
{
|
2023-01-26 21:17:07 +00:00
|
|
|
auto whiteTexture = std::make_unique<resources::Texture>(
|
2023-04-29 14:22:25 +00:00
|
|
|
&render_data_,
|
|
|
|
GetResourcePath("engine/textures/white.png"),
|
2023-03-31 08:08:49 +00:00
|
|
|
resources::Texture::Filtering::OFF
|
2023-01-20 20:59:35 +00:00
|
|
|
);
|
2023-04-29 14:22:25 +00:00
|
|
|
GetResourceManager<resources::Texture>()->AddPersistent("builtin.white", std::move(whiteTexture));
|
2023-01-20 20:59:35 +00:00
|
|
|
}
|
2022-10-04 10:54:23 +00:00
|
|
|
}
|
|
|
|
|
2023-03-13 17:10:46 +00:00
|
|
|
Application::~Application()
|
|
|
|
{
|
2023-04-29 14:22:25 +00:00
|
|
|
for (const auto& [info, sampler] : render_data_.samplers) {
|
|
|
|
gfxdev()->DestroySampler(sampler);
|
2023-03-31 08:08:49 +00:00
|
|
|
}
|
2023-04-29 14:22:25 +00:00
|
|
|
gfxdev()->DestroyDescriptorSetLayout(render_data_.material_set_layout);
|
2023-03-23 19:07:10 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
gfxdev()->DestroyUniformBuffer(render_data_.frame_set_uniform_buffer);
|
|
|
|
gfxdev()->DestroyDescriptorSetLayout(render_data_.frame_set_layout);
|
2023-03-21 23:52:52 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
gfxdev()->DestroyUniformBuffer(render_data_.global_set_uniform_buffer);
|
|
|
|
gfxdev()->DestroyDescriptorSetLayout(render_data_.global_set_layout);
|
2023-03-13 17:10:46 +00:00
|
|
|
}
|
2022-10-04 10:54:23 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
void Application::GameLoop()
|
2022-10-04 10:54:23 +00:00
|
|
|
{
|
2023-03-12 16:14:55 +00:00
|
|
|
LOG_TRACE("Begin game loop...");
|
2022-10-22 12:15:25 +00:00
|
|
|
|
2022-11-10 14:12:29 +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-04-29 14:22:25 +00:00
|
|
|
auto lastTick = window_->getNanos();
|
2023-01-05 13:21:33 +00:00
|
|
|
|
2022-10-04 10:54:23 +00:00
|
|
|
// single-threaded game loop
|
2023-04-29 14:57:32 +00:00
|
|
|
while (window_->IsRunning()) {
|
2022-10-04 10:54:23 +00:00
|
|
|
|
2022-11-28 16:33:50 +00:00
|
|
|
/* logic */
|
2023-04-29 14:22:25 +00:00
|
|
|
scene_manager_->UpdateActiveScene(window_->dt());
|
2022-10-22 12:15:25 +00:00
|
|
|
|
2023-04-29 14:57:32 +00:00
|
|
|
if(window_->GetKeyPress(inputs::Key::K_F)) [[unlikely]] {
|
2023-04-29 14:22:25 +00:00
|
|
|
window_->infoBox("fps", std::to_string(window_->getFPS()) + " fps " + std::to_string(window_->dt() * 1000.0f) + " ms");
|
2022-12-20 23:51:04 +00:00
|
|
|
}
|
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
uint64_t now = window_->getNanos();
|
2023-01-06 16:45:39 +00:00
|
|
|
if (now - lastTick >= 1000000000LL * 5LL) [[unlikely]] {
|
|
|
|
lastTick = now;
|
2023-04-29 14:22:25 +00:00
|
|
|
LOG_INFO("fps: {}", window_->getAvgFPS());
|
|
|
|
gfxdev()->LogPerformanceInfo();
|
|
|
|
window_->resetAvgFPS();
|
2023-01-06 16:45:39 +00:00
|
|
|
}
|
|
|
|
|
2022-10-04 10:54:23 +00:00
|
|
|
/* poll events */
|
2023-04-29 14:57:32 +00:00
|
|
|
window_->GetInputAndEvents();
|
2022-10-04 10:54:23 +00:00
|
|
|
|
2022-11-10 14:12:29 +00:00
|
|
|
/* fps limiter */
|
2023-04-29 14:22:25 +00:00
|
|
|
if (enable_frame_limiter_) {
|
2022-12-20 23:51:04 +00:00
|
|
|
std::this_thread::sleep_until(endFrame);
|
|
|
|
}
|
2022-11-10 14:12:29 +00:00
|
|
|
beginFrame = endFrame;
|
|
|
|
endFrame = beginFrame + FRAMETIME_LIMIT;
|
|
|
|
|
2022-10-04 10:54:23 +00:00
|
|
|
}
|
2022-10-20 19:28:51 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
gfxdev()->WaitIdle();
|
2022-09-13 18:25:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|