feat: surface system This commit puts the project in major jeopardy as it overhauls the architecture such as removing the layer stack completely, etc. I am filled with determination.
This commit is contained in:
		
							parent
							
								
									d9229ad912
								
							
						
					
					
						commit
						2b96a85b62
					
				
					 52 changed files with 1094 additions and 1751 deletions
				
			
		|  | @ -4,22 +4,21 @@ add_subdirectory(./time) | |||
| add_subdirectory(./logger) | ||||
| add_subdirectory(./debug) | ||||
| add_subdirectory(./math) | ||||
| 
 | ||||
| #  | ||||
| add_subdirectory(./asset_baker) | ||||
| add_subdirectory(./asset_parser) | ||||
| add_subdirectory(./asset_manager) | ||||
| 
 | ||||
| # add_subdirectory(./asset_manager) | ||||
| #  | ||||
| add_subdirectory(./camera) | ||||
| add_subdirectory(./input) | ||||
| add_subdirectory(./ui) | ||||
| 
 | ||||
| add_subdirectory(./window) | ||||
| add_subdirectory(./renderer) | ||||
| # add_subdirectory(./input) | ||||
| # add_subdirectory(./ui) | ||||
| #  | ||||
| add_subdirectory(./surface) | ||||
| # add_subdirectory(./renderer) | ||||
| add_subdirectory(./ecs) | ||||
| 
 | ||||
| #  | ||||
| add_subdirectory(./app) | ||||
| 
 | ||||
| # apps  | ||||
| add_subdirectory(./mirror) | ||||
| 
 | ||||
| add_subdirectory(test) | ||||
|  |  | |||
|  | @ -1,21 +1,2 @@ | |||
| add_library_module(app | ||||
|     application.cpp | ||||
|     layer.cpp | ||||
|     layer_stack.cpp | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(app | ||||
| PUBLIC  | ||||
|     renderer | ||||
|     logger | ||||
|     ui | ||||
|     asset_parser | ||||
|     asset_manager | ||||
|     lt_debug  | ||||
|     ecs  | ||||
|     window | ||||
|     glad | ||||
|     time | ||||
|     opengl::opengl | ||||
|     EnTT::EnTT | ||||
| ) | ||||
| add_library_module(app application.cpp) | ||||
| target_link_libraries(app PRIVATE lt_debug) | ||||
|  |  | |||
|  | @ -1,203 +1,48 @@ | |||
| #include <app/application.hpp> | ||||
| #include <app/layer.hpp> | ||||
| #include <app/layer_stack.hpp> | ||||
| #include <asset_manager/asset_manager.hpp> | ||||
| #include <input/events/event.hpp> | ||||
| #include <input/events/keyboard.hpp> | ||||
| #include <input/events/window.hpp> | ||||
| #include <input/input.hpp> | ||||
| #include <lt_debug/assertions.hpp> | ||||
| #include <ranges> | ||||
| #include <renderer/blender.hpp> | ||||
| #include <renderer/graphics_context.hpp> | ||||
| #include <renderer/render_command.hpp> | ||||
| #include <renderer/renderer.hpp> | ||||
| #include <ui/ui.hpp> | ||||
| #include <window/window.hpp> | ||||
| #include <app/system.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| Application *Application::s_instance = nullptr; | ||||
| 
 | ||||
| Application::Application(): m_window(nullptr) | ||||
| { | ||||
| 	ensure(!s_instance, "Application constructed twice"); | ||||
| 	s_instance = this; | ||||
| 
 | ||||
| 	m_window = Window::create([this](auto &&PH1) { on_event(std::forward<decltype(PH1)>(PH1)); }); | ||||
| 
 | ||||
| 	// create graphics context
 | ||||
| 	m_graphics_context = GraphicsContext::create( | ||||
| 	    GraphicsAPI::OpenGL, | ||||
| 	    (GLFWwindow *)m_window->get_handle() | ||||
| 	); | ||||
| 
 | ||||
| 	AssetManager::load_shader( | ||||
| 	    "LT_ENGINE_RESOURCES_TEXTURE_SHADER", | ||||
| 	    "data/assets/shaders/texture/vs.asset", | ||||
| 	    "data/assets/shaders/texture/ps.asset" | ||||
| 	); | ||||
| 
 | ||||
| 	AssetManager::load_shader( | ||||
| 	    "LT_ENGINE_RESOURCES_TINTED_TEXTURE_SHADER", | ||||
| 	    "data/assets/shaders/tinted_texture/vs.asset", | ||||
| 	    "data/assets/shaders/tinted_texture/ps.asset" | ||||
| 	); | ||||
| 
 | ||||
| 	AssetManager::load_shader( | ||||
| 	    "LT_ENGINE_RESOURCES_QUAD_SHADER", | ||||
| 	    "data/assets/shaders/quads/vs.asset", | ||||
| 	    "data/assets/shaders/quads/ps.asset" | ||||
| 	); | ||||
| 
 | ||||
| 	m_renderer = Renderer::create( | ||||
| 	    (GLFWwindow *)m_window->get_handle(), | ||||
| 	    lt::GraphicsContext::get_shared_context(), | ||||
| 	    Renderer::CreateInfo { | ||||
| 	        .quad_renderer_shader = AssetManager::get_shader("LT_ENGINE_RESOURCES_QUAD_SHADER"), | ||||
| 	        .texture_renderer_shader = AssetManager::get_shader( | ||||
| 	            "LT_ENGINE_RESOURCES_TEXTURE_SHADER" | ||||
| 	        ), | ||||
| 	        .tinted_texture_renderer_shader = AssetManager::get_shader( | ||||
| 	            "LT_ENGINE_RESOURCES_TINTED_" | ||||
| 	            "TEXTURE_SHADER" | ||||
| 	        ), | ||||
| 	    } | ||||
| 	); | ||||
| 	ensure(m_graphics_context, "lWindow::lWindow: failed to create 'GraphicsContext'"); | ||||
| 
 | ||||
| 	m_user_interface = UserInterface::create( | ||||
| 	    (GLFWwindow *)m_window->get_handle(), | ||||
| 	    lt::GraphicsContext::get_shared_context() | ||||
| 	); | ||||
| 
 | ||||
| 	m_layer_stack = create_scope<LayerStack>(); | ||||
| } | ||||
| 
 | ||||
| Application::~Application() | ||||
| { | ||||
| 	/** This is required to make forward-declarations possible:
 | ||||
| 	 * https://stackoverflow.com/questions/34072862/why-is-error-invalid-application-of-sizeof-to-an-incomplete-type-using-uniqu
 | ||||
| 	 */ | ||||
| } | ||||
| namespace lt::app { | ||||
| 
 | ||||
| void Application::game_loop() | ||||
| { | ||||
| 	m_window->set_visibility(true); | ||||
| 
 | ||||
| 	while (!m_window->is_closed()) | ||||
| 	for (auto &system : m_systems) | ||||
| 	{ | ||||
| 		update_layers(); | ||||
| 		render_layers(); | ||||
| 		render_user_interface(); | ||||
| 		poll_events(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Application::quit() | ||||
| { | ||||
| 	s_instance->m_window->close(); | ||||
| } | ||||
| 
 | ||||
| void Application::update_layers() | ||||
| { | ||||
| 	for (auto &it : *m_layer_stack) | ||||
| 	{ | ||||
| 		// narrowing double -> float
 | ||||
| 		it->on_update(static_cast<float>(m_timer.elapsed_time().count())); | ||||
| 		system->init(); | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(Light): each layer should have their own "delta time"
 | ||||
| 	m_timer.reset(); | ||||
| } | ||||
| 
 | ||||
| void Application::render_layers() | ||||
| { | ||||
| 	m_renderer->begin_frame(); | ||||
| 
 | ||||
| 	for (auto &it : *m_layer_stack) | ||||
| 	while (true) | ||||
| 	{ | ||||
| 		it->on_render(); | ||||
| 	} | ||||
| 
 | ||||
| 	m_renderer->end_frame(); | ||||
| } | ||||
| 
 | ||||
| void Application::render_user_interface() | ||||
| { | ||||
| 	m_user_interface->begin(); | ||||
| 
 | ||||
| 	for (auto &it : *m_layer_stack) | ||||
| 	{ | ||||
| 		it->on_user_interface_update(); | ||||
| 	} | ||||
| 
 | ||||
| 	m_user_interface->end(); | ||||
| } | ||||
| 
 | ||||
| void Application::poll_events() | ||||
| { | ||||
| 	m_window->poll_events(); | ||||
| } | ||||
| 
 | ||||
| void Application::on_event(const Event &event) | ||||
| { | ||||
| 	// window
 | ||||
| 	if (event.has_category(WindowEventCategory)) | ||||
| 	{ | ||||
| 		m_window->on_event(event); | ||||
| 
 | ||||
| 		if (event.get_event_type() == EventType::WindowResized) | ||||
| 		for (auto &system : m_systems) | ||||
| 		{ | ||||
| 			m_renderer->on_window_resize(dynamic_cast<const WindowResizedEvent &>(event)); | ||||
| 			if (system->tick()) | ||||
| 			{ | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// input
 | ||||
| 	if (event.has_category(InputEventCategory)) | ||||
| 	{ | ||||
| 		Input::instance().on_event(event); | ||||
| 
 | ||||
| 		if (!Input::instance().is_receiving_game_events()) | ||||
| 		for (auto &system : m_systems_to_be_removed) | ||||
| 		{ | ||||
| 			return; | ||||
| 			m_systems.erase( | ||||
| 			    std::remove(m_systems.begin(), m_systems.end(), system), | ||||
| 			    m_systems.end() | ||||
| 			); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto &it : std::ranges::reverse_view(*m_layer_stack)) | ||||
| 	{ | ||||
| 		if (it->on_event(event)) | ||||
| 		if (m_systems.empty()) | ||||
| 		{ | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] auto Application::sanity_check() const -> bool | ||||
| void Application::register_system(Ref<app::ISystem> system) | ||||
| { | ||||
| 	log_inf("Checking application sanity..."); | ||||
| 	ensure(s_instance, "Application not constructed!?"); | ||||
| 	ensure(m_window, "Window is not initialized"); | ||||
| 	ensure(m_user_interface, "User interface is not initialized"); | ||||
| 	ensure(m_graphics_context, "Graphics context is not initialized"); | ||||
| 	ensure(m_renderer, "Renderer is not initialized"); | ||||
| 	ensure(m_layer_stack, "Layer_stack is not initialized"); | ||||
| 	ensure(!m_layer_stack->is_empty(), "Layer_stack is empty"); | ||||
| 
 | ||||
| 	log_inf("Logging application state..."); | ||||
| 	this->log_debug_data(); | ||||
| 	m_graphics_context->log_debug_data(); | ||||
| 	m_user_interface->log_debug_data(); | ||||
| 
 | ||||
| 	return true; | ||||
| 	m_systems.emplace_back(std::move(system)); | ||||
| } | ||||
| 
 | ||||
| void Application::log_debug_data() const | ||||
| void Application::unregister_system(Ref<app::ISystem> system) | ||||
| { | ||||
| 	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()); | ||||
| 	m_systems_to_be_removed.emplace_back(std::move(system)); | ||||
| } | ||||
| 
 | ||||
| } // namespace lt
 | ||||
| } // namespace lt::app
 | ||||
|  |  | |||
|  | @ -1,47 +0,0 @@ | |||
| #include <app/layer.hpp> | ||||
| #include <input/events/char.hpp> | ||||
| #include <input/events/event.hpp> | ||||
| #include <input/events/keyboard.hpp> | ||||
| #include <input/events/mouse.hpp> | ||||
| #include <input/events/window.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| Layer::Layer(std::string name): m_layer_name(std::move(name)) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| auto Layer::on_event(const Event &event) -> bool | ||||
| { | ||||
| 	switch (event.get_event_type()) | ||||
| 	{ | ||||
| 	case EventType::MouseMoved: return on_mouse_moved(dynamic_cast<const MouseMovedEvent &>(event)); | ||||
| 	case EventType::ButtonPressed: | ||||
| 		return on_button_pressed(dynamic_cast<const ButtonPressedEvent &>(event)); | ||||
| 	case EventType::ButtonReleased: | ||||
| 		return on_button_released(dynamic_cast<const ButtonReleasedEvent &>(event)); | ||||
| 	case EventType::WheelScrolled: | ||||
| 		return on_wheel_scrolled(dynamic_cast<const WheelScrolledEvent &>(event)); | ||||
| 
 | ||||
| 	case EventType::KeyPressed: return on_key_pressed(dynamic_cast<const KeyPressedEvent &>(event)); | ||||
| 	case EventType::KeyRepeated: return on_key_repeat(dynamic_cast<const KeyRepeatEvent &>(event)); | ||||
| 	case EventType::KeyReleased: | ||||
| 		return on_key_released(dynamic_cast<const KeyReleasedEvent &>(event)); | ||||
| 	case EventType::SetChar: return on_set_char(dynamic_cast<const SetCharEvent &>(event)); | ||||
| 
 | ||||
| 	case EventType::WindowClosed: | ||||
| 		return on_window_closed(dynamic_cast<const WindowClosedEvent &>(event)); | ||||
| 	case EventType::WindowResized: | ||||
| 		return on_window_resized(dynamic_cast<const WindowResizedEvent &>(event)); | ||||
| 	case EventType::WindowMoved: | ||||
| 		return on_window_moved(dynamic_cast<const WindowMovedEvent &>(event)); | ||||
| 	case EventType::WindowLostFocus: | ||||
| 		return on_window_lost_focus(dynamic_cast<const WindowLostFocusEvent &>(event)); | ||||
| 	case EventType::WindowGainFocus: | ||||
| 		return on_window_gain_focus(dynamic_cast<const WindowGainFocusEvent &>(event)); | ||||
| 
 | ||||
| 	default: ensure(false, "Invalid event: {}", event.get_info_lt_log()); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,18 +0,0 @@ | |||
| #include <app/layer.hpp> | ||||
| #include <app/layer_stack.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| void LayerStack::attach_layer(Ref<Layer> layer) | ||||
| { | ||||
| 	log_trc("Attaching layer [{}]", layer->get_name()); | ||||
| 	m_layers.emplace_back(std::move(layer)); | ||||
| } | ||||
| 
 | ||||
| void LayerStack::detach_layer(const Ref<Layer> &layer) | ||||
| { | ||||
| 	log_trc("Detaching layer [{}]", layer->get_name()); | ||||
| 	m_layers.erase(std::find(m_layers.begin(), m_layers.end(), layer)); | ||||
| } | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,18 +1,15 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <time/timer.hpp> | ||||
| namespace lt::app { | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class Renderer; | ||||
| class Window; | ||||
| class Event; | ||||
| class GraphicsContext; | ||||
| class UserInterface; | ||||
| class LayerStack; | ||||
| class ISystem; | ||||
| 
 | ||||
| extern Scope<class Application> create_application(); | ||||
| 
 | ||||
| /** The main application class.
 | ||||
|  * Think of this like an aggregate of systems, you register systems through this interface. | ||||
|  * Then they'll tick every "application frame". | ||||
|  */ | ||||
| class Application | ||||
| { | ||||
| public: | ||||
|  | @ -24,54 +21,22 @@ public: | |||
| 
 | ||||
| 	auto operator=(Application &&) -> Application & = delete; | ||||
| 
 | ||||
| 	virtual ~Application(); | ||||
| 
 | ||||
| 	[[nodiscard]] auto sanity_check() const -> bool; | ||||
| 	virtual ~Application() = default; | ||||
| 
 | ||||
| 	void game_loop(); | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_window() -> Window & | ||||
| 	{ | ||||
| 		return *m_window; | ||||
| 	} | ||||
| 	void register_system(Ref<app::ISystem> system); | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_layer_stack() -> LayerStack & | ||||
| 	{ | ||||
| 		return *m_layer_stack; | ||||
| 	} | ||||
| 
 | ||||
| 	static void quit(); | ||||
| 	void unregister_system(Ref<app::ISystem> system); | ||||
| 
 | ||||
| protected: | ||||
| 	Application(); | ||||
| 	Application() = default; | ||||
| 
 | ||||
| private: | ||||
| 	void update_layers(); | ||||
| 	std::vector<Ref<app::ISystem>> m_systems; | ||||
| 
 | ||||
| 	void render_layers(); | ||||
| 
 | ||||
| 	void render_user_interface(); | ||||
| 
 | ||||
| 	void poll_events(); | ||||
| 
 | ||||
| 	void on_event(const Event &event); | ||||
| 
 | ||||
| 	void log_debug_data() const; | ||||
| 
 | ||||
| 	Timer m_timer; | ||||
| 
 | ||||
| 	Scope<Window> m_window; | ||||
| 
 | ||||
| 	Scope<UserInterface> m_user_interface; | ||||
| 
 | ||||
| 	Scope<GraphicsContext> m_graphics_context; | ||||
| 
 | ||||
| 	Scope<Renderer> m_renderer; | ||||
| 
 | ||||
| 	Scope<LayerStack> m_layer_stack; | ||||
| 
 | ||||
| 	static Application *s_instance; | ||||
| 	std::vector<Ref<app::ISystem>> m_systems_to_be_removed; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } // namespace lt
 | ||||
| } // namespace lt::app
 | ||||
|  |  | |||
|  | @ -2,21 +2,21 @@ | |||
| 
 | ||||
| #include <app/application.hpp> | ||||
| 
 | ||||
| int main(int argc, char *argv[]) // NOLINT
 | ||||
| auto main(int argc, char *argv[]) -> int32_t | ||||
| try | ||||
| { | ||||
| 	std::ignore = argc; | ||||
| 	std::ignore = argv; | ||||
| 
 | ||||
| 	auto application = lt::Scope<lt::Application> {}; | ||||
| 	auto application = lt::Scope<lt::app::Application> {}; | ||||
| 
 | ||||
| 	application = lt::create_application(); | ||||
| 
 | ||||
| 	lt::ensure(application, "Failed to create application"); | ||||
| 	lt::ensure(application->sanity_check(), "Failed to verify the sanity of the application"); | ||||
| 	application = lt::app::create_application(); | ||||
| 	if (!application) | ||||
| 	{ | ||||
| 		throw std::runtime_error { "Failed to create application\n" }; | ||||
| 	} | ||||
| 
 | ||||
| 	application->game_loop(); | ||||
| 
 | ||||
| 	return EXIT_SUCCESS; | ||||
| } | ||||
| catch (const std::exception &exp) | ||||
|  |  | |||
|  | @ -1,116 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class Event; | ||||
| 
 | ||||
| class MouseMovedEvent; | ||||
| class ButtonPressedEvent; | ||||
| class ButtonReleasedEvent; | ||||
| class WheelScrolledEvent; | ||||
| class KeyPressedEvent; | ||||
| class KeyRepeatEvent; | ||||
| class KeyReleasedEvent; | ||||
| class SetCharEvent; | ||||
| class WindowClosedEvent; | ||||
| class WindowResizedEvent; | ||||
| class WindowMovedEvent; | ||||
| class WindowLostFocusEvent; | ||||
| class WindowGainFocusEvent; | ||||
| 
 | ||||
| class Layer | ||||
| { | ||||
| public: | ||||
| 	Layer(std::string name); | ||||
| 
 | ||||
| 	virtual ~Layer() = default; | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_name() const -> const std::string & | ||||
| 	{ | ||||
| 		return m_layer_name; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void on_update(float deltaTime) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void on_user_interface_update() | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void on_render() | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	auto on_event(const Event &event) -> bool; | ||||
| 
 | ||||
| protected: | ||||
| 	std::string m_layer_name; | ||||
| 
 | ||||
| 	virtual auto on_mouse_moved(const MouseMovedEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_button_pressed(const ButtonPressedEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_button_released(const ButtonReleasedEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_wheel_scrolled(const WheelScrolledEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_key_pressed(const KeyPressedEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_key_repeat(const KeyRepeatEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_key_released(const KeyReleasedEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_set_char(const SetCharEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_window_closed(const WindowClosedEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_window_resized(const WindowResizedEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_window_moved(const WindowMovedEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_window_lost_focus(const WindowLostFocusEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto on_window_gain_focus(const WindowGainFocusEvent & /*event*/) -> bool | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,50 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class Layer; | ||||
| class Event; | ||||
| 
 | ||||
| class LayerStack | ||||
| { | ||||
| public: | ||||
| 	template<typename Layer_T, typename... Args> | ||||
| 	void emplace_layer(Args &&...args) | ||||
| 	{ | ||||
| 		attach_layer(create_ref<Layer_T>(std::forward<Args>(args)...)); | ||||
| 	} | ||||
| 
 | ||||
| 	void attach_layer(Ref<Layer> layer); | ||||
| 
 | ||||
| 	void detach_layer(const Ref<Layer> &layer); | ||||
| 
 | ||||
| 	[[nodiscard]] auto is_empty() const -> bool | ||||
| 	{ | ||||
| 		return m_layers.empty(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto begin() -> std::vector<Ref<Layer>>::iterator | ||||
| 	{ | ||||
| 		return m_layers.begin(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto end() -> std::vector<Ref<Layer>>::iterator | ||||
| 	{ | ||||
| 		return m_layers.end(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto rbegin() -> std::vector<Ref<Layer>>::reverse_iterator | ||||
| 	{ | ||||
| 		return m_layers.rbegin(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto rend() -> std::vector<Ref<Layer>>::reverse_iterator | ||||
| 	{ | ||||
| 		return m_layers.rend(); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	std::vector<Ref<Layer>> m_layers; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
							
								
								
									
										25
									
								
								modules/app/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								modules/app/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| #pragma once | ||||
| 
 | ||||
| namespace lt::app { | ||||
| 
 | ||||
| class ISystem | ||||
| { | ||||
| public: | ||||
| 	ISystem() = default; | ||||
| 
 | ||||
| 	virtual ~ISystem() = default; | ||||
| 
 | ||||
| 	ISystem(ISystem &&) = default; | ||||
| 
 | ||||
| 	ISystem(const ISystem &) = delete; | ||||
| 
 | ||||
| 	auto operator=(ISystem &&) -> ISystem & = default; | ||||
| 
 | ||||
| 	auto operator=(const ISystem &) -> ISystem & = delete; | ||||
| 
 | ||||
| 	virtual void init() = 0; | ||||
| 
 | ||||
| 	virtual auto tick() -> bool = 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::app
 | ||||
|  | @ -5,5 +5,5 @@ add_library_module(asset_manager | |||
| target_link_libraries( | ||||
|   asset_manager | ||||
|   PUBLIC asset_parser | ||||
|   PRIVATE renderer | ||||
|   PRIVATE logger | ||||
| ) | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| add_library_module(ecs entity.cpp scene.cpp uuid.cpp serializer.cpp) | ||||
| add_library_module(ecs entity.cpp scene.cpp uuid.cpp ) | ||||
| target_link_libraries(ecs  | ||||
|     PUBLIC logger lt_debug EnTT::EnTT renderer input camera | ||||
|     PRIVATE yaml-cpp::yaml-cpp asset_manager | ||||
|     PUBLIC logger lt_debug EnTT::EnTT  input camera math | ||||
| ) | ||||
|  |  | |||
|  | @ -1,73 +1,9 @@ | |||
| #include <camera/component.hpp> | ||||
| #include <ecs/components.hpp> | ||||
| #include <ecs/entity.hpp> | ||||
| #include <ecs/scene.hpp> | ||||
| #include <renderer/renderer.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| void Scene::on_create() | ||||
| { | ||||
| 	/* native scripts */ | ||||
| 	{ | ||||
| 		m_registry.view<NativeScriptComponent>().each([](NativeScriptComponent &nsc) { | ||||
| 			if (nsc.instance == nullptr) | ||||
| 			{ | ||||
| 				nsc.instance = nsc.CreateInstance(); | ||||
| 				nsc.instance->on_create(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Scene::on_update(float deltaTime) | ||||
| { | ||||
| 	/* native scripts */ | ||||
| 	{ | ||||
| 		m_registry.view<NativeScriptComponent>().each([=](NativeScriptComponent &nsc) { | ||||
| 			nsc.instance->on_update(deltaTime); | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Scene::on_render(const Ref<Framebuffer> &targetFrameBuffer /* = nullptr */) | ||||
| { | ||||
| 	auto *sceneCamera = (Camera *)nullptr; | ||||
| 	auto *sceneCameraTransform = (TransformComponent *)nullptr; | ||||
| 
 | ||||
| 	/* scene camera */ | ||||
| 	{ | ||||
| 		m_registry.group(entt::get<TransformComponent, CameraComponent>) | ||||
| 		    .each([&](TransformComponent &transformComp, CameraComponent &cameraComp) { | ||||
| 			    if (cameraComp.isPrimary) | ||||
| 			    { | ||||
| 				    sceneCamera = &cameraComp.camera; | ||||
| 				    sceneCameraTransform = &transformComp; | ||||
| 			    } | ||||
| 		    }); | ||||
| 	} | ||||
| 
 | ||||
| 	/* draw quads */ | ||||
| 	{ | ||||
| 		if (sceneCamera) | ||||
| 		{ | ||||
| 			Renderer::begin_scene(sceneCamera, *sceneCameraTransform, targetFrameBuffer); | ||||
| 
 | ||||
| 			m_registry.group(entt::get<TransformComponent, SpriteRendererComponent>) | ||||
| 			    .each([](TransformComponent &transformComp, | ||||
| 			             SpriteRendererComponent &spriteRendererComp) { | ||||
| 				    Renderer::draw_quad( | ||||
| 				        transformComp, | ||||
| 				        spriteRendererComp.tint, | ||||
| 				        spriteRendererComp.texture | ||||
| 				    ); | ||||
| 			    }); | ||||
| 
 | ||||
| 			Renderer::end_scene(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| auto Scene::create_entity(const std::string &name, const TransformComponent &transform) -> Entity | ||||
| { | ||||
| 	return create_entity_with_uuid(name, UUID(), transform); | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| #include <ecs/components/transform.hpp> | ||||
| #include <ecs/uuid.hpp> | ||||
| #include <entt/entt.hpp> | ||||
| #include <functional> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
|  | @ -12,11 +13,11 @@ class Framebuffer; | |||
| class Scene | ||||
| { | ||||
| public: | ||||
| 	void on_create(); | ||||
| 
 | ||||
| 	void on_update(float deltaTime); | ||||
| 
 | ||||
| 	void on_render(const Ref<Framebuffer> &targetFrameBuffer = nullptr); | ||||
| 	template<typename... T> | ||||
| 	auto group() | ||||
| 	{ | ||||
| 		return m_registry.group(entt::get<T...>); | ||||
| 	} | ||||
| 
 | ||||
| 	auto create_entity( | ||||
| 	    const std::string &name, | ||||
|  | @ -25,6 +26,11 @@ public: | |||
| 
 | ||||
| 	auto get_entity_by_tag(const std::string &tag) -> Entity; | ||||
| 
 | ||||
| 	auto get_entt_registry() -> entt::registry & | ||||
| 	{ | ||||
| 		return m_registry; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	friend class Entity; | ||||
| 
 | ||||
|  | @ -41,4 +47,12 @@ private: | |||
| 	) -> Entity; | ||||
| }; | ||||
| 
 | ||||
| namespace ecs { | ||||
| 
 | ||||
| using Registry = Scene; | ||||
| 
 | ||||
| using Entity = ::lt::Entity; | ||||
| 
 | ||||
| } // namespace ecs
 | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| add_library_module(input input.cpp) | ||||
| target_link_libraries(input PUBLIC math imgui::imgui logger) | ||||
| target_link_libraries(input PUBLIC surface math imgui::imgui logger) | ||||
|  |  | |||
|  | @ -1,10 +1,5 @@ | |||
| #include <imgui.h> | ||||
| #include <input/events/char.hpp> | ||||
| #include <input/events/event.hpp> | ||||
| #include <input/events/keyboard.hpp> | ||||
| #include <input/events/mouse.hpp> | ||||
| #include <input/input.hpp> | ||||
| #include <input/key_codes.hpp> | ||||
| #include <logger/logger.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
|  |  | |||
							
								
								
									
										5
									
								
								modules/input/private/system.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								modules/input/private/system.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| #include <input/system.hpp> | ||||
| 
 | ||||
| namespace lt::input { | ||||
| 
 | ||||
| } // namespace lt::input
 | ||||
|  | @ -1,41 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <input/events/event.hpp> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class SetCharEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	SetCharEvent(unsigned int character): m_character(character) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_character() const -> int | ||||
| 	{ | ||||
| 		return m_character; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "CharSet: " << m_character; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::SetChar; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(InputEventCategory | KeyboardEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const unsigned int m_character; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,56 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| enum class EventType : uint8_t | ||||
| { | ||||
| 	None = 0, | ||||
| 
 | ||||
| 	// input
 | ||||
| 	MouseMoved, | ||||
| 	WheelScrolled, | ||||
| 	ButtonPressed, | ||||
| 	ButtonReleased, | ||||
| 	KeyPressed, | ||||
| 	KeyRepeated, | ||||
| 	KeyReleased, | ||||
| 	SetChar, | ||||
| 
 | ||||
| 	// window
 | ||||
| 	WindowMoved, | ||||
| 	WindowResized, | ||||
| 	WindowClosed, | ||||
| 	WindowLostFocus, | ||||
| 	WindowGainFocus, | ||||
| }; | ||||
| 
 | ||||
| enum EventCategory : uint8_t | ||||
| { | ||||
| 	None = 0, | ||||
| 
 | ||||
| 	WindowEventCategory = bit(0), | ||||
| 	InputEventCategory = bit(1), | ||||
| 	KeyboardEventCategory = bit(2), | ||||
| 	MouseEventCategory = bit(3), | ||||
| }; | ||||
| 
 | ||||
| class Event | ||||
| { | ||||
| public: | ||||
| 	Event() = default; | ||||
| 
 | ||||
| 	virtual ~Event() = default; | ||||
| 
 | ||||
| 	[[nodiscard]] virtual auto get_event_type() const -> EventType = 0; | ||||
| 
 | ||||
| 	[[nodiscard]] virtual auto get_info_lt_log() const -> std::string = 0; | ||||
| 
 | ||||
| 	[[nodiscard]] virtual auto has_category(EventCategory category) const -> bool = 0; | ||||
| 
 | ||||
| 	friend auto operator<<(std::ostream &os, const Event &e) -> std::ostream & | ||||
| 	{ | ||||
| 		return os << e.get_info_lt_log(); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,107 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <input/events/event.hpp> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class KeyPressedEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	KeyPressedEvent(int key): m_key(key) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_key() const -> int | ||||
| 	{ | ||||
| 		return m_key; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "KeyPressed: " << m_key; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::KeyPressed; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(InputEventCategory | KeyboardEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const int m_key; | ||||
| }; | ||||
| 
 | ||||
| class KeyRepeatEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	KeyRepeatEvent(int key): m_key(key) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_key() const -> int | ||||
| 	{ | ||||
| 		return m_key; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "KeyRepeated: " << m_key; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::KeyRepeated; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(InputEventCategory | KeyboardEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const int m_key; | ||||
| }; | ||||
| 
 | ||||
| class KeyReleasedEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	KeyReleasedEvent(int key): m_key(key) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_key() const -> int | ||||
| 	{ | ||||
| 		return m_key; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "KeyReleased: " << m_key; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::KeyReleased; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(InputEventCategory | KeyboardEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const int m_key; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,151 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <input/events/event.hpp> | ||||
| #include <math/vec2.hpp> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class MouseMovedEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	MouseMovedEvent(float x, float y): m_position(x, y) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_position() const -> const math::vec2 & | ||||
| 	{ | ||||
| 		return m_position; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_x() const -> float | ||||
| 	{ | ||||
| 		return m_position.x; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_y() const -> float | ||||
| 	{ | ||||
| 		return m_position.y; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "MouseMoved: " << m_position.x << ", " << m_position.y; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::MouseMoved; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(InputEventCategory | MouseEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const math::vec2 m_position; | ||||
| }; | ||||
| 
 | ||||
| class WheelScrolledEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	WheelScrolledEvent(float offset): m_offset(offset) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_offset() const -> float | ||||
| 	{ | ||||
| 		return m_offset; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "WheelScrolled: " << m_offset; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::WheelScrolled; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(InputEventCategory | MouseEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const float m_offset; | ||||
| }; | ||||
| 
 | ||||
| class ButtonPressedEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	ButtonPressedEvent(int button): m_button(button) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_button() const -> int | ||||
| 	{ | ||||
| 		return m_button; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "ButtonPressed: " << m_button; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::ButtonPressed; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(InputEventCategory | MouseEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const int m_button; | ||||
| }; | ||||
| 
 | ||||
| class ButtonReleasedEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	ButtonReleasedEvent(int button): m_button(button) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_button() const -> int | ||||
| 	{ | ||||
| 		return m_button; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "ButtonReleased: " << m_button; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::ButtonReleased; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(InputEventCategory | MouseEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const int m_button; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,133 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <input/events/event.hpp> | ||||
| #include <math/vec2.hpp> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class WindowClosedEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		return "WindowClosedEvent"; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::WindowClosed; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(WindowEventCategory) & category; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| class WindowMovedEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	WindowMovedEvent(int x, int y): m_position(x, y) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_position() const -> const math::ivec2 & | ||||
| 	{ | ||||
| 		return m_position; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "WindwoMoved: " << m_position.x << ", " << m_position.y; | ||||
| 		return ss.str(); | ||||
| 		; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::WindowMoved; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(WindowEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const math::ivec2 m_position; | ||||
| }; | ||||
| 
 | ||||
| class WindowResizedEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	WindowResizedEvent(unsigned int width, unsigned int height): m_size(width, height) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_size() const -> const math::uvec2 & | ||||
| 	{ | ||||
| 		return m_size; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "WindowResized: " << m_size.x << ", " << m_size.y; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::WindowResized; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(WindowEventCategory) & category; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	const math::uvec2 m_size; | ||||
| }; | ||||
| 
 | ||||
| class WindowLostFocusEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		return "WindowLostFocus"; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::WindowLostFocus; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(WindowEventCategory) & category; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| class WindowGainFocusEvent: public Event | ||||
| { | ||||
| public: | ||||
| 	[[nodiscard]] auto get_info_lt_log() const -> std::string override | ||||
| 	{ | ||||
| 		return "WindowGainFocus"; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_event_type() const -> EventType override | ||||
| 	{ | ||||
| 		return ::lt::EventType::WindowGainFocus; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto has_category(EventCategory category) const -> bool override | ||||
| 	{ | ||||
| 		return static_cast<uint8_t>(WindowEventCategory) & category; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
							
								
								
									
										64
									
								
								modules/input/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								modules/input/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <surface/system.hpp> | ||||
| 
 | ||||
| namespace lt::input { | ||||
| 
 | ||||
| template<class... Ts> | ||||
| struct overloads: Ts... | ||||
| { | ||||
| 	using Ts::operator()...; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * | ||||
|  * @note If this system is attached, it will always consume the input events f rom surface. | ||||
|  * Therefore if you want any input detection mechanism, callbacks should be setup with this | ||||
|  * system and not directly with surface. | ||||
|  */ | ||||
| class System | ||||
| { | ||||
| public: | ||||
| 	System(lt::surface::System &surface_system) | ||||
| 	{ | ||||
| 		surface_system.add_event_listener([this](auto &&event) { | ||||
| 			return handle_event(std::forward<decltype(event)>(event)); | ||||
| 		}); | ||||
| 	}; | ||||
| 
 | ||||
| private: | ||||
| 	auto handle_event(const lt::surface::System::Event &event) -> bool | ||||
| 	{ | ||||
| 		const auto visitor = overloads { | ||||
| 			[this](const lt::surface::KeyPressedEvent &event) { | ||||
| 			    m_keys[event.get_key()] = true; | ||||
| 			    return true; | ||||
| 			}, | ||||
| 
 | ||||
| 			[](const lt::surface::KeyRepeatEvent &) { return false; }, | ||||
| 
 | ||||
| 			[](const lt::surface::KeyReleasedEvent &) { return false; }, | ||||
| 
 | ||||
| 			[](const lt::surface::KeySetCharEvent &) { return false; }, | ||||
| 
 | ||||
| 			[](const lt::surface::MouseMovedEvent &) { return false; }, | ||||
| 
 | ||||
| 			[](const lt::surface::WheelScrolledEvent &) { return false; }, | ||||
| 
 | ||||
| 			[](const lt::surface::ButtonPressedEvent &) { return false; }, | ||||
| 
 | ||||
| 			[](const lt::surface::ButtonReleasedEvent &) { return false; }, | ||||
| 
 | ||||
| 			[](const auto &) { return false; }, | ||||
| 		}; | ||||
| 
 | ||||
| 		return std::visit(visitor, event); | ||||
| 	} | ||||
| 
 | ||||
| 	void setup_callbacks(GLFWwindow *handle); | ||||
| 
 | ||||
| 	std::array<bool, 512> m_keys {}; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } // namespace lt::input
 | ||||
|  | @ -1,16 +1,11 @@ | |||
| add_library_module(libmirror  | ||||
|     layers/editor_layer.cpp | ||||
|     panels/asset_browser.cpp | ||||
|     panels/properties.cpp | ||||
|     panels/scene_hierarchy.cpp | ||||
| ) | ||||
| target_link_libraries( | ||||
|   libmirror | ||||
|   PUBLIC app | ||||
|   PUBLIC opengl::opengl | ||||
|   PUBLIC ui | ||||
|   PUBLIC imgui | ||||
|   PUBLIC input | ||||
|   INTERFACE | ||||
|   app | ||||
|   opengl::opengl | ||||
|   surface | ||||
| ) | ||||
| 
 | ||||
| add_test_module(libmirror  | ||||
|  |  | |||
|  | @ -1,30 +1,74 @@ | |||
| #include <app/application.hpp> | ||||
| #include <app/entrypoint.hpp> | ||||
| #include <app/layer_stack.hpp> | ||||
| #include <app/system.hpp> | ||||
| #include <math/vec2.hpp> | ||||
| #include <mirror/layers/editor_layer.hpp> | ||||
| #include <window/window.hpp> | ||||
| #include <surface/system.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class Mirror: public Application | ||||
| template<class... Ts> | ||||
| struct overloads: Ts... | ||||
| { | ||||
| 	using Ts::operator()...; | ||||
| }; | ||||
| 
 | ||||
| class Mirror: public app::Application | ||||
| { | ||||
| public: | ||||
| 	Mirror() | ||||
| 	{ | ||||
| 		get_window().set_properties( | ||||
| 		    Window::Properties { | ||||
| 		        .title = "Mirror", | ||||
| 		        .size = math::uvec2(1280u, 720u), | ||||
| 		        .vsync = true, | ||||
| 		    } | ||||
| 		); | ||||
| 		m_editor_registry = create_ref<ecs::Registry>(); | ||||
| 
 | ||||
| 		get_layer_stack().emplace_layer<EditorLayer>("MirrorLayer"); | ||||
| 		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; | ||||
| 
 | ||||
| 				    if (event.get_key() == 81) | ||||
| 				    { | ||||
| 					    unregister_system(m_window_system); | ||||
| 					    log_inf("Quitting..."); | ||||
| 				    } | ||||
| 				    return true; | ||||
| 				}, | ||||
| 				[](const auto &) { return false; }, | ||||
| 			}; | ||||
| 
 | ||||
| 			return std::visit(visitor, event); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	void setup_window_system() | ||||
| 	{ | ||||
| 		using lt::surface::SurfaceComponent; | ||||
| 		m_window_system = create_ref<lt::surface::System>(m_editor_registry); | ||||
| 
 | ||||
| 		m_window = m_editor_registry->create_entity("Editor Window"); | ||||
| 		m_window.add_component<SurfaceComponent>(SurfaceComponent::CreateInfo { | ||||
| 		    .title = "Editor Window", | ||||
| 		    .size = { 800u, 600u }, | ||||
| 		    .vsync = true, | ||||
| 		    .visible = true, | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	void register_systems() | ||||
| 	{ | ||||
| 		register_system(m_window_system); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	Ref<ecs::Registry> m_editor_registry; | ||||
| 
 | ||||
| 	Ref<lt::surface::System> m_window_system; | ||||
| 
 | ||||
| 	lt::ecs::Entity m_window; | ||||
| }; | ||||
| 
 | ||||
| auto create_application() -> Scope<Application> | ||||
| auto app::create_application() -> Scope<app::Application> | ||||
| { | ||||
| 	return create_scope<Mirror>(); | ||||
| } | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| add_library_module(renderer | ||||
|     system.cpp | ||||
|     blender.cpp | ||||
|     buffers.cpp | ||||
|     framebuffer.cpp | ||||
|  | @ -19,6 +20,7 @@ add_library_module(renderer | |||
|     gl/shader.cpp | ||||
|     gl/texture.cpp | ||||
|     gl/vertex_layout.cpp | ||||
|     vk/instance.cpp | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries( | ||||
|  | @ -34,4 +36,15 @@ target_link_libraries( | |||
|   PUBLIC yaml-cpp::yaml-cpp | ||||
|   PUBLIC EnTT::EnTT | ||||
|   PRIVATE lt_debug  | ||||
|   PRIVATE window | ||||
|   PUBLIC vulkan | ||||
| ) | ||||
| 
 | ||||
| add_test_module(renderer  | ||||
|     system.test.cpp | ||||
| )  | ||||
| target_link_libraries( | ||||
|   renderer_tests | ||||
|   PRIVATE lt_debug  | ||||
|   PRIVATE window | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										18
									
								
								modules/renderer/private/system.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								modules/renderer/private/system.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| #include <lt_debug/assertions.hpp> | ||||
| #include <renderer/system.hpp> | ||||
| 
 | ||||
| namespace lt::renderer { | ||||
| 
 | ||||
| System::System(InitRequirements requirements): m_registry(std::move(requirements.registry)) | ||||
| { | ||||
| 	ensure(m_registry, "null registry"); | ||||
| 	ensure(requirements.glfw_window_handle, "null glfw handle"); | ||||
| } | ||||
| 
 | ||||
| System::~System() = default; | ||||
| 
 | ||||
| void System::tick(TickRequirements requirements) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| } // namespace lt::renderer
 | ||||
							
								
								
									
										50
									
								
								modules/renderer/private/system.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								modules/renderer/private/system.test.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| #include <ranges> | ||||
| #include <renderer/system.hpp> | ||||
| #include <test/test.hpp> | ||||
| #include <window/window.hpp> | ||||
| 
 | ||||
| using namespace lt; | ||||
| 
 | ||||
| using lt::test::Case; | ||||
| using lt::test::Suite; | ||||
| 
 | ||||
| Suite raii = [] { | ||||
| 	using lt::test::expect_true; | ||||
| 	using lt::test::expect_throw; | ||||
| 	using renderer::System; | ||||
| 
 | ||||
| 	auto *window = static_cast<GLFWwindow *>(lt::Window::create([](auto &&PH1) {})->get_handle()); | ||||
| 
 | ||||
| 	Case { "happy" } = [=] { | ||||
| 		std::ignore = System { { | ||||
| 			.glfw_window_handle = window, | ||||
| 			.registry = create_ref<ecs::Registry>(), | ||||
| 		} }; | ||||
| 	}; | ||||
| 
 | ||||
| 	Case { "unhappy" } = [=] { | ||||
| 		expect_throw([=] { | ||||
| 			std::ignore = System { { | ||||
| 				.glfw_window_handle = window, | ||||
| 				.registry = {}, | ||||
| 			} }; | ||||
| 		}); | ||||
| 
 | ||||
| 		expect_throw([=] { | ||||
| 			std::ignore = System { { | ||||
| 				.glfw_window_handle = {}, | ||||
| 				.registry = create_ref<ecs::Registry>(), | ||||
| 			} }; | ||||
| 		}); | ||||
| 	}; | ||||
| 
 | ||||
| 	Case { "plenty" } = [=] { | ||||
| 		for (auto idx : std::views::iota(0, 100'001)) | ||||
| 		{ | ||||
| 			std::ignore = System { { | ||||
| 				.glfw_window_handle = window, | ||||
| 				.registry = create_ref<ecs::Registry>(), | ||||
| 			} }; | ||||
| 		} | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										0
									
								
								modules/renderer/private/vk/device.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/renderer/private/vk/device.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										5
									
								
								modules/renderer/private/vk/instance.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								modules/renderer/private/vk/instance.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| #include <renderer/vk/instance.hpp> | ||||
| 
 | ||||
| namespace lt::vk { | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										19
									
								
								modules/renderer/private/vk/instance.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								modules/renderer/private/vk/instance.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <vulkan/vulkan.h> | ||||
| #include <vulkan/vulkan.hpp> | ||||
| 
 | ||||
| namespace lt::vk { | ||||
| 
 | ||||
| class Instance | ||||
| { | ||||
| public: | ||||
| 	Instance() | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	::vk::Instance m_instace; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::vk
 | ||||
							
								
								
									
										8
									
								
								modules/renderer/private/vk/instance.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								modules/renderer/private/vk/instance.test.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| #include <renderer/vk/instance.hpp> | ||||
| #include <test/test.hpp> | ||||
| 
 | ||||
| lt::test::Suite raii = [] { | ||||
| 	lt::test::Case { "raii" } = [] { | ||||
| 		auto instance = lt::vk::Instance {}; | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										12
									
								
								modules/renderer/public/components.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								modules/renderer/public/components.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #pragma once | ||||
| 
 | ||||
| namespace lt::renderer { | ||||
| 
 | ||||
| /** Requires a Transform Component
 | ||||
|  * @todo(Light): Figure out how to enforce a component requirement list for a component | ||||
|  */ | ||||
| struct RendererComponent | ||||
| { | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::renderer
 | ||||
							
								
								
									
										9
									
								
								modules/renderer/public/context.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								modules/renderer/public/context.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| #pragma once | ||||
| 
 | ||||
| namespace lt::renderer { | ||||
| 
 | ||||
| class Context | ||||
| { | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::renderer
 | ||||
							
								
								
									
										60
									
								
								modules/renderer/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								modules/renderer/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <base/base.hpp> | ||||
| #include <ecs/scene.hpp> | ||||
| 
 | ||||
| struct GLFWwindow; | ||||
| 
 | ||||
| namespace lt::renderer { | ||||
| 
 | ||||
| /** The system for putting gore on your display
 | ||||
|  * | ||||
|  * Exclusively operates on components: | ||||
|  * - RendererComponent | ||||
|  * - PostEffectsComponent | ||||
|  * - UserInterfaceComponent | ||||
|  * | ||||
|  * Requires read acces on components: | ||||
|  * - TransformComponent | ||||
|  */ | ||||
| class System | ||||
| { | ||||
| public: | ||||
| 	/** The configurations of this system. */ | ||||
| 	struct Properties | ||||
| 	{ | ||||
| 	}; | ||||
| 
 | ||||
| 	/** The requirements for this system to initialize. */ | ||||
| 	struct InitRequirements | ||||
| 	{ | ||||
| 		GLFWwindow *glfw_window_handle; | ||||
| 
 | ||||
| 		Ref<ecs::Registry> registry; | ||||
| 	}; | ||||
| 
 | ||||
| 	/** The requirements for this system to tick. */ | ||||
| 	struct TickRequirements | ||||
| 	{ | ||||
| 		double delta_time; | ||||
| 	}; | ||||
| 
 | ||||
| 	[[nodiscard]] System(InitRequirements requirements); | ||||
| 
 | ||||
| 	System(System &&) = default; | ||||
| 
 | ||||
| 	System(const System &) = delete; | ||||
| 
 | ||||
| 	auto operator=(System &&) -> System & = default; | ||||
| 
 | ||||
| 	auto operator=(const System &) -> System & = delete; | ||||
| 
 | ||||
| 	~System(); | ||||
| 
 | ||||
| 	void tick(TickRequirements requirements); | ||||
| 
 | ||||
| private: | ||||
| 	Ref<ecs::Registry> m_registry; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::renderer
 | ||||
							
								
								
									
										13
									
								
								modules/surface/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								modules/surface/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| if (NOT WIN32) | ||||
|     add_library_module(surface system.cpp linux/system.cpp) | ||||
| else() | ||||
| endif() | ||||
| 
 | ||||
| target_link_libraries(surface PUBLIC  | ||||
|     ecs | ||||
|     app | ||||
|     PRIVATE | ||||
|     glfw | ||||
|     logger  | ||||
|     lt_debug | ||||
| ) | ||||
							
								
								
									
										198
									
								
								modules/surface/private/linux/system.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								modules/surface/private/linux/system.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,198 @@ | |||
| #include <GLFW/glfw3.h> | ||||
| #include <surface/system.hpp> | ||||
| 
 | ||||
| namespace lt::surface { | ||||
| 
 | ||||
| void handle_event(GLFWwindow *window, const System::Event &event) | ||||
| { | ||||
| 	auto &callbacks = *static_cast<std::vector<System::EventCallback> *>( | ||||
| 	    glfwGetWindowUserPointer(window) | ||||
| 	); | ||||
| 
 | ||||
| 	for (auto &callback : callbacks) | ||||
| 	{ | ||||
| 		if (callback(event)) | ||||
| 		{ | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void bind_glfw_events(GLFWwindow *handle) | ||||
| { | ||||
| 	glfwSetWindowPosCallback(handle, [](GLFWwindow *window, int xpos, int ypos) { | ||||
| 		handle_event(window, MovedEvent { xpos, ypos }); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowSizeCallback(handle, [](GLFWwindow *window, int width, int height) { | ||||
| 		handle_event( | ||||
| 		    window, | ||||
| 		    ResizedEvent { static_cast<uint32_t>(width), static_cast<uint32_t>(height) } | ||||
| 		); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowCloseCallback(handle, [](GLFWwindow *window) { | ||||
| 		handle_event(window, ClosedEvent {}); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowFocusCallback(handle, [](GLFWwindow *window, int focus) { | ||||
| 		if (focus == GLFW_TRUE) | ||||
| 		{ | ||||
| 			handle_event(window, GainFocusEvent {}); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			handle_event(window, LostFocusEvent {}); | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetCursorPosCallback(handle, [](GLFWwindow *window, double xpos, double ypos) { | ||||
| 		handle_event( | ||||
| 		    window, | ||||
| 		    MouseMovedEvent { static_cast<float>(xpos), static_cast<float>(ypos) } | ||||
| 		); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetMouseButtonCallback( | ||||
| 	    handle, | ||||
| 	    [](GLFWwindow *window, int button, int action, int /*mods*/) { | ||||
| 		    if (action == GLFW_PRESS) | ||||
| 		    { | ||||
| 			    handle_event(window, ButtonPressedEvent { button }); | ||||
| 		    } | ||||
| 		    else if (action == GLFW_RELEASE) | ||||
| 		    { | ||||
| 			    handle_event(window, ButtonReleasedEvent { button }); | ||||
| 		    } | ||||
| 	    } | ||||
| 	); | ||||
| 
 | ||||
| 	glfwSetScrollCallback(handle, [](GLFWwindow *window, double /*xoffset*/, double yoffset) { | ||||
| 		handle_event(window, WheelScrolledEvent { static_cast<float>(yoffset) }); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetKeyCallback( | ||||
| 	    handle, | ||||
| 	    [](GLFWwindow *window, int key, int /*scancode*/, int action, int /*mods*/) { | ||||
| 		    if (action == GLFW_PRESS) | ||||
| 		    { | ||||
| 			    handle_event(window, KeyPressedEvent { key }); | ||||
| 		    } | ||||
| 		    else if (action == GLFW_RELEASE) | ||||
| 		    { | ||||
| 			    handle_event(window, KeyReleasedEvent { key }); | ||||
| 		    } | ||||
| 	    } | ||||
| 	); | ||||
| 
 | ||||
| 	glfwSetCharCallback(handle, [](GLFWwindow *window, unsigned int character) { | ||||
| 		handle_event(window, KeySetCharEvent { character }); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| void System::on_surface_construct(entt::registry ®istry, entt::entity entity) | ||||
| { | ||||
| 	ensure(glfwInit(), "Failed to initialize 'glfw'"); | ||||
| 
 | ||||
| 	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | ||||
| 	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); | ||||
| 	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | ||||
| 	// glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
 | ||||
| 
 | ||||
| 	auto &surface = registry.get<SurfaceComponent>(entity); | ||||
| 	auto [width, height] = surface.get_size(); | ||||
| 
 | ||||
| 	surface.m_glfw_handle = glfwCreateWindow( | ||||
| 	    static_cast<int32_t>(width), | ||||
| 	    static_cast<int32_t>(height), | ||||
| 	    surface.get_title().begin(), | ||||
| 	    nullptr, | ||||
| 	    nullptr | ||||
| 	); | ||||
| 	ensure(surface.m_glfw_handle, "Failed to create 'GLFWwindow'"); | ||||
| 
 | ||||
| 	glfwSetWindowUserPointer(surface.m_glfw_handle, &m_event_callbacks); | ||||
| 	bind_glfw_events(surface.m_glfw_handle); | ||||
| } | ||||
| 
 | ||||
| void System::on_surface_destroy(entt::registry ®istry, entt::entity entity) | ||||
| { | ||||
| 	auto &surface = registry.get<SurfaceComponent>(entity); | ||||
| 	glfwDestroyWindow(surface.m_glfw_handle); | ||||
| } | ||||
| 
 | ||||
| void System::set_title(ecs::Entity entity, std::string_view new_title) | ||||
| { | ||||
| 	auto &surface = entity.get_component<SurfaceComponent>(); | ||||
| 
 | ||||
| 	surface.m_title = new_title; | ||||
| 	glfwSetWindowTitle(surface.m_glfw_handle, surface.m_title.begin()); | ||||
| } | ||||
| 
 | ||||
| auto System::tick() -> bool | ||||
| { | ||||
| 	glfwPollEvents(); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void System::set_size(ecs::Entity surface_entity, const math::uvec2 &new_size) | ||||
| { | ||||
| 	auto &surface = surface_entity.get_component<SurfaceComponent>(); | ||||
| 	surface.m_size = new_size; | ||||
| 
 | ||||
| 	glfwSetWindowSize( | ||||
| 	    surface.m_glfw_handle, | ||||
| 	    static_cast<int>(new_size.x), | ||||
| 	    static_cast<int>(new_size.y) | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| void System::set_v_sync(ecs::Entity surface_entity, bool vsync) | ||||
| { | ||||
| 	auto &surface = surface_entity.get_component<SurfaceComponent>(); | ||||
| 	surface.m_vsync = vsync; | ||||
| 
 | ||||
| 	glfwSwapInterval(vsync); | ||||
| } | ||||
| 
 | ||||
| void System::set_visibility(ecs::Entity surface_entity, bool visible) | ||||
| { | ||||
| 	auto &surface = surface_entity.get_component<SurfaceComponent>(); | ||||
| 	surface.m_visible = visible; | ||||
| 
 | ||||
| 	if (visible) | ||||
| 	{ | ||||
| 		glfwShowWindow(surface.m_glfw_handle); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		glfwHideWindow(surface.m_glfw_handle); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| } // 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
 | ||||
							
								
								
									
										27
									
								
								modules/surface/private/system.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								modules/surface/private/system.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| #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
									
								
								modules/surface/private/system.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/surface/private/system.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										77
									
								
								modules/surface/public/components.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								modules/surface/public/components.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <math/vec2.hpp> | ||||
| 
 | ||||
| struct GLFWwindow; | ||||
| 
 | ||||
| namespace lt::surface { | ||||
| 
 | ||||
| class SurfaceComponent | ||||
| { | ||||
| public: | ||||
| 	friend class System; | ||||
| 
 | ||||
| 	struct CreateInfo | ||||
| 	{ | ||||
| 		std::string_view title; | ||||
| 
 | ||||
| 		math::uvec2 size; | ||||
| 
 | ||||
| 		bool vsync; | ||||
| 
 | ||||
| 		bool visible; | ||||
| 	}; | ||||
| 
 | ||||
| 	SurfaceComponent(const CreateInfo &info) | ||||
| 	    : m_title(info.title) | ||||
| 	    , m_size(info.size) | ||||
| 	    , m_vsync(info.vsync) | ||||
| 	    , m_visible(info.visible) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_title() const -> const std::string_view & | ||||
| 	{ | ||||
| 		return m_title; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_size() const -> const math::uvec2 & | ||||
| 	{ | ||||
| 		return m_size; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto is_vsync() const -> bool | ||||
| 	{ | ||||
| 		return m_vsync; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto is_visible() const -> bool | ||||
| 	{ | ||||
| 		return m_visible; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_native_handle() const -> void * | ||||
| 	{ | ||||
| 		return m_native_handle; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_glfw_handle() const -> GLFWwindow * | ||||
| 	{ | ||||
| 		return m_glfw_handle; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	std::string_view m_title; | ||||
| 
 | ||||
| 	math::uvec2 m_size; | ||||
| 
 | ||||
| 	bool m_vsync; | ||||
| 
 | ||||
| 	bool m_visible; | ||||
| 
 | ||||
| 	void *m_native_handle {}; | ||||
| 
 | ||||
| 	GLFWwindow *m_glfw_handle {}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::surface
 | ||||
							
								
								
									
										91
									
								
								modules/surface/public/events/keyboard.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								modules/surface/public/events/keyboard.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,91 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <format> | ||||
| 
 | ||||
| namespace lt::surface { | ||||
| 
 | ||||
| class KeyPressedEvent | ||||
| { | ||||
| public: | ||||
| 	KeyPressedEvent(int32_t key): m_key(key) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_key() const -> int32_t | ||||
| 	{ | ||||
| 		return m_key; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		return std::format("KeyPressed: {}", m_key); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	int32_t m_key; | ||||
| }; | ||||
| 
 | ||||
| class KeyRepeatEvent | ||||
| { | ||||
| public: | ||||
| 	KeyRepeatEvent(int key): m_key(key) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_key() const -> int32_t | ||||
| 	{ | ||||
| 		return m_key; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		return std::format("KeyRepeated: {}", m_key); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	int32_t m_key; | ||||
| }; | ||||
| 
 | ||||
| class KeyReleasedEvent | ||||
| { | ||||
| public: | ||||
| 	KeyReleasedEvent(int key): m_key(key) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_key() const -> int32_t | ||||
| 	{ | ||||
| 		return m_key; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		return std::format("KeyReleased: {}", m_key); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	int32_t m_key; | ||||
| }; | ||||
| 
 | ||||
| class KeySetCharEvent | ||||
| { | ||||
| public: | ||||
| 	KeySetCharEvent(uint32_t character): m_character(character) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_character() const -> uint32_t | ||||
| 	{ | ||||
| 		return m_character; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		return std::format("KeyCharSet: {}", m_character); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	uint32_t m_character; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::surface
 | ||||
							
								
								
									
										103
									
								
								modules/surface/public/events/mouse.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								modules/surface/public/events/mouse.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <math/vec2.hpp> | ||||
| 
 | ||||
| namespace lt::surface { | ||||
| 
 | ||||
| class MouseMovedEvent | ||||
| { | ||||
| public: | ||||
| 	MouseMovedEvent(float x, float y): m_position(x, y) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_position() const -> const math::vec2 & | ||||
| 	{ | ||||
| 		return m_position; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_x() const -> float | ||||
| 	{ | ||||
| 		return m_position.x; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_y() const -> float | ||||
| 	{ | ||||
| 		return m_position.y; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		return std::format("MouseMoved: {}, {}", m_position.x, m_position.y); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	math::vec2 m_position; | ||||
| }; | ||||
| 
 | ||||
| class WheelScrolledEvent | ||||
| { | ||||
| public: | ||||
| 	WheelScrolledEvent(float offset): m_offset(offset) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_offset() const -> float | ||||
| 	{ | ||||
| 		return m_offset; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		std::stringstream ss; | ||||
| 		ss << "WheelScrolled: " << m_offset; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	float m_offset; | ||||
| }; | ||||
| 
 | ||||
| class ButtonPressedEvent | ||||
| { | ||||
| public: | ||||
| 	ButtonPressedEvent(int button): m_button(button) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_button() const -> int | ||||
| 	{ | ||||
| 		return m_button; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		return std::format("ButtonPressed: {}", m_button); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	int m_button; | ||||
| }; | ||||
| 
 | ||||
| class ButtonReleasedEvent | ||||
| { | ||||
| public: | ||||
| 	ButtonReleasedEvent(int button): m_button(button) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_button() const -> int | ||||
| 	{ | ||||
| 		return m_button; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		return std::format("ButtonReleased: {}", m_button); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	int m_button; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::surface
 | ||||
							
								
								
									
										81
									
								
								modules/surface/public/events/surface.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								modules/surface/public/events/surface.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <math/vec2.hpp> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace lt::surface { | ||||
| 
 | ||||
| class ClosedEvent | ||||
| { | ||||
| public: | ||||
| 	[[nodiscard]] auto to_string() const -> std::string_view | ||||
| 	{ | ||||
| 		return "SurfaceClosedEvent"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| class MovedEvent | ||||
| { | ||||
| public: | ||||
| 	MovedEvent(int x, int y): m_position(x, y) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_position() const -> const math::ivec2 & | ||||
| 	{ | ||||
| 		return m_position; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		auto stream = std::stringstream {}; | ||||
| 		stream << "WindwoMoved: " << m_position.x << ", " << m_position.y; | ||||
| 		return stream.str(); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	math::ivec2 m_position; | ||||
| }; | ||||
| 
 | ||||
| class ResizedEvent | ||||
| { | ||||
| public: | ||||
| 	ResizedEvent(unsigned int width, unsigned int height): m_size(width, height) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_size() const -> const math::uvec2 & | ||||
| 	{ | ||||
| 		return m_size; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto to_string() const -> std::string | ||||
| 	{ | ||||
| 		auto stream = std::stringstream {}; | ||||
| 		stream << "SurfaceResized: " << m_size.x << ", " << m_size.y; | ||||
| 		return stream.str(); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	math::uvec2 m_size; | ||||
| }; | ||||
| 
 | ||||
| class LostFocusEvent | ||||
| { | ||||
| public: | ||||
| 	[[nodiscard]] auto to_string() const -> std::string_view | ||||
| 	{ | ||||
| 		return "SurfaceLostFocus"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| class GainFocusEvent | ||||
| { | ||||
| public: | ||||
| 	[[nodiscard]] auto to_string() const -> std::string_view | ||||
| 	{ | ||||
| 		return "SurfaceGainFocus"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt::surface
 | ||||
							
								
								
									
										80
									
								
								modules/surface/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								modules/surface/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,80 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <app/system.hpp> | ||||
| #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); | ||||
| 
 | ||||
| 	~System() override; | ||||
| 
 | ||||
| 	System(System &&) = default; | ||||
| 
 | ||||
| 	System(const System &) = delete; | ||||
| 
 | ||||
| 	auto operator=(System &&) -> System & = default; | ||||
| 
 | ||||
| 	auto operator=(const System &) -> System & = delete; | ||||
| 
 | ||||
| 	void init() override | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	auto tick() -> bool override; | ||||
| 
 | ||||
| 	void set_title(ecs::Entity surface_entity, std::string_view new_title); | ||||
| 
 | ||||
| 	void set_size(ecs::Entity surface_entity, const math::uvec2 &new_size); | ||||
| 
 | ||||
| 	void set_v_sync(ecs::Entity surface_entity, bool vsync); | ||||
| 
 | ||||
| 	void set_visibility(ecs::Entity surface_entity, bool visible); | ||||
| 
 | ||||
| 	void add_event_listener(EventCallback callback) | ||||
| 	{ | ||||
| 		m_event_callbacks.emplace_back(std::move(callback)); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	void on_surface_construct(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; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } // namespace lt::surface
 | ||||
|  | @ -1,13 +0,0 @@ | |||
| if (NOT WIN32) | ||||
|     add_library_module(window linux/window.cpp) | ||||
| else() | ||||
|     add_library_module(window windows/window.cpp) | ||||
| endif() | ||||
| 
 | ||||
| target_link_libraries(window PUBLIC  | ||||
|     PRIVATE | ||||
|     glfw | ||||
|     logger  | ||||
|     lt_debug | ||||
|     input | ||||
| ) | ||||
|  | @ -1,219 +0,0 @@ | |||
| #include <GLFW/glfw3.h> | ||||
| #include <input/events/char.hpp> | ||||
| #include <input/events/event.hpp> | ||||
| #include <input/events/keyboard.hpp> | ||||
| #include <input/events/mouse.hpp> | ||||
| #include <input/events/window.hpp> | ||||
| #include <window/linux/window.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| Window::~Window() = default; | ||||
| 
 | ||||
| auto Window::create(const std::function<void(Event &)> &callback) -> Scope<Window> | ||||
| { | ||||
| 	return create_scope<lWindow>(callback); | ||||
| } | ||||
| 
 | ||||
| lWindow::lWindow(std::function<void(Event &)> callback) | ||||
|     : m_event_callback(std::move(std::move(callback))) | ||||
| { | ||||
| 	ensure(glfwInit(), "Failed to initialize 'glfw'"); | ||||
| 
 | ||||
| 	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | ||||
| 	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); | ||||
| 	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | ||||
| 	glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); | ||||
| 
 | ||||
| 	// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||||
| 	m_handle = glfwCreateWindow(1u, 1u, "", nullptr, nullptr); | ||||
| 	ensure(m_handle, "Failed to create 'GLFWwindow'"); | ||||
| 
 | ||||
| 	glfwSetWindowUserPointer(m_handle, &m_event_callback); | ||||
| 	bind_glfw_events(); | ||||
| } | ||||
| 
 | ||||
| lWindow::~lWindow() | ||||
| { | ||||
| 	glfwDestroyWindow(m_handle); | ||||
| } | ||||
| 
 | ||||
| void lWindow::poll_events() | ||||
| { | ||||
| 	glfwPollEvents(); | ||||
| } | ||||
| 
 | ||||
| void lWindow::on_event(const Event &event) | ||||
| { | ||||
| 	switch (event.get_event_type()) | ||||
| 	{ | ||||
| 	/* closed */ | ||||
| 	case EventType::WindowClosed: b_Closed = true; break; | ||||
| 
 | ||||
| 	/* resized */ | ||||
| 	case EventType::WindowResized: | ||||
| 		on_window_resize(dynamic_cast<const WindowResizedEvent &>(event)); | ||||
| 		break; | ||||
| 
 | ||||
| 	default: break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void lWindow::on_window_resize(const WindowResizedEvent &event) | ||||
| { | ||||
| 	m_properties.size = event.get_size(); | ||||
| } | ||||
| 
 | ||||
| void lWindow::set_properties(const Properties &properties, bool overrideVisibility /* = false */) | ||||
| { | ||||
| 	// save the visibility status and re-assign if 'overrideVisibility' is false
 | ||||
| 	auto visible = overrideVisibility ? properties.visible : m_properties.visible; | ||||
| 	m_properties = properties; | ||||
| 	m_properties.visible = visible; | ||||
| 
 | ||||
| 	// set properties
 | ||||
| 	set_title(properties.title); | ||||
| 	set_size(properties.size); | ||||
| 	set_v_sync(properties.vsync); | ||||
| 	set_visibility(visible); | ||||
| } | ||||
| 
 | ||||
| void lWindow::set_title(const std::string &title) | ||||
| { | ||||
| 	m_properties.title = title; | ||||
| 
 | ||||
| 	glfwSetWindowTitle(m_handle, title.c_str()); | ||||
| } | ||||
| 
 | ||||
| void lWindow::set_size(const math::uvec2 &size) | ||||
| { | ||||
| 	m_properties.size = size; | ||||
| 	glfwSetWindowSize(m_handle, static_cast<int>(size.x), static_cast<int>(size.y)); | ||||
| } | ||||
| 
 | ||||
| void lWindow::set_v_sync(bool vsync, bool toggle /* = false */) | ||||
| { | ||||
| 	m_properties.vsync = toggle ? !m_properties.vsync : vsync; | ||||
| 
 | ||||
| 	glfwSwapInterval(m_properties.vsync); | ||||
| } | ||||
| 
 | ||||
| void lWindow::set_visibility(bool visible, bool toggle) | ||||
| { | ||||
| 	m_properties.visible = toggle ? !m_properties.visible : visible; | ||||
| 
 | ||||
| 	if (m_properties.visible) | ||||
| 	{ | ||||
| 		glfwShowWindow(m_handle); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		glfwHideWindow(m_handle); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void lWindow::bind_glfw_events() | ||||
| { | ||||
| 	glfwSetCursorPosCallback(m_handle, [](GLFWwindow *window, double xpos, double ypos) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		auto event = MouseMovedEvent { | ||||
| 			static_cast<float>(xpos), | ||||
| 			static_cast<float>(ypos), | ||||
| 		}; | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetMouseButtonCallback( | ||||
| 	    m_handle, | ||||
| 	    [](GLFWwindow *window, int button, int action, int /*mods*/) { | ||||
| 		    std::function<void(Event &)> const callback = *( | ||||
| 		        std::function<void(Event &)> * | ||||
| 		    )glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		    if (action == GLFW_PRESS) | ||||
| 		    { | ||||
| 			    auto event = ButtonPressedEvent { button }; | ||||
| 			    callback(event); | ||||
| 		    } | ||||
| 		    else if (action == GLFW_RELEASE) | ||||
| 		    { | ||||
| 			    auto event = ButtonReleasedEvent { button }; | ||||
| 			    callback(event); | ||||
| 		    } | ||||
| 	    } | ||||
| 	); | ||||
| 
 | ||||
| 	glfwSetScrollCallback(m_handle, [](GLFWwindow *window, double /*xoffset*/, double yoffset) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		auto event = WheelScrolledEvent { static_cast<float>(yoffset) }; | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetKeyCallback( | ||||
| 	    m_handle, | ||||
| 	    [](GLFWwindow *window, int key, int /*scancode*/, int action, int /*mods*/) { | ||||
| 		    auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		    if (action == GLFW_PRESS) | ||||
| 		    { | ||||
| 			    auto event = KeyPressedEvent { key }; | ||||
| 			    callback(event); | ||||
| 		    } | ||||
| 		    else if (action == GLFW_RELEASE) | ||||
| 		    { | ||||
| 			    auto event = KeyReleasedEvent { key }; | ||||
| 			    callback(event); | ||||
| 		    } | ||||
| 	    } | ||||
| 	); | ||||
| 
 | ||||
| 	glfwSetCharCallback(m_handle, [](GLFWwindow *window, unsigned int character) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		auto event = SetCharEvent { character }; | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowPosCallback(m_handle, [](GLFWwindow *window, int xpos, int ypos) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 		auto event = WindowMovedEvent { xpos, ypos }; | ||||
| 
 | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowSizeCallback(m_handle, [](GLFWwindow *window, int width, int height) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 		auto event = WindowResizedEvent { | ||||
| 			static_cast<unsigned int>(width), | ||||
| 			static_cast<unsigned int>(height), | ||||
| 		}; | ||||
| 
 | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowCloseCallback(m_handle, [](GLFWwindow *window) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 		auto event = WindowClosedEvent {}; | ||||
| 
 | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowFocusCallback(m_handle, [](GLFWwindow *window, int focus) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		if (focus == GLFW_TRUE) | ||||
| 		{ | ||||
| 			auto event = WindowGainFocusEvent {}; | ||||
| 			callback(event); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			auto event = WindowLostFocusEvent {}; | ||||
| 			callback(event); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,60 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <window/window.hpp> | ||||
| 
 | ||||
| struct GLFWwindow; | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class Event; | ||||
| class WindowResizedEvent; | ||||
| 
 | ||||
| class lWindow: public Window | ||||
| { | ||||
| public: | ||||
| 	lWindow(std::function<void(Event &)> callback); | ||||
| 
 | ||||
| 	~lWindow() override; | ||||
| 
 | ||||
| 	lWindow(lWindow &&) = delete; | ||||
| 
 | ||||
| 	lWindow(const lWindow &) = delete; | ||||
| 
 | ||||
| 	auto operator=(lWindow &&) -> lWindow & = delete; | ||||
| 
 | ||||
| 	auto operator=(const lWindow &) -> lWindow & = delete; | ||||
| 
 | ||||
| 	void poll_events() override; | ||||
| 
 | ||||
| 	void on_event(const Event &event) override; | ||||
| 
 | ||||
| 	void set_properties(const Properties &properties, bool overrideVisibility = false) override; | ||||
| 
 | ||||
| 	void set_title(const std::string &title) override; | ||||
| 
 | ||||
| 	void set_size(const math::uvec2 &size) override; | ||||
| 
 | ||||
| 	void set_v_sync(bool vsync, bool toggle = false) override; | ||||
| 
 | ||||
| 	void set_visibility(bool visible, bool toggle = false) override; | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_handle() -> void * override | ||||
| 	{ | ||||
| 		return m_handle; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	void on_window_resize(const WindowResizedEvent &event); | ||||
| 
 | ||||
| 	void bind_glfw_events(); | ||||
| 
 | ||||
| 	GLFWwindow *m_handle { nullptr }; | ||||
| 
 | ||||
| 	std::function<void(Event &)> m_event_callback; | ||||
| 
 | ||||
| 	Properties m_properties {}; | ||||
| 
 | ||||
| 	bool b_Closed {}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,219 +0,0 @@ | |||
| #include <GLFW/glfw3.h> | ||||
| #include <input/events/char.hpp> | ||||
| #include <input/events/event.hpp> | ||||
| #include <input/events/keyboard.hpp> | ||||
| #include <input/events/mouse.hpp> | ||||
| #include <input/events/window.hpp> | ||||
| #include <window/windows/window.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| Window::~Window() = default; | ||||
| 
 | ||||
| auto Window::create(const std::function<void(Event &)> &callback) -> Scope<Window> | ||||
| { | ||||
| 	return create_scope<wWindow>(callback); | ||||
| } | ||||
| 
 | ||||
| wWindow::wWindow(std::function<void(Event &)> callback) | ||||
|     : m_event_callback(std::move(std::move(callback))) | ||||
| { | ||||
| 	ensure(glfwInit(), "Failed to initialize 'glfw'"); | ||||
| 
 | ||||
| 	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | ||||
| 	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); | ||||
| 	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | ||||
| 	glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); | ||||
| 
 | ||||
| 	// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||||
| 	m_handle = glfwCreateWindow(1u, 1u, "", nullptr, nullptr); | ||||
| 	ensure(m_handle, "Failed to create 'GLFWwindow'"); | ||||
| 
 | ||||
| 	glfwSetWindowUserPointer(m_handle, &m_event_callback); | ||||
| 	bind_glfw_events(); | ||||
| } | ||||
| 
 | ||||
| wWindow::~wWindow() | ||||
| { | ||||
| 	glfwDestroyWindow(m_handle); | ||||
| } | ||||
| 
 | ||||
| void wWindow::poll_events() | ||||
| { | ||||
| 	glfwPollEvents(); | ||||
| } | ||||
| 
 | ||||
| void wWindow::on_event(const Event &event) | ||||
| { | ||||
| 	switch (event.get_event_type()) | ||||
| 	{ | ||||
| 	/* closed */ | ||||
| 	case EventType::WindowClosed: b_Closed = true; break; | ||||
| 
 | ||||
| 	/* resized */ | ||||
| 	case EventType::WindowResized: | ||||
| 		on_window_resize(dynamic_cast<const WindowResizedEvent &>(event)); | ||||
| 		break; | ||||
| 
 | ||||
| 	default: break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void wWindow::on_window_resize(const WindowResizedEvent &event) | ||||
| { | ||||
| 	m_properties.size = event.get_size(); | ||||
| } | ||||
| 
 | ||||
| void wWindow::set_properties(const Properties &properties, bool overrideVisibility /* = false */) | ||||
| { | ||||
| 	// save the visibility status and re-assign if 'overrideVisibility' is false
 | ||||
| 	auto visible = overrideVisibility ? properties.visible : m_properties.visible; | ||||
| 	m_properties = properties; | ||||
| 	m_properties.visible = visible; | ||||
| 
 | ||||
| 	// set properties
 | ||||
| 	set_title(properties.title); | ||||
| 	set_size(properties.size); | ||||
| 	set_v_sync(properties.vsync); | ||||
| 	set_visibility(visible); | ||||
| } | ||||
| 
 | ||||
| void wWindow::set_title(const std::string &title) | ||||
| { | ||||
| 	m_properties.title = title; | ||||
| 
 | ||||
| 	glfwSetWindowTitle(m_handle, title.c_str()); | ||||
| } | ||||
| 
 | ||||
| void wWindow::set_size(const math::uvec2 &size) | ||||
| { | ||||
| 	m_properties.size = size; | ||||
| 	glfwSetWindowSize(m_handle, static_cast<int>(size.x), static_cast<int>(size.y)); | ||||
| } | ||||
| 
 | ||||
| void wWindow::set_v_sync(bool vsync, bool toggle /* = false */) | ||||
| { | ||||
| 	m_properties.vsync = toggle ? !m_properties.vsync : vsync; | ||||
| 
 | ||||
| 	glfwSwapInterval(m_properties.vsync); | ||||
| } | ||||
| 
 | ||||
| void wWindow::set_visibility(bool visible, bool toggle) | ||||
| { | ||||
| 	m_properties.visible = toggle ? !m_properties.visible : visible; | ||||
| 
 | ||||
| 	if (m_properties.visible) | ||||
| 	{ | ||||
| 		glfwShowWindow(m_handle); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		glfwHideWindow(m_handle); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void wWindow::bind_glfw_events() | ||||
| { | ||||
| 	glfwSetCursorPosCallback(m_handle, [](GLFWwindow *window, double xpos, double ypos) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		auto event = MouseMovedEvent { | ||||
| 			static_cast<float>(xpos), | ||||
| 			static_cast<float>(ypos), | ||||
| 		}; | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetMouseButtonCallback( | ||||
| 	    m_handle, | ||||
| 	    [](GLFWwindow *window, int button, int action, int /*mods*/) { | ||||
| 		    std::function<void(Event &)> const callback = *( | ||||
| 		        std::function<void(Event &)> * | ||||
| 		    )glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		    if (action == GLFW_PRESS) | ||||
| 		    { | ||||
| 			    auto event = ButtonPressedEvent { button }; | ||||
| 			    callback(event); | ||||
| 		    } | ||||
| 		    else if (action == GLFW_RELEASE) | ||||
| 		    { | ||||
| 			    auto event = ButtonReleasedEvent { button }; | ||||
| 			    callback(event); | ||||
| 		    } | ||||
| 	    } | ||||
| 	); | ||||
| 
 | ||||
| 	glfwSetScrollCallback(m_handle, [](GLFWwindow *window, double /*xoffset*/, double yoffset) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		auto event = WheelScrolledEvent { static_cast<float>(yoffset) }; | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetKeyCallback( | ||||
| 	    m_handle, | ||||
| 	    [](GLFWwindow *window, int key, int /*scancode*/, int action, int /*mods*/) { | ||||
| 		    auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		    if (action == GLFW_PRESS) | ||||
| 		    { | ||||
| 			    auto event = KeyPressedEvent { key }; | ||||
| 			    callback(event); | ||||
| 		    } | ||||
| 		    else if (action == GLFW_RELEASE) | ||||
| 		    { | ||||
| 			    auto event = KeyReleasedEvent { key }; | ||||
| 			    callback(event); | ||||
| 		    } | ||||
| 	    } | ||||
| 	); | ||||
| 
 | ||||
| 	glfwSetCharCallback(m_handle, [](GLFWwindow *window, unsigned int character) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		auto event = SetCharEvent { character }; | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowPosCallback(m_handle, [](GLFWwindow *window, int xpos, int ypos) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 		auto event = WindowMovedEvent { xpos, ypos }; | ||||
| 
 | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowSizeCallback(m_handle, [](GLFWwindow *window, int width, int height) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 		auto event = WindowResizedEvent { | ||||
| 			static_cast<unsigned int>(width), | ||||
| 			static_cast<unsigned int>(height), | ||||
| 		}; | ||||
| 
 | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowCloseCallback(m_handle, [](GLFWwindow *window) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 		auto event = WindowClosedEvent {}; | ||||
| 
 | ||||
| 		callback(event); | ||||
| 	}); | ||||
| 
 | ||||
| 	glfwSetWindowFocusCallback(m_handle, [](GLFWwindow *window, int focus) { | ||||
| 		auto callback = *(std::function<void(Event &)> *)glfwGetWindowUserPointer(window); | ||||
| 
 | ||||
| 		if (focus == GLFW_TRUE) | ||||
| 		{ | ||||
| 			auto event = WindowGainFocusEvent {}; | ||||
| 			callback(event); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			auto event = WindowLostFocusEvent {}; | ||||
| 			callback(event); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,60 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <window/window.hpp> | ||||
| 
 | ||||
| struct GLFWwindow; | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class Event; | ||||
| class WindowResizedEvent; | ||||
| 
 | ||||
| class wWindow: public Window | ||||
| { | ||||
| public: | ||||
| 	wWindow(std::function<void(Event &)> callback); | ||||
| 
 | ||||
| 	~wWindow() override; | ||||
| 
 | ||||
| 	wWindow(wWindow &&) = delete; | ||||
| 
 | ||||
| 	wWindow(const wWindow &) = delete; | ||||
| 
 | ||||
| 	auto operator=(wWindow &&) -> wWindow & = delete; | ||||
| 
 | ||||
| 	auto operator=(const wWindow &) -> wWindow & = delete; | ||||
| 
 | ||||
| 	void poll_events() override; | ||||
| 
 | ||||
| 	void on_event(const Event &event) override; | ||||
| 
 | ||||
| 	void set_properties(const Properties &properties, bool overrideVisibility = false) override; | ||||
| 
 | ||||
| 	void set_title(const std::string &title) override; | ||||
| 
 | ||||
| 	void set_size(const math::uvec2 &size) override; | ||||
| 
 | ||||
| 	void set_v_sync(bool vsync, bool toggle = false) override; | ||||
| 
 | ||||
| 	void set_visibility(bool visible, bool toggle = false) override; | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_handle() -> void * override | ||||
| 	{ | ||||
| 		return m_handle; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	void on_window_resize(const WindowResizedEvent &event); | ||||
| 
 | ||||
| 	void bind_glfw_events(); | ||||
| 
 | ||||
| 	GLFWwindow *m_handle { nullptr }; | ||||
| 
 | ||||
| 	std::function<void(Event &)> m_event_callback; | ||||
| 
 | ||||
| 	Properties m_properties {}; | ||||
| 
 | ||||
| 	bool b_Closed {}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
|  | @ -1,98 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <math/vec2.hpp> | ||||
| 
 | ||||
| namespace lt { | ||||
| 
 | ||||
| class Event; | ||||
| 
 | ||||
| class Window | ||||
| { | ||||
| public: | ||||
| 	struct Properties | ||||
| 	{ | ||||
| 		std::string title; | ||||
| 
 | ||||
| 		math::uvec2 size; | ||||
| 
 | ||||
| 		bool vsync, visible; | ||||
| 	}; | ||||
| 
 | ||||
| 	static Scope<Window> create(const std::function<void(Event &)> &callback); | ||||
| 
 | ||||
| 	Window() = default; | ||||
| 
 | ||||
| 	virtual ~Window(); | ||||
| 
 | ||||
| 	Window(Window &&) = delete; | ||||
| 
 | ||||
| 	Window(const Window &) = delete; | ||||
| 
 | ||||
| 	auto operator=(Window &&) -> Window & = delete; | ||||
| 
 | ||||
| 	auto operator=(const Window &) -> Window & = delete; | ||||
| 
 | ||||
| 	virtual void poll_events() = 0; | ||||
| 
 | ||||
| 	virtual void on_event(const Event &event) = 0; | ||||
| 
 | ||||
| 	virtual void set_properties(const Properties &properties, bool affectVisibility = false) = 0; | ||||
| 
 | ||||
| 	virtual void set_title(const std::string &title) = 0; | ||||
| 
 | ||||
| 	virtual void set_size(const math::uvec2 &size) = 0; | ||||
| 
 | ||||
| 	void close() | ||||
| 	{ | ||||
| 		b_Closed = true; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void set_v_sync(bool vsync, bool toggle = false) = 0; | ||||
| 
 | ||||
| 	virtual void set_visibility(bool visible, bool toggle = false) = 0; | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_properties() const -> const Properties & | ||||
| 	{ | ||||
| 		return m_properties; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_title() const -> const std::string & | ||||
| 	{ | ||||
| 		return m_properties.title; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto get_size() const -> const math::uvec2 & | ||||
| 	{ | ||||
| 		return m_properties.size; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto is_closed() const -> bool | ||||
| 	{ | ||||
| 		return b_Closed; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto is_v_sync() const -> bool | ||||
| 	{ | ||||
| 		return m_properties.vsync; | ||||
| 	} | ||||
| 
 | ||||
| 	[[nodiscard]] auto is_visible() const -> bool | ||||
| 	{ | ||||
| 		return m_properties.visible; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual auto get_handle() -> void * = 0; | ||||
| 
 | ||||
| protected: | ||||
| 	auto get_properties_handle() -> Properties & | ||||
| 	{ | ||||
| 		return m_properties; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	Properties m_properties {}; | ||||
| 
 | ||||
| 	bool b_Closed {}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace lt
 | ||||
		Loading…
	
	Add table
		
		Reference in a new issue