mirror of
https://github.com/NoelFB/blah.git
synced 2024-11-25 16:18: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
|
||||
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
|
||||
struct Config
|
||||
{
|
||||
|
@ -34,10 +43,13 @@ namespace Blah
|
|||
// defaults to 5.
|
||||
int max_updates = 5;
|
||||
|
||||
// target framerate.
|
||||
// target framerate when running with Fixed Timestep
|
||||
// defaults to 60.
|
||||
int target_framerate = 60;
|
||||
|
||||
// default starting flags
|
||||
u32 flags = Flags::VSync | Flags::Resizable | Flags::FixedTimestep;
|
||||
|
||||
// Callback on application startup
|
||||
AppEventFn on_startup = nullptr;
|
||||
|
||||
|
@ -113,9 +125,23 @@ namespace Blah
|
|||
// If the window is currently focused or has mouse input
|
||||
bool focused();
|
||||
|
||||
// Toggles fullscreen if supported on the platform.
|
||||
// Otherwise this function does nothing.
|
||||
void fullscreen(bool enabled);
|
||||
// Toggles a specific flag
|
||||
void set_flag(u32 flag, 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
|
||||
const RendererInfo& renderer();
|
||||
|
|
94
src/app.cpp
94
src/app.cpp
|
@ -28,6 +28,7 @@ namespace
|
|||
bool app_is_exiting = false;
|
||||
u64 app_time_last;
|
||||
u64 app_time_accumulator = 0;
|
||||
u32 app_flags = 0;
|
||||
TargetRef app_backbuffer;
|
||||
|
||||
void get_drawable_size(int* w, int* h)
|
||||
|
@ -90,6 +91,7 @@ bool App::run(const Config* c)
|
|||
// default values
|
||||
app_is_running = true;
|
||||
app_is_exiting = false;
|
||||
app_flags = app_config.flags;
|
||||
app_backbuffer = TargetRef(new BackBuffer());
|
||||
|
||||
// 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::Internal::init();
|
||||
Input::Internal::step_state();
|
||||
|
@ -164,14 +170,26 @@ bool App::is_running()
|
|||
|
||||
void App::Internal::iterate()
|
||||
{
|
||||
// update at a fixed timerate
|
||||
// TODO: allow a non-fixed step update?
|
||||
static const auto step = []()
|
||||
{
|
||||
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_curr = App::Internal::platform->ticks();
|
||||
u64 time_diff = time_curr - app_time_last;
|
||||
app_time_last = time_curr;
|
||||
app_time_accumulator += time_diff;
|
||||
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;
|
||||
|
||||
// do not let us run too fast
|
||||
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);
|
||||
App::Internal::platform->sleep(milliseconds);
|
||||
|
||||
time_curr = App::Internal::platform->ticks();
|
||||
time_diff = time_curr - app_time_last;
|
||||
app_time_last = time_curr;
|
||||
app_time_accumulator += time_diff;
|
||||
ticks_curr = App::Internal::platform->ticks();
|
||||
ticks_diff = ticks_curr - app_time_last;
|
||||
app_time_last = ticks_curr;
|
||||
app_time_accumulator += ticks_diff;
|
||||
}
|
||||
|
||||
// Do not allow us to fall behind too many updates
|
||||
|
@ -212,23 +230,39 @@ void App::Internal::iterate()
|
|||
Time::previous_seconds = Time::seconds;
|
||||
Time::seconds += Time::delta;
|
||||
|
||||
Input::Internal::step_state();
|
||||
platform->update(Input::state);
|
||||
Input::Internal::update_bindings();
|
||||
renderer->update();
|
||||
step();
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
app_config.on_update();
|
||||
Time::delta = ticks_diff / (float)Time::ticks_per_second;
|
||||
|
||||
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();
|
||||
|
||||
if (app_config.on_render != nullptr)
|
||||
app_config.on_render();
|
||||
|
||||
renderer->after_render();
|
||||
platform->present();
|
||||
}
|
||||
|
@ -353,10 +387,28 @@ bool App::focused()
|
|||
return Internal::platform->get_focused();
|
||||
}
|
||||
|
||||
void App::fullscreen(bool enabled)
|
||||
void App::set_flag(u32 flag, bool enabled)
|
||||
{
|
||||
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()
|
||||
|
|
|
@ -35,6 +35,9 @@ namespace Blah
|
|||
// Called to present the window contents
|
||||
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
|
||||
virtual const char* get_title() = 0;
|
||||
|
||||
|
@ -50,9 +53,6 @@ namespace Blah
|
|||
// Gets whether the Window has focus
|
||||
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
|
||||
virtual void get_size(int* width, int* height) = 0;
|
||||
|
||||
|
|
|
@ -89,12 +89,12 @@ namespace Blah
|
|||
void update(InputState& state) override;
|
||||
void sleep(int milliseconds) override;
|
||||
void present() override;
|
||||
void set_app_flags(u32 flags) override;
|
||||
const char* get_title() override;
|
||||
void set_title(const char* title) override;
|
||||
void get_position(int* x, int* y) override;
|
||||
void set_position(int x, int y) override;
|
||||
bool get_focused() override;
|
||||
void set_fullscreen(bool enabled) override;
|
||||
void get_size(int* width, int* height) override;
|
||||
void set_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;
|
||||
}
|
||||
|
||||
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
|
||||
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN;
|
||||
|
||||
// enable OpenGL
|
||||
if (config.renderer_type == RendererType::OpenGL)
|
||||
|
@ -192,22 +192,12 @@ bool SDL2_Platform::init(const Config& config)
|
|||
return false;
|
||||
}
|
||||
|
||||
// set window properties
|
||||
SDL_SetWindowResizable(window, SDL_TRUE);
|
||||
SDL_SetWindowMinimumSize(window, 256, 256);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -446,9 +436,7 @@ void SDL2_Platform::sleep(int milliseconds)
|
|||
void SDL2_Platform::present()
|
||||
{
|
||||
if (App::renderer().type == RendererType::OpenGL)
|
||||
{
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
|
||||
// display the window
|
||||
// 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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
SDL_GetWindowSize(window, width, height);
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace Blah
|
|||
void get_position(int* x, int* y) override;
|
||||
void set_position(int x, int y) 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 set_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;
|
||||
}
|
||||
|
||||
void Win32_Platform::set_fullscreen(bool enabled)
|
||||
void Win32_Platform::set_app_flags(u32 flags)
|
||||
{
|
||||
if (fullscreen == enabled)
|
||||
return;
|
||||
|
||||
fullscreen = enabled;
|
||||
|
||||
if (fullscreen)
|
||||
// toggle fullscreen
|
||||
{
|
||||
GetWindowRect(hwnd, &windowed_position);
|
||||
bool enabled = (flags & Flags::Fullscreen) != 0;
|
||||
if (fullscreen == enabled)
|
||||
return;
|
||||
fullscreen = enabled;
|
||||
|
||||
int w = GetSystemMetrics(SM_CXSCREEN);
|
||||
int h = GetSystemMetrics(SM_CYSCREEN);
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
SetWindowPos(hwnd, HWND_TOP, 0, 0, w, h, 0);
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
|
||||
SetWindowPos(hwnd, HWND_TOP,
|
||||
windowed_position.left,
|
||||
windowed_position.top,
|
||||
windowed_position.right - windowed_position.left,
|
||||
windowed_position.bottom - windowed_position.top, 0);
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
if (fullscreen)
|
||||
{
|
||||
GetWindowRect(hwnd, &windowed_position);
|
||||
|
||||
int w = GetSystemMetrics(SM_CXSCREEN);
|
||||
int h = GetSystemMetrics(SM_CYSCREEN);
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
SetWindowPos(hwnd, HWND_TOP, 0, 0, w, h, 0);
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
|
||||
SetWindowPos(hwnd, HWND_TOP,
|
||||
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)
|
||||
|
|
|
@ -32,6 +32,9 @@ namespace Blah
|
|||
// Called after renderings ends
|
||||
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.
|
||||
// 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; }
|
||||
|
|
|
@ -932,7 +932,8 @@ namespace Blah
|
|||
|
||||
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");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user