Merge pull request #6 from SeanOMik/feature/fixed-timestep
Implement fixed timestep
This commit is contained in:
commit
8493e2aa86
18
.clang-tidy
18
.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"
|
||||
---
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "simpleengine/gfx/renderer.h"
|
||||
#include "simpleengine/gfx/texture.h"
|
||||
#include "simpleengine/vector.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <simpleengine/ecs/component/model_component.h>
|
||||
#include <simpleengine/ecs/component/rotating_component.h>
|
||||
#include <simpleengine/event/event.h>
|
||||
|
@ -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<se::Camera>(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<se::gfx::Renderer>(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<se::Scene>(renderer);
|
||||
game.add_event(scene);
|
||||
auto scene = std::make_shared<se::Scene>(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<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx",
|
||||
se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT);
|
||||
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.
|
||||
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",
|
||||
se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT);
|
||||
|
||||
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();
|
||||
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>();
|
||||
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));
|
||||
game.add_event(light);
|
||||
|
||||
auto fps_counter = std::make_shared<FPSCounterEvent>();
|
||||
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();
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
//#include "simpleengine/scene.h"
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
};
|
||||
}
|
|
@ -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<simpleengine::Event> event);
|
||||
void add_renderable(std::shared_ptr<simpleengine::Renderable> 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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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> 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<RenderingJob>& queue);
|
||||
virtual void render_job_queue(std::map<float, RenderingJob, std::greater<>>& queue);
|
||||
virtual bool render_job(const float& interpolate_alpha, const RenderingJob& job);
|
||||
virtual void render_job_queue(const float& interpolate_alpha, std::queue<RenderingJob>& queue);
|
||||
virtual void render_job_queue(const float& interpolate_alpha, std::map<float, RenderingJob, std::greater<>>& queue);
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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 <memory>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
|
@ -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<gfx::Renderer> renderer;
|
||||
|
||||
// Last transform matrixes for all entities.
|
||||
std::unordered_map<uint32_t, glm::mat4> last_transforms;
|
||||
|
||||
std::shared_ptr<Camera> camera;
|
||||
public:
|
||||
Scene(std::shared_ptr<gfx::Renderer> renderer);
|
||||
Scene(std::shared_ptr<gfx::Renderer> renderer, std::shared_ptr<Camera> 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;
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ struct Material {
|
|||
|
||||
bool has_specular_map;
|
||||
sampler2D specular_map;
|
||||
|
||||
|
||||
bool has_normal_map;
|
||||
sampler2D normal_map;
|
||||
|
||||
|
|
|
@ -1,29 +1,34 @@
|
|||
#include "camera.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/ext/quaternion_common.hpp>
|
||||
#include <glm/ext/quaternion_geometric.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include <glm/trigonometric.hpp>
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
58
src/game.cpp
58
src/game.cpp
|
@ -10,16 +10,14 @@
|
|||
#ifdef __linux__
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GL/gl.h>
|
||||
#else
|
||||
#include <gl/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <gl/gl.h>
|
||||
#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>& event : events) {
|
||||
event->input_update(delta_time);
|
||||
}
|
||||
}
|
||||
|
||||
void simpleengine::Game::update(const float& delta_time) {
|
||||
// Update items
|
||||
for (const std::shared_ptr<Event>& 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 : 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;
|
||||
|
|
|
@ -13,11 +13,14 @@
|
|||
#include <glm/geometric.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include <glm/gtx/matrix_interpolation.hpp>
|
||||
|
||||
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> 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> &material = mesh->material;
|
||||
|
||||
|
@ -196,12 +214,12 @@ namespace simpleengine::gfx {
|
|||
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()) {
|
||||
// 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<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
|
||||
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<float, RenderingJob, std::greater<>> 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
|
|
@ -6,8 +6,11 @@
|
|||
#include "ecs/entity.h"
|
||||
#include "gfx/renderer.h"
|
||||
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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<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?
|
||||
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) {
|
||||
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<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;
|
||||
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<TransformComponent, RotatingComponent>().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() {
|
||||
|
|
Loading…
Reference in New Issue