diff --git a/.clang-tidy b/.clang-tidy index b3fa1d3..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,17 +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" --- - diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index ca77c59..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; } } }; @@ -65,18 +106,19 @@ 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); 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); + 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(); @@ -85,28 +127,29 @@ 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"); + 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); 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/camera.h b/include/simpleengine/camera.h index 3a5f012..e2ffe2d 100644 --- a/include/simpleengine/camera.h +++ b/include/simpleengine/camera.h @@ -5,8 +5,6 @@ #include -#include -#include #include namespace simpleengine { @@ -14,6 +12,7 @@ namespace simpleengine { private: GLFWwindow* window; public: + glm::vec3 position; glm::vec3 rotation; gfx::Shader shader; @@ -29,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/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/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 2f1ad17..3c8803d 100644 --- a/include/simpleengine/game.h +++ b/include/simpleengine/game.h @@ -32,18 +32,15 @@ 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); void set_enable_vsync(const bool& enabled); 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 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(); int run(); @@ -63,8 +60,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; + + // 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; 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..436c95d 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 { @@ -41,9 +42,10 @@ 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 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 +54,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 +63,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..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" @@ -9,6 +10,7 @@ #include #include +#include #include #include @@ -18,16 +20,24 @@ 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; + + 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/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/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 dc7d5ac..b5e6e12 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10,16 +10,14 @@ #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, 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 @@ -44,18 +42,9 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name, const int glfwTerminate(); } - enable_default_gl_options(); -} - -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); + last_frame_time = std::chrono::high_resolution_clock::now(); } void simpleengine::Game::initialize(const int& gl_profile, const int& major_version, const int& minor_version, @@ -105,28 +94,30 @@ void simpleengine::Game::update_enabled_vsync() const { } } -void simpleengine::Game::update(const float& delta_time) { - handle_input(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) { // Update items for (const std::shared_ptr& event : events) { event->update(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); } } @@ -154,19 +145,32 @@ 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(); + float frame_time = get_delta_time(); // Poll input events glfwPollEvents(); + + input_update(frame_time); - update(delta_time); - render_window(delta_time); + tps_accumulator += frame_time; + + // https://gafferongames.com/post/fix_your_timestep/ + while (tps_accumulator >= fixed_delta_time) { + update(fixed_delta_time); + + tps_accumulator -= fixed_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; diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 47d099d..eb3ad47 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -13,11 +13,14 @@ #include #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)) */ {} @@ -44,14 +47,16 @@ namespace simpleengine::gfx { glDebugMessageCallback(debug_message_callback, 0); } - void Renderer::sort_jobs() { - // Sort transparents - - // std::sort() + void Renderer::enable_gl_option(GLenum option) const { + glEnable(option); } - void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) { - RenderingJob job(rendering_type, mesh, position); + void Renderer::sort_jobs() { + + } + + 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); } @@ -61,8 +66,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; } @@ -113,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); @@ -129,16 +133,30 @@ namespace simpleengine::gfx { std::cout << "Destroying renderer..." << std::endl; shader.delete_program(); - - /* for (auto& [handle, rendering] : rendering_models) { - rendering.destroy_buffers(); - } */ } - bool Renderer::render_job(const RenderingJob &job) { + glm::mat4 lerp(glm::mat4 to, glm::mat4 from, float alpha) { + //return a * (1.f - alpha) + b * alpha; + glm::quat rot0 = glm::quat_cast(to); + glm::quat rot1 = glm::quat_cast(from); + + glm::quat final_rot = glm::slerp(rot0, rot1, alpha); + + glm::mat4 final_mat = glm::mat4_cast(final_rot); + + // Interpolate position + final_mat[3] = glm::mix(to[3], from[3], alpha); + + return final_mat; + } + + 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); + // Iterpolate between transforms + glm::mat4 transform_mat = lerp(job.last_transform_mat, job.transform_mat, interpolate_alpha); + + shader.set_uniform_matrix_4f("u_transform_matrix", transform_mat); std::optional &material = mesh->material; @@ -196,12 +214,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 +228,24 @@ 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(); + // 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(other_render_queue); + render_job_queue(interpolate_alpha, other_render_queue); // Render transparent objects std::map> transparent_jobs; @@ -235,6 +258,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..2ecb694 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -6,8 +6,11 @@ #include "ecs/entity.h" #include "gfx/renderer.h" +#include +#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) { } @@ -15,31 +18,45 @@ 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) { + 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); + }); + } + + 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)); } }); - 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)); }); - 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() {