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)
|
||||
for (auto &system : m_systems)
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_renderer->on_window_resize(dynamic_cast<const WindowResizedEvent &>(event));
|
||||
}
|
||||
}
|
||||
|
||||
// input
|
||||
if (event.has_category(InputEventCategory))
|
||||
{
|
||||
Input::instance().on_event(event);
|
||||
|
||||
if (!Input::instance().is_receiving_game_events())
|
||||
if (system->tick())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : std::ranges::reverse_view(*m_layer_stack))
|
||||
for (auto &system : m_systems_to_be_removed)
|
||||
{
|
||||
if (it->on_event(event))
|
||||
m_systems.erase(
|
||||
std::remove(m_systems.begin(), m_systems.end(), system),
|
||||
m_systems.end()
|
||||
);
|
||||
}
|
||||
|
||||
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