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

View file

@ -16,30 +16,32 @@ struct ScopeProfileResult
class Instrumentor
{
public:
static Scope<Instrumentor> create();
static auto instance() -> Instrumentor &
{
static auto instance = Instrumentor {};
return instance;
}
static void begin_session(const std::string &outputPath)
{
s_context->begin_session_impl(outputPath);
instance().begin_session_impl(outputPath);
}
static void end_session()
{
s_context->end_session_impl();
instance().end_session_impl();
}
static void submit_scope_profile(const ScopeProfileResult &profileResult)
{
s_context->submit_scope_profile_impl(profileResult);
instance().submit_scope_profile_impl(profileResult);
}
private:
static Instrumentor *s_context;
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);

View file

@ -11,29 +11,35 @@ class Event;
class Input
{
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)
{
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)
{
s_context->receieve_game_events_impl(receive, toggle);
instance().receieve_game_events_impl(receive, toggle);
}
static auto get_keyboard_key(int code) -> bool
{
return s_context->m_keyboad_keys[code];
}
static auto get_mouse_button(int code) -> bool
{
return s_context->m_mouse_buttons[code];
return instance().m_keyboad_keys[code];
}
static auto get_mouse_position(int /*code*/) -> const glm::vec2 &
static auto get_mouse_button(int code) -> bool
{
return s_context->m_mouse_position;
return instance().m_mouse_buttons[code];
}
static auto get_mouse_position(int /*code*/) -> const glm::vec2 &
{
return instance().m_mouse_position;
}
void on_event(const Event &inputEvent);
@ -49,22 +55,6 @@ public:
}
private:
static Input *s_context;
std::array<bool, 348> m_keyboad_keys{};
std::array<bool, 8> m_mouse_buttons{};
glm::vec2 m_mouse_position;
glm::vec2 m_mouse_delta;
float m_mouse_wheel_delta{};
bool m_user_interface_events{true};
bool m_game_events{true};
Input();
void receive_user_interface_events_impl(bool receive, bool toggle = false);
@ -72,6 +62,20 @@ private:
void receieve_game_events_impl(bool receive, bool toggle = false);
void restart_input_state();
std::array<bool, 348> m_keyboad_keys {};
std::array<bool, 8> m_mouse_buttons {};
glm::vec2 m_mouse_position;
glm::vec2 m_mouse_delta;
float m_mouse_wheel_delta {};
bool m_user_interface_events { true };
bool m_game_events { true };
};
} // namespace Light

View file

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

View file

@ -11,7 +11,11 @@ class SharedContext;
class ResourceManager
{
public:
static auto create() -> Scope<ResourceManager>;
static auto instance() -> ResourceManager &
{
static auto instance = ResourceManager {};
return instance;
}
static void load_shader(
const std::string &name,
@ -19,7 +23,7 @@ public:
const std::string &pixelPath
)
{
s_context->load_shader_impl(name, vertexPath, pixelPath);
instance().load_shader_impl(name, vertexPath, pixelPath);
}
static void load_texture(
@ -28,32 +32,26 @@ public:
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)
{
s_context->release_texture_impl(name);
instance().release_texture_impl(name);
}
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>
{
return s_context->m_textures[name];
return instance().m_textures[name];
}
private:
static ResourceManager *s_context;
std::unordered_map<std::string, Ref<Shader>> m_shaders;
std::unordered_map<std::string, Ref<Texture>> m_textures;
ResourceManager();
ResourceManager() = default;
void load_shader_impl(
const std::string &name,
@ -68,6 +66,10 @@ private:
);
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

View file

@ -12,34 +12,23 @@
namespace Light {
Application *Application::s_context = nullptr;
Application::Application()
: m_instrumentor(nullptr)
, m_layer_stack(nullptr)
, m_input(nullptr)
, m_window(nullptr)
Application::Application(): m_window(nullptr)
{
lt_assert(!s_context, "Repeated singleton construction");
s_context = this;
static auto constructed = false;
lt_assert(!constructed, "Application constructed twice");
constructed = true;
log_debug_data();
m_instrumentor = Instrumentor::create();
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()
{
log_trc("Application::~Application()");
Light::Instrumentor::end_session();
Instrumentor::end_session();
}
void Application::game_loop()
@ -54,8 +43,8 @@ void Application::game_loop()
// reveal window
m_window->set_visibility(true);
Light::Instrumentor::end_session();
Light::Instrumentor::begin_session("Logs/ProfileResults_GameLoop.json");
Instrumentor::end_session();
Instrumentor::begin_session("Logs/ProfileResults_GameLoop.json");
/* game loop */
auto delta_timer = DeltaTimer {};
@ -65,9 +54,10 @@ void Application::game_loop()
// update layers
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());
}
}
}
{
@ -75,9 +65,10 @@ void Application::game_loop()
lt_profile_scope("game_loop::Render");
m_window->get_graphics_context()->get_renderer()->begin_frame();
for (auto & it : *m_layer_stack) {
for (auto &it : *m_layer_stack)
{
it->on_render();
}
}
m_window->get_graphics_context()->get_renderer()->end_frame();
}
@ -87,9 +78,10 @@ void Application::game_loop()
lt_profile_scope("game_loop::UserInterface");
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();
}
}
m_window->get_graphics_context()->get_user_interface()->end();
}
@ -104,13 +96,13 @@ void Application::game_loop()
delta_timer.update();
}
Light::Instrumentor::end_session();
Light::Instrumentor::begin_session("Logs/ProfileResults_Termination.json");
Instrumentor::end_session();
Instrumentor::begin_session("Logs/ProfileResults_Termination.json");
}
void Application::quit()
{
s_context->m_window->close();
/** TODO: fix quitting procedure */
}
void Application::on_event(const Event &event)
@ -120,19 +112,20 @@ void Application::on_event(const 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(
(const WindowResizedEvent &)event
);
}
}
}
// input
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;
}
@ -149,13 +142,10 @@ void Application::on_event(const Event &event)
void Application::log_debug_data()
{
// #todo: log more information
log_inf("________________________________________");
log_inf("Platform::");
log_inf(" Platform name: {}", constants::platform_name);
log_inf(" Platform identifier: {}", std::to_underlying(constants::platform));
log_inf(" CWD: {}", std::filesystem::current_path().generic_string());
log_inf("________________________________________");
}
} // namespace Light

View file

@ -2,23 +2,6 @@
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)
{
std::filesystem::create_directory(outputPath.substr(0, outputPath.find_last_of('/') + 1));
@ -29,9 +12,10 @@ void Instrumentor::begin_session_impl(const std::string &outputPath)
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");
}
}
m_current_session_count = 0u;
@ -42,11 +26,14 @@ void Instrumentor::end_session_impl()
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 << "{";
} else {
}
else
{
m_output_file_stream << ",{";
}
}
m_output_file_stream << R"("name":")" << profileResult.name << "\",";
m_output_file_stream << R"("cat": "scope",)";
@ -59,7 +46,7 @@ void Instrumentor::submit_scope_profile_impl(const ScopeProfileResult &profileRe
}
InstrumentorTimer::InstrumentorTimer(const std::string &scopeName)
: m_result({ .name=scopeName, .start=0, .duration=0, .threadID=0 })
: m_result({ .name = scopeName, .start = 0, .duration = 0, .threadID = 0 })
, m_start(std::chrono::steady_clock::now())
{
}

View file

@ -8,25 +8,9 @@
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();
}
@ -40,9 +24,10 @@ void Input::receieve_game_events_impl(bool receive, bool toggle /*= false*/)
auto prev = m_game_events;
m_game_events = toggle ? !m_user_interface_events : receive;
if (m_game_events != prev) {
if (m_game_events != prev)
{
restart_input_state();
}
}
}
void Input::restart_input_state()
@ -71,9 +56,10 @@ void Input::on_event(const Event &inputEvent)
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());
}
}
return;
}
@ -81,13 +67,15 @@ void Input::on_event(const Event &inputEvent)
{
const auto &event = dynamic_cast<const ButtonPressedEvent &>(inputEvent);
if (m_game_events) {
if (m_game_events)
{
m_mouse_buttons[event.get_button()] = true;
}
}
if (m_user_interface_events) {
if (m_user_interface_events)
{
io.MouseDown[event.get_button()] = true;
}
}
return;
}
@ -95,13 +83,15 @@ void Input::on_event(const Event &inputEvent)
{
const auto &event = dynamic_cast<const ButtonReleasedEvent &>(inputEvent);
if (m_game_events) {
if (m_game_events)
{
m_mouse_buttons[event.get_button()] = false;
}
}
if (m_user_interface_events) {
if (m_user_interface_events)
{
io.MouseDown[event.get_button()] = false;
}
}
return;
}
@ -109,13 +99,15 @@ void Input::on_event(const Event &inputEvent)
{
const auto &event = dynamic_cast<const WheelScrolledEvent &>(inputEvent);
if (m_game_events) {
if (m_game_events)
{
m_mouse_wheel_delta = event.get_offset();
}
}
if (m_user_interface_events) {
if (m_user_interface_events)
{
io.MouseWheel = event.get_offset();
}
}
return;
}
@ -124,9 +116,10 @@ void Input::on_event(const Event &inputEvent)
{
const auto &event = dynamic_cast<const KeyPressedEvent &>(inputEvent);
if (m_game_events) {
if (m_game_events)
{
m_keyboad_keys[event.get_key()] = true;
}
}
if (m_user_interface_events)
{
@ -141,13 +134,15 @@ void Input::on_event(const Event &inputEvent)
{
const auto &event = dynamic_cast<const KeyReleasedEvent &>(inputEvent);
if (m_game_events) {
if (m_game_events)
{
m_keyboad_keys[event.get_key()] = false;
}
}
if (m_user_interface_events) {
if (m_user_interface_events)
{
io.KeysDown[event.get_key()] = false;
}
}
return;
}

View file

@ -7,27 +7,12 @@
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()
{
for (auto *layer : m_layers) {
for (auto *layer : m_layers)
{
delete layer;
}
}
}
void LayerStack::attach_layer_impl(Layer *layer)

View file

@ -6,19 +6,6 @@
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(
const std::string &name,
const std::string &vertexPath,
@ -26,7 +13,6 @@ void ResourceManager::load_shader_impl(
)
{
// check
lt_assert(s_context, "Uninitliazed singleton");
lt_assert(!vertexPath.empty(), "Empty 'vertexPath'");
lt_assert(!pixelPath.empty(), "Empty 'pixelPath'");
@ -54,8 +40,6 @@ void ResourceManager::load_texture_impl(
unsigned int desiredComponents /* = 4u */
)
{
lt_assert(s_context, "Uninitliazed singleton");
// load file
auto imgFile = FileManager::read_image_file(path, desiredComponents);

View file

@ -19,9 +19,10 @@ struct convert<glm::vec3>
static auto decode(const Node &node, glm::vec3 &rhs) -> bool
{
if (!node.IsSequence() || node.size() != 3) {
if (!node.IsSequence() || node.size() != 3)
{
return false;
}
}
rhs.x = node[0].as<float>();
rhs.y = node[1].as<float>();
@ -45,9 +46,10 @@ struct convert<glm::vec4>
static auto decode(const Node &node, glm::vec4 &rhs) -> bool
{
if (!node.IsSequence() || node.size() != 4) {
if (!node.IsSequence() || node.size() != 4)
{
return false;
}
}
rhs.x = node[0].as<float>();
rhs.y = node[1].as<float>();
@ -60,14 +62,14 @@ struct convert<glm::vec4>
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::BeginSeq << v.x << v.y << v.z << YAML::EndSeq;
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::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq;