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