mirror of
				https://github.com/NoelFB/blah.git
				synced 2025-11-04 01:41:34 +08:00 
			
		
		
		
	added App flags, implemented v-sync and fixed timestep flags
This commit is contained in:
		
							
								
								
									
										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");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user