diff --git a/resources/meshes/translation_arrow.fbx b/resources/meshes/translation_arrow.fbx new file mode 100644 index 0000000..ec259a8 Binary files /dev/null and b/resources/meshes/translation_arrow.fbx differ diff --git a/resources/shaders/3d_project.vert b/resources/shaders/3d_project.vert new file mode 100644 index 0000000..cc0f1b0 --- /dev/null +++ b/resources/shaders/3d_project.vert @@ -0,0 +1,11 @@ +#version 460 core + +layout(location = 0) in vec3 i_vertex_position; + +uniform mat4 u_model_matrix; +uniform mat4 u_vp_matrix; + +void main() +{ + gl_Position = u_vp_matrix * u_model_matrix * vec4(i_vertex_position, 1.0); +} diff --git a/resources/shaders/grid.frag b/resources/shaders/grid.frag new file mode 100644 index 0000000..e180223 --- /dev/null +++ b/resources/shaders/grid.frag @@ -0,0 +1,27 @@ +#version 460 core + +in vec2 fragment_position; +flat in int line_segment_index; + +uniform float u_grid_size; +uniform int u_grid_count; + +out vec4 o_color; + +vec3 lighten(vec3 color, float percent) { return color * percent; } + +float is_nth(int i, int n) { return (1 - sign(i % n - .5)) / 2.0; } + +void main() +{ + vec3 color = vec3(0.4); + const float max_distance = (u_grid_count / 4) * u_grid_size; + + float nth = is_nth(abs(line_segment_index), 10); + color = lighten(color, 1.0 + nth * .5); + + float falloff = 1 - distance(fragment_position, vec2(0)) / max_distance; + falloff = clamp(falloff, 0, 1); + + o_color = vec4(color, falloff); +} diff --git a/resources/shaders/grid.vert b/resources/shaders/grid.vert new file mode 100644 index 0000000..61f7476 --- /dev/null +++ b/resources/shaders/grid.vert @@ -0,0 +1,55 @@ +#version 460 core + +layout(location = 0) in vec2 i_vertex_position; + +uniform vec3 u_grid_origin; +uniform mat4 u_model_matrix; +uniform mat4 u_vp_matrix; +uniform float u_grid_size; +uniform int u_grid_count; + +out vec2 fragment_position; +flat out int line_segment_index; + +void main() +{ + const int grid_count_half = u_grid_count / 2; + const int grid_count_quarter = u_grid_count / 4; + + /* + Determine, whether the x and y coordinates should be swapped. + Basically, the upper half number of instances will be used as y axis + grid. + */ + int switch_factor = gl_InstanceID / grid_count_half; + + /* + Calculates the the index of the line in the axis range. Counts from 0. + */ + int index_per_axis = gl_InstanceID % grid_count_half; + + /* + Calculate the displacement across the axis. + */ + int symmetric_index = index_per_axis - grid_count_quarter; + float position_per_axis = symmetric_index * u_grid_size; + + vec2 pos = i_vertex_position; + pos.x = position_per_axis; + + /* + Calculate the length of each line, so that the grid closes complete + */ + pos.y *= u_grid_size * grid_count_quarter; + + /* + Based on the instance id, determine whether this is an x axis or y axis + grid line + */ + pos = mix(pos.xy, pos.yx, switch_factor); + + mat4 mvp = u_vp_matrix * u_model_matrix; + gl_Position = mvp * vec4(pos.x, 0, pos.y, 1); + fragment_position = pos; + line_segment_index = symmetric_index; +} diff --git a/resources/shaders/simple_coloring.frag b/resources/shaders/simple_coloring.frag new file mode 100644 index 0000000..96df5b6 --- /dev/null +++ b/resources/shaders/simple_coloring.frag @@ -0,0 +1,7 @@ +#version 460 core + +uniform vec4 u_color = vec4(1, 0, 1, 1); + +out vec4 o_color; + +void main() { o_color = u_color; } diff --git a/resources/standard/basic_lit.shader b/resources/standard/basic_lit.shader new file mode 100644 index 0000000..546a370 --- /dev/null +++ b/resources/standard/basic_lit.shader @@ -0,0 +1,2 @@ +../shaders/3d_project.vert +../shaders/simple_coloring.frag diff --git a/resources/standard/grid.shader b/resources/standard/grid.shader new file mode 100644 index 0000000..f6d8e51 --- /dev/null +++ b/resources/standard/grid.shader @@ -0,0 +1,2 @@ +../shaders/grid.vert +../shaders/grid.frag diff --git a/resources/standard/line.shader b/resources/standard/line.shader new file mode 100644 index 0000000..546a370 --- /dev/null +++ b/resources/standard/line.shader @@ -0,0 +1,2 @@ +../shaders/3d_project.vert +../shaders/simple_coloring.frag diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 12947cd..5394965 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,6 +62,8 @@ add_library( viewport.cpp window.hpp window.cpp + experimental/editor_window.hpp + experimental/editor_window.cpp experimental/input_system.hpp experimental/input_system.cpp experimental/viewport.hpp diff --git a/src/experimental/editor_window.cpp b/src/experimental/editor_window.cpp new file mode 100644 index 0000000..91658f1 --- /dev/null +++ b/src/experimental/editor_window.cpp @@ -0,0 +1,163 @@ +#include + +#include "experimental/editor_window.hpp" + +#include "asset_manager.hpp" +#include "experimental/input_system.hpp" +#include "renderer_3d.hpp" + +namespace experimental +{ + +editor_window::editor_window() +{ + on_user_initialize += [ this ](auto) { initialize(); }; +} + +editor_window::~editor_window() { } + +void editor_window::initialize() +{ + asset_manager::default_asset_manager()->load_asset( + "resources/standard/grid.shader"); + asset_manager::default_asset_manager()->load_asset( + "resources/standard/line.shader"); + + _camera_position = { 5, 5, 5 }; + _camera_direction = glm::normalize(glm::vec3 { 1, 1, 1 }); + + input_system::on_keypress += [ this ](int keycode) + { + // control local camera movement + switch (keycode) + { + // case GLFW_KEY_D: + // { + // _camera_position.x += .1; + // break; + // } + // case GLFW_KEY_A: + // { + // _camera_position.x -= .1; + // break; + // } + // case GLFW_KEY_SPACE: + // { + // _camera_position.y += .1; + // break; + // } + // case GLFW_KEY_LEFT_CONTROL: + // { + // _camera_position.y -= .1; + // break; + // } + case GLFW_KEY_W: + { + _camera_position -= _camera_direction * .07f; + break; + } + case GLFW_KEY_S: + { + _camera_position += _camera_direction * .07f; + break; + } + } + }; + get_events().render += [ this ](auto re) + { + render_grid(); + render_axis(); + }; + get_events().mouse_move += [ this ](auto me) + { + if (!get_has_grab()) + { + _mouse_position = std::nullopt; + return; + } + + if (!_mouse_position) + { + _mouse_position = me.get_local_position(); + return; + } + + auto diff = me.get_local_position() - _mouse_position.value(); + _mouse_position = me.get_local_position(); + + _camera_direction = + glm::normalize(glm::rotate(glm::rotate(glm::identity(), + glm::radians(diff.x), + glm::vec3(0, 1, 0)), + glm::radians(-diff.y), + glm::vec3(1, 0, 0)) * + _camera_direction); + }; +} + +void editor_window::render_grid() +{ + auto camera_right = + glm::normalize(glm::cross(_camera_direction, { 0, 1, 0 })); + auto camera_up = + glm::normalize(glm::cross(camera_right, _camera_direction)); + auto inverse_view_from_origin = + glm::mat4(glm::mat3(camera_right, camera_up, _camera_direction)); + auto inverse_view = + glm::translate(glm::identity(), _camera_position) * + inverse_view_from_origin; + auto view = glm::inverse(inverse_view); + auto projection = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 100.0f); + + glViewport(0, 0, get_width(), get_height()); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + renderer_3d::draw_grid(0.3f, glm::identity(), view, projection); +} + +void editor_window::render_axis() +{ + auto camera_right = + glm::normalize(glm::cross(_camera_direction, { 0, 1, 0 })); + auto camera_up = + glm::normalize(glm::cross(camera_right, _camera_direction)); + auto inverse_view_from_origin = + glm::mat4(glm::mat3(camera_right, camera_up, _camera_direction)); + auto inverse_view = + glm::translate(glm::identity(), _camera_position) * + inverse_view_from_origin; + auto view = glm::inverse(inverse_view); + auto projection = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 100.0f); + + unsigned axis_viewport_size = 80; + glViewport(get_width() - axis_viewport_size - 20, + get_height() - axis_viewport_size - 20, + axis_viewport_size, + axis_viewport_size); + view = glm::inverse(inverse_view_from_origin); + + renderer_3d::draw_ray(glm::vec3 { -_camera_direction }, + glm::vec3 { 1, 0, 0 }, + 0.3f, + { 1, 0, 0, 1 }, + view, + projection); + renderer_3d::draw_ray(glm::vec3 { -_camera_direction }, + glm::vec3 { 0, 1, 0 }, + 0.3f, + { 0, 1, 0, 1 }, + view, + projection); + renderer_3d::draw_ray(glm::vec3 { -_camera_direction }, + glm::vec3 { 0, 0, 1 }, + 0.3f, + { 0, 0, 1, 1 }, + view, + projection); +} + +} // namespace experimental diff --git a/src/experimental/editor_window.hpp b/src/experimental/editor_window.hpp new file mode 100644 index 0000000..0ae04a2 --- /dev/null +++ b/src/experimental/editor_window.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "experimental/window.hpp" +#include "utils.hpp" + +namespace experimental +{ + +class editor_window + : public window + , public singleton +{ +public: + ~editor_window(); + +private: + editor_window(); + + void initialize(); + void render_grid(); + void render_axis(); + + friend singleton_t; + +private: + glm::vec3 _camera_position; + glm::vec3 _camera_direction; + std::optional _mouse_position; +}; + +} // namespace experimental diff --git a/src/experimental/window.cpp b/src/experimental/window.cpp index 53ab52b..7a37446 100644 --- a/src/experimental/window.cpp +++ b/src/experimental/window.cpp @@ -8,6 +8,7 @@ #include "experimental/window.hpp" +#include "experimental/editor_window.hpp" #include "experimental/window_events.hpp" #include "input_system.hpp" #include "logging.hpp" @@ -37,10 +38,9 @@ struct window::window_private_data GLFWwindow* _glfw_window_handle { nullptr }; glm::uvec2 _size { 800, 600 }; glm::uvec2 _position { 200, 200 }; - std::shared_ptr _events { nullptr }; + window_events _events; std::vector> _viewports; std::string _title { "Window" }; - bool _is_main_window { false }; bool _can_grab { false }; bool _has_grab { false }; bool _is_input_source { false }; @@ -74,12 +74,6 @@ void window::init() } std::string title = _p->_title; - if (!_main_window) - { - _main_window = shared_from_this(); - _p->_is_main_window = true; - _p->_is_input_source = true; - } glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true); glfwWindowHint(GLFW_SAMPLES, 8); @@ -87,12 +81,12 @@ void window::init() glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - _p->_glfw_window_handle = glfwCreateWindow( - static_cast(get_width()), - static_cast(get_height()), - title.c_str(), - nullptr, - _p->_is_main_window ? nullptr : _main_window->_p->_glfw_window_handle); + _p->_glfw_window_handle = + glfwCreateWindow(static_cast(get_width()), + static_cast(get_height()), + title.c_str(), + nullptr, + editor_window::get()->_p->_glfw_window_handle); if (_p->_glfw_window_handle == nullptr) { log()->error("Failed to create GLFW window"); @@ -109,7 +103,7 @@ void window::init() auto _this = static_cast(glfwGetWindowUserPointer(wnd)); glm::uvec2 old_size = _this->_p->_size; _this->_p->_size = { w, h }; - _this->get_events()->resize( + _this->get_events().resize( resize_event(old_size, _this->_p->_size, _this)); }); @@ -119,7 +113,7 @@ void window::init() auto _this = static_cast(glfwGetWindowUserPointer(wnd)); glm::uvec2 old_pos = _this->_p->_position; _this->_p->_position = { xpos, ypos }; - _this->get_events()->move( + _this->get_events().move( move_event(old_pos, _this->_p->_position, _this)); }); @@ -194,9 +188,9 @@ void window::update() if (glfwWindowShouldClose(_p->_glfw_window_handle)) { + get_events().close(close_event(this)); glfwDestroyWindow(_p->_glfw_window_handle); _p->_glfw_window_handle = nullptr; - get_events()->close(close_event(this)); return; } @@ -209,7 +203,7 @@ void window::update() activate(); - get_events()->render(render_event(window_event::type::Render, this)); + get_events().render(render_event(window_event::type::Render, this)); glfwSwapBuffers(_p->_glfw_window_handle); glfwPollEvents(); @@ -255,12 +249,7 @@ std::vector> window::get_viewports() return _p->_viewports; } -std::shared_ptr window::get_events() const -{ - return _p->_events; -} - -std::shared_ptr window::get_main_window() { return _main_window; } +window_events& window::get_events() const { return _p->_events; } void window::setup_mouse_callbacks() { @@ -276,24 +265,25 @@ void window::setup_mouse_enter_callback() [](GLFWwindow* wnd, int entered) { auto _this = static_cast(glfwGetWindowUserPointer(wnd)); - std::shared_ptr events = _this->get_events(); + window_events& events = _this->get_events(); if (entered == 0) { - events->leave(window_event(window_event::type::Leave, _this)); + events.leave(window_event(window_event::type::Leave, _this)); return; } + _this->set_as_input_source(true); glm::dvec2 pos; glfwGetCursorPos(wnd, &pos.x, &pos.y); _this->_p->_mouse_state._position = pos; - events->enter(enter_event(window_event::type::Enter, - _this->_p->_mouse_state._position, - _this->_p->_mouse_state._position, - _this->_p->_mouse_state._position, - 0, - _this->_p->_mouse_state._buttons, - _this->_p->_mouse_state._mods, - _this)); + events.enter(enter_event(window_event::type::Enter, + _this->_p->_mouse_state._position, + _this->_p->_mouse_state._position, + _this->_p->_mouse_state._position, + 0, + _this->_p->_mouse_state._buttons, + _this->_p->_mouse_state._mods, + _this)); }); } @@ -304,7 +294,7 @@ void window::setup_mouse_move_callback() [](GLFWwindow* wnd, double x_position, double y_position) { auto _this = static_cast(glfwGetWindowUserPointer(wnd)); - std::shared_ptr events = _this->get_events(); + window_events& events = _this->get_events(); _this->_p->_mouse_state._position = { x_position, y_position }; if (_this->_p->_mouse_state._buttons) @@ -312,14 +302,14 @@ void window::setup_mouse_move_callback() _this->check_for_drag(); } - events->mouse_move(mouse_event(window_event::type::MouseMove, - _this->_p->_mouse_state._position, - _this->_p->_mouse_state._position, - _this->_p->_mouse_state._position, - 0, - _this->_p->_mouse_state._buttons, - _this->_p->_mouse_state._mods, - _this)); + events.mouse_move(mouse_event(window_event::type::MouseMove, + _this->_p->_mouse_state._position, + _this->_p->_mouse_state._position, + _this->_p->_mouse_state._position, + 0, + _this->_p->_mouse_state._buttons, + _this->_p->_mouse_state._mods, + _this)); if (_this->get_is_input_source()) { @@ -335,21 +325,20 @@ void window::setup_mouse_button_callback() [](GLFWwindow* wnd, int button, int action, int mods) { auto _this = static_cast(glfwGetWindowUserPointer(wnd)); - std::shared_ptr events = _this->get_events(); + window_events& events = _this->get_events(); if (action == GLFW_PRESS) { _this->_p->_mouse_state._press_started_position = _this->_p->_mouse_state._position; _this->_p->_mouse_state._buttons |= (1 << button); - events->mouse_press( - mouse_event(window_event::type::MouseButtonPress, - _this->_p->_mouse_state._position, - _this->_p->_mouse_state._position, - _this->_p->_mouse_state._position, - button, - _this->_p->_mouse_state._buttons, - _this->_p->_mouse_state._mods, - _this)); + events.mouse_press(mouse_event(window_event::type::MouseButtonPress, + _this->_p->_mouse_state._position, + _this->_p->_mouse_state._position, + _this->_p->_mouse_state._position, + button, + _this->_p->_mouse_state._buttons, + _this->_p->_mouse_state._mods, + _this)); if (_this->get_can_grab()) { @@ -360,7 +349,7 @@ void window::setup_mouse_button_callback() { _this->_p->_mouse_state._buttons ^= (1 << button); - events->mouse_release( + events.mouse_release( mouse_event(window_event::type::MouseButtonRelease, _this->_p->_mouse_state._position, _this->_p->_mouse_state._position, @@ -413,19 +402,19 @@ void window::setup_mouse_button_callback() case 1: { event_type = window_event::type::MouseButtonClick; - f = &events->mouse_click; + f = &events.mouse_click; break; } case 2: { event_type = window_event::type::MouseButtonDoubleClick; - f = &events->mouse_double_click; + f = &events.mouse_double_click; break; } case 3: { event_type = window_event::type::MouseButtonTripleClick; - f = &events->mouse_triple_click; + f = &events.mouse_triple_click; break; } default: @@ -461,9 +450,9 @@ void window::setup_mouse_wheel_callback() [](GLFWwindow* wnd, double x_offset, double y_offset) { auto _this = static_cast(glfwGetWindowUserPointer(wnd)); - std::shared_ptr events = _this->get_events(); + window_events& events = _this->get_events(); - events->mouse_scroll(wheel_event( + events.mouse_scroll(wheel_event( window_event::type::MouseWheel, _this->_p->_mouse_state._position, _this->_p->_mouse_state._position, @@ -490,7 +479,6 @@ void window::check_for_drag() void window::configure_input_system() { - _p->_events = std::make_shared(); setup_mouse_callbacks(); glfwSetKeyCallback( @@ -500,7 +488,7 @@ void window::configure_input_system() auto _this = static_cast(glfwGetWindowUserPointer(wnd)); window_event::type type = window_event::type::KeyRelease; - event* f = &_this->_p->_events->key_release; + event* f = &_this->_p->_events.key_release; bool is_repeat = false; _this->_p->_mouse_state._mods = @@ -509,12 +497,12 @@ void window::configure_input_system() if (action == GLFW_PRESS) { type = window_event::type::KeyPress; - f = &_this->_p->_events->key_press; + f = &_this->_p->_events.key_press; } else if (action == GLFW_REPEAT) { type = window_event::type::KeyRepeat; - f = &_this->_p->_events->key_repeat; + f = &_this->_p->_events.key_repeat; is_repeat = true; } (*f)(key_event( @@ -527,6 +515,4 @@ void window::configure_input_system() }); } -std::shared_ptr window::_main_window = nullptr; - } // namespace experimental diff --git a/src/experimental/window.hpp b/src/experimental/window.hpp index 69d1ac1..12487ac 100644 --- a/src/experimental/window.hpp +++ b/src/experimental/window.hpp @@ -55,12 +55,10 @@ class window : public std::enable_shared_from_this void remove_viewport(std::shared_ptr vp); std::vector> get_viewports(); - std::shared_ptr get_events() const; + window_events& get_events() const; event)> on_user_initialize; - static std::shared_ptr get_main_window(); - private: void setup_mouse_callbacks(); @@ -76,8 +74,6 @@ class window : public std::enable_shared_from_this private: struct window_private_data; std::unique_ptr _p { nullptr }; - - static std::shared_ptr _main_window; }; } // namespace experimental diff --git a/src/main.cpp b/src/main.cpp index b56e525..c14b791 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,7 @@ #include "components/text_component.hpp" #include "components/text_renderer_component.hpp" #include "components/walking_component.hpp" +#include "experimental/editor_window.hpp" #include "experimental/input_system.hpp" #include "experimental/viewport.hpp" #include "experimental/window.hpp" @@ -234,26 +235,26 @@ int main(int argc, char** argv) void initMainWindow() { - windows.push_back(std::make_shared()); - auto& wnd = windows.back(); + auto wnd = experimental::editor_window::get(); + windows.push_back(wnd); wnd->on_user_initialize += [](auto) { load_internal_resources(); }; wnd->init(); wnd->resize(800, 800); - wnd->get_events()->close += [](auto ce) + wnd->get_events().close += [](auto ce) { std::erase(windows, ce.get_sender()->shared_from_this()); }; std::shared_ptr vp = std::make_shared(); vp->initialize(); wnd->add_viewport(vp); main_camera = std::make_shared(); vp->set_camera(main_camera); - wnd->get_events()->resize += + wnd->get_events().resize += [ vp ](auto re) { vp->set_size(re.get_new_size()); }; - wnd->get_events()->render += [ vp ](auto re) + wnd->get_events().render += [ vp ](auto re) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); vp->render(); }; - windows.back()->get_events()->resize += [ vp ](auto re) + wnd->get_events().resize += [ vp ](auto re) { vp->set_size( { re.get_sender()->get_width(), re.get_sender()->get_height() }); @@ -269,11 +270,11 @@ void initViewports() auto wnd = windows.back(); wnd->init(); wnd->resize(400, 1200); - windows[ 0 ]->set_position(windows[ 1 ]->get_position().x + - windows[ 1 ]->get_width(), - windows[ 1 ]->get_position().y); + experimental::editor_window::get()->set_position( + windows[ 1 ]->get_position().x + windows[ 1 ]->get_width(), + windows[ 1 ]->get_position().y); - wnd->get_events()->close += [](auto ce) + wnd->get_events().close += [](auto ce) { std::erase(windows, ce.get_sender()->shared_from_this()); }; for (int i = 0; i < _view_cameras.size(); ++i) @@ -285,7 +286,7 @@ void initViewports() vp->set_camera(cam); cam->set_ortho(true); wnd->add_viewport(vp); - wnd->get_events()->mouse_scroll += [ cam, vp ](auto we) + wnd->get_events().mouse_scroll += [ cam, vp ](auto we) { auto pos = we.get_local_position(); pos.y = we.get_sender()->get_height() - pos.y; @@ -300,7 +301,7 @@ void initViewports() cam->get_transform().get_position() * std::pow(1.2, we.get_delta().y)); }; - windows.back()->get_events()->resize += [ vp, i ](auto re) + windows.back()->get_events().resize += [ vp, i ](auto re) { vp->set_size({ re.get_new_size().x, re.get_new_size().y / 3.0 }); vp->set_position({ 0, re.get_new_size().y / 3.0 * i }); @@ -310,7 +311,7 @@ void initViewports() vp->set_position({ 0, wnd->get_height() / 3.0 * i }); } - windows.back()->get_events()->render += [](auto re) + windows.back()->get_events().render += [](auto re) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for (auto vp : re.get_sender()->get_viewports()) @@ -336,8 +337,7 @@ void initViewports() void setupMouseEvents() { - experimental::window::get_main_window()->get_events()->mouse_move += - [](auto me) + experimental::editor_window::get()->get_events().mouse_move += [](auto me) { if (me.get_sender()->get_has_grab()) { diff --git a/src/renderer/renderer_3d.cpp b/src/renderer/renderer_3d.cpp index 106dcfb..6ee9c0f 100644 --- a/src/renderer/renderer_3d.cpp +++ b/src/renderer/renderer_3d.cpp @@ -9,6 +9,8 @@ #include "graphics_buffer.hpp" #include "material.hpp" #include "mesh.hpp" +#include "shader.hpp" +#include "transform.hpp" #include "vaomap.hpp" #include "vertex.hpp" @@ -39,3 +41,160 @@ void renderer_3d::draw_mesh(mesh* m, material* mat) GL_UNSIGNED_INT, 0); } + +void renderer_3d::draw_grid(float grid_size, + const glm::mat4& model, + const glm::mat4& view, + const glm::mat4& proj) +{ + auto sp = prof::profile(__FUNCTION__); + std::array line; + line[ 0 ].position() = glm::vec2 { 0, -1 }; + line[ 1 ].position() = glm::vec2 { 0, 1 }; + std::array indices = { 0, 1 }; + + graphics_buffer vbo(graphics_buffer::type::vertex); + graphics_buffer ebo(graphics_buffer::type::index); + + vbo.set_element_count(2); + vbo.set_element_stride(simple_vertex2d::size); + vbo.set_data(line.data()); + + ebo.set_element_count(2); + ebo.set_element_stride(sizeof(unsigned)); + ebo.set_data(indices.data()); + + // TODO: crashes when changing to instance()._vao.activate() + vao_map vao; + if (vao.activate()) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo.get_handle()); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo.get_handle()); + + simple_vertex2d::initialize_attributes(); + } + + simple_vertex2d::activate_attributes(); + + constexpr int grid_count = 82; + + auto grid_shader = + asset_manager::default_asset_manager()->get_shader("grid"); + grid_shader->set_uniform("u_grid_count", grid_count); + grid_shader->set_uniform("u_grid_size", grid_size / 2.0f); + grid_shader->set_uniform("u_model_matrix", model); + grid_shader->set_uniform("u_vp_matrix", proj * view); + + grid_shader->use(); + glDrawElementsInstanced(GL_LINES, 2, GL_UNSIGNED_INT, nullptr, grid_count); +} + +void renderer_3d::render_transform_controls(transform& t, + const glm::mat4& view, + const glm::mat4& proj) +{ + auto sp = prof::profile(__FUNCTION__); + + auto arrow_mesh = asset_manager::default_asset_manager()->get_mesh( + "translation_arrow_mesh"); + auto shader = + asset_manager::default_asset_manager()->get_shader("basic_lit"); + + vao_map vao; + if (vao.activate()) + { + glBindBuffer(GL_ARRAY_BUFFER, + arrow_mesh->get_vertex_buffer().get_handle()); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, + arrow_mesh->get_index_buffer().get_handle()); + + vertex3d::initialize_attributes(); + } + vertex3d::activate_attributes(); + + shader->set_uniform("u_vp_matrix", proj * view); + shader->set_uniform("u_model_matrix", glm::identity()); + shader->set_uniform("u_color", glm::vec4 { 0.82, 0.33, 0.35, 1.0 }); + shader->use(); + glDrawElements(GL_TRIANGLES, + arrow_mesh->get_index_buffer().get_element_count(), + GL_UNSIGNED_INT, + nullptr); + shader->set_uniform("u_color", glm::vec4 { 0.46, 0.61, 0.11, 1.0 }); + shader->set_uniform("u_model_matrix", + glm::rotate(glm::identity(), + glm::radians(90.0f), + glm::vec3 { 0, 0, 1 })); + shader->use(); + glDrawElements(GL_TRIANGLES, + arrow_mesh->get_index_buffer().get_element_count(), + GL_UNSIGNED_INT, + nullptr); + shader->set_uniform("u_color", glm::vec4 { 0.2, 0.42, 0.64, 1.0 }); + shader->set_uniform("u_model_matrix", + glm::rotate(glm::identity(), + glm::radians(-90.0f), + glm::vec3 { 0, 1, 0 })); + shader->use(); + glDrawElements(GL_TRIANGLES, + arrow_mesh->get_index_buffer().get_element_count(), + GL_UNSIGNED_INT, + nullptr); +} + +void renderer_3d::draw_ray(const glm::vec3& origin, + const glm::vec3& direction, + float length, + const glm::vec4& color, + const glm::mat4& view, + const glm::mat4& proj) +{ + auto sp = prof::profile(__FUNCTION__); + std::array line; + line[ 0 ].position() = origin; + line[ 1 ].position() = origin + glm::normalize(direction) * length; + std::array indices = { 0, 1 }; + + graphics_buffer vbo(graphics_buffer::type::vertex); + graphics_buffer ebo(graphics_buffer::type::index); + + vbo.set_element_count(2); + vbo.set_element_stride(simple_vertex3d::size); + vbo.set_data(line.data()); + + ebo.set_element_count(2); + ebo.set_element_stride(sizeof(unsigned)); + ebo.set_data(indices.data()); + + // TODO: crashes when changing to instance()._vao.activate() + vao_map vao; + if (vao.activate()) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo.get_handle()); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo.get_handle()); + + simple_vertex3d::initialize_attributes(); + } + + simple_vertex3d::activate_attributes(); + + auto line_shader = + asset_manager::default_asset_manager()->get_shader("line"); + line_shader->set_uniform("u_color", color); + line_shader->set_uniform("u_model_matrix", glm::identity()); + line_shader->set_uniform("u_vp_matrix", proj * view); + + line_shader->use(); + glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, nullptr); +} + +renderer_3d& renderer_3d::instance() +{ + if (!_instance) + { + _instance = std::make_unique(); + } + return *_instance; +} + +std::unique_ptr renderer_3d::_instance = nullptr; diff --git a/src/renderer/renderer_3d.hpp b/src/renderer/renderer_3d.hpp index 9ee0b8d..b809be0 100644 --- a/src/renderer/renderer_3d.hpp +++ b/src/renderer/renderer_3d.hpp @@ -11,6 +11,23 @@ class renderer_3d : public renderer public: void draw_mesh(mesh* m, material* mat); + static void draw_grid(float grid_size, + const glm::mat4& model, + const glm::mat4& view, + const glm::mat4& proj); + static void render_transform_controls(transform& t, + const glm::mat4& view, + const glm::mat4& proj); + static void draw_ray(const glm::vec3& origin, + const glm::vec3& direction, + float length, + const glm::vec4& color, + const glm::mat4& view, + const glm::mat4& proj); + + static renderer_3d& instance(); + private: vao_map _vao; + static std::unique_ptr _instance; }; diff --git a/src/samples/multiple_viewports.cpp b/src/samples/multiple_viewports.cpp index 53606b7..cdff99a 100644 --- a/src/samples/multiple_viewports.cpp +++ b/src/samples/multiple_viewports.cpp @@ -72,10 +72,10 @@ int main(int argc, char** argv) exp_window->set_can_grab(true); - exp_window->get_events()->close += [ &windows ](auto ce) + exp_window->get_events().close += [ &windows ](auto ce) { std::erase(windows, ce.get_sender()->shared_from_this()); }; - exp_window->get_events()->resize += [](auto re) + exp_window->get_events().resize += [](auto re) { auto wnd = re.get_sender(); if (auto vp = wnd->get_viewports()[ 0 ]) @@ -85,7 +85,7 @@ int main(int argc, char** argv) }; int frame_counter = 0; - exp_window->get_events()->render += [ &frame_counter ](auto re) + exp_window->get_events().render += [ &frame_counter ](auto re) { if (frame_counter % 30 == 0) { diff --git a/src/samples/scene_load.cpp b/src/samples/scene_load.cpp index 14d59c5..663ebb1 100644 --- a/src/samples/scene_load.cpp +++ b/src/samples/scene_load.cpp @@ -59,10 +59,10 @@ int main(int argc, char** argv) exp_window->set_can_grab(true); - exp_window->get_events()->close += [ &windows ](auto ce) + exp_window->get_events().close += [ &windows ](auto ce) { std::erase(windows, ce.get_sender()->shared_from_this()); }; - exp_window->get_events()->resize += [](auto re) + exp_window->get_events().resize += [](auto re) { auto wnd = re.get_sender(); if (auto vp = wnd->get_viewports()[ 0 ]) @@ -72,7 +72,7 @@ int main(int argc, char** argv) }; int frame_counter = 0; - exp_window->get_events()->render += [ &frame_counter ](auto re) + exp_window->get_events().render += [ &frame_counter ](auto re) { if (frame_counter % 30 == 0) { diff --git a/src/samples/viewport.cpp b/src/samples/viewport.cpp index 7afee72..38e174d 100644 --- a/src/samples/viewport.cpp +++ b/src/samples/viewport.cpp @@ -65,10 +65,10 @@ int main(int argc, char** argv) exp_window->set_can_grab(true); - exp_window->get_events()->close += [ &windows ](auto ce) + exp_window->get_events().close += [ &windows ](auto ce) { std::erase(windows, ce.get_sender()->shared_from_this()); }; - exp_window->get_events()->resize += [](auto re) + exp_window->get_events().resize += [](auto re) { auto wnd = re.get_sender(); if (auto vp = wnd->get_viewports()[ 0 ]) @@ -78,7 +78,7 @@ int main(int argc, char** argv) }; int frame_counter = 0; - exp_window->get_events()->render += [ &frame_counter ](auto re) + exp_window->get_events().render += [ &frame_counter ](auto re) { if (frame_counter % 30 == 0) { diff --git a/src/samples/window.cpp b/src/samples/window.cpp index fc78ff7..7547d62 100644 --- a/src/samples/window.cpp +++ b/src/samples/window.cpp @@ -3,9 +3,9 @@ #include /* clang-format on */ +#include #include #include -#include #include @@ -40,7 +40,7 @@ int main(int argc, char** argv) exp_window->set_can_grab(true); - exp_window->get_events()->close += [ &windows ](auto ce) + exp_window->get_events().close += [ &windows ](auto ce) { (void)ce; assert(ce.get_sender() != nullptr); @@ -48,14 +48,14 @@ int main(int argc, char** argv) std::erase(windows, ce.get_sender()->shared_from_this()); }; - exp_window->get_events()->leave += [](auto ee) + exp_window->get_events().leave += [](auto ee) { (void)ee; assert(ee.get_sender() != nullptr); log()->info("Cursor left the window"); }; - exp_window->get_events()->enter += [](auto ee) + exp_window->get_events().enter += [](auto ee) { assert(ee.get_sender() != nullptr); log()->info("Cursor entered the window at: {}x{}", @@ -63,7 +63,7 @@ int main(int argc, char** argv) ee.get_local_position().y); }; - exp_window->get_events()->move += [](auto me) + exp_window->get_events().move += [](auto me) { assert(me.get_sender() != nullptr); log()->info("Window moved from: {}x{} to: {}x{}", @@ -73,7 +73,7 @@ int main(int argc, char** argv) me.get_new_position().y); }; - exp_window->get_events()->resize += [](auto re) + exp_window->get_events().resize += [](auto re) { assert(re.get_sender() != nullptr); log()->info("Window resized from: {}x{} to: {}x{}", @@ -83,7 +83,7 @@ int main(int argc, char** argv) re.get_new_size().y); }; - exp_window->get_events()->mouse_move += [](auto me) + exp_window->get_events().mouse_move += [](auto me) { assert(me.get_sender() != nullptr); log()->info("Mouse position: {}x{}", @@ -91,55 +91,55 @@ int main(int argc, char** argv) me.get_local_position().y); }; - exp_window->get_events()->mouse_release += [](auto me) + exp_window->get_events().mouse_release += [](auto me) { assert(me.get_sender() != nullptr); log()->info("Mouse release: {}", me.get_button()); }; - exp_window->get_events()->mouse_press += [](auto me) + exp_window->get_events().mouse_press += [](auto me) { assert(me.get_sender() != nullptr); log()->info("Mouse press: {}", me.get_button()); }; - exp_window->get_events()->mouse_click += [](auto me) + exp_window->get_events().mouse_click += [](auto me) { assert(me.get_sender() != nullptr); log()->info("Mouse click: {}", me.get_button()); }; - exp_window->get_events()->mouse_double_click += [](auto me) + exp_window->get_events().mouse_double_click += [](auto me) { assert(me.get_sender() != nullptr); log()->info("Mouse double click: {}", me.get_button()); }; - exp_window->get_events()->mouse_triple_click += [](auto me) + exp_window->get_events().mouse_triple_click += [](auto me) { assert(me.get_sender() != nullptr); log()->info("Mouse triple click: {}", me.get_button()); }; - exp_window->get_events()->mouse_scroll += [](auto we) + exp_window->get_events().mouse_scroll += [](auto we) { assert(we.get_sender() != nullptr); log()->info("Mouse scroll: {}x{}", we.get_delta().x, we.get_delta().y); }; - exp_window->get_events()->key_press += [](auto ke) + exp_window->get_events().key_press += [](auto ke) { assert(ke.get_sender() != nullptr); log()->info("Key pressed: {}", ke.get_scancode()); }; - exp_window->get_events()->key_repeat += [](auto ke) + exp_window->get_events().key_repeat += [](auto ke) { assert(ke.get_sender() != nullptr); log()->info("Key repeated: {}", ke.get_scancode()); }; - exp_window->get_events()->key_release += [](auto ke) + exp_window->get_events().key_release += [](auto ke) { assert(ke.get_sender() != nullptr); log()->info("Key released: {}", ke.get_scancode()); diff --git a/src/utils.hpp b/src/utils.hpp index 8c7b422..8939482 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -45,5 +45,29 @@ bool rect_contains(glm::vec<2, T, glm::defaultp> top_left, return is_in_range(tl.x, br.x, pos.x) && is_in_range(tl.y, br.y, pos.y); } +template +class singleton +{ +public: + static std::shared_ptr get() { return _instance; } + +private: + using singleton_t = singleton; + + singleton() = default; + singleton(const singleton&) = delete; + singleton& operator=(const singleton&) = delete; + singleton(singleton&&) = delete; + singleton& operator=(singleton&&) = delete; + ~singleton() = default; + + friend T; + + static std::shared_ptr _instance; +}; + +template +std::shared_ptr singleton::_instance = std::shared_ptr(new T()); + template R gl_convert(ARGS&&... args);