Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ endif()

add_library(Caffeine
src/core/Timer.cpp
src/core/GameLoop.cpp
)

target_include_directories(Caffeine PUBLIC
Expand Down
82 changes: 82 additions & 0 deletions src/core/GameLoop.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include "GameLoop.hpp"
#include <algorithm>

namespace Caffeine {

GameLoop::GameLoop(const GameLoopConfig& config)
: m_config(config) {
}

GameLoop::~GameLoop() {
}

void GameLoop::init() {
if (m_state != GameState::Init) return;
m_state = GameState::Running;
m_accumulator = 0.0;
m_elapsedTime = 0.0;
m_alpha = 0.0;
m_frameCount = 0;
}

void GameLoop::tick(f64 deltaTime) {
if (m_state != GameState::Running && m_state != GameState::Paused) return;

if (m_callbacks) m_callbacks->onBeginFrame();
if (onBeginFrame) onBeginFrame();

deltaTime = std::min(deltaTime, m_config.maxFrameTime);
m_elapsedTime += deltaTime;

if (m_state == GameState::Running) {
m_accumulator += deltaTime;

while (m_accumulator >= m_config.fixedDeltaTime) {
processFixedUpdate(m_config.fixedDeltaTime);
m_accumulator -= m_config.fixedDeltaTime;
}

if (m_config.interpolation) {
m_alpha = m_accumulator / m_config.fixedDeltaTime;
} else {
m_alpha = 0.0;
}
}

if (m_callbacks) m_callbacks->onRender(m_alpha);
if (onRender) onRender(m_alpha);

if (m_callbacks) m_callbacks->onEndFrame();
if (onEndFrame) onEndFrame();

m_frameCount++;
}

void GameLoop::pause() {
if (m_state == GameState::Running) {
m_state = GameState::Paused;
}
}

void GameLoop::resume() {
if (m_state == GameState::Paused) {
m_state = GameState::Running;
}
}

void GameLoop::shutdown() {
if (m_state == GameState::Running || m_state == GameState::Paused) {
m_state = GameState::Shutdown;
}
}

void GameLoop::setCallbacks(IGameCallbacks* callbacks) {
m_callbacks = callbacks;
}

void GameLoop::processFixedUpdate(f64 dt) {
if (m_callbacks) m_callbacks->onFixedUpdate(dt);
if (onFixedUpdate) onFixedUpdate(dt);
}

}
71 changes: 71 additions & 0 deletions src/core/GameLoop.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once

#include "Types.hpp"
#include <functional>

namespace Caffeine {

enum class GameState : u8 {
Init,
Running,
Paused,
Shutdown
};

struct GameLoopConfig {
f64 fixedDeltaTime = 1.0 / 60.0;
f64 maxFrameTime = 0.25;
u32 targetFPS = 0;
bool vsync = true;
bool interpolation = true;
};

class IGameCallbacks {
public:
virtual ~IGameCallbacks() = default;

virtual void onBeginFrame() {}
virtual void onFixedUpdate(f64 dt) { (void)dt; }
virtual void onRender(f64 alpha) { (void)alpha; }
virtual void onEndFrame() {}
};

class GameLoop {
public:
explicit GameLoop(const GameLoopConfig& config = {});
~GameLoop();

void init();
void tick(f64 deltaTime);
void pause();
void resume();
void shutdown();

GameState state() const { return m_state; }
f64 elapsedTime() const { return m_elapsedTime; }
f64 interpolationAlpha() const { return m_alpha; }
u64 frameCount() const { return m_frameCount; }
f64 accumulator() const { return m_accumulator; }

void setCallbacks(IGameCallbacks* callbacks);

std::function<void(f64 dt)> onFixedUpdate;
std::function<void(f64 alpha)> onRender;
std::function<void()> onBeginFrame;
std::function<void()> onEndFrame;

const GameLoopConfig& config() const { return m_config; }

private:
void processFixedUpdate(f64 dt);

GameLoopConfig m_config;
IGameCallbacks* m_callbacks = nullptr;
GameState m_state = GameState::Init;
f64 m_accumulator = 0.0;
f64 m_elapsedTime = 0.0;
f64 m_alpha = 0.0;
u64 m_frameCount = 0;
};

}
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_executable(CaffeineTest
test_math.cpp
test_core.cpp
test_timer.cpp
test_gameloop.cpp
)

target_link_libraries(CaffeineTest PRIVATE Caffeine)
Expand Down
Loading
Loading