#pragma once #include "components/camera.hpp" #include "components/lights.hpp" #include "graphics/opengl/buffer.hpp" #include "graphics/opengl/framebuffer.hpp" #include "graphics/opengl/program.hpp" #include "graphics/opengl/vertex_array.hpp" #include "maths/transform.hpp" #include "resources/material.hpp" #include "resources/model.hpp" #include "resources/primitive.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace kuiper { namespace gl { static constexpr std::size_t MAX_NUM_LIGHTS = 100; static constexpr std::size_t LIGHT_SSBO_INIT_SIZE = 1000; static constexpr std::uint32_t NUM_CLUSTERS_X = 12; static constexpr std::uint32_t NUM_CLUSTERS_Y = 12; static constexpr std::uint32_t NUM_CLUSTERS_Z = 24; static constexpr std::uint32_t NUM_CLUSTERS = NUM_CLUSTERS_X * NUM_CLUSTERS_Y * NUM_CLUSTERS_Z; static constexpr std::uint32_t LOCAL_SIZE = 128; static constexpr float NEAR_Z_DEPTH = 0.1f; static constexpr float FAR_Z_DEPTH = std::numeric_limits::max(); struct gl_state { // Vertex & element buffers vertex_array::s_ptr vao {nullptr}; buffer::s_ptr vertex_buffer {nullptr}; buffer::s_ptr index_buffer {nullptr}; // Indirect & model matrix buffer buffer::s_ptr indirect_buffer {nullptr}; buffer::s_ptr matrix_buffer {nullptr}; // Shaders program::s_ptr pbr_shader {nullptr}; program::s_ptr clustering_shader {nullptr}; program::s_ptr light_culling_shader {nullptr}; // Lighting buffers buffer::s_ptr cluster_buffer {nullptr}; buffer::s_ptr lights_buffer {nullptr}; // Configuration std::uint32_t max_texture_units {32}; std::vector texture_unit_slots {}; }; struct renderer_metrics { std::size_t n_vertices {}; std::size_t n_indices {}; std::size_t n_draw_cmds {}; std::size_t n_matrices {}; std::size_t n_materials {}; std::size_t n_lights {}; }; class renderer { public: using vertex_t = vertex; using index_t = std::uint32_t; struct draw_elements_indirect_cmd { std::uint32_t count {0}; std::uint32_t instance_count {0}; std::uint32_t first_index {0}; std::uint32_t base_vertex {0}; std::uint32_t base_instance {0}; }; struct alignas(4) render_matrices { glm::mat4 model_matrix; glm::mat3 normal_matrix; }; struct alignas(16) cluster { glm::vec4 min_point; glm::vec4 max_point; std::uint32_t count; std::uint32_t light_indices[MAX_NUM_LIGHTS]; }; struct alignas(16) point_light { glm::vec4 position; glm::vec4 colour; float intensity; float radius; }; private: using vertex_storage_t = std::vector; using index_storage_t = std::vector; using draw_cmd_storage_t = std::vector; using matrix_storage_t = std::vector; using material_storage_t = std::vector; using light_storage_t = std::vector; public: renderer(gl_state&& state) : m_state(std::move(state)) {} ~renderer() = default; renderer(const renderer&) = delete; renderer& operator=(const renderer&) = delete; renderer(renderer&&) noexcept = delete; renderer& operator=(renderer&&) noexcept = delete; static renderer init(); void render(const framebuffer::s_ptr& framebuffer, const glm::vec3& cam_pos, const component::camera_props& cam_props) noexcept; void flush() noexcept; renderer_metrics metrics() const noexcept; void draw_model(const resource::model& model, const maths::transform_euler& transform); void draw_mesh(const resource::mesh& mesh, const std::vector& materials, const glm::mat4& transform); void draw_primitive(const resource::primitive& primitive, const resource::material& material, const maths::transform_euler& transform); void draw_primitive(const resource::primitive& primitive, const resource::material& material, const glm::mat4& transform); void add_light(const glm::vec3& pos, const component::point_light& light) noexcept; private: void update_and_upload() noexcept; private: gl_state m_state {}; vertex_storage_t m_vertices {}; index_storage_t m_indices {}; draw_cmd_storage_t m_draw_cmds {}; matrix_storage_t m_matrices {}; material_storage_t m_materials {}; light_storage_t m_lights {}; }; } // namespace gl } // namespace kuiper