Compare commits

...

23 commits

Author SHA1 Message Date
4941b68eab
ci(documentation): add the dockerfile
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-09-18 19:39:32 +03:30
d448726350
ci(ci/amd64/clang/fuzz): add fuzz dockerfile 2025-09-18 19:38:24 +03:30
8741a769a6
style: remove trailing whitespace 2025-09-18 19:37:48 +03:30
e695808f98
ci(amd64/gcc/valgrind): change base image from alpine to arch 2025-09-18 19:37:25 +03:30
1158da1a39
ci(amd64/gcc/unit_tests): change base image from alpine to arch 2025-09-18 19:36:44 +03:30
0b03dda72f
ci(amd64/clang/coverage): update dockerfile pacman packages 2025-09-18 19:36:09 +03:30
a08b5689dd
ci(amd64/clang/msan): update dockerfile pacman packages 2025-09-18 19:34:44 +03:30
2358dc6824
ci(mad64/clang/lsan): update dockerfile pacman packages 2025-09-18 19:34:19 +03:30
061ebaddb5
ci: update build_ci_images.sh 2025-09-18 19:33:20 +03:30
de23d7a319
build: remove imgui, glad, opengl & glfw from cmake find_package dependencies 2025-09-18 19:32:51 +03:30
249cecdb50
refactor(tests): printable now checks if the type is std::formattable 2025-09-18 19:32:11 +03:30
794b52c10b
build: remove external directory from build subdirectories 2025-09-18 19:30:21 +03:30
cd7fb754d2
ci(amd64/gcc/unit_tests): remove redundant use_mold commandline option 2025-09-18 19:29:29 +03:30
cd7274cbd5
ci(amd64/clang/coverage): remove imgui/glfw from ignore-filename-regex 2025-09-18 19:28:47 +03:30
92b9c49f44
chore: add module back 2025-09-18 19:27:08 +03:30
0993adf0f0
refactor(ui): removed imgui as dependency, will implement ui w/out dependency 2025-09-18 19:25:21 +03:30
3a713b6af7
wip: renderer rewrite 2025-09-18 19:24:27 +03:30
3c1193eedc
refactor(mirror): adjusted code for new surface & input module changes 2025-09-18 19:23:31 +03:30
3020f17507
feat(math): add std::formatter specializations 2025-09-18 19:21:52 +03:30
bb6485488c
feat(math): add constexpr to some functions & add equality comparison operators 2025-09-18 19:19:32 +03:30
9e6300f1aa
chore(ecs): remove input as dependency 2025-09-18 19:17:39 +03:30
d69315c6aa
feat: reimplement input system 2025-09-18 19:16:54 +03:30
21e9933a42
feat(surface/linux): replace glfw with xlib 2025-09-18 19:15:29 +03:30
78 changed files with 1802 additions and 4864 deletions

View file

@ -40,4 +40,3 @@ if(ENABLE_LLVM_COVERAGE)
endif ()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/modules)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/external/glad)

View file

@ -10,7 +10,7 @@ add_subdirectory(./asset_parser)
# add_subdirectory(./asset_manager)
#
add_subdirectory(./camera)
# add_subdirectory(./input)
add_subdirectory(./input)
# add_subdirectory(./ui)
#
add_subdirectory(./surface)

View file

@ -1,4 +1,4 @@
add_library_module(ecs entity.cpp scene.cpp uuid.cpp )
target_link_libraries(ecs
PUBLIC logger lt_debug EnTT::EnTT input camera math
PUBLIC logger lt_debug EnTT::EnTT camera math
)

View file

@ -1,2 +1,4 @@
add_library_module(input input.cpp)
target_link_libraries(input PUBLIC surface math imgui::imgui logger)
add_library_module(input system.cpp)
target_link_libraries(input PUBLIC surface math logger)
add_test_module(input system.test.cpp)

View file

@ -1,159 +0,0 @@
#include <imgui.h>
#include <input/input.hpp>
#include <logger/logger.hpp>
namespace lt {
Input::Input(): m_mouse_position {}, m_mouse_delta {}
{
restart_input_state();
}
void Input::receive_user_interface_events_impl(bool receive, bool toggle /* = false */)
{
m_user_interface_events = toggle ? !m_user_interface_events : receive;
}
void Input::receieve_game_events_impl(bool receive, bool toggle /*= false*/)
{
auto prev = m_game_events;
m_game_events = toggle ? !m_user_interface_events : receive;
if (m_game_events != prev)
{
restart_input_state();
}
}
void Input::restart_input_state()
{
m_keyboad_keys.fill(false);
m_mouse_buttons.fill(false);
m_mouse_position = math::vec2(0.0f);
m_mouse_delta = math::vec2(0.0f);
m_mouse_wheel_delta = 0.0f;
}
void Input::on_event(const Event &inputEvent)
{
auto &io = ImGui::GetIO();
switch (inputEvent.get_event_type())
{
//** MOUSE_EVENTS **//
case EventType::MouseMoved:
{
const auto &event = dynamic_cast<const MouseMovedEvent &>(inputEvent);
if (m_game_events)
{
m_mouse_delta = event.get_position() - m_mouse_position;
m_mouse_position = event.get_position();
}
if (m_user_interface_events)
{
io.MousePos = ImVec2(event.get_x(), event.get_y());
}
return;
}
case EventType::ButtonPressed:
{
const auto &event = dynamic_cast<const ButtonPressedEvent &>(inputEvent);
if (m_game_events)
{
m_mouse_buttons[event.get_button()] = true;
}
if (m_user_interface_events)
{
io.MouseDown[event.get_button()] = true;
}
return;
}
case EventType::ButtonReleased:
{
const auto &event = dynamic_cast<const ButtonReleasedEvent &>(inputEvent);
if (m_game_events)
{
m_mouse_buttons[event.get_button()] = false;
}
if (m_user_interface_events)
{
io.MouseDown[event.get_button()] = false;
}
return;
}
case EventType::WheelScrolled:
{
const auto &event = dynamic_cast<const WheelScrolledEvent &>(inputEvent);
if (m_game_events)
{
m_mouse_wheel_delta = event.get_offset();
}
if (m_user_interface_events)
{
io.MouseWheel = event.get_offset();
}
return;
}
//** KEYBOARD_EVENTS **//
case EventType::KeyPressed:
{
const auto &event = dynamic_cast<const KeyPressedEvent &>(inputEvent);
if (m_game_events)
{
m_keyboad_keys[event.get_key()] = true;
}
if (m_user_interface_events)
{
// io.AddKeyEvent(event.get_key(), true);
// if (event.get_key() == Key::BackSpace)
// io.AddInputCharacter(Key::BackSpace);
}
return;
}
case EventType::KeyReleased:
{
const auto &event = dynamic_cast<const KeyReleasedEvent &>(inputEvent);
if (m_game_events)
{
m_keyboad_keys[event.get_key()] = false;
}
if (m_user_interface_events)
{
// io.AddKeyEvent(event.get_key(), false);
}
return;
}
case EventType::SetChar:
{
if (m_user_interface_events)
{
const auto &event = dynamic_cast<const SetCharEvent &>(inputEvent);
io.AddInputCharacter(event.get_character());
}
return;
}
default: log_trc("Dropped event");
}
}
} // namespace lt

View file

@ -1,5 +1,138 @@
#include <input/components.hpp>
#include <input/system.hpp>
namespace lt::input {
template<class... Ts>
struct overloads: Ts...
{
using Ts::operator()...;
};
System::System(Ref<ecs::Registry> registry): m_registry(std::move(registry))
{
ensure(m_registry, "Failed to initialize input system: null registry");
}
auto System::tick() -> bool
{
m_registry->view<surface::SurfaceComponent>().each([&](const entt::entity,
surface::SurfaceComponent &surface) {
for (const auto &event : surface.peek_events())
{
handle_event(event);
}
});
m_registry->view<InputComponent>().each([&](const entt::entity, InputComponent &input) {
// TODO(Light): instead of iterating over all actions each frame,
// make a list of "dirty" actions to reset
// and a surface_input->input_action mapping to get to action through input
// instead of brute-force checking all of them.
for (auto &action : input.m_actions)
{
auto code = action.trigger.mapped_keycode;
if (code < m_keys.size() && m_keys[code])
{
if (action.state == InputAction::State::triggered)
{
action.state = InputAction::State::active;
}
else if (action.state == InputAction::State::inactive)
{
action.state = InputAction::State::triggered;
}
}
else
{
action.state = InputAction::State::inactive;
}
}
});
return false;
}
void System::on_register()
{
}
void System::on_unregister()
{
}
void System::handle_event(const surface::SurfaceComponent::Event &event)
{
const auto visitor = overloads {
[this](const surface::ClosedEvent &) { on_surface_lost_focus(); },
[this](const surface::LostFocusEvent &) { on_surface_lost_focus(); },
[this](const surface::KeyPressedEvent &event) { on_key_press(event); },
[this](const surface::KeyReleasedEvent &event) { on_key_release(event); },
[this](const surface::MouseMovedEvent &event) { on_pointer_move(event); },
[this](const surface::ButtonPressedEvent &event) { on_button_press(event); },
[this](const surface::ButtonReleasedEvent &event) { on_button_release(event); },
[this](auto) {},
};
std::visit(visitor, event);
}
void System::on_surface_lost_focus()
{
for (auto &key : m_keys)
{
key = false;
}
for (auto &button : m_buttons)
{
button = false;
}
}
void System::on_key_press(const lt::surface::KeyPressedEvent &event)
{
if (event.get_key() > m_keys.size())
{
log_dbg(
"Key code larger than key container size, implement platform-dependant "
"key-code-mapping!"
);
return;
}
m_keys[event.get_key()] = true;
}
void System::on_key_release(const lt::surface::KeyReleasedEvent &event)
{
if (event.get_key() > m_keys.size())
{
log_dbg(
"Key code larger than key container size, implement platform-dependant "
"key-code-mapping!"
);
return;
}
m_keys[event.get_key()] = false;
}
void System::on_pointer_move(const lt::surface::MouseMovedEvent &event)
{
m_pointer_position = event.get_position();
}
void System::on_button_press(const lt::surface::ButtonPressedEvent &event)
{
m_buttons[event.get_button()] = true;
}
void System::on_button_release(const lt::surface::ButtonReleasedEvent &event)
{
m_buttons[event.get_button()] = false;
}
} // namespace lt::input

View file

@ -0,0 +1,169 @@
#include <ecs/entity.hpp>
#include <input/components.hpp>
#include <input/system.hpp>
#include <test/test.hpp>
// NOLINTBEGIN
using namespace lt;
using input::InputComponent;
using input::System;
using std::ignore;
using test::Case;
using test::expect_eq;
using test::expect_false;
using test::expect_ne;
using test::expect_not_nullptr;
using test::expect_throw;
using test::Suite;
// NOLINTEND
class Fixture
{
public:
[[nodiscard]] auto registry() -> Ref<ecs::Registry>
{
return m_registry;
}
auto add_input_component() -> ecs::Entity
{
auto entity = m_registry->create_entity("");
entity.add_component<InputComponent>();
return entity;
}
auto add_surface_component() -> ecs::Entity
{
auto entity = m_registry->create_entity("");
entity.add_component<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {});
return entity;
}
private:
Ref<ecs::Registry> m_registry = create_ref<ecs::Registry>();
};
Suite raii = [] {
Case { "happy path won't throw" } = [&] {
System { Fixture {}.registry() };
};
Case { "many won't freeze/throw" } = [&] {
auto fixture = Fixture {};
for (auto idx : std::views::iota(0, 10'000))
{
ignore = System { fixture.registry() };
}
};
Case { "unhappy path throws" } = [] {
expect_throw([] { ignore = System { {} }; });
};
};
Suite system_events = [] {
Case { "on_register won't throw" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
system.on_register();
expect_eq(fixture.registry()->view<InputComponent>().size(), 0);
};
Case { "on_unregister won't throw" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
system.on_register();
system.on_unregister();
expect_eq(fixture.registry()->view<InputComponent>().size(), 0);
};
};
Suite registry_events = [] {
Case { "on_construct<InputComnent>" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
const auto &entity = fixture.add_input_component();
expect_eq(fixture.registry()->view<InputComponent>().size(), 1);
};
Case { "on_destrroy<InputComponent>" } = [] {
auto fixture = Fixture {};
auto system = create_scope<System>(fixture.registry());
auto entity_a = fixture.add_input_component();
auto entity_b = fixture.add_input_component();
expect_eq(fixture.registry()->view<InputComponent>().size(), 2);
entity_a.remove_component<InputComponent>();
expect_eq(fixture.registry()->view<InputComponent>().size(), 1);
system.reset();
expect_eq(fixture.registry()->view<InputComponent>().size(), 1);
entity_b.remove_component<InputComponent>();
expect_eq(fixture.registry()->view<InputComponent>().size(), 0);
};
};
Suite tick = [] {
Case { "Empty tick won't throw" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
expect_false(system.tick());
};
Case { "Tick triggers input action" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
auto &surface = fixture.add_surface_component().get_component<surface::SurfaceComponent>();
auto &input = fixture.add_input_component().get_component<InputComponent>();
auto action_key = input.add_action(
{
.name { "test" },
.trigger = { .mapped_keycode = 69 },
}
);
expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive);
system.tick();
expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive);
surface.push_event(surface::KeyPressedEvent(69));
system.tick();
expect_eq(input.get_action(action_key).state, input::InputAction::State::triggered);
system.tick();
expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive);
system.tick();
system.tick();
system.tick();
expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive);
surface.push_event(surface::KeyPressedEvent(69));
system.tick();
};
Case { "Tick triggers" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
auto &surface = fixture.add_surface_component().get_component<surface::SurfaceComponent>();
auto &input = fixture.add_input_component().get_component<InputComponent>();
auto action_key = input.add_action(
{
.name { "test" },
.trigger = { .mapped_keycode = 69 },
}
);
};
};

View file

@ -0,0 +1,57 @@
#pragma once
#include <vector>
namespace lt::input {
struct Trigger
{
uint32_t mapped_keycode;
};
struct InputAction
{
using Key = size_t;
enum class State : uint8_t
{
inactive,
active,
triggered,
cancelled,
};
std::string name;
State state;
Trigger trigger;
};
class InputComponent
{
public:
InputComponent() = default;
auto add_action(InputAction action) -> size_t
{
m_actions.emplace_back(std::move(action));
return m_actions.size() - 1;
}
auto get_action(auto idx) -> const InputAction &
{
return m_actions[idx];
}
private:
friend class System;
void push_event()
{
}
std::vector<InputAction> m_actions;
};
} // namespace lt::input

View file

@ -0,0 +1,44 @@
#pragma once
#include <math/vec2.hpp>
namespace lt::input {
class AnalogEvent
{
public:
AnalogEvent(uint32_t input_code, math::uvec2 pointer_position)
: m_input_code(input_code)
, m_pointer_position(pointer_position)
{
}
[[nodiscard]] auto get_code() const -> uint32_t
{
return m_input_code;
};
[[nodiscard]] auto get_pointer_position() const -> math::uvec2
{
return m_pointer_position;
}
[[nodiscard]] auto to_string() const -> std::string
{
auto stream = std::stringstream {};
const auto &[x, y] = m_pointer_position;
stream << "input::AnalogEvent: " << m_input_code << " @ " << x << ", " << y;
return stream.str();
}
private:
uint32_t m_input_code;
math::uvec2 m_pointer_position;
};
class AxisEvent
{
};
} // namespace lt::input

View file

@ -1,80 +0,0 @@
#pragma once
#include <array>
#include <math/vec2.hpp>
namespace lt {
class Event;
class Input
{
public:
static auto instance() -> Input &
{
static auto instance = Input {};
return instance;
}
static void receive_user_interface_events(bool receive, bool toggle = false)
{
instance().receive_user_interface_events_impl(receive, toggle);
}
static void receive_game_events(bool receive, bool toggle = false)
{
instance().receieve_game_events_impl(receive, toggle);
}
static auto get_keyboard_key(int code) -> bool
{
return instance().m_keyboad_keys[code];
}
static auto get_mouse_button(int code) -> bool
{
return instance().m_mouse_buttons[code];
}
static auto get_mouse_position(int /*code*/) -> const math::vec2 &
{
return instance().m_mouse_position;
}
void on_event(const Event &inputEvent);
[[nodiscard]] auto is_receiving_input_events() const -> bool
{
return m_user_interface_events;
}
[[nodiscard]] auto is_receiving_game_events() const -> bool
{
return m_game_events;
}
private:
Input();
void receive_user_interface_events_impl(bool receive, bool toggle = false);
void receieve_game_events_impl(bool receive, bool toggle = false);
void restart_input_state();
std::array<bool, 348> m_keyboad_keys {};
std::array<bool, 8> m_mouse_buttons {};
math::vec2 m_mouse_position;
math::vec2 m_mouse_delta;
float m_mouse_wheel_delta {};
bool m_user_interface_events { true };
bool m_game_events { true };
};
} // namespace lt

View file

@ -1,63 +1,46 @@
#pragma once
#include <surface/system.hpp>
#include <app/system.hpp>
#include <ecs/scene.hpp>
#include <surface/components.hpp>
#include <surface/events/keyboard.hpp>
#include <surface/events/mouse.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
class System: public app::ISystem
{
public:
System(lt::surface::System &surface_system)
{
surface_system.add_event_listener([this](auto &&event) {
return handle_event(std::forward<decltype(event)>(event));
});
};
System(Ref<ecs::Registry> registry);
auto tick() -> bool override;
void on_register() override;
void on_unregister() override;
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;
},
void handle_event(const surface::SurfaceComponent::Event &event);
[](const lt::surface::KeyRepeatEvent &) { return false; },
void on_surface_lost_focus();
[](const lt::surface::KeyReleasedEvent &) { return false; },
void on_key_press(const lt::surface::KeyPressedEvent &event);
[](const lt::surface::KeySetCharEvent &) { return false; },
void on_key_release(const lt::surface::KeyReleasedEvent &event);
[](const lt::surface::MouseMovedEvent &) { return false; },
void on_pointer_move(const lt::surface::MouseMovedEvent &event);
[](const lt::surface::WheelScrolledEvent &) { return false; },
void on_button_press(const lt::surface::ButtonPressedEvent &event);
[](const lt::surface::ButtonPressedEvent &) { return false; },
void on_button_release(const lt::surface::ButtonReleasedEvent &event);
[](const lt::surface::ButtonReleasedEvent &) { return false; },
[](const auto &) { return false; },
};
return std::visit(visitor, event);
}
void setup_callbacks(GLFWwindow *handle);
Ref<ecs::Registry> m_registry;
std::array<bool, 512> m_keys {};
std::array<bool, 512> m_buttons {};
math::vec2 m_pointer_position;
};

View file

@ -9,7 +9,7 @@ template<typename T = float>
struct mat4_impl
{
using Column_T = vec4_impl<T>;
explicit mat4_impl(T scalar = 0)
constexpr explicit mat4_impl(T scalar = 0)
: values(
{
Column_T { scalar },
@ -22,7 +22,7 @@ struct mat4_impl
}
// clang-format off
mat4_impl(
constexpr mat4_impl(
const T& x0, const T& y0, const T& z0, const T& w0,
const T& x1, const T& y1, const T& z1, const T& w1,
const T& x2, const T& y2, const T& z2, const T& w2,
@ -33,7 +33,7 @@ struct mat4_impl
{
}
mat4_impl(
constexpr mat4_impl(
const Column_T &column_x,
const Column_T &column_y,
const Column_T &column_z,
@ -53,22 +53,22 @@ struct mat4_impl
};
}
[[nodiscard]] auto operator[](size_t idx) -> Column_T &
[[nodiscard]] constexpr auto operator[](size_t idx) -> Column_T &
{
return values[idx];
}
[[nodiscard]] auto operator[](size_t idx) const -> const Column_T &
[[nodiscard]] constexpr auto operator[](size_t idx) const -> const Column_T &
{
return values[idx];
}
[[nodiscard]] auto operator*(const mat4_impl<T> &other) const -> mat4_impl<T>
[[nodiscard]] constexpr auto operator*(const mat4_impl<T> &other) const -> mat4_impl<T>
{
return mat4_impl<T> {};
}
[[nodiscard]] auto operator*(const vec4_impl<T> &other) const -> vec4_impl<T>
[[nodiscard]] constexpr auto operator*(const vec4_impl<T> &other) const -> vec4_impl<T>
{
return vec4_impl<T> {};
}

View file

@ -5,18 +5,28 @@ namespace lt::math {
template<typename T = float>
struct vec2_impl
{
vec2_impl(): x(), y()
constexpr vec2_impl(): x(), y()
{
}
explicit vec2_impl(T scalar): x(scalar), y(scalar)
constexpr explicit vec2_impl(T scalar): x(scalar), y(scalar)
{
}
vec2_impl(T x, T y): x(x), y(y)
constexpr vec2_impl(T x, T y): x(x), y(y)
{
}
[[nodiscard]] auto operator==(const vec2_impl<T> &other) const -> bool
{
return x == other.x && y == other.y;
}
[[nodiscard]] auto operator!=(const vec2_impl<T> &other) const -> bool
{
return !(*this == other);
}
[[nodiscard]] auto operator*(const vec2_impl<T> &other) const -> vec2_impl
{
return {
@ -41,12 +51,12 @@ struct vec2_impl
};
}
T x; // NOLINT
T y; // NOLINT
};
using vec2 = vec2_impl<float>;
using ivec2 = vec2_impl<int32_t>;
@ -54,3 +64,17 @@ using ivec2 = vec2_impl<int32_t>;
using uvec2 = vec2_impl<uint32_t>;
} // namespace lt::math
template<typename T>
struct std::formatter<lt::math::vec2_impl<T>>
{
constexpr auto parse(std::format_parse_context &context)
{
return context.begin();
}
auto format(const lt::math::vec2_impl<T> &val, std::format_context &context) const
{
return std::format_to(context.out(), "{}, {}", val.x, val.y);
}
};

View file

@ -7,19 +7,29 @@ namespace lt::math {
template<typename T = float>
struct vec3_impl
{
vec3_impl(): x(), y(), z()
constexpr vec3_impl(): x(), y(), z()
{
}
explicit vec3_impl(T scalar): x(scalar), y(scalar), z(scalar)
constexpr explicit vec3_impl(T scalar): x(scalar), y(scalar), z(scalar)
{
}
vec3_impl(T x, T y, T z): x(x), y(y), z(z)
constexpr vec3_impl(T x, T y, T z): x(x), y(y), z(z)
{
}
[[nodiscard]] auto operator-(const vec3_impl<T> &other) const -> vec3_impl
[[nodiscard]] auto operator==(const vec3_impl<T> &other) const -> bool
{
return x == other.x && y == other.y && z == other.z;
}
[[nodiscard]] auto operator!=(const vec3_impl<T> &other) const -> bool
{
return !(*this == other);
}
[[nodiscard]] constexpr auto operator-(const vec3_impl<T> &other) const -> vec3_impl
{
return {
x - other.x,
@ -28,7 +38,7 @@ struct vec3_impl
};
}
[[nodiscard]] auto operator*(const vec3_impl<T> &other) const -> vec3_impl
[[nodiscard]] constexpr auto operator*(const vec3_impl<T> &other) const -> vec3_impl
{
return {
x * other.x,
@ -37,6 +47,12 @@ struct vec3_impl
};
}
friend auto operator<<(std::ostream &stream, vec3_impl<T> value) -> std::ostream &
{
stream << value.x << ", " << value.y << ", " << value.z;
return stream;
}
T x; // NOLINT
T y; // NOLINT
@ -51,3 +67,17 @@ using ivec3 = vec3_impl<int32_t>;
using uvec3 = vec3_impl<uint32_t>;
} // namespace lt::math
template<typename T>
struct std::formatter<lt::math::vec3_impl<T>>
{
constexpr auto parse(std::format_parse_context &context)
{
return context.begin();
}
auto format(const lt::math::vec3_impl<T> &val, std::format_context &context) const
{
return std::format_to(context.out(), "{}, {}, {}", val.x, val.y, val.z);
}
};

View file

@ -7,19 +7,29 @@ namespace lt::math {
template<typename T = float>
struct vec4_impl
{
vec4_impl(): x(), y(), z(), w()
constexpr vec4_impl(): x(), y(), z(), w()
{
}
explicit vec4_impl(T scalar): x(scalar), y(scalar), z(scalar), w(scalar)
constexpr explicit vec4_impl(T scalar): x(scalar), y(scalar), z(scalar), w(scalar)
{
}
vec4_impl(T x, T y, T z, T w): x(x), y(y), z(z), w(w)
constexpr vec4_impl(T x, T y, T z, T w): x(x), y(y), z(z), w(w)
{
}
[[nodiscard]] auto operator-(const vec4_impl<T> &other) const -> vec4_impl
[[nodiscard]] auto operator==(const vec4_impl<T> &other) const -> bool
{
return x == other.x && y == other.y && z == other.z && w == other.w;
}
[[nodiscard]] auto operator!=(const vec4_impl<T> &other) const -> bool
{
return !(*this == other);
}
[[nodiscard]] constexpr auto operator-(const vec4_impl<T> &other) const -> vec4_impl
{
return {
x - other.x,
@ -29,16 +39,22 @@ struct vec4_impl
};
}
[[nodiscard]] auto operator[](size_t idx) -> T &
[[nodiscard]] constexpr auto operator[](size_t idx) -> T &
{
return values[idx];
}
[[nodiscard]] auto operator[](size_t idx) const -> const T &
[[nodiscard]] constexpr auto operator[](size_t idx) const -> const T &
{
return values[idx];
}
friend auto operator<<(std::ostream &stream, vec4_impl<T> value) -> std::ostream &
{
stream << value.x << ", " << value.y << ", " << value.z << ", " << value.w;
return stream;
}
// NOLINTNEXTLINE
union
{
@ -76,3 +92,17 @@ using ivec4 = vec4_impl<int32_t>;
using uvec4 = vec4_impl<uint32_t>;
} // namespace lt::math
template<typename T>
struct std::formatter<lt::math::vec4_impl<T>>
{
constexpr auto parse(std::format_parse_context &context)
{
return context.begin();
}
auto format(const lt::math::vec4_impl<T> &val, std::format_context &context) const
{
return std::format_to(context.out(), "{}, {}, {}, {}", val.x, val.y, val.z, val.w);
}
};

View file

@ -4,7 +4,8 @@ target_link_libraries(
libmirror
INTERFACE
app
opengl::opengl
time
input
surface
)
@ -16,4 +17,4 @@ add_test_module(libmirror
)
add_executable_module(mirror entrypoint/mirror.cpp)
target_link_libraries(mirror PRIVATE libmirror)
target_link_libraries(mirror PRIVATE libmirror input)

View file

@ -1,15 +1,100 @@
#include <X11/keysym.h>
#include <app/application.hpp>
#include <app/entrypoint.hpp>
#include <app/system.hpp>
#include <ecs/entity.hpp>
#include <input/components.hpp>
#include <input/system.hpp>
#include <math/vec2.hpp>
#include <surface/events/keyboard.hpp>
#include <surface/events/surface.hpp>
#include <surface/system.hpp>
#include <time/timer.hpp>
namespace lt {
template<class... Ts>
struct overloads: Ts...
class MirrorSystem: public lt::app::ISystem
{
using Ts::operator()...;
public:
MirrorSystem(
Ref<ecs::Registry> registry,
lt::input::InputAction::Key quit_action_key,
std::array<lt::input::InputAction::Key, 4> debug_action_keys
)
: m_registry(std::move(registry))
, m_quit_action_key(quit_action_key)
, m_debug_action_keys(debug_action_keys)
{
using Surface = lt::surface::SurfaceComponent;
using Input = lt::input::InputComponent;
auto view = m_registry->get_entt_registry().view<Surface, Input>();
view.each([&](Surface &surface, Input &input) {});
}
auto tick() -> bool override
{
using Surface = lt::surface::SurfaceComponent;
using Input = lt::input::InputComponent;
static lt::Timer timer;
std::this_thread::sleep_for(std::chrono::milliseconds { 10 });
auto should_quit = false;
auto view = m_registry->get_entt_registry().view<Surface, Input>();
view.each([&](Surface &surface, Input &input) {
using State = lt::input::InputAction::State;
const auto &[x, y] = surface.get_position();
const auto &[width, height] = surface.get_resolution();
if (input.get_action(m_quit_action_key).state == State::active)
{
log_dbg("Quit triggered! BYE!");
should_quit = true;
}
if (input.get_action(m_debug_action_keys[0]).state == State::active)
{
log_dbg("Deubg action 1");
surface.push_request(surface::ModifyPositionRequest({ x + 5, y + 5 }));
}
if (input.get_action(m_debug_action_keys[1]).state == State::active)
{
log_dbg("Deubg action 2");
surface.push_request(surface::ModifyPositionRequest({ x - 5, y - 5 }));
}
if (input.get_action(m_debug_action_keys[2]).state == State::active)
{
log_dbg("Deubg action 3");
surface.push_request(surface::ModifyResolutionRequest({ width + 5, height + 5 }));
}
if (input.get_action(m_debug_action_keys[3]).state == State::active)
{
log_dbg("Deubg action 4");
surface.push_request(surface::ModifyResolutionRequest({ width - 5, height - 5 }));
}
});
timer.reset();
return should_quit;
}
void on_register() override
{
}
void on_unregister() override
{
}
private:
Ref<ecs::Registry> m_registry;
lt::input::InputAction::Key m_quit_action_key;
std::array<lt::input::InputAction::Key, 4> m_debug_action_keys {};
};
class Mirror: public app::Application
@ -20,53 +105,99 @@ public:
m_editor_registry = create_ref<ecs::Registry>();
setup_window_system();
setup_input_system();
register_systems();
}
m_window_system->add_event_listener(
m_window,
[&](const surface::SurfaceComponent::Event &event) {
const auto visitor = overloads {
[&](const lt::surface::KeyPressedEvent &event) {
std::cout << "key pressed: " << event.to_string() << std::endl;
void on_window_close()
{
log_inf("Window close requested...");
if (event.get_key() == 81)
{
unregister_system(m_window_system);
log_inf("Quitting...");
}
return true;
},
[](const auto &) { return false; },
};
return std::visit(visitor, event);
}
);
unregister_system(m_input_system);
unregister_system(m_surface_system);
unregister_system(m_mirror_system);
}
void setup_window_system()
{
using lt::input::InputComponent;
using lt::surface::SurfaceComponent;
m_window_system = create_ref<lt::surface::System>(m_editor_registry);
m_surface_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",
.resolution = { 800u, 600u },
.resolution = { 400u, 400u },
.vsync = true,
.visible = true,
});
auto &input = m_window.add_component<InputComponent>();
auto quit_action_key = input.add_action(
input::InputAction {
.name = "quit",
.trigger = input::Trigger { .mapped_keycode = XK_q },
}
);
auto debug_action_keys = std::array<lt::input::InputAction::Key, 4> {};
debug_action_keys[0] = input.add_action(
input::InputAction {
.name = "debug_1",
.trigger = input::Trigger { .mapped_keycode = XK_1 },
}
);
debug_action_keys[1] = input.add_action(
input::InputAction {
.name = "debug_2",
.trigger = input::Trigger { .mapped_keycode = XK_2 },
}
);
debug_action_keys[2] = input.add_action(
input::InputAction {
.name = "debug_3",
.trigger = input::Trigger { .mapped_keycode = XK_3 },
}
);
debug_action_keys[3] = input.add_action(
input::InputAction {
.name = "debug_4",
.trigger = input::Trigger { .mapped_keycode = XK_4 },
}
);
m_input_system = create_ref<input::System>(m_editor_registry);
m_mirror_system = create_ref<MirrorSystem>(
m_editor_registry,
quit_action_key,
debug_action_keys
);
}
void setup_input_system()
{
}
void register_systems()
{
register_system(m_window_system);
register_system(m_surface_system);
register_system(m_input_system);
register_system(m_mirror_system);
}
private:
Ref<ecs::Registry> m_editor_registry;
Ref<lt::surface::System> m_window_system;
Ref<lt::surface::System> m_surface_system;
Ref<lt::input::System> m_input_system;
Ref<MirrorSystem> m_mirror_system;
lt::ecs::Entity m_window;
};

View file

@ -0,0 +1,248 @@
---
Checks: "-*,
performance-unnecessary-value-param,
performance-unnecessary-copy-initialization,
performance-type-promotion-in-math-fn,
performance-trivially-destructible,
performance-noexcept-swap,
performance-noexcept-move-constructor,
performance-noexcept-destructor,
performance-no-int-to-ptr,
performance-no-automatic-move,
performance-move-constructor-init,
performance-move-const-arg,
performance-inefficient-vector-operation,
performance-inefficient-string-concatenation,
performance-inefficient-algorithm,
performance-implicit-conversion-in-loop,
performance-for-range-copy,
performance-faster-string-find,
performance-enum-size,
performance-avoid-endl,
readability-avoid-const-params-in-decls,
readability-avoid-nested-conditional-operator,
readability-avoid-return-with-void-value,
readability-avoid-unconditional-preprocessor-if,
readability-braces-around-statements,
readability-const-return-type,
readability-container-contains,
readability-container-data-pointdr,
readability-container-size-empty,
readability-delete-null-pointer,
readability-duplicate-include,
readability-else-after-return,
readability-inconsistent-declaration-parameter-name,
readability-isolate-declaration,
readability-make-member-function-const,
readability-misleading-indentation,
readability-misplaced-array-index,
readability-named-parameter,
readability-non-const-parameter,
readability-qualified-auto,
readability-redundant-access-specifiers,
readability-redundant-casting,
readability-redundant-control-flow,
readability-redundant-declaration,
readability-redundant-function-ptr-dereference,
readability-redundant-inline-specifier,
readability-redundant-member-init,
readability-redundant-preprocessor,
readability-redundant-smartptr-get,
readability-redundant-string-cstr,
readability-reference-to-constructed-temporary,
readability-simplify-boolean-expr,
readability-simplify-subscript-expr,
readability-static-accessed-through-instance,
readability-static-definition-in-anonymous-namespace,
readability-string-compare,
readability-suspicious-call-argument,
readability-uniqueptr-delete-release,
readability-use-anyofallof
readability-use-std-min-max,
readability-function-cognitive-complexity
readability-function-size
readability-identifier-naming
readability-identifier-length
readability-magic-numbers
modernize-avoid-bind,
modernize-avoid-c-arrays,
modernize-concat-nested-namespaces,
modernize-deprecated-headers,
modernize-deprecated-ios-base-aliases,
modernize-loop-convert,
modernize-macro-to-enum,
modernize-make-shared,
modernize-make-unique,
modernize-pass-by-value,
modernize-raw-string-literal,
modernize-redundant-void-arg,
modernize-replace-auto-ptr,
modernize-replace-disallow-copy-and-assign-macro,
modernize-replace-random-shuffle,
modernize-return-braced-init-list,
modernize-shrink-to-fit,
modernize-type-traits,
modernize-unary-static-assert,
modernize-use-auto,
modernize-use-bool-literals,
modernize-use-constraints,
modernize-use-default-member-init,
modernize-use-designated-initializers,
modernize-use-emplace,
modernize-use-equals-default,
modernize-use-equals-delete,
modernize-use-nodiscard,
modernize-use-noexcept,
modernize-use-nullptr,
modernize-use-override,
modernize-use-starts-ends-with,
modernize-use-std-numbers,
modernize-use-std-print,
modernize-use-transparent-functors,
modernize-use-uncaught-exceptions,
modernize-use-using
modernize-min-max-use-initializer-list,
cppcoreguidelines-avoid-capturing-lambda-coroutines,
cppcoreguidelines-avoid-const-or-ref-data-members,
cppcoreguidelines-avoid-do-while,
cppcoreguidelines-avoid-goto,
cppcoreguidelines-avoid-non-const-global-variables,
cppcoreguidelines-avoid-reference-coroutine-parameters,
cppcoreguidelines-init-variables,
cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-macro-usage,
cppcoreguidelines-misleading-capture-default-by-value,
cppcoreguidelines-missing-std-forward,
cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-no-malloc,
cppcoreguidelines-no-suspend-with-lock,
cppcoreguidelines-owning-memory,
cppcoreguidelines-prefer-member-initializer,
cppcoreguidelines-pro-bounds-array-to-pointer-decay,
cppcoreguidelines-pro-bounds-pointer-arithmetic,
cppcoreguidelines-pro-type-const-cast,
cppcoreguidelines-pro-type-cstyle-cast,
cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-pro-type-reinterpret-cast,
cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-pro-type-vararg,
cppcoreguidelines-rvalue-reference-param-not-moved,
cppcoreguidelines-slicing,
cppcoreguidelines-special-member-functions,
cppcoreguidelines-virtual-class-destructor,
bugprone-argument-comment,
bugprone-assert-side-effect,
bugprone-assignment-in-if-condition,
bugprone-bad-signal-to-kill-thread,
bugprone-bool-pointer-implicit-conversion,
bugprone-branch-clone,
bugprone-casting-through-void,
bugprone-chained-comparison,
bugprone-compare-pointer-to-member-virtual-function,
bugprone-copy-constructor-init,
bugprone-crtp-constructor-accessibility,
bugprone-dangling-handle,
bugprone-empty-catch,
bugprone-exception-escape,
bugprone-fold-init-type,
bugprone-forward-declaration-namespace,
bugprone-forwarding-reference-overload,
bugprone-implicit-widening-of-multiplication-result,
bugprone-inaccurate-erase,
bugprone-inc-dec-in-conditions,
bugprone-incorrect-enable-if,
bugprone-incorrect-roundings,
bugprone-infinite-loop,
bugprone-integer-division,
bugprone-lambda-function-name,
bugprone-macro-parentheses,
bugprone-macro-repeated-side-effects,
bugprone-misplaced-operator-in-strlen-in-alloc,
bugprone-misplaced-pointer-arithmetic-in-alloc,
bugprone-misplaced-widening-cast,
bugprone-move-forwarding-reference,
bugprone-multi-level-implicit-pointer-conversion,
bugprone-multiple-new-in-one-expression,
bugprone-multiple-statement-macro,
bugprone-no-escape,
bugprone-non-zero-enum-to-bool-conversion,
bugprone-not-null-terminated-result,
bugprone-optional-value-conversion,
bugprone-parent-virtual-call,
bugprone-posix-return,
bugprone-redundant-branch-condition,
bugprone-reserved-identifier,
bugprone-return-const-ref-from-parameter,
bugprone-shared-ptr-array-mismatch,
bugprone-signal-handler,
bugprone-signed-char-misuse,
bugprone-sizeof-container,
bugprone-sizeof-expression,
bugprone-spuriously-wake-up-functions,
bugprone-standalone-empty,
bugprone-string-constructor,
bugprone-string-integer-assignment,
bugprone-string-literal-with-embedded-nul,
bugprone-stringview-nullptr,
bugprone-suspicious-enum-usage,
bugprone-suspicious-include,
bugprone-suspicious-memory-comparison,
bugprone-suspicious-memset-usage,
bugprone-suspicious-missing-comma,
bugprone-suspicious-realloc-usage,
bugprone-suspicious-semicolon,
bugprone-suspicious-string-compare,
bugprone-suspicious-stringview-data-usage,
bugprone-swapped-arguments,
bugprone-switch-missing-default-case,
bugprone-terminating-continue,
bugprone-throw-keyword-missing,
bugprone-too-small-loop-variable,
bugprone-unchecked-optional-access,
bugprone-undefined-memory-manipulation,
bugprone-undelegated-constructor,
bugprone-unhandled-exception-at-new,
bugprone-unhandled-self-assignment,
bugprone-unique-ptr-array-mismatch,
bugprone-unsafe-functions,
bugprone-unused-local-non-trivial-variable,
bugprone-unused-raii,
bugprone-unused-return-value,
bugprone-use-after-move,
bugprone-virtual-near-miss,
concurrency-mt-unsafe,
concurrency-thread-canceltype-asynchronous,
misc-use-anonymous-namespace,
misc-unused-using-decls,
misc-unused-parameters,
misc-unused-alias-decls,
misc-uniqueptr-reset-release,
misc-unconventional-assign-operator,
misc-throw-by-value-catch-by-reference,
misc-static-assert,
misc-redundant-expression,
misc-non-private-member-variables-in-classes,
misc-non-copyable-objects,
misc-no-recursion,
misc-new-delete-overloads,
misc-misplaced-const,
misc-misleading-identifier,
misc-misleading-bidirectional,
misc-header-include-cycle,
misc-definitions-in-headers,
misc-coroutine-hostile-raii,
misc-const-correctness,
-hicpp-signed-bitwise,
hicpp-no-assembler,
hicpp-multiway-paths-covered,
hicpp-ignored-remove-result,
hicpp-exception-baseclass,
"

View file

@ -27,10 +27,7 @@ target_link_libraries(
renderer
PUBLIC camera
PUBLIC input
PUBLIC glad
PUBLIC logger
PUBLIC opengl::opengl
PUBLIC glfw
PUBLIC imgui
PUBLIC asset_parser
PUBLIC yaml-cpp::yaml-cpp

View file

@ -0,0 +1,14 @@
#include <ranges>
#include <renderer/system.hpp>
#include <test/test.hpp>
using namespace lt;
#include <renderer/backend.hpp>
using lt::test::Case;
using lt::test::Suite;
Suite raii = [] {
Case { "happy path won't throw" } = [] {
};
};

View file

@ -7,15 +7,9 @@
#include <renderer/renderer.hpp> // required for forward declaratio>
#include <ui/ui.hpp> // required for forward declaratio>
#define GLFW_EXPOSE_NATIVE_WIN32
#include <glfw/glfw3.h>
#include <glfw/glfw3native.h>
namespace lt {
dxGraphicsContext::dxGraphicsContext(GLFWwindow *windowHandle)
: m_window_handle(windowHandle)
, m_debug_interface(nullptr)
dxGraphicsContext::dxGraphicsContext(): m_window_handle(windowHandle), m_debug_interface(nullptr)
{
// set 'GraphicsAPI';
m_graphics_api = GraphicsAPI::DirectX;
@ -28,7 +22,7 @@ dxGraphicsContext::dxGraphicsContext(GLFWwindow *windowHandle)
setup_debug_interface();
}
void dxGraphicsContext::setup_device_and_swap_chain(GLFWwindow *windowHandle)
void dxGraphicsContext::setup_device_and_swap_chain()
{
auto context = std::static_pointer_cast<dxSharedContext>(m_shared_context);
@ -52,8 +46,7 @@ void dxGraphicsContext::setup_device_and_swap_chain(GLFWwindow *windowHandle)
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1u;
// #todo: don't handle Windows's window with glfw, create it yourself
sd.OutputWindow = static_cast<HWND>(glfwGetWin32Window(windowHandle));
sd.OutputWindow = {}; // ...
sd.Windowed = true;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

View file

@ -4,23 +4,19 @@
#include <renderer/graphics_context.hpp>
#include <wrl.h>
struct GLFWwindow;
namespace lt {
class dxGraphicsContext: public GraphicsContext
{
public:
dxGraphicsContext(GLFWwindow *windowHandle);
dxGraphicsContext();
virtual void log_debug_data() override;
private:
GLFWwindow *m_window_handle;
Microsoft::WRL::ComPtr<ID3D11Debug> m_debug_interface;
void setup_device_and_swap_chain(GLFWwindow *windowHandle);
void setup_device_and_swap_chain();
void setup_render_targets();

View file

@ -1,66 +0,0 @@
#include <input/key_codes.hpp>
#include <renderer/dx/shared_context.hpp>
#include <renderer/dx/user_interface.hpp>
#define GLFW_EXPOSE_NATIVE_WIN32
#include <backends/imgui_impl_dx11.h>
#include <backends/imgui_impl_win32.h>
#include <glfw/glfw3.h>
#include <glfw/glfw3native.h>
#include <imgui.h>
namespace lt {
void dxUserInterface::platform_implementation(
GLFWwindow *windowHandle,
Ref<SharedContext> sharedContext
)
{
auto &io = ImGui::GetIO();
auto context = std::dynamic_pointer_cast<dxSharedContext>(sharedContext);
ImGui_ImplWin32_Init(glfwGetWin32Window(windowHandle));
ImGui_ImplDX11_Init(context->get_device().Get(), context->get_device_context().Get());
}
dxUserInterface::~dxUserInterface()
{
// #todo: handle this in a better way
auto &io = ImGui::GetIO();
if (io.IniFilename == "default_gui_layout.ini")
io.IniFilename = "user_gui_layout.ini";
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
}
void dxUserInterface::begin()
{
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
}
void dxUserInterface::end()
{
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
void dxUserInterface::log_debug_data()
{
// #todo: improve
log_inf("________________________________________");
log_inf("UserInterface::");
log_inf(" API : ImGui");
log_inf(" Version: {}", ImGui::GetVersion());
log_inf(" GraphicsAPI : DirectX");
log_inf("________________________________________");
}
} // namespace lt

View file

@ -4,8 +4,6 @@
#include <ui/ui.hpp>
#include <wrl.h>
struct GLFWwindow;
namespace lt {
class dxSharedContext;
@ -17,10 +15,7 @@ public:
~dxUserInterface();
void platform_implementation(
GLFWwindow *windowHandle,
Ref<SharedContext> sharedContext
) override;
void platform_implementation(Ref<SharedContext> sharedContext) override;
void begin() override;

View file

@ -1,4 +1,3 @@
#include <glad/gl.h>
#include <renderer/gl/blender.hpp>
namespace lt {

View file

@ -1,5 +1,4 @@
#include <cstddef>
#include <glad/gl.h>
#include <logger/logger.hpp>
#include <renderer/gl/buffers.hpp>

View file

@ -1,4 +1,3 @@
#include <glad/gl.h>
#include <renderer/gl/framebuffers.hpp>
namespace lt {

View file

@ -1,4 +1,3 @@
#include <glad/gl.h>
#include <input/events/window.hpp>
#include <renderer/blender.hpp> // required for forward declaratio>
#include <renderer/buffers.hpp> // required for forward declaratio>
@ -6,18 +5,11 @@
#include <renderer/render_command.hpp> // required for forward declaratio>
#include <renderer/renderer.hpp> // required for forward declaratio>
#ifndef STOP_FUCKING_ORDERING_THESE_THE_WRONG_WAY_CLANG_FORMAT____
#include <GLFW/glfw3.h>
#endif
namespace lt {
glGraphicsContext::glGraphicsContext(GLFWwindow *windowHandle): m_window_handle(windowHandle)
glGraphicsContext::glGraphicsContext()
{
m_graphics_api = GraphicsAPI::OpenGL;
glfwMakeContextCurrent(windowHandle);
ensure(gladLoadGL(glfwGetProcAddress), "Failed to initialize opengl (glad)");
set_debug_message_callback();
}

View file

@ -3,20 +3,16 @@
#include <renderer/graphics_context.hpp>
struct GLFWwindow;
namespace lt {
class glGraphicsContext: public GraphicsContext
{
public:
glGraphicsContext(GLFWwindow *windowHandle);
glGraphicsContext();
void log_debug_data() override;
private:
GLFWwindow *m_window_handle;
void set_debug_message_callback();
};

View file

@ -1,18 +1,13 @@
#include <glad/gl.h>
#include <renderer/gl/render_command.hpp>
#ifndef DONT_FUCKING_ORDER_THESSE_PLEASE_FOR_THE_LOVE_OF_GOD_CLANG_FORMAT
#include <GLFW/glfw3.h>
#endif
namespace lt {
glRenderCommand::glRenderCommand(GLFWwindow *windowHandle): m_window_handle(windowHandle)
glRenderCommand::glRenderCommand(): m_window_handle(windowHandle)
{
}
void glRenderCommand::swap_buffers()
{
glfwSwapBuffers(m_window_handle);
}
void glRenderCommand::clear_back_buffer(const math::vec4 &clearColor)

View file

@ -3,14 +3,12 @@
#include <math/vec4.hpp>
#include <renderer/render_command.hpp>
struct GLFWwindow;
namespace lt {
class glRenderCommand: public RenderCommand
{
public:
glRenderCommand(GLFWwindow *windowHandle);
glRenderCommand();
void swap_buffers() override;
@ -28,9 +26,6 @@ public:
unsigned int width,
unsigned int height
) override;
private:
GLFWwindow *m_window_handle;
};
} // namespace lt

View file

@ -1,6 +1,4 @@
#include <asset_parser/assets/text.hpp>
#include <glad/gl.h>
#include <renderer/gl/shader.hpp>
namespace lt {

View file

@ -1,5 +1,4 @@
#include <asset_parser/assets/texture.hpp>
#include <glad/gl.h>
#include <lt_debug/assertions.hpp>
#include <renderer/gl/texture.hpp>

View file

@ -3,8 +3,6 @@
#include <ui/ui.hpp>
struct GLFWwindow;
namespace lt {
class glUserInterface: public UserInterface
@ -14,19 +12,13 @@ public:
~glUserInterface() override;
void platform_implementation(
GLFWwindow *windowHandle,
Ref<SharedContext> sharedContext
) override;
void platform_implementation(Ref<SharedContext> sharedContext) override;
void begin() override;
void end() override;
void log_debug_data() override;
private:
GLFWwindow *m_window_handle {};
};
} // namespace lt

View file

@ -1,4 +1,3 @@
#include <glad/gl.h>
#include <lt_debug/assertions.hpp>
#include <renderer/gl/buffers.hpp>
#include <renderer/gl/vertex_layout.hpp>

View file

@ -12,7 +12,7 @@ GraphicsContext *GraphicsContext::s_context = nullptr;
GraphicsContext::~GraphicsContext() = default;
auto GraphicsContext::create(GraphicsAPI api, GLFWwindow *window_handle) -> Scope<GraphicsContext>
auto GraphicsContext::create(GraphicsAPI api) -> Scope<GraphicsContext>
{
delete s_context;

View file

@ -11,12 +11,11 @@
namespace lt {
auto RenderCommand::create(GLFWwindow *windowHandle, const Ref<SharedContext> & /*sharedContext*/)
-> Scope<RenderCommand>
auto RenderCommand::create(const Ref<SharedContext> & /*sharedContext*/) -> Scope<RenderCommand>
{
switch (GraphicsContext::get_graphics_api())
{
case GraphicsAPI::OpenGL: return create_scope<glRenderCommand>(windowHandle);
case GraphicsAPI::OpenGL: return create_scope<glRenderCommand>();
case GraphicsAPI::DirectX:
lt_win(

View file

@ -16,11 +16,7 @@ namespace lt {
Renderer *Renderer::s_context = nullptr;
Renderer::Renderer(
GLFWwindow *window_handle,
const Ref<SharedContext> &shared_context,
CreateInfo create_info
)
Renderer::Renderer(const Ref<SharedContext> &shared_context, CreateInfo create_info)
: m_quad_renderer(
create_scope<QuadRendererProgram>(
LT_MAX_QUAD_RENDERER_VERTICES,
@ -66,15 +62,9 @@ Renderer::~Renderer() // NOLINT
{
}
auto Renderer::create(
GLFWwindow *windowHandle,
Ref<SharedContext> sharedContext,
CreateInfo create_info
) -> Scope<Renderer>
auto Renderer::create(Ref<SharedContext> sharedContext, CreateInfo create_info) -> Scope<Renderer>
{
return make_scope<Renderer>(
new Renderer(windowHandle, std::move(sharedContext), std::move(create_info))
);
return make_scope<Renderer>(new Renderer(std::move(sharedContext), std::move(create_info)));
}
void Renderer::on_window_resize(const WindowResizedEvent &event)

View file

@ -6,7 +6,6 @@ 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;

View file

@ -13,11 +13,8 @@ Suite raii = [] {
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>(),
} };
};
@ -25,14 +22,12 @@ Suite raii = [] {
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>(),
} };
});
@ -42,7 +37,6 @@ Suite raii = [] {
for (auto idx : std::views::iota(0, 100'001))
{
std::ignore = System { {
.glfw_window_handle = window,
.registry = create_ref<ecs::Registry>(),
} };
}

View file

@ -1,7 +1,5 @@
#pragma once
struct GLFWwindow;
namespace lt {
class SharedContext;
@ -19,12 +17,7 @@ enum class GraphicsAPI
class GraphicsContext
{
public:
static auto create(
GraphicsAPI api,
GLFWwindow *window_handle
) -> Scope<GraphicsContext>;
static auto create(GraphicsAPI api) -> Scope<GraphicsContext>;
GraphicsContext(const GraphicsContext &) = delete;
GraphicsContext &operator=(const GraphicsContext &) = delete;

View file

@ -2,8 +2,6 @@
#include <math/vec4.hpp>
struct GLFWwindow;
namespace lt {
class SharedContext;
@ -11,8 +9,7 @@ class SharedContext;
class RenderCommand
{
public:
static auto create(GLFWwindow *windowHandle, const Ref<SharedContext> &sharedContext)
-> Scope<RenderCommand>;
static auto create(const Ref<SharedContext> &sharedContext) -> Scope<RenderCommand>;
RenderCommand(const RenderCommand &) = delete;

View file

@ -13,8 +13,6 @@
#define LT_MAX_TEXTURE_RENDERER_VERTICES (1028u * 4u)
#define LT_MAX_TINTED_TEXTURE_RENDERER_VERTICES (1028u * 4u)
struct GLFWwindow;
namespace lt {
class ConstantBuffer;
@ -42,11 +40,7 @@ public:
Ref<Shader> tinted_texture_renderer_shader;
};
static auto create(
GLFWwindow *windowHandle,
Ref<SharedContext> sharedContext,
CreateInfo create_info
) -> Scope<Renderer>;
static auto create(Ref<SharedContext> sharedContext, CreateInfo create_info) -> Scope<Renderer>;
static void draw_quad(
const math::vec3 &position,
@ -134,11 +128,7 @@ private:
bool m_should_clear_backbuffer { false };
Renderer(
GLFWwindow *window_handle,
const Ref<SharedContext> &shared_context,
CreateInfo create_info
);
Renderer(const Ref<SharedContext> &shared_context, CreateInfo create_info);
void draw_quad_impl(
const math::vec3 &position,

View file

@ -3,8 +3,6 @@
#include <base/base.hpp>
#include <ecs/scene.hpp>
struct GLFWwindow;
namespace lt::renderer {
/** The system for putting gore on your display
@ -28,8 +26,6 @@ public:
/** The requirements for this system to initialize. */
struct InitRequirements
{
GLFWwindow *glfw_window_handle;
Ref<ecs::Registry> registry;
};

View file

@ -3,7 +3,6 @@
namespace Assets {
class TextureAsset;
}
namespace lt {

View file

@ -1,14 +1,16 @@
if (NOT WIN32)
add_library_module(surface linux/system.cpp)
target_link_libraries(surface PRIVATE X11)
else(WIN32)
add_library_module(surface windows/system.cpp)
endif()
target_link_libraries(surface PUBLIC
ecs
app
PRIVATE
glfw
logger
lt_debug
)

View file

@ -1,143 +1,42 @@
#define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <ecs/components.hpp>
#include <surface/components.hpp>
#include <surface/events/mouse.hpp>
#include <surface/requests/surface.hpp>
#include <surface/system.hpp>
//
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/keysymdef.h>
namespace lt::surface {
// This class is to ensure glfwInit/glfwTerminate is called only once and exactly when needed during
// entire application runtime
class GlfwSingleton
template<class... Ts>
struct overloads: Ts...
{
public:
[[nodiscard]] static auto get() -> GlfwSingleton &
{
static auto instance = GlfwSingleton {};
return instance;
}
GlfwSingleton(GlfwSingleton &&) = delete;
GlfwSingleton(const GlfwSingleton &) = delete;
auto operator=(GlfwSingleton &&) -> GlfwSingleton & = delete;
auto operator=(const GlfwSingleton &) -> GlfwSingleton & = delete;
private:
GlfwSingleton()
{
log_inf("Initializing glfw...");
ensure(glfwInit(), "Failed to initialize 'glfw'");
log_inf("...Finished");
}
~GlfwSingleton()
{
log_inf("Terminating glfw...");
glfwTerminate();
log_inf("...Finished");
}
using Ts::operator()...;
};
void glfw_error_callbac(int32_t code, const char *description)
{
log_err("GLFW ERROR: {} -> {}", code, description);
}
void ensure_component_sanity(const SurfaceComponent &component);
void handle_event(GLFWwindow *window, const SurfaceComponent::Event &event)
{
auto &callbacks = *static_cast<std::vector<SurfaceComponent::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 });
});
}
constexpr auto all_events_mask = KeyPressMask | //
KeyReleaseMask | //
ButtonPressMask | //
ButtonReleaseMask | //
EnterWindowMask | //
LeaveWindowMask | //
PointerMotionMask | //
KeymapStateMask | //
ExposureMask | //
VisibilityChangeMask | //
StructureNotifyMask | //
FocusChangeMask | //
ColormapChangeMask | //
OwnerGrabButtonMask;
System::System(Ref<ecs::Registry> registry): m_registry(std::move(registry))
{
glfwSetErrorCallback(&glfw_error_callbac);
// will call `glfwInit()` only the first time
auto &glfw_instance = GlfwSingleton::get();
ensure(m_registry, "Failed to initialize surface system: null registry");
ensure(
@ -178,29 +77,94 @@ System::~System()
});
}
void System::on_register()
{
}
void System::on_unregister()
{
}
void System::on_surface_construct(entt::registry &registry, entt::entity entity)
{
try
{
auto &surface = registry.get<SurfaceComponent>(entity);
const auto &resolution = surface.get_resolution();
const auto &position = surface.get_position();
ensure_component_sanity(surface);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// TODO(Light): refactor "environment" into standalone module
// NOLINTNEXTLINE(concurrency-mt-unsafe)
auto *display_env = std::getenv("DISPLAY");
ensure(display_env != nullptr, "DISPLAY env var not found!");
surface.m_glfw_handle = glfwCreateWindow(
static_cast<int>(surface.get_resolution().x),
static_cast<int>(surface.get_resolution().y),
surface.get_title().begin(),
nullptr,
nullptr
auto *display = XOpenDisplay(display_env);
auto root_window = XDefaultRootWindow(display);
auto border_width = 0;
auto depth = 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
);
ensure(surface.m_glfw_handle, "Failed to create 'GLFWwindow'");
surface.m_native_data.display = display;
surface.m_native_data.window = main_window;
glfwSetWindowUserPointer(surface.m_glfw_handle, &surface.m_event_callbacks);
surface.m_native_handle = glfwGetX11Window(surface.m_glfw_handle);
bind_glfw_events(surface.m_glfw_handle);
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
long hints[5] = { 2, 0, 0, 0, 0 };
Atom motif_hints = XInternAtom(display, "_MOTIF_WM_HINTS", False);
XChangeProperty(
display,
surface.m_native_data.window,
motif_hints,
motif_hints,
32,
PropModeReplace,
(unsigned char *)&hints,
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 (...)
{
@ -212,82 +176,213 @@ void System::on_surface_construct(entt::registry &registry, entt::entity entity)
void System::on_surface_update(entt::registry &registry, entt::entity entity)
{
auto &surface = registry.get<SurfaceComponent>(entity);
glfwSetWindowUserPointer(surface.m_glfw_handle, &surface.m_event_callbacks);
}
void System::on_surface_destroy(entt::registry &registry, entt::entity entity)
{
auto &surface = registry.get<SurfaceComponent>(entity);
if (surface.m_glfw_handle)
const auto &[display, window, _] = registry.get<SurfaceComponent>(entity).get_native_data();
if (!display)
{
glfwDestroyWindow(surface.m_glfw_handle);
log_wrn("Surface component destroyed with null display");
return;
}
XDestroyWindow(display, window);
}
void System::handle_events(SurfaceComponent &surface)
{
auto &queue = surface.m_event_queue;
queue.clear();
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<uint32_t>(XLookupKeysym(&event.xkey, 0))
);
break;
}
case KeyRelease:
{
queue.emplace_back<KeyReleasedEvent>(
static_cast<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<uint32_t>(new_width),
static_cast<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;
}
case Expose: break;
case GraphicsExpose: break;
case NoExpose: break;
case CirculateRequest: break;
case ConfigureRequest: break;
case MapRequest: break;
case ResizeRequest: break;
case CirculateNotify: break;
case CreateNotify: break;
case DestroyNotify: break;
case GravityNotify: break;
case MapNotify: break;
case MappingNotify: break;
case ReparentNotify: break;
case UnmapNotify: break;
case VisibilityNotify: break;
case ColormapNotify: break;
case PropertyNotify: break;
case SelectionClear: break;
case SelectionNotify: break;
case SelectionRequest: break;
default: log_inf("Unknown X Event");
}
}
}
void System::set_title(ecs::Entity entity, std::string_view new_title)
void System::handle_requests(SurfaceComponent &surface)
{
auto &surface = entity.get_component<SurfaceComponent>();
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_err("Unknown surface request"); },
};
surface.m_title = new_title;
glfwSetWindowTitle(surface.m_glfw_handle, surface.m_title.c_str());
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;
const auto &[display, window, _] = surface.get_native_data();
const auto &[width, height] = request.resolution;
XResizeWindow(display, window, width, height);
}
void System::modify_position(SurfaceComponent &surface, const ModifyPositionRequest &request)
{
surface.m_position = request.position;
const auto &[display, window, _] = surface.get_native_data();
const auto &[x, y] = request.position;
XMoveWindow(display, window, static_cast<int>(x), static_cast<int>(y));
}
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);
}
}
auto System::tick() -> bool
{
m_registry->view<SurfaceComponent>().each([](SurfaceComponent &surface) {
glfwSwapBuffers(surface.m_glfw_handle);
m_registry->view<SurfaceComponent>().each([this](SurfaceComponent &surface) {
handle_requests(surface);
handle_events(surface);
});
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_resolution = 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);
}
}
void System::add_event_listener(
ecs::Entity surface_entity,
SurfaceComponent::EventCallback callback
)
{
auto &surface = surface_entity.get_component<SurfaceComponent>();
surface.m_event_callbacks.emplace_back(std::move(callback));
}
void System::ensure_component_sanity(const SurfaceComponent &component)
void ensure_component_sanity(const SurfaceComponent &component)
{
auto [width, height] = component.get_resolution();

View file

@ -1,11 +1,13 @@
#include <ecs/entity.hpp>
#include <ecs/scene.hpp>
#include <surface/components.hpp>
#include <surface/system.hpp>
#include <test/fuzz.hpp>
#include <test/test.hpp>
namespace lt::surface {
enum class Action : uint8_t
enum class FuzzAction : uint8_t
{
create_entity,
@ -13,7 +15,22 @@ enum class Action : uint8_t
destroy_surface_component,
tick,
push_request,
push_event,
tick_system,
count,
};
enum class EventType : uint8_t
{
Closed,
Moved,
Resized,
LostFocus,
GainFocus,
};
void create_surface_component(test::FuzzDataProvider &provider, ecs::Registry &registry)
@ -55,6 +72,14 @@ void remove_surface_component(ecs::Registry &registry)
}
}
void push_request(ecs::Registry &registry)
{
}
void push_event(ecs::Registry &registry)
{
}
void check_invariants()
{
}
@ -67,9 +92,14 @@ test::FuzzHarness harness = [](const uint8_t *data, size_t size) {
while (auto action = provider.consume<uint8_t>())
{
switch (static_cast<Action>(action.value()))
if (*action > std::to_underlying(FuzzAction::count))
{
case Action::create_entity:
*action = *action % std::to_underlying(FuzzAction::count);
}
switch (static_cast<FuzzAction>(action.value()))
{
case FuzzAction::create_entity:
{
const auto length = std::min(provider.consume<uint32_t>().value_or(16), 255u);
const auto tag = provider.consume_string(length).value_or("");
@ -77,17 +107,36 @@ test::FuzzHarness harness = [](const uint8_t *data, size_t size) {
break;
}
case Action::create_surface_component:
case FuzzAction::create_surface_component:
{
create_surface_component(provider, *registry);
break;
}
case Action::destroy_surface_component:
case FuzzAction::destroy_surface_component:
{
remove_surface_component(*registry);
break;
}
case Action::tick:
case FuzzAction::push_event:
{
const auto view = registry->get_entt_registry().view<SurfaceComponent>();
if (!view->empty())
{
view.each([&](auto entity, SurfaceComponent &surface) {
provider.consume<uint8_t>().value_or(0);
});
registry->get_entt_registry().remove<SurfaceComponent>(*view.begin());
}
break;
}
case FuzzAction::push_request:
{
break;
}
case FuzzAction::tick_system:
{
system.tick();
break;

View file

@ -1,3 +1,6 @@
#include <ecs/entity.hpp>
#include <surface/components.hpp>
#include <surface/requests/surface.hpp>
#include <surface/system.hpp>
#include <test/test.hpp>
@ -18,6 +21,13 @@ constexpr auto height = 600u;
constexpr auto vsync = true;
constexpr auto visible = false;
template<class... Ts>
struct overloads: Ts...
{
using Ts::operator()...;
};
class Fixture
{
public:
@ -41,7 +51,11 @@ public:
void check_values(const SurfaceComponent &component)
{
expect_ne(std::get<SurfaceComponent::X11NativeHandle>(component.get_native_handle()), 0);
#ifdef LIGHT_PLATFORM_LINUX
expect_not_nullptr(component.get_native_data().display);
expect_ne(component.get_native_data().window, 0);
#endif
expect_eq(component.get_resolution().x, width);
expect_eq(component.get_resolution().y, height);
expect_eq(component.get_title(), title);
@ -61,9 +75,7 @@ Suite raii = [] {
Case { "many won't freeze/throw" } = [] {
auto fixture = Fixture {};
/* range is small since glfw init/terminate is slow. */
for (auto idx : std::views::iota(0, 100))
for (auto idx : std::views::iota(0, 250))
{
ignore = System { fixture.registry() };
}
@ -74,7 +86,7 @@ Suite raii = [] {
auto fixture = Fixture {};
fixture.add_surface_component();
expect_throw([&] { ignore = System { { fixture.registry() } }; });
expect_throw([&] { ignore = System { fixture.registry() }; });
};
Case { "post construct has correct state" } = [] {
@ -107,8 +119,8 @@ Suite system_events = [] {
Case { "on_unregister won't throw" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
system.on_register();
system.on_register();
system.on_unregister();
expect_eq(fixture.registry()->view<SurfaceComponent>().size(), 0);
};
@ -185,14 +197,73 @@ Suite tick = [] {
fixture.add_surface_component();
system.tick();
};
};
Case { "ticking on chaotic registry won't throw" } = [] {
Suite tick_handles_events = [] {
Case { "ticking clears previous tick's events" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
auto &surface = fixture.add_surface_component();
// flush window-creation events
system.tick();
expect_eq(surface.peek_events().size(), 0);
surface.push_event(surface::MovedEvent({}, {}));
expect_eq(surface.peek_events().size(), 1);
surface.push_event(surface::ButtonPressedEvent({}));
expect_eq(surface.peek_events().size(), 2);
system.tick();
expect_eq(surface.peek_events().size(), 0);
};
};
Suite property_setters = [] {
Suite tick_handles_requests = [] {
Case { "ticking clears requests" } = [] {
auto fixture = Fixture {};
auto system = System { fixture.registry() };
auto &surface = fixture.add_surface_component();
};
constexpr auto title = "ABC";
constexpr auto position = math::ivec2 { 50, 50 };
constexpr auto resolution = math::uvec2 { 50, 50 };
Suite listeners = [] {
expect_eq(surface.peek_requests().size(), 0);
surface.push_request(surface::ModifyVisibilityRequest(true));
expect_eq(surface.peek_requests().size(), 1);
system.tick();
expect_eq(surface.peek_requests().size(), 0);
surface.push_request(surface::ModifyTitleRequest(title));
expect_eq(surface.peek_requests().size(), 1);
surface.push_request(surface::ModifyResolutionRequest(resolution));
surface.push_request(surface::ModifyPositionRequest(position));
expect_eq(surface.peek_requests().size(), 1 + 2);
surface.push_request(surface::ModifyVisibilityRequest(false));
surface.push_request(surface::ModifyVisibilityRequest(true));
surface.push_request(surface::ModifyVisibilityRequest(false));
expect_eq(surface.peek_requests().size(), 1 + 2 + 3);
system.tick();
expect_eq(surface.peek_requests().size(), 0);
expect_eq(surface.get_title(), title);
expect_eq(surface.get_position(), position);
expect_eq(surface.get_resolution(), resolution);
log_dbg("EVENT COUNT: {}", surface.peek_events().size());
for (const auto &event : surface.peek_events())
{
const auto visitor = overloads {
[&](auto event) { log_dbg("event: {}", event.to_string()); },
};
std::visit(visitor, event);
}
};
};

View file

@ -1,143 +1,12 @@
#define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <surface/system.hpp>
#include <utility>
namespace lt::surface {
// This class is to ensure glfwInit/glfwTerminate is called only once and exactly when needed during
// entire application runtime
class GlfwSingleton
System::System(Ref<ecs::Registry> registry, Ref<app::EventMediator> event_mediator)
: m_registry(std::move(registry))
, m_event_mediator(std::move(event_mediator))
{
public:
[[nodiscard]] static auto get() -> GlfwSingleton &
{
static auto instance = GlfwSingleton {};
return instance;
}
GlfwSingleton(GlfwSingleton &&) = delete;
GlfwSingleton(const GlfwSingleton &) = delete;
auto operator=(GlfwSingleton &&) -> GlfwSingleton & = delete;
auto operator=(const GlfwSingleton &) -> GlfwSingleton & = delete;
private:
GlfwSingleton()
{
log_inf("Initializing glfw...");
ensure(glfwInit(), "Failed to initialize 'glfw'");
log_inf("...Finished");
}
~GlfwSingleton()
{
log_inf("Terminating glfw...");
glfwTerminate();
log_inf("...Finished");
}
};
void glfw_error_callbac(int32_t code, const char *description)
{
log_err("GLFW ERROR: {} -> {}", code, description);
}
void handle_event(GLFWwindow *window, const SurfaceComponent::Event &event)
{
auto &callbacks = *static_cast<std::vector<SurfaceComponent::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 });
});
}
System::System(Ref<ecs::Registry> registry): m_registry(std::move(registry))
{
glfwSetErrorCallback(&glfw_error_callbac);
// will call `glfwInit()` only the first time
auto &glfw_instance = GlfwSingleton::get();
ensure(m_registry, "Failed to initialize surface system: null registry");
ensure(
@ -183,24 +52,9 @@ void System::on_surface_construct(entt::registry &registry, entt::entity entity)
try
{
auto &surface = registry.get<SurfaceComponent>(entity);
const auto &resolution = surface.get_resolution();
const auto &position = surface.get_position();
ensure_component_sanity(surface);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
surface.m_glfw_handle = glfwCreateWindow(
static_cast<int>(surface.get_resolution().x),
static_cast<int>(surface.get_resolution().y),
surface.get_title().begin(),
nullptr,
nullptr
);
ensure(surface.m_glfw_handle, "Failed to create 'GLFWwindow'");
glfwSetWindowUserPointer(surface.m_glfw_handle, &surface.m_event_callbacks);
surface.m_native_handle = glfwGetX11Window(surface.m_glfw_handle);
bind_glfw_events(surface.m_glfw_handle);
}
catch (...)
{
@ -212,17 +66,11 @@ void System::on_surface_construct(entt::registry &registry, entt::entity entity)
void System::on_surface_update(entt::registry &registry, entt::entity entity)
{
auto &surface = registry.get<SurfaceComponent>(entity);
glfwSetWindowUserPointer(surface.m_glfw_handle, &surface.m_event_callbacks);
}
void System::on_surface_destroy(entt::registry &registry, entt::entity entity)
{
auto &surface = registry.get<SurfaceComponent>(entity);
if (surface.m_glfw_handle)
{
glfwDestroyWindow(surface.m_glfw_handle);
}
}
void System::set_title(ecs::Entity entity, std::string_view new_title)
@ -230,16 +78,10 @@ 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.c_str());
}
auto System::tick() -> bool
{
m_registry->view<SurfaceComponent>().each([](SurfaceComponent &surface) {
glfwSwapBuffers(surface.m_glfw_handle);
});
glfwPollEvents();
return false;
}
@ -247,20 +89,12 @@ 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;
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)
@ -270,23 +104,12 @@ void System::set_visibility(ecs::Entity surface_entity, bool visible)
if (visible)
{
glfwShowWindow(surface.m_glfw_handle);
}
else
{
glfwHideWindow(surface.m_glfw_handle);
}
}
void System::add_event_listener(
ecs::Entity surface_entity,
SurfaceComponent::EventCallback callback
)
{
auto &surface = surface_entity.get_component<SurfaceComponent>();
surface.m_event_callbacks.emplace_back(std::move(callback));
}
void System::ensure_component_sanity(const SurfaceComponent &component)
{
auto [width, height] = component.get_resolution();

View file

@ -4,16 +4,14 @@
#include <surface/events/keyboard.hpp>
#include <surface/events/mouse.hpp>
#include <surface/events/surface.hpp>
#include <surface/requests/surface.hpp>
#include <variant>
struct GLFWwindow;
typedef struct _XDisplay Display;
namespace lt::surface {
/** Represents a platform's surface (eg. a Window).
*
* @note Read-only component, should only be modified through a system.
*/
/** Represents a platform's surface (eg. a Window). */
class SurfaceComponent
{
public:
@ -29,23 +27,27 @@ public:
// keyboard events
KeyPressedEvent,
KeyRepeatEvent,
KeyReleasedEvent,
KeySetCharEvent,
// mouse events
MouseMovedEvent,
WheelScrolledEvent,
ButtonPressedEvent,
ButtonReleasedEvent>;
using EventCallback = std::function<bool(const Event &)>;
using Request = std::variant<
ModifyTitleRequest,
ModifyResolutionRequest,
ModifyPositionRequest,
ModifyVisibilityRequest>;
using WindowsNativeHandle = void *;
using X11NativeHandle = unsigned long;
using NativeHandle = std::variant<WindowsNativeHandle, X11NativeHandle>;
#ifdef LIGHT_PLATFORM_LINUX
struct NativeData
{
Display *display;
uint32_t window;
unsigned long wm_delete_message;
};
#endif
static constexpr auto max_dimension = 4096;
@ -67,6 +69,7 @@ public:
, m_resolution(info.resolution)
, m_vsync(info.vsync)
, m_visible(info.visible)
, m_native_data({})
{
}
@ -80,6 +83,11 @@ public:
return m_resolution;
}
[[nodiscard]] auto get_position() const -> const math::ivec2 &
{
return m_position;
}
[[nodiscard]] auto is_vsync() const -> bool
{
return m_vsync;
@ -90,30 +98,48 @@ public:
return m_visible;
}
[[nodiscard]] auto get_native_handle() const -> NativeHandle
[[nodiscard]] auto get_native_data() const -> const NativeData &
{
return m_native_handle;
return m_native_data;
}
[[nodiscard]] auto peek_events() const -> const std::vector<Event> &
{
return m_event_queue;
}
[[nodiscard]] auto peek_requests() const -> const std::vector<Request> &
{
return m_requests;
};
void push_request(const Request &request)
{
m_requests.emplace_back(request);
}
/** @note: Only the surface system and tests should push events */
void push_event(const Event &event)
{
m_event_queue.emplace_back(event);
}
private:
[[nodiscard]] auto get_glfw_handle() const -> GLFWwindow *
{
return m_glfw_handle;
}
std::string m_title;
math::uvec2 m_resolution;
math::ivec2 m_position;
bool m_vsync;
bool m_visible;
NativeHandle m_native_handle;
NativeData m_native_data;
GLFWwindow *m_glfw_handle {};
std::vector<Event> m_event_queue;
std::vector<EventCallback> m_event_callbacks;
std::vector<Request> m_requests;
};
} // namespace lt::surface

View file

@ -7,11 +7,11 @@ namespace lt::surface {
class KeyPressedEvent
{
public:
KeyPressedEvent(int32_t key): m_key(key)
KeyPressedEvent(uint32_t key): m_key(key)
{
}
[[nodiscard]] auto get_key() const -> int32_t
[[nodiscard]] auto get_key() const -> uint32_t
{
return m_key;
}
@ -22,7 +22,7 @@ public:
}
private:
int32_t m_key;
uint32_t m_key;
};
class KeyRepeatEvent
@ -32,7 +32,7 @@ public:
{
}
[[nodiscard]] auto get_key() const -> int32_t
[[nodiscard]] auto get_key() const -> uint32_t
{
return m_key;
}
@ -43,17 +43,17 @@ public:
}
private:
int32_t m_key;
uint32_t m_key;
};
class KeyReleasedEvent
{
public:
KeyReleasedEvent(int key): m_key(key)
KeyReleasedEvent(uint32_t key): m_key(key)
{
}
[[nodiscard]] auto get_key() const -> int32_t
[[nodiscard]] auto get_key() const -> uint32_t
{
return m_key;
}
@ -64,7 +64,7 @@ public:
}
private:
int32_t m_key;
uint32_t m_key;
};
class KeySetCharEvent

View file

@ -0,0 +1,27 @@
#pragma once
#include <math/vec2.hpp>
namespace lt::surface {
struct ModifyTitleRequest
{
std::string title;
};
struct ModifyResolutionRequest
{
math::uvec2 resolution;
};
struct ModifyPositionRequest
{
math::ivec2 position;
};
struct ModifyVisibilityRequest
{
bool visible;
};
}; // namespace lt::surface

View file

@ -1,9 +1,7 @@
#pragma once
#include <app/system.hpp>
#include <ecs/entity.hpp>
#include <ecs/scene.hpp>
#include <surface/components.hpp>
namespace lt::surface {
@ -22,26 +20,12 @@ public:
auto operator=(const System &) -> System & = delete;
void on_register() override
{
}
void on_register() override;
void on_unregister() override
{
}
void on_unregister() override;
auto tick() -> bool override;
static 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(ecs::Entity surface_entity, SurfaceComponent::EventCallback callback);
private:
void on_surface_construct(entt::registry &registry, entt::entity entity);
@ -49,10 +33,35 @@ private:
void on_surface_destroy(entt::registry &registry, entt::entity entity);
void ensure_component_sanity(const SurfaceComponent &component);
void handle_requests(struct SurfaceComponent &surface);
void handle_events(struct SurfaceComponent &surface);
void modify_title(struct SurfaceComponent &surface, const struct ModifyTitleRequest &request);
void modify_resolution(
struct SurfaceComponent &surface,
const struct ModifyResolutionRequest &request
);
void modify_position(
struct SurfaceComponent &surface,
const struct ModifyPositionRequest &request
);
void modify_visiblity(
struct SurfaceComponent &surface,
const struct ModifyVisibilityRequest &request
);
void modify_position(ecs::Entity surface_entity, const math::ivec2 &new_size);
void modify_position(ecs::Entity surface_entity, const math::uvec2 &new_size);
void set_visibility(ecs::Entity surface_entity, bool visible);
Ref<ecs::Registry> m_registry;
};
} // namespace lt::surface

View file

@ -7,9 +7,12 @@
namespace lt::test {
template<typename T>
concept Printable = requires(std::ostream &stream, T value) {
{ stream << value } -> std::same_as<std::ostream &>;
} || requires(std::ostream &stream, T value) {
concept Formattable = requires(T &v, std::format_context ctx) {
std::formatter<std::remove_cvref_t<T>>().format(v, ctx);
};
template<typename T>
concept Printable = Formattable<T> || requires(std::ostream &stream, T value) {
{ stream << std::to_underlying<T>(value) } -> std::same_as<std::ostream &>;
};

View file

@ -1,2 +1,2 @@
add_library_module(ui ui.cpp gl/ui.cpp gl/backend.cpp glfw/glfw.cpp)
add_library_module(ui ui.cpp)
target_link_libraries(ui PUBLIC imgui renderer logger lt_debug)

View file

@ -1,3 +0,0 @@
# Disable all checks in this subdirectory
Checks: '-*'

File diff suppressed because it is too large Load diff

View file

@ -1,70 +0,0 @@
// clang-format off
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// About WebGL/ES:
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
// - This is done automatically on iOS, Android and Emscripten targets.
// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
// About GLSL version:
// The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string.
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
// (Optional) Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
IMGUI_IMPL_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex);
// Configuration flags to add in your imconfig file:
//#define IMGUI_IMPL_OPENGL_ES2 // Enable ES 2 (Auto-detected on Emscripten)
//#define IMGUI_IMPL_OPENGL_ES3 // Enable ES 3 (Auto-detected on iOS/Android)
// You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
&& !defined(IMGUI_IMPL_OPENGL_ES3)
// Try to detect GLES on matching platforms
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
#elif defined(__EMSCRIPTEN__) || defined(__amigaos4__)
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
#else
// Otherwise imgui_impl_opengl3_loader.h will be used.
#endif
#endif
#endif // #ifndef IMGUI_DISABLE

View file

@ -1,923 +0,0 @@
// clang-format off
//-----------------------------------------------------------------------------
// About imgui_impl_opengl3_loader.h:
//
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
// which proved to be endless problems for users.
// Our loader is custom-generated, based on gl3w but automatically filtered to only include
// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
//
// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
//
// IF YOU GET BUILD ERRORS IN THIS FILE (commonly macro redefinitions or function redefinitions):
// IT LIKELY MEANS THAT YOU ARE BUILDING 'imgui_impl_opengl3.cpp' OR INCLUDING 'imgui_impl_opengl3_loader.h'
// IN THE SAME COMPILATION UNIT AS ONE OF YOUR FILE WHICH IS USING A THIRD-PARTY OPENGL LOADER.
// (e.g. COULD HAPPEN IF YOU ARE DOING A UNITY/JUMBO BUILD, OR INCLUDING .CPP FILES FROM OTHERS)
// YOU SHOULD NOT BUILD BOTH IN THE SAME COMPILATION UNIT.
// BUT IF YOU REALLY WANT TO, you can '#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM' and imgui_impl_opengl3.cpp
// WILL NOT BE USING OUR LOADER, AND INSTEAD EXPECT ANOTHER/YOUR LOADER TO BE AVAILABLE IN THE COMPILATION UNIT.
//
// Regenerate with:
// python3 gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
//
// More info:
// https://github.com/dearimgui/gl3w_stripped
// https://github.com/ocornut/imgui/issues/4445
//-----------------------------------------------------------------------------
/*
* This file was generated with gl3w_gen.py, part of imgl3w
* (hosted at https://github.com/dearimgui/gl3w_stripped)
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __gl3w_h_
#define __gl3w_h_
// Adapted from KHR/khrplatform.h to avoid including entire file.
#ifndef __khrplatform_h_
typedef float khronos_float_t;
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
#ifdef _WIN64
typedef signed long long int khronos_intptr_t;
typedef signed long long int khronos_ssize_t;
#else
typedef signed long int khronos_intptr_t;
typedef signed long int khronos_ssize_t;
#endif
#if defined(_MSC_VER) && !defined(__clang__)
typedef signed __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
#include <stdint.h>
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#else
typedef signed long long khronos_int64_t;
typedef unsigned long long khronos_uint64_t;
#endif
#endif // __khrplatform_h_
#ifndef __gl_glcorearb_h_
#define __gl_glcorearb_h_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright 2013-2020 The Khronos Group Inc.
** SPDX-License-Identifier: MIT
**
** This header is generated from the Khronos OpenGL / OpenGL ES XML
** API Registry. The current version of the Registry, generator scripts
** used to make the header, and the header can be found at
** https://github.com/KhronosGroup/OpenGL-Registry
*/
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#endif
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
#ifndef GLAPI
#define GLAPI extern
#endif
/* glcorearb.h is for use with OpenGL core profile implementations.
** It should should be placed in the same directory as gl.h and
** included as <GL/glcorearb.h>.
**
** glcorearb.h includes only APIs in the latest OpenGL core profile
** implementation together with APIs in newer ARB extensions which
** can be supported by the core profile. It does not, and never will
** include functionality removed from the core profile, such as
** fixed-function vertex and fragment processing.
**
** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or
** <GL/glext.h> in the same source file.
*/
/* Generated C header for:
* API: gl
* Profile: core
* Versions considered: .*
* Versions emitted: .*
* Default extensions included: glcore
* Additional extensions included: _nomatch_^
* Extensions removed: _nomatch_^
*/
#ifndef GL_VERSION_1_0
typedef void GLvoid;
typedef unsigned int GLenum;
typedef khronos_float_t GLfloat;
typedef int GLint;
typedef int GLsizei;
typedef unsigned int GLbitfield;
typedef double GLdouble;
typedef unsigned int GLuint;
typedef unsigned char GLboolean;
typedef khronos_uint8_t GLubyte;
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_FALSE 0
#define GL_TRUE 1
#define GL_TRIANGLES 0x0004
#define GL_ONE 1
#define GL_SRC_ALPHA 0x0302
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
#define GL_FRONT 0x0404
#define GL_BACK 0x0405
#define GL_FRONT_AND_BACK 0x0408
#define GL_POLYGON_MODE 0x0B40
#define GL_CULL_FACE 0x0B44
#define GL_DEPTH_TEST 0x0B71
#define GL_STENCIL_TEST 0x0B90
#define GL_VIEWPORT 0x0BA2
#define GL_BLEND 0x0BE2
#define GL_SCISSOR_BOX 0x0C10
#define GL_SCISSOR_TEST 0x0C11
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#define GL_PACK_ALIGNMENT 0x0D05
#define GL_MAX_TEXTURE_SIZE 0x0D33
#define GL_TEXTURE_2D 0x0DE1
#define GL_UNSIGNED_BYTE 0x1401
#define GL_UNSIGNED_SHORT 0x1403
#define GL_UNSIGNED_INT 0x1405
#define GL_FLOAT 0x1406
#define GL_RGBA 0x1908
#define GL_FILL 0x1B02
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
#define GL_LINEAR 0x2601
#define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MIN_FILTER 0x2801
#define GL_TEXTURE_WRAP_S 0x2802
#define GL_TEXTURE_WRAP_T 0x2803
#define GL_REPEAT 0x2901
typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLFLUSHPROC) (void);
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);
GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
GLAPI void APIENTRY glClear (GLbitfield mask);
GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
GLAPI void APIENTRY glDisable (GLenum cap);
GLAPI void APIENTRY glEnable (GLenum cap);
GLAPI void APIENTRY glFlush (void);
GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
GLAPI GLenum APIENTRY glGetError (void);
GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
#endif
#endif /* GL_VERSION_1_0 */
#ifndef GL_VERSION_1_1
typedef khronos_float_t GLclampf;
typedef double GLclampd;
#define GL_TEXTURE_BINDING_2D 0x8069
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
GLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
#endif
#endif /* GL_VERSION_1_1 */
#ifndef GL_VERSION_1_2
#define GL_CLAMP_TO_EDGE 0x812F
#endif /* GL_VERSION_1_2 */
#ifndef GL_VERSION_1_3
#define GL_TEXTURE0 0x84C0
#define GL_ACTIVE_TEXTURE 0x84E0
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glActiveTexture (GLenum texture);
#endif
#endif /* GL_VERSION_1_3 */
#ifndef GL_VERSION_1_4
#define GL_BLEND_DST_RGB 0x80C8
#define GL_BLEND_SRC_RGB 0x80C9
#define GL_BLEND_DST_ALPHA 0x80CA
#define GL_BLEND_SRC_ALPHA 0x80CB
#define GL_FUNC_ADD 0x8006
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
GLAPI void APIENTRY glBlendEquation (GLenum mode);
#endif
#endif /* GL_VERSION_1_4 */
#ifndef GL_VERSION_1_5
typedef khronos_ssize_t GLsizeiptr;
typedef khronos_intptr_t GLintptr;
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
#define GL_STREAM_DRAW 0x88E0
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
#endif
#endif /* GL_VERSION_1_5 */
#ifndef GL_VERSION_2_0
typedef char GLchar;
typedef khronos_int16_t GLshort;
typedef khronos_int8_t GLbyte;
typedef khronos_uint16_t GLushort;
#define GL_BLEND_EQUATION_RGB 0x8009
#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
#define GL_BLEND_EQUATION_ALPHA 0x883D
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_COMPILE_STATUS 0x8B81
#define GL_LINK_STATUS 0x8B82
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_CURRENT_PROGRAM 0x8B8D
#define GL_UPPER_LEFT 0x8CA2
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
GLAPI void APIENTRY glCompileShader (GLuint shader);
GLAPI GLuint APIENTRY glCreateProgram (void);
GLAPI GLuint APIENTRY glCreateShader (GLenum type);
GLAPI void APIENTRY glDeleteProgram (GLuint program);
GLAPI void APIENTRY glDeleteShader (GLuint shader);
GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index);
GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);
GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);
GLAPI GLboolean APIENTRY glIsProgram (GLuint program);
GLAPI void APIENTRY glLinkProgram (GLuint program);
GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
GLAPI void APIENTRY glUseProgram (GLuint program);
GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
#endif
#endif /* GL_VERSION_2_0 */
#ifndef GL_VERSION_2_1
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
#endif /* GL_VERSION_2_1 */
#ifndef GL_VERSION_3_0
typedef khronos_uint16_t GLhalf;
#define GL_MAJOR_VERSION 0x821B
#define GL_MINOR_VERSION 0x821C
#define GL_NUM_EXTENSIONS 0x821D
#define GL_FRAMEBUFFER_SRGB 0x8DB9
#define GL_VERTEX_ARRAY_BINDING 0x85B5
typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
GLAPI void APIENTRY glBindVertexArray (GLuint array);
GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
#endif
#endif /* GL_VERSION_3_0 */
#ifndef GL_VERSION_3_1
#define GL_VERSION_3_1 1
#define GL_PRIMITIVE_RESTART 0x8F9D
#endif /* GL_VERSION_3_1 */
#ifndef GL_VERSION_3_2
#define GL_VERSION_3_2 1
typedef struct __GLsync *GLsync;
typedef khronos_uint64_t GLuint64;
typedef khronos_int64_t GLint64;
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
#define GL_CONTEXT_PROFILE_MASK 0x9126
typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
#endif
#endif /* GL_VERSION_3_2 */
#ifndef GL_VERSION_3_3
#define GL_VERSION_3_3 1
#define GL_SAMPLER_BINDING 0x8919
typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
#endif
#endif /* GL_VERSION_3_3 */
#ifndef GL_VERSION_4_1
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
#endif /* GL_VERSION_4_1 */
#ifndef GL_VERSION_4_3
typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
#endif /* GL_VERSION_4_3 */
#ifndef GL_VERSION_4_5
#define GL_CLIP_ORIGIN 0x935C
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
#endif /* GL_VERSION_4_5 */
#ifndef GL_ARB_bindless_texture
typedef khronos_uint64_t GLuint64EXT;
#endif /* GL_ARB_bindless_texture */
#ifndef GL_ARB_cl_event
struct _cl_context;
struct _cl_event;
#endif /* GL_ARB_cl_event */
#ifndef GL_ARB_clip_control
#define GL_ARB_clip_control 1
#endif /* GL_ARB_clip_control */
#ifndef GL_ARB_debug_output
typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
#endif /* GL_ARB_debug_output */
#ifndef GL_EXT_EGL_image_storage
typedef void *GLeglImageOES;
#endif /* GL_EXT_EGL_image_storage */
#ifndef GL_EXT_direct_state_access
typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
#endif /* GL_EXT_direct_state_access */
#ifndef GL_NV_draw_vulkan_image
typedef void (APIENTRY *GLVULKANPROCNV)(void);
#endif /* GL_NV_draw_vulkan_image */
#ifndef GL_NV_gpu_shader5
typedef khronos_int64_t GLint64EXT;
#endif /* GL_NV_gpu_shader5 */
#ifndef GL_NV_vertex_buffer_unified_memory
typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
#endif /* GL_NV_vertex_buffer_unified_memory */
#ifdef __cplusplus
}
#endif
#endif
#ifndef GL3W_API
#define GL3W_API
#endif
#ifndef __gl_h_
#define __gl_h_
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define GL3W_OK 0
#define GL3W_ERROR_INIT -1
#define GL3W_ERROR_LIBRARY_OPEN -2
#define GL3W_ERROR_OPENGL_VERSION -3
typedef void (*GL3WglProc)(void);
typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
/* gl3w api */
GL3W_API int imgl3wInit(void);
GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
GL3W_API int imgl3wIsSupported(int major, int minor);
GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
/* gl3w internal state */
union ImGL3WProcs {
GL3WglProc ptr[60];
struct {
PFNGLACTIVETEXTUREPROC ActiveTexture;
PFNGLATTACHSHADERPROC AttachShader;
PFNGLBINDBUFFERPROC BindBuffer;
PFNGLBINDSAMPLERPROC BindSampler;
PFNGLBINDTEXTUREPROC BindTexture;
PFNGLBINDVERTEXARRAYPROC BindVertexArray;
PFNGLBLENDEQUATIONPROC BlendEquation;
PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
PFNGLBUFFERDATAPROC BufferData;
PFNGLBUFFERSUBDATAPROC BufferSubData;
PFNGLCLEARPROC Clear;
PFNGLCLEARCOLORPROC ClearColor;
PFNGLCOMPILESHADERPROC CompileShader;
PFNGLCREATEPROGRAMPROC CreateProgram;
PFNGLCREATESHADERPROC CreateShader;
PFNGLDELETEBUFFERSPROC DeleteBuffers;
PFNGLDELETEPROGRAMPROC DeleteProgram;
PFNGLDELETESHADERPROC DeleteShader;
PFNGLDELETETEXTURESPROC DeleteTextures;
PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
PFNGLDETACHSHADERPROC DetachShader;
PFNGLDISABLEPROC Disable;
PFNGLDISABLEVERTEXATTRIBARRAYPROC DisableVertexAttribArray;
PFNGLDRAWELEMENTSPROC DrawElements;
PFNGLDRAWELEMENTSBASEVERTEXPROC DrawElementsBaseVertex;
PFNGLENABLEPROC Enable;
PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
PFNGLFLUSHPROC Flush;
PFNGLGENBUFFERSPROC GenBuffers;
PFNGLGENTEXTURESPROC GenTextures;
PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
PFNGLGETERRORPROC GetError;
PFNGLGETINTEGERVPROC GetIntegerv;
PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
PFNGLGETPROGRAMIVPROC GetProgramiv;
PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
PFNGLGETSHADERIVPROC GetShaderiv;
PFNGLGETSTRINGPROC GetString;
PFNGLGETSTRINGIPROC GetStringi;
PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
PFNGLGETVERTEXATTRIBPOINTERVPROC GetVertexAttribPointerv;
PFNGLGETVERTEXATTRIBIVPROC GetVertexAttribiv;
PFNGLISENABLEDPROC IsEnabled;
PFNGLISPROGRAMPROC IsProgram;
PFNGLLINKPROGRAMPROC LinkProgram;
PFNGLPIXELSTOREIPROC PixelStorei;
PFNGLPOLYGONMODEPROC PolygonMode;
PFNGLREADPIXELSPROC ReadPixels;
PFNGLSCISSORPROC Scissor;
PFNGLSHADERSOURCEPROC ShaderSource;
PFNGLTEXIMAGE2DPROC TexImage2D;
PFNGLTEXPARAMETERIPROC TexParameteri;
PFNGLTEXSUBIMAGE2DPROC TexSubImage2D;
PFNGLUNIFORM1IPROC Uniform1i;
PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv;
PFNGLUSEPROGRAMPROC UseProgram;
PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
PFNGLVIEWPORTPROC Viewport;
} gl;
};
GL3W_API extern union ImGL3WProcs imgl3wProcs;
/* OpenGL functions */
#define glActiveTexture imgl3wProcs.gl.ActiveTexture
#define glAttachShader imgl3wProcs.gl.AttachShader
#define glBindBuffer imgl3wProcs.gl.BindBuffer
#define glBindSampler imgl3wProcs.gl.BindSampler
#define glBindTexture imgl3wProcs.gl.BindTexture
#define glBindVertexArray imgl3wProcs.gl.BindVertexArray
#define glBlendEquation imgl3wProcs.gl.BlendEquation
#define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
#define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
#define glBufferData imgl3wProcs.gl.BufferData
#define glBufferSubData imgl3wProcs.gl.BufferSubData
#define glClear imgl3wProcs.gl.Clear
#define glClearColor imgl3wProcs.gl.ClearColor
#define glCompileShader imgl3wProcs.gl.CompileShader
#define glCreateProgram imgl3wProcs.gl.CreateProgram
#define glCreateShader imgl3wProcs.gl.CreateShader
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
#define glDeleteProgram imgl3wProcs.gl.DeleteProgram
#define glDeleteShader imgl3wProcs.gl.DeleteShader
#define glDeleteTextures imgl3wProcs.gl.DeleteTextures
#define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
#define glDetachShader imgl3wProcs.gl.DetachShader
#define glDisable imgl3wProcs.gl.Disable
#define glDisableVertexAttribArray imgl3wProcs.gl.DisableVertexAttribArray
#define glDrawElements imgl3wProcs.gl.DrawElements
#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
#define glEnable imgl3wProcs.gl.Enable
#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
#define glFlush imgl3wProcs.gl.Flush
#define glGenBuffers imgl3wProcs.gl.GenBuffers
#define glGenTextures imgl3wProcs.gl.GenTextures
#define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
#define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
#define glGetError imgl3wProcs.gl.GetError
#define glGetIntegerv imgl3wProcs.gl.GetIntegerv
#define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
#define glGetProgramiv imgl3wProcs.gl.GetProgramiv
#define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
#define glGetShaderiv imgl3wProcs.gl.GetShaderiv
#define glGetString imgl3wProcs.gl.GetString
#define glGetStringi imgl3wProcs.gl.GetStringi
#define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
#define glGetVertexAttribPointerv imgl3wProcs.gl.GetVertexAttribPointerv
#define glGetVertexAttribiv imgl3wProcs.gl.GetVertexAttribiv
#define glIsEnabled imgl3wProcs.gl.IsEnabled
#define glIsProgram imgl3wProcs.gl.IsProgram
#define glLinkProgram imgl3wProcs.gl.LinkProgram
#define glPixelStorei imgl3wProcs.gl.PixelStorei
#define glPolygonMode imgl3wProcs.gl.PolygonMode
#define glReadPixels imgl3wProcs.gl.ReadPixels
#define glScissor imgl3wProcs.gl.Scissor
#define glShaderSource imgl3wProcs.gl.ShaderSource
#define glTexImage2D imgl3wProcs.gl.TexImage2D
#define glTexParameteri imgl3wProcs.gl.TexParameteri
#define glTexSubImage2D imgl3wProcs.gl.TexSubImage2D
#define glUniform1i imgl3wProcs.gl.Uniform1i
#define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
#define glUseProgram imgl3wProcs.gl.UseProgram
#define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
#define glViewport imgl3wProcs.gl.Viewport
#ifdef __cplusplus
}
#endif
#endif
#ifdef IMGL3W_IMPL
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#define GL3W_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
static HMODULE libgl;
typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
static GL3WglGetProcAddr wgl_get_proc_address;
static int open_libgl(void)
{
libgl = LoadLibraryA("opengl32.dll");
if (!libgl)
return GL3W_ERROR_LIBRARY_OPEN;
wgl_get_proc_address = (GL3WglGetProcAddr)GetProcAddress(libgl, "wglGetProcAddress");
return GL3W_OK;
}
static void close_libgl(void) { FreeLibrary(libgl); }
static GL3WglProc get_proc(const char *proc)
{
GL3WglProc res;
res = (GL3WglProc)wgl_get_proc_address(proc);
if (!res)
res = (GL3WglProc)GetProcAddress(libgl, proc);
return res;
}
#elif defined(__APPLE__)
#include <dlfcn.h>
static void *libgl;
static int open_libgl(void)
{
libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
if (!libgl)
return GL3W_ERROR_LIBRARY_OPEN;
return GL3W_OK;
}
static void close_libgl(void) { dlclose(libgl); }
static GL3WglProc get_proc(const char *proc)
{
GL3WglProc res;
*(void **)(&res) = dlsym(libgl, proc);
return res;
}
#else
#include <dlfcn.h>
static void* libgl; // OpenGL library
static void* libglx; // GLX library
static void* libegl; // EGL library
static GL3WGetProcAddressProc gl_get_proc_address;
static void close_libgl(void)
{
if (libgl) {
dlclose(libgl);
libgl = NULL;
}
if (libegl) {
dlclose(libegl);
libegl = NULL;
}
if (libglx) {
dlclose(libglx);
libglx = NULL;
}
}
static int is_library_loaded(const char* name, void** lib)
{
*lib = dlopen(name, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
return *lib != NULL;
}
static int open_libs(void)
{
// On Linux we have two APIs to get process addresses: EGL and GLX.
// EGL is supported under both X11 and Wayland, whereas GLX is X11-specific.
libgl = NULL;
libegl = NULL;
libglx = NULL;
// First check what's already loaded, the windowing library might have
// already loaded either EGL or GLX and we want to use the same one.
if (is_library_loaded("libEGL.so.1", &libegl) ||
is_library_loaded("libGLX.so.0", &libglx)) {
libgl = dlopen("libOpenGL.so.0", RTLD_LAZY | RTLD_LOCAL);
if (libgl)
return GL3W_OK;
else
close_libgl();
}
if (is_library_loaded("libGL.so", &libgl))
return GL3W_OK;
if (is_library_loaded("libGL.so.1", &libgl))
return GL3W_OK;
if (is_library_loaded("libGL.so.3", &libgl))
return GL3W_OK;
// Neither is already loaded, so we have to load one. Try EGL first
// because it is supported under both X11 and Wayland.
// Load OpenGL + EGL
libgl = dlopen("libOpenGL.so.0", RTLD_LAZY | RTLD_LOCAL);
libegl = dlopen("libEGL.so.1", RTLD_LAZY | RTLD_LOCAL);
if (libgl && libegl)
return GL3W_OK;
else
close_libgl();
// Fall back to legacy libGL, which includes GLX
// While most systems use libGL.so.1, NetBSD seems to use that libGL.so.3. See https://github.com/ocornut/imgui/issues/6983
libgl = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL);
if (!libgl)
libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
if (!libgl)
libgl = dlopen("libGL.so.3", RTLD_LAZY | RTLD_LOCAL);
if (libgl)
return GL3W_OK;
return GL3W_ERROR_LIBRARY_OPEN;
}
static int open_libgl(void)
{
int res = open_libs();
if (res)
return res;
if (libegl)
*(void**)(&gl_get_proc_address) = dlsym(libegl, "eglGetProcAddress");
else if (libglx)
*(void**)(&gl_get_proc_address) = dlsym(libglx, "glXGetProcAddressARB");
else
*(void**)(&gl_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
if (!gl_get_proc_address) {
close_libgl();
return GL3W_ERROR_LIBRARY_OPEN;
}
return GL3W_OK;
}
static GL3WglProc get_proc(const char* proc)
{
GL3WglProc res = NULL;
// Before EGL version 1.5, eglGetProcAddress doesn't support querying core
// functions and may return a dummy function if we try, so try to load the
// function from the GL library directly first.
if (libegl)
*(void**)(&res) = dlsym(libgl, proc);
if (!res)
res = gl_get_proc_address(proc);
if (!libegl && !res)
*(void**)(&res) = dlsym(libgl, proc);
return res;
}
#endif
static struct { int major, minor; } version;
static int parse_version(void)
{
if (!glGetIntegerv)
return GL3W_ERROR_INIT;
glGetIntegerv(GL_MAJOR_VERSION, &version.major);
glGetIntegerv(GL_MINOR_VERSION, &version.minor);
if (version.major == 0 && version.minor == 0)
{
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
if (const char* gl_version = (const char*)glGetString(GL_VERSION))
sscanf(gl_version, "%d.%d", &version.major, &version.minor);
}
if (version.major < 2)
return GL3W_ERROR_OPENGL_VERSION;
return GL3W_OK;
}
static void load_procs(GL3WGetProcAddressProc proc);
int imgl3wInit(void)
{
int res = open_libgl();
if (res)
return res;
atexit(close_libgl);
return imgl3wInit2(get_proc);
}
int imgl3wInit2(GL3WGetProcAddressProc proc)
{
load_procs(proc);
return parse_version();
}
int imgl3wIsSupported(int major, int minor)
{
if (major < 2)
return 0;
if (version.major == major)
return version.minor >= minor;
return version.major >= major;
}
GL3WglProc imgl3wGetProcAddress(const char *proc) { return get_proc(proc); }
static const char *proc_names[] = {
"glActiveTexture",
"glAttachShader",
"glBindBuffer",
"glBindSampler",
"glBindTexture",
"glBindVertexArray",
"glBlendEquation",
"glBlendEquationSeparate",
"glBlendFuncSeparate",
"glBufferData",
"glBufferSubData",
"glClear",
"glClearColor",
"glCompileShader",
"glCreateProgram",
"glCreateShader",
"glDeleteBuffers",
"glDeleteProgram",
"glDeleteShader",
"glDeleteTextures",
"glDeleteVertexArrays",
"glDetachShader",
"glDisable",
"glDisableVertexAttribArray",
"glDrawElements",
"glDrawElementsBaseVertex",
"glEnable",
"glEnableVertexAttribArray",
"glFlush",
"glGenBuffers",
"glGenTextures",
"glGenVertexArrays",
"glGetAttribLocation",
"glGetError",
"glGetIntegerv",
"glGetProgramInfoLog",
"glGetProgramiv",
"glGetShaderInfoLog",
"glGetShaderiv",
"glGetString",
"glGetStringi",
"glGetUniformLocation",
"glGetVertexAttribPointerv",
"glGetVertexAttribiv",
"glIsEnabled",
"glIsProgram",
"glLinkProgram",
"glPixelStorei",
"glPolygonMode",
"glReadPixels",
"glScissor",
"glShaderSource",
"glTexImage2D",
"glTexParameteri",
"glTexSubImage2D",
"glUniform1i",
"glUniformMatrix4fv",
"glUseProgram",
"glVertexAttribPointer",
"glViewport",
};
GL3W_API union ImGL3WProcs imgl3wProcs;
static void load_procs(GL3WGetProcAddressProc proc)
{
size_t i;
for (i = 0; i < GL3W_ARRAY_SIZE(proc_names); i++)
imgl3wProcs.ptr[i] = proc(proc_names[i]);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,64 +0,0 @@
#include <GLFW/glfw3.h>
#include <imgui.h>
#include <input/key_codes.hpp>
#include <ui/gl/backend.hpp>
#include <ui/gl/ui.hpp>
#include <ui/glfw/glfw.h>
namespace lt {
void glUserInterface::platform_implementation(
GLFWwindow *windowHandle,
Ref<SharedContext> /* shared_context */
)
{
m_window_handle = windowHandle;
ImGui_ImplGlfw_InitForOpenGL(windowHandle, false);
ImGui_ImplOpenGL3_Init();
}
glUserInterface::~glUserInterface()
{
// #todo: handle this in a better way
auto &io = ImGui::GetIO();
if (io.IniFilename == "default_gui_layout.ini")
{
io.IniFilename = "user_gui_layout.ini";
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
}
void glUserInterface::begin()
{
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
void glUserInterface::end()
{
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(m_window_handle);
}
void glUserInterface::log_debug_data()
{
// #todo: improve
log_inf("________________________________________");
log_inf("UserInterface::");
log_inf(" API : ImGui");
log_inf(" Version: {}", ImGui::GetVersion());
log_inf(" GraphicsAPI : OpenGL");
log_inf("________________________________________");
}
} // namespace lt

View file

@ -1,31 +0,0 @@
#pragma once
#include <ui/ui.hpp>
struct GLFWwindow;
namespace lt {
class glUserInterface: public UserInterface
{
public:
glUserInterface() = default;
~glUserInterface() override;
void platform_implementation(
GLFWwindow *windowHandle,
Ref<SharedContext> sharedContext
) override;
void begin() override;
void end() override;
void log_debug_data() override;
private:
GLFWwindow *m_window_handle {};
};
} // namespace lt

View file

@ -1,3 +0,0 @@
# Disable all checks in this subdirectory
Checks: '-*'

File diff suppressed because it is too large Load diff

View file

@ -1,74 +0,0 @@
// clang-format off
// dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// [X] Multiple Dear ImGui contexts support.
// Missing features or Issues:
// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround.
// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors.
// [ ] Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
struct GLFWwindow;
struct GLFWmonitor;
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
// Emscripten related initialization phase methods (call after ImGui_ImplGlfw_InitForOpenGL)
#ifdef __EMSCRIPTEN__
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* window, const char* canvas_selector);
//static inline void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector) { ImGui_ImplGlfw_InstallEmscriptenCallbacks(nullptr, canvas_selector); } } // Renamed in 1.91.0
#endif
// GLFW callbacks install
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
// GFLW callbacks options:
// - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user)
IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows);
// GLFW callbacks (individual callbacks to call yourself if you didn't install callbacks)
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
// GLFW helpers
IMGUI_IMPL_API void ImGui_ImplGlfw_Sleep(int milliseconds);
IMGUI_IMPL_API float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window);
IMGUI_IMPL_API float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor);
#endif // #ifndef IMGUI_DISABLE

View file

@ -25,8 +25,7 @@ namespace lt {
UserInterface *UserInterface::s_context = nullptr;
auto UserInterface::create(GLFWwindow *windowHandle, Ref<SharedContext> sharedContext)
-> Scope<UserInterface>
auto UserInterface::create(Ref<SharedContext> sharedContext) -> Scope<UserInterface>
{
auto scopeUserInterface = Scope<UserInterface> { nullptr };
@ -66,7 +65,7 @@ UserInterface::UserInterface()
s_context = this;
}
void UserInterface::init(GLFWwindow *windowHandle, Ref<SharedContext> sharedContext)
void UserInterface::init(Ref<SharedContext> sharedContext)
{
// create context
IMGUI_CHECKVERSION();

View file

@ -1,9 +1,5 @@
#pragma once
#include <imgui.h>
struct GLFWwindow;
namespace lt {
class Event;
@ -12,8 +8,7 @@ class SharedContext;
class UserInterface
{
public:
static auto create(GLFWwindow *windowHandle, Ref<SharedContext> sharedContext)
-> Scope<UserInterface>;
static auto create(Ref<SharedContext> sharedContext) -> Scope<UserInterface>;
static void dockspace_begin();
@ -25,12 +20,9 @@ public:
virtual ~UserInterface() = default;
void init(GLFWwindow *windowHandle, Ref<SharedContext> sharedContext);
void init(Ref<SharedContext> sharedContext);
virtual void platform_implementation(
GLFWwindow *window_handle,
Ref<SharedContext> sharedContext
) = 0;
virtual void platform_implementation(Ref<SharedContext> sharedContext) = 0;
virtual void begin() = 0;
@ -45,8 +37,6 @@ private:
static UserInterface *s_context;
void set_dark_theme_colors();
ImGuiWindowFlags m_dockspace_flags;
};
} // namespace lt

View file

@ -4,7 +4,6 @@ RUN pacman -Syu --noconfirm --disable-download-timeout \
&& pacman -S --noconfirm --disable-download-timeout reflector \
&& reflector --verbose --latest 10 --protocol https --sort rate --save /etc/pacman.d/mirrorlist \
&& sed -i 's/^#ParallelDownloads = .*/ParallelDownloads = 8/' /etc/pacman.conf \
&& grep "ParallelDownloads" /etc/pacman.conf
RUN pacman -S --noconfirm --disable-download-timeout \
bash \
@ -14,6 +13,7 @@ RUN pacman -S --noconfirm --disable-download-timeout \
python \
python-pip \
clang \
gcc \
llvm \
mesa \
mold \
@ -22,7 +22,13 @@ RUN pacman -S --noconfirm --disable-download-timeout \
wget \
zlib \
libc++ \
libinput
libinput \
xorg-server-xvfb \
libx11 \
libxrandr \
libxinerama \
libxcursor \
libxi
RUN pip install --no-cache-dir --break-system-packages conan gitpython \
&& conan profile detect

View file

@ -6,6 +6,8 @@ rm -rf ./build
Xvfb :99 -screen 0 1024x768x16 &
export DISPLAY=:99
export CXX=$(which clang++)
export CC=$(which clang)
conan build . \
-c tools.system.package_manager:mode=install \
@ -37,11 +39,6 @@ LLVM_COV_SHOW=$(llvm-cov show \
$(find ./build -type f -name '*\.a' -exec printf -- '-object %s ' {} \;) \
-ignore-filename-regex='\.test\.cpp$' \
-ignore-filename-regex='./external/' \
-ignore-filename-regex='gl\/backend.cpp$' \
-ignore-filename-regex='gl\/backend.hpp$' \
-ignore-filename-regex='gl\/loader.hpp$' \
-ignore-filename-regex='glfw\/glfw.h$' \
-ignore-filename-regex='glfw\/glfw.cpp$'
)
echo "${LLVM_COV_SHOW}" > './build/coverage/coverage.txt'

View file

@ -0,0 +1,72 @@
FROM archlinux:base-devel
RUN pacman -Syyu --noconfirm && \
pacman -S --noconfirm \
bash \
base-devel \
clang \
llvm \
libc++ \
cmake \
git \
python \
python-pip \
mesa \
mold \
ninja \
zlib \
libc++ \
libinput \
xorg-server-xvfb \
libx11 \
libxrandr \
libxinerama \
libxcursor \
libxi \
afl++ \
afl-utils
RUN pip install --no-cache-dir --break-system-packages conan gitpython \
&& conan profile detect
RUN clang --version \
&& conan --version \
&& pip --version \
&& cmake --version \
&& g++ --version \
&& clang --version \
&& ninja --version \
&& mold --version \
&& afl-fuzz --version \
&& afl-clang-lto --version \
&& afl-clang-lto++ --version
RUN git clone 'https://git.light7734.com/light7734/light.git' --depth=1 \
&& cd light \
&& export CC=$(which afl-clang-lto) \
&& export CXX=$(which afl-clang-lto++) \
&& export AR=$(which llvm-ar) \
&& export RANLIB=$(which llvm-ranlib) \
&& export AS=$(which llvm-as) \
&& conan install . \
-c tools.system.package_manager:mode=install \
-c tools.cmake.cmaketoolchain:generator=Ninja \
-c tools.build:compiler_executables='{"c": "afl-clang-lto", "cpp": "afl-clang-lto++"}' \
-s build_type=Release \
-s compiler=clang \
-s compiler.version=20 \
-s compiler.libcxx=libc++ \
-o use_mold=True \
--build=missing \
&& conan install . \
-c tools.system.package_manager:mode=install \
-c tools.cmake.cmaketoolchain:generator=Ninja \
-c tools.build:compiler_executables='{"c": "clang", "cpp": "clang++"}' \
-s build_type=Release \
-s compiler=clang \
-s compiler.version=20 \
-s compiler.libcxx=libc++ \
-o use_mold=True \
-o enable_llvm_coverage=True \
--build=missing \
&& rm -r ../light/

View file

@ -14,7 +14,15 @@ RUN pacman -Syu --noconfirm && \
mold \
ninja \
zlib \
libunwind
libc++ \
libinput \
libunwind \
xorg-server-xvfb \
libx11 \
libxrandr \
libxinerama \
libxcursor \
libxi
RUN pip install --no-cache-dir --break-system-packages conan gitpython \
&& conan profile detect

View file

@ -14,7 +14,17 @@ RUN pacman -Syu --noconfirm && \
mold \
ninja \
zlib \
libunwind
libc++ \
libinput \
libunwind \
xorg-server-xvfb \
libx11 \
libxrandr \
libxinerama \
libxcursor \
libxi \
xcb-util-cursor
RUN pip install --no-cache-dir --break-system-packages conan gitpython \
&& conan profile detect

View file

@ -1,22 +1,39 @@
FROM alpine:latest
FROM archlinux:base-devel
RUN apk add --no-cache \
RUN pacman -Syu --noconfirm --disable-download-timeout \
&& pacman -S --noconfirm --needed --disable-download-timeout reflector \
&& reflector --verbose --latest 10 --protocol https --sort rate --save /etc/pacman.d/mirrorlist \
&& sed -i 's/^#ParallelDownloads = .*/ParallelDownloads = 9/' /etc/pacman.conf
RUN pacman -S --noconfirm --needed --disable-download-timeout \
bash \
clang \
llvm \
cmake \
base-devel \
git \
make \
g++ \
python3 \
py3-pip \
mesa-dev \
mesa-gl \
pkgconf \
cmake \
python \
python-pip \
clang \
gcc \
llvm \
mesa \
ninja \
mold
mold \
curl \
wget \
zlib \
libc++ \
libinput \
xorg-server-xvfb \
libx11 \
libxrandr \
libxinerama \
libxcursor \
libxi \
xcb-util-cursor
RUN pip install --no-cache-dir --break-system-packages conan gitpython \
RUN pip install --no-cache-dir --break-system-packages \
conan \
gitpython \
&& conan profile detect
RUN clang --version \
@ -28,11 +45,22 @@ RUN clang --version \
&& ninja --version \
&& mold --version
RUN git clone 'https://git.light7734.com/light7734/light.git' \
# We `build` instead of `install` to make sure the project can be built with the current image state.
RUN git clone 'https://git.light7734.com/light7734/light.git' --depth=1 \
&& cd light \
&& conan install . \
-s build_type=Release \
-c tools.system.package_manager:mode=install \
-c tools.cmake.cmaketoolchain:generator=Ninja \
-o use_mold=True \
--build=missing
&& conan build . \
-c tools.system.package_manager:mode=install \
-c tools.cmake.cmaketoolchain:generator=Ninja \
-c tools.build:compiler_executables='{"c": "gcc", "cpp": "g++"}' \
-s build_type=Release \
-s compiler=gcc \
-s compiler.version=15 \
-s compiler.libcxx=libstdc++ \
-o enable_unit_tests=True \
-o enable_fuzz_tests=False \
-o enable_llvm_coverage=False \
-o enable_static_analysis=False \
-o use_mold=True \
-o export_compile_commands=False \
--build=missing \
&& rm -rf ../light

View file

@ -17,7 +17,6 @@ conan build . \
-s compiler=gcc \
-s compiler.version=15 \
-s compiler.libcxx=libstdc++ \
-o use_mold=True \
-o enable_unit_tests=True \
-o enable_fuzz_tests=False \
-o enable_llvm_coverage=False \

View file

@ -1,23 +1,41 @@
FROM alpine:latest
FROM archlinux:base-devel
RUN apk add --no-cache \
RUN pacman -Syu --noconfirm --disable-download-timeout \
&& pacman -S --noconfirm --needed --disable-download-timeout reflector \
&& reflector --verbose --latest 10 --protocol https --sort rate --save /etc/pacman.d/mirrorlist \
&& sed -i 's/^#ParallelDownloads = .*/ParallelDownloads = 9/' /etc/pacman.conf
RUN pacman -S --noconfirm --needed --disable-download-timeout \
bash \
clang \
llvm \
cmake \
base-devel \
git \
make \
g++ \
python3 \
py3-pip \
mesa-dev \
mesa-gl \
pkgconf \
cmake \
python \
python-pip \
clang \
gcc \
llvm \
mesa \
ninja \
mold \
valgrind
valgrind \
curl \
wget \
zlib \
libc++ \
libinput \
xorg-server-xvfb \
libx11 \
libxrandr \
libxinerama \
libxcursor \
libxi \
xcb-util-cursor
RUN pip install --no-cache-dir --break-system-packages conan gitpython \
RUN pip install --no-cache-dir --break-system-packages \
conan \
gitpython \
&& conan profile detect
RUN clang --version \
@ -27,13 +45,25 @@ RUN clang --version \
&& g++ --version \
&& clang --version \
&& ninja --version \
&& mold --version
&& mold --version \
&& valgrind --version
RUN git clone 'https://git.light7734.com/light7734/light.git' \
# We `build` instead of `install` to make sure the project can be built with the current image state.
RUN git clone 'https://git.light7734.com/light7734/light.git' --depth=1 \
&& cd light \
&& conan install . \
-s build_type=Release \
-c tools.system.package_manager:mode=install \
-c tools.cmake.cmaketoolchain:generator=Ninja \
-o use_mold=True \
--build=missing
&& conan build . \
-c tools.system.package_manager:mode=install \
-c tools.cmake.cmaketoolchain:generator=Ninja \
-c tools.build:compiler_executables='{"c": "gcc", "cpp": "g++"}' \
-s build_type=Release \
-s compiler=gcc \
-s compiler.version=15 \
-s compiler.libcxx=libstdc++ \
-o enable_unit_tests=True \
-o enable_fuzz_tests=False \
-o enable_llvm_coverage=False \
-o enable_static_analysis=False \
-o use_mold=True \
-o export_compile_commands=False \
--build=missing \
&& rm -rf ../light

View file

@ -0,0 +1,27 @@
FROM alpine:latest
RUN apk add --no-cache \
bash \
clang \
llvm \
cmake \
git \
make \
g++ \
python3 \
py3-pip \
mesa-dev \
mesa-gl \
pkgconf \
clang-extra-tools \
mold \
ninja \
doxygen \
openssh
RUN pip install --no-cache-dir --break-system-packages \
conan \
gitpython \
Sphinx \
sphinx_rtd_theme \
&& conan profile detect

View file

@ -1,15 +1,4 @@
find_package(glfw3 REQUIRED)
find_package(stb REQUIRED)
find_package(yaml-cpp REQUIRED)
find_package(EnTT REQUIRED)
find_package(opengl_system REQUIRED)
find_package(lz4 REQUIRED)
find_package(imgui REQUIRED)
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
target_link_libraries(
imgui::imgui
INTERFACE glad
INTERFACE opengl::opengl
INTERFACE glfw
)

View file

@ -3,25 +3,34 @@
set -e
CI_DIR="$(git rev-parse --show-toplevel)/tools/ci/"
echo "==> Building image: clang_format"
docker build -t clang_format -f $CI_DIR/static_analysis/clang_format.dockerfile .
echo "==> Building image: static_analysis"
docker build -t clang_tidy -f $CI_DIR/static_analysis/clang_tidy.dockerfile .
echo "==> Building image: amd64_gcc_unit_tests"
docker build -t amd64_gcc_unit_tests -f $CI_DIR/amd64/gcc/unit_tests.dockerfile .
echo "==> Building image: amd64_gcc_valgrind"
docker build -t amd64_gcc_valgrind -f $CI_DIR/amd64/gcc/valgrind.dockerfile .
echo "==> Building image: amd64_clang_coverage"
echo "===========[ amd64_clang ]==========="]
echo "==> Building amd64_clang_coverage..."
docker build -t amd64_clang_coverage -f $CI_DIR/amd64/clang/coverage.dockerfile .
echo "...DONE <=="
echo "==> Building image: amd64_clang_lsan"
echo "==> Building amd64_clang_lsan..."
docker build -t amd64_clang_lsan -f $CI_DIR/amd64/clang/lsan.dockerfile .
echo "...DONE <=="
echo "==> Building image: amd64_clang_msan"
docker build -t amd64_clang_msan -f $CI_DIR/amd64/clang/msan.dockerfile .
echo "...DONE <=="
echo "==> Building image: clang_format"
docker build -t clang_format -f $CI_DIR/static_analysis/clang_format.dockerfile .
echo "...DONE <=="
echo "==> Building image: static_analysis"
docker build -t clang_tidy -f $CI_DIR/static_analysis/clang_tidy.dockerfile .
echo "...DONE <=="
echo "===========[ amd64_gcc ]==========="]
echo "==> Building image: amd64_gcc_unit_tests"
docker build -t amd64_gcc_unit_tests -f $CI_DIR/amd64/gcc/unit_tests.dockerfile .
echo "...DONE <=="
echo "==> Building image: amd64_gcc_valgrind"
docker build -t amd64_gcc_valgrind -f $CI_DIR/amd64/gcc/valgrind.dockerfile .
echo "...DONE <=="
echo "WOOOOOOOOOOOOOOOOH!!! DONE :D"