Refactored Platform into a struct to hold global state better

This commit is contained in:
Noel Berry 2022-02-11 20:19:14 -08:00
parent ddb7d1b372
commit 1caa31032b
20 changed files with 971 additions and 791 deletions

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "blah/common.h"
#include "blah/app.h" #include "blah/app.h"
#include "blah/filesystem.h" #include "blah/filesystem.h"
#include "blah/common.h"
#include "blah/time.h" #include "blah/time.h"
#include "blah/input.h" #include "blah/input.h"
@ -13,7 +13,6 @@
#include "blah/graphics/batch.h" #include "blah/graphics/batch.h"
#include "blah/graphics/spritefont.h" #include "blah/graphics/spritefont.h"
#include "blah/graphics/subtexture.h" #include "blah/graphics/subtexture.h"
#include "blah/graphics/blend.h" #include "blah/graphics/blend.h"
#include "blah/graphics/material.h" #include "blah/graphics/material.h"
#include "blah/graphics/mesh.h" #include "blah/graphics/mesh.h"

View File

@ -19,7 +19,7 @@ namespace Blah
}; };
// Renderer Information // Renderer Information
struct RendererFeatures struct RendererInfo
{ {
// The type of Renderer being used // The type of Renderer being used
RendererType type = RendererType::None; RendererType type = RendererType::None;
@ -142,8 +142,8 @@ namespace Blah
// Otherwise this function does nothing. // Otherwise this function does nothing.
void fullscreen(bool enabled); void fullscreen(bool enabled);
// Retrieves the Renderer Features // Retrieves the Renderer Information
const RendererFeatures& renderer(); const RendererInfo& renderer();
// Gets the BackBuffer // Gets the BackBuffer
const TargetRef& backbuffer(); const TargetRef& backbuffer();

View File

@ -2,9 +2,9 @@
#include <blah/common.h> #include <blah/common.h>
#include <blah/time.h> #include <blah/time.h>
#include <blah/graphics/target.h> #include <blah/graphics/target.h>
#include "internal/internal.h"
#include "internal/platform.h" #include "internal/platform.h"
#include "internal/renderer.h" #include "internal/renderer.h"
#include "internal/input.h"
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
#include <emscripten.h> #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)") #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 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 // A dummy Frame Buffer that represents the Back Buffer
// it doesn't actually contain any textures or details. // it doesn't actually contain any textures or details.
class BackBuffer final : public Target class BackBuffer final : public Target
@ -103,15 +31,24 @@ namespace
Attachments empty_textures; Attachments empty_textures;
Attachments& textures() override { BLAH_ASSERT(false, "Backbuffer doesn't have any textures"); return 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; } 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 width() const override {
int height() const override { int w, h; Platform::get_draw_size(&w, &h); return h; } 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 void clear(Color color, float depth, u8 stencil, ClearMask mask) override
{ {
BLAH_ASSERT_RENDERER(); 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; 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->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->max_updates > 0, "Max Updates must be >= 1");
BLAH_ASSERT(c->target_framerate > 0, "Target Framerate 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) 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; return false;
}
// default values // default values
app_is_running = true; app_is_running = true;
@ -145,81 +86,176 @@ bool App::run(const Config* c)
app_backbuffer = TargetRef(new BackBuffer()); app_backbuffer = TargetRef(new BackBuffer());
// initialize the system // 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"); Log::error("Failed to initialize Platform module");
App::Internal::shutdown();
return false; return false;
} }
// initialize graphics // initialize graphics
Internal::renderer = Renderer::try_make_renderer(app_config.renderer_type);
if (Internal::renderer == nullptr)
{ {
// instantiate Log::error("Renderer module was not found");
Renderer::instance = Renderer::try_make_renderer(app_config.renderer_type); App::Internal::shutdown();
return false;
}
// wasn't able to make any if (!Internal::renderer->init())
if (Renderer::instance == nullptr) {
{ Log::error("Failed to initialize Renderer module");
Log::error("Renderer implementation was not found"); App::Internal::shutdown();
return false; return false;
}
if (!Renderer::instance->init())
{
Log::error("Renderer failed to initialize");
delete Renderer::instance;
return false;
}
} }
// input // input
Input::init(); Input::Internal::init();
// prepare by updating input & platform once // prepare by updating input & platform once
Input::update_state(); Input::Internal::update_state();
Platform::update(Input::state); Internal::platform->update(Input::state);
// startup // startup
if (app_config.on_startup != nullptr) if (app_config.on_startup != nullptr)
app_config.on_startup(); app_config.on_startup();
app_time_last = Platform::ticks(); app_time_last = Internal::platform->ticks();
app_time_accumulator = 0; app_time_accumulator = 0;
// display window // display window
Platform::ready(); Internal::platform->ready();
// Begin main loop // Begin main loop
// Emscripten requires the main loop be separated into its own call // Emscripten requires the main loop be separated into its own call
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
emscripten_set_main_loop(app_iterate, 0, 1); emscripten_set_main_loop(App::Internal::iterate, 0, 1);
#else #else
while (!app_is_exiting) while (!app_is_exiting)
app_iterate(); App::Internal::iterate();
#endif #endif
// shutdown // shutdown
if (app_config.on_shutdown != nullptr) if (app_config.on_shutdown != nullptr)
app_config.on_shutdown(); app_config.on_shutdown();
Renderer::instance->shutdown(); App::Internal::shutdown();
Platform::shutdown(); return true;
}
delete Renderer::instance; void App::Internal::iterate()
Renderer::instance = nullptr; {
// 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_running = false;
app_is_exiting = false; app_is_exiting = false;
app_time_last = 0;
app_time_accumulator = 0;
app_backbuffer = TargetRef(); app_backbuffer = TargetRef();
// clear static Time state
Time::ticks = 0; Time::ticks = 0;
Time::seconds = 0; Time::seconds = 0;
Time::previous_ticks = 0; Time::previous_ticks = 0;
Time::previous_seconds = 0; Time::previous_seconds = 0;
Time::delta = 0; Time::delta = 0;
return true;
} }
void App::exit() void App::exit()
@ -238,59 +274,59 @@ const Config& App::config()
const char* App::path() const char* App::path()
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
return Platform::app_path(); return Internal::platform->app_path();
} }
const char* App::user_path() const char* App::user_path()
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
return Platform::user_path(); return Internal::platform->user_path();
} }
const char* App::get_title() const char* App::get_title()
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
return Platform::get_title(); return Internal::platform->get_title();
} }
void App::set_title(const char* title) void App::set_title(const char* title)
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
Platform::set_title(title); Internal::platform->set_title(title);
} }
Point App::get_position() Point App::get_position()
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
Point result; Point result;
Platform::get_position(&result.x, &result.y); Internal::platform->get_position(&result.x, &result.y);
return result; return result;
} }
void App::set_position(Point point) void App::set_position(Point point)
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
Platform::set_position(point.x, point.y); Internal::platform->set_position(point.x, point.y);
} }
Point App::get_size() Point App::get_size()
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
Point result; Point result;
Platform::get_size(&result.x, &result.y); Internal::platform->get_size(&result.x, &result.y);
return result; return result;
} }
void App::set_size(Point point) void App::set_size(Point point)
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
Platform::set_size(point.x, point.y); Internal::platform->set_size(point.x, point.y);
} }
Point App::get_backbuffer_size() Point App::get_backbuffer_size()
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
if (Renderer::instance) if (Internal::renderer)
return Point(app_backbuffer->width(), app_backbuffer->height()); return Point(app_backbuffer->width(), app_backbuffer->height());
return Point(0, 0); return Point(0, 0);
} }
@ -298,26 +334,26 @@ Point App::get_backbuffer_size()
float App::content_scale() float App::content_scale()
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
return Platform::get_content_scale(); return Internal::platform->get_content_scale();
} }
bool App::focused() bool App::focused()
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
return Platform::get_focused(); return Internal::platform->get_focused();
} }
void App::fullscreen(bool enabled) void App::fullscreen(bool enabled)
{ {
BLAH_ASSERT_RUNNING(); 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_RUNNING();
BLAH_ASSERT_RENDERER(); BLAH_ASSERT_RENDERER();
return Renderer::instance->features; return Internal::renderer->info;
} }
const TargetRef& App::backbuffer() const TargetRef& App::backbuffer()
@ -329,5 +365,5 @@ const TargetRef& App::backbuffer()
void System::open_url(const char* url) void System::open_url(const char* url)
{ {
BLAH_ASSERT_RUNNING(); BLAH_ASSERT_RUNNING();
Platform::open_url(url); App::Internal::platform->open_url(url);
} }

View File

@ -1,56 +1,78 @@
#include <blah/filesystem.h> #include <blah/filesystem.h>
#include <blah/streams/filestream.h> #include <blah/streams/filestream.h>
#include "internal/platform.h" #include "internal/internal.h"
using namespace Blah; using namespace Blah;
FileRef File::open(const FilePath& path, FileMode mode) 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) 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) 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) 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) 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) 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) Vector<FilePath> Directory::enumerate(const FilePath& path, bool recursive)
{ {
BLAH_ASSERT_PLATFORM();
Vector<FilePath> list; Vector<FilePath> list;
// get files if (App::Internal::platform)
Platform::dir_enumerate(list, path.cstr(), recursive); {
App::Internal::platform->dir_enumerate(list, path.cstr(), recursive);
// normalize path names for (auto& it : list)
for (auto& it : list) it.replace('\\', '/');
it.replace('\\', '/'); }
return list; return list;
} }
void Directory::explore(const FilePath& path) 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) FilePath Path::get_file_name(const FilePath& path)

View File

@ -6,7 +6,7 @@
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
#include <blah/math/calc.h> #include <blah/math/calc.h>
#include <blah/app.h> #include <blah/app.h>
#include "../internal/renderer.h" #include "../internal/internal.h"
#include <cmath> #include <cmath>
using namespace Blah; using namespace Blah;
@ -288,7 +288,7 @@ void Batch::render(const TargetRef& target, const Mat4x4f& matrix)
if (!m_default_material) if (!m_default_material)
{ {
BLAH_ASSERT_RENDERER(); BLAH_ASSERT_RENDERER();
m_default_material = Material::create(Renderer::instance->default_batcher_shader); m_default_material = Material::create(App::Internal::renderer->default_batcher_shader);
} }
} }

View File

@ -1,5 +1,5 @@
#include <blah/graphics/mesh.h> #include <blah/graphics/mesh.h>
#include "../internal/renderer.h" #include "../internal/internal.h"
using namespace Blah; using namespace Blah;
@ -7,8 +7,8 @@ MeshRef Mesh::create()
{ {
BLAH_ASSERT_RENDERER(); BLAH_ASSERT_RENDERER();
if (Renderer::instance) if (App::Internal::renderer)
return Renderer::instance->create_mesh(); return App::Internal::renderer->create_mesh();
return MeshRef(); return MeshRef();
} }

View File

@ -1,6 +1,6 @@
#include <blah/graphics/renderpass.h> #include <blah/graphics/renderpass.h>
#include <blah/common.h> #include <blah/common.h>
#include "../internal/renderer.h" #include "../internal/internal.h"
using namespace Blah; using namespace Blah;
@ -28,7 +28,7 @@ void RenderPass::perform()
BLAH_ASSERT(material->shader(), "Trying to draw with an invalid Shader"); BLAH_ASSERT(material->shader(), "Trying to draw with an invalid Shader");
BLAH_ASSERT(mesh, "Trying to draw with an invalid Mesh"); BLAH_ASSERT(mesh, "Trying to draw with an invalid Mesh");
if (!Renderer::instance) if (!App::Internal::renderer)
return; return;
// copy call // copy call
@ -90,5 +90,5 @@ void RenderPass::perform()
pass.scissor = pass.scissor.overlap_rect(Rectf(0, 0, draw_size.x, draw_size.y)); pass.scissor = pass.scissor.overlap_rect(Rectf(0, 0, draw_size.x, draw_size.y));
// perform render // perform render
Renderer::instance->render(pass); App::Internal::renderer->render(pass);
} }

View File

@ -1,6 +1,6 @@
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/app.h> #include <blah/app.h>
#include "../internal/renderer.h" #include "../internal/internal.h"
using namespace Blah; using namespace Blah;
@ -13,8 +13,8 @@ ShaderRef Shader::create(const ShaderData& data)
ShaderRef shader; ShaderRef shader;
if (Renderer::instance) if (App::Internal::renderer)
shader = Renderer::instance->create_shader(&data); shader = App::Internal::renderer->create_shader(&data);
// validate the shader // validate the shader
if (shader) if (shader)

View File

@ -1,5 +1,5 @@
#include <blah/graphics/target.h> #include <blah/graphics/target.h>
#include "../internal/renderer.h" #include "../internal/internal.h"
using namespace Blah; 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(depth_count <= 1, "Target can only have 1 Depth/Stencil Texture");
BLAH_ASSERT(color_count <= Attachments::capacity - 1, "Exceeded maximum Color texture count"); BLAH_ASSERT(color_count <= Attachments::capacity - 1, "Exceeded maximum Color texture count");
if (Renderer::instance) if (App::Internal::renderer)
return Renderer::instance->create_target(width, height, textures.data(), textures.size()); return App::Internal::renderer->create_target(width, height, textures.data(), textures.size());
return TargetRef(); return TargetRef();
} }

View File

@ -2,7 +2,7 @@
#include <blah/images/image.h> #include <blah/images/image.h>
#include <blah/streams/stream.h> #include <blah/streams/stream.h>
#include <blah/common.h> #include <blah/common.h>
#include "../internal/renderer.h" #include "../internal/internal.h"
using namespace Blah; 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(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"); 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) if (tex && data != nullptr)
tex->set_data(data); tex->set_data(data);

View File

@ -3,7 +3,7 @@
#include <blah/time.h> #include <blah/time.h>
#include <blah/common.h> #include <blah/common.h>
#include <blah/math/calc.h> #include <blah/math/calc.h>
#include "internal/input.h" #include "internal/internal.h"
#include "internal/platform.h" #include "internal/platform.h"
#include <blah/graphics/target.h> #include <blah/graphics/target.h>
#include <cstring> #include <cstring>
@ -26,7 +26,7 @@ InputState Blah::Input::last_state;
float Blah::Input::repeat_delay = 0.35f; float Blah::Input::repeat_delay = 0.35f;
float Blah::Input::repeat_interval = 0.025f; float Blah::Input::repeat_interval = 0.025f;
void Input::init() void Input::Internal::init()
{ {
g_empty_controller.name = "Disconnected"; g_empty_controller.name = "Disconnected";
for (int i = 0; i < Input::max_controllers; i++) for (int i = 0; i < Input::max_controllers; i++)
@ -39,7 +39,12 @@ void Input::init()
g_sticks.dispose(); g_sticks.dispose();
} }
void Input::update_state() void Input::Internal::shutdown()
{
init();
}
void Input::Internal::update_state()
{ {
// cycle states // cycle states
Input::last_state = Input::state; Input::last_state = Input::state;
@ -75,10 +80,11 @@ void Input::update_state()
} }
// get clipboard // 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++) 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) void Input::set_clipboard(const String& text)
{ {
g_clipboard = 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) ButtonBindingRef Input::register_binding(const ButtonBinding& binding)

View File

@ -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
View 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();
}
}
}

View File

@ -8,105 +8,110 @@ namespace Blah
{ {
struct Config; struct Config;
namespace Platform class Platform
{ {
// Initialize the System public:
bool init(const Config& config);
// Initialize the Graphics
virtual bool init(const Config& config) = 0;
// Called after the on_startup callback, but before the update loop begins // Called after the on_startup callback, but before the update loop begins
void ready(); virtual void ready() = 0;
// Called during shutdown // Called during shutdown
void shutdown(); virtual void shutdown() = 0;
// The time, in ticks (microseconds) since the Application was started // The time, in ticks (microseconds) since the Application was started
u64 ticks(); virtual u64 ticks() = 0;
// Called every frame // Called every frame
void update(InputState& state); virtual void update(InputState& state) = 0;
// Sleeps the current thread // Sleeps the current thread
void sleep(int milliseconds); virtual void sleep(int milliseconds) = 0;
// Called to present the window contents // Called to present the window contents
void present(); virtual void present() = 0;
// Gets the Application Window Title in UTF-8 // 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 // 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 // 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 // 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 // Gets whether the Window has focus
bool get_focused(); virtual bool get_focused() = 0;
// Sets the Window Fullscreen if enabled is not 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 // 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 // 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. // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // OpenGL Methods
void* gl_get_func(const char* name); virtual void* gl_get_func(const char* name) = 0;
void* gl_context_create(); virtual void* gl_context_create() = 0;
void gl_context_make_current(void* context); virtual void gl_context_make_current(void* context) = 0;
void gl_context_destroy(void* context); virtual void gl_context_destroy(void* context) = 0;
// D3D11 Methods // D3D11 Methods
void* d3d11_get_hwnd(); virtual void* d3d11_get_hwnd() = 0;
}
// Instantiates the Platform object
static Platform* try_make_platform(const Config& config);
};
} }

View File

@ -1,7 +1,6 @@
#ifdef BLAH_PLATFORM_SDL2 #ifdef BLAH_PLATFORM_SDL2
#include "platform.h" #include "platform.h"
#include "input.h"
#include "renderer.h" #include "renderer.h"
#include <blah/input.h> #include <blah/input.h>
#include <blah/app.h> #include <blah/app.h>
@ -28,30 +27,6 @@
namespace Blah 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) void blah_sdl_log(void* userdata, int category, SDL_LogPriority priority, const char* message)
{ {
if (priority <= SDL_LOG_PRIORITY_INFO) if (priority <= SDL_LOG_PRIORITY_INFO)
@ -83,14 +58,80 @@ namespace Blah
} }
return -1; 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; 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 // Required to call this for Windows
// I'm not sure why SDL2 doesn't do this on Windows automatically? // I'm not sure why SDL2 doesn't do this on Windows automatically?
#if _WIN32 #if _WIN32
@ -141,8 +182,8 @@ bool Platform::init(const Config& config)
} }
// create the window // create the window
g_platform.window = SDL_CreateWindow(config.name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config.width, config.height, flags); window = SDL_CreateWindow(config.name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config.width, config.height, flags);
if (g_platform.window == nullptr) if (window == nullptr)
{ {
Log::error("Failed to create a Window"); Log::error("Failed to create a Window");
return false; return false;
@ -153,7 +194,7 @@ bool Platform::init(const Config& config)
#if _WIN32 #if _WIN32
{ {
// find the display index // find the display index
int display = SDL_GetWindowDisplayIndex(g_platform.window); int display = SDL_GetWindowDisplayIndex(window);
float ddpi, hdpi, vdpi; float ddpi, hdpi, vdpi;
if (SDL_GetDisplayDPI(display, &ddpi, &hdpi, &vdpi) == 0) if (SDL_GetDisplayDPI(display, &ddpi, &hdpi, &vdpi) == 0)
{ {
@ -164,21 +205,21 @@ bool Platform::init(const Config& config)
{ {
SDL_DisplayMode mode; SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(display, &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_SetWindowPosition(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_SetWindowSize(window, (int)(config.width * dpi), (int)(config.height * dpi));
} }
} }
} }
#endif #endif
// set window properties // set window properties
SDL_SetWindowResizable(g_platform.window, SDL_TRUE); SDL_SetWindowResizable(window, SDL_TRUE);
SDL_SetWindowMinimumSize(g_platform.window, 256, 256); SDL_SetWindowMinimumSize(window, 256, 256);
return true; return true;
} }
void Platform::ready() void SDL2_Platform::ready()
{ {
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
// enable V-Sync // enable V-Sync
@ -189,36 +230,36 @@ void Platform::ready()
#endif #endif
} }
void Platform::shutdown() void SDL2_Platform::shutdown()
{ {
if (g_platform.window != nullptr) if (window != nullptr)
SDL_DestroyWindow(g_platform.window); SDL_DestroyWindow(window);
g_platform.window = nullptr; window = nullptr;
g_platform.displayed = false; displayed = false;
if (g_platform.base_path != nullptr) if (base_path_value != nullptr)
SDL_free(g_platform.base_path); SDL_free(base_path_value);
if (g_platform.user_path != nullptr) if (user_path_value != nullptr)
SDL_free(g_platform.user_path); SDL_free(user_path_value);
SDL_Quit(); SDL_Quit();
} }
u64 Platform::ticks() u64 SDL2_Platform::ticks()
{ {
auto counter = SDL_GetPerformanceCounter(); auto counter = SDL_GetPerformanceCounter();
auto per_second = (double)SDL_GetPerformanceFrequency(); auto per_second = (double)SDL_GetPerformanceFrequency();
return (u64)(counter * (Time::ticks_per_second / per_second)); 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 // update the mouse every frame
{ {
int win_x, win_y, x, y; 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); SDL_GetGlobalMouseState(&x, &y);
state.mouse.on_move( 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) 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 name = SDL_JoystickName(ptr);
auto button_count = SDL_JoystickNumButtons(ptr); auto button_count = SDL_JoystickNumButtons(ptr);
auto axis_count = SDL_JoystickNumAxes(ptr); auto axis_count = SDL_JoystickNumAxes(ptr);
@ -300,19 +341,19 @@ void Platform::update(InputState& state)
} }
else if (event.type == SDL_JOYDEVICEREMOVED) 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 (index >= 0)
{ {
if (SDL_IsGameController(index) == SDL_FALSE) if (SDL_IsGameController(index) == SDL_FALSE)
{ {
state.controllers[index].on_disconnect(); state.controllers[index].on_disconnect();
SDL_JoystickClose(g_platform.joysticks[index]); SDL_JoystickClose(joysticks[index]);
} }
} }
} }
else if (event.type == SDL_JOYBUTTONDOWN) 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 (index >= 0)
{ {
if (SDL_IsGameController(index) == SDL_FALSE) if (SDL_IsGameController(index) == SDL_FALSE)
@ -321,7 +362,7 @@ void Platform::update(InputState& state)
} }
else if (event.type == SDL_JOYBUTTONUP) 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 (index >= 0)
{ {
if (SDL_IsGameController(index) == SDL_FALSE) if (SDL_IsGameController(index) == SDL_FALSE)
@ -330,7 +371,7 @@ void Platform::update(InputState& state)
} }
else if (event.type == SDL_JOYAXISMOTION) 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 (index >= 0)
{ {
if (SDL_IsGameController(index) == SDL_FALSE) if (SDL_IsGameController(index) == SDL_FALSE)
@ -350,7 +391,7 @@ void Platform::update(InputState& state)
auto index = event.cdevice.which; auto index = event.cdevice.which;
if (index >= 0 && index < Input::max_controllers) 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 name = SDL_GameControllerName(ptr);
auto vendor = SDL_GameControllerGetVendor(ptr); auto vendor = SDL_GameControllerGetVendor(ptr);
auto product = SDL_GameControllerGetProduct(ptr); auto product = SDL_GameControllerGetProduct(ptr);
@ -361,16 +402,16 @@ void Platform::update(InputState& state)
} }
else if (event.type == SDL_CONTROLLERDEVICEREMOVED) 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) if (index >= 0)
{ {
state.controllers[index].on_disconnect(); state.controllers[index].on_disconnect();
SDL_GameControllerClose(g_platform.gamepads[index]); SDL_GameControllerClose(gamepads[index]);
} }
} }
else if (event.type == SDL_CONTROLLERBUTTONDOWN) 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) if (index >= 0)
{ {
Button button = Button::None; Button button = Button::None;
@ -382,7 +423,7 @@ void Platform::update(InputState& state)
} }
else if (event.type == SDL_CONTROLLERBUTTONUP) 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) if (index >= 0)
{ {
Button button = Button::None; Button button = Button::None;
@ -394,7 +435,7 @@ void Platform::update(InputState& state)
} }
else if (event.type == SDL_CONTROLLERAXISMOTION) 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) if (index >= 0)
{ {
Axis axis = Axis::None; 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) if (milliseconds >= 0)
SDL_Delay((u32)milliseconds); SDL_Delay((u32)milliseconds);
} }
void Platform::present() void SDL2_Platform::present()
{ {
if (App::renderer().type == RendererType::OpenGL) if (App::renderer().type == RendererType::OpenGL)
{ {
SDL_GL_SwapWindow(g_platform.window); SDL_GL_SwapWindow(window);
} }
// display the window // display the window
// this avoids a short black screen on macoS // this avoids a short black screen on macoS
if (!g_platform.displayed) if (!displayed)
{ {
SDL_ShowWindow(g_platform.window); SDL_ShowWindow(window);
g_platform.displayed = true; 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; 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) if (enabled)
SDL_SetWindowFullscreen(g_platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP); SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
else 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) if (App::renderer().type == RendererType::OpenGL)
{ {
SDL_GL_GetDrawableSize(g_platform.window, width, height); SDL_GL_GetDrawableSize(window, width, height);
} }
else 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: // TODO:
// This is incorrect! but for some reason the scale // This is incorrect! but for some reason the scale
@ -506,7 +547,7 @@ float Platform::get_content_scale()
float hidpiRes = 72; float hidpiRes = 72;
#endif #endif
int index = SDL_GetWindowDisplayIndex(g_platform.window); int index = SDL_GetWindowDisplayIndex(window);
if (index < 0) if (index < 0)
Log::error(SDL_GetError()); Log::error(SDL_GetError());
@ -517,27 +558,25 @@ float Platform::get_content_scale()
return (ddpi / hidpiRes); return (ddpi / hidpiRes);
} }
// FILE IO const char* SDL2_Platform::app_path()
const char* Platform::app_path()
{ {
if (g_platform.base_path == nullptr) if (base_path_value == nullptr)
g_platform.base_path = SDL_GetBasePath(); base_path_value = SDL_GetBasePath();
return g_platform.base_path; 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(); 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 = ""; const char* sdl_mode = "";
@ -561,35 +600,35 @@ FileRef Platform::file_open(const char* path, FileMode mode)
if (!ptr) if (!ptr)
return FileRef(); 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); 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); 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); 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); 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; 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)) 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 #if _WIN32
@ -623,54 +662,59 @@ void Platform::dir_explore(const char* path)
#endif #endif
} }
void Platform::set_clipboard(const char* text) void SDL2_Platform::set_clipboard(const char* text)
{ {
SDL_SetClipboardText(text); SDL_SetClipboardText(text);
} }
const char* Platform::get_clipboard() const char* SDL2_Platform::get_clipboard()
{ {
return SDL_GetClipboardText(); 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); 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) if (pointer == nullptr)
Log::error("SDL_GL_CreateContext failed: %s", SDL_GetError()); Log::error("SDL_GL_CreateContext failed: %s", SDL_GetError());
return pointer; 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); SDL_GL_DeleteContext(context);
} }
void* Platform::d3d11_get_hwnd() void* SDL2_Platform::d3d11_get_hwnd()
{ {
#if _WIN32 #if _WIN32
SDL_SysWMinfo info; SDL_SysWMinfo info;
SDL_VERSION(&info.version); SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(g_platform.window, &info); SDL_GetWindowWMInfo(window, &info);
return info.info.win.window; return info.info.win.window;
#else #else
return nullptr; return nullptr;
#endif #endif
} }
void Platform::open_url(const char* url) void SDL2_Platform::open_url(const char* url)
{ {
SDL_OpenURL(url); SDL_OpenURL(url);
} }
Platform* Platform::try_make_platform(const Config& config)
{
return new SDL2_Platform();
}
#endif // BLAH_PLATFORM_SDL2 #endif // BLAH_PLATFORM_SDL2

File diff suppressed because it is too large Load Diff

View File

@ -8,19 +8,14 @@
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
#include <blah/math/color.h> #include <blah/math/color.h>
#define BLAH_ASSERT_RENDERER() BLAH_ASSERT(Renderer::instance, "Renderer has not been created")
namespace Blah namespace Blah
{ {
class Renderer class Renderer
{ {
public: public:
// Reference to the current Renderer in use // Renderer Info
inline static Renderer* instance = nullptr; RendererInfo info;
// Renderer Features
RendererFeatures features;
// Default Shader for the Batcher // Default Shader for the Batcher
ShaderRef default_batcher_shader; ShaderRef default_batcher_shader;

View File

@ -4,6 +4,7 @@
// Note the D3D11 Implementation is still a work-in-progress // Note the D3D11 Implementation is still a work-in-progress
#include "renderer.h" #include "renderer.h"
#include "internal.h"
#include "platform.h" #include "platform.h"
#include <blah/common.h> #include <blah/common.h>
#include <cstdio> #include <cstdio>
@ -16,7 +17,7 @@
#include <d3dcompiler.h> #include <d3dcompiler.h>
// shorthand to our internal state // shorthand to our internal state
#define renderer ((Renderer_D3D11*)Renderer::instance) #define renderer ((Renderer_D3D11*)App::Internal::renderer)
namespace Blah namespace Blah
{ {
@ -773,7 +774,7 @@ namespace Blah
desc.SampleDesc.Quality = 0; desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 1; desc.BufferCount = 1;
desc.OutputWindow = (HWND)Platform::d3d11_get_hwnd(); desc.OutputWindow = (HWND)App::Internal::platform->d3d11_get_hwnd();
desc.Windowed = true; desc.Windowed = true;
// Creation Flags // Creation Flags
@ -815,10 +816,10 @@ namespace Blah
// create a depth backbuffer // create a depth backbuffer
// Store Features // Store Features
features.type = RendererType::D3D11; info.type = RendererType::D3D11;
features.instancing = true; info.instancing = true;
features.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; info.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
features.origin_bottom_left = false; info.origin_bottom_left = false;
// Print Driver Info // Print Driver Info
{ {

View File

@ -1,6 +1,7 @@
#ifdef BLAH_RENDERER_OPENGL #ifdef BLAH_RENDERER_OPENGL
#include "renderer.h" #include "renderer.h"
#include "internal.h"
#include "platform.h" #include "platform.h"
#include <blah/common.h> #include <blah/common.h>
#include <stdio.h> #include <stdio.h>
@ -339,7 +340,7 @@ typedef void (APIENTRY* DEBUGPROC)(GLenum source,
const void* userParam); const void* userParam);
// shorthand to our internal state // shorthand to our internal state
#define renderer ((Renderer_OpenGL*)Renderer::instance) #define renderer ((Renderer_OpenGL*)App::Internal::renderer)
namespace Blah namespace Blah
{ {
@ -1158,16 +1159,16 @@ namespace Blah
bool Renderer_OpenGL::init() bool Renderer_OpenGL::init()
{ {
// create gl context // create gl context
context = Platform::gl_context_create(); context = App::Internal::platform->gl_context_create();
if (context == nullptr) if (context == nullptr)
{ {
Log::error("Failed to create OpenGL Context"); Log::error("Failed to create OpenGL Context");
return false; return false;
} }
Platform::gl_context_make_current(context); App::Internal::platform->gl_context_make_current(context);
// bind opengl functions // 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 GL_FUNCTIONS
#undef GL_FUNC #undef GL_FUNC
@ -1198,10 +1199,10 @@ namespace Blah
gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1); gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
// assign info // assign info
features.type = RendererType::OpenGL; info.type = RendererType::OpenGL;
features.instancing = true; info.instancing = true;
features.origin_bottom_left = true; info.origin_bottom_left = true;
features.max_texture_size = max_texture_size; info.max_texture_size = max_texture_size;
// create the default batch shader // create the default batch shader
default_batcher_shader = Shader::create(opengl_batch_shader_data); default_batcher_shader = Shader::create(opengl_batch_shader_data);
@ -1211,7 +1212,7 @@ namespace Blah
void Renderer_OpenGL::shutdown() void Renderer_OpenGL::shutdown()
{ {
Platform::gl_context_destroy(context); App::Internal::platform->gl_context_destroy(context);
context = nullptr; context = nullptr;
} }

View File

@ -1,5 +1,5 @@
#include <blah/time.h> #include <blah/time.h>
#include "internal/platform.h" #include "internal/internal.h"
using namespace Blah; using namespace Blah;
@ -12,7 +12,9 @@ float Time::pause_timer = 0;
u64 Time::get_ticks() u64 Time::get_ticks()
{ {
return Platform::ticks(); if (App::Internal::platform)
return App::Internal::platform->ticks();
return 0;
} }
void Time::pause_for(float duration) void Time::pause_for(float duration)
@ -66,7 +68,7 @@ Stopwatch::Stopwatch()
void Stopwatch::reset() void Stopwatch::reset()
{ {
start_time = Platform::ticks(); start_time = Time::get_ticks();
} }
u64 Stopwatch::milliseconds() const u64 Stopwatch::milliseconds() const
@ -76,5 +78,5 @@ u64 Stopwatch::milliseconds() const
u64 Stopwatch::microseconds() const u64 Stopwatch::microseconds() const
{ {
return Platform::ticks() - start_time; return Time::get_ticks() - start_time;
} }