Merge pull request #6 from SeanOMik/feature/fixed-timestep

Implement fixed timestep
This commit is contained in:
SeanOMik 2022-10-23 12:12:06 -04:00 committed by GitHub
commit 8493e2aa86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 246 additions and 141 deletions

View File

@ -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 WarningsAsErrors: true
HeaderFilterRegex: "" HeaderFilterRegex: ""
AnalyzeTemporaryDtors: false AnalyzeTemporaryDtors: false
@ -11,8 +12,6 @@ CheckOptions:
value: "0" value: "0"
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
value: "1" value: "1"
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: "1"
- key: google-readability-braces-around-statements.ShortStatementLines - key: google-readability-braces-around-statements.ShortStatementLines
value: "1" value: "1"
- key: google-readability-function-size.StatementThreshold - key: google-readability-function-size.StatementThreshold
@ -23,17 +22,4 @@ CheckOptions:
value: "2" value: "2"
- key: modernize-loop-convert.MaxCopySize - key: modernize-loop-convert.MaxCopySize
value: "16" 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"
--- ---

View File

@ -9,6 +9,7 @@
#include "simpleengine/gfx/renderer.h" #include "simpleengine/gfx/renderer.h"
#include "simpleengine/gfx/texture.h" #include "simpleengine/gfx/texture.h"
#include "simpleengine/vector.h" #include "simpleengine/vector.h"
#include <GLFW/glfw3.h>
#include <simpleengine/ecs/component/model_component.h> #include <simpleengine/ecs/component/model_component.h>
#include <simpleengine/ecs/component/rotating_component.h> #include <simpleengine/ecs/component/rotating_component.h>
#include <simpleengine/event/event.h> #include <simpleengine/event/event.h>
@ -33,27 +34,67 @@
namespace se = simpleengine; namespace se = simpleengine;
class FPSCounterEvent : public se::Event { class FPSCounterEvent : public se::Renderable {
public: public:
double last_frame_time; double last_frame_time_input;
int frame_count; int frame_count_input;
FPSCounterEvent() : se::Event() { double last_frame_time_tps;
this->last_frame_time = glfwGetTime(); int frame_count_tps;
frame_count = 0;
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) { virtual void update(const float &delta_time) {
double current_time = glfwGetTime(); double current_time = glfwGetTime();
frame_count++; frame_count_tps++;
// Check if the last print was 1 second ago. // Check if the last print was 1 second ago.
if (current_time - last_frame_time >= 1.0) { if (current_time - last_frame_time_tps >= 1.0) {
double ms_per_frame = 1000 / (double)frame_count; double ms_per_frame = 1000 / (double)frame_count_tps;
printf("%d fps, %f ms/frame\n", frame_count, ms_per_frame); printf("Fixed update: %d tps, %f ms/frame\n", frame_count_tps, ms_per_frame);
frame_count = 0; frame_count_tps = 0;
last_frame_time += 1.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; se::gfx::shaders::Core3dShader core_shader;
auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0)); auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0));
game.add_event(camera); //game.add_event(camera);
// Create a renderer // Create a renderer
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader, camera); auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader, camera);
renderer->initialize(); renderer->initialize();
game.add_renderable(renderer); //game.add_renderable(renderer);
// Create a Scene and give it the renderer // Create a Scene and give it the renderer
auto scene = std::make_shared<se::Scene>(renderer); auto scene = std::make_shared<se::Scene>(renderer, camera);
game.add_event(scene); //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<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx", other_e.add_component<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx",
se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT); se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT);
auto &other_transform = other_e.add_component<se::TransformComponent>(); auto &other_transform = other_e.add_component<se::TransformComponent>();
@ -85,28 +127,29 @@ int main(int argc, char *argv[]) {
// Create an Entity in the Scene and add components to it. // Create an Entity in the Scene and add components to it.
se::ecs::Entity entity = scene->create_entity(); se::ecs::Entity entity = scene->create_entity();
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/planks/planks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
entity.add_component<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx", entity.add_component<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx",
se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT); se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT);
auto &transform_comp = entity.add_component<se::TransformComponent>(); auto &transform_comp = entity.add_component<se::TransformComponent>();
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(); se::ecs::Entity brick_e = scene->create_entity();
brick_e.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx"); brick_e.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx");
brick_e.add_component<se::RotatingComponent>();
auto &brick_transf = brick_e.add_component<se::TransformComponent>(); auto &brick_transf = brick_e.add_component<se::TransformComponent>();
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<se::gfx::Light>(core_shader, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f)); auto light = std::make_shared<se::gfx::Light>(core_shader, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f));
game.add_event(light); game.add_event(light);
auto fps_counter = std::make_shared<FPSCounterEvent>(); auto fps_counter = std::make_shared<FPSCounterEvent>();
game.add_event(fps_counter); game.add_renderable(fps_counter);
game.set_enable_vsync(true); /* game.set_enable_vsync(false);
// game.set_fps_limit(120); game.set_fps_limit(100); */
int res = game.run(); int res = game.run();
std::cout << "Engine result: " << res << std::endl; std::cout << "Engine result: " << res << std::endl;
renderer->destroy(); renderer->destroy();

View File

@ -5,8 +5,6 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/glm.hpp> #include <glm/glm.hpp>
namespace simpleengine { namespace simpleengine {
@ -14,6 +12,7 @@ namespace simpleengine {
private: private:
GLFWwindow* window; GLFWwindow* window;
public: public:
glm::vec3 position; glm::vec3 position;
glm::vec3 rotation; glm::vec3 rotation;
gfx::Shader shader; gfx::Shader shader;
@ -29,13 +28,12 @@ namespace simpleengine {
float movement_speed = 2.5f; 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), 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), float near_plane = 0.1f, float far_plane = 1000.f);
glm::vec3 cam_front = glm::vec3(0.f, 0.f, -1.f));
Camera(GLFWwindow* window, GLuint shader_prog, float fov = 70, glm::vec3 position = glm::vec3(0.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 rotation = glm::vec3(0.f), float near_plane = 0.1f, float far_plane = 1000.f);
glm::vec3 cam_front = glm::vec3(0.f, 0.f, -1.f));
virtual void update(const float& delta_time) override; virtual void update(const float& delta_time) override;
virtual void input_update(const float& delta_time) override;
}; };
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
//#include "simpleengine/scene.h"
#include <glm/ext/matrix_transform.hpp> #include <glm/ext/matrix_transform.hpp>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@ -9,14 +10,18 @@ namespace simpleengine {
* *
*/ */
class TransformComponent { 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: public:
glm::mat4 transform_matrix; 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) {
} }

View File

@ -10,6 +10,22 @@ namespace simpleengine {
Event() = default; Event() = default;
virtual ~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; 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) {}
}; };
} }

View File

@ -32,18 +32,15 @@ namespace simpleengine {
const int& minor_version = 4, const bool& resizeable = false, const int& forward_compat = GL_TRUE); const int& minor_version = 4, const bool& resizeable = false, const int& forward_compat = GL_TRUE);
virtual ~Game(); virtual ~Game();
void enable_default_gl_options() const;
void enable_gl_option(GLenum option) const;
void add_event(std::shared_ptr<simpleengine::Event> event); void add_event(std::shared_ptr<simpleengine::Event> event);
void add_renderable(std::shared_ptr<simpleengine::Renderable> renderable_event); void add_renderable(std::shared_ptr<simpleengine::Renderable> renderable_event);
void set_fps_limit(const int& fps_limit); void set_fps_limit(const int& fps_limit);
void set_enable_vsync(const bool& enabled); void set_enable_vsync(const bool& enabled);
void update(const float& delta_time); 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& delta_time); void render_window(const float& interpolate_alpha, const float& delta_time);
void render_items(const float& delta_time); void render_items(const float& interpolate_alpha, const float& delta_time);
void exit(); void exit();
int run(); int run();
@ -63,8 +60,13 @@ namespace simpleengine {
// FPS related stuff // FPS related stuff
void update_enabled_vsync() const; 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`. 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; int fps_limit = -1;
bool enable_vsync; 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(); float get_delta_time();

View File

@ -23,7 +23,7 @@ namespace simpleengine::gfx {
shader.unuse(); shader.unuse();
} }
virtual void render() override { virtual void render(const float& interpolate_alpha, const float& frame_time) override {
} }
}; };

View File

@ -17,9 +17,10 @@ namespace simpleengine::gfx {
public: public:
RenderingType rendering_type; RenderingType rendering_type;
gfx::Mesh* rendering_mesh; gfx::Mesh* rendering_mesh;
glm::mat4 last_transform_mat;
glm::mat4 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 { class Renderer : public simpleengine::Renderable {
@ -41,9 +42,10 @@ namespace simpleengine::gfx {
Renderer(GLFWwindow* window, GLuint shader_program, std::shared_ptr<Camera> camera); Renderer(GLFWwindow* window, GLuint shader_program, std::shared_ptr<Camera> camera);
void enable_debug(); void enable_debug();
void enable_gl_option(GLenum option) const;
virtual void sort_jobs(); 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 queue_job(RenderingJob job);
virtual void create_job_buffers(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 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. * @brief Renders a single job.
@ -61,8 +63,8 @@ namespace simpleengine::gfx {
* @return true if the job was rendered successfully. * @return true if the job was rendered successfully.
* @return false if there was an error when trying to render the job. * @return false if there was an error when trying to render the job.
*/ */
virtual bool render_job(const RenderingJob& job); virtual bool render_job(const float& interpolate_alpha, const RenderingJob& job);
virtual void render_job_queue(std::queue<RenderingJob>& queue); virtual void render_job_queue(const float& interpolate_alpha, std::queue<RenderingJob>& queue);
virtual void render_job_queue(std::map<float, RenderingJob, std::greater<>>& queue); virtual void render_job_queue(const float& interpolate_alpha, std::map<float, RenderingJob, std::greater<>>& queue);
}; };
} }

View File

@ -14,6 +14,6 @@ namespace simpleengine {
Renderable() = default; Renderable() = default;
virtual ~Renderable() = default; virtual ~Renderable() = default;
virtual void render() = 0; virtual void render(const float& interpolate_alpha, const float& frame_time) = 0;
}; };
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "camera.h"
#include "entt/entity/fwd.hpp" #include "entt/entity/fwd.hpp"
#include "gfx/mesh.h" #include "gfx/mesh.h"
#include "event/event.h" #include "event/event.h"
@ -9,6 +10,7 @@
#include <memory> #include <memory>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <unordered_map>
#include <vector> #include <vector>
#include <entt/entt.hpp> #include <entt/entt.hpp>
@ -18,16 +20,24 @@ namespace simpleengine {
class Entity; class Entity;
} }
class Scene : public simpleengine::Event { //class Scene : public simpleengine::Event {
class Scene : public simpleengine::Renderable {
protected: protected:
entt::registry registry; entt::registry registry;
std::shared_ptr<gfx::Renderer> renderer; std::shared_ptr<gfx::Renderer> renderer;
// Last transform matrixes for all entities.
std::unordered_map<uint32_t, glm::mat4> last_transforms;
std::shared_ptr<Camera> camera;
public: public:
Scene(std::shared_ptr<gfx::Renderer> renderer); Scene(std::shared_ptr<gfx::Renderer> renderer, std::shared_ptr<Camera> camera);
ecs::Entity create_entity(); ecs::Entity create_entity();
virtual void update(const float& delta_time) override; 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; virtual void destroy() override;
}; };

View File

@ -26,7 +26,7 @@ struct Material {
bool has_specular_map; bool has_specular_map;
sampler2D specular_map; sampler2D specular_map;
bool has_normal_map; bool has_normal_map;
sampler2D normal_map; sampler2D normal_map;

View File

@ -1,29 +1,34 @@
#include "camera.h" #include "camera.h"
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/ext/quaternion_common.hpp>
#include <glm/ext/quaternion_geometric.hpp> #include <glm/ext/quaternion_geometric.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/trigonometric.hpp> #include <glm/trigonometric.hpp>
namespace simpleengine { namespace simpleengine {
Camera::Camera(GLFWwindow* window, gfx::Shader shader, float fov, glm::vec3 position, glm::vec3 rotation, 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), float near_plane, float far_plane) : 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) { 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. // TODO: Update width and height on window resize.
int width, height; int width, height;
glfwGetFramebufferSize(window, &width, &height); glfwGetFramebufferSize(window, &width, &height);
projection_matrix = glm::perspective(glm::radians(fov), ((float) width) / height, near_plane, far_plane); 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, 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, float near_plane, float far_plane) : Camera(window, gfx::Shader(shader_prog), fov, position,
rotation, near_plane, far_plane, world_up, cam_front) { rotation, near_plane, far_plane) {
} }
void Camera::update(const float& delta_time) { void Camera::update(const float& delta_time) {
}
void Camera::input_update(const float& delta_time) {
if (glfwGetKey(window, GLFW_KEY_MINUS) == GLFW_PRESS) { if (glfwGetKey(window, GLFW_KEY_MINUS) == GLFW_PRESS) {
movement_speed -= abs(movement_speed - .2f); movement_speed -= abs(movement_speed - .2f);
} }
@ -94,11 +99,5 @@ namespace simpleengine {
camera_front = glm::normalize(direction); camera_front = glm::normalize(direction);
view_matrix = glm::lookAt(position, position + camera_front, camera_up); 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();
} }
} }

View File

@ -10,16 +10,14 @@
#ifdef __linux__ #ifdef __linux__
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <GL/gl.h>
#else #else
#include <gl/glew.h> #include <gl/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <gl/gl.h>
#endif #endif
simpleengine::Game::Game(int w, int h, const std::string& window_name, const int& gl_profile, const int& major_version, 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), 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); initialize(gl_profile, major_version, minor_version, window_resizeable, forward_compat);
// Create a window // Create a window
@ -44,18 +42,9 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name, const int
glfwTerminate(); glfwTerminate();
} }
enable_default_gl_options();
}
void simpleengine::Game::enable_default_gl_options() const {
//glFrontFace(GL_CW);
update_enabled_vsync(); update_enabled_vsync();
}
void simpleengine::Game::enable_gl_option(GLenum option) const { last_frame_time = std::chrono::high_resolution_clock::now();
glEnable(option);
} }
void simpleengine::Game::initialize(const int& gl_profile, const int& major_version, const int& minor_version, 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) { void simpleengine::Game::input_update(const float& delta_time) {
handle_input(delta_time); // TODO
for (const std::shared_ptr<Event>& event : events) {
event->input_update(delta_time);
}
}
void simpleengine::Game::update(const float& delta_time) {
// Update items // Update items
for (const std::shared_ptr<Event>& event : events) { for (const std::shared_ptr<Event>& event : events) {
event->update(delta_time); event->update(delta_time);
} }
} }
void simpleengine::Game::handle_input(const float& delta_time) { void simpleengine::Game::render_window(const float& interpolate_alpha, const float& delta_time) {
// TODO
}
void simpleengine::Game::render_window(const float& delta_time) {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 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 : renderable_events) { for (const std::shared_ptr<Renderable>& 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() { int simpleengine::Game::run() {
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
// Get delta time first thing // Get delta time first thing
float delta_time = get_delta_time(); float frame_time = get_delta_time();
// Poll input events // Poll input events
glfwPollEvents(); glfwPollEvents();
input_update(frame_time);
update(delta_time); tps_accumulator += frame_time;
render_window(delta_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 // End draw
glfwSwapBuffers(window); glfwSwapBuffers(window);
glFlush(); glFlush();
limit_framerate(delta_time); limit_framerate(frame_time);
} }
return 0; return 0;

View File

@ -13,11 +13,14 @@
#include <glm/geometric.hpp> #include <glm/geometric.hpp>
#include <stdexcept> #include <stdexcept>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtx/matrix_interpolation.hpp>
namespace simpleengine::gfx { namespace simpleengine::gfx {
void create_mesh_buffers(simpleengine::gfx::Mesh &mesh); void create_mesh_buffers(simpleengine::gfx::Mesh &mesh);
RenderingJob::RenderingJob(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) RenderingJob::RenderingJob(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 last_pos, glm::mat4 position)
: rendering_type(rendering_type), rendering_mesh(&mesh), transform_mat(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> camera) Renderer::Renderer(GLFWwindow *window, gfx::Shader shader, std::shared_ptr<Camera> camera)
: window(window), shader(shader), camera(camera)/* , transparent_render_queue(CameraDistanceComparator(camera)) */ {} : window(window), shader(shader), camera(camera)/* , transparent_render_queue(CameraDistanceComparator(camera)) */ {}
@ -44,14 +47,16 @@ namespace simpleengine::gfx {
glDebugMessageCallback(debug_message_callback, 0); glDebugMessageCallback(debug_message_callback, 0);
} }
void Renderer::sort_jobs() { void Renderer::enable_gl_option(GLenum option) const {
// Sort transparents glEnable(option);
// std::sort()
} }
void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) { void Renderer::sort_jobs() {
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); this->queue_job(job);
} }
@ -61,8 +66,6 @@ namespace simpleengine::gfx {
switch (job.rendering_type) { switch (job.rendering_type) {
case RenderingType::RendType_TRANSPARENT: { case RenderingType::RendType_TRANSPARENT: {
/* glm::vec3 pos = job.transform_mat[3];
float distance = glm::distance(pos, camera->position); */
this->transparent_render_queue.emplace(job); this->transparent_render_queue.emplace(job);
break; break;
} }
@ -113,9 +116,10 @@ namespace simpleengine::gfx {
} }
void Renderer::initialize() { void Renderer::initialize() {
glEnable(GL_DEPTH_TEST); enable_gl_option(GL_DEPTH_TEST);
glEnable(GL_BLEND); enable_gl_option(GL_BLEND);
glEnable(GL_CULL_FACE); enable_gl_option(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -129,16 +133,30 @@ namespace simpleengine::gfx {
std::cout << "Destroying renderer..." << std::endl; std::cout << "Destroying renderer..." << std::endl;
shader.delete_program(); 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; 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> &material = mesh->material; std::optional<Material> &material = mesh->material;
@ -196,12 +214,12 @@ namespace simpleengine::gfx {
return true; return true;
} }
void Renderer::render_job_queue(std::queue<RenderingJob> &rendering_queue) { void Renderer::render_job_queue(const float& interpolate_alpha, std::queue<RenderingJob> &rendering_queue) {
while (!rendering_queue.empty()) { while (!rendering_queue.empty()) {
// Get the job from the queue, we'll remove it after we render. // Get the job from the queue, we'll remove it after we render.
RenderingJob &job = rendering_queue.front(); RenderingJob &job = rendering_queue.front();
bool res = this->render_job(job); bool res = this->render_job(interpolate_alpha, job);
if (res) { if (res) {
// Now we'll remove the job from the queue. // Now we'll remove the job from the queue.
@ -210,19 +228,24 @@ namespace simpleengine::gfx {
} }
} }
void Renderer::render_job_queue(std::map<float, RenderingJob, std::greater<>>& rendering_queue) { void Renderer::render_job_queue(const float& interpolate_alpha, std::map<float, RenderingJob, std::greater<>>& rendering_queue) {
// Render each job then clear the queue // Render each job then clear the queue
for (const auto& it : rendering_queue) { for (const auto& it : rendering_queue) {
this->render_job(it.second); this->render_job(interpolate_alpha, it.second);
} }
rendering_queue.clear(); rendering_queue.clear();
} }
void Renderer::render() { void Renderer::render(const float& interpolate_alpha, const float& frame_time) {
check_if_initialized(); 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 other (opaque) objects first
render_job_queue(other_render_queue); render_job_queue(interpolate_alpha, other_render_queue);
// Render transparent objects // Render transparent objects
std::map<float, RenderingJob, std::greater<>> transparent_jobs; std::map<float, RenderingJob, std::greater<>> transparent_jobs;
@ -235,6 +258,6 @@ namespace simpleengine::gfx {
transparent_render_queue.pop(); transparent_render_queue.pop();
} }
render_job_queue(transparent_jobs); render_job_queue(interpolate_alpha, transparent_jobs);
} }
} // namespace simpleengine::gfx } // namespace simpleengine::gfx

View File

@ -6,8 +6,11 @@
#include "ecs/entity.h" #include "ecs/entity.h"
#include "gfx/renderer.h" #include "gfx/renderer.h"
#include <glm/gtx/string_cast.hpp>
#include <stdexcept>
namespace simpleengine { namespace simpleengine {
Scene::Scene(std::shared_ptr<gfx::Renderer> renderer) : renderer(renderer) { Scene::Scene(std::shared_ptr<gfx::Renderer> renderer, std::shared_ptr<Camera> camera) : renderer(renderer), camera(camera) {
} }
@ -15,31 +18,45 @@ namespace simpleengine {
return ecs::Entity(registry, registry.create()); 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) { void Scene::update(const float& delta_time) {
// Update the last transform matrix
registry.view<TransformComponent>().each([this, &delta_time](TransformComponent& transform) {
transform.last_transform_matrix = transform.transform_matrix;
});
// Rotate the model
registry.view<TransformComponent, RotatingComponent>().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? // Is there a way these can be grouped?
registry.view<const TransformComponent, ModelComponent>().each([this](const TransformComponent& transform, ModelComponent& model_component) { registry.view<TransformComponent, ModelComponent>().each([this](TransformComponent& transform, ModelComponent& model_component) {
for (auto& mesh : model_component.model.meshes) { for (auto& mesh : model_component.model.meshes) {
auto rendering_type = gfx::RenderingType::RendType_OPAQUE; auto rendering_type = gfx::RenderingType::RendType_OPAQUE;
if (mesh.material) { if (mesh.material) {
rendering_type = mesh.material->rendering_type; 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<const TransformComponent, MeshComponent>().each([this](const TransformComponent& transform, MeshComponent& mesh_component) { registry.view<TransformComponent, MeshComponent>().each([this](TransformComponent& transform, MeshComponent& mesh_component) {
auto rendering_type = gfx::RenderingType::RendType_OPAQUE; auto rendering_type = gfx::RenderingType::RendType_OPAQUE;
if (mesh_component.mesh.material) { if (mesh_component.mesh.material) {
rendering_type = mesh_component.mesh.material->rendering_type; 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<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) { renderer->render(interpolate_alpha, frame_time);
transform.rotate(rotating.rate * delta_time, rotating.rotation_axis);
});
} }
void Scene::destroy() { void Scene::destroy() {