diff --git a/CMakeLists.txt b/CMakeLists.txt index 54cba84..f26937d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,11 +48,7 @@ cmrc_add_resource_library( # Link dependencies target_link_libraries(simpleengine PUBLIC GLEW::GLEW) target_link_libraries(simpleengine PUBLIC glfw) -if (WIN32) - target_link_libraries(simpleengine PUBLIC glm::glm) -else() - target_link_libraries(simpleengine PUBLIC glm) -endif() +target_link_libraries(simpleengine PUBLIC ${GLM_LIBRARIES}) target_link_libraries(simpleengine PUBLIC soil2) target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES}) target_link_libraries(simpleengine PRIVATE simpleengine_resources) diff --git a/cmrc b/cmrc index a64bea5..e386a62 160000 --- a/cmrc +++ b/cmrc @@ -1 +1 @@ -Subproject commit a64bea50c05594c8e7cf1f08e441bb9507742e2e +Subproject commit e386a629eb537d384811e598a3c96b9ca928f65e diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index 1d02513..93b5150 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -7,6 +7,7 @@ #include "simpleengine/gfx/renderer.h" #include "simpleengine/gfx/texture.h" #include "simpleengine/vector.h" +#include #include #include #include @@ -37,6 +38,31 @@ CMRC_DECLARE(resource_shaders); namespace se = simpleengine; +class FPSCounterEvent : public se::Event { +public: + double last_frame_time; + int frame_count; + + FPSCounterEvent() : se::Event() { + this->last_frame_time = glfwGetTime(); + frame_count = 0; + } + + virtual void update(const float& delta_time) { + double current_time = glfwGetTime(); + frame_count++; + + // 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; + + printf("%d fps, %f ms/frame\n", frame_count, ms_per_frame); + frame_count = 0; + last_frame_time += 1.0; + } + } +}; + std::string read_resource_shader(const std::string& path) { auto fs = cmrc::resource_shaders::get_filesystem(); cmrc::file vertex_file = fs.open(path); @@ -161,7 +187,7 @@ int main(int argc, char *argv[]) { auto renderer = std::make_shared(game.get_window(), core_shader); renderer->enable_debug(); renderer->submit_entity(entity); - game.add_event(renderer); + game.add_renderable(renderer); /* renderer->add_model(white_texture, cube); game.add_event(renderer); */ @@ -171,6 +197,11 @@ int main(int argc, char *argv[]) { auto camera = std::make_shared(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0)); game.add_event(camera); + auto fps_counter = std::make_shared(); + game.add_event(fps_counter); + + game.set_enable_vsync(true); + //game.set_fps_limit(120); int res = game.run(); renderer->destroy(); diff --git a/include/simpleengine/game.h b/include/simpleengine/game.h index a9c6f5e..2f1ad17 100644 --- a/include/simpleengine/game.h +++ b/include/simpleengine/game.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -13,6 +14,7 @@ #include #include "event/event.h" +#include "simpleengine/renderable.h" namespace simpleengine { class Game { @@ -34,6 +36,9 @@ namespace simpleengine { 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); @@ -52,12 +57,17 @@ namespace simpleengine { GLFWwindow* window; std::vector> events; + std::vector> renderable_events; const bool& window_resizeable; + // 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; + float get_delta_time(); - float last_frame_time; - /* float currentFrameTime; - float deltaTime; */ + std::chrono::high_resolution_clock::time_point last_frame_time; }; } \ No newline at end of file diff --git a/include/simpleengine/gfx/light.h b/include/simpleengine/gfx/light.h index 6e6c3a4..252b044 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(GLFWwindow* target) override { + virtual void render() override { } }; diff --git a/include/simpleengine/gfx/renderer.h b/include/simpleengine/gfx/renderer.h index 66baa22..9e45b75 100644 --- a/include/simpleengine/gfx/renderer.h +++ b/include/simpleengine/gfx/renderer.h @@ -54,6 +54,6 @@ namespace simpleengine::gfx { virtual void update(const float& delta_time) override; - virtual void render(GLFWwindow* target) override; + virtual void render() override; }; } \ No newline at end of file diff --git a/include/simpleengine/renderable.h b/include/simpleengine/renderable.h index 297e81f..cf7446c 100644 --- a/include/simpleengine/renderable.h +++ b/include/simpleengine/renderable.h @@ -1,11 +1,11 @@ #pragma once - + #include "event/event.h" -#include - #include +#include + namespace simpleengine { class Renderable : public simpleengine::Event { private: @@ -14,6 +14,6 @@ namespace simpleengine { Renderable() = default; virtual ~Renderable() = default; - virtual void render(GLFWwindow* target) = 0; + virtual void render() = 0; }; } \ No newline at end of file diff --git a/include/simpleengine/shader_program.h b/include/simpleengine/shader_program.h index ec3880d..120ddb2 100644 --- a/include/simpleengine/shader_program.h +++ b/include/simpleengine/shader_program.h @@ -111,9 +111,5 @@ namespace simpleengine { virtual void update(const float& delta_time) { } - - virtual void render(GLFWwindow* target) { - glUseProgram(program); - } }; } \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..5a0ba1a --- /dev/null +++ b/shell.nix @@ -0,0 +1,16 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + # nativeBuildInputs is usually what you want -- tools you need to run + nativeBuildInputs = with pkgs; [ + gdb + lldb + cmake + pkg-config + ninja + glew + glfw + glm + (callPackage ./soil2.nix { }) + ]; +} \ No newline at end of file diff --git a/soil2.nix b/soil2.nix new file mode 100644 index 0000000..09f587e --- /dev/null +++ b/soil2.nix @@ -0,0 +1,37 @@ +{ lib +, stdenv +, fetchFromGitHub +, cmake +, libGL +, libX11 +}: + +stdenv.mkDerivation rec { + version = "39028e64921c03cabbc53b937da4a85aba264e00"; + pname = "soil2"; + + src = fetchFromGitHub { + owner = "SpartanJ"; + repo = pname; + rev = version; + sha256 = "sha256-zQQ8lwOkMCxdlf6zfnIOYVUTGVqnJuHL/LL8fbzxwHY="; + }; + + nativeBuildInputs = [ cmake libGL libX11 ]; + + installPhase = '' + runHook preInstall + + cmake --build . --target install --config Release + + runHook postInstall + ''; + + meta = with lib; { + description = "SOIL2 is a tiny C library used primarily for uploading textures into OpenGL."; + homepage = "https://github.com/SpartanJ/SOIL2"; + license = licenses.mit0; + platforms = platforms.unix; + maintainers = with maintainers; [ seanomik ]; + }; +} \ No newline at end of file diff --git a/src/game.cpp b/src/game.cpp index 783a7d8..9d603e9 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,7 +1,11 @@ #include "game.h" #include "event/event.h" +#include "renderable.h" +#include #include +#include +#include #ifdef __linux__ #include @@ -14,7 +18,8 @@ #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) { + const int& minor_version, const bool& resizeable, const int& forward_compat) : window_resizeable(resizeable), + enable_vsync(true), fps_limit(-1) { initialize(gl_profile, major_version, minor_version, window_resizeable, forward_compat); // Create a window @@ -47,6 +52,8 @@ void simpleengine::Game::enable_default_gl_options() const { glEnable(GL_CULL_FACE); glCullFace(GL_BACK); //glFrontFace(GL_CW); + + update_enabled_vsync(); } void simpleengine::Game::enable_gl_option(GLenum option) const { @@ -73,6 +80,33 @@ void simpleengine::Game::add_event(std::shared_ptr event) { events.push_back(event); } +void simpleengine::Game::add_renderable(std::shared_ptr renderable_event) { + renderable_events.push_back(renderable_event); + + // Also push to normal events to trigger updates. + // Instead of this, we could instead loop renderable_events in the update function, + // but that would cause multiple loops. + events.push_back(renderable_event); +} + +void simpleengine::Game::set_fps_limit(const int& fps_limit) { + this->fps_limit = fps_limit; +} + +void simpleengine::Game::set_enable_vsync(const bool& enabled) { + this->enable_vsync = enabled; + + this->update_enabled_vsync(); +} + +void simpleengine::Game::update_enabled_vsync() const { + if (enable_vsync) { + //glfwSwapInterval(1); + } else { + glfwSwapInterval(0); + } +} + void simpleengine::Game::update(const float& delta_time) { handle_input(delta_time); @@ -83,7 +117,7 @@ void simpleengine::Game::update(const float& delta_time) { } void simpleengine::Game::handle_input(const float& delta_time) { - + // TODO } void simpleengine::Game::render_window(const float& delta_time) { @@ -93,17 +127,30 @@ void simpleengine::Game::render_window(const float& delta_time) { } void simpleengine::Game::render_items(const float& delta_time) { - for (const std::shared_ptr& event : events) { - //event->render(window); + for (const std::shared_ptr& renderable : renderable_events) { + renderable->render(); } } float simpleengine::Game::get_delta_time() { - float current_frame_time = glfwGetTime(); - float delta_time = current_frame_time - last_frame_time; + auto current_frame_time = std::chrono::high_resolution_clock::now(); + std::chrono::duration delta_dur = current_frame_time - last_frame_time; last_frame_time = current_frame_time; - return delta_time; + return std::chrono::duration_cast>(delta_dur).count(); +} + +void simpleengine::Game::limit_framerate(const float& delta_time) const { + if (!enable_vsync && fps_limit >= 15) { + auto delta_time_duration = std::chrono::duration(delta_time); + auto limit_duration = std::chrono::duration(1 / ( (float) fps_limit / 2)); + + if (delta_time_duration < limit_duration) { + auto sleep_duration = limit_duration - delta_time_duration; + + std::this_thread::sleep_for(sleep_duration); + } + } } int simpleengine::Game::run() { @@ -111,16 +158,17 @@ int simpleengine::Game::run() { // Get delta time first thing float delta_time = get_delta_time(); - // Update input + // Poll input events glfwPollEvents(); update(delta_time); - render_window(delta_time); // End draw glfwSwapBuffers(window); glFlush(); + + limit_framerate(delta_time); } return 0; diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index f5af14f..6f14c22 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -100,7 +100,7 @@ namespace simpleengine::gfx { } void Renderer::update(const float& delta_time) { - this->render(nullptr); + } void Renderer::initialize() { @@ -115,7 +115,7 @@ namespace simpleengine::gfx { } } - void Renderer::render(GLFWwindow* target) { + void Renderer::render() { shader.use(); for (auto& [handle, rendering] : rendering_models) {