refactor: surface, app, tests, ecs refactors
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
This commit is contained in:
parent
a102db0699
commit
638a009047
16 changed files with 336 additions and 141 deletions
|
@ -5,11 +5,6 @@ namespace lt::app {
|
||||||
|
|
||||||
void Application::game_loop()
|
void Application::game_loop()
|
||||||
{
|
{
|
||||||
for (auto &system : m_systems)
|
|
||||||
{
|
|
||||||
system->init();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
for (auto &system : m_systems)
|
for (auto &system : m_systems)
|
||||||
|
@ -20,7 +15,12 @@ void Application::game_loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &system : m_systems_to_be_removed)
|
for (auto &system : m_systems_to_be_registered)
|
||||||
|
{
|
||||||
|
m_systems.emplace_back(system)->on_register();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &system : m_systems_to_be_unregistered)
|
||||||
{
|
{
|
||||||
m_systems.erase(
|
m_systems.erase(
|
||||||
std::remove(m_systems.begin(), m_systems.end(), system),
|
std::remove(m_systems.begin(), m_systems.end(), system),
|
||||||
|
@ -42,7 +42,7 @@ void Application::register_system(Ref<app::ISystem> system)
|
||||||
|
|
||||||
void Application::unregister_system(Ref<app::ISystem> system)
|
void Application::unregister_system(Ref<app::ISystem> system)
|
||||||
{
|
{
|
||||||
m_systems_to_be_removed.emplace_back(std::move(system));
|
m_systems_to_be_unregistered.emplace_back(std::move(system));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace lt::app
|
} // namespace lt::app
|
||||||
|
|
|
@ -35,7 +35,9 @@ protected:
|
||||||
private:
|
private:
|
||||||
std::vector<Ref<app::ISystem>> m_systems;
|
std::vector<Ref<app::ISystem>> m_systems;
|
||||||
|
|
||||||
std::vector<Ref<app::ISystem>> m_systems_to_be_removed;
|
std::vector<Ref<app::ISystem>> m_systems_to_be_unregistered;
|
||||||
|
|
||||||
|
std::vector<Ref<app::ISystem>> m_systems_to_be_registered;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ public:
|
||||||
|
|
||||||
auto operator=(const ISystem &) -> ISystem & = delete;
|
auto operator=(const ISystem &) -> ISystem & = delete;
|
||||||
|
|
||||||
virtual void init() = 0;
|
virtual void on_register() = 0;
|
||||||
|
|
||||||
|
virtual void on_unregister() = 0;
|
||||||
|
|
||||||
virtual auto tick() -> bool = 0;
|
virtual auto tick() -> bool = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <format>
|
||||||
#include <logger/logger.hpp>
|
#include <logger/logger.hpp>
|
||||||
|
#include <source_location>
|
||||||
|
|
||||||
namespace lt {
|
namespace lt {
|
||||||
|
|
||||||
|
@ -12,15 +14,6 @@ struct FailedAssertion: std::exception
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Expression_T, typename... Args>
|
|
||||||
constexpr void ensure(Expression_T &&expression, std::format_string<Args...> fmt, Args &&...args)
|
|
||||||
{
|
|
||||||
if (!static_cast<bool>(expression))
|
|
||||||
{
|
|
||||||
Logger::log(LogLvl::critical, fmt, std::forward<Args>(args)...);
|
|
||||||
throw ::lt::FailedAssertion(__FILE__, __LINE__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Expression_T>
|
template<typename Expression_T>
|
||||||
constexpr void ensure(Expression_T &&expression, const char *message)
|
constexpr void ensure(Expression_T &&expression, const char *message)
|
||||||
|
|
|
@ -11,21 +11,6 @@ auto Scene::create_entity(const std::string &name, const TransformComponent &tra
|
||||||
|
|
||||||
auto Scene::get_entity_by_tag(const std::string &tag) -> Entity
|
auto Scene::get_entity_by_tag(const std::string &tag) -> Entity
|
||||||
{
|
{
|
||||||
// TagComponent tagComp(tag);
|
|
||||||
// entt::entity entity = entt::to_entity(m_registry, tagComp);
|
|
||||||
auto entity = Entity {};
|
|
||||||
|
|
||||||
m_registry.view<TagComponent>().each([&](TagComponent &tagComp) {
|
|
||||||
// if (tagComp.tag == tag)
|
|
||||||
// entity = entity(entt::to_entity(m_registry, tagComp), this);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (entity.is_valid())
|
|
||||||
{
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure(false, "Scene::get_entity_by_tag: failed to find entity by tag: {}", tag);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,12 @@ public:
|
||||||
return m_registry.group(entt::get<T...>);
|
return m_registry.group(entt::get<T...>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto view()
|
||||||
|
{
|
||||||
|
return m_registry.view<T>();
|
||||||
|
}
|
||||||
|
|
||||||
auto create_entity(
|
auto create_entity(
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
const TransformComponent &transform = TransformComponent()
|
const TransformComponent &transform = TransformComponent()
|
||||||
|
@ -31,6 +37,7 @@ public:
|
||||||
return m_registry;
|
return m_registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Entity;
|
friend class Entity;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
namespace lt::math {
|
namespace lt::math {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* let...
|
* let...
|
||||||
* a = h / w ==> for aspect ratio adjustment
|
* a = h / w ==> for aspect ratio adjustment
|
||||||
|
|
|
@ -22,7 +22,9 @@ public:
|
||||||
setup_window_system();
|
setup_window_system();
|
||||||
register_systems();
|
register_systems();
|
||||||
|
|
||||||
m_window_system->add_event_listener([&](const surface::System::Event &event) {
|
m_window_system->add_event_listener(
|
||||||
|
m_window,
|
||||||
|
[&](const surface::SurfaceComponent::Event &event) {
|
||||||
const auto visitor = overloads {
|
const auto visitor = overloads {
|
||||||
[&](const lt::surface::KeyPressedEvent &event) {
|
[&](const lt::surface::KeyPressedEvent &event) {
|
||||||
std::cout << "key pressed: " << event.to_string() << std::endl;
|
std::cout << "key pressed: " << event.to_string() << std::endl;
|
||||||
|
@ -38,7 +40,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
return std::visit(visitor, event);
|
return std::visit(visitor, event);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_window_system()
|
void setup_window_system()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
add_library_module(surface system.cpp linux/system.cpp)
|
add_library_module(surface linux/system.cpp)
|
||||||
else()
|
else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -11,3 +11,6 @@ target_link_libraries(surface PUBLIC
|
||||||
logger
|
logger
|
||||||
lt_debug
|
lt_debug
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_test_module(surface system.test.cpp)
|
||||||
|
target_link_libraries(surface_tests PRIVATE glfw)
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
#define GLFW_EXPOSE_NATIVE_X11
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <GLFW/glfw3native.h>
|
||||||
#include <surface/system.hpp>
|
#include <surface/system.hpp>
|
||||||
|
|
||||||
namespace lt::surface {
|
namespace lt::surface {
|
||||||
|
|
||||||
void handle_event(GLFWwindow *window, const System::Event &event)
|
void handle_event(GLFWwindow *window, const SurfaceComponent::Event &event)
|
||||||
{
|
{
|
||||||
auto &callbacks = *static_cast<std::vector<System::EventCallback> *>(
|
auto &callbacks = *static_cast<std::vector<SurfaceComponent::EventCallback> *>(
|
||||||
glfwGetWindowUserPointer(window)
|
glfwGetWindowUserPointer(window)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -90,6 +92,50 @@ void bind_glfw_events(GLFWwindow *handle)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System::System(Ref<ecs::Registry> registry): m_registry(std::move(registry))
|
||||||
|
{
|
||||||
|
ensure(m_registry, "Failed to initialize surface system: null registry");
|
||||||
|
ensure(
|
||||||
|
m_registry->view<SurfaceComponent>().size() == 0,
|
||||||
|
"Failed to initialize surface system: registry has surface component(s)"
|
||||||
|
);
|
||||||
|
|
||||||
|
m_registry->get_entt_registry()
|
||||||
|
.on_construct<SurfaceComponent>()
|
||||||
|
.connect<&System::on_surface_construct>(this);
|
||||||
|
|
||||||
|
m_registry->get_entt_registry()
|
||||||
|
.on_update<SurfaceComponent>()
|
||||||
|
.connect<&System::on_surface_update>(this);
|
||||||
|
|
||||||
|
m_registry->get_entt_registry()
|
||||||
|
.on_destroy<SurfaceComponent>()
|
||||||
|
.connect<&System::on_surface_destroy>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
System::~System()
|
||||||
|
{
|
||||||
|
m_registry->get_entt_registry()
|
||||||
|
.on_construct<SurfaceComponent>()
|
||||||
|
.disconnect<&System::on_surface_construct>(this);
|
||||||
|
|
||||||
|
m_registry->get_entt_registry()
|
||||||
|
.on_update<SurfaceComponent>()
|
||||||
|
.connect<&System::on_surface_update>(this);
|
||||||
|
|
||||||
|
m_registry->get_entt_registry()
|
||||||
|
.on_destroy<SurfaceComponent>()
|
||||||
|
.disconnect<&System::on_surface_destroy>(this);
|
||||||
|
|
||||||
|
|
||||||
|
m_registry->view<SurfaceComponent>().each([&](const entt::entity entity, SurfaceComponent &) {
|
||||||
|
std::cout << "REMOVED SURFACE COMPONENT ON DESTRUCTION" << std::endl;
|
||||||
|
m_registry->get_entt_registry().remove<SurfaceComponent>(entity);
|
||||||
|
});
|
||||||
|
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
void System::on_surface_construct(entt::registry ®istry, entt::entity entity)
|
void System::on_surface_construct(entt::registry ®istry, entt::entity entity)
|
||||||
{
|
{
|
||||||
ensure(glfwInit(), "Failed to initialize 'glfw'");
|
ensure(glfwInit(), "Failed to initialize 'glfw'");
|
||||||
|
@ -111,10 +157,17 @@ void System::on_surface_construct(entt::registry ®istry, entt::entity entity)
|
||||||
);
|
);
|
||||||
ensure(surface.m_glfw_handle, "Failed to create 'GLFWwindow'");
|
ensure(surface.m_glfw_handle, "Failed to create 'GLFWwindow'");
|
||||||
|
|
||||||
glfwSetWindowUserPointer(surface.m_glfw_handle, &m_event_callbacks);
|
glfwSetWindowUserPointer(surface.m_glfw_handle, &surface.m_event_callbacks);
|
||||||
|
surface.m_native_handle = glfwGetX11Window(surface.m_glfw_handle);
|
||||||
bind_glfw_events(surface.m_glfw_handle);
|
bind_glfw_events(surface.m_glfw_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::on_surface_update(entt::registry ®istry, entt::entity entity)
|
||||||
|
{
|
||||||
|
auto &surface = registry.get<SurfaceComponent>(entity);
|
||||||
|
glfwSetWindowUserPointer(surface.m_glfw_handle, &surface.m_event_callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
void System::on_surface_destroy(entt::registry ®istry, entt::entity entity)
|
void System::on_surface_destroy(entt::registry ®istry, entt::entity entity)
|
||||||
{
|
{
|
||||||
auto &surface = registry.get<SurfaceComponent>(entity);
|
auto &surface = registry.get<SurfaceComponent>(entity);
|
||||||
|
@ -170,29 +223,17 @@ void System::set_visibility(ecs::Entity surface_entity, bool visible)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::add_event_listener(
|
||||||
|
ecs::Entity surface_entity,
|
||||||
|
SurfaceComponent::EventCallback callback
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto &surface = surface_entity.get_component<SurfaceComponent>();
|
||||||
|
surface.m_event_callbacks.emplace_back(std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace lt::surface
|
} // namespace lt::surface
|
||||||
|
|
||||||
namespace lt {
|
namespace lt {
|
||||||
|
|
||||||
// void System::on_event(const Event &event)
|
|
||||||
// {
|
|
||||||
// switch (event.get_event_type())
|
|
||||||
// {
|
|
||||||
// /* closed */
|
|
||||||
// case EventType::WindowClosed: b_Closed = true; break;
|
|
||||||
//
|
|
||||||
// /* resized */
|
|
||||||
// case EventType::WindowResized:
|
|
||||||
// on_surface_resize(dynamic_cast<const WindowResizedEvent &>(event));
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// default: break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// void System::on_surface_resize(const WindowResizedEvent &event)
|
|
||||||
// {
|
|
||||||
// m_properties.size = event.get_size();
|
|
||||||
// }
|
|
||||||
|
|
||||||
} // namespace lt
|
} // namespace lt
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
#include <surface/system.hpp>
|
|
||||||
|
|
||||||
namespace lt::surface {
|
|
||||||
|
|
||||||
System::System(Ref<ecs::Registry> registry): m_registry(std::move(registry))
|
|
||||||
{
|
|
||||||
m_registry->get_entt_registry()
|
|
||||||
.on_construct<SurfaceComponent>()
|
|
||||||
.connect<&System::on_surface_construct>(this);
|
|
||||||
|
|
||||||
m_registry->get_entt_registry()
|
|
||||||
.on_destroy<SurfaceComponent>()
|
|
||||||
.connect<&System::on_surface_destroy>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
System::~System()
|
|
||||||
{
|
|
||||||
m_registry->get_entt_registry()
|
|
||||||
.on_construct<SurfaceComponent>()
|
|
||||||
.disconnect<&System::on_surface_construct>(this);
|
|
||||||
|
|
||||||
m_registry->get_entt_registry()
|
|
||||||
.on_destroy<SurfaceComponent>()
|
|
||||||
.disconnect<&System::on_surface_destroy>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt::surface
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
#include <surface/system.hpp>
|
||||||
|
#include <test/test.hpp>
|
||||||
|
|
||||||
|
using namespace lt;
|
||||||
|
using std::ignore;
|
||||||
|
using surface::SurfaceComponent;
|
||||||
|
using surface::System;
|
||||||
|
using test::Case;
|
||||||
|
using test::expect_eq;
|
||||||
|
using test::expect_ne;
|
||||||
|
using test::expect_not_nullptr;
|
||||||
|
using test::expect_throw;
|
||||||
|
using test::Suite;
|
||||||
|
|
||||||
|
constexpr auto title = "TestWindow";
|
||||||
|
constexpr auto width = 800u;
|
||||||
|
constexpr auto height = 600u;
|
||||||
|
constexpr auto vsync = true;
|
||||||
|
constexpr auto visible = false;
|
||||||
|
|
||||||
|
class Fixture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]] auto registry() -> Ref<ecs::Registry>
|
||||||
|
{
|
||||||
|
return m_registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto add_surface_component() -> SurfaceComponent &
|
||||||
|
{
|
||||||
|
auto entity = m_registry->create_entity("");
|
||||||
|
return entity.add_component<SurfaceComponent>(SurfaceComponent::CreateInfo {
|
||||||
|
.title = title,
|
||||||
|
.size = { width, height },
|
||||||
|
.vsync = vsync,
|
||||||
|
.visible = visible,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_values(const SurfaceComponent &component)
|
||||||
|
{
|
||||||
|
expect_ne(std::get<SurfaceComponent::X11NativeHandle>(component.get_native_handle()), 0);
|
||||||
|
expect_eq(component.get_size().x, width);
|
||||||
|
expect_eq(component.get_size().y, height);
|
||||||
|
expect_eq(component.get_title(), title);
|
||||||
|
expect_eq(component.is_vsync(), vsync);
|
||||||
|
expect_eq(component.is_visible(), visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ref<ecs::Registry> m_registry = create_ref<ecs::Registry>();
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite raii = [] {
|
||||||
|
Case { "happy path won't throw" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
ignore = System { fixture.registry() };
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "many won't throw" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
for (auto idx : std::views::iota(0, 100'001))
|
||||||
|
{
|
||||||
|
ignore = System { fixture.registry() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "unhappy path throws" } = [] {
|
||||||
|
expect_throw([] { ignore = System { {} }; });
|
||||||
|
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
fixture.add_surface_component();
|
||||||
|
expect_throw([&] { ignore = System { { fixture.registry() } }; });
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "post construct has correct state" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
auto system = System { fixture.registry() };
|
||||||
|
expect_eq(fixture.registry()->view<SurfaceComponent>()->size(), 0);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite system_events = [] {
|
||||||
|
Case { "on_register won't throw" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
auto system = System { fixture.registry() };
|
||||||
|
|
||||||
|
system.on_register();
|
||||||
|
expect_eq(fixture.registry()->view<SurfaceComponent>().size(), 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "on_unregister won't throw" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
auto system = System { fixture.registry() };
|
||||||
|
system.on_register();
|
||||||
|
|
||||||
|
system.on_unregister();
|
||||||
|
expect_eq(fixture.registry()->view<SurfaceComponent>().size(), 0);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite registry_events = [] {
|
||||||
|
Case { "on_construct<SurfaceComponent> initializes component" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
auto system = System { fixture.registry() };
|
||||||
|
|
||||||
|
const auto &component = fixture.add_surface_component();
|
||||||
|
expect_eq(fixture.registry()->view<SurfaceComponent>().size(), 1);
|
||||||
|
fixture.check_values(component);
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "on_destrroy<SurfaceComponent> cleans up component" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
auto system = create_scope<System>(fixture.registry());
|
||||||
|
|
||||||
|
const auto &component = fixture.add_surface_component();
|
||||||
|
expect_eq(fixture.registry()->view<SurfaceComponent>().size(), 1);
|
||||||
|
fixture.check_values(component);
|
||||||
|
|
||||||
|
system.reset();
|
||||||
|
expect_eq(fixture.registry()->view<SurfaceComponent>().size(), 0);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite tick = [] {
|
||||||
|
Case { "ticking on empty registry won't throw" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
System { fixture.registry() }.tick();
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "ticking on non-empty registry won't throw" } = [] {
|
||||||
|
auto fixture = Fixture {};
|
||||||
|
auto system = System { fixture.registry() };
|
||||||
|
|
||||||
|
fixture.add_surface_component();
|
||||||
|
system.tick();
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "ticking on chaotic registry won't throw" } = [] {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite property_setters = [] {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite listeners = [] {
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite fuzzy = [] {
|
||||||
|
};
|
|
@ -1,16 +1,52 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <math/vec2.hpp>
|
#include <math/vec2.hpp>
|
||||||
|
#include <surface/events/keyboard.hpp>
|
||||||
|
#include <surface/events/mouse.hpp>
|
||||||
|
#include <surface/events/surface.hpp>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
struct GLFWwindow;
|
struct GLFWwindow;
|
||||||
|
|
||||||
namespace lt::surface {
|
namespace lt::surface {
|
||||||
|
|
||||||
|
/** Represents a platform's surface (eg. a Window).
|
||||||
|
*
|
||||||
|
* @note Read-only component, should only be modified through a system.
|
||||||
|
*/
|
||||||
class SurfaceComponent
|
class SurfaceComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class System;
|
friend class System;
|
||||||
|
|
||||||
|
using Event = std::variant<
|
||||||
|
// surface events
|
||||||
|
ClosedEvent,
|
||||||
|
MovedEvent,
|
||||||
|
ResizedEvent,
|
||||||
|
LostFocusEvent,
|
||||||
|
GainFocusEvent,
|
||||||
|
|
||||||
|
// keyboard events
|
||||||
|
KeyPressedEvent,
|
||||||
|
KeyRepeatEvent,
|
||||||
|
KeyReleasedEvent,
|
||||||
|
KeySetCharEvent,
|
||||||
|
|
||||||
|
// mouse events
|
||||||
|
MouseMovedEvent,
|
||||||
|
WheelScrolledEvent,
|
||||||
|
ButtonPressedEvent,
|
||||||
|
ButtonReleasedEvent>;
|
||||||
|
|
||||||
|
using EventCallback = std::function<bool(const Event &)>;
|
||||||
|
|
||||||
|
using WindowsNativeHandle = void *;
|
||||||
|
|
||||||
|
using X11NativeHandle = unsigned long;
|
||||||
|
|
||||||
|
using NativeHandle = std::variant<WindowsNativeHandle, X11NativeHandle>;
|
||||||
|
|
||||||
struct CreateInfo
|
struct CreateInfo
|
||||||
{
|
{
|
||||||
std::string_view title;
|
std::string_view title;
|
||||||
|
@ -50,17 +86,17 @@ public:
|
||||||
return m_visible;
|
return m_visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_native_handle() const -> void *
|
[[nodiscard]] auto get_native_handle() const -> NativeHandle
|
||||||
{
|
{
|
||||||
return m_native_handle;
|
return m_native_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
[[nodiscard]] auto get_glfw_handle() const -> GLFWwindow *
|
[[nodiscard]] auto get_glfw_handle() const -> GLFWwindow *
|
||||||
{
|
{
|
||||||
return m_glfw_handle;
|
return m_glfw_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
std::string_view m_title;
|
std::string_view m_title;
|
||||||
|
|
||||||
math::uvec2 m_size;
|
math::uvec2 m_size;
|
||||||
|
@ -69,9 +105,11 @@ private:
|
||||||
|
|
||||||
bool m_visible;
|
bool m_visible;
|
||||||
|
|
||||||
void *m_native_handle {};
|
NativeHandle m_native_handle;
|
||||||
|
|
||||||
GLFWwindow *m_glfw_handle {};
|
GLFWwindow *m_glfw_handle {};
|
||||||
|
|
||||||
|
std::vector<EventCallback> m_event_callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lt::surface
|
} // namespace lt::surface
|
||||||
|
|
|
@ -4,38 +4,13 @@
|
||||||
#include <ecs/entity.hpp>
|
#include <ecs/entity.hpp>
|
||||||
#include <ecs/scene.hpp>
|
#include <ecs/scene.hpp>
|
||||||
#include <surface/components.hpp>
|
#include <surface/components.hpp>
|
||||||
#include <surface/events/keyboard.hpp>
|
|
||||||
#include <surface/events/mouse.hpp>
|
|
||||||
#include <surface/events/surface.hpp>
|
|
||||||
|
|
||||||
namespace lt::surface {
|
namespace lt::surface {
|
||||||
|
|
||||||
class System: public app::ISystem
|
class System: public app::ISystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Event = std::variant<
|
[[nodiscard]] System(Ref<ecs::Registry> registry);
|
||||||
// surface events
|
|
||||||
ClosedEvent,
|
|
||||||
MovedEvent,
|
|
||||||
ResizedEvent,
|
|
||||||
LostFocusEvent,
|
|
||||||
GainFocusEvent,
|
|
||||||
|
|
||||||
// keyboard events
|
|
||||||
KeyPressedEvent,
|
|
||||||
KeyRepeatEvent,
|
|
||||||
KeyReleasedEvent,
|
|
||||||
KeySetCharEvent,
|
|
||||||
|
|
||||||
// mouse events
|
|
||||||
MouseMovedEvent,
|
|
||||||
WheelScrolledEvent,
|
|
||||||
ButtonPressedEvent,
|
|
||||||
ButtonReleasedEvent>;
|
|
||||||
|
|
||||||
using EventCallback = std::function<bool(const Event &)>;
|
|
||||||
|
|
||||||
System(Ref<ecs::Registry> registry);
|
|
||||||
|
|
||||||
~System() override;
|
~System() override;
|
||||||
|
|
||||||
|
@ -47,7 +22,11 @@ public:
|
||||||
|
|
||||||
auto operator=(const System &) -> System & = delete;
|
auto operator=(const System &) -> System & = delete;
|
||||||
|
|
||||||
void init() override
|
void on_register() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_unregister() override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,19 +40,16 @@ public:
|
||||||
|
|
||||||
void set_visibility(ecs::Entity surface_entity, bool visible);
|
void set_visibility(ecs::Entity surface_entity, bool visible);
|
||||||
|
|
||||||
void add_event_listener(EventCallback callback)
|
void add_event_listener(ecs::Entity surface_entity, SurfaceComponent::EventCallback callback);
|
||||||
{
|
|
||||||
m_event_callbacks.emplace_back(std::move(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void on_surface_construct(entt::registry ®istry, entt::entity entity);
|
void on_surface_construct(entt::registry ®istry, entt::entity entity);
|
||||||
|
|
||||||
|
void on_surface_update(entt::registry ®istry, entt::entity entity);
|
||||||
|
|
||||||
void on_surface_destroy(entt::registry ®istry, entt::entity entity);
|
void on_surface_destroy(entt::registry ®istry, entt::entity entity);
|
||||||
|
|
||||||
Ref<ecs::Registry> m_registry;
|
Ref<ecs::Registry> m_registry;
|
||||||
|
|
||||||
std::vector<EventCallback> m_event_callbacks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,27 @@ constexpr void expect_false(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr void expect_not_nullptr(
|
||||||
|
auto *pointer,
|
||||||
|
std::source_location source_location = std::source_location::current()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (pointer == nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format(
|
||||||
|
"Failed true expectation:\n"
|
||||||
|
"\tactual: nullptr\n"
|
||||||
|
"\texpected: not nullptr\n"
|
||||||
|
"\tlocation: {}:{}",
|
||||||
|
source_location.file_name(),
|
||||||
|
source_location.line()
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
constexpr void expect_le(
|
constexpr void expect_le(
|
||||||
Testable auto lhs,
|
Testable auto lhs,
|
||||||
Testable auto rhs,
|
Testable auto rhs,
|
||||||
|
|
|
@ -84,7 +84,8 @@ struct Case
|
||||||
{
|
{
|
||||||
auto operator=(std::invocable auto test) -> void // NOLINT
|
auto operator=(std::invocable auto test) -> void // NOLINT
|
||||||
{
|
{
|
||||||
std::cout << "Running... " << name;
|
std::cout << "[Running-----------] --> ";
|
||||||
|
std::cout << name << '\n';
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -92,14 +93,14 @@ struct Case
|
||||||
}
|
}
|
||||||
catch (const std::exception &exp)
|
catch (const std::exception &exp)
|
||||||
{
|
{
|
||||||
std::cout << " --> FAIL !" << '\n';
|
std::cout << exp.what() << "\n";
|
||||||
std::cout << exp.what() << "\n\n";
|
std::cout << "[-----------FAIL !!]" << "\n\n";
|
||||||
details::Registry::increment_failed_count();
|
details::Registry::increment_failed_count();
|
||||||
return; // TODO(Light): Should we run the remaining tests after a failure?
|
return; // TODO(Light): Should we run the remaining tests after a failure?
|
||||||
}
|
}
|
||||||
|
|
||||||
details::Registry::increment_passed_count();
|
details::Registry::increment_passed_count();
|
||||||
std::cout << " --> SUCCESS :D" << "\n";
|
std::cout << "[--------SUCCESS :D]" << "\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view name;
|
std::string_view name;
|
||||||
|
|
Loading…
Add table
Reference in a new issue