mirror of
https://github.com/NoelFB/blah.git
synced 2024-11-28 16:58:57 +08:00
added App flags, implemented v-sync and fixed timestep flags
This commit is contained in:
parent
05b58706d7
commit
c94e372e7d
|
@ -11,6 +11,15 @@ namespace Blah
|
||||||
// Application Logging Functions
|
// Application Logging Functions
|
||||||
using AppLogFn = Func<void, const char*, Log::Category>;
|
using AppLogFn = Func<void, const char*, Log::Category>;
|
||||||
|
|
||||||
|
// Application flags
|
||||||
|
namespace Flags
|
||||||
|
{
|
||||||
|
constexpr u32 FixedTimestep = 1 << 0;
|
||||||
|
constexpr u32 VSync = 1 << 1;
|
||||||
|
constexpr u32 Fullscreen = 1 << 2;
|
||||||
|
constexpr u32 Resizable = 1 << 3;
|
||||||
|
}
|
||||||
|
|
||||||
// Application Configuration
|
// Application Configuration
|
||||||
struct Config
|
struct Config
|
||||||
{
|
{
|
||||||
|
@ -34,10 +43,13 @@ namespace Blah
|
||||||
// defaults to 5.
|
// defaults to 5.
|
||||||
int max_updates = 5;
|
int max_updates = 5;
|
||||||
|
|
||||||
// target framerate.
|
// target framerate when running with Fixed Timestep
|
||||||
// defaults to 60.
|
// defaults to 60.
|
||||||
int target_framerate = 60;
|
int target_framerate = 60;
|
||||||
|
|
||||||
|
// default starting flags
|
||||||
|
u32 flags = Flags::VSync | Flags::Resizable | Flags::FixedTimestep;
|
||||||
|
|
||||||
// Callback on application startup
|
// Callback on application startup
|
||||||
AppEventFn on_startup = nullptr;
|
AppEventFn on_startup = nullptr;
|
||||||
|
|
||||||
|
@ -113,9 +125,23 @@ namespace Blah
|
||||||
// If the window is currently focused or has mouse input
|
// If the window is currently focused or has mouse input
|
||||||
bool focused();
|
bool focused();
|
||||||
|
|
||||||
// Toggles fullscreen if supported on the platform.
|
// Toggles a specific flag
|
||||||
// Otherwise this function does nothing.
|
void set_flag(u32 flag, bool enabled);
|
||||||
void fullscreen(bool enabled);
|
|
||||||
|
// Gets whether a specific flag is enabled
|
||||||
|
bool get_flag(u32 flag);
|
||||||
|
|
||||||
|
// Toggles the fullscreen flag
|
||||||
|
inline void set_fullscreen(bool enabled) { set_flag(Flags::Fullscreen, enabled); }
|
||||||
|
|
||||||
|
// Toggles the V-Sync flag
|
||||||
|
inline void set_vsync(bool enabled) { set_flag(Flags::VSync, enabled); }
|
||||||
|
|
||||||
|
// Toggles the resizable flag
|
||||||
|
inline void set_resizable(bool enabled) { set_flag(Flags::Resizable, enabled); }
|
||||||
|
|
||||||
|
// Toggles whether to update with Fixed Timestep
|
||||||
|
inline void set_fixedtimestep(bool enabled) { set_flag(Flags::FixedTimestep, enabled); }
|
||||||
|
|
||||||
// Retrieves the Renderer Information
|
// Retrieves the Renderer Information
|
||||||
const RendererInfo& renderer();
|
const RendererInfo& renderer();
|
||||||
|
|
94
src/app.cpp
94
src/app.cpp
|
@ -28,6 +28,7 @@ namespace
|
||||||
bool app_is_exiting = false;
|
bool app_is_exiting = false;
|
||||||
u64 app_time_last;
|
u64 app_time_last;
|
||||||
u64 app_time_accumulator = 0;
|
u64 app_time_accumulator = 0;
|
||||||
|
u32 app_flags = 0;
|
||||||
TargetRef app_backbuffer;
|
TargetRef app_backbuffer;
|
||||||
|
|
||||||
void get_drawable_size(int* w, int* h)
|
void get_drawable_size(int* w, int* h)
|
||||||
|
@ -90,6 +91,7 @@ bool App::run(const Config* c)
|
||||||
// default values
|
// default values
|
||||||
app_is_running = true;
|
app_is_running = true;
|
||||||
app_is_exiting = false;
|
app_is_exiting = false;
|
||||||
|
app_flags = app_config.flags;
|
||||||
app_backbuffer = TargetRef(new BackBuffer());
|
app_backbuffer = TargetRef(new BackBuffer());
|
||||||
|
|
||||||
// initialize the system
|
// initialize the system
|
||||||
|
@ -128,6 +130,10 @@ bool App::run(const Config* c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply default flags
|
||||||
|
Internal::platform->set_app_flags(app_flags);
|
||||||
|
Internal::renderer->set_app_flags(app_flags);
|
||||||
|
|
||||||
// input + poll the platform once
|
// input + poll the platform once
|
||||||
Input::Internal::init();
|
Input::Internal::init();
|
||||||
Input::Internal::step_state();
|
Input::Internal::step_state();
|
||||||
|
@ -164,14 +170,26 @@ bool App::is_running()
|
||||||
|
|
||||||
void App::Internal::iterate()
|
void App::Internal::iterate()
|
||||||
{
|
{
|
||||||
// update at a fixed timerate
|
static const auto step = []()
|
||||||
// TODO: allow a non-fixed step update?
|
{
|
||||||
|
Input::Internal::step_state();
|
||||||
|
platform->update(Input::state);
|
||||||
|
Input::Internal::update_bindings();
|
||||||
|
renderer->update();
|
||||||
|
if (app_config.on_update != nullptr)
|
||||||
|
app_config.on_update();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool is_fixed_timestep = get_flag(Flags::FixedTimestep);
|
||||||
|
|
||||||
|
// Update in Fixed Timestep
|
||||||
|
if (is_fixed_timestep)
|
||||||
{
|
{
|
||||||
u64 time_target = (u64)((1.0 / app_config.target_framerate) * Time::ticks_per_second);
|
u64 time_target = (u64)((1.0 / app_config.target_framerate) * Time::ticks_per_second);
|
||||||
u64 time_curr = App::Internal::platform->ticks();
|
u64 ticks_curr = App::Internal::platform->ticks();
|
||||||
u64 time_diff = time_curr - app_time_last;
|
u64 ticks_diff = ticks_curr - app_time_last;
|
||||||
app_time_last = time_curr;
|
app_time_last = ticks_curr;
|
||||||
app_time_accumulator += time_diff;
|
app_time_accumulator += ticks_diff;
|
||||||
|
|
||||||
// do not let us run too fast
|
// do not let us run too fast
|
||||||
while (app_time_accumulator < time_target)
|
while (app_time_accumulator < time_target)
|
||||||
|
@ -179,10 +197,10 @@ void App::Internal::iterate()
|
||||||
int milliseconds = (int)(time_target - app_time_accumulator) / (Time::ticks_per_second / 1000);
|
int milliseconds = (int)(time_target - app_time_accumulator) / (Time::ticks_per_second / 1000);
|
||||||
App::Internal::platform->sleep(milliseconds);
|
App::Internal::platform->sleep(milliseconds);
|
||||||
|
|
||||||
time_curr = App::Internal::platform->ticks();
|
ticks_curr = App::Internal::platform->ticks();
|
||||||
time_diff = time_curr - app_time_last;
|
ticks_diff = ticks_curr - app_time_last;
|
||||||
app_time_last = time_curr;
|
app_time_last = ticks_curr;
|
||||||
app_time_accumulator += time_diff;
|
app_time_accumulator += ticks_diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not allow us to fall behind too many updates
|
// Do not allow us to fall behind too many updates
|
||||||
|
@ -212,23 +230,39 @@ void App::Internal::iterate()
|
||||||
Time::previous_seconds = Time::seconds;
|
Time::previous_seconds = Time::seconds;
|
||||||
Time::seconds += Time::delta;
|
Time::seconds += Time::delta;
|
||||||
|
|
||||||
Input::Internal::step_state();
|
step();
|
||||||
platform->update(Input::state);
|
}
|
||||||
Input::Internal::update_bindings();
|
}
|
||||||
renderer->update();
|
// Update with Variable Timestep
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u64 ticks_curr = App::Internal::platform->ticks();
|
||||||
|
u64 ticks_diff = ticks_curr - app_time_last;
|
||||||
|
app_time_last = ticks_curr;
|
||||||
|
app_time_accumulator += ticks_diff;
|
||||||
|
|
||||||
if (app_config.on_update != nullptr)
|
Time::delta = ticks_diff / (float)Time::ticks_per_second;
|
||||||
app_config.on_update();
|
|
||||||
|
if (Time::pause_timer > 0)
|
||||||
|
{
|
||||||
|
Time::pause_timer -= Time::delta;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Time::previous_ticks = Time::ticks;
|
||||||
|
Time::ticks += ticks_diff;
|
||||||
|
Time::previous_seconds = Time::seconds;
|
||||||
|
Time::seconds += Time::delta;
|
||||||
|
|
||||||
|
step();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// render
|
// Draw Frame
|
||||||
{
|
{
|
||||||
renderer->before_render();
|
renderer->before_render();
|
||||||
|
|
||||||
if (app_config.on_render != nullptr)
|
if (app_config.on_render != nullptr)
|
||||||
app_config.on_render();
|
app_config.on_render();
|
||||||
|
|
||||||
renderer->after_render();
|
renderer->after_render();
|
||||||
platform->present();
|
platform->present();
|
||||||
}
|
}
|
||||||
|
@ -353,10 +387,28 @@ bool App::focused()
|
||||||
return Internal::platform->get_focused();
|
return Internal::platform->get_focused();
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::fullscreen(bool enabled)
|
void App::set_flag(u32 flag, bool enabled)
|
||||||
{
|
{
|
||||||
BLAH_ASSERT_RUNNING();
|
BLAH_ASSERT_RUNNING();
|
||||||
Internal::platform->set_fullscreen(enabled);
|
|
||||||
|
u32 was = app_flags;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
app_flags |= flag;
|
||||||
|
else
|
||||||
|
app_flags &= ~flag;
|
||||||
|
|
||||||
|
if (was != app_flags)
|
||||||
|
{
|
||||||
|
Internal::platform->set_app_flags(app_flags);
|
||||||
|
Internal::renderer->set_app_flags(app_flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::get_flag(u32 flag)
|
||||||
|
{
|
||||||
|
BLAH_ASSERT_RUNNING();
|
||||||
|
return ((app_flags & flag) == flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
const RendererInfo& App::renderer()
|
const RendererInfo& App::renderer()
|
||||||
|
|
|
@ -35,6 +35,9 @@ namespace Blah
|
||||||
// Called to present the window contents
|
// Called to present the window contents
|
||||||
virtual void present() = 0;
|
virtual void present() = 0;
|
||||||
|
|
||||||
|
// Called when the App sets flags
|
||||||
|
virtual void set_app_flags(u32 flags) = 0;
|
||||||
|
|
||||||
// Gets the Application Window Title in UTF-8
|
// Gets the Application Window Title in UTF-8
|
||||||
virtual const char* get_title() = 0;
|
virtual const char* get_title() = 0;
|
||||||
|
|
||||||
|
@ -50,9 +53,6 @@ namespace Blah
|
||||||
// Gets whether the Window has focus
|
// Gets whether the Window has focus
|
||||||
virtual bool get_focused() = 0;
|
virtual bool get_focused() = 0;
|
||||||
|
|
||||||
// Sets the Window Fullscreen if enabled is not 0
|
|
||||||
virtual void set_fullscreen(bool enabled) = 0;
|
|
||||||
|
|
||||||
// Gets the Application Window Size, in Screen Coordinates
|
// Gets the Application Window Size, in Screen Coordinates
|
||||||
virtual void get_size(int* width, int* height) = 0;
|
virtual void get_size(int* width, int* height) = 0;
|
||||||
|
|
||||||
|
|
|
@ -89,12 +89,12 @@ namespace Blah
|
||||||
void update(InputState& state) override;
|
void update(InputState& state) override;
|
||||||
void sleep(int milliseconds) override;
|
void sleep(int milliseconds) override;
|
||||||
void present() override;
|
void present() override;
|
||||||
|
void set_app_flags(u32 flags) override;
|
||||||
const char* get_title() override;
|
const char* get_title() override;
|
||||||
void set_title(const char* title) override;
|
void set_title(const char* title) override;
|
||||||
void get_position(int* x, int* y) override;
|
void get_position(int* x, int* y) override;
|
||||||
void set_position(int x, int y) override;
|
void set_position(int x, int y) override;
|
||||||
bool get_focused() override;
|
bool get_focused() override;
|
||||||
void set_fullscreen(bool enabled) override;
|
|
||||||
void get_size(int* width, int* height) override;
|
void get_size(int* width, int* height) override;
|
||||||
void set_size(int width, int height) override;
|
void set_size(int width, int height) override;
|
||||||
void get_draw_size(int* width, int* height) override;
|
void get_draw_size(int* width, int* height) override;
|
||||||
|
@ -158,7 +158,7 @@ bool SDL2_Platform::init(const Config& config)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
|
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN;
|
||||||
|
|
||||||
// enable OpenGL
|
// enable OpenGL
|
||||||
if (config.renderer_type == RendererType::OpenGL)
|
if (config.renderer_type == RendererType::OpenGL)
|
||||||
|
@ -192,22 +192,12 @@ bool SDL2_Platform::init(const Config& config)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set window properties
|
|
||||||
SDL_SetWindowResizable(window, SDL_TRUE);
|
|
||||||
SDL_SetWindowMinimumSize(window, 256, 256);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDL2_Platform::ready()
|
void SDL2_Platform::ready()
|
||||||
{
|
{
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
// enable V-Sync
|
|
||||||
// TODO:
|
|
||||||
// This should be a toggle or controllable in some way
|
|
||||||
if (App::renderer().type == RendererType::OpenGL)
|
|
||||||
SDL_GL_SetSwapInterval(1);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDL2_Platform::shutdown()
|
void SDL2_Platform::shutdown()
|
||||||
|
@ -446,9 +436,7 @@ void SDL2_Platform::sleep(int milliseconds)
|
||||||
void SDL2_Platform::present()
|
void SDL2_Platform::present()
|
||||||
{
|
{
|
||||||
if (App::renderer().type == RendererType::OpenGL)
|
if (App::renderer().type == RendererType::OpenGL)
|
||||||
{
|
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
}
|
|
||||||
|
|
||||||
// display the window
|
// display the window
|
||||||
// this avoids a short black screen on macoS
|
// this avoids a short black screen on macoS
|
||||||
|
@ -459,6 +447,21 @@ void SDL2_Platform::present()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDL2_Platform::set_app_flags(u32 flags)
|
||||||
|
{
|
||||||
|
// Toggle Fullscreen
|
||||||
|
SDL_SetWindowFullscreen(window, ((flags & Flags::Fullscreen) != 0) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||||
|
|
||||||
|
// Toggle Resizable
|
||||||
|
SDL_SetWindowResizable(window, ((flags & Flags::Resizable) != 0) ? SDL_TRUE : SDL_FALSE);
|
||||||
|
|
||||||
|
// Toggle V-Sync for OpenGL
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
if (App::renderer().type == RendererType::OpenGL)
|
||||||
|
SDL_GL_SetSwapInterval(((flags & Flags::VSync) != 0) ? 1 : 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
const char* SDL2_Platform::get_title()
|
const char* SDL2_Platform::get_title()
|
||||||
{
|
{
|
||||||
return SDL_GetWindowTitle(window);
|
return SDL_GetWindowTitle(window);
|
||||||
|
@ -485,14 +488,6 @@ bool SDL2_Platform::get_focused()
|
||||||
return (flags & SDL_WINDOW_INPUT_FOCUS) != 0 && (flags & SDL_WINDOW_MINIMIZED) == 0;
|
return (flags & SDL_WINDOW_INPUT_FOCUS) != 0 && (flags & SDL_WINDOW_MINIMIZED) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDL2_Platform::set_fullscreen(bool enabled)
|
|
||||||
{
|
|
||||||
if (enabled)
|
|
||||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
|
||||||
else
|
|
||||||
SDL_SetWindowFullscreen(window, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL2_Platform::get_size(int* width, int* height)
|
void SDL2_Platform::get_size(int* width, int* height)
|
||||||
{
|
{
|
||||||
SDL_GetWindowSize(window, width, height);
|
SDL_GetWindowSize(window, width, height);
|
||||||
|
|
|
@ -99,7 +99,7 @@ namespace Blah
|
||||||
void get_position(int* x, int* y) override;
|
void get_position(int* x, int* y) override;
|
||||||
void set_position(int x, int y) override;
|
void set_position(int x, int y) override;
|
||||||
bool get_focused() override;
|
bool get_focused() override;
|
||||||
void set_fullscreen(bool enabled) override;
|
void set_app_flags(u32 flags) override;
|
||||||
void get_size(int* width, int* height) override;
|
void get_size(int* width, int* height) override;
|
||||||
void set_size(int width, int height) override;
|
void set_size(int width, int height) override;
|
||||||
void get_draw_size(int* width, int* height) override;
|
void get_draw_size(int* width, int* height) override;
|
||||||
|
@ -474,33 +474,39 @@ bool Win32_Platform::get_focused()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32_Platform::set_fullscreen(bool enabled)
|
void Win32_Platform::set_app_flags(u32 flags)
|
||||||
{
|
{
|
||||||
if (fullscreen == enabled)
|
// toggle fullscreen
|
||||||
return;
|
|
||||||
|
|
||||||
fullscreen = enabled;
|
|
||||||
|
|
||||||
if (fullscreen)
|
|
||||||
{
|
{
|
||||||
GetWindowRect(hwnd, &windowed_position);
|
bool enabled = (flags & Flags::Fullscreen) != 0;
|
||||||
|
if (fullscreen == enabled)
|
||||||
|
return;
|
||||||
|
fullscreen = enabled;
|
||||||
|
|
||||||
int w = GetSystemMetrics(SM_CXSCREEN);
|
if (fullscreen)
|
||||||
int h = GetSystemMetrics(SM_CYSCREEN);
|
{
|
||||||
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
GetWindowRect(hwnd, &windowed_position);
|
||||||
SetWindowPos(hwnd, HWND_TOP, 0, 0, w, h, 0);
|
|
||||||
ShowWindow(hwnd, SW_SHOW);
|
int w = GetSystemMetrics(SM_CXSCREEN);
|
||||||
}
|
int h = GetSystemMetrics(SM_CYSCREEN);
|
||||||
else
|
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||||
{
|
SetWindowPos(hwnd, HWND_TOP, 0, 0, w, h, 0);
|
||||||
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
|
ShowWindow(hwnd, SW_SHOW);
|
||||||
SetWindowPos(hwnd, HWND_TOP,
|
}
|
||||||
windowed_position.left,
|
else
|
||||||
windowed_position.top,
|
{
|
||||||
windowed_position.right - windowed_position.left,
|
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
|
||||||
windowed_position.bottom - windowed_position.top, 0);
|
SetWindowPos(hwnd, HWND_TOP,
|
||||||
ShowWindow(hwnd, SW_SHOW);
|
windowed_position.left,
|
||||||
|
windowed_position.top,
|
||||||
|
windowed_position.right - windowed_position.left,
|
||||||
|
windowed_position.bottom - windowed_position.top, 0);
|
||||||
|
ShowWindow(hwnd, SW_SHOW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// toggle resizable
|
||||||
|
// TODO: ...
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32_Platform::get_size(int* width, int* height)
|
void Win32_Platform::get_size(int* width, int* height)
|
||||||
|
|
|
@ -32,6 +32,9 @@ namespace Blah
|
||||||
// Called after renderings ends
|
// Called after renderings ends
|
||||||
virtual void after_render() = 0;
|
virtual void after_render() = 0;
|
||||||
|
|
||||||
|
// Called when the App sets flags
|
||||||
|
virtual void set_app_flags(u32 flags) { }
|
||||||
|
|
||||||
// Optional implementation to get the drawable backbuffer size in pixels.
|
// Optional implementation to get the drawable backbuffer size in pixels.
|
||||||
// Not all implementations will use this so it can be up to the Platform.
|
// Not all implementations will use this so it can be up to the Platform.
|
||||||
virtual bool get_draw_size(int* w, int* h) { return false; }
|
virtual bool get_draw_size(int* w, int* h) { return false; }
|
||||||
|
|
|
@ -932,7 +932,8 @@ namespace Blah
|
||||||
|
|
||||||
void Renderer_D3D11::after_render()
|
void Renderer_D3D11::after_render()
|
||||||
{
|
{
|
||||||
auto hr = swap_chain->Present(1, 0);
|
auto vsync = App::get_flag(Flags::VSync);
|
||||||
|
auto hr = swap_chain->Present(vsync ? 1 : 0, 0);
|
||||||
BLAH_ASSERT(SUCCEEDED(hr), "Failed to Present swap chain");
|
BLAH_ASSERT(SUCCEEDED(hr), "Failed to Present swap chain");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user