Introduce event-based input system
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
BreakBeforeBraces: Mozilla
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BinPackParameters: 'false'
|
||||
BinPackArguments: 'false'
|
||||
ColumnLimit: '100'
|
||||
|
||||
@@ -14,42 +14,28 @@
|
||||
"deprecated": true,
|
||||
"unusedCli": true,
|
||||
"systemVars": false
|
||||
},
|
||||
"errors": {
|
||||
"dev": true,
|
||||
"deprecated": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-mode",
|
||||
"hidden": true,
|
||||
"inherits": "cmake-pedantic",
|
||||
"cacheVariables": {
|
||||
"CMAKE_COLOR_DIAGNOSTICS": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-std",
|
||||
"name": "std",
|
||||
"description": "This preset makes sure the project actually builds with at least the specified standard",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_EXTENSIONS": "OFF"
|
||||
"CMAKE_CXX_EXTENSIONS": "OFF",
|
||||
"CMAKE_CXX_STANDARD": "20",
|
||||
"CMAKE_CXX_STANDARD_REQUIRED": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "flags-unix",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wshadow -Wformat=2 -Wundef"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-unix",
|
||||
"name": "dev",
|
||||
"generator": "Unix Makefiles",
|
||||
"hidden": true,
|
||||
"inherits": ["flags-unix", "ci-std"],
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"inherits": [
|
||||
"std"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#version 330 core
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
in vec3 v_texCoord;
|
||||
|
||||
uniform samplerCube u_skybox;
|
||||
|
||||
void main() {
|
||||
|
||||
vec3 fragmentColor = vec3(texture(u_skybox, v_texCoord));
|
||||
|
||||
f_color = vec4(fragmentColor, 1.0f);
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec3 a_position;
|
||||
|
||||
out vec3 v_texCoord;
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;
|
||||
uniform mat4 u_viewProjectionMatrix;
|
||||
|
||||
void main() {
|
||||
|
||||
gl_Position = u_viewProjectionMatrix * vec4(a_position, 1.0);
|
||||
|
||||
v_texCoord = a_position;
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@ add_library(fever_engine
|
||||
scene/gltf_loader.cpp
|
||||
scene/scene.cpp
|
||||
util/log.cpp
|
||||
window/Window.cpp
|
||||
window/window.cpp
|
||||
)
|
||||
|
||||
target_compile_features(fever_engine PUBLIC cxx_std_20)
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include "core/shader.h"
|
||||
#include "core/time.h"
|
||||
#include "input/input.h"
|
||||
#include "scene/gltf_loader.h"
|
||||
#include "window/Window.h"
|
||||
#include "scene/scene.h"
|
||||
#include "window/window.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <array>
|
||||
@@ -22,27 +22,34 @@
|
||||
|
||||
using namespace entt::literals;
|
||||
|
||||
static constexpr unsigned MAX_FPS = 60;
|
||||
|
||||
Controller::Controller()
|
||||
: m_gameWindow(std::make_shared<Window>()),
|
||||
post_processing_framebuffer(m_gameWindow->physical_dimensions()),
|
||||
m_gltf_loader{.image_cache = m_image_cache,
|
||||
.material_cache = m_material_cache,
|
||||
.mesh_cache = m_mesh_cache,
|
||||
.shader_cache = m_shader_cache,
|
||||
.scene_cache = m_scene_cache,
|
||||
.gltf_mesh_cache = m_gltf_mesh_cache,
|
||||
.gltf_node_cache = m_gltf_node_cache},
|
||||
m_gltf_cache(m_gltf_loader)
|
||||
Controller::Controller() :
|
||||
m_gameWindow(std::make_shared<Window>(event_dispatcher)),
|
||||
post_processing_framebuffer(m_gameWindow->physical_dimensions()),
|
||||
m_gltf_loader{.image_cache = m_image_cache,
|
||||
.material_cache = m_material_cache,
|
||||
.mesh_cache = m_mesh_cache,
|
||||
.shader_cache = m_shader_cache,
|
||||
.scene_cache = m_scene_cache,
|
||||
.gltf_mesh_cache = m_gltf_mesh_cache,
|
||||
.gltf_node_cache = m_gltf_node_cache,
|
||||
.registry = registry},
|
||||
m_gltf_cache(m_gltf_loader),
|
||||
key_listener{.registry = registry},
|
||||
cursor_listener{.registry = registry}
|
||||
{
|
||||
std::filesystem::path document_path("ABeautifulGame.glb");
|
||||
std::filesystem::path document_path("WaterBottle/glTF-Binary/WaterBottle.glb");
|
||||
entt::hashed_string document_hash(document_path.c_str());
|
||||
|
||||
entt::resource<Gltf> gltf_document =
|
||||
m_gltf_cache.load(document_hash, document_path).first->second;
|
||||
|
||||
m_scene = gltf_document->default_scene.value_or(gltf_document->scenes.at(0)).handle();
|
||||
|
||||
Input::State<Input::KeyCode>::init_state(registry);
|
||||
|
||||
event_dispatcher.sink<Window::ResizeEvent>().connect<&Controller::recreate_framebuffer>(this);
|
||||
event_dispatcher.sink<Input::KeyInput>().connect<&Input::KeyListener::key_event>(key_listener);
|
||||
event_dispatcher.sink<Input::MouseMotion>().connect<&Input::CursorListener::cursor_event>(cursor_listener);
|
||||
}
|
||||
|
||||
void Controller::run()
|
||||
@@ -54,41 +61,44 @@ void Controller::run()
|
||||
spdlog::info("Startup complete. Enter game loop.");
|
||||
|
||||
// This is the game loop
|
||||
while (glfwWindowShouldClose(&m_gameWindow->glfw_window()) == GLFW_FALSE) {
|
||||
while (glfwWindowShouldClose(&m_gameWindow->handle()) == GLFW_FALSE) {
|
||||
// --- Timing ---
|
||||
Time::update_delta_time(m_scene->registry());
|
||||
Time::update_delta_time(registry);
|
||||
|
||||
// --- Check events, handle input ---
|
||||
m_gameWindow->clear_mouse_cursor_input();
|
||||
// m_gameWindow->clear_mouse_cursor_input();
|
||||
glfwPollEvents();
|
||||
|
||||
Input::handle_keyboard_input(m_scene->registry(), m_gameWindow->key_input());
|
||||
Input::handle_mouse_cursor_input(m_scene->registry(), m_gameWindow->mouse_cursor_input());
|
||||
Input::handle_mouse_button_input(m_scene->registry(), m_gameWindow->mouse_button_input());
|
||||
m_gameWindow->update_catched_mouse(m_scene->registry());
|
||||
m_gameWindow->update_descriptor(m_scene->registry());
|
||||
|
||||
// --- Update game state ---
|
||||
event_dispatcher.update();
|
||||
|
||||
m_gameWindow->update_descriptor(registry);
|
||||
m_gameWindow->mouse_catching(registry);
|
||||
m_gameWindow->close_on_esc(registry);
|
||||
|
||||
m_scene->update();
|
||||
|
||||
Input::State<Input::KeyCode>::update_state(registry);
|
||||
Input::reset_mouse_motion(registry);
|
||||
|
||||
// --- Render and buffer swap ---
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
post_processing_framebuffer.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
Light::update_lights(m_scene->registry(), standard_material_shader);
|
||||
Render::render(m_scene->registry());
|
||||
Light::update_lights(registry, standard_material_shader);
|
||||
Render::render(registry);
|
||||
|
||||
Framebuffer::unbind();
|
||||
post_processing_framebuffer.draw(post_processing_shader);
|
||||
|
||||
glfwSwapBuffers(&m_gameWindow->glfw_window());
|
||||
|
||||
// Update window size
|
||||
if (m_gameWindow->dimensions_changed()) {
|
||||
auto dimensions = m_gameWindow->physical_dimensions();
|
||||
post_processing_framebuffer = Framebuffer(dimensions);
|
||||
}
|
||||
glfwSwapBuffers(&m_gameWindow->handle());
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::recreate_framebuffer()
|
||||
{
|
||||
auto dimensions = m_gameWindow->physical_dimensions();
|
||||
post_processing_framebuffer = Framebuffer(dimensions);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
#include "core/graphics/framebuffer.h"
|
||||
#include "core/shader.h"
|
||||
#include "entt/entity/fwd.hpp"
|
||||
#include "scene/gltf_loader.h"
|
||||
#include "scene/scene.h"
|
||||
#include "input/input.h"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
@@ -11,9 +12,9 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class Window;
|
||||
class Scene;
|
||||
class Camera;
|
||||
class Window;
|
||||
class Framebuffer;
|
||||
|
||||
class Controller
|
||||
@@ -24,14 +25,19 @@ public:
|
||||
void run();
|
||||
|
||||
private:
|
||||
void recreate_framebuffer();
|
||||
|
||||
std::shared_ptr<Window> m_gameWindow;
|
||||
std::shared_ptr<Scene> m_scene;
|
||||
Shader skybox_shader{"skybox", "data/shaders"};
|
||||
|
||||
Shader post_processing_shader{"post_processing", "data/shaders"};
|
||||
Framebuffer post_processing_framebuffer;
|
||||
|
||||
double m_deltaTime{};
|
||||
entt::registry registry;
|
||||
|
||||
entt::dispatcher event_dispatcher{};
|
||||
Input::KeyListener key_listener;
|
||||
Input::CursorListener cursor_listener;
|
||||
|
||||
// Resource caches
|
||||
entt::resource_cache<Image> m_image_cache;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "camera.h"
|
||||
#include "core/time.h"
|
||||
#include "input/input.h"
|
||||
#include "window/Window.h"
|
||||
#include "window/window.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <algorithm>
|
||||
@@ -40,7 +40,7 @@ void Camera::keyboard_movement(entt::registry& registry)
|
||||
};
|
||||
|
||||
auto& movement_context = registry.ctx().emplace<KeyboardMovementContext>();
|
||||
auto const& key_input = registry.ctx().get<Input::Key>();
|
||||
auto const& key_state = registry.ctx().get<Input::State<Input::KeyCode>>();
|
||||
auto const& delta_time = registry.ctx().get<Time::Delta>();
|
||||
|
||||
auto camera_view = registry.view<Camera const, Transform, GlobalTransform const>();
|
||||
@@ -55,29 +55,28 @@ void Camera::keyboard_movement(entt::registry& registry)
|
||||
SPEED * delta_time.delta.count() * (movement_context.accelerate ? ACCELERATION : 1.0F);
|
||||
movement_context.accelerate = false;
|
||||
|
||||
for (auto const& [key, pressed] : key_input.key_map) {
|
||||
if (key == GLFW_KEY_W && pressed) {
|
||||
delta_pos += delta_factor * glm::normalize(front_vec);
|
||||
}
|
||||
if (key == GLFW_KEY_S && pressed) {
|
||||
delta_pos -= delta_factor * glm::normalize(front_vec);
|
||||
}
|
||||
if (key == GLFW_KEY_A && pressed) {
|
||||
delta_pos -= delta_factor * glm::normalize(glm::cross(front_vec, Camera::UP_VECTOR));
|
||||
}
|
||||
if (key == GLFW_KEY_D && pressed) {
|
||||
delta_pos += delta_factor * glm::normalize(glm::cross(front_vec, Camera::UP_VECTOR));
|
||||
}
|
||||
if (key == GLFW_KEY_SPACE && pressed) {
|
||||
delta_pos += delta_factor * UP_VECTOR;
|
||||
}
|
||||
if (key == GLFW_KEY_LEFT_SHIFT && pressed) {
|
||||
delta_pos -= delta_factor * UP_VECTOR;
|
||||
}
|
||||
if (key == GLFW_KEY_LEFT_ALT && pressed) {
|
||||
movement_context.accelerate = true;
|
||||
}
|
||||
if (key_state.pressed(Input::KeyCode{GLFW_KEY_W})) {
|
||||
delta_pos += delta_factor * glm::normalize(front_vec);
|
||||
}
|
||||
if (key_state.pressed(Input::KeyCode{GLFW_KEY_S})) {
|
||||
delta_pos -= delta_factor * glm::normalize(front_vec);
|
||||
}
|
||||
if (key_state.pressed(Input::KeyCode{GLFW_KEY_A})) {
|
||||
delta_pos -= delta_factor * glm::normalize(glm::cross(front_vec, Camera::UP_VECTOR));
|
||||
}
|
||||
if (key_state.pressed(Input::KeyCode{GLFW_KEY_D})) {
|
||||
delta_pos += delta_factor * glm::normalize(glm::cross(front_vec, Camera::UP_VECTOR));
|
||||
}
|
||||
if (key_state.pressed(Input::KeyCode{GLFW_KEY_SPACE})) {
|
||||
delta_pos += delta_factor * UP_VECTOR;
|
||||
}
|
||||
if (key_state.pressed(Input::KeyCode{GLFW_KEY_LEFT_SHIFT})) {
|
||||
delta_pos -= delta_factor * UP_VECTOR;
|
||||
}
|
||||
if (key_state.pressed(Input::KeyCode{GLFW_KEY_LEFT_ALT})) {
|
||||
movement_context.accelerate = true;
|
||||
}
|
||||
|
||||
camera_transform.translation += delta_pos;
|
||||
}
|
||||
|
||||
@@ -87,16 +86,12 @@ void Camera::mouse_orientation(entt::registry& registry)
|
||||
auto camera_entity = camera_view.front();
|
||||
auto [camera, camera_transform] = camera_view.get(camera_entity);
|
||||
|
||||
auto const& mouse_cursor_input = registry.ctx().get<Input::MouseCursor>();
|
||||
auto [deltaX, deltaY] = mouse_cursor_input.cursor_movement;
|
||||
auto const& mouse_cursor_input = registry.ctx().get<Input::MouseMotion>();
|
||||
auto delta_x = mouse_cursor_input.delta.x;
|
||||
auto delta_y = mouse_cursor_input.delta.y;
|
||||
|
||||
if (std::abs(deltaX) < std::numeric_limits<double>::epsilon() &&
|
||||
std::abs(deltaY) < std::numeric_limits<double>::epsilon()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pitch = static_cast<float>(deltaY);
|
||||
auto yaw = static_cast<float>(deltaX);
|
||||
auto pitch = static_cast<float>(-delta_y);
|
||||
auto yaw = static_cast<float>(delta_x);
|
||||
|
||||
// Orthographic projection currently unsupported
|
||||
auto& camera_perspective = std::get<Perspective>(camera.projection);
|
||||
|
||||
@@ -1,21 +1,44 @@
|
||||
#include "input.h"
|
||||
|
||||
void Input::handle_keyboard_input(entt::registry ®istry, Key const &key_input)
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace Input {
|
||||
|
||||
void KeyListener::key_event(KeyInput const& key_input_event)
|
||||
{
|
||||
registry.ctx().erase<Key>();
|
||||
registry.ctx().emplace<Key>(key_input);
|
||||
auto& key_state = registry.ctx().emplace<State<KeyCode>>();
|
||||
|
||||
if (key_input_event.action == static_cast<Action>(GLFW_PRESS)) {
|
||||
key_state.press(key_input_event.key_code);
|
||||
} else if (key_input_event.action == static_cast<Action>(GLFW_RELEASE)) {
|
||||
key_state.release(key_input_event.key_code);
|
||||
}
|
||||
}
|
||||
|
||||
void Input::handle_mouse_button_input(entt::registry ®istry,
|
||||
MouseButton const &mouse_button_input)
|
||||
void CursorListener::cursor_event(MouseMotion const& mouse_motion_event)
|
||||
{
|
||||
registry.ctx().erase<MouseButton>();
|
||||
registry.ctx().emplace<MouseButton>(mouse_button_input);
|
||||
auto& mouse_motion = registry.ctx().emplace<MouseMotion>();
|
||||
mouse_motion.delta += mouse_motion_event.delta;
|
||||
}
|
||||
|
||||
void Input::handle_mouse_cursor_input(entt::registry ®istry,
|
||||
MouseCursor const &mouse_cursor_input)
|
||||
void reset_mouse_motion(entt::registry& registry)
|
||||
{
|
||||
registry.ctx().erase<MouseCursor>();
|
||||
registry.ctx().emplace<MouseCursor>(mouse_cursor_input);
|
||||
auto& mouse_motion = registry.ctx().emplace<MouseMotion>();
|
||||
mouse_motion = {};
|
||||
}
|
||||
|
||||
template <typename T> void State<T>::init_state(entt::registry& registry)
|
||||
{
|
||||
registry.ctx().emplace<State<T>>();
|
||||
}
|
||||
|
||||
template <typename T> void State<T>::update_state(entt::registry& registry)
|
||||
{
|
||||
auto& state = registry.ctx().get<State<T>>();
|
||||
state.just_pressed_keys.clear();
|
||||
state.just_released_keys.clear();
|
||||
}
|
||||
|
||||
template class State<KeyCode>;
|
||||
|
||||
} // namespace Input
|
||||
|
||||
@@ -1,27 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "entt/entity/fwd.hpp"
|
||||
#include <entt/entt.hpp>
|
||||
#include <unordered_map>
|
||||
#include <glm/glm.hpp>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
namespace Input {
|
||||
|
||||
struct Key
|
||||
enum class KeyCode : int
|
||||
{
|
||||
std::unordered_map<int, bool> key_map;
|
||||
};
|
||||
|
||||
struct MouseButton
|
||||
enum class Action : int
|
||||
{
|
||||
std::unordered_map<int, bool> button_map;
|
||||
};
|
||||
struct MouseCursor
|
||||
{
|
||||
std::pair<double, double> cursor_movement;
|
||||
};
|
||||
|
||||
void handle_keyboard_input(entt::registry ®istry, Key const &key_input);
|
||||
void handle_mouse_button_input(entt::registry ®istry, MouseButton const &mouse_button_input);
|
||||
void handle_mouse_cursor_input(entt::registry ®istry, MouseCursor const &mouse_cursor_input);
|
||||
struct KeyInput
|
||||
{
|
||||
KeyCode key_code;
|
||||
Action action;
|
||||
};
|
||||
|
||||
struct MouseMotion
|
||||
{
|
||||
glm::vec2 delta{};
|
||||
};
|
||||
|
||||
template <typename T> class State
|
||||
{
|
||||
public:
|
||||
auto pressed(T input) const -> bool { return pressed_keys.contains(input); }
|
||||
auto just_pressed(T input) const -> bool { return just_pressed_keys.contains(input); }
|
||||
auto just_released(T input) const -> bool { return just_pressed_keys.contains(input); }
|
||||
|
||||
static void init_state(entt::registry& registry);
|
||||
static void update_state(entt::registry& registry);
|
||||
|
||||
private:
|
||||
void press(T input)
|
||||
{
|
||||
if (pressed_keys.insert(input).second) {
|
||||
just_pressed_keys.insert(input);
|
||||
}
|
||||
}
|
||||
|
||||
void release(T input)
|
||||
{
|
||||
if (pressed_keys.erase(input) != 0) {
|
||||
just_released_keys.insert(input);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<T> pressed_keys;
|
||||
std::set<T> just_pressed_keys;
|
||||
std::set<T> just_released_keys;
|
||||
|
||||
friend class KeyListener;
|
||||
friend class CursorListener;
|
||||
};
|
||||
|
||||
struct KeyListener
|
||||
{
|
||||
entt::registry& registry;
|
||||
void key_event(KeyInput const& key_input_event);
|
||||
};
|
||||
|
||||
struct CursorListener
|
||||
{
|
||||
entt::registry& registry;
|
||||
void cursor_event(MouseMotion const& mouse_motion_event);
|
||||
};
|
||||
|
||||
void reset_mouse_motion(entt::registry& registry);
|
||||
|
||||
}; // namespace Input
|
||||
|
||||
@@ -405,13 +405,10 @@ auto GltfLoader::operator()(std::filesystem::path const& document_path) -> resul
|
||||
spdlog::warn("glTF scene has no name.");
|
||||
}
|
||||
|
||||
entt::registry registry;
|
||||
|
||||
// Spawn an entity for every node in scene
|
||||
for (auto const& node : nodes) {
|
||||
std::function<entt::entity(GltfNode const&, std::optional<entt::entity>)> spawn_node =
|
||||
[this, &spawn_node, ®istry](GltfNode const& node,
|
||||
std::optional<entt::entity> parent) {
|
||||
[this, &spawn_node](GltfNode const& node, std::optional<entt::entity> parent) {
|
||||
auto entity = registry.create();
|
||||
registry.emplace<Name>(entity, node.name);
|
||||
registry.emplace<Transform>(entity, node.transform);
|
||||
@@ -475,7 +472,7 @@ auto GltfLoader::operator()(std::filesystem::path const& document_path) -> resul
|
||||
|
||||
entt::hashed_string scene_hash(gltf_scene.name.c_str());
|
||||
entt::resource<Scene> scene_resource =
|
||||
scene_cache.load(scene_hash, Scene{std::move(registry)}).first->second;
|
||||
scene_cache.load(scene_hash, Scene{registry}).first->second;
|
||||
scenes.push_back(scene_resource);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "entt/entity/fwd.hpp"
|
||||
#include "gltf.h"
|
||||
#include "components/transform.h"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
#include <filesystem>
|
||||
@@ -9,18 +9,20 @@
|
||||
|
||||
static constexpr auto MAX_SIZE = 512 * 1024 * 1024;
|
||||
|
||||
struct GltfLoader final
|
||||
struct GltfLoader
|
||||
{
|
||||
using result_type = std::shared_ptr<Gltf>;
|
||||
|
||||
auto operator()(std::filesystem::path const &document_path) -> result_type;
|
||||
auto operator()(std::filesystem::path const& document_path) -> result_type;
|
||||
|
||||
entt::resource_cache<Image> &image_cache;
|
||||
entt::resource_cache<Material> &material_cache;
|
||||
entt::resource_cache<Mesh> &mesh_cache;
|
||||
entt::resource_cache<Shader, ShaderLoader> &shader_cache;
|
||||
entt::resource_cache<Scene> &scene_cache;
|
||||
entt::resource_cache<Image>& image_cache;
|
||||
entt::resource_cache<Material>& material_cache;
|
||||
entt::resource_cache<Mesh>& mesh_cache;
|
||||
entt::resource_cache<Shader, ShaderLoader>& shader_cache;
|
||||
entt::resource_cache<Scene>& scene_cache;
|
||||
|
||||
entt::resource_cache<GltfMesh> &gltf_mesh_cache;
|
||||
entt::resource_cache<GltfNode> &gltf_node_cache;
|
||||
entt::resource_cache<GltfMesh>& gltf_mesh_cache;
|
||||
entt::resource_cache<GltfNode>& gltf_node_cache;
|
||||
|
||||
entt::registry& registry;
|
||||
};
|
||||
|
||||
@@ -2,55 +2,56 @@
|
||||
#include "components/name.h"
|
||||
#include "components/transform.h"
|
||||
#include "core/camera.h"
|
||||
#include "core/graphics/material.h"
|
||||
#include "core/graphics/mesh.h"
|
||||
#include "core/light.h"
|
||||
#include "window/Window.h"
|
||||
#include "window/window.h"
|
||||
|
||||
Scene::Scene(entt::registry registry) : m_registry(std::move(registry))
|
||||
Scene::Scene(entt::registry& registry) : registry(registry)
|
||||
{
|
||||
auto mesh_view = m_registry.view<entt::resource<Mesh>>();
|
||||
auto mesh_view = registry.view<entt::resource<Mesh>>();
|
||||
for (auto [entity, mesh] : mesh_view.each()) {
|
||||
m_registry.emplace<GpuMesh>(entity, GpuMesh(mesh));
|
||||
registry.emplace<GpuMesh>(entity, GpuMesh(mesh));
|
||||
|
||||
// Remove Mesh resource as it is no longer needed.
|
||||
m_registry.erase<entt::resource<Mesh>>(entity);
|
||||
registry.erase<entt::resource<Mesh>>(entity);
|
||||
}
|
||||
|
||||
auto material_view = m_registry.view<entt::resource<Material>>();
|
||||
auto material_view = registry.view<entt::resource<Material>>();
|
||||
for (auto [entity, material] : material_view.each()) {
|
||||
m_registry.emplace<GpuMaterial>(entity, GpuMaterial(material));
|
||||
registry.emplace<GpuMaterial>(entity, GpuMaterial(material));
|
||||
|
||||
// Remove Material resource as it is no longer needed.
|
||||
m_registry.erase<entt::resource<Material>>(entity);
|
||||
registry.erase<entt::resource<Material>>(entity);
|
||||
}
|
||||
|
||||
// Spawn default lights
|
||||
auto directional_light = m_registry.create();
|
||||
m_registry.emplace<Name>(directional_light, "Directional Light");
|
||||
m_registry.emplace<Transform>(
|
||||
auto directional_light = registry.create();
|
||||
registry.emplace<Name>(directional_light, "Directional Light");
|
||||
registry.emplace<Transform>(
|
||||
directional_light,
|
||||
Transform{.orientation = glm::toQuat(
|
||||
glm::lookAt({}, DirectionalLight::DEFAULT_DIRECTION, Camera::UP_VECTOR))});
|
||||
m_registry.emplace<GlobalTransform>(directional_light, GlobalTransform{});
|
||||
m_registry.emplace<DirectionalLight>(
|
||||
registry.emplace<GlobalTransform>(directional_light, GlobalTransform{});
|
||||
registry.emplace<DirectionalLight>(
|
||||
directional_light, DirectionalLight{.illuminance = DirectionalLight::DEFAULT_ILLUMINANCE});
|
||||
|
||||
auto point_light = m_registry.create();
|
||||
m_registry.emplace<Name>(point_light, "Point Light");
|
||||
m_registry.emplace<Transform>(point_light,
|
||||
Transform{.translation = PointLight::DEFAULT_POSITION});
|
||||
m_registry.emplace<GlobalTransform>(point_light, GlobalTransform{});
|
||||
m_registry.emplace<PointLight>(point_light,
|
||||
PointLight{.intensity = PointLight::DEFAULT_INTENSITY});
|
||||
auto point_light = registry.create();
|
||||
registry.emplace<Name>(point_light, "Point Light");
|
||||
registry.emplace<Transform>(point_light,
|
||||
Transform{.translation = PointLight::DEFAULT_POSITION});
|
||||
registry.emplace<GlobalTransform>(point_light, GlobalTransform{});
|
||||
registry.emplace<PointLight>(point_light,
|
||||
PointLight{.intensity = PointLight::DEFAULT_INTENSITY});
|
||||
}
|
||||
|
||||
void Scene::update()
|
||||
{
|
||||
GlobalTransform::update(m_registry);
|
||||
Camera::aspect_ratio_update(m_registry);
|
||||
Camera::keyboard_movement(m_registry);
|
||||
GlobalTransform::update(registry);
|
||||
Camera::aspect_ratio_update(registry);
|
||||
Camera::keyboard_movement(registry);
|
||||
|
||||
if (m_registry.ctx().get<Window::MouseCatched>().catched) {
|
||||
Camera::mouse_orientation(m_registry);
|
||||
if (registry.ctx().get<Window::MouseCatched>().catched) {
|
||||
Camera::mouse_orientation(registry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "gltf.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
class Scene
|
||||
{
|
||||
public:
|
||||
Scene(entt::registry registry);
|
||||
Scene(entt::registry& registry);
|
||||
|
||||
void update();
|
||||
auto registry() -> auto & { return m_registry; }
|
||||
|
||||
private:
|
||||
entt::registry m_registry;
|
||||
entt::registry& registry;
|
||||
};
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
#include "Window.h"
|
||||
#include "core/glad.h"
|
||||
|
||||
#include <glad/gl.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
static constexpr unsigned INIT_WINDOW_WIDTH = 1280;
|
||||
static constexpr unsigned INIT_WINDOW_HEIGHT = 720;
|
||||
|
||||
Window::Window()
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
#ifndef NDEBUG
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
|
||||
#else
|
||||
// Maximize in release build
|
||||
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
|
||||
#endif
|
||||
|
||||
m_glfw_window = std::shared_ptr<GLFWwindow>(
|
||||
glfwCreateWindow(INIT_WINDOW_WIDTH, INIT_WINDOW_HEIGHT, "OpenGL", nullptr, nullptr),
|
||||
[](GLFWwindow* window) { glfwDestroyWindow(window); });
|
||||
|
||||
if (!m_glfw_window) {
|
||||
spdlog::critical("Failed to create window");
|
||||
}
|
||||
|
||||
// Create OpenGL context
|
||||
glfwMakeContextCurrent(m_glfw_window.get());
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Disable mouse cursor
|
||||
m_mouse_catched.catched = false;
|
||||
#endif
|
||||
|
||||
set_catched_cursor(m_mouse_catched.catched);
|
||||
|
||||
// Callbacks
|
||||
glfwSetWindowUserPointer(m_glfw_window.get(), this);
|
||||
glfwSetKeyCallback(m_glfw_window.get(), key_callback);
|
||||
glfwSetCursorPosCallback(m_glfw_window.get(), mouse_cursor_callback);
|
||||
glfwSetFramebufferSizeCallback(m_glfw_window.get(), framebuffer_size_callback);
|
||||
|
||||
init_glad();
|
||||
}
|
||||
|
||||
auto Window::dimensions_changed() -> bool
|
||||
{
|
||||
bool temp = m_dimensions_changed;
|
||||
m_dimensions_changed = false;
|
||||
return temp;
|
||||
}
|
||||
|
||||
void Window::set_catched_cursor(bool value)
|
||||
{
|
||||
glfwSetInputMode(
|
||||
m_glfw_window.get(), GLFW_CURSOR, value ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL);
|
||||
|
||||
m_mouse_catched.catched = value;
|
||||
}
|
||||
|
||||
void Window::glfw_error_callback(int error, char const* description)
|
||||
{
|
||||
spdlog::warn("GLFW [{:d}]: {:s}\n", error, description);
|
||||
}
|
||||
|
||||
void Window::framebuffer_size_callback(GLFWwindow* glfw_window, int width, int height)
|
||||
{
|
||||
auto& window = *static_cast<Window*>(glfwGetWindowUserPointer(glfw_window));
|
||||
window.m_dimensions_changed = true;
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
void Window::key_callback(GLFWwindow* glfw_window,
|
||||
int key,
|
||||
[[maybe_unused]] int scancode,
|
||||
int action,
|
||||
[[maybe_unused]] int mods)
|
||||
{
|
||||
auto& window = *static_cast<Window*>(glfwGetWindowUserPointer(glfw_window));
|
||||
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
||||
glfwSetWindowShouldClose(glfw_window, GLFW_TRUE);
|
||||
} else if (key == GLFW_KEY_LEFT_CONTROL && action == GLFW_PRESS) {
|
||||
window.set_catched_cursor(!window.m_mouse_catched.catched);
|
||||
} else if (key == GLFW_KEY_O && action == GLFW_PRESS) {
|
||||
window.m_wire_frame_mode = !window.m_wire_frame_mode;
|
||||
glPolygonMode(GL_FRONT_AND_BACK, window.m_wire_frame_mode ? GL_LINE : GL_FILL);
|
||||
} else if (action == GLFW_PRESS || action == GLFW_RELEASE) {
|
||||
window.m_key_input.key_map[key] = (action == GLFW_PRESS);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::mouse_cursor_callback(GLFWwindow* glfw_window, double xpos, double ypos)
|
||||
{
|
||||
auto& window = *static_cast<Window*>(glfwGetWindowUserPointer(glfw_window));
|
||||
|
||||
double deltaCursorPosX = xpos - window.m_last_cursor_pos_x;
|
||||
double deltaCursorPosY = -(ypos - window.m_last_cursor_pos_y);
|
||||
|
||||
window.m_last_cursor_pos_x = xpos;
|
||||
window.m_last_cursor_pos_y = ypos;
|
||||
|
||||
// Check if this is the first VALID mouse event after window being resized
|
||||
if (window.m_first_mouse_input &&
|
||||
(std::abs(deltaCursorPosX) >= std::numeric_limits<double>::epsilon() ||
|
||||
std::abs(deltaCursorPosY) >= std::numeric_limits<double>::epsilon())) {
|
||||
window.m_first_mouse_input = false;
|
||||
deltaCursorPosX = 0.0;
|
||||
deltaCursorPosY = 0.0;
|
||||
}
|
||||
|
||||
deltaCursorPosX *= MOUSE_SENSITIVITY;
|
||||
deltaCursorPosY *= MOUSE_SENSITIVITY;
|
||||
|
||||
auto& [deltaX, deltaY] = window.m_mouse_cursor_input.cursor_movement;
|
||||
deltaX += deltaCursorPosX;
|
||||
deltaY += deltaCursorPosY;
|
||||
}
|
||||
|
||||
auto Window::logical_dimensions() const -> glm::u32vec2
|
||||
{
|
||||
int width{};
|
||||
int height{};
|
||||
glfwGetWindowSize(m_glfw_window.get(), &width, &height);
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
auto Window::physical_dimensions() const -> glm::u32vec2
|
||||
{
|
||||
int width{};
|
||||
int height{};
|
||||
glfwGetFramebufferSize(m_glfw_window.get(), &width, &height);
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
void Window::clear_mouse_cursor_input()
|
||||
{
|
||||
m_mouse_cursor_input = {};
|
||||
};
|
||||
|
||||
void Window::update_catched_mouse(entt::registry& registry) const
|
||||
{
|
||||
registry.ctx().erase<MouseCatched>();
|
||||
registry.ctx().emplace<MouseCatched>(m_mouse_catched);
|
||||
}
|
||||
|
||||
void Window::update_descriptor(entt::registry& registry) const
|
||||
{
|
||||
auto dimensions = logical_dimensions();
|
||||
|
||||
registry.ctx().erase<Descriptor>();
|
||||
registry.ctx().emplace<Descriptor>(Descriptor{
|
||||
.logical_dimensions = dimensions,
|
||||
.aspect_ratio = static_cast<float>(dimensions.x) / static_cast<float>(dimensions.y)});
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "input/input.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
class GLFWwindow;
|
||||
|
||||
class Window
|
||||
{
|
||||
public:
|
||||
struct MouseCatched
|
||||
{
|
||||
bool catched = true;
|
||||
};
|
||||
|
||||
struct Descriptor
|
||||
{
|
||||
glm::u32vec2 logical_dimensions;
|
||||
float aspect_ratio{};
|
||||
};
|
||||
|
||||
Window();
|
||||
|
||||
[[nodiscard]] auto glfw_window() -> GLFWwindow& { return *m_glfw_window; }
|
||||
[[nodiscard]] auto physical_dimensions() const -> glm::u32vec2;
|
||||
[[nodiscard]] auto logical_dimensions() const -> glm::u32vec2;
|
||||
[[nodiscard]] auto dimensions_changed() -> bool;
|
||||
[[nodiscard]] auto key_input() const -> auto const& { return m_key_input; }
|
||||
[[nodiscard]] auto mouse_cursor_input() const -> auto const& { return m_mouse_cursor_input; }
|
||||
[[nodiscard]] auto mouse_button_input() const -> auto const& { return m_mouse_button_input; }
|
||||
[[nodiscard]] auto cursor_catched() const -> auto { return m_mouse_catched; }
|
||||
|
||||
void clear_mouse_cursor_input();
|
||||
void update_catched_mouse(entt::registry& registry) const;
|
||||
void update_descriptor(entt::registry& registry) const;
|
||||
|
||||
private:
|
||||
static void key_callback(GLFWwindow* glfw_window, int key, int scancode, int action, int mods);
|
||||
static void mouse_cursor_callback(GLFWwindow* glfw_window, double xpos, double ypos);
|
||||
static void framebuffer_size_callback(GLFWwindow* glfw_window, int width, int height);
|
||||
static void glfw_error_callback(int error, char const* description);
|
||||
|
||||
static constexpr float MOUSE_SENSITIVITY = 0.15F;
|
||||
|
||||
void set_catched_cursor(bool value);
|
||||
|
||||
std::shared_ptr<GLFWwindow> m_glfw_window;
|
||||
|
||||
// <Key, Action>
|
||||
Input::Key m_key_input;
|
||||
Input::MouseButton m_mouse_button_input;
|
||||
Input::MouseCursor m_mouse_cursor_input;
|
||||
|
||||
bool m_dimensions_changed = false;
|
||||
double m_last_cursor_pos_x = 0.0;
|
||||
double m_last_cursor_pos_y = 0.0;
|
||||
|
||||
bool m_first_mouse_input = false;
|
||||
MouseCatched m_mouse_catched;
|
||||
bool m_wire_frame_mode = false;
|
||||
};
|
||||
149
src/window/window.cpp
Normal file
149
src/window/window.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "window.h"
|
||||
#include "core/glad.h"
|
||||
#include "input/input.h"
|
||||
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
static constexpr unsigned INIT_WINDOW_WIDTH = 1280;
|
||||
static constexpr unsigned INIT_WINDOW_HEIGHT = 720;
|
||||
|
||||
Window::Window(entt::dispatcher& event_dispatcher) : event_dispatcher(event_dispatcher)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
#ifndef NDEBUG
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
|
||||
#else
|
||||
// Maximize in release build
|
||||
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
|
||||
#endif
|
||||
|
||||
glfw_window = std::shared_ptr<GLFWwindow>(
|
||||
glfwCreateWindow(INIT_WINDOW_WIDTH, INIT_WINDOW_HEIGHT, "OpenGL", nullptr, nullptr),
|
||||
[](GLFWwindow* window) { glfwDestroyWindow(window); });
|
||||
|
||||
if (!glfw_window) {
|
||||
spdlog::critical("Failed to create window");
|
||||
}
|
||||
|
||||
// Create OpenGL context
|
||||
glfwMakeContextCurrent(glfw_window.get());
|
||||
|
||||
// Callbacks
|
||||
glfwSetWindowUserPointer(glfw_window.get(), this);
|
||||
glfwSetKeyCallback(glfw_window.get(), key_callback);
|
||||
glfwSetCursorPosCallback(glfw_window.get(), mouse_cursor_callback);
|
||||
glfwSetFramebufferSizeCallback(glfw_window.get(), framebuffer_size_callback);
|
||||
|
||||
init_glad();
|
||||
}
|
||||
|
||||
void Window::glfw_error_callback(int error, char const* description)
|
||||
{
|
||||
spdlog::warn("GLFW [{:d}]: {:s}\n", error, description);
|
||||
}
|
||||
|
||||
void Window::framebuffer_size_callback(GLFWwindow* glfw_window, int width, int height)
|
||||
{
|
||||
auto& window = *static_cast<Window*>(glfwGetWindowUserPointer(glfw_window));
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
window.event_dispatcher.enqueue<ResizeEvent>();
|
||||
}
|
||||
|
||||
void Window::key_callback(GLFWwindow* glfw_window,
|
||||
int key,
|
||||
[[maybe_unused]] int scancode,
|
||||
int action,
|
||||
[[maybe_unused]] int mods)
|
||||
{
|
||||
auto& window = *static_cast<Window*>(glfwGetWindowUserPointer(glfw_window));
|
||||
|
||||
window.event_dispatcher.enqueue<Input::KeyInput>(
|
||||
Input::KeyInput{.key_code = static_cast<Input::KeyCode>(key),
|
||||
.action = static_cast<Input::Action>(action)});
|
||||
}
|
||||
|
||||
void Window::mouse_cursor_callback(GLFWwindow* glfw_window, double xpos, double ypos)
|
||||
{
|
||||
auto& window = *static_cast<Window*>(glfwGetWindowUserPointer(glfw_window));
|
||||
|
||||
glm::vec2 delta{xpos - window.last_cursor_pos.x, ypos - window.last_cursor_pos.y};
|
||||
|
||||
window.last_cursor_pos = {xpos, ypos};
|
||||
delta *= MOUSE_SENSITIVITY;
|
||||
|
||||
// Check if this is the first VALID mouse event after window being resized
|
||||
if (window.first_mouse_input && (delta.x >= std::numeric_limits<double>::epsilon() ||
|
||||
delta.y >= std::numeric_limits<double>::epsilon())) {
|
||||
window.first_mouse_input = false;
|
||||
return;
|
||||
}
|
||||
|
||||
window.event_dispatcher.enqueue<Input::MouseMotion>(Input::MouseMotion{.delta = delta});
|
||||
}
|
||||
|
||||
auto Window::logical_dimensions() const -> glm::u32vec2
|
||||
{
|
||||
int width{};
|
||||
int height{};
|
||||
glfwGetWindowSize(glfw_window.get(), &width, &height);
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
auto Window::physical_dimensions() const -> glm::u32vec2
|
||||
{
|
||||
int width{};
|
||||
int height{};
|
||||
glfwGetFramebufferSize(glfw_window.get(), &width, &height);
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
void Window::mouse_catching(entt::registry& registry) const
|
||||
{
|
||||
if (!registry.ctx().contains<MouseCatched>()) {
|
||||
bool catched = true;
|
||||
|
||||
#ifndef NDEBUG
|
||||
catched = false;
|
||||
#endif
|
||||
|
||||
registry.ctx().emplace<MouseCatched>(MouseCatched{.catched = catched});
|
||||
}
|
||||
|
||||
auto& mouse_catched = registry.ctx().get<MouseCatched>();
|
||||
auto const& key_state = registry.ctx().get<Input::State<Input::KeyCode>>();
|
||||
|
||||
if (key_state.just_pressed(Input::KeyCode{GLFW_KEY_LEFT_CONTROL})) {
|
||||
mouse_catched.catched = !mouse_catched.catched;
|
||||
|
||||
glfwSetInputMode(glfw_window.get(),
|
||||
GLFW_CURSOR,
|
||||
mouse_catched.catched ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::close_on_esc(entt::registry& registry) const
|
||||
{
|
||||
auto const& key_state = registry.ctx().get<Input::State<Input::KeyCode>>();
|
||||
|
||||
if (key_state.just_pressed(Input::KeyCode{GLFW_KEY_ESCAPE})) {
|
||||
glfwSetWindowShouldClose(glfw_window.get(), GLFW_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::update_descriptor(entt::registry& registry) const
|
||||
{
|
||||
auto dimensions = logical_dimensions();
|
||||
|
||||
registry.ctx().erase<Descriptor>();
|
||||
registry.ctx().emplace<Descriptor>(Descriptor{
|
||||
.logical_dimensions = dimensions,
|
||||
.aspect_ratio = static_cast<float>(dimensions.x) / static_cast<float>(dimensions.y)});
|
||||
}
|
||||
52
src/window/window.h
Normal file
52
src/window/window.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
class GLFWwindow;
|
||||
|
||||
class Window
|
||||
{
|
||||
public:
|
||||
struct MouseCatched
|
||||
{
|
||||
bool catched = true;
|
||||
};
|
||||
|
||||
struct Descriptor
|
||||
{
|
||||
glm::u32vec2 logical_dimensions;
|
||||
float aspect_ratio{};
|
||||
};
|
||||
|
||||
struct ResizeEvent
|
||||
{};
|
||||
|
||||
Window(entt::dispatcher& event_dispatcher);
|
||||
|
||||
[[nodiscard]] auto handle() -> GLFWwindow& { return *glfw_window; }
|
||||
[[nodiscard]] auto physical_dimensions() const -> glm::u32vec2;
|
||||
[[nodiscard]] auto logical_dimensions() const -> glm::u32vec2;
|
||||
|
||||
void update_descriptor(entt::registry& registry) const;
|
||||
void mouse_catching(entt::registry& registry) const;
|
||||
void close_on_esc(entt::registry& registry) const;
|
||||
|
||||
private:
|
||||
static void key_callback(GLFWwindow* glfw_window, int key, int scancode, int action, int mods);
|
||||
static void mouse_cursor_callback(GLFWwindow* glfw_window, double xpos, double ypos);
|
||||
static void framebuffer_size_callback(GLFWwindow* glfw_window, int width, int height);
|
||||
static void glfw_error_callback(int error, char const* description);
|
||||
|
||||
static constexpr float MOUSE_SENSITIVITY = 0.15F;
|
||||
|
||||
std::shared_ptr<GLFWwindow> glfw_window;
|
||||
|
||||
entt::dispatcher& event_dispatcher;
|
||||
|
||||
glm::vec2 last_cursor_pos{};
|
||||
bool first_mouse_input = true;
|
||||
};
|
||||
Reference in New Issue
Block a user