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() | ||||
| { | ||||
| 	for (auto &system : m_systems) | ||||
| 	{ | ||||
| 		system->init(); | ||||
| 	} | ||||
| 
 | ||||
| 	while (true) | ||||
| 	{ | ||||
| 		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( | ||||
| 			    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) | ||||
| { | ||||
| 	m_systems_to_be_removed.emplace_back(std::move(system)); | ||||
| 	m_systems_to_be_unregistered.emplace_back(std::move(system)); | ||||
| } | ||||
| 
 | ||||
| } // namespace lt::app
 | ||||
|  |  | |||
|  | @ -35,7 +35,9 @@ protected: | |||
| private: | ||||
| 	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; | ||||
| 
 | ||||
| 	virtual void init() = 0; | ||||
| 	virtual void on_register() = 0; | ||||
| 
 | ||||
| 	virtual void on_unregister() = 0; | ||||
| 
 | ||||
| 	virtual auto tick() -> bool = 0; | ||||
| }; | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <format> | ||||
| #include <logger/logger.hpp> | ||||
| #include <source_location> | ||||
| 
 | ||||
| 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> | ||||
| 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 | ||||
| { | ||||
| 	// 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 {}; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,6 +19,12 @@ public: | |||
| 		return m_registry.group(entt::get<T...>); | ||||
| 	} | ||||
| 
 | ||||
| 	template<typename T> | ||||
| 	auto view() | ||||
| 	{ | ||||
| 		return m_registry.view<T>(); | ||||
| 	} | ||||
| 
 | ||||
| 	auto create_entity( | ||||
| 	    const std::string &name, | ||||
| 	    const TransformComponent &transform = TransformComponent() | ||||
|  | @ -31,6 +37,7 @@ public: | |||
| 		return m_registry; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| private: | ||||
| 	friend class Entity; | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| 
 | ||||
| namespace lt::math { | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * let... | ||||
|  * a = h / w ==> for aspect ratio adjustment | ||||
|  |  | |||
|  | @ -22,23 +22,26 @@ public: | |||
| 		setup_window_system(); | ||||
| 		register_systems(); | ||||
| 
 | ||||
| 		m_window_system->add_event_listener([&](const surface::System::Event &event) { | ||||
| 			const auto visitor = overloads { | ||||
| 				[&](const lt::surface::KeyPressedEvent &event) { | ||||
| 				    std::cout << "key pressed: " << event.to_string() << std::endl; | ||||
| 		m_window_system->add_event_listener( | ||||
| 		    m_window, | ||||
| 		    [&](const surface::SurfaceComponent::Event &event) { | ||||
| 			    const auto visitor = overloads { | ||||
| 				    [&](const lt::surface::KeyPressedEvent &event) { | ||||
| 				        std::cout << "key pressed: " << event.to_string() << std::endl; | ||||
| 
 | ||||
| 				    if (event.get_key() == 81) | ||||
| 				    { | ||||
| 					    unregister_system(m_window_system); | ||||
| 					    log_inf("Quitting..."); | ||||
| 				    } | ||||
| 				    return true; | ||||
| 				}, | ||||
| 				[](const auto &) { return false; }, | ||||
| 			}; | ||||
| 				        if (event.get_key() == 81) | ||||
| 				        { | ||||
| 					        unregister_system(m_window_system); | ||||
| 					        log_inf("Quitting..."); | ||||
| 				        } | ||||
| 				        return true; | ||||
| 				    }, | ||||
| 				    [](const auto &) { return false; }, | ||||
| 			    }; | ||||
| 
 | ||||
| 			return std::visit(visitor, event); | ||||
| 		}); | ||||
| 			    return std::visit(visitor, event); | ||||
| 		    } | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	void setup_window_system() | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| if (NOT WIN32) | ||||
|     add_library_module(surface system.cpp linux/system.cpp) | ||||
|     add_library_module(surface linux/system.cpp) | ||||
| else() | ||||
| endif() | ||||
| 
 | ||||
|  | @ -11,3 +11,6 @@ target_link_libraries(surface PUBLIC | |||
|     logger  | ||||
|     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/glfw3native.h> | ||||
| #include <surface/system.hpp> | ||||
| 
 | ||||
| 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) | ||||
| 	); | ||||
| 
 | ||||
|  | @ -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) | ||||
| { | ||||
| 	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'"); | ||||
| 
 | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
| 	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 { | ||||
| 
 | ||||
| // 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
 | ||||
|  |  | |||
|  | @ -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 | ||||
| 
 | ||||
| #include <math/vec2.hpp> | ||||
| #include <surface/events/keyboard.hpp> | ||||
| #include <surface/events/mouse.hpp> | ||||
| #include <surface/events/surface.hpp> | ||||
| #include <variant> | ||||
| 
 | ||||
| struct GLFWwindow; | ||||
| 
 | ||||
| namespace lt::surface { | ||||
| 
 | ||||
| /** Represents a platform's surface (eg. a Window).
 | ||||
|  * | ||||
|  * @note Read-only component, should only be modified through a system. | ||||
|  */ | ||||
| class SurfaceComponent | ||||
| { | ||||
| public: | ||||
| 	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 | ||||
| 	{ | ||||
| 		std::string_view title; | ||||
|  | @ -50,17 +86,17 @@ public: | |||
| 		return m_visible; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_native_handle() const -> void * | ||||
| 	[[nodiscard]] auto get_native_handle() const -> NativeHandle | ||||
| 	{ | ||||
| 		return m_native_handle; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	[[nodiscard]] auto get_glfw_handle() const -> GLFWwindow * | ||||
| 	{ | ||||
| 		return m_glfw_handle; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	std::string_view m_title; | ||||
| 
 | ||||
| 	math::uvec2 m_size; | ||||
|  | @ -69,9 +105,11 @@ private: | |||
| 
 | ||||
| 	bool m_visible; | ||||
| 
 | ||||
| 	void *m_native_handle {}; | ||||
| 	NativeHandle m_native_handle; | ||||
| 
 | ||||
| 	GLFWwindow *m_glfw_handle {}; | ||||
| 
 | ||||
| 	std::vector<EventCallback> m_event_callbacks; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::surface
 | ||||
|  |  | |||
|  | @ -4,38 +4,13 @@ | |||
| #include <ecs/entity.hpp> | ||||
| #include <ecs/scene.hpp> | ||||
| #include <surface/components.hpp> | ||||
| #include <surface/events/keyboard.hpp> | ||||
| #include <surface/events/mouse.hpp> | ||||
| #include <surface/events/surface.hpp> | ||||
| 
 | ||||
| namespace lt::surface { | ||||
| 
 | ||||
| class System: public app::ISystem | ||||
| { | ||||
| public: | ||||
| 	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 &)>; | ||||
| 
 | ||||
| 	System(Ref<ecs::Registry> registry); | ||||
| 	[[nodiscard]] System(Ref<ecs::Registry> registry); | ||||
| 
 | ||||
| 	~System() override; | ||||
| 
 | ||||
|  | @ -47,7 +22,11 @@ public: | |||
| 
 | ||||
| 	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 add_event_listener(EventCallback callback) | ||||
| 	{ | ||||
| 		m_event_callbacks.emplace_back(std::move(callback)); | ||||
| 	} | ||||
| 	void add_event_listener(ecs::Entity surface_entity, SurfaceComponent::EventCallback callback); | ||||
| 
 | ||||
| private: | ||||
| 	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); | ||||
| 
 | ||||
| 	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( | ||||
|     Testable auto lhs, | ||||
|     Testable auto rhs, | ||||
|  |  | |||
|  | @ -84,7 +84,8 @@ struct Case | |||
| { | ||||
| 	auto operator=(std::invocable auto test) -> void // NOLINT
 | ||||
| 	{ | ||||
| 		std::cout << "Running... " << name; | ||||
| 		std::cout << "[Running-----------] --> "; | ||||
|         std::cout << name << '\n'; | ||||
| 
 | ||||
| 		try | ||||
| 		{ | ||||
|  | @ -92,14 +93,14 @@ struct Case | |||
| 		} | ||||
| 		catch (const std::exception &exp) | ||||
| 		{ | ||||
| 			std::cout << " --> FAIL !" << '\n'; | ||||
| 			std::cout << exp.what() << "\n\n"; | ||||
| 			std::cout << exp.what() << "\n"; | ||||
| 			std::cout << "[-----------FAIL !!]" << "\n\n"; | ||||
| 			details::Registry::increment_failed_count(); | ||||
| 			return; // TODO(Light): Should we run the remaining tests after a failure?
 | ||||
| 		} | ||||
| 
 | ||||
| 		details::Registry::increment_passed_count(); | ||||
| 		std::cout << " --> SUCCESS :D" << "\n"; | ||||
| 		std::cout << "[--------SUCCESS :D]" << "\n\n"; | ||||
| 	} | ||||
| 
 | ||||
| 	std::string_view name; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue