refactor: singleton pattern

This commit is contained in:
light7734 2025-07-06 17:23:28 +03:30
parent 072772957e
commit 25e1ee8aa0
Signed by: light7734
GPG key ID: 8C30176798F1A6BA
11 changed files with 144 additions and 202 deletions

View file

@ -1,16 +1,13 @@
#pragma once #pragma once
#include <engine/base/base.hpp> #include <engine/base/base.hpp>
#include <engine/debug/instrumentor.hpp>
#include <engine/input/input.hpp> #include <engine/input/input.hpp>
#include <engine/layer/layer_stack.hpp> #include <engine/layer/layer_stack.hpp>
#include <engine/utils/resource_manager.hpp>
namespace Light { namespace Light {
class Window; class Window;
class Event; class Event;
class Instrumentor;
class Application class Application
{ {
@ -35,15 +32,7 @@ private:
void log_debug_data(); void log_debug_data();
static Application *s_context;
Scope<Instrumentor> m_instrumentor;
Scope<LayerStack> m_layer_stack; Scope<LayerStack> m_layer_stack;
Scope<Input> m_input;
Scope<ResourceManager> m_resource_manager;
}; };
extern Light::Scope<Application> create_application(); extern Light::Scope<Application> create_application();

View file

@ -16,30 +16,32 @@ struct ScopeProfileResult
class Instrumentor class Instrumentor
{ {
public: public:
static Scope<Instrumentor> create(); static auto instance() -> Instrumentor &
{
static auto instance = Instrumentor {};
return instance;
}
static void begin_session(const std::string &outputPath) static void begin_session(const std::string &outputPath)
{ {
s_context->begin_session_impl(outputPath); instance().begin_session_impl(outputPath);
} }
static void end_session() static void end_session()
{ {
s_context->end_session_impl(); instance().end_session_impl();
} }
static void submit_scope_profile(const ScopeProfileResult &profileResult) static void submit_scope_profile(const ScopeProfileResult &profileResult)
{ {
s_context->submit_scope_profile_impl(profileResult); instance().submit_scope_profile_impl(profileResult);
} }
private: private:
static Instrumentor *s_context;
std::ofstream m_output_file_stream; std::ofstream m_output_file_stream;
unsigned int m_current_session_count { 0u }; unsigned int m_current_session_count { 0u };
Instrumentor(); Instrumentor() = default;
void begin_session_impl(const std::string &outputPath); void begin_session_impl(const std::string &outputPath);

View file

@ -11,29 +11,35 @@ class Event;
class Input class Input
{ {
public: public:
static auto create() -> Scope<Input>; static auto instance() -> Input &
{
static auto instance = Input {};
return instance;
}
static void receive_user_interface_events(bool receive, bool toggle = false) static void receive_user_interface_events(bool receive, bool toggle = false)
{ {
s_context->receive_user_interface_events_impl(receive, toggle); instance().receive_user_interface_events_impl(receive, toggle);
} }
static void receive_game_events(bool receive, bool toggle = false) static void receive_game_events(bool receive, bool toggle = false)
{ {
s_context->receieve_game_events_impl(receive, toggle); instance().receieve_game_events_impl(receive, toggle);
} }
static auto get_keyboard_key(int code) -> bool static auto get_keyboard_key(int code) -> bool
{ {
return s_context->m_keyboad_keys[code]; return instance().m_keyboad_keys[code];
} }
static auto get_mouse_button(int code) -> bool static auto get_mouse_button(int code) -> bool
{ {
return s_context->m_mouse_buttons[code]; return instance().m_mouse_buttons[code];
} }
static auto get_mouse_position(int /*code*/) -> const glm::vec2 & static auto get_mouse_position(int /*code*/) -> const glm::vec2 &
{ {
return s_context->m_mouse_position; return instance().m_mouse_position;
} }
void on_event(const Event &inputEvent); void on_event(const Event &inputEvent);
@ -49,7 +55,13 @@ public:
} }
private: private:
static Input *s_context; Input();
void receive_user_interface_events_impl(bool receive, bool toggle = false);
void receieve_game_events_impl(bool receive, bool toggle = false);
void restart_input_state();
std::array<bool, 348> m_keyboad_keys {}; std::array<bool, 348> m_keyboad_keys {};
@ -64,14 +76,6 @@ private:
bool m_user_interface_events { true }; bool m_user_interface_events { true };
bool m_game_events { true }; bool m_game_events { true };
Input();
void receive_user_interface_events_impl(bool receive, bool toggle = false);
void receieve_game_events_impl(bool receive, bool toggle = false);
void restart_input_state();
}; };
} // namespace Light } // namespace Light

View file

@ -10,7 +10,11 @@ class Event;
class LayerStack /* singleton */ class LayerStack /* singleton */
{ {
public: public:
static auto create() -> Scope<LayerStack>; static auto instance() -> LayerStack &
{
static auto instance = LayerStack {};
return instance;
}
~LayerStack(); ~LayerStack();
@ -18,17 +22,17 @@ public:
template<typename t, typename... Args> template<typename t, typename... Args>
static void emplace_layer(Args &&...args) static void emplace_layer(Args &&...args)
{ {
s_context->attach_layer_impl(new t((args)...)); instance().attach_layer_impl(new t((args)...));
} }
static void attach_layer(Layer *layer) static void attach_layer(Layer *layer)
{ {
s_context->attach_layer_impl(layer); instance().attach_layer_impl(layer);
} }
static void detach_layer(Layer *layer) static void detach_layer(Layer *layer)
{ {
s_context->detach_layer_impl(layer); instance().detach_layer_impl(layer);
} }
auto is_empty() -> bool auto is_empty() -> bool
@ -57,15 +61,13 @@ public:
} }
private: private:
static LayerStack *s_context;
std::vector<Layer *> m_layers; std::vector<Layer *> m_layers;
std::vector<Layer *>::iterator m_begin; std::vector<Layer *>::iterator m_begin;
std::vector<Layer *>::iterator m_end; std::vector<Layer *>::iterator m_end;
LayerStack(); LayerStack() = default;
void attach_layer_impl(Layer *layer); void attach_layer_impl(Layer *layer);

View file

@ -11,7 +11,11 @@ class SharedContext;
class ResourceManager class ResourceManager
{ {
public: public:
static auto create() -> Scope<ResourceManager>; static auto instance() -> ResourceManager &
{
static auto instance = ResourceManager {};
return instance;
}
static void load_shader( static void load_shader(
const std::string &name, const std::string &name,
@ -19,7 +23,7 @@ public:
const std::string &pixelPath const std::string &pixelPath
) )
{ {
s_context->load_shader_impl(name, vertexPath, pixelPath); instance().load_shader_impl(name, vertexPath, pixelPath);
} }
static void load_texture( static void load_texture(
@ -28,32 +32,26 @@ public:
unsigned int desiredComponents = 4u unsigned int desiredComponents = 4u
) )
{ {
s_context->load_texture_impl(name, path, desiredComponents); instance().load_texture_impl(name, path, desiredComponents);
} }
static void release_texture(const std::string &name) static void release_texture(const std::string &name)
{ {
s_context->release_texture_impl(name); instance().release_texture_impl(name);
} }
static auto get_shader(const std::string &name) -> Ref<Shader> static auto get_shader(const std::string &name) -> Ref<Shader>
{ {
return s_context->m_shaders[name]; return instance().m_shaders[name];
} }
static auto get_texture(const std::string &name) -> Ref<Texture> static auto get_texture(const std::string &name) -> Ref<Texture>
{ {
return s_context->m_textures[name]; return instance().m_textures[name];
} }
private: private:
static ResourceManager *s_context; ResourceManager() = default;
std::unordered_map<std::string, Ref<Shader>> m_shaders;
std::unordered_map<std::string, Ref<Texture>> m_textures;
ResourceManager();
void load_shader_impl( void load_shader_impl(
const std::string &name, const std::string &name,
@ -68,6 +66,10 @@ private:
); );
void release_texture_impl(const std::string &name); void release_texture_impl(const std::string &name);
std::unordered_map<std::string, Ref<Shader>> m_shaders;
std::unordered_map<std::string, Ref<Texture>> m_textures;
}; };
} // namespace Light } // namespace Light

View file

@ -12,34 +12,23 @@
namespace Light { namespace Light {
Application *Application::s_context = nullptr; Application::Application(): m_window(nullptr)
Application::Application()
: m_instrumentor(nullptr)
, m_layer_stack(nullptr)
, m_input(nullptr)
, m_window(nullptr)
{ {
lt_assert(!s_context, "Repeated singleton construction"); static auto constructed = false;
s_context = this; lt_assert(!constructed, "Application constructed twice");
constructed = true;
log_debug_data(); log_debug_data();
m_instrumentor = Instrumentor::create();
Light::Instrumentor::begin_session("Logs/ProfileResults_Startup.json"); Light::Instrumentor::begin_session("Logs/ProfileResults_Startup.json");
m_layer_stack = LayerStack::create();
m_input = Input::create();
m_resource_manager = ResourceManager::create();
m_window = Window::create([this](auto &&PH1) { on_event(std::forward<decltype(PH1)>(PH1)); }); m_window = Window::create([this](auto &&PH1) { on_event(std::forward<decltype(PH1)>(PH1)); });
} }
Application::~Application() Application::~Application()
{ {
log_trc("Application::~Application()"); log_trc("Application::~Application()");
Light::Instrumentor::end_session(); Instrumentor::end_session();
} }
void Application::game_loop() void Application::game_loop()
@ -54,8 +43,8 @@ void Application::game_loop()
// reveal window // reveal window
m_window->set_visibility(true); m_window->set_visibility(true);
Light::Instrumentor::end_session(); Instrumentor::end_session();
Light::Instrumentor::begin_session("Logs/ProfileResults_GameLoop.json"); Instrumentor::begin_session("Logs/ProfileResults_GameLoop.json");
/* game loop */ /* game loop */
auto delta_timer = DeltaTimer {}; auto delta_timer = DeltaTimer {};
@ -65,7 +54,8 @@ void Application::game_loop()
// update layers // update layers
lt_profile_scope("game_loop::update"); lt_profile_scope("game_loop::update");
for (auto & it : *m_layer_stack) { for (auto &it : *m_layer_stack)
{
it->on_update(delta_timer.get_delta_time()); it->on_update(delta_timer.get_delta_time());
} }
} }
@ -75,7 +65,8 @@ void Application::game_loop()
lt_profile_scope("game_loop::Render"); lt_profile_scope("game_loop::Render");
m_window->get_graphics_context()->get_renderer()->begin_frame(); m_window->get_graphics_context()->get_renderer()->begin_frame();
for (auto & it : *m_layer_stack) { for (auto &it : *m_layer_stack)
{
it->on_render(); it->on_render();
} }
@ -87,7 +78,8 @@ void Application::game_loop()
lt_profile_scope("game_loop::UserInterface"); lt_profile_scope("game_loop::UserInterface");
m_window->get_graphics_context()->get_user_interface()->begin(); m_window->get_graphics_context()->get_user_interface()->begin();
for (auto & it : *m_layer_stack) { for (auto &it : *m_layer_stack)
{
it->on_user_interface_update(); it->on_user_interface_update();
} }
@ -104,13 +96,13 @@ void Application::game_loop()
delta_timer.update(); delta_timer.update();
} }
Light::Instrumentor::end_session(); Instrumentor::end_session();
Light::Instrumentor::begin_session("Logs/ProfileResults_Termination.json"); Instrumentor::begin_session("Logs/ProfileResults_Termination.json");
} }
void Application::quit() void Application::quit()
{ {
s_context->m_window->close(); /** TODO: fix quitting procedure */
} }
void Application::on_event(const Event &event) void Application::on_event(const Event &event)
@ -120,7 +112,8 @@ void Application::on_event(const Event &event)
{ {
m_window->on_event(event); m_window->on_event(event);
if (event.get_event_type() == EventType::WindowResized) { if (event.get_event_type() == EventType::WindowResized)
{
m_window->get_graphics_context()->get_renderer()->on_window_resize( m_window->get_graphics_context()->get_renderer()->on_window_resize(
(const WindowResizedEvent &)event (const WindowResizedEvent &)event
); );
@ -130,9 +123,9 @@ void Application::on_event(const Event &event)
// input // input
if (event.has_category(InputEventCategory)) if (event.has_category(InputEventCategory))
{ {
m_input->on_event(event); Input::instance().on_event(event);
if (!m_input->is_receiving_game_events()) if (!Input::instance().is_receiving_game_events())
{ {
return; return;
} }
@ -149,13 +142,10 @@ void Application::on_event(const Event &event)
void Application::log_debug_data() void Application::log_debug_data()
{ {
// #todo: log more information
log_inf("________________________________________");
log_inf("Platform::"); log_inf("Platform::");
log_inf(" Platform name: {}", constants::platform_name); log_inf(" Platform name: {}", constants::platform_name);
log_inf(" Platform identifier: {}", std::to_underlying(constants::platform)); log_inf(" Platform identifier: {}", std::to_underlying(constants::platform));
log_inf(" CWD: {}", std::filesystem::current_path().generic_string()); log_inf(" CWD: {}", std::filesystem::current_path().generic_string());
log_inf("________________________________________");
} }
} // namespace Light } // namespace Light

View file

@ -2,23 +2,6 @@
namespace Light { namespace Light {
Instrumentor *Instrumentor::s_context = nullptr;
auto Instrumentor::create() -> Scope<Instrumentor>
{
return make_scope<Instrumentor>(new Instrumentor);
}
Instrumentor::Instrumentor()
{
// #todo: maintenance
lt_assert(
!s_context,
"An instance of 'Instrumentor' already exists, do not construct this class!"
);
s_context = this;
}
void Instrumentor::begin_session_impl(const std::string &outputPath) void Instrumentor::begin_session_impl(const std::string &outputPath)
{ {
std::filesystem::create_directory(outputPath.substr(0, outputPath.find_last_of('/') + 1)); std::filesystem::create_directory(outputPath.substr(0, outputPath.find_last_of('/') + 1));
@ -29,7 +12,8 @@ void Instrumentor::begin_session_impl(const std::string &outputPath)
void Instrumentor::end_session_impl() void Instrumentor::end_session_impl()
{ {
if (m_current_session_count == 0u) { if (m_current_session_count == 0u)
{
log_wrn("0 profiling for the ended session"); log_wrn("0 profiling for the ended session");
} }
@ -42,9 +26,12 @@ void Instrumentor::end_session_impl()
void Instrumentor::submit_scope_profile_impl(const ScopeProfileResult &profileResult) void Instrumentor::submit_scope_profile_impl(const ScopeProfileResult &profileResult)
{ {
if (m_current_session_count++ == 0u) { if (m_current_session_count++ == 0u)
{
m_output_file_stream << "{"; m_output_file_stream << "{";
} else { }
else
{
m_output_file_stream << ",{"; m_output_file_stream << ",{";
} }

View file

@ -8,25 +8,9 @@
namespace Light { namespace Light {
Input *Input::s_context = nullptr; Input::Input(): m_mouse_position {}, m_mouse_delta {}
auto Input::create() -> Scope<Input>
{
return make_scope(new Input);
}
Input::Input()
:
m_mouse_position {}
, m_mouse_delta {}
{ {
lt_assert(
!s_context,
"Input::Input: an instance of 'Input' already exists, do not construct this class!"
);
s_context = this;
restart_input_state(); restart_input_state();
} }
@ -40,7 +24,8 @@ void Input::receieve_game_events_impl(bool receive, bool toggle /*= false*/)
auto prev = m_game_events; auto prev = m_game_events;
m_game_events = toggle ? !m_user_interface_events : receive; m_game_events = toggle ? !m_user_interface_events : receive;
if (m_game_events != prev) { if (m_game_events != prev)
{
restart_input_state(); restart_input_state();
} }
} }
@ -71,7 +56,8 @@ void Input::on_event(const Event &inputEvent)
m_mouse_position = event.get_position(); m_mouse_position = event.get_position();
} }
if (m_user_interface_events) { if (m_user_interface_events)
{
io.MousePos = ImVec2(event.get_x(), event.get_y()); io.MousePos = ImVec2(event.get_x(), event.get_y());
} }
@ -81,11 +67,13 @@ void Input::on_event(const Event &inputEvent)
{ {
const auto &event = dynamic_cast<const ButtonPressedEvent &>(inputEvent); const auto &event = dynamic_cast<const ButtonPressedEvent &>(inputEvent);
if (m_game_events) { if (m_game_events)
{
m_mouse_buttons[event.get_button()] = true; m_mouse_buttons[event.get_button()] = true;
} }
if (m_user_interface_events) { if (m_user_interface_events)
{
io.MouseDown[event.get_button()] = true; io.MouseDown[event.get_button()] = true;
} }
@ -95,11 +83,13 @@ void Input::on_event(const Event &inputEvent)
{ {
const auto &event = dynamic_cast<const ButtonReleasedEvent &>(inputEvent); const auto &event = dynamic_cast<const ButtonReleasedEvent &>(inputEvent);
if (m_game_events) { if (m_game_events)
{
m_mouse_buttons[event.get_button()] = false; m_mouse_buttons[event.get_button()] = false;
} }
if (m_user_interface_events) { if (m_user_interface_events)
{
io.MouseDown[event.get_button()] = false; io.MouseDown[event.get_button()] = false;
} }
@ -109,11 +99,13 @@ void Input::on_event(const Event &inputEvent)
{ {
const auto &event = dynamic_cast<const WheelScrolledEvent &>(inputEvent); const auto &event = dynamic_cast<const WheelScrolledEvent &>(inputEvent);
if (m_game_events) { if (m_game_events)
{
m_mouse_wheel_delta = event.get_offset(); m_mouse_wheel_delta = event.get_offset();
} }
if (m_user_interface_events) { if (m_user_interface_events)
{
io.MouseWheel = event.get_offset(); io.MouseWheel = event.get_offset();
} }
@ -124,7 +116,8 @@ void Input::on_event(const Event &inputEvent)
{ {
const auto &event = dynamic_cast<const KeyPressedEvent &>(inputEvent); const auto &event = dynamic_cast<const KeyPressedEvent &>(inputEvent);
if (m_game_events) { if (m_game_events)
{
m_keyboad_keys[event.get_key()] = true; m_keyboad_keys[event.get_key()] = true;
} }
@ -141,11 +134,13 @@ void Input::on_event(const Event &inputEvent)
{ {
const auto &event = dynamic_cast<const KeyReleasedEvent &>(inputEvent); const auto &event = dynamic_cast<const KeyReleasedEvent &>(inputEvent);
if (m_game_events) { if (m_game_events)
{
m_keyboad_keys[event.get_key()] = false; m_keyboad_keys[event.get_key()] = false;
} }
if (m_user_interface_events) { if (m_user_interface_events)
{
io.KeysDown[event.get_key()] = false; io.KeysDown[event.get_key()] = false;
} }

View file

@ -7,25 +7,10 @@
namespace Light { namespace Light {
LayerStack *LayerStack::s_context = nullptr;
auto LayerStack::create() -> Scope<LayerStack>
{
return make_scope<LayerStack>(new LayerStack());
}
LayerStack::LayerStack()
{
lt_assert(
!s_context,
"An instance of 'LayerStack' already exists, do not construct this class!"
) s_context
= this;
}
LayerStack::~LayerStack() LayerStack::~LayerStack()
{ {
for (auto *layer : m_layers) { for (auto *layer : m_layers)
{
delete layer; delete layer;
} }
} }

View file

@ -6,19 +6,6 @@
namespace Light { namespace Light {
ResourceManager *ResourceManager::s_context = nullptr;
auto ResourceManager::create() -> Scope<ResourceManager>
{
return make_scope(new ResourceManager());
}
ResourceManager::ResourceManager()
{
lt_assert(!s_context, "Repeated singleton construction");
s_context = this;
}
void ResourceManager::load_shader_impl( void ResourceManager::load_shader_impl(
const std::string &name, const std::string &name,
const std::string &vertexPath, const std::string &vertexPath,
@ -26,7 +13,6 @@ void ResourceManager::load_shader_impl(
) )
{ {
// check // check
lt_assert(s_context, "Uninitliazed singleton");
lt_assert(!vertexPath.empty(), "Empty 'vertexPath'"); lt_assert(!vertexPath.empty(), "Empty 'vertexPath'");
lt_assert(!pixelPath.empty(), "Empty 'pixelPath'"); lt_assert(!pixelPath.empty(), "Empty 'pixelPath'");
@ -54,8 +40,6 @@ void ResourceManager::load_texture_impl(
unsigned int desiredComponents /* = 4u */ unsigned int desiredComponents /* = 4u */
) )
{ {
lt_assert(s_context, "Uninitliazed singleton");
// load file // load file
auto imgFile = FileManager::read_image_file(path, desiredComponents); auto imgFile = FileManager::read_image_file(path, desiredComponents);

View file

@ -19,7 +19,8 @@ struct convert<glm::vec3>
static auto decode(const Node &node, glm::vec3 &rhs) -> bool static auto decode(const Node &node, glm::vec3 &rhs) -> bool
{ {
if (!node.IsSequence() || node.size() != 3) { if (!node.IsSequence() || node.size() != 3)
{
return false; return false;
} }
@ -45,7 +46,8 @@ struct convert<glm::vec4>
static auto decode(const Node &node, glm::vec4 &rhs) -> bool static auto decode(const Node &node, glm::vec4 &rhs) -> bool
{ {
if (!node.IsSequence() || node.size() != 4) { if (!node.IsSequence() || node.size() != 4)
{
return false; return false;
} }
@ -60,14 +62,14 @@ struct convert<glm::vec4>
namespace Light { namespace Light {
static auto operator<<(YAML::Emitter &out, const glm::vec3 &v) -> YAML::Emitter & auto operator<<(YAML::Emitter &out, const glm::vec3 &v) -> YAML::Emitter &
{ {
out << YAML::Flow; out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq; out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq;
return out; return out;
} }
static auto operator<<(YAML::Emitter &out, const glm::vec4 &v) -> YAML::Emitter & auto operator<<(YAML::Emitter &out, const glm::vec4 &v) -> YAML::Emitter &
{ {
out << YAML::Flow; out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq; out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq;