From 78ef93bcf513276e0eec2304db6ebbca284d76e7 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Fri, 14 Oct 2022 23:17:22 -0400 Subject: [PATCH 1/5] Start working on fixed timestep Frame interprelation still needs to be done to make a slow TPS look smooth --- .clang-tidy | 4 ++ examples/dev_testing/src/main.cpp | 6 +- include/simpleengine/camera.h | 11 ++++ .../ecs/component/transform_component.h | 9 ++- include/simpleengine/game.h | 13 +++-- include/simpleengine/gfx/light.h | 2 +- include/simpleengine/gfx/renderer.h | 13 +++-- include/simpleengine/renderable.h | 2 +- include/simpleengine/scene.h | 8 ++- resources/shaders/core/3d/fragment_core.glsl | 2 +- src/game.cpp | 36 ++++++++---- src/gfx/renderer.cpp | 55 ++++++++++++++----- src/scene.cpp | 21 ++++--- 13 files changed, 133 insertions(+), 49 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index b3fa1d3..adcf3e8 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -35,5 +35,9 @@ CheckOptions: value: "NULL" - key: readability-magic-numbers value: "0" + - key: cppcoreguidelines-avoid-magic-numbers + value: "0" + - key: cppcoreguidelines-non-private-member-variables-in-classes + value: "0" --- diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index ca77c59..e87abfe 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -70,11 +70,12 @@ int main(int argc, char *argv[]) { // Create a renderer auto renderer = std::make_shared(game.get_window(), core_shader, camera); renderer->initialize(); - game.add_renderable(renderer); + //game.add_renderable(renderer); // Create a Scene and give it the renderer auto scene = std::make_shared(renderer); - game.add_event(scene); + //game.add_event(scene); + game.add_renderable(scene); se::ecs::Entity other_e = scene->create_entity(); other_e.add_component("examples/dev_testing/resources/transparent_window.fbx", @@ -95,6 +96,7 @@ int main(int argc, char *argv[]) { se::ecs::Entity brick_e = scene->create_entity(); brick_e.add_component("examples/dev_testing/resources/bricks/bricks.fbx"); + brick_e.add_component(); auto &brick_transf = brick_e.add_component(); brick_transf.translate(6.f, -0.5f, 1.f); diff --git a/include/simpleengine/camera.h b/include/simpleengine/camera.h index 3a5f012..bf7c3a5 100644 --- a/include/simpleengine/camera.h +++ b/include/simpleengine/camera.h @@ -10,10 +10,21 @@ #include namespace simpleengine { + namespace gfx { + class Renderer; + } + class Camera : public simpleengine::Event { + friend gfx::Renderer; private: GLFWwindow* window; + + glm::vec3 last_position; + glm::vec3 last_rotation; + glm::mat4 last_view_matrix; + glm::vec3 last_camera_front; public: + glm::vec3 position; glm::vec3 rotation; gfx::Shader shader; diff --git a/include/simpleengine/ecs/component/transform_component.h b/include/simpleengine/ecs/component/transform_component.h index f0fa948..9a15519 100644 --- a/include/simpleengine/ecs/component/transform_component.h +++ b/include/simpleengine/ecs/component/transform_component.h @@ -1,5 +1,6 @@ #pragma once +//#include "simpleengine/scene.h" #include #include @@ -9,14 +10,18 @@ namespace simpleengine { * */ class TransformComponent { + friend class Scene; + private: + // This is the transform from the last render loop. The renderer uses this for frame interprelation + glm::mat4 last_transform_matrix; public: glm::mat4 transform_matrix; - TransformComponent() : transform_matrix(glm::mat4(1.f)) { + TransformComponent() : transform_matrix(1.f), last_transform_matrix(1.f) { } - TransformComponent(glm::mat4 transform_matrix) : transform_matrix(transform_matrix) { + TransformComponent(glm::mat4 transform_matrix) : transform_matrix(transform_matrix), last_transform_matrix(1.f) { } diff --git a/include/simpleengine/game.h b/include/simpleengine/game.h index 2f1ad17..ce6bd95 100644 --- a/include/simpleengine/game.h +++ b/include/simpleengine/game.h @@ -42,8 +42,8 @@ namespace simpleengine { void update(const float& delta_time); void handle_input(const float& delta_time); - void render_window(const float& delta_time); - void render_items(const float& delta_time); + void render_window(const float& interpolate_alpha, const float& delta_time); + void render_items(const float& interpolate_alpha, const float& delta_time); void exit(); int run(); @@ -63,8 +63,13 @@ namespace simpleengine { // FPS related stuff void update_enabled_vsync() const; void limit_framerate(const float& delta_time) const; // Triggered at the end of a draw to help limit the FPS to `fps_limit`. - int fps_limit; - bool enable_vsync; + int fps_limit = -1; + bool enable_vsync = true; + + int max_engine_tps = 60; // The maximum engine TPS + double tps_accumulator = 0.f; + //int engine_ticks_second = 0; // The amount of ticks in a second + //double last_sec_engine_tick; // The time of the last second float get_delta_time(); diff --git a/include/simpleengine/gfx/light.h b/include/simpleengine/gfx/light.h index f534792..a522f1c 100644 --- a/include/simpleengine/gfx/light.h +++ b/include/simpleengine/gfx/light.h @@ -23,7 +23,7 @@ namespace simpleengine::gfx { shader.unuse(); } - virtual void render() override { + virtual void render(const float& interpolate_alpha, const float& frame_time) override { } }; diff --git a/include/simpleengine/gfx/renderer.h b/include/simpleengine/gfx/renderer.h index bb0e06b..8536602 100644 --- a/include/simpleengine/gfx/renderer.h +++ b/include/simpleengine/gfx/renderer.h @@ -17,9 +17,10 @@ namespace simpleengine::gfx { public: RenderingType rendering_type; gfx::Mesh* rendering_mesh; + glm::mat4 last_transform_mat; glm::mat4 transform_mat; - RenderingJob(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 position); + RenderingJob(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 last_pos, glm::mat4 position); }; class Renderer : public simpleengine::Renderable { @@ -43,7 +44,7 @@ namespace simpleengine::gfx { void enable_debug(); virtual void sort_jobs(); - virtual void queue_job(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 position); + virtual void queue_job(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 last_position, glm::mat4 position); virtual void queue_job(RenderingJob job); virtual void create_job_buffers(RenderingJob& job); @@ -52,7 +53,7 @@ namespace simpleengine::gfx { virtual void update(const float& delta_time) override; - virtual void render() override; + virtual void render(const float& interpolate_alpha, const float& frame_time) override; /** * @brief Renders a single job. @@ -61,8 +62,8 @@ namespace simpleengine::gfx { * @return true if the job was rendered successfully. * @return false if there was an error when trying to render the job. */ - virtual bool render_job(const RenderingJob& job); - virtual void render_job_queue(std::queue& queue); - virtual void render_job_queue(std::map>& queue); + virtual bool render_job(const float& interpolate_alpha, const RenderingJob& job); + virtual void render_job_queue(const float& interpolate_alpha, std::queue& queue); + virtual void render_job_queue(const float& interpolate_alpha, std::map>& queue); }; } \ No newline at end of file diff --git a/include/simpleengine/renderable.h b/include/simpleengine/renderable.h index cf7446c..667c20b 100644 --- a/include/simpleengine/renderable.h +++ b/include/simpleengine/renderable.h @@ -14,6 +14,6 @@ namespace simpleengine { Renderable() = default; virtual ~Renderable() = default; - virtual void render() = 0; + virtual void render(const float& interpolate_alpha, const float& frame_time) = 0; }; } \ No newline at end of file diff --git a/include/simpleengine/scene.h b/include/simpleengine/scene.h index ec086fa..bda0945 100644 --- a/include/simpleengine/scene.h +++ b/include/simpleengine/scene.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -18,16 +19,21 @@ namespace simpleengine { class Entity; } - class Scene : public simpleengine::Event { + //class Scene : public simpleengine::Event { + class Scene : public simpleengine::Renderable { protected: entt::registry registry; std::shared_ptr renderer; + + // Last transform matrixes for all entities. + std::unordered_map last_transforms; public: Scene(std::shared_ptr renderer); ecs::Entity create_entity(); virtual void update(const float& delta_time) override; + virtual void render(const float& interpolate_alpha, const float& frame_time) override; virtual void destroy() override; }; diff --git a/resources/shaders/core/3d/fragment_core.glsl b/resources/shaders/core/3d/fragment_core.glsl index cd76c7b..f7ffb44 100644 --- a/resources/shaders/core/3d/fragment_core.glsl +++ b/resources/shaders/core/3d/fragment_core.glsl @@ -26,7 +26,7 @@ struct Material { bool has_specular_map; sampler2D specular_map; - + bool has_normal_map; sampler2D normal_map; diff --git a/src/game.cpp b/src/game.cpp index dc7d5ac..f158503 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -19,7 +19,7 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name, const int& gl_profile, const int& major_version, const int& minor_version, const bool& resizeable, const int& forward_compat) : window_resizeable(resizeable), - enable_vsync(true), fps_limit(-1) { + tps_accumulator(0.f) { initialize(gl_profile, major_version, minor_version, window_resizeable, forward_compat); // Create a window @@ -45,6 +45,8 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name, const int } enable_default_gl_options(); + + last_frame_time = std::chrono::high_resolution_clock::now(); } void simpleengine::Game::enable_default_gl_options() const { @@ -105,6 +107,10 @@ void simpleengine::Game::update_enabled_vsync() const { } } +void simpleengine::Game::handle_input(const float& delta_time) { + // TODO +} + void simpleengine::Game::update(const float& delta_time) { handle_input(delta_time); @@ -114,19 +120,15 @@ void simpleengine::Game::update(const float& delta_time) { } } -void simpleengine::Game::handle_input(const float& delta_time) { - // TODO -} - -void simpleengine::Game::render_window(const float& delta_time) { +void simpleengine::Game::render_window(const float& interpolate_alpha, const float& delta_time) { glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - render_items(delta_time); + render_items(interpolate_alpha, delta_time); } -void simpleengine::Game::render_items(const float& delta_time) { +void simpleengine::Game::render_items(const float& interpolate_alpha, const float& delta_time) { for (const std::shared_ptr& renderable : renderable_events) { - renderable->render(); + renderable->render(interpolate_alpha, delta_time); } } @@ -155,12 +157,24 @@ int simpleengine::Game::run() { while (!glfwWindowShouldClose(window)) { // Get delta time first thing float delta_time = get_delta_time(); + //std::cout << "Delta time: " << delta_time << std::endl; // Poll input events glfwPollEvents(); - update(delta_time); - render_window(delta_time); + const double max_delta_time = 0.5; + + tps_accumulator += delta_time; + + while (tps_accumulator >= max_delta_time) { + update(max_delta_time); + + tps_accumulator -= max_delta_time; + } + + const double interpolate_alpha = tps_accumulator / max_delta_time; + + render_window(interpolate_alpha, delta_time); // End draw glfwSwapBuffers(window); diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 47d099d..514ec33 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -13,11 +13,13 @@ #include #include +#include + namespace simpleengine::gfx { void create_mesh_buffers(simpleengine::gfx::Mesh &mesh); - RenderingJob::RenderingJob(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) - : rendering_type(rendering_type), rendering_mesh(&mesh), transform_mat(position) {} + RenderingJob::RenderingJob(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 last_pos, glm::mat4 position) + : rendering_type(rendering_type), rendering_mesh(&mesh), last_transform_mat(last_pos), transform_mat(position) {} Renderer::Renderer(GLFWwindow *window, gfx::Shader shader, std::shared_ptr camera) : window(window), shader(shader), camera(camera)/* , transparent_render_queue(CameraDistanceComparator(camera)) */ {} @@ -50,8 +52,8 @@ namespace simpleengine::gfx { // std::sort() } - void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) { - RenderingJob job(rendering_type, mesh, position); + void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 last_position, glm::mat4 position) { + RenderingJob job(rendering_type, mesh, last_position, position); this->queue_job(job); } @@ -135,10 +137,37 @@ namespace simpleengine::gfx { } */ } - bool Renderer::render_job(const RenderingJob &job) { + glm::mat4 lerp(glm::mat4 a, glm::mat4 b, float alpha) { + //return a * (1.f - alpha) + b * alpha; + glm::quat rot0 = glm::quat_cast(a); + glm::quat rot1= glm::quat_cast(b); + + glm::quat finalRot = glm::slerp(rot0, rot1, alpha); + + glm::mat4 finalMat = glm::mat4_cast(finalRot); + + finalMat[3] = a[3] * (1 - alpha) + b[3] * alpha; + + return finalMat; + } + + bool Renderer::render_job(const float& interpolate_alpha, const RenderingJob &job) { Mesh *mesh = job.rendering_mesh; - shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat); + /* glm::mat4 transform_mat = job.transform_mat * interpolate_alpha + + job.last_transform_mat * (1.f - interpolate_alpha); */ + + //glm::mat4 transform_mat = lerp(job.transform_mat, job.last_transform_mat, interpolate_alpha); + glm::mat4 transform_mat = lerp(job.last_transform_mat, job.transform_mat, interpolate_alpha); + + std::cout << "Last transform: " << glm::to_string(job.last_transform_mat) << std::endl << + "Current Transform: " << glm::to_string(job.transform_mat) << std::endl << + "Lerp: " << glm::to_string(transform_mat) << std::endl << std::endl; + + //std::cout << "Current: " << job.transform_mat[3] + + shader.set_uniform_matrix_4f("u_transform_matrix", transform_mat); + //shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat); std::optional &material = mesh->material; @@ -196,12 +225,12 @@ namespace simpleengine::gfx { return true; } - void Renderer::render_job_queue(std::queue &rendering_queue) { + void Renderer::render_job_queue(const float& interpolate_alpha, std::queue &rendering_queue) { while (!rendering_queue.empty()) { // Get the job from the queue, we'll remove it after we render. RenderingJob &job = rendering_queue.front(); - bool res = this->render_job(job); + bool res = this->render_job(interpolate_alpha, job); if (res) { // Now we'll remove the job from the queue. @@ -210,19 +239,19 @@ namespace simpleengine::gfx { } } - void Renderer::render_job_queue(std::map>& rendering_queue) { + void Renderer::render_job_queue(const float& interpolate_alpha, std::map>& rendering_queue) { // Render each job then clear the queue for (const auto& it : rendering_queue) { - this->render_job(it.second); + this->render_job(interpolate_alpha, it.second); } rendering_queue.clear(); } - void Renderer::render() { + void Renderer::render(const float& interpolate_alpha, const float& frame_time) { check_if_initialized(); // Render other (opaque) objects first - render_job_queue(other_render_queue); + render_job_queue(interpolate_alpha, other_render_queue); // Render transparent objects std::map> transparent_jobs; @@ -235,6 +264,6 @@ namespace simpleengine::gfx { transparent_render_queue.pop(); } - render_job_queue(transparent_jobs); + render_job_queue(interpolate_alpha, transparent_jobs); } } // namespace simpleengine::gfx \ No newline at end of file diff --git a/src/scene.cpp b/src/scene.cpp index d5e5540..875acd8 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -16,30 +16,37 @@ namespace simpleengine { } void Scene::update(const float& delta_time) { + // Rotate the model + registry.view().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) { + transform.rotate(rotating.rate * delta_time, rotating.rotation_axis); + }); + } + + void Scene::render(const float& interpolate_alpha, const float& frame_time) { // Is there a way these can be grouped? - registry.view().each([this](const TransformComponent& transform, ModelComponent& model_component) { + registry.view().each([this](TransformComponent& transform, ModelComponent& model_component) { for (auto& mesh : model_component.model.meshes) { auto rendering_type = gfx::RenderingType::RendType_OPAQUE; if (mesh.material) { rendering_type = mesh.material->rendering_type; } - renderer->queue_job(gfx::RenderingJob(rendering_type, mesh, transform.transform_matrix)); + renderer->queue_job(gfx::RenderingJob(rendering_type, mesh, transform.last_transform_matrix, transform.transform_matrix)); + transform.last_transform_matrix = transform.transform_matrix; // Update last transform } }); - registry.view().each([this](const TransformComponent& transform, MeshComponent& mesh_component) { + registry.view().each([this](TransformComponent& transform, MeshComponent& mesh_component) { auto rendering_type = gfx::RenderingType::RendType_OPAQUE; if (mesh_component.mesh.material) { rendering_type = mesh_component.mesh.material->rendering_type; } - renderer->queue_job(gfx::RenderingJob(rendering_type, mesh_component.mesh, transform.transform_matrix)); + renderer->queue_job(gfx::RenderingJob(rendering_type, mesh_component.mesh, transform.last_transform_matrix, transform.transform_matrix)); + transform.last_transform_matrix = transform.transform_matrix; // Update last transform }); - registry.view().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) { - transform.rotate(rotating.rate * delta_time, rotating.rotation_axis); - }); + renderer->render(interpolate_alpha, frame_time); } void Scene::destroy() { From 4a53c24e9c1aa2882c2b2f98d50385283575d150 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sat, 15 Oct 2022 23:39:20 -0400 Subject: [PATCH 2/5] Implement transform interpolation for slower TPS than FPS --- src/gfx/renderer.cpp | 12 +----------- src/scene.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 514ec33..764e07a 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -154,20 +154,10 @@ namespace simpleengine::gfx { bool Renderer::render_job(const float& interpolate_alpha, const RenderingJob &job) { Mesh *mesh = job.rendering_mesh; - /* glm::mat4 transform_mat = job.transform_mat * interpolate_alpha + - job.last_transform_mat * (1.f - interpolate_alpha); */ - - //glm::mat4 transform_mat = lerp(job.transform_mat, job.last_transform_mat, interpolate_alpha); + // Iterpolate between transforms glm::mat4 transform_mat = lerp(job.last_transform_mat, job.transform_mat, interpolate_alpha); - std::cout << "Last transform: " << glm::to_string(job.last_transform_mat) << std::endl << - "Current Transform: " << glm::to_string(job.transform_mat) << std::endl << - "Lerp: " << glm::to_string(transform_mat) << std::endl << std::endl; - - //std::cout << "Current: " << job.transform_mat[3] - shader.set_uniform_matrix_4f("u_transform_matrix", transform_mat); - //shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat); std::optional &material = mesh->material; diff --git a/src/scene.cpp b/src/scene.cpp index 875acd8..20630ff 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -6,6 +6,9 @@ #include "ecs/entity.h" #include "gfx/renderer.h" +#include +#include + namespace simpleengine { Scene::Scene(std::shared_ptr renderer) : renderer(renderer) { @@ -16,6 +19,11 @@ namespace simpleengine { } void Scene::update(const float& delta_time) { + // Update the last transform matrix + registry.view().each([this, &delta_time](TransformComponent& transform) { + transform.last_transform_matrix = transform.transform_matrix; + }); + // Rotate the model registry.view().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) { transform.rotate(rotating.rate * delta_time, rotating.rotation_axis); @@ -32,7 +40,6 @@ namespace simpleengine { } renderer->queue_job(gfx::RenderingJob(rendering_type, mesh, transform.last_transform_matrix, transform.transform_matrix)); - transform.last_transform_matrix = transform.transform_matrix; // Update last transform } }); @@ -43,7 +50,6 @@ namespace simpleengine { } renderer->queue_job(gfx::RenderingJob(rendering_type, mesh_component.mesh, transform.last_transform_matrix, transform.transform_matrix)); - transform.last_transform_matrix = transform.transform_matrix; // Update last transform }); renderer->render(interpolate_alpha, frame_time); From 0a5dc66e4c96c74cd069615f3e5026bb85d93923 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sun, 16 Oct 2022 15:23:35 -0400 Subject: [PATCH 3/5] Create input update loop with varying timestep --- .clang-tidy | 22 ++------------------- examples/dev_testing/src/main.cpp | 10 ++++------ include/simpleengine/camera.h | 21 ++++---------------- include/simpleengine/event/event.h | 16 +++++++++++++++ include/simpleengine/game.h | 2 +- include/simpleengine/scene.h | 6 +++++- src/camera.cpp | 23 +++++++++++----------- src/game.cpp | 12 ++++++++---- src/gfx/renderer.cpp | 31 +++++++++++++++--------------- src/scene.cpp | 6 +++++- 10 files changed, 71 insertions(+), 78 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index adcf3e8..593434a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,6 @@ --- -Checks: "clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,modernize-*,-modernize-use-trailing-return-type" +Checks: "clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,modernize-*,-modernize-use-trailing-return-type, + -*-non-private-member-variables-in-classes,-*-magic-numbers" WarningsAsErrors: true HeaderFilterRegex: "" AnalyzeTemporaryDtors: false @@ -11,8 +12,6 @@ CheckOptions: value: "0" - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors value: "1" - - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic - value: "1" - key: google-readability-braces-around-statements.ShortStatementLines value: "1" - key: google-readability-function-size.StatementThreshold @@ -23,21 +22,4 @@ CheckOptions: value: "2" - key: modernize-loop-convert.MaxCopySize value: "16" - - key: modernize-loop-convert.MinConfidence - value: reasonable - - key: modernize-loop-convert.NamingStyle - value: CamelCase - - key: modernize-pass-by-value.IncludeStyle - value: llvm - - key: modernize-replace-auto-ptr.IncludeStyle - value: llvm - - key: modernize-use-nullptr.NullMacros - value: "NULL" - - key: readability-magic-numbers - value: "0" - - key: cppcoreguidelines-avoid-magic-numbers - value: "0" - - key: cppcoreguidelines-non-private-member-variables-in-classes - value: "0" --- - diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index e87abfe..c53be1e 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -65,7 +65,7 @@ int main(int argc, char *argv[]) { se::gfx::shaders::Core3dShader core_shader; auto camera = std::make_shared(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0)); - game.add_event(camera); + //game.add_event(camera); // Create a renderer auto renderer = std::make_shared(game.get_window(), core_shader, camera); @@ -73,11 +73,11 @@ int main(int argc, char *argv[]) { //game.add_renderable(renderer); // Create a Scene and give it the renderer - auto scene = std::make_shared(renderer); + auto scene = std::make_shared(renderer, camera); //game.add_event(scene); game.add_renderable(scene); - se::ecs::Entity other_e = scene->create_entity(); + /* se::ecs::Entity other_e = scene->create_entity(); other_e.add_component("examples/dev_testing/resources/transparent_window.fbx", se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT); auto &other_transform = other_e.add_component(); @@ -86,13 +86,11 @@ int main(int argc, char *argv[]) { // Create an Entity in the Scene and add components to it. se::ecs::Entity entity = scene->create_entity(); - // entity.add_component("examples/dev_testing/resources/planks/planks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE); - //entity.add_component("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE); entity.add_component("examples/dev_testing/resources/transparent_window.fbx", se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT); auto &transform_comp = entity.add_component(); - transform_comp.translate(4.f, 0.f, 0.f); + transform_comp.translate(4.f, 0.f, 0.f); */ se::ecs::Entity brick_e = scene->create_entity(); brick_e.add_component("examples/dev_testing/resources/bricks/bricks.fbx"); diff --git a/include/simpleengine/camera.h b/include/simpleengine/camera.h index bf7c3a5..e2ffe2d 100644 --- a/include/simpleengine/camera.h +++ b/include/simpleengine/camera.h @@ -5,24 +5,12 @@ #include -#include -#include #include namespace simpleengine { - namespace gfx { - class Renderer; - } - class Camera : public simpleengine::Event { - friend gfx::Renderer; private: GLFWwindow* window; - - glm::vec3 last_position; - glm::vec3 last_rotation; - glm::mat4 last_view_matrix; - glm::vec3 last_camera_front; public: glm::vec3 position; @@ -40,13 +28,12 @@ namespace simpleengine { float movement_speed = 2.5f; Camera(GLFWwindow* window, gfx::Shader shader, float fov = 70, glm::vec3 position = glm::vec3(0.f), glm::vec3 rotation = glm::vec3(0.f), - float near_plane = 0.1f, float far_plane = 1000.f, glm::vec3 world_up = glm::vec3(0.f, 1.f, 0.f), - glm::vec3 cam_front = glm::vec3(0.f, 0.f, -1.f)); + float near_plane = 0.1f, float far_plane = 1000.f); Camera(GLFWwindow* window, GLuint shader_prog, float fov = 70, glm::vec3 position = glm::vec3(0.f), - glm::vec3 rotation = glm::vec3(0.f), float near_plane = 0.1f, float far_plane = 1000.f, glm::vec3 world_up = glm::vec3(0.f, 1.f, 0.f), - glm::vec3 cam_front = glm::vec3(0.f, 0.f, -1.f)); - + glm::vec3 rotation = glm::vec3(0.f), float near_plane = 0.1f, float far_plane = 1000.f); + virtual void update(const float& delta_time) override; + virtual void input_update(const float& delta_time) override; }; } \ No newline at end of file diff --git a/include/simpleengine/event/event.h b/include/simpleengine/event/event.h index 9010083..35d09b7 100644 --- a/include/simpleengine/event/event.h +++ b/include/simpleengine/event/event.h @@ -10,6 +10,22 @@ namespace simpleengine { Event() = default; virtual ~Event() = default; + /** + * @brief The update function with fixed-timestep. + * + * Since this is fixed timestep, this function is primarily for game-logic and physics updates. + * + * @param delta_time + */ virtual void update(const float& delta_time) = 0; + + /** + * @brief The update function with varying-timestep. + * + * Since this has a varying timestep, this function is primarily for input related updates. + * + * @param delta_time + */ + virtual void input_update(const float& delta_time) {} }; } \ No newline at end of file diff --git a/include/simpleengine/game.h b/include/simpleengine/game.h index ce6bd95..0078a61 100644 --- a/include/simpleengine/game.h +++ b/include/simpleengine/game.h @@ -41,7 +41,7 @@ namespace simpleengine { void set_enable_vsync(const bool& enabled); void update(const float& delta_time); - void handle_input(const float& delta_time); + void input_update(const float& delta_time); void render_window(const float& interpolate_alpha, const float& delta_time); void render_items(const float& interpolate_alpha, const float& delta_time); void exit(); diff --git a/include/simpleengine/scene.h b/include/simpleengine/scene.h index bda0945..56820dd 100644 --- a/include/simpleengine/scene.h +++ b/include/simpleengine/scene.h @@ -1,5 +1,6 @@ #pragma once +#include "camera.h" #include "entt/entity/fwd.hpp" #include "gfx/mesh.h" #include "event/event.h" @@ -27,12 +28,15 @@ namespace simpleengine { // Last transform matrixes for all entities. std::unordered_map last_transforms; + + std::shared_ptr camera; public: - Scene(std::shared_ptr renderer); + Scene(std::shared_ptr renderer, std::shared_ptr camera); ecs::Entity create_entity(); virtual void update(const float& delta_time) override; + virtual void input_update(const float& delta_time) override; virtual void render(const float& interpolate_alpha, const float& frame_time) override; virtual void destroy() override; diff --git a/src/camera.cpp b/src/camera.cpp index 5f07904..d4572bf 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -1,29 +1,34 @@ #include "camera.h" #include +#include #include +#include +#include #include namespace simpleengine { Camera::Camera(GLFWwindow* window, gfx::Shader shader, float fov, glm::vec3 position, glm::vec3 rotation, - float near_plane, float far_plane, glm::vec3 world_up, glm::vec3 cam_front) : window(window), shader(shader), - projection_matrix(1.f), view_matrix(1.f), fov(fov), position(position), rotation(rotation), near_plane(near_plane), far_plane(far_plane) { + float near_plane, float far_plane) : window(window), shader(shader), + projection_matrix(1.f), fov(fov), position(position), rotation(rotation), near_plane(near_plane), far_plane(far_plane) { // TODO: Update width and height on window resize. int width, height; glfwGetFramebufferSize(window, &width, &height); projection_matrix = glm::perspective(glm::radians(fov), ((float) width) / height, near_plane, far_plane); - - //rotation = glm::vec3(0.f, 0.f, -1.f); } Camera::Camera(GLFWwindow* window, GLuint shader_prog, float fov, glm::vec3 position, glm::vec3 rotation, - float near_plane, float far_plane, glm::vec3 world_up, glm::vec3 cam_front) : Camera(window, gfx::Shader(shader_prog), fov, position, - rotation, near_plane, far_plane, world_up, cam_front) { + float near_plane, float far_plane) : Camera(window, gfx::Shader(shader_prog), fov, position, + rotation, near_plane, far_plane) { } void Camera::update(const float& delta_time) { + + } + + void Camera::input_update(const float& delta_time) { if (glfwGetKey(window, GLFW_KEY_MINUS) == GLFW_PRESS) { movement_speed -= abs(movement_speed - .2f); } @@ -94,11 +99,5 @@ namespace simpleengine { camera_front = glm::normalize(direction); view_matrix = glm::lookAt(position, position + camera_front, camera_up); - - shader.use(); - shader.set_uniform_float_vec3("u_view_pos", position); - shader.set_uniform_matrix_4f("u_view_matrix", view_matrix); - shader.set_uniform_matrix_4f("u_projection_matrix", projection_matrix); - shader.unuse(); } } \ No newline at end of file diff --git a/src/game.cpp b/src/game.cpp index f158503..22a6573 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -107,13 +107,15 @@ void simpleengine::Game::update_enabled_vsync() const { } } -void simpleengine::Game::handle_input(const float& delta_time) { +void simpleengine::Game::input_update(const float& delta_time) { // TODO + + for (const std::shared_ptr& event : events) { + event->input_update(delta_time); + } } void simpleengine::Game::update(const float& delta_time) { - handle_input(delta_time); - // Update items for (const std::shared_ptr& event : events) { event->update(delta_time); @@ -162,10 +164,12 @@ int simpleengine::Game::run() { // Poll input events glfwPollEvents(); - const double max_delta_time = 0.5; + const double max_delta_time = 0.25; tps_accumulator += delta_time; + input_update(delta_time); + while (tps_accumulator >= max_delta_time) { update(max_delta_time); diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 764e07a..9ab6c81 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -14,6 +14,7 @@ #include #include +#include namespace simpleengine::gfx { void create_mesh_buffers(simpleengine::gfx::Mesh &mesh); @@ -47,9 +48,7 @@ namespace simpleengine::gfx { } void Renderer::sort_jobs() { - // Sort transparents - - // std::sort() + } void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 last_position, glm::mat4 position) { @@ -63,8 +62,6 @@ namespace simpleengine::gfx { switch (job.rendering_type) { case RenderingType::RendType_TRANSPARENT: { - /* glm::vec3 pos = job.transform_mat[3]; - float distance = glm::distance(pos, camera->position); */ this->transparent_render_queue.emplace(job); break; } @@ -131,24 +128,21 @@ namespace simpleengine::gfx { std::cout << "Destroying renderer..." << std::endl; shader.delete_program(); - - /* for (auto& [handle, rendering] : rendering_models) { - rendering.destroy_buffers(); - } */ } - glm::mat4 lerp(glm::mat4 a, glm::mat4 b, float alpha) { + glm::mat4 lerp(glm::mat4 to, glm::mat4 from, float alpha) { //return a * (1.f - alpha) + b * alpha; - glm::quat rot0 = glm::quat_cast(a); - glm::quat rot1= glm::quat_cast(b); + glm::quat rot0 = glm::quat_cast(to); + glm::quat rot1 = glm::quat_cast(from); - glm::quat finalRot = glm::slerp(rot0, rot1, alpha); + glm::quat final_rot = glm::slerp(rot0, rot1, alpha); - glm::mat4 finalMat = glm::mat4_cast(finalRot); + glm::mat4 final_mat = glm::mat4_cast(final_rot); - finalMat[3] = a[3] * (1 - alpha) + b[3] * alpha; + // Interpolate position + final_mat[3] = glm::mix(to[3], from[3], alpha); - return finalMat; + return final_mat; } bool Renderer::render_job(const float& interpolate_alpha, const RenderingJob &job) { @@ -240,6 +234,11 @@ namespace simpleengine::gfx { void Renderer::render(const float& interpolate_alpha, const float& frame_time) { check_if_initialized(); + // Set camera related uniforms + shader.set_uniform_float_vec3("u_view_pos", camera->position); + shader.set_uniform_matrix_4f("u_view_matrix", camera->view_matrix); + shader.set_uniform_matrix_4f("u_projection_matrix", camera->projection_matrix); + // Render other (opaque) objects first render_job_queue(interpolate_alpha, other_render_queue); diff --git a/src/scene.cpp b/src/scene.cpp index 20630ff..2ecb694 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -10,7 +10,7 @@ #include namespace simpleengine { - Scene::Scene(std::shared_ptr renderer) : renderer(renderer) { + Scene::Scene(std::shared_ptr renderer, std::shared_ptr camera) : renderer(renderer), camera(camera) { } @@ -18,6 +18,10 @@ namespace simpleengine { return ecs::Entity(registry, registry.create()); } + void Scene::input_update(const float& delta_time) { + camera->input_update(delta_time); // Update camera input + } + void Scene::update(const float& delta_time) { // Update the last transform matrix registry.view().each([this, &delta_time](TransformComponent& transform) { From 1e7e9a4f9eb42588f1bd00c31b33a030f210b0dd Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sun, 16 Oct 2022 15:42:19 -0400 Subject: [PATCH 4/5] Increase default TPS --- examples/dev_testing/src/main.cpp | 3 ++- include/simpleengine/game.h | 7 +++---- src/game.cpp | 26 ++++++++++++-------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index c53be1e..8ab98d6 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -96,7 +96,8 @@ int main(int argc, char *argv[]) { brick_e.add_component("examples/dev_testing/resources/bricks/bricks.fbx"); brick_e.add_component(); auto &brick_transf = brick_e.add_component(); - brick_transf.translate(6.f, -0.5f, 1.f); + brick_transf.translate(6.f, 0.f, 0.f); + //brick_transf.translate(6.f, -0.5f, 1.f); auto light = std::make_shared(core_shader, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f)); game.add_event(light); diff --git a/include/simpleengine/game.h b/include/simpleengine/game.h index 0078a61..e3bcd55 100644 --- a/include/simpleengine/game.h +++ b/include/simpleengine/game.h @@ -66,10 +66,9 @@ namespace simpleengine { int fps_limit = -1; bool enable_vsync = true; - int max_engine_tps = 60; // The maximum engine TPS - double tps_accumulator = 0.f; - //int engine_ticks_second = 0; // The amount of ticks in a second - //double last_sec_engine_tick; // The time of the last second + int max_engine_tps = 120; // The maximum engine TPS + float fixed_delta_time = 1.f / (float) max_engine_tps; // The delta time from fixed timestep + float tps_accumulator = 0.f; float get_delta_time(); diff --git a/src/game.cpp b/src/game.cpp index 22a6573..bab41da 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -158,33 +158,31 @@ void simpleengine::Game::limit_framerate(const float& delta_time) const { int simpleengine::Game::run() { while (!glfwWindowShouldClose(window)) { // Get delta time first thing - float delta_time = get_delta_time(); - //std::cout << "Delta time: " << delta_time << std::endl; + float frame_time = get_delta_time(); // Poll input events glfwPollEvents(); + input_update(frame_time); // Update input on varying timestep - const double max_delta_time = 0.25; + tps_accumulator += frame_time; - tps_accumulator += delta_time; + // https://gafferongames.com/post/fix_your_timestep/ + while (tps_accumulator >= fixed_delta_time) { + update(fixed_delta_time); - input_update(delta_time); - - while (tps_accumulator >= max_delta_time) { - update(max_delta_time); - - tps_accumulator -= max_delta_time; + tps_accumulator -= fixed_delta_time; } - - const double interpolate_alpha = tps_accumulator / max_delta_time; - render_window(interpolate_alpha, delta_time); + // Alpha used for interpolating objects in rendering + float interpolate_alpha = tps_accumulator / fixed_delta_time; + + render_window(interpolate_alpha, frame_time); // End draw glfwSwapBuffers(window); glFlush(); - limit_framerate(delta_time); + limit_framerate(frame_time); } return 0; From ca546621f1d8a68ec3b3fbad77f2624e7969422e Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Tue, 18 Oct 2022 16:36:34 -0400 Subject: [PATCH 5/5] Move OpenGL stuff out of Game class and into the Renderer class --- examples/dev_testing/src/main.cpp | 72 +++++++++++++++++++++++------ include/simpleengine/game.h | 4 +- include/simpleengine/gfx/renderer.h | 1 + src/game.cpp | 18 ++------ src/gfx/renderer.cpp | 11 +++-- 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index 8ab98d6..7cdc2ba 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -9,6 +9,7 @@ #include "simpleengine/gfx/renderer.h" #include "simpleengine/gfx/texture.h" #include "simpleengine/vector.h" +#include #include #include #include @@ -33,27 +34,67 @@ namespace se = simpleengine; -class FPSCounterEvent : public se::Event { +class FPSCounterEvent : public se::Renderable { public: - double last_frame_time; - int frame_count; + double last_frame_time_input; + int frame_count_input; - FPSCounterEvent() : se::Event() { - this->last_frame_time = glfwGetTime(); - frame_count = 0; + double last_frame_time_tps; + int frame_count_tps; + + double last_frame_time_render; + int frame_count_render; + + FPSCounterEvent() : se::Renderable() { + last_frame_time_input = glfwGetTime(); + frame_count_input = 0; + + last_frame_time_tps = glfwGetTime(); + frame_count_tps = 0; + + last_frame_time_render = glfwGetTime(); + frame_count_render = 0; } virtual void update(const float &delta_time) { double current_time = glfwGetTime(); - frame_count++; + frame_count_tps++; // Check if the last print was 1 second ago. - if (current_time - last_frame_time >= 1.0) { - double ms_per_frame = 1000 / (double)frame_count; + if (current_time - last_frame_time_tps >= 1.0) { + double ms_per_frame = 1000 / (double)frame_count_tps; - printf("%d fps, %f ms/frame\n", frame_count, ms_per_frame); - frame_count = 0; - last_frame_time += 1.0; + printf("Fixed update: %d tps, %f ms/frame\n", frame_count_tps, ms_per_frame); + frame_count_tps = 0; + last_frame_time_tps += 1.0; + } + } + + virtual void input_update(const float &delta_time) { + double current_time = glfwGetTime(); + frame_count_input++; + + // Check if the last print was 1 second ago. + if (current_time - last_frame_time_input >= 1.0) { + double ms_per_frame = 1000 / (double)frame_count_input; + + printf("Input: %d tps, %f ms/frame\n", frame_count_input, ms_per_frame); + frame_count_input = 0; + last_frame_time_input += 1.0; + } + } + + virtual void render(const float& interpolate_alpha, const float& frame_time) { + double current_time = glfwGetTime(); + frame_count_render++; + + // Check if the last print was 1 second ago. + if (current_time - last_frame_time_render >= 1.0) { + double ms_per_frame = 1000 / (double)frame_count_render; + + printf("Render: %d fps, %f ms/frame\n\n", frame_count_render, ms_per_frame); + frame_count_render = 0; + last_frame_time_render += 1.0; } } }; @@ -103,11 +144,12 @@ int main(int argc, char *argv[]) { game.add_event(light); auto fps_counter = std::make_shared(); - game.add_event(fps_counter); + game.add_renderable(fps_counter); - game.set_enable_vsync(true); - // game.set_fps_limit(120); + /* game.set_enable_vsync(false); + game.set_fps_limit(100); */ int res = game.run(); + std::cout << "Engine result: " << res << std::endl; renderer->destroy(); diff --git a/include/simpleengine/game.h b/include/simpleengine/game.h index e3bcd55..3c8803d 100644 --- a/include/simpleengine/game.h +++ b/include/simpleengine/game.h @@ -32,9 +32,6 @@ namespace simpleengine { const int& minor_version = 4, const bool& resizeable = false, const int& forward_compat = GL_TRUE); virtual ~Game(); - void enable_default_gl_options() const; - void enable_gl_option(GLenum option) const; - void add_event(std::shared_ptr event); void add_renderable(std::shared_ptr renderable_event); void set_fps_limit(const int& fps_limit); @@ -66,6 +63,7 @@ namespace simpleengine { int fps_limit = -1; bool enable_vsync = true; + // Engine TPS related stuff int max_engine_tps = 120; // The maximum engine TPS float fixed_delta_time = 1.f / (float) max_engine_tps; // The delta time from fixed timestep float tps_accumulator = 0.f; diff --git a/include/simpleengine/gfx/renderer.h b/include/simpleengine/gfx/renderer.h index 8536602..436c95d 100644 --- a/include/simpleengine/gfx/renderer.h +++ b/include/simpleengine/gfx/renderer.h @@ -42,6 +42,7 @@ namespace simpleengine::gfx { Renderer(GLFWwindow* window, GLuint shader_program, std::shared_ptr camera); void enable_debug(); + void enable_gl_option(GLenum option) const; virtual void sort_jobs(); virtual void queue_job(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 last_position, glm::mat4 position); diff --git a/src/game.cpp b/src/game.cpp index bab41da..b5e6e12 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10,11 +10,9 @@ #ifdef __linux__ #include #include -#include #else #include #include -#include #endif simpleengine::Game::Game(int w, int h, const std::string& window_name, const int& gl_profile, const int& major_version, @@ -44,22 +42,11 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name, const int glfwTerminate(); } - enable_default_gl_options(); + update_enabled_vsync(); last_frame_time = std::chrono::high_resolution_clock::now(); } -void simpleengine::Game::enable_default_gl_options() const { - - //glFrontFace(GL_CW); - - update_enabled_vsync(); -} - -void simpleengine::Game::enable_gl_option(GLenum option) const { - glEnable(option); -} - void simpleengine::Game::initialize(const int& gl_profile, const int& major_version, const int& minor_version, const bool& resizeable, const int& forward_compat) { glfwInit(); @@ -162,7 +149,8 @@ int simpleengine::Game::run() { // Poll input events glfwPollEvents(); - input_update(frame_time); // Update input on varying timestep + + input_update(frame_time); tps_accumulator += frame_time; diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 9ab6c81..eb3ad47 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -47,6 +47,10 @@ namespace simpleengine::gfx { glDebugMessageCallback(debug_message_callback, 0); } + void Renderer::enable_gl_option(GLenum option) const { + glEnable(option); + } + void Renderer::sort_jobs() { } @@ -112,9 +116,10 @@ namespace simpleengine::gfx { } void Renderer::initialize() { - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glEnable(GL_CULL_FACE); + enable_gl_option(GL_DEPTH_TEST); + enable_gl_option(GL_BLEND); + enable_gl_option(GL_CULL_FACE); + glCullFace(GL_BACK); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);