wip: convert from include style to module import style :D
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
This commit is contained in:
parent
a2efc487c4
commit
90c0147660
11 changed files with 545 additions and 123 deletions
|
|
@ -1,3 +1,11 @@
|
||||||
|
add_library_module(NAME logger INTERFACES logger.cppm)
|
||||||
|
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
||||||
|
add_library_module(NAME env INTERFACES constants.cppm)
|
||||||
|
add_library_module(
|
||||||
|
NAME memory INTERFACES null_on_move.cppm reference.cppm scope.cppm
|
||||||
|
)
|
||||||
|
add_library_module(NAME time INTERFACES timer.cppm)
|
||||||
|
|
||||||
add_library_module(
|
add_library_module(
|
||||||
NAME
|
NAME
|
||||||
test
|
test
|
||||||
|
|
@ -11,18 +19,6 @@ add_library_module(
|
||||||
logger
|
logger
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library_module(NAME logger INTERFACES logger.cppm)
|
|
||||||
|
|
||||||
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
|
||||||
|
|
||||||
add_library_module(NAME env INTERFACES constants.cppm)
|
|
||||||
|
|
||||||
add_library_module(
|
|
||||||
NAME memory INTERFACES null_on_move.cppm reference.cppm scope.cppm
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library_module(NAME time INTERFACES timer.cppm)
|
|
||||||
|
|
||||||
add_library_module(
|
add_library_module(
|
||||||
NAME
|
NAME
|
||||||
lt_debug
|
lt_debug
|
||||||
|
|
@ -104,11 +100,36 @@ add_library_module(
|
||||||
memory
|
memory
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(WIN32)
|
||||||
add_library_module(
|
add_library_module(
|
||||||
NAME
|
NAME
|
||||||
surface
|
surface
|
||||||
INTERFACES
|
INTERFACES
|
||||||
|
constants.cppm
|
||||||
|
system.cppm
|
||||||
|
requests.cppm
|
||||||
|
events.cppm
|
||||||
|
components.cppm
|
||||||
|
SOURCES
|
||||||
|
platform_windows.cpp
|
||||||
|
DEPENDENCIES
|
||||||
|
ecs
|
||||||
|
app
|
||||||
|
math
|
||||||
|
memory
|
||||||
|
tbb
|
||||||
|
PRIVATE_DEPENDENCIES
|
||||||
|
logger
|
||||||
|
lt_debug
|
||||||
|
time
|
||||||
|
)
|
||||||
|
|
||||||
|
elseif(UNIX)
|
||||||
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
surface
|
||||||
|
INTERFACES
|
||||||
|
constants.cppm
|
||||||
system.cppm
|
system.cppm
|
||||||
requests.cppm
|
requests.cppm
|
||||||
events.cppm
|
events.cppm
|
||||||
|
|
@ -127,7 +148,9 @@ if(NOT WIN32)
|
||||||
lt_debug
|
lt_debug
|
||||||
time
|
time
|
||||||
)
|
)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
|
message(FATAL "Failed to generate cmake: unsupported platform")
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -176,6 +199,8 @@ add_library_module(
|
||||||
surface
|
surface
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return()
|
||||||
|
|
||||||
add_library_module(
|
add_library_module(
|
||||||
NAME
|
NAME
|
||||||
libmirror
|
libmirror
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,9 @@ export class SystemStats
|
||||||
public:
|
public:
|
||||||
void push_diagnosis(SystemDiagnosis &&diagnosis)
|
void push_diagnosis(SystemDiagnosis &&diagnosis)
|
||||||
{
|
{
|
||||||
auto diag = m_diagnosis.emplace_back(std::move(diagnosis));
|
auto &diag = m_diagnosis.emplace_back(std::move(diagnosis));
|
||||||
|
|
||||||
log::debug("message: {}", diag.message);
|
log::info("message: {}", std::string { diag.message });
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto empty_diagnosis() const -> bool
|
[[nodiscard]] auto empty_diagnosis() const -> bool
|
||||||
|
|
|
||||||
|
|
@ -15,26 +15,24 @@ export void bake_shader(
|
||||||
using lt::assets::ShaderAsset;
|
using lt::assets::ShaderAsset;
|
||||||
using enum lt::assets::ShaderAsset::Type;
|
using enum lt::assets::ShaderAsset::Type;
|
||||||
|
|
||||||
auto glsl_path = in_path.string();
|
auto glsl_path = std::string { in_path.string() };
|
||||||
auto spv_path = std::format("{}.spv", glsl_path);
|
auto spv_path = std::format("{}.spv", glsl_path);
|
||||||
lt::log::trace(
|
lt::log::trace(
|
||||||
"Compiling {} shader {} -> {}",
|
"Compiling {} shader {} -> {}",
|
||||||
type == vertex ? "vertex" : "fragment",
|
type == vertex ? "vertex" : "fragment",
|
||||||
glsl_path,
|
std::string { glsl_path },
|
||||||
spv_path
|
std::string { spv_path }
|
||||||
);
|
);
|
||||||
|
|
||||||
// Don't bother linking to shaderc, just invoke the command with a system call.
|
// Don't bother linking to shaderc, just invoke the command with a system call.
|
||||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||||
std::system(
|
std::system(std::format(
|
||||||
std::format(
|
"glslc --target-env=vulkan1.4 -std=450core -fshader-stage={} {} -o {}",
|
||||||
"glslc --target-env=vulkan1.4 -std=450core -fshader-stage={} {} -o {}",
|
type == vertex ? "vert" : "frag",
|
||||||
type == vertex ? "vert" : "frag",
|
glsl_path,
|
||||||
glsl_path,
|
spv_path
|
||||||
spv_path
|
)
|
||||||
)
|
.c_str());
|
||||||
.c_str()
|
|
||||||
);
|
|
||||||
|
|
||||||
auto stream = std::ifstream(spv_path, std::ios::binary);
|
auto stream = std::ifstream(spv_path, std::ios::binary);
|
||||||
lt::debug::ensure(
|
lt::debug::ensure(
|
||||||
|
|
|
||||||
|
|
@ -251,11 +251,16 @@ private:
|
||||||
|
|
||||||
TypeId m_entity_count;
|
TypeId m_entity_count;
|
||||||
|
|
||||||
std::flat_map<TypeId, memory::Scope<UnderlyingSparseSet_T>> m_sparsed_sets;
|
/** MSVC DOES NOT SUPPORT FLAT MAP!!
|
||||||
|
* IT"S YEAR ~2026, great...
|
||||||
|
* using ::std::map for the time being.
|
||||||
|
*/
|
||||||
|
|
||||||
std::flat_map<TypeId, Callback_T> m_on_construct_hooks;
|
std::map<TypeId, memory::Scope<UnderlyingSparseSet_T>> m_sparsed_sets;
|
||||||
|
|
||||||
std::flat_map<TypeId, Callback_T> m_on_destruct_hooks;
|
std::map<TypeId, Callback_T> m_on_construct_hooks;
|
||||||
|
|
||||||
|
std::map<TypeId, Callback_T> m_on_destruct_hooks;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lt::ecs
|
} // namespace lt::ecs
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ struct [[maybe_unused]] print
|
||||||
// clang-format off
|
// clang-format off
|
||||||
switch (level)
|
switch (level)
|
||||||
{
|
{
|
||||||
using enum Level;
|
using enum ::lt::log::Level;
|
||||||
case trace : return "\033[1;37m| trc |\033[0m";
|
case trace : return "\033[1;37m| trc |\033[0m";
|
||||||
case debug : return "\033[1;36m| dbg |\033[0m";
|
case debug : return "\033[1;36m| dbg |\033[0m";
|
||||||
case info : return "\033[1;32m| inf |\033[0m";
|
case info : return "\033[1;32m| inf |\033[0m";
|
||||||
|
|
@ -71,7 +71,7 @@ struct [[maybe_unused]] print
|
||||||
std::println(
|
std::println(
|
||||||
"{} {} ==> {}",
|
"{} {} ==> {}",
|
||||||
to_string(level, location),
|
to_string(level, location),
|
||||||
std::format("{}:{}", path.filename().c_str(), location.line()),
|
std::format("{}:{}", path.filename().string(), location.line()),
|
||||||
std::format(format, std::forward<Args>(arguments)...)
|
std::format(format, std::forward<Args>(arguments)...)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
module;
|
module;
|
||||||
#ifdef LIGHT_PLATFORM_LINUX
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
typedef struct _XDisplay Display;
|
typedef struct _XDisplay Display;
|
||||||
|
#else defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
export module surface.system:components;
|
export module surface.system:components;
|
||||||
|
|
@ -38,13 +40,18 @@ public:
|
||||||
ModifyPositionRequest,
|
ModifyPositionRequest,
|
||||||
ModifyVisibilityRequest>;
|
ModifyVisibilityRequest>;
|
||||||
|
|
||||||
#ifdef LIGHT_PLATFORM_LINUX
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
struct NativeData
|
struct NativeData
|
||||||
{
|
{
|
||||||
Display *display;
|
Display *display;
|
||||||
std::uint32_t window;
|
std::uint32_t window;
|
||||||
unsigned long wm_delete_message;
|
unsigned long wm_delete_message;
|
||||||
};
|
};
|
||||||
|
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
|
struct NativeData
|
||||||
|
{
|
||||||
|
HWND window;
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static constexpr auto max_dimension = 4096;
|
static constexpr auto max_dimension = 4096;
|
||||||
|
|
|
||||||
7
modules/surface/constants.cppm
Normal file
7
modules/surface/constants.cppm
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
export module surface.constants;
|
||||||
|
|
||||||
|
export namespace lt::surface::constants {
|
||||||
|
|
||||||
|
constexpr auto *class_name = "light_engine_window_class_name:3";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -75,7 +75,7 @@ System::~System()
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO(Light): make registry.remove not validate iterators
|
// TODO(Light): make registry.remove not invalidate iterators
|
||||||
auto entities_to_remove = std::vector<ecs::EntityId> {};
|
auto entities_to_remove = std::vector<ecs::EntityId> {};
|
||||||
for (auto &[entity, surface] : m_registry->view<SurfaceComponent>())
|
for (auto &[entity, surface] : m_registry->view<SurfaceComponent>())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,139 +1,508 @@
|
||||||
#include <memory/reference.hpp>
|
module;
|
||||||
#include <surface/system.hpp>
|
#include <Windows.h>
|
||||||
#include <utility>
|
module surface.system;
|
||||||
|
import surface.constants;
|
||||||
|
import debug.assertions;
|
||||||
|
import memory.reference;
|
||||||
|
import surface.requests;
|
||||||
|
import surface.events;
|
||||||
|
import logger;
|
||||||
|
import ecs.registry;
|
||||||
|
import ecs.entity;
|
||||||
|
import time;
|
||||||
|
import std;
|
||||||
|
|
||||||
namespace lt::surface {
|
namespace lt::surface {
|
||||||
|
|
||||||
System::System(memory::Ref<ecs::Registry> registry, memory::Ref<app::EventMediator> event_mediator)
|
template<class... Ts>
|
||||||
: m_registry(std::move(registry))
|
struct overloads: Ts...
|
||||||
, m_event_mediator(std::move(event_mediator))
|
|
||||||
{
|
{
|
||||||
ensure(m_registry, "Failed to initialize surface system: null registry");
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
|
|
||||||
ensure(
|
void ensure_component_sanity(const SurfaceComponent &component);
|
||||||
m_registry->view<SurfaceComponent>().size() == 0,
|
|
||||||
|
auto CALLBACK native_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> LRESULT;
|
||||||
|
|
||||||
|
System::System(memory::Ref<ecs::Registry> registry): m_registry(std::move(registry))
|
||||||
|
{
|
||||||
|
debug::ensure(m_registry, "Failed to initialize surface system: null registry");
|
||||||
|
|
||||||
|
debug::ensure(
|
||||||
|
m_registry->view<SurfaceComponent>().get_size() == 0,
|
||||||
"Failed to initialize surface system: registry has surface component(s)"
|
"Failed to initialize surface system: registry has surface component(s)"
|
||||||
);
|
);
|
||||||
|
|
||||||
m_registry->get_entt_registry()
|
m_registry->connect_on_destruct<SurfaceComponent>(
|
||||||
.on_construct<SurfaceComponent>()
|
[this](ecs::Registry ®istry, ecs::EntityId entity) {
|
||||||
.connect<&System::on_surface_construct>(this);
|
on_surface_destruct(registry, entity);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
m_registry->get_entt_registry()
|
auto window_class = WNDCLASS {
|
||||||
.on_update<SurfaceComponent>()
|
.lpfnWndProc = native_window_proc,
|
||||||
.connect<&System::on_surface_update>(this);
|
.hInstance = GetModuleHandle(nullptr),
|
||||||
|
.lpszClassName = constants::class_name,
|
||||||
m_registry->get_entt_registry()
|
};
|
||||||
.on_destroy<SurfaceComponent>()
|
RegisterClass(&window_class);
|
||||||
.connect<&System::on_surface_destroy>(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
System::~System()
|
System::~System()
|
||||||
{
|
{
|
||||||
m_registry->get_entt_registry()
|
if (!m_registry)
|
||||||
.on_construct<SurfaceComponent>()
|
{
|
||||||
.disconnect<&System::on_surface_construct>(this);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_registry->get_entt_registry()
|
|
||||||
.on_update<SurfaceComponent>()
|
|
||||||
.connect<&System::on_surface_update>(this);
|
|
||||||
|
|
||||||
m_registry->get_entt_registry()
|
|
||||||
.on_destroy<SurfaceComponent>()
|
|
||||||
.disconnect<&System::on_surface_destroy>(this);
|
|
||||||
|
|
||||||
|
|
||||||
m_registry->view<SurfaceComponent>().each([&](const entt::entity entity, SurfaceComponent &) {
|
|
||||||
m_registry->get_entt_registry().remove<SurfaceComponent>(entity);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::on_surface_construct(entt::registry ®istry, entt::entity entity)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto &surface = registry.get<SurfaceComponent>(entity);
|
// TODO(Light): make registry.remove not invalidate iterators
|
||||||
const auto &resolution = surface.get_resolution();
|
auto entities_to_remove = std::vector<ecs::EntityId> {};
|
||||||
const auto &position = surface.get_position();
|
for (auto &[entity, surface] : m_registry->view<SurfaceComponent>())
|
||||||
ensure_component_sanity(surface);
|
{
|
||||||
|
entities_to_remove.emplace_back(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto entity : entities_to_remove)
|
||||||
|
{
|
||||||
|
m_registry->remove<SurfaceComponent>(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_registry->disconnect_on_construct<SurfaceComponent>();
|
||||||
|
m_registry->disconnect_on_destruct<SurfaceComponent>();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (const std::exception &exp)
|
||||||
{
|
{
|
||||||
registry.remove<SurfaceComponent>(entity);
|
log::error("Uncaught exception in surface::~System:");
|
||||||
throw;
|
log::error("\twhat: {}", exp.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::on_surface_update(entt::registry ®istry, entt::entity entity)
|
void System::on_register()
|
||||||
{
|
{
|
||||||
auto &surface = registry.get<SurfaceComponent>(entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::on_surface_destroy(entt::registry ®istry, entt::entity entity)
|
void System::on_unregister()
|
||||||
{
|
{
|
||||||
auto &surface = registry.get<SurfaceComponent>(entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::set_title(ecs::Entity entity, std::string_view new_title)
|
void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::CreateInfo info)
|
||||||
|
try
|
||||||
{
|
{
|
||||||
auto &surface = entity.get_component<SurfaceComponent>();
|
auto &component = m_registry->add<SurfaceComponent>(entity, info);
|
||||||
|
auto &surface = m_registry->get<SurfaceComponent>(entity);
|
||||||
|
const auto &resolution = surface.get_resolution();
|
||||||
|
const auto &position = surface.get_position();
|
||||||
|
ensure_component_sanity(surface);
|
||||||
|
|
||||||
surface.m_title = new_title;
|
surface.m_native_data.window = CreateWindowEx(
|
||||||
|
0,
|
||||||
|
constants::class_name,
|
||||||
|
info.title.data(),
|
||||||
|
WS_OVERLAPPEDWINDOW,
|
||||||
|
CW_USEDEFAULT,
|
||||||
|
CW_USEDEFAULT,
|
||||||
|
CW_USEDEFAULT,
|
||||||
|
CW_USEDEFAULT,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
GetModuleHandle(nullptr),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
debug::ensure(surface.m_native_data.window, "Failed to create Windows surface component");
|
||||||
|
|
||||||
|
ShowWindow(surface.m_native_data.window, SW_NORMAL);
|
||||||
|
|
||||||
|
// TODO(Light): refactor "environment" into standalone module
|
||||||
|
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||||
|
// auto *display_env = std::getenv("DISPLAY");
|
||||||
|
// debug::ensure(display_env != nullptr, "DISPLAY env var not found!");
|
||||||
|
//
|
||||||
|
// auto *display = XOpenDisplay(display_env);
|
||||||
|
// debug::ensure(display, "Failed to open XDisplay with DISPLAY: {}", display_env);
|
||||||
|
//
|
||||||
|
// auto root_window = XDefaultRootWindow(display);
|
||||||
|
//
|
||||||
|
// auto border_width = 0;
|
||||||
|
// auto depth = std::int32_t { CopyFromParent };
|
||||||
|
// auto window_class = CopyFromParent;
|
||||||
|
// auto *visual = (Visual *)CopyFromParent;
|
||||||
|
//
|
||||||
|
// auto attribute_value_mask = CWBackPixel | CWEventMask;
|
||||||
|
// auto attributes = XSetWindowAttributes {
|
||||||
|
// .background_pixel = 0xffafe9af,
|
||||||
|
// .event_mask = all_events_mask,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// typedef struct Hints
|
||||||
|
// {
|
||||||
|
// unsigned long flags;
|
||||||
|
// unsigned long functions;
|
||||||
|
// unsigned long decorations;
|
||||||
|
// long inputMode;
|
||||||
|
// unsigned long status;
|
||||||
|
// } Hints;
|
||||||
|
//
|
||||||
|
// auto main_window = XCreateWindow(
|
||||||
|
// display,
|
||||||
|
// root_window,
|
||||||
|
// position.x,
|
||||||
|
// position.y,
|
||||||
|
// resolution.x,
|
||||||
|
// resolution.y,
|
||||||
|
// border_width,
|
||||||
|
// depth,
|
||||||
|
// window_class,
|
||||||
|
// visual,
|
||||||
|
// attribute_value_mask,
|
||||||
|
// &attributes
|
||||||
|
// );
|
||||||
|
// surface.m_native_data.display = display;
|
||||||
|
// surface.m_native_data.window = main_window;
|
||||||
|
//
|
||||||
|
// surface.m_native_data.wm_delete_message = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
||||||
|
// XSetWMProtocols(display, main_window, &surface.m_native_data.wm_delete_message, 1);
|
||||||
|
//
|
||||||
|
// // code to remove decoration
|
||||||
|
// auto hints = std::array<const unsigned char, 5> { 2, 0, 0, 0, 0 };
|
||||||
|
// const auto motif_hints = XInternAtom(display, "_MOTIF_WM_HINTS", False);
|
||||||
|
//
|
||||||
|
// XChangeProperty(
|
||||||
|
// display,
|
||||||
|
// surface.m_native_data.window,
|
||||||
|
// motif_hints,
|
||||||
|
// motif_hints,
|
||||||
|
// 32,
|
||||||
|
// PropModeReplace,
|
||||||
|
// hints.data(),
|
||||||
|
// 5
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// XMapWindow(display, main_window);
|
||||||
|
// XStoreName(display, main_window, surface.m_title.c_str());
|
||||||
|
// XFlush(display);
|
||||||
|
//
|
||||||
|
// if (!surface.is_visible())
|
||||||
|
// {
|
||||||
|
// XUnmapWindow(display, main_window);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
catch (const std::exception &exp)
|
||||||
|
{
|
||||||
|
log::error("Exception thrown when on_constructing surface component");
|
||||||
|
log::error("\tentity: {}", std::uint32_t { entity });
|
||||||
|
log::error("\twhat: {}", exp.what());
|
||||||
|
m_registry->remove<SurfaceComponent>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::tick() -> bool
|
void System::on_surface_destruct(ecs::Registry ®istry, ecs::EntityId entity)
|
||||||
{
|
{
|
||||||
return false;
|
auto *window = registry.get<SurfaceComponent>(entity).get_native_data().window;
|
||||||
}
|
if (!window)
|
||||||
|
|
||||||
void System::set_size(ecs::Entity surface_entity, const math::uvec2 &new_size)
|
|
||||||
{
|
|
||||||
auto &surface = surface_entity.get_component<SurfaceComponent>();
|
|
||||||
surface.m_resolution = new_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::set_v_sync(ecs::Entity surface_entity, bool vsync)
|
|
||||||
{
|
|
||||||
auto &surface = surface_entity.get_component<SurfaceComponent>();
|
|
||||||
surface.m_vsync = vsync;
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::set_visibility(ecs::Entity surface_entity, bool visible)
|
|
||||||
{
|
|
||||||
auto &surface = surface_entity.get_component<SurfaceComponent>();
|
|
||||||
surface.m_visible = visible;
|
|
||||||
|
|
||||||
if (visible)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
log::warn("Surface component destroyed with null window handle");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DestroyWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::ensure_component_sanity(const SurfaceComponent &component)
|
void System::handle_events(SurfaceComponent &surface)
|
||||||
|
{
|
||||||
|
auto &queue = surface.m_event_queue;
|
||||||
|
queue.clear();
|
||||||
|
|
||||||
|
auto message = MSG {};
|
||||||
|
while (PeekMessage(&message, 0, {}, {}, PM_REMOVE))
|
||||||
|
{
|
||||||
|
switch (message.message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug("Window message type: {}", std::uint32_t { message.message });
|
||||||
|
}
|
||||||
|
|
||||||
|
// auto event = XEvent {};
|
||||||
|
// auto &[display, window, wm_delete_message] = surface.m_native_data;
|
||||||
|
//
|
||||||
|
// XFlush(display);
|
||||||
|
// while (XEventsQueued(display, QueuedAlready) != 0)
|
||||||
|
// {
|
||||||
|
// XNextEvent(surface.m_native_data.display, &event);
|
||||||
|
//
|
||||||
|
// switch (event.type)
|
||||||
|
// {
|
||||||
|
// case KeyPress:
|
||||||
|
// {
|
||||||
|
// queue.emplace_back<KeyPressedEvent>(
|
||||||
|
// static_cast<std::uint32_t>(XLookupKeysym(&event.xkey, 0))
|
||||||
|
// );
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case KeyRelease:
|
||||||
|
// {
|
||||||
|
// queue.emplace_back<KeyReleasedEvent>(
|
||||||
|
// static_cast<std::uint32_t>(XLookupKeysym(&event.xkey, 0))
|
||||||
|
// );
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case ButtonPress:
|
||||||
|
// {
|
||||||
|
// queue.emplace_back<ButtonPressedEvent>(static_cast<int>(event.xbutton.button));
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case ButtonRelease:
|
||||||
|
// {
|
||||||
|
// queue.emplace_back<ButtonReleasedEvent>(static_cast<int>(event.xbutton.button));
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case FocusIn:
|
||||||
|
// {
|
||||||
|
// queue.emplace_back<GainFocusEvent>({});
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case FocusOut:
|
||||||
|
// {
|
||||||
|
// queue.emplace_back<LostFocusEvent>({});
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case ClientMessage:
|
||||||
|
// {
|
||||||
|
// if (event.xclient.data.l[0] == wm_delete_message)
|
||||||
|
// {
|
||||||
|
// queue.emplace_back<ClosedEvent>({});
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case MotionNotify:
|
||||||
|
// {
|
||||||
|
// queue.emplace_back<MouseMovedEvent>(MouseMovedEvent {
|
||||||
|
// static_cast<float>(event.xmotion.x),
|
||||||
|
// static_cast<float>(event.xmotion.y),
|
||||||
|
// });
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case ConfigureNotify:
|
||||||
|
// {
|
||||||
|
// const auto [prev_width, prev_height] = surface.get_resolution();
|
||||||
|
// const auto new_width = event.xconfigure.width;
|
||||||
|
// const auto new_height = event.xconfigure.height;
|
||||||
|
// if (prev_width != new_width || prev_height != new_height)
|
||||||
|
// {
|
||||||
|
// surface.m_resolution.x = new_width;
|
||||||
|
// surface.m_resolution.y = new_height;
|
||||||
|
// queue.emplace_back<ResizedEvent>(ResizedEvent {
|
||||||
|
// static_cast<std::uint32_t>(new_width),
|
||||||
|
// static_cast<std::uint32_t>(new_height),
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// const auto [prev_x, prev_y] = surface.get_position();
|
||||||
|
// const auto new_x = event.xconfigure.x;
|
||||||
|
// const auto new_y = event.xconfigure.y;
|
||||||
|
// if (prev_x != new_x || prev_y != new_y)
|
||||||
|
// {
|
||||||
|
// surface.m_position.x = new_x;
|
||||||
|
// surface.m_position.y = new_y;
|
||||||
|
// queue.emplace_back<MovedEvent>(MovedEvent {
|
||||||
|
// new_x,
|
||||||
|
// new_y,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// default: break; /* pass */
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::handle_requests(SurfaceComponent &surface)
|
||||||
|
{
|
||||||
|
const auto visitor = overloads {
|
||||||
|
[&](const ModifyTitleRequest &request) { modify_title(surface, request); },
|
||||||
|
[&](const ModifyResolutionRequest &request) { modify_resolution(surface, request); },
|
||||||
|
[&](const ModifyPositionRequest &request) { modify_position(surface, request); },
|
||||||
|
[&](const ModifyVisibilityRequest &request) { modify_visiblity(surface, request); },
|
||||||
|
[&](const auto &) { log::error("Unknown surface request"); },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &request : surface.peek_requests())
|
||||||
|
{
|
||||||
|
std::visit(visitor, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
surface.m_requests.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::modify_title(SurfaceComponent &surface, const ModifyTitleRequest &request)
|
||||||
|
{
|
||||||
|
surface.m_title = request.title;
|
||||||
|
|
||||||
|
// const auto &[display, window, _] = surface.get_native_data();
|
||||||
|
// XStoreName(display, window, request.title.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::modify_resolution(SurfaceComponent &surface, const ModifyResolutionRequest &request)
|
||||||
|
{
|
||||||
|
// surface.m_resolution = request.resolution;
|
||||||
|
|
||||||
|
// auto &[display, window, _] = surface.m_native_data;
|
||||||
|
// const auto &[width, height] = request.resolution;
|
||||||
|
// // XResizeWindow(display, window, width, height);
|
||||||
|
//
|
||||||
|
// // get baseline serial number for X requests generated from XResizeWindow
|
||||||
|
// auto serial = NextRequest(display);
|
||||||
|
//
|
||||||
|
// // request a new window size from the X server
|
||||||
|
// XResizeWindow(
|
||||||
|
// display,
|
||||||
|
// window,
|
||||||
|
// static_cast<std::uint32_t>(width),
|
||||||
|
// static_cast<std::uint32_t>(height)
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // flush output queue and wait for X server to processes the request
|
||||||
|
// XSync(display, False);
|
||||||
|
// // The documentation for XResizeWindow includes this important note:
|
||||||
|
// //
|
||||||
|
// // If the override-redirect flag of the window is False and some
|
||||||
|
// // other client has selected SubstructureRedirectMask on the parent,
|
||||||
|
// // the X server generates a ConfigureRequest event, and no further
|
||||||
|
// // processing is performed.
|
||||||
|
// //
|
||||||
|
// // What this means, essentially, is that if this window is a top-level
|
||||||
|
// // window, then it's the window manager (the "other client") that is
|
||||||
|
// // responsible for changing this window's size. So when we call
|
||||||
|
// // XResizeWindow() on a top-level window, then instead of resizing
|
||||||
|
// // the window immediately, the X server informs the window manager,
|
||||||
|
// // and then the window manager sets our new size (usually it will be
|
||||||
|
// // the size we asked for). We receive a ConfigureNotify event when
|
||||||
|
// // our new size has been set.
|
||||||
|
// constexpr auto lifespan = std::chrono::milliseconds { 10 };
|
||||||
|
// auto timer = time::Timer {};
|
||||||
|
// auto event = XEvent {};
|
||||||
|
// while (!XCheckIfEvent(
|
||||||
|
// display,
|
||||||
|
// &event,
|
||||||
|
// XEventTypeEquals<ConfigureNotify>,
|
||||||
|
// reinterpret_cast<XPointer>(&window) // NOLINT
|
||||||
|
// )
|
||||||
|
// || event.xconfigure.serial < serial)
|
||||||
|
// {
|
||||||
|
// std::this_thread::sleep_for(std::chrono::microseconds { 100 });
|
||||||
|
// if (timer.elapsed_time() > lifespan)
|
||||||
|
// {
|
||||||
|
// log::error("Timed out waiting for XResizeWindow's event");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // We don't need to update the component's state and handle the event in this funcion.
|
||||||
|
// // Since handle_requests is called before handle_events.
|
||||||
|
// // So we just put the event back into the queue and move on.
|
||||||
|
// XPutBackEvent(display, &event);
|
||||||
|
// XSync(display, False);
|
||||||
|
// XFlush(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::modify_position(SurfaceComponent &surface, const ModifyPositionRequest &request)
|
||||||
|
{
|
||||||
|
// surface.m_position = request.position;
|
||||||
|
|
||||||
|
// auto &[display, window, _] = surface.m_native_data;
|
||||||
|
// const auto &[x, y] = request.position;
|
||||||
|
//
|
||||||
|
// // get baseline serial number for X requests generated from XResizeWindow
|
||||||
|
// auto serial = NextRequest(display);
|
||||||
|
// XMoveWindow(display, window, static_cast<int>(x), static_cast<int>(y));
|
||||||
|
//
|
||||||
|
// // flush output queue and wait for X server to processes the request
|
||||||
|
// XSync(display, False);
|
||||||
|
// constexpr auto lifespan = std::chrono::milliseconds { 10 };
|
||||||
|
// auto timer = time::Timer {};
|
||||||
|
// auto event = XEvent {};
|
||||||
|
// while (!XCheckIfEvent(
|
||||||
|
// display,
|
||||||
|
// &event,
|
||||||
|
// XEventTypeEquals<ConfigureNotify>,
|
||||||
|
// reinterpret_cast<XPointer>(&window) // NOLINT
|
||||||
|
// )
|
||||||
|
// || event.xconfigure.serial < serial)
|
||||||
|
// {
|
||||||
|
// std::this_thread::sleep_for(std::chrono::microseconds { 100 });
|
||||||
|
// if (timer.elapsed_time() > lifespan)
|
||||||
|
// {
|
||||||
|
// log::error("Timed out waiting for XMoveWindow's event");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // We don't need to update the component's state and handle the event in this funcion.
|
||||||
|
// // Since handle_requests is called before handle_events.
|
||||||
|
// // So we just put the event back into the queue and move on.
|
||||||
|
// XPutBackEvent(display, &event);
|
||||||
|
// XSync(display, False);
|
||||||
|
// XFlush(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::modify_visiblity(SurfaceComponent &surface, const ModifyVisibilityRequest &request)
|
||||||
|
{
|
||||||
|
// const auto &[display, window, _] = surface.get_native_data();
|
||||||
|
// surface.m_visible = request.visible;
|
||||||
|
|
||||||
|
// if (request.visible)
|
||||||
|
// {
|
||||||
|
// XMapWindow(display, window);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// XUnmapWindow(display, window);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::tick(app::TickInfo tick)
|
||||||
|
{
|
||||||
|
for (auto &[id, surface] : m_registry->view<SurfaceComponent>())
|
||||||
|
{
|
||||||
|
handle_requests(surface);
|
||||||
|
handle_events(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
m_last_tick_result = app::TickResult {
|
||||||
|
.info = tick,
|
||||||
|
.duration = now - tick.start_time,
|
||||||
|
.end_time = now,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensure_component_sanity(const SurfaceComponent &component)
|
||||||
{
|
{
|
||||||
auto [width, height] = component.get_resolution();
|
auto [width, height] = component.get_resolution();
|
||||||
|
|
||||||
ensure(width != 0u, "Received bad values for surface component: width({}) == 0", width);
|
debug::ensure(width != 0u, "Received bad values for surface component: width({}) == 0", width);
|
||||||
|
|
||||||
ensure(height != 0u, "Received bad values for surface component: height({}) == 0", height);
|
debug::ensure(
|
||||||
|
height != 0u,
|
||||||
|
"Received bad values for surface component: height({}) == 0",
|
||||||
|
height
|
||||||
|
);
|
||||||
|
|
||||||
ensure(
|
debug::ensure(
|
||||||
width < SurfaceComponent::max_dimension,
|
width < SurfaceComponent::max_dimension,
|
||||||
"Received bad values for surface component: width({}) > max_dimension({})",
|
"Received bad values for surface component: width({}) > max_dimension({})",
|
||||||
width,
|
width,
|
||||||
SurfaceComponent::max_dimension
|
SurfaceComponent::max_dimension
|
||||||
);
|
);
|
||||||
|
|
||||||
ensure(
|
debug::ensure(
|
||||||
height < SurfaceComponent::max_dimension,
|
height < SurfaceComponent::max_dimension,
|
||||||
"Received bad values for surface component: height({}) > max_dimension({})",
|
"Received bad values for surface component: height({}) > max_dimension({})",
|
||||||
height,
|
height,
|
||||||
SurfaceComponent::max_dimension
|
SurfaceComponent::max_dimension
|
||||||
);
|
);
|
||||||
|
|
||||||
ensure(
|
debug::ensure(
|
||||||
component.get_title().size() < SurfaceComponent::max_title_length,
|
component.get_title().size() < SurfaceComponent::max_title_length,
|
||||||
"Received bad values for surface component: title.size({}) > max_title_length({})",
|
"Received bad values for surface component: title.size({}) > max_title_length({})",
|
||||||
component.get_title().size(),
|
component.get_title().size(),
|
||||||
|
|
@ -141,8 +510,18 @@ void System::ensure_component_sanity(const SurfaceComponent &component)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto CALLBACK native_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> LRESULT
|
||||||
|
{
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WM_DESTROY:
|
||||||
|
{
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace lt::surface
|
} // namespace lt::surface
|
||||||
|
|
||||||
namespace lt {
|
|
||||||
|
|
||||||
} // namespace lt
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import math.vec2;
|
||||||
import app.system;
|
import app.system;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
|
||||||
using ::lt::surface::SurfaceComponent;
|
using ::lt::surface::SurfaceComponent;
|
||||||
using ::lt::surface::System;
|
using ::lt::surface::System;
|
||||||
using ::lt::test::Case;
|
using ::lt::test::Case;
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,6 @@ if(WIN32)
|
||||||
add_compile_definitions(LIGHT_PLATFORM_WINDOWS)
|
add_compile_definitions(LIGHT_PLATFORM_WINDOWS)
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
add_compile_definitions(LIGHT_PLATFORM_LINUX)
|
add_compile_definitions(LIGHT_PLATFORM_LINUX)
|
||||||
|
else()
|
||||||
|
message(FATAL "Failed to generate cmake: unsupported platform")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue