mirror of
				https://github.com/NoelFB/blah.git
				synced 2025-11-04 01:41:34 +08:00 
			
		
		
		
	Refactored Platform into a struct to hold global state better
This commit is contained in:
		
							
								
								
									
										290
									
								
								src/app.cpp
									
									
									
									
									
								
							
							
						
						
									
										290
									
								
								src/app.cpp
									
									
									
									
									
								
							@ -2,9 +2,9 @@
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <blah/time.h>
 | 
			
		||||
#include <blah/graphics/target.h>
 | 
			
		||||
#include "internal/internal.h"
 | 
			
		||||
#include "internal/platform.h"
 | 
			
		||||
#include "internal/renderer.h"
 | 
			
		||||
#include "internal/input.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
#include <emscripten.h>
 | 
			
		||||
@ -15,86 +15,14 @@ using namespace Blah;
 | 
			
		||||
 | 
			
		||||
#define BLAH_ASSERT_RUNNING() BLAH_ASSERT(app_is_running, "The App is not running (call App::run)")
 | 
			
		||||
 | 
			
		||||
// Interal Platform Pointer
 | 
			
		||||
Platform* App::Internal::platform = nullptr;
 | 
			
		||||
 | 
			
		||||
// Internal Renderer Pointer
 | 
			
		||||
Renderer* App::Internal::renderer = nullptr;
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
	Config app_config;
 | 
			
		||||
	bool app_is_running = false;
 | 
			
		||||
	bool app_is_exiting = false;
 | 
			
		||||
	u64 app_time_last;
 | 
			
		||||
	u64 app_time_accumulator = 0;
 | 
			
		||||
 | 
			
		||||
	void app_iterate()
 | 
			
		||||
	{
 | 
			
		||||
		// update at a fixed timerate
 | 
			
		||||
		// TODO: allow a non-fixed step update?
 | 
			
		||||
		{
 | 
			
		||||
			u64 time_target = (u64)((1.0 / app_config.target_framerate) * Time::ticks_per_second);
 | 
			
		||||
			u64 time_curr = Platform::ticks();
 | 
			
		||||
			u64 time_diff = time_curr - app_time_last;
 | 
			
		||||
			app_time_last = time_curr;
 | 
			
		||||
			app_time_accumulator += time_diff;
 | 
			
		||||
 | 
			
		||||
			// do not let us run too fast
 | 
			
		||||
			while (app_time_accumulator < time_target)
 | 
			
		||||
			{
 | 
			
		||||
				int milliseconds = (int)(time_target - app_time_accumulator) / (Time::ticks_per_second / 1000);
 | 
			
		||||
				Platform::sleep(milliseconds);
 | 
			
		||||
 | 
			
		||||
				time_curr = Platform::ticks();
 | 
			
		||||
				time_diff = time_curr - app_time_last;
 | 
			
		||||
				app_time_last = time_curr;
 | 
			
		||||
				app_time_accumulator += time_diff;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Do not allow us to fall behind too many updates
 | 
			
		||||
			// (otherwise we'll get spiral of death)
 | 
			
		||||
			u64 time_maximum = app_config.max_updates * time_target;
 | 
			
		||||
			if (app_time_accumulator > time_maximum)
 | 
			
		||||
				app_time_accumulator = time_maximum;
 | 
			
		||||
 | 
			
		||||
			// do as many updates as we can
 | 
			
		||||
			while (app_time_accumulator >= time_target)
 | 
			
		||||
			{
 | 
			
		||||
				app_time_accumulator -= time_target;
 | 
			
		||||
 | 
			
		||||
				Time::delta = (1.0f / app_config.target_framerate);
 | 
			
		||||
 | 
			
		||||
				if (Time::pause_timer > 0)
 | 
			
		||||
				{
 | 
			
		||||
					Time::pause_timer -= Time::delta;
 | 
			
		||||
					if (Time::pause_timer <= -0.0001)
 | 
			
		||||
						Time::delta = -Time::pause_timer;
 | 
			
		||||
					else
 | 
			
		||||
						continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				Time::previous_ticks = Time::ticks;
 | 
			
		||||
				Time::ticks += time_target;
 | 
			
		||||
				Time::previous_seconds = Time::seconds;
 | 
			
		||||
				Time::seconds += Time::delta;
 | 
			
		||||
 | 
			
		||||
				Input::update_state();
 | 
			
		||||
				Platform::update(Input::state);
 | 
			
		||||
				Input::update_bindings();
 | 
			
		||||
				Renderer::instance->update();
 | 
			
		||||
 | 
			
		||||
				if (app_config.on_update != nullptr)
 | 
			
		||||
					app_config.on_update();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// render
 | 
			
		||||
		{
 | 
			
		||||
			Renderer::instance->before_render();
 | 
			
		||||
 | 
			
		||||
			if (app_config.on_render != nullptr)
 | 
			
		||||
				app_config.on_render();
 | 
			
		||||
 | 
			
		||||
			Renderer::instance->after_render();
 | 
			
		||||
			Platform::present();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// A dummy Frame Buffer that represents the Back Buffer
 | 
			
		||||
	// it doesn't actually contain any textures or details.
 | 
			
		||||
	class BackBuffer final : public Target
 | 
			
		||||
@ -103,15 +31,24 @@ namespace
 | 
			
		||||
		Attachments empty_textures;
 | 
			
		||||
		Attachments& textures() override { BLAH_ASSERT(false, "Backbuffer doesn't have any textures"); return empty_textures; }
 | 
			
		||||
		const Attachments& textures() const override { BLAH_ASSERT(false, "Backbuffer doesn't have any textures"); return empty_textures; }
 | 
			
		||||
		int width() const override { int w, h; Platform::get_draw_size(&w, &h); return w; }
 | 
			
		||||
		int height() const override { int w, h; Platform::get_draw_size(&w, &h); return h; }
 | 
			
		||||
		int width() const override {
 | 
			
		||||
			int w, h; App::Internal::platform->get_draw_size(&w, &h); return w;
 | 
			
		||||
		}
 | 
			
		||||
		int height() const override { int w, h; App::Internal::platform->get_draw_size(&w, &h); return h; }
 | 
			
		||||
		void clear(Color color, float depth, u8 stencil, ClearMask mask) override
 | 
			
		||||
		{
 | 
			
		||||
			BLAH_ASSERT_RENDERER();
 | 
			
		||||
			if (Renderer::instance) Renderer::instance->clear_backbuffer(color, depth, stencil, mask);
 | 
			
		||||
			if (App::Internal::renderer)
 | 
			
		||||
				App::Internal::renderer->clear_backbuffer(color, depth, stencil, mask);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Global App State
 | 
			
		||||
	Config app_config;
 | 
			
		||||
	bool app_is_running = false;
 | 
			
		||||
	bool app_is_exiting = false;
 | 
			
		||||
	u64 app_time_last;
 | 
			
		||||
	u64 app_time_accumulator = 0;
 | 
			
		||||
	TargetRef app_backbuffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -136,8 +73,12 @@ bool App::run(const Config* c)
 | 
			
		||||
	BLAH_ASSERT(c->width > 0 && c->height > 0, "The Width and Height must be larget than 0");
 | 
			
		||||
	BLAH_ASSERT(c->max_updates > 0, "Max Updates must be >= 1");
 | 
			
		||||
	BLAH_ASSERT(c->target_framerate > 0, "Target Framerate must be >= 1");
 | 
			
		||||
 | 
			
		||||
	if (app_is_running || c == nullptr || c->width <= 0 || c->height <= 0 || c->max_updates <= 0 || c->target_framerate <= 0)
 | 
			
		||||
	{
 | 
			
		||||
		App::Internal::shutdown();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// default values
 | 
			
		||||
	app_is_running = true;
 | 
			
		||||
@ -145,81 +86,176 @@ bool App::run(const Config* c)
 | 
			
		||||
	app_backbuffer = TargetRef(new BackBuffer());
 | 
			
		||||
 | 
			
		||||
	// initialize the system
 | 
			
		||||
	if (!Platform::init(app_config))
 | 
			
		||||
	Internal::platform = Platform::try_make_platform(app_config);
 | 
			
		||||
	if (!Internal::platform)
 | 
			
		||||
	{
 | 
			
		||||
		Log::error("Failed to create Platform module");
 | 
			
		||||
		App::Internal::shutdown();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!Internal::platform->init(app_config))
 | 
			
		||||
	{
 | 
			
		||||
		Log::error("Failed to initialize Platform module");
 | 
			
		||||
		App::Internal::shutdown();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// initialize graphics
 | 
			
		||||
	Internal::renderer = Renderer::try_make_renderer(app_config.renderer_type);
 | 
			
		||||
	if (Internal::renderer == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		// instantiate
 | 
			
		||||
		Renderer::instance = Renderer::try_make_renderer(app_config.renderer_type);
 | 
			
		||||
		Log::error("Renderer module was not found");
 | 
			
		||||
		App::Internal::shutdown();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		// wasn't able to make any
 | 
			
		||||
		if (Renderer::instance == nullptr)
 | 
			
		||||
		{
 | 
			
		||||
			Log::error("Renderer implementation was not found");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!Renderer::instance->init())
 | 
			
		||||
		{
 | 
			
		||||
			Log::error("Renderer failed to initialize");
 | 
			
		||||
			delete Renderer::instance;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	if (!Internal::renderer->init())
 | 
			
		||||
	{
 | 
			
		||||
		Log::error("Failed to initialize Renderer module");
 | 
			
		||||
		App::Internal::shutdown();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// input
 | 
			
		||||
	Input::init();
 | 
			
		||||
	Input::Internal::init();
 | 
			
		||||
 | 
			
		||||
	// prepare by updating input & platform once
 | 
			
		||||
	Input::update_state();
 | 
			
		||||
	Platform::update(Input::state);
 | 
			
		||||
	Input::Internal::update_state();
 | 
			
		||||
	Internal::platform->update(Input::state);
 | 
			
		||||
 | 
			
		||||
	// startup
 | 
			
		||||
	if (app_config.on_startup != nullptr)
 | 
			
		||||
		app_config.on_startup();
 | 
			
		||||
 | 
			
		||||
	app_time_last = Platform::ticks();
 | 
			
		||||
	app_time_last = Internal::platform->ticks();
 | 
			
		||||
	app_time_accumulator = 0;
 | 
			
		||||
 | 
			
		||||
	// display window
 | 
			
		||||
	Platform::ready();
 | 
			
		||||
	Internal::platform->ready();
 | 
			
		||||
 | 
			
		||||
	// Begin main loop
 | 
			
		||||
	// Emscripten requires the main loop be separated into its own call
 | 
			
		||||
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
	emscripten_set_main_loop(app_iterate, 0, 1);
 | 
			
		||||
	emscripten_set_main_loop(App::Internal::iterate, 0, 1);
 | 
			
		||||
#else
 | 
			
		||||
	while (!app_is_exiting)
 | 
			
		||||
		app_iterate();
 | 
			
		||||
		App::Internal::iterate();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	// shutdown
 | 
			
		||||
	if (app_config.on_shutdown != nullptr)
 | 
			
		||||
		app_config.on_shutdown();
 | 
			
		||||
 | 
			
		||||
	Renderer::instance->shutdown();
 | 
			
		||||
	Platform::shutdown();
 | 
			
		||||
	App::Internal::shutdown();
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	delete Renderer::instance;
 | 
			
		||||
	Renderer::instance = nullptr;
 | 
			
		||||
void App::Internal::iterate()
 | 
			
		||||
{
 | 
			
		||||
	// update at a fixed timerate
 | 
			
		||||
	// TODO: allow a non-fixed step update?
 | 
			
		||||
	{
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
	// clear static state
 | 
			
		||||
		// do not let us run too fast
 | 
			
		||||
		while (app_time_accumulator < time_target)
 | 
			
		||||
		{
 | 
			
		||||
			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;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Do not allow us to fall behind too many updates
 | 
			
		||||
		// (otherwise we'll get spiral of death)
 | 
			
		||||
		u64 time_maximum = app_config.max_updates * time_target;
 | 
			
		||||
		if (app_time_accumulator > time_maximum)
 | 
			
		||||
			app_time_accumulator = time_maximum;
 | 
			
		||||
 | 
			
		||||
		// do as many updates as we can
 | 
			
		||||
		while (app_time_accumulator >= time_target)
 | 
			
		||||
		{
 | 
			
		||||
			app_time_accumulator -= time_target;
 | 
			
		||||
 | 
			
		||||
			Time::delta = (1.0f / app_config.target_framerate);
 | 
			
		||||
 | 
			
		||||
			if (Time::pause_timer > 0)
 | 
			
		||||
			{
 | 
			
		||||
				Time::pause_timer -= Time::delta;
 | 
			
		||||
				if (Time::pause_timer <= -0.0001)
 | 
			
		||||
					Time::delta = -Time::pause_timer;
 | 
			
		||||
				else
 | 
			
		||||
					continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Time::previous_ticks = Time::ticks;
 | 
			
		||||
			Time::ticks += time_target;
 | 
			
		||||
			Time::previous_seconds = Time::seconds;
 | 
			
		||||
			Time::seconds += Time::delta;
 | 
			
		||||
 | 
			
		||||
			Input::Internal::update_state();
 | 
			
		||||
			platform->update(Input::state);
 | 
			
		||||
			Input::Internal::update_bindings();
 | 
			
		||||
			renderer->update();
 | 
			
		||||
 | 
			
		||||
			if (app_config.on_update != nullptr)
 | 
			
		||||
				app_config.on_update();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// render
 | 
			
		||||
	{
 | 
			
		||||
		renderer->before_render();
 | 
			
		||||
 | 
			
		||||
		if (app_config.on_render != nullptr)
 | 
			
		||||
			app_config.on_render();
 | 
			
		||||
 | 
			
		||||
		renderer->after_render();
 | 
			
		||||
		platform->present();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void App::Internal::shutdown()
 | 
			
		||||
{
 | 
			
		||||
	Input::Internal::shutdown();
 | 
			
		||||
 | 
			
		||||
	if (renderer)
 | 
			
		||||
		renderer->shutdown();
 | 
			
		||||
 | 
			
		||||
	if (platform)
 | 
			
		||||
		platform->shutdown();
 | 
			
		||||
 | 
			
		||||
	if (renderer)
 | 
			
		||||
		delete renderer;
 | 
			
		||||
	renderer = nullptr;
 | 
			
		||||
 | 
			
		||||
	if (platform)
 | 
			
		||||
		delete platform;
 | 
			
		||||
	platform = nullptr;
 | 
			
		||||
 | 
			
		||||
	// clear static App state
 | 
			
		||||
	app_config = Config();
 | 
			
		||||
	app_is_running = false;
 | 
			
		||||
	app_is_exiting = false;
 | 
			
		||||
	app_time_last = 0;
 | 
			
		||||
	app_time_accumulator = 0;
 | 
			
		||||
	app_backbuffer = TargetRef();
 | 
			
		||||
 | 
			
		||||
	// clear static Time state
 | 
			
		||||
	Time::ticks = 0;
 | 
			
		||||
	Time::seconds = 0;
 | 
			
		||||
	Time::previous_ticks = 0;
 | 
			
		||||
	Time::previous_seconds = 0;
 | 
			
		||||
	Time::delta = 0;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void App::exit()
 | 
			
		||||
@ -238,59 +274,59 @@ const Config& App::config()
 | 
			
		||||
const char* App::path()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	return Platform::app_path();
 | 
			
		||||
	return Internal::platform->app_path();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char* App::user_path()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	return Platform::user_path();
 | 
			
		||||
	return Internal::platform->user_path();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char* App::get_title()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	return Platform::get_title();
 | 
			
		||||
	return Internal::platform->get_title();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void App::set_title(const char* title)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	Platform::set_title(title);
 | 
			
		||||
	Internal::platform->set_title(title);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Point App::get_position()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	Point result;
 | 
			
		||||
	Platform::get_position(&result.x, &result.y);
 | 
			
		||||
	Internal::platform->get_position(&result.x, &result.y);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void App::set_position(Point point)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	Platform::set_position(point.x, point.y);
 | 
			
		||||
	Internal::platform->set_position(point.x, point.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Point App::get_size()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	Point result;
 | 
			
		||||
	Platform::get_size(&result.x, &result.y);
 | 
			
		||||
	Internal::platform->get_size(&result.x, &result.y);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void App::set_size(Point point)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	Platform::set_size(point.x, point.y);
 | 
			
		||||
	Internal::platform->set_size(point.x, point.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Point App::get_backbuffer_size()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	if (Renderer::instance)
 | 
			
		||||
	if (Internal::renderer)
 | 
			
		||||
		return Point(app_backbuffer->width(), app_backbuffer->height());
 | 
			
		||||
	return Point(0, 0);
 | 
			
		||||
}
 | 
			
		||||
@ -298,26 +334,26 @@ Point App::get_backbuffer_size()
 | 
			
		||||
float App::content_scale()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	return Platform::get_content_scale();
 | 
			
		||||
	return Internal::platform->get_content_scale();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool App::focused()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	return Platform::get_focused();
 | 
			
		||||
	return Internal::platform->get_focused();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void App::fullscreen(bool enabled)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	Platform::set_fullscreen(enabled);
 | 
			
		||||
	Internal::platform->set_fullscreen(enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const RendererFeatures& App::renderer()
 | 
			
		||||
const RendererInfo& App::renderer()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	return Renderer::instance->features;
 | 
			
		||||
	return Internal::renderer->info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const TargetRef& App::backbuffer()
 | 
			
		||||
@ -329,5 +365,5 @@ const TargetRef& App::backbuffer()
 | 
			
		||||
void System::open_url(const char* url)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RUNNING();
 | 
			
		||||
	Platform::open_url(url);
 | 
			
		||||
	App::Internal::platform->open_url(url);
 | 
			
		||||
}
 | 
			
		||||
@ -1,56 +1,78 @@
 | 
			
		||||
#include <blah/filesystem.h>
 | 
			
		||||
#include <blah/streams/filestream.h>
 | 
			
		||||
#include "internal/platform.h"
 | 
			
		||||
#include "internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
FileRef File::open(const FilePath& path, FileMode mode)
 | 
			
		||||
{
 | 
			
		||||
	return Platform::file_open(path.cstr(), mode);
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		return App::Internal::platform->file_open(path.cstr(), mode);
 | 
			
		||||
	return FileRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool File::exists(const FilePath& path)
 | 
			
		||||
{
 | 
			
		||||
	return Platform::file_exists(path.cstr());
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		return App::Internal::platform->file_exists(path.cstr());
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool File::destroy(const FilePath& path)
 | 
			
		||||
{
 | 
			
		||||
	return Platform::file_delete(path.cstr());
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		return App::Internal::platform->file_delete(path.cstr());
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Directory::create(const FilePath& path)
 | 
			
		||||
{
 | 
			
		||||
	return Platform::dir_create(path.cstr());
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		return App::Internal::platform->dir_create(path.cstr());
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Directory::exists(const FilePath& path)
 | 
			
		||||
{
 | 
			
		||||
	return Platform::dir_exists(path.cstr());
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		return App::Internal::platform->dir_exists(path.cstr());
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Directory::destroy(const FilePath& path)
 | 
			
		||||
{
 | 
			
		||||
	return Platform::dir_delete(path.cstr());
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		return App::Internal::platform->dir_delete(path.cstr());
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Vector<FilePath> Directory::enumerate(const FilePath& path, bool recursive)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
 | 
			
		||||
	Vector<FilePath> list;
 | 
			
		||||
 | 
			
		||||
	// get files
 | 
			
		||||
	Platform::dir_enumerate(list, path.cstr(), recursive);
 | 
			
		||||
 | 
			
		||||
	// normalize path names
 | 
			
		||||
	for (auto& it : list)
 | 
			
		||||
		it.replace('\\', '/');
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
	{
 | 
			
		||||
		App::Internal::platform->dir_enumerate(list, path.cstr(), recursive);
 | 
			
		||||
		for (auto& it : list)
 | 
			
		||||
			it.replace('\\', '/');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Directory::explore(const FilePath& path)
 | 
			
		||||
{
 | 
			
		||||
	Platform::dir_explore(path);
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		App::Internal::platform->dir_explore(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FilePath Path::get_file_name(const FilePath& path)
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
#include <blah/graphics/material.h>
 | 
			
		||||
#include <blah/math/calc.h>
 | 
			
		||||
#include <blah/app.h>
 | 
			
		||||
#include "../internal/renderer.h"
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
@ -288,7 +288,7 @@ void Batch::render(const TargetRef& target, const Mat4x4f& matrix)
 | 
			
		||||
		if (!m_default_material)
 | 
			
		||||
		{
 | 
			
		||||
			BLAH_ASSERT_RENDERER();
 | 
			
		||||
			m_default_material = Material::create(Renderer::instance->default_batcher_shader);
 | 
			
		||||
			m_default_material = Material::create(App::Internal::renderer->default_batcher_shader);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#include <blah/graphics/mesh.h>
 | 
			
		||||
#include "../internal/renderer.h"
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -7,8 +7,8 @@ MeshRef Mesh::create()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
 | 
			
		||||
	if (Renderer::instance)
 | 
			
		||||
		return Renderer::instance->create_mesh();
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		return App::Internal::renderer->create_mesh();
 | 
			
		||||
 | 
			
		||||
	return MeshRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
#include <blah/graphics/renderpass.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include "../internal/renderer.h"
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ void RenderPass::perform()
 | 
			
		||||
	BLAH_ASSERT(material->shader(), "Trying to draw with an invalid Shader");
 | 
			
		||||
	BLAH_ASSERT(mesh, "Trying to draw with an invalid Mesh");
 | 
			
		||||
 | 
			
		||||
	if (!Renderer::instance)
 | 
			
		||||
	if (!App::Internal::renderer)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// copy call
 | 
			
		||||
@ -90,5 +90,5 @@ void RenderPass::perform()
 | 
			
		||||
		pass.scissor = pass.scissor.overlap_rect(Rectf(0, 0, draw_size.x, draw_size.y));
 | 
			
		||||
 | 
			
		||||
	// perform render
 | 
			
		||||
	Renderer::instance->render(pass);
 | 
			
		||||
	App::Internal::renderer->render(pass);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
#include <blah/graphics/shader.h>
 | 
			
		||||
#include <blah/app.h>
 | 
			
		||||
#include "../internal/renderer.h"
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -13,8 +13,8 @@ ShaderRef Shader::create(const ShaderData& data)
 | 
			
		||||
 | 
			
		||||
	ShaderRef shader;
 | 
			
		||||
 | 
			
		||||
	if (Renderer::instance)
 | 
			
		||||
		shader = Renderer::instance->create_shader(&data);
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		shader = App::Internal::renderer->create_shader(&data);
 | 
			
		||||
	
 | 
			
		||||
	// validate the shader
 | 
			
		||||
	if (shader)
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#include <blah/graphics/target.h>
 | 
			
		||||
#include "../internal/renderer.h"
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -32,8 +32,8 @@ TargetRef Target::create(int width, int height, const AttachmentFormats& texture
 | 
			
		||||
	BLAH_ASSERT(depth_count <= 1, "Target can only have 1 Depth/Stencil Texture");
 | 
			
		||||
	BLAH_ASSERT(color_count <= Attachments::capacity - 1, "Exceeded maximum Color texture count");
 | 
			
		||||
 | 
			
		||||
	if (Renderer::instance)
 | 
			
		||||
		return Renderer::instance->create_target(width, height, textures.data(), textures.size());
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		return App::Internal::renderer->create_target(width, height, textures.data(), textures.size());
 | 
			
		||||
 | 
			
		||||
	return TargetRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
#include <blah/images/image.h>
 | 
			
		||||
#include <blah/streams/stream.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include "../internal/renderer.h"
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -17,9 +17,9 @@ TextureRef Texture::create(int width, int height, TextureFormat format, unsigned
 | 
			
		||||
	BLAH_ASSERT(width > 0 && height > 0, "Texture width and height must be larger than 0");
 | 
			
		||||
	BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format");
 | 
			
		||||
 | 
			
		||||
	if (Renderer::instance)
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
	{
 | 
			
		||||
		auto tex = Renderer::instance->create_texture(width, height, format);
 | 
			
		||||
		auto tex = App::Internal::renderer->create_texture(width, height, format);
 | 
			
		||||
 | 
			
		||||
		if (tex && data != nullptr)
 | 
			
		||||
			tex->set_data(data);
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
#include <blah/time.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <blah/math/calc.h>
 | 
			
		||||
#include "internal/input.h"
 | 
			
		||||
#include "internal/internal.h"
 | 
			
		||||
#include "internal/platform.h"
 | 
			
		||||
#include <blah/graphics/target.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
@ -26,7 +26,7 @@ InputState Blah::Input::last_state;
 | 
			
		||||
float Blah::Input::repeat_delay = 0.35f;
 | 
			
		||||
float Blah::Input::repeat_interval = 0.025f;
 | 
			
		||||
 | 
			
		||||
void Input::init()
 | 
			
		||||
void Input::Internal::init()
 | 
			
		||||
{
 | 
			
		||||
	g_empty_controller.name = "Disconnected";
 | 
			
		||||
	for (int i = 0; i < Input::max_controllers; i++)
 | 
			
		||||
@ -39,7 +39,12 @@ void Input::init()
 | 
			
		||||
	g_sticks.dispose();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Input::update_state()
 | 
			
		||||
void Input::Internal::shutdown()
 | 
			
		||||
{
 | 
			
		||||
	init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Input::Internal::update_state()
 | 
			
		||||
{
 | 
			
		||||
	// cycle states
 | 
			
		||||
	Input::last_state = Input::state;
 | 
			
		||||
@ -75,10 +80,11 @@ void Input::update_state()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get clipboard
 | 
			
		||||
	g_clipboard = Platform::get_clipboard();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		g_clipboard = App::Internal::platform->get_clipboard();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Input::update_bindings()
 | 
			
		||||
void Input::Internal::update_bindings()
 | 
			
		||||
{
 | 
			
		||||
	for (int i = 0; i < g_buttons.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
@ -394,7 +400,8 @@ const String& Input::get_clipboard()
 | 
			
		||||
void Input::set_clipboard(const String& text)
 | 
			
		||||
{
 | 
			
		||||
	g_clipboard = text;
 | 
			
		||||
	return Platform::set_clipboard(text);
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		App::Internal::platform->set_clipboard(text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ButtonBindingRef Input::register_binding(const ButtonBinding& binding)
 | 
			
		||||
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <blah/input.h>
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	namespace Input
 | 
			
		||||
	{
 | 
			
		||||
		// Initializes the Input State
 | 
			
		||||
		void init();
 | 
			
		||||
 | 
			
		||||
		// Steps the input state
 | 
			
		||||
		void update_state();
 | 
			
		||||
 | 
			
		||||
		// Updates bindings
 | 
			
		||||
		void update_bindings();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								src/internal/internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/internal/internal.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "renderer.h"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
 | 
			
		||||
#define BLAH_ASSERT_RENDERER() BLAH_ASSERT(App::Internal::renderer, "Renderer has not been created")
 | 
			
		||||
#define BLAH_ASSERT_PLATFORM() BLAH_ASSERT(App::Internal::platform, "Platform has not been created")
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	namespace App
 | 
			
		||||
	{
 | 
			
		||||
		namespace Internal
 | 
			
		||||
		{
 | 
			
		||||
			extern Platform* platform;
 | 
			
		||||
			extern Renderer* renderer;
 | 
			
		||||
 | 
			
		||||
			void iterate();
 | 
			
		||||
			void shutdown();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	namespace Input
 | 
			
		||||
	{
 | 
			
		||||
		namespace Internal
 | 
			
		||||
		{
 | 
			
		||||
			// Initializes the Input State
 | 
			
		||||
			void init();
 | 
			
		||||
 | 
			
		||||
			// Steps the input state
 | 
			
		||||
			void update_state();
 | 
			
		||||
 | 
			
		||||
			// Updates bindings
 | 
			
		||||
			void update_bindings();
 | 
			
		||||
 | 
			
		||||
			// Clears Input State
 | 
			
		||||
			void shutdown();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -8,105 +8,110 @@ namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	struct Config;
 | 
			
		||||
 | 
			
		||||
	namespace Platform
 | 
			
		||||
	class Platform
 | 
			
		||||
	{
 | 
			
		||||
		// Initialize the System
 | 
			
		||||
		bool init(const Config& config);
 | 
			
		||||
	public:
 | 
			
		||||
 | 
			
		||||
		// Initialize the Graphics
 | 
			
		||||
		virtual bool init(const Config& config) = 0;
 | 
			
		||||
 | 
			
		||||
		// Called after the on_startup callback, but before the update loop begins
 | 
			
		||||
		void ready();
 | 
			
		||||
		virtual void ready() = 0;
 | 
			
		||||
 | 
			
		||||
		// Called during shutdown
 | 
			
		||||
		void shutdown();
 | 
			
		||||
		virtual void shutdown() = 0;
 | 
			
		||||
 | 
			
		||||
		// The time, in ticks (microseconds) since the Application was started
 | 
			
		||||
		u64 ticks();
 | 
			
		||||
		virtual u64 ticks() = 0;
 | 
			
		||||
 | 
			
		||||
		// Called every frame
 | 
			
		||||
		void update(InputState& state);
 | 
			
		||||
		virtual void update(InputState& state) = 0;
 | 
			
		||||
 | 
			
		||||
		// Sleeps the current thread
 | 
			
		||||
		void sleep(int milliseconds);
 | 
			
		||||
		virtual void sleep(int milliseconds) = 0;
 | 
			
		||||
 | 
			
		||||
		// Called to present the window contents
 | 
			
		||||
		void present();
 | 
			
		||||
		virtual void present() = 0;
 | 
			
		||||
 | 
			
		||||
		// Gets the Application Window Title in UTF-8
 | 
			
		||||
		const char* get_title();
 | 
			
		||||
		virtual const char* get_title() = 0;
 | 
			
		||||
 | 
			
		||||
		// Sets the Application Window Title in UTF-8
 | 
			
		||||
		void set_title(const char* title);
 | 
			
		||||
		virtual void set_title(const char* title) = 0;
 | 
			
		||||
 | 
			
		||||
		// Gets the Application Window Position, in Screen Coordinates
 | 
			
		||||
		void get_position(int* x, int* y);
 | 
			
		||||
		virtual void get_position(int* x, int* y) = 0;
 | 
			
		||||
 | 
			
		||||
		// Sets the Application Window Position, in Screen Coordinates
 | 
			
		||||
		void set_position(int x, int y);
 | 
			
		||||
		virtual void set_position(int x, int y) = 0;
 | 
			
		||||
		
 | 
			
		||||
		// Gets whether the Window has focus
 | 
			
		||||
		bool get_focused();
 | 
			
		||||
		virtual bool get_focused() = 0;
 | 
			
		||||
 | 
			
		||||
		// Sets the Window Fullscreen if enabled is not 0
 | 
			
		||||
		void set_fullscreen(bool enabled);
 | 
			
		||||
		virtual void set_fullscreen(bool enabled) = 0;
 | 
			
		||||
 | 
			
		||||
		// Gets the Application Window Size, in Screen Coordinates
 | 
			
		||||
		void get_size(int* width, int* height);
 | 
			
		||||
		virtual void get_size(int* width, int* height) = 0;
 | 
			
		||||
 | 
			
		||||
		// Sets the Application Window Size, in Screen Coordinates
 | 
			
		||||
		void set_size(int width, int height);
 | 
			
		||||
		virtual void set_size(int width, int height) = 0;
 | 
			
		||||
 | 
			
		||||
		// Gets the Application Window Drawing Size, in Pixels. This may differ from the Window Size on hi-dpi displays.
 | 
			
		||||
		void get_draw_size(int* width, int* height);
 | 
			
		||||
		virtual void get_draw_size(int* width, int* height) = 0;
 | 
			
		||||
 | 
			
		||||
		// Gets the Desktop Content Scale. Gui should be scaled by this value
 | 
			
		||||
		float get_content_scale();
 | 
			
		||||
		virtual float get_content_scale() = 0;
 | 
			
		||||
 | 
			
		||||
		// Returns the absoluate path to the directory that the application was started from
 | 
			
		||||
		const char* app_path();
 | 
			
		||||
		virtual const char* app_path() = 0;
 | 
			
		||||
 | 
			
		||||
		// Returns the absolute path to the user directory where save data and settings should be stored
 | 
			
		||||
		const char* user_path();
 | 
			
		||||
		virtual const char* user_path() = 0;
 | 
			
		||||
 | 
			
		||||
		// Opens a file and sets the handle, or returns an empty handle if it fails
 | 
			
		||||
		FileRef file_open(const char* path, FileMode mode);
 | 
			
		||||
		virtual FileRef file_open(const char* path, FileMode mode) = 0;
 | 
			
		||||
 | 
			
		||||
		// Returns true if a file with the given path exists
 | 
			
		||||
		bool file_exists(const char* path);
 | 
			
		||||
		virtual bool file_exists(const char* path) = 0;
 | 
			
		||||
 | 
			
		||||
		// Returns true if a file with the given path was deleted
 | 
			
		||||
		bool file_delete(const char* path);
 | 
			
		||||
		virtual bool file_delete(const char* path) = 0;
 | 
			
		||||
 | 
			
		||||
		// Returns true if a directory with the given path was successfully created
 | 
			
		||||
		bool dir_create(const char* path);
 | 
			
		||||
		virtual bool dir_create(const char* path) = 0;
 | 
			
		||||
 | 
			
		||||
		// Returns true if a directory with the given path exists
 | 
			
		||||
		bool dir_exists(const char* path);
 | 
			
		||||
		virtual bool dir_exists(const char* path) = 0;
 | 
			
		||||
 | 
			
		||||
		// Returns true if a directory with the given path was deleted
 | 
			
		||||
		bool dir_delete(const char* path);
 | 
			
		||||
		virtual bool dir_delete(const char* path) = 0;
 | 
			
		||||
 | 
			
		||||
		// enumerates a directory and appends each file to the given list
 | 
			
		||||
		void dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive);
 | 
			
		||||
		virtual void dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive) = 0;
 | 
			
		||||
 | 
			
		||||
		// opens a directory in the OS file explorer / finder
 | 
			
		||||
		void dir_explore(const char* path);
 | 
			
		||||
		virtual void dir_explore(const char* path) = 0;
 | 
			
		||||
 | 
			
		||||
		// sets the contents of the clipboard
 | 
			
		||||
		void set_clipboard(const char* text);
 | 
			
		||||
		virtual void set_clipboard(const char* text) = 0;
 | 
			
		||||
 | 
			
		||||
		// gets the contents of the clipboard into the given string
 | 
			
		||||
		const char* get_clipboard();
 | 
			
		||||
		virtual const char* get_clipboard() = 0;
 | 
			
		||||
 | 
			
		||||
		// Tries to open a URL in a web browser
 | 
			
		||||
		void open_url(const char* url);
 | 
			
		||||
		virtual void open_url(const char* url) = 0;
 | 
			
		||||
 | 
			
		||||
		// OpenGL Methods
 | 
			
		||||
		void* gl_get_func(const char* name);
 | 
			
		||||
		void* gl_context_create();
 | 
			
		||||
		void gl_context_make_current(void* context);
 | 
			
		||||
		void gl_context_destroy(void* context);
 | 
			
		||||
		virtual void* gl_get_func(const char* name) = 0;
 | 
			
		||||
		virtual void* gl_context_create() = 0;
 | 
			
		||||
		virtual void gl_context_make_current(void* context) = 0;
 | 
			
		||||
		virtual void gl_context_destroy(void* context) = 0;
 | 
			
		||||
 | 
			
		||||
		// D3D11 Methods
 | 
			
		||||
		void* d3d11_get_hwnd();
 | 
			
		||||
	}
 | 
			
		||||
		virtual void* d3d11_get_hwnd() = 0;
 | 
			
		||||
 | 
			
		||||
		// Instantiates the Platform object
 | 
			
		||||
		static Platform* try_make_platform(const Config& config);
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
#ifdef BLAH_PLATFORM_SDL2
 | 
			
		||||
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include "input.h"
 | 
			
		||||
#include "renderer.h"
 | 
			
		||||
#include <blah/input.h>
 | 
			
		||||
#include <blah/app.h>
 | 
			
		||||
@ -28,30 +27,6 @@
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	// Blah SDL2 Platform State
 | 
			
		||||
	struct SDL2Platform
 | 
			
		||||
	{
 | 
			
		||||
		SDL_Window* window = nullptr;
 | 
			
		||||
		SDL_Joystick* joysticks[Input::max_controllers];
 | 
			
		||||
		SDL_GameController* gamepads[Input::max_controllers];
 | 
			
		||||
		char* base_path = nullptr;
 | 
			
		||||
		char* user_path = nullptr;
 | 
			
		||||
		bool displayed = false;
 | 
			
		||||
	} g_platform;
 | 
			
		||||
 | 
			
		||||
	// Blah SDL2 File
 | 
			
		||||
	struct SDL2File : public File
 | 
			
		||||
	{
 | 
			
		||||
		SDL_RWops* handle;
 | 
			
		||||
		SDL2File(SDL_RWops* handle) : handle(handle) { }
 | 
			
		||||
		~SDL2File() { if (handle) SDL_RWclose(handle); }
 | 
			
		||||
		size_t length() override { return SDL_RWsize(handle); }
 | 
			
		||||
		size_t position() override { return SDL_RWtell(handle); }
 | 
			
		||||
		size_t seek(size_t position) override { return SDL_RWseek(handle, position, RW_SEEK_SET); }
 | 
			
		||||
		size_t read(unsigned char* buffer, size_t length) override { return SDL_RWread(handle, buffer, sizeof(char), length); }
 | 
			
		||||
		size_t write(const unsigned char* buffer, size_t length) override { return SDL_RWwrite(handle, buffer, sizeof(char), length); }
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void blah_sdl_log(void* userdata, int category, SDL_LogPriority priority, const char* message)
 | 
			
		||||
	{
 | 
			
		||||
		if (priority <= SDL_LOG_PRIORITY_INFO)
 | 
			
		||||
@ -83,14 +58,80 @@ namespace Blah
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct SDL2_File : public File
 | 
			
		||||
	{
 | 
			
		||||
		SDL_RWops* handle;
 | 
			
		||||
		SDL2_File(SDL_RWops* handle) : handle(handle) { }
 | 
			
		||||
		~SDL2_File() { if (handle) SDL_RWclose(handle); }
 | 
			
		||||
		size_t length() override { return SDL_RWsize(handle); }
 | 
			
		||||
		size_t position() override { return SDL_RWtell(handle); }
 | 
			
		||||
		size_t seek(size_t position) override { return SDL_RWseek(handle, position, RW_SEEK_SET); }
 | 
			
		||||
		size_t read(unsigned char* buffer, size_t length) override { return SDL_RWread(handle, buffer, sizeof(char), length); }
 | 
			
		||||
		size_t write(const unsigned char* buffer, size_t length) override { return SDL_RWwrite(handle, buffer, sizeof(char), length); }
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct SDL2_Platform : public Platform
 | 
			
		||||
	{
 | 
			
		||||
		SDL_Window* window = nullptr;
 | 
			
		||||
		SDL_Joystick* joysticks[Input::max_controllers];
 | 
			
		||||
		SDL_GameController* gamepads[Input::max_controllers];
 | 
			
		||||
		char* base_path_value = nullptr;
 | 
			
		||||
		char* user_path_value = nullptr;
 | 
			
		||||
		bool displayed = false;
 | 
			
		||||
 | 
			
		||||
		SDL2_Platform();
 | 
			
		||||
		bool init(const Config& config) override;
 | 
			
		||||
		void ready() override;
 | 
			
		||||
		void shutdown() override;
 | 
			
		||||
		u64 ticks() override;
 | 
			
		||||
		void update(InputState& state) override;
 | 
			
		||||
		void sleep(int milliseconds) override;
 | 
			
		||||
		void present() 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;
 | 
			
		||||
		float get_content_scale() override;
 | 
			
		||||
		const char* app_path() override;
 | 
			
		||||
		const char* user_path() override;
 | 
			
		||||
		FileRef file_open(const char* path, FileMode mode) override;
 | 
			
		||||
		bool file_exists(const char* path) override;
 | 
			
		||||
		bool file_delete(const char* path) override;
 | 
			
		||||
		bool dir_create(const char* path) override;
 | 
			
		||||
		bool dir_exists(const char* path) override;
 | 
			
		||||
		bool dir_delete(const char* path) override;
 | 
			
		||||
		void dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive) override;
 | 
			
		||||
		void dir_explore(const char* path) override;
 | 
			
		||||
		void set_clipboard(const char* text) override;
 | 
			
		||||
		const char* get_clipboard() override;
 | 
			
		||||
		void open_url(const char* url) override;
 | 
			
		||||
		void* gl_get_func(const char* name) override;
 | 
			
		||||
		void* gl_context_create() override;
 | 
			
		||||
		void gl_context_make_current(void* context) override;
 | 
			
		||||
		void gl_context_destroy(void* context) override;
 | 
			
		||||
		void* d3d11_get_hwnd() override;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
bool Platform::init(const Config& config)
 | 
			
		||||
SDL2_Platform::SDL2_Platform()
 | 
			
		||||
{
 | 
			
		||||
	g_platform = SDL2Platform();
 | 
			
		||||
	for (int i = 0; i < Input::max_controllers; i++)
 | 
			
		||||
	{
 | 
			
		||||
		joysticks[i] = nullptr;
 | 
			
		||||
		gamepads[i] = nullptr;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SDL2_Platform::init(const Config& config)
 | 
			
		||||
{
 | 
			
		||||
	// Required to call this for Windows
 | 
			
		||||
	// I'm not sure why SDL2 doesn't do this on Windows automatically?
 | 
			
		||||
#if _WIN32
 | 
			
		||||
@ -141,8 +182,8 @@ bool Platform::init(const Config& config)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// create the window
 | 
			
		||||
	g_platform.window = SDL_CreateWindow(config.name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config.width, config.height, flags);
 | 
			
		||||
	if (g_platform.window == nullptr)
 | 
			
		||||
	window = SDL_CreateWindow(config.name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config.width, config.height, flags);
 | 
			
		||||
	if (window == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		Log::error("Failed to create a Window");
 | 
			
		||||
		return false;
 | 
			
		||||
@ -153,7 +194,7 @@ bool Platform::init(const Config& config)
 | 
			
		||||
#if _WIN32
 | 
			
		||||
	{
 | 
			
		||||
		// find the display index
 | 
			
		||||
		int display = SDL_GetWindowDisplayIndex(g_platform.window);
 | 
			
		||||
		int display = SDL_GetWindowDisplayIndex(window);
 | 
			
		||||
		float ddpi, hdpi, vdpi;
 | 
			
		||||
		if (SDL_GetDisplayDPI(display, &ddpi, &hdpi, &vdpi) == 0)
 | 
			
		||||
		{
 | 
			
		||||
@ -164,21 +205,21 @@ bool Platform::init(const Config& config)
 | 
			
		||||
			{
 | 
			
		||||
				SDL_DisplayMode mode;
 | 
			
		||||
				SDL_GetDesktopDisplayMode(display, &mode);
 | 
			
		||||
				SDL_SetWindowPosition(g_platform.window, (int)(mode.w - config.width * dpi) / 2, (int)(mode.h - config.height * dpi) / 2);
 | 
			
		||||
				SDL_SetWindowSize(g_platform.window, (int)(config.width * dpi), (int)(config.height * dpi));
 | 
			
		||||
				SDL_SetWindowPosition(window, (int)(mode.w - config.width * dpi) / 2, (int)(mode.h - config.height * dpi) / 2);
 | 
			
		||||
				SDL_SetWindowSize(window, (int)(config.width * dpi), (int)(config.height * dpi));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	// set window properties
 | 
			
		||||
	SDL_SetWindowResizable(g_platform.window, SDL_TRUE);
 | 
			
		||||
	SDL_SetWindowMinimumSize(g_platform.window, 256, 256);
 | 
			
		||||
	SDL_SetWindowResizable(window, SDL_TRUE);
 | 
			
		||||
	SDL_SetWindowMinimumSize(window, 256, 256);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::ready()
 | 
			
		||||
void SDL2_Platform::ready()
 | 
			
		||||
{
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
	// enable V-Sync
 | 
			
		||||
@ -189,36 +230,36 @@ void Platform::ready()
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::shutdown()
 | 
			
		||||
void SDL2_Platform::shutdown()
 | 
			
		||||
{
 | 
			
		||||
	if (g_platform.window != nullptr)
 | 
			
		||||
		SDL_DestroyWindow(g_platform.window);
 | 
			
		||||
	g_platform.window = nullptr;
 | 
			
		||||
	g_platform.displayed = false;
 | 
			
		||||
	if (window != nullptr)
 | 
			
		||||
		SDL_DestroyWindow(window);
 | 
			
		||||
	window = nullptr;
 | 
			
		||||
	displayed = false;
 | 
			
		||||
 | 
			
		||||
	if (g_platform.base_path != nullptr)
 | 
			
		||||
		SDL_free(g_platform.base_path);
 | 
			
		||||
	if (base_path_value != nullptr)
 | 
			
		||||
		SDL_free(base_path_value);
 | 
			
		||||
 | 
			
		||||
	if (g_platform.user_path != nullptr)
 | 
			
		||||
		SDL_free(g_platform.user_path);
 | 
			
		||||
	if (user_path_value != nullptr)
 | 
			
		||||
		SDL_free(user_path_value);
 | 
			
		||||
 | 
			
		||||
	SDL_Quit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u64 Platform::ticks()
 | 
			
		||||
u64 SDL2_Platform::ticks()
 | 
			
		||||
{
 | 
			
		||||
	auto counter = SDL_GetPerformanceCounter();
 | 
			
		||||
	auto per_second = (double)SDL_GetPerformanceFrequency();
 | 
			
		||||
	return (u64)(counter * (Time::ticks_per_second / per_second));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::update(InputState& state)
 | 
			
		||||
void SDL2_Platform::update(InputState& state)
 | 
			
		||||
{
 | 
			
		||||
	// update the mouse every frame
 | 
			
		||||
	{
 | 
			
		||||
		int win_x, win_y, x, y;
 | 
			
		||||
 | 
			
		||||
		SDL_GetWindowPosition(g_platform.window, &win_x, &win_y);
 | 
			
		||||
		SDL_GetWindowPosition(window, &win_x, &win_y);
 | 
			
		||||
		SDL_GetGlobalMouseState(&x, &y);
 | 
			
		||||
 | 
			
		||||
		state.mouse.on_move(
 | 
			
		||||
@ -287,7 +328,7 @@ void Platform::update(InputState& state)
 | 
			
		||||
 | 
			
		||||
			if (SDL_IsGameController(index) == SDL_FALSE && index >= 0 && index < Input::max_controllers)
 | 
			
		||||
			{
 | 
			
		||||
				auto ptr = g_platform.joysticks[index] = SDL_JoystickOpen(index);
 | 
			
		||||
				auto ptr = joysticks[index] = SDL_JoystickOpen(index);
 | 
			
		||||
				auto name = SDL_JoystickName(ptr);
 | 
			
		||||
				auto button_count = SDL_JoystickNumButtons(ptr);
 | 
			
		||||
				auto axis_count = SDL_JoystickNumAxes(ptr);
 | 
			
		||||
@ -300,19 +341,19 @@ void Platform::update(InputState& state)
 | 
			
		||||
		}
 | 
			
		||||
		else if (event.type == SDL_JOYDEVICEREMOVED)
 | 
			
		||||
		{
 | 
			
		||||
			auto index = blah_sdl_find_joystick_index(g_platform.joysticks, event.jdevice.which);
 | 
			
		||||
			auto index = blah_sdl_find_joystick_index(joysticks, event.jdevice.which);
 | 
			
		||||
			if (index >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				if (SDL_IsGameController(index) == SDL_FALSE)
 | 
			
		||||
				{
 | 
			
		||||
					state.controllers[index].on_disconnect();
 | 
			
		||||
					SDL_JoystickClose(g_platform.joysticks[index]);
 | 
			
		||||
					SDL_JoystickClose(joysticks[index]);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (event.type == SDL_JOYBUTTONDOWN)
 | 
			
		||||
		{
 | 
			
		||||
			auto index = blah_sdl_find_joystick_index(g_platform.joysticks, event.jdevice.which);
 | 
			
		||||
			auto index = blah_sdl_find_joystick_index(joysticks, event.jdevice.which);
 | 
			
		||||
			if (index >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				if (SDL_IsGameController(index) == SDL_FALSE)
 | 
			
		||||
@ -321,7 +362,7 @@ void Platform::update(InputState& state)
 | 
			
		||||
		}
 | 
			
		||||
		else if (event.type == SDL_JOYBUTTONUP)
 | 
			
		||||
		{
 | 
			
		||||
			auto index = blah_sdl_find_joystick_index(g_platform.joysticks, event.jdevice.which);
 | 
			
		||||
			auto index = blah_sdl_find_joystick_index(joysticks, event.jdevice.which);
 | 
			
		||||
			if (index >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				if (SDL_IsGameController(index) == SDL_FALSE)
 | 
			
		||||
@ -330,7 +371,7 @@ void Platform::update(InputState& state)
 | 
			
		||||
		}
 | 
			
		||||
		else if (event.type == SDL_JOYAXISMOTION)
 | 
			
		||||
		{
 | 
			
		||||
			auto index = blah_sdl_find_joystick_index(g_platform.joysticks, event.jdevice.which);
 | 
			
		||||
			auto index = blah_sdl_find_joystick_index(joysticks, event.jdevice.which);
 | 
			
		||||
			if (index >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				if (SDL_IsGameController(index) == SDL_FALSE)
 | 
			
		||||
@ -350,7 +391,7 @@ void Platform::update(InputState& state)
 | 
			
		||||
			auto index = event.cdevice.which;
 | 
			
		||||
			if (index >= 0 && index < Input::max_controllers)
 | 
			
		||||
			{
 | 
			
		||||
				auto ptr = g_platform.gamepads[index] = SDL_GameControllerOpen(index);
 | 
			
		||||
				auto ptr = gamepads[index] = SDL_GameControllerOpen(index);
 | 
			
		||||
				auto name = SDL_GameControllerName(ptr);
 | 
			
		||||
				auto vendor = SDL_GameControllerGetVendor(ptr);
 | 
			
		||||
				auto product = SDL_GameControllerGetProduct(ptr);
 | 
			
		||||
@ -361,16 +402,16 @@ void Platform::update(InputState& state)
 | 
			
		||||
		}
 | 
			
		||||
		else if (event.type == SDL_CONTROLLERDEVICEREMOVED)
 | 
			
		||||
		{
 | 
			
		||||
			auto index = blah_sdl_find_gamepad_index(g_platform.gamepads, event.cdevice.which);
 | 
			
		||||
			auto index = blah_sdl_find_gamepad_index(gamepads, event.cdevice.which);
 | 
			
		||||
			if (index >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				state.controllers[index].on_disconnect();
 | 
			
		||||
				SDL_GameControllerClose(g_platform.gamepads[index]);
 | 
			
		||||
				SDL_GameControllerClose(gamepads[index]);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (event.type == SDL_CONTROLLERBUTTONDOWN)
 | 
			
		||||
		{
 | 
			
		||||
			auto index = blah_sdl_find_gamepad_index(g_platform.gamepads, event.cdevice.which);
 | 
			
		||||
			auto index = blah_sdl_find_gamepad_index(gamepads, event.cdevice.which);
 | 
			
		||||
			if (index >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				Button button = Button::None;
 | 
			
		||||
@ -382,7 +423,7 @@ void Platform::update(InputState& state)
 | 
			
		||||
		}
 | 
			
		||||
		else if (event.type == SDL_CONTROLLERBUTTONUP)
 | 
			
		||||
		{
 | 
			
		||||
			auto index = blah_sdl_find_gamepad_index(g_platform.gamepads, event.cdevice.which);
 | 
			
		||||
			auto index = blah_sdl_find_gamepad_index(gamepads, event.cdevice.which);
 | 
			
		||||
			if (index >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				Button button = Button::None;
 | 
			
		||||
@ -394,7 +435,7 @@ void Platform::update(InputState& state)
 | 
			
		||||
		}
 | 
			
		||||
		else if (event.type == SDL_CONTROLLERAXISMOTION)
 | 
			
		||||
		{
 | 
			
		||||
			auto index = blah_sdl_find_gamepad_index(g_platform.gamepads, event.cdevice.which);
 | 
			
		||||
			auto index = blah_sdl_find_gamepad_index(gamepads, event.cdevice.which);
 | 
			
		||||
			if (index >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				Axis axis = Axis::None;
 | 
			
		||||
@ -413,85 +454,85 @@ void Platform::update(InputState& state)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::sleep(int milliseconds)
 | 
			
		||||
void SDL2_Platform::sleep(int milliseconds)
 | 
			
		||||
{
 | 
			
		||||
	if (milliseconds >= 0)
 | 
			
		||||
		SDL_Delay((u32)milliseconds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::present()
 | 
			
		||||
void SDL2_Platform::present()
 | 
			
		||||
{
 | 
			
		||||
	if (App::renderer().type == RendererType::OpenGL)
 | 
			
		||||
	{
 | 
			
		||||
		SDL_GL_SwapWindow(g_platform.window);
 | 
			
		||||
		SDL_GL_SwapWindow(window);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// display the window
 | 
			
		||||
	// this avoids a short black screen on macoS
 | 
			
		||||
	if (!g_platform.displayed)
 | 
			
		||||
	if (!displayed)
 | 
			
		||||
	{
 | 
			
		||||
		SDL_ShowWindow(g_platform.window);
 | 
			
		||||
		g_platform.displayed = true;
 | 
			
		||||
		SDL_ShowWindow(window);
 | 
			
		||||
		displayed = true;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char* Platform::get_title()
 | 
			
		||||
const char* SDL2_Platform::get_title()
 | 
			
		||||
{
 | 
			
		||||
	return SDL_GetWindowTitle(g_platform.window);
 | 
			
		||||
	return SDL_GetWindowTitle(window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::set_title(const char* title)
 | 
			
		||||
void SDL2_Platform::set_title(const char* title)
 | 
			
		||||
{
 | 
			
		||||
	SDL_SetWindowTitle(g_platform.window, title);
 | 
			
		||||
	SDL_SetWindowTitle(window, title);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::get_position(int* x, int* y)
 | 
			
		||||
void SDL2_Platform::get_position(int* x, int* y)
 | 
			
		||||
{
 | 
			
		||||
	SDL_GetWindowPosition(g_platform.window, x, y);
 | 
			
		||||
	SDL_GetWindowPosition(window, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::set_position(int x, int y)
 | 
			
		||||
void SDL2_Platform::set_position(int x, int y)
 | 
			
		||||
{
 | 
			
		||||
	SDL_SetWindowPosition(g_platform.window, x, y);
 | 
			
		||||
	SDL_SetWindowPosition(window, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Platform::get_focused()
 | 
			
		||||
bool SDL2_Platform::get_focused()
 | 
			
		||||
{
 | 
			
		||||
	auto flags = SDL_GetWindowFlags(g_platform.window);
 | 
			
		||||
	auto flags = SDL_GetWindowFlags(window);
 | 
			
		||||
	return (flags & SDL_WINDOW_INPUT_FOCUS) != 0 && (flags & SDL_WINDOW_MINIMIZED) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::set_fullscreen(bool enabled)
 | 
			
		||||
void SDL2_Platform::set_fullscreen(bool enabled)
 | 
			
		||||
{
 | 
			
		||||
	if (enabled)
 | 
			
		||||
		SDL_SetWindowFullscreen(g_platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
 | 
			
		||||
		SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
 | 
			
		||||
	else
 | 
			
		||||
		SDL_SetWindowFullscreen(g_platform.window, 0);
 | 
			
		||||
		SDL_SetWindowFullscreen(window, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::get_size(int* width, int* height)
 | 
			
		||||
void SDL2_Platform::get_size(int* width, int* height)
 | 
			
		||||
{
 | 
			
		||||
	SDL_GetWindowSize(g_platform.window, width, height);
 | 
			
		||||
	SDL_GetWindowSize(window, width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::set_size(int width, int height)
 | 
			
		||||
void SDL2_Platform::set_size(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	SDL_SetWindowSize(g_platform.window, width, height);
 | 
			
		||||
	SDL_SetWindowSize(window, width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::get_draw_size(int* width, int* height)
 | 
			
		||||
void SDL2_Platform::get_draw_size(int* width, int* height)
 | 
			
		||||
{
 | 
			
		||||
	if (App::renderer().type == RendererType::OpenGL)
 | 
			
		||||
	{
 | 
			
		||||
		SDL_GL_GetDrawableSize(g_platform.window, width, height);
 | 
			
		||||
		SDL_GL_GetDrawableSize(window, width, height);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		SDL_GetWindowSize(g_platform.window, width, height);
 | 
			
		||||
		SDL_GetWindowSize(window, width, height);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Platform::get_content_scale()
 | 
			
		||||
float SDL2_Platform::get_content_scale()
 | 
			
		||||
{
 | 
			
		||||
	// TODO:
 | 
			
		||||
	// This is incorrect! but for some reason the scale
 | 
			
		||||
@ -506,7 +547,7 @@ float Platform::get_content_scale()
 | 
			
		||||
	float hidpiRes = 72;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	int index = SDL_GetWindowDisplayIndex(g_platform.window);
 | 
			
		||||
	int index = SDL_GetWindowDisplayIndex(window);
 | 
			
		||||
	if (index < 0)
 | 
			
		||||
		Log::error(SDL_GetError());
 | 
			
		||||
 | 
			
		||||
@ -517,27 +558,25 @@ float Platform::get_content_scale()
 | 
			
		||||
	return (ddpi / hidpiRes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FILE IO
 | 
			
		||||
 | 
			
		||||
const char* Platform::app_path()
 | 
			
		||||
const char* SDL2_Platform::app_path()
 | 
			
		||||
{
 | 
			
		||||
	if (g_platform.base_path == nullptr)
 | 
			
		||||
		g_platform.base_path = SDL_GetBasePath();
 | 
			
		||||
	return g_platform.base_path;
 | 
			
		||||
	if (base_path_value == nullptr)
 | 
			
		||||
		base_path_value = SDL_GetBasePath();
 | 
			
		||||
	return base_path_value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char* Platform::user_path()
 | 
			
		||||
const char* SDL2_Platform::user_path()
 | 
			
		||||
{
 | 
			
		||||
	if (g_platform.user_path == nullptr)
 | 
			
		||||
	if (user_path_value == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		auto& config = App::config();
 | 
			
		||||
		g_platform.user_path = SDL_GetPrefPath(nullptr, config.name);
 | 
			
		||||
		user_path_value = SDL_GetPrefPath(nullptr, config.name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return g_platform.user_path;
 | 
			
		||||
	return user_path_value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileRef Platform::file_open(const char* path, FileMode mode)
 | 
			
		||||
FileRef SDL2_Platform::file_open(const char* path, FileMode mode)
 | 
			
		||||
{
 | 
			
		||||
	const char* sdl_mode = "";
 | 
			
		||||
 | 
			
		||||
@ -561,35 +600,35 @@ FileRef Platform::file_open(const char* path, FileMode mode)
 | 
			
		||||
	if (!ptr)
 | 
			
		||||
		return FileRef();
 | 
			
		||||
 | 
			
		||||
	return FileRef(new SDL2File(ptr));
 | 
			
		||||
	return FileRef(new SDL2_File(ptr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Platform::file_exists(const char* path)
 | 
			
		||||
bool SDL2_Platform::file_exists(const char* path)
 | 
			
		||||
{
 | 
			
		||||
	return std::filesystem::is_regular_file(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Platform::file_delete(const char* path)
 | 
			
		||||
bool SDL2_Platform::file_delete(const char* path)
 | 
			
		||||
{
 | 
			
		||||
	return std::filesystem::remove(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Platform::dir_create(const char* path)
 | 
			
		||||
bool SDL2_Platform::dir_create(const char* path)
 | 
			
		||||
{
 | 
			
		||||
	return std::filesystem::create_directories(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Platform::dir_exists(const char* path)
 | 
			
		||||
bool SDL2_Platform::dir_exists(const char* path)
 | 
			
		||||
{
 | 
			
		||||
	return std::filesystem::is_directory(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Platform::dir_delete(const char* path)
 | 
			
		||||
bool SDL2_Platform::dir_delete(const char* path)
 | 
			
		||||
{
 | 
			
		||||
	return std::filesystem::remove_all(path) > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
 | 
			
		||||
void SDL2_Platform::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
 | 
			
		||||
{
 | 
			
		||||
	if (std::filesystem::is_directory(path))
 | 
			
		||||
	{
 | 
			
		||||
@ -606,7 +645,7 @@ void Platform::dir_enumerate(Vector<FilePath>& list, const char* path, bool recu
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::dir_explore(const char* path)
 | 
			
		||||
void SDL2_Platform::dir_explore(const char* path)
 | 
			
		||||
{
 | 
			
		||||
#if _WIN32
 | 
			
		||||
 | 
			
		||||
@ -623,54 +662,59 @@ void Platform::dir_explore(const char* path)
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::set_clipboard(const char* text)
 | 
			
		||||
void SDL2_Platform::set_clipboard(const char* text)
 | 
			
		||||
{
 | 
			
		||||
	SDL_SetClipboardText(text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char* Platform::get_clipboard()
 | 
			
		||||
const char* SDL2_Platform::get_clipboard()
 | 
			
		||||
{
 | 
			
		||||
	return SDL_GetClipboardText();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* Platform::gl_get_func(const char* name)
 | 
			
		||||
void* SDL2_Platform::gl_get_func(const char* name)
 | 
			
		||||
{
 | 
			
		||||
	return SDL_GL_GetProcAddress(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* Platform::gl_context_create()
 | 
			
		||||
void* SDL2_Platform::gl_context_create()
 | 
			
		||||
{
 | 
			
		||||
	void* pointer = SDL_GL_CreateContext(g_platform.window);
 | 
			
		||||
	void* pointer = SDL_GL_CreateContext(window);
 | 
			
		||||
	if (pointer == nullptr)
 | 
			
		||||
		Log::error("SDL_GL_CreateContext failed: %s", SDL_GetError());
 | 
			
		||||
	return pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::gl_context_make_current(void* context)
 | 
			
		||||
void SDL2_Platform::gl_context_make_current(void* context)
 | 
			
		||||
{
 | 
			
		||||
	SDL_GL_MakeCurrent(g_platform.window, context);
 | 
			
		||||
	SDL_GL_MakeCurrent(window, context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::gl_context_destroy(void* context)
 | 
			
		||||
void SDL2_Platform::gl_context_destroy(void* context)
 | 
			
		||||
{
 | 
			
		||||
	SDL_GL_DeleteContext(context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* Platform::d3d11_get_hwnd()
 | 
			
		||||
void* SDL2_Platform::d3d11_get_hwnd()
 | 
			
		||||
{
 | 
			
		||||
#if _WIN32
 | 
			
		||||
	SDL_SysWMinfo info;
 | 
			
		||||
	SDL_VERSION(&info.version);
 | 
			
		||||
	SDL_GetWindowWMInfo(g_platform.window, &info);
 | 
			
		||||
	SDL_GetWindowWMInfo(window, &info);
 | 
			
		||||
	return info.info.win.window;
 | 
			
		||||
#else
 | 
			
		||||
	return nullptr;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Platform::open_url(const char* url)
 | 
			
		||||
void SDL2_Platform::open_url(const char* url)
 | 
			
		||||
{
 | 
			
		||||
	SDL_OpenURL(url);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Platform* Platform::try_make_platform(const Config& config)
 | 
			
		||||
{
 | 
			
		||||
	return new SDL2_Platform();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // BLAH_PLATFORM_SDL2
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -8,19 +8,14 @@
 | 
			
		||||
#include <blah/graphics/material.h>
 | 
			
		||||
#include <blah/math/color.h>
 | 
			
		||||
 | 
			
		||||
#define BLAH_ASSERT_RENDERER() BLAH_ASSERT(Renderer::instance, "Renderer has not been created")
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	class Renderer
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
 | 
			
		||||
		// Reference to the current Renderer in use
 | 
			
		||||
		inline static Renderer* instance = nullptr;
 | 
			
		||||
 | 
			
		||||
		// Renderer Features
 | 
			
		||||
		RendererFeatures features;
 | 
			
		||||
		// Renderer Info
 | 
			
		||||
		RendererInfo info;
 | 
			
		||||
 | 
			
		||||
		// Default Shader for the Batcher
 | 
			
		||||
		ShaderRef default_batcher_shader;
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
// Note the D3D11 Implementation is still a work-in-progress
 | 
			
		||||
 | 
			
		||||
#include "renderer.h"
 | 
			
		||||
#include "internal.h"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
@ -16,7 +17,7 @@
 | 
			
		||||
#include <d3dcompiler.h>
 | 
			
		||||
 | 
			
		||||
// shorthand to our internal state
 | 
			
		||||
#define renderer ((Renderer_D3D11*)Renderer::instance)
 | 
			
		||||
#define renderer ((Renderer_D3D11*)App::Internal::renderer)
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
@ -773,7 +774,7 @@ namespace Blah
 | 
			
		||||
		desc.SampleDesc.Quality = 0;
 | 
			
		||||
		desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
 | 
			
		||||
		desc.BufferCount = 1;
 | 
			
		||||
		desc.OutputWindow = (HWND)Platform::d3d11_get_hwnd();
 | 
			
		||||
		desc.OutputWindow = (HWND)App::Internal::platform->d3d11_get_hwnd();
 | 
			
		||||
		desc.Windowed = true;
 | 
			
		||||
 | 
			
		||||
		// Creation Flags
 | 
			
		||||
@ -815,10 +816,10 @@ namespace Blah
 | 
			
		||||
		// create a depth backbuffer
 | 
			
		||||
 | 
			
		||||
		// Store Features
 | 
			
		||||
		features.type = RendererType::D3D11;
 | 
			
		||||
		features.instancing = true;
 | 
			
		||||
		features.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
 | 
			
		||||
		features.origin_bottom_left = false;
 | 
			
		||||
		info.type = RendererType::D3D11;
 | 
			
		||||
		info.instancing = true;
 | 
			
		||||
		info.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
 | 
			
		||||
		info.origin_bottom_left = false;
 | 
			
		||||
 | 
			
		||||
		// Print Driver Info
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
#ifdef BLAH_RENDERER_OPENGL
 | 
			
		||||
 | 
			
		||||
#include "renderer.h"
 | 
			
		||||
#include "internal.h"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
@ -339,7 +340,7 @@ typedef void (APIENTRY* DEBUGPROC)(GLenum source,
 | 
			
		||||
	const void* userParam);
 | 
			
		||||
 | 
			
		||||
// shorthand to our internal state
 | 
			
		||||
#define renderer ((Renderer_OpenGL*)Renderer::instance)
 | 
			
		||||
#define renderer ((Renderer_OpenGL*)App::Internal::renderer)
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
@ -1158,16 +1159,16 @@ namespace Blah
 | 
			
		||||
	bool Renderer_OpenGL::init()
 | 
			
		||||
	{
 | 
			
		||||
		// create gl context
 | 
			
		||||
		context = Platform::gl_context_create();
 | 
			
		||||
		context = App::Internal::platform->gl_context_create();
 | 
			
		||||
		if (context == nullptr)
 | 
			
		||||
		{
 | 
			
		||||
			Log::error("Failed to create OpenGL Context");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		Platform::gl_context_make_current(context);
 | 
			
		||||
		App::Internal::platform->gl_context_make_current(context);
 | 
			
		||||
 | 
			
		||||
		// bind opengl functions
 | 
			
		||||
		#define GL_FUNC(name, ...) gl.name = (Renderer_OpenGL::Bindings::name ## Func)(Platform::gl_get_func("gl" #name));
 | 
			
		||||
		#define GL_FUNC(name, ...) gl.name = (Renderer_OpenGL::Bindings::name ## Func)(App::Internal::platform->gl_get_func("gl" #name));
 | 
			
		||||
		GL_FUNCTIONS
 | 
			
		||||
		#undef GL_FUNC
 | 
			
		||||
 | 
			
		||||
@ -1198,10 +1199,10 @@ namespace Blah
 | 
			
		||||
		gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
 | 
			
		||||
 | 
			
		||||
		// assign info
 | 
			
		||||
		features.type = RendererType::OpenGL;
 | 
			
		||||
		features.instancing = true;
 | 
			
		||||
		features.origin_bottom_left = true;
 | 
			
		||||
		features.max_texture_size = max_texture_size;
 | 
			
		||||
		info.type = RendererType::OpenGL;
 | 
			
		||||
		info.instancing = true;
 | 
			
		||||
		info.origin_bottom_left = true;
 | 
			
		||||
		info.max_texture_size = max_texture_size;
 | 
			
		||||
 | 
			
		||||
		// create the default batch shader
 | 
			
		||||
		default_batcher_shader = Shader::create(opengl_batch_shader_data);
 | 
			
		||||
@ -1211,7 +1212,7 @@ namespace Blah
 | 
			
		||||
 | 
			
		||||
	void Renderer_OpenGL::shutdown()
 | 
			
		||||
	{
 | 
			
		||||
		Platform::gl_context_destroy(context);
 | 
			
		||||
		App::Internal::platform->gl_context_destroy(context);
 | 
			
		||||
		context = nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								src/time.cpp
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/time.cpp
									
									
									
									
									
								
							@ -1,5 +1,5 @@
 | 
			
		||||
#include <blah/time.h>
 | 
			
		||||
#include "internal/platform.h"
 | 
			
		||||
#include "internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,9 @@ float Time::pause_timer = 0;
 | 
			
		||||
 | 
			
		||||
u64 Time::get_ticks()
 | 
			
		||||
{
 | 
			
		||||
	return Platform::ticks();
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		return App::Internal::platform->ticks();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Time::pause_for(float duration)
 | 
			
		||||
@ -66,7 +68,7 @@ Stopwatch::Stopwatch()
 | 
			
		||||
 | 
			
		||||
void Stopwatch::reset()
 | 
			
		||||
{
 | 
			
		||||
	start_time = Platform::ticks();
 | 
			
		||||
	start_time = Time::get_ticks();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u64 Stopwatch::milliseconds() const
 | 
			
		||||
@ -76,5 +78,5 @@ u64 Stopwatch::milliseconds() const
 | 
			
		||||
 | 
			
		||||
u64 Stopwatch::microseconds() const
 | 
			
		||||
{
 | 
			
		||||
	return Platform::ticks() - start_time;
 | 
			
		||||
	return Time::get_ticks() - start_time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user