diff --git a/include/Cubed/app.hpp b/include/Cubed/app.hpp index e19d209..dcea01b 100644 --- a/include/Cubed/app.hpp +++ b/include/Cubed/app.hpp @@ -6,7 +6,7 @@ #define GLFW_INCLUDE_NONE #include "Cubed/camera.hpp" #include "Cubed/dev_panel.hpp" -#include "Cubed/renderer.hpp" +#include "Cubed/render/renderer.hpp" #include "Cubed/texture_manager.hpp" #include "Cubed/window.hpp" namespace Cubed { diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index 8516198..310a294 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -58,8 +58,8 @@ public: void rebuild_world(); - void push_delete_vbo(GLuint vbo); - void push_delete_vao(GLuint vao); + void push_delete_vbo(std::unique_ptr& vbo); + void push_delete_vao(std::unique_ptr& vao); // void hot_reload(); // void rebuild_world(); @@ -134,8 +134,8 @@ private: tbb::concurrent_queue> m_pending_upload_queue; tbb::concurrent_queue m_dirty_chunk_queue; tbb::concurrent_queue m_pending_sound; - std::vector m_pending_delete_vbo; - std::vector m_pending_delete_vao; + std::vector> m_pending_delete_vbo; + std::vector> m_pending_delete_vao; std::deque m_dirty_queue; std::vector m_render_snapshots; diff --git a/include/Cubed/gameplay/vertex_data.hpp b/include/Cubed/gameplay/vertex_data.hpp index b9d07b9..84d0871 100644 --- a/include/Cubed/gameplay/vertex_data.hpp +++ b/include/Cubed/gameplay/vertex_data.hpp @@ -1,15 +1,18 @@ #pragma once #include "Cubed/primitive_data.hpp" +#include "Cubed/render/vertex_array.hpp" +#include "Cubed/render/vertex_buffer.hpp" #include #include +#include #include namespace Cubed { class ClientWorld; struct VertexData { std::vector m_vertices; - GLuint m_vbo = 0; - GLuint m_vao = 0; + std::unique_ptr m_vbo; + std::unique_ptr m_vao; std::atomic m_sum{0}; ClientWorld& m_world; VertexData(ClientWorld& world); diff --git a/include/Cubed/render/frame_buffer.hpp b/include/Cubed/render/frame_buffer.hpp new file mode 100644 index 0000000..4ae3d8d --- /dev/null +++ b/include/Cubed/render/frame_buffer.hpp @@ -0,0 +1,46 @@ +#pragma once +#include "Cubed/render/texture.hpp" + +#include +#include + +enum class Attachment : GLenum { + COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0, + COLOR_ATTACHMENT1 = GL_COLOR_ATTACHMENT1, + DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT +}; + +enum class FrameBufferType : GLenum { + FRAMEBUFFER = GL_FRAMEBUFFER, + READ_FRAMEBUFFER = GL_READ_FRAMEBUFFER, + DRAW_FRAMEBUFFER = GL_DRAW_FRAMEBUFFER +}; + +namespace Cubed { +class FrameBuffer { +public: + FrameBuffer(); + ~FrameBuffer(); + FrameBuffer(const FrameBuffer&) = delete; + FrameBuffer(FrameBuffer&&) noexcept; + FrameBuffer& operator=(const FrameBuffer&) = delete; + FrameBuffer& operator=(FrameBuffer&&) noexcept; + + void bind(FrameBufferType type = FrameBufferType::FRAMEBUFFER) const; + GLuint id() const; + + void attach(Attachment attachment, const Texture& texture, + GLint level = 0) const; + static void unbind(); + + bool check_status() const; + + void draw_buffer(GLenum buf) const; + void read_buffer(GLenum src) const; + void draw_buffer(GLsizei n, const GLenum* bufs) const; + void draw_buffer(std::span bufs) const; + +private: + GLuint m_fbo = 0; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/player_renderer.hpp b/include/Cubed/render/player_renderer.hpp similarity index 100% rename from include/Cubed/player_renderer.hpp rename to include/Cubed/render/player_renderer.hpp diff --git a/include/Cubed/render/renderer.hpp b/include/Cubed/render/renderer.hpp new file mode 100644 index 0000000..240a961 --- /dev/null +++ b/include/Cubed/render/renderer.hpp @@ -0,0 +1,125 @@ +#pragma once + +#include "Cubed/constants.hpp" +#include "Cubed/primitive_data.hpp" +#include "Cubed/render/player_renderer.hpp" +#include "Cubed/render/shader_manager.hpp" +#include "Cubed/render/vertex_array.hpp" +#include "Cubed/render/vertex_buffer.hpp" +#include "Cubed/render/world_renderer.hpp" +#include "Cubed/shader.hpp" +#include "Cubed/ui/text.hpp" + +#include +#include +namespace Cubed { + +class Camera; +class TextureManager; +class ClientWorld; +class DevPanel; +class Renderer { +public: + constexpr static int NUM_VAO = 7; + + Renderer(const Camera& camera, ClientWorld& world, + const TextureManager& texture_manager, DevPanel& dev_panel); + ~Renderer(); + void hot_reload(); + void init(bool debug_on); + const Shader& get_shader(const std::string& name) const; + void render(); + void update(float delta_time); + void update_fov(float fov); + void update_proj_matrix(float aspect, float width, float height); + void updata_framebuffer(int width, int height); + float& ambient_strength(); + + bool& discard_transparent(); + bool& shader_on(); + bool& water_perturb(); + bool& water_depth_fade(); + bool& pbr(); + bool& flip_y(); + int& shadow_mode(); + int& light_cull_face(); + int& light_size_uv(); + float& min_radius(); + float& max_radius(); + int& samples(); + float& specular_strength(); + float& cloud_speed(); + float& cloud_threshold_low(); + float& cloud_threshold_high(); + float& refract_strength(); + + float& underwater_fog_density(); + float& water_density(); + + const Camera& camera() const; + const ClientWorld& world() const; + ClientWorld& world(); + const glm::mat4& world_proj_matrix() const; + const TextureManager& texture_mamger() const; + float delta_time() const; + + float height() const; + float width() const; + const glm::mat4& p_mat() const; + + const std::vector& vao() const; + +private: + const Camera& m_camera; + DevPanel& m_dev_panel; + const TextureManager& m_texture_manager; + ClientWorld& m_world; + + bool m_init = false; + + float m_aspect = 0.0f; + float m_fov = DEFAULT_FOV; + + float m_delta_time = 0.0f; + + float m_width = 0.0f; + float m_height = 0.0f; + + glm::mat4 m_world_proj_matrix; + + std::unique_ptr m_sky_vbo; + std::unique_ptr m_outline_indices_vbo; + std::unique_ptr m_outline_vbo; + std::unique_ptr m_ui_vbo; + std::unique_ptr m_player_vbo; + std::unique_ptr m_quad_vbo; + + glm::mat4 m_ui_proj_matrix; + glm::mat4 m_ui_model_matrix; + ShaderManager m_shaders; + + /* + 0 - quad vao + 1 - sky vao + 2 - outline vao + 3 - ui vao + 4 - text vao + */ + std::vector m_vao; + std::vector m_ui; + + WorldRenderer m_world_renderer; + + void init_quad(); + void init_text(); + + void day_night_calculation(); + + void render_sky(); + void render_text(); + void render_ui(); + + void render_dev_panel(); +}; + +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/render/renderer_constants.hpp b/include/Cubed/render/renderer_constants.hpp new file mode 100644 index 0000000..5925c5a --- /dev/null +++ b/include/Cubed/render/renderer_constants.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace Cubed { +constexpr glm::vec3 SUN_COLOR{1.00f, 0.95f, 0.80f}; +constexpr glm::vec3 MOON_COLOR{0.75f, 0.80f, 1.00f}; + +constexpr glm::vec3 SUNSET_SUNLIGHT_COLOR{1.00f, 0.45f, 0.15f}; +constexpr glm::vec3 NOON_SUNLIGHT_COLOR{1.00f, 0.90f, 0.65f}; +constexpr glm::vec3 SUNSET_AMBIENT_COLOR{0.18f, 0.12f, 0.35f}; +constexpr glm::vec3 NOON_AMBIENT_COLOR{0.35f, 0.50f, 0.85f}; +constexpr glm::vec3 MOONLIGHT_COLOR{0.55f, 0.70f, 1.00f}; +constexpr glm::vec3 NIGHT_AMBIENT_COLOR{0.08f, 0.10f, 0.18f}; +constexpr float FAR_PLANE = 1000.0f; +constexpr float NEAR_PLANE = 0.1f; +constexpr float SUN_SIZE = 50.0f; +constexpr float MOON_SIZE = 50.0f; +constexpr float DEPTH_MAP_SIZE = 4096.0f; +constexpr float ANGLE_STEP_DEG = 0.5f; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/render/shader_manager.hpp b/include/Cubed/render/shader_manager.hpp new file mode 100644 index 0000000..9c566a5 --- /dev/null +++ b/include/Cubed/render/shader_manager.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Cubed/shader.hpp" + +#include +#include +namespace Cubed { +class ShaderManager { +public: + ShaderManager(); + ~ShaderManager(); + ShaderManager(const ShaderManager&) = delete; + ShaderManager(ShaderManager&&) = delete; + ShaderManager& operator=(const ShaderManager&) = delete; + ShaderManager& operator=(ShaderManager&&) = delete; + + void init(); + + const Shader& get_shader(const std::string& name) const; + +private: + std::unordered_map m_shaders; + + void register_shader(const std::string& name, const std::string& v_shader, + const std::string& f_shader); +}; + +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/render/texture.hpp b/include/Cubed/render/texture.hpp new file mode 100644 index 0000000..df975e8 --- /dev/null +++ b/include/Cubed/render/texture.hpp @@ -0,0 +1,94 @@ +#pragma once +#include +#include +namespace Cubed { + +enum TextureType : GLenum { + TEXTURE_2D = GL_TEXTURE_2D, + TEXTURE_2D_ARRAY = GL_TEXTURE_2D_ARRAY +}; + +enum TexturePname : GLenum { + MIN_FILTER = GL_TEXTURE_MIN_FILTER, + MAG_FILTER = GL_TEXTURE_MAG_FILTER, + WRAP_S = GL_TEXTURE_WRAP_S, + WRAP_T = GL_TEXTURE_WRAP_T, + WRAP_R = GL_TEXTURE_WRAP_R, + BORDER_COLOR = GL_TEXTURE_BORDER_COLOR, + COMPARE_MODE = GL_TEXTURE_COMPARE_MODE +}; + +enum TextureParam : GLenum { + LINEAR = GL_LINEAR, + NEAREST = GL_NEAREST, + LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR, + CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER, + CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE, + T_NONE = GL_NONE, + REPEAT = GL_REPEAT +}; + +enum TextureFormat : GLenum { + DEPTH_COMPONENT32F = GL_DEPTH_COMPONENT32F, + DEPTH_COMPONENT = GL_DEPTH_COMPONENT, + R16F = GL_R16F, + RGBA16F = GL_RGBA16F, + RED = GL_RED, + RGBA = GL_RGBA, + RGB = GL_RGB, + RGBA8 = GL_RGBA8, + +}; + +class Texture { +public: + explicit Texture(TextureType type); + ~Texture(); + Texture(const Texture&) = delete; + Texture(Texture&&) noexcept; + Texture& operator=(const Texture&) = delete; + Texture& operator=(Texture&&) noexcept; + + void bind() const; + void bind(size_t unit) const; + static void unbind(); + static void active(size_t id); + GLuint id() const; + + void parameter(TexturePname pname, TextureParam param) const; + void parameterfv(TexturePname pname, const float* param) const; + + void tex_image_2d(TextureFormat internalformat, TextureFormat format, + GLenum type, const void* data, GLsizei width, + GLsizei height, GLint level = 0, GLint border = 0) const; + + void tex_image_3d(TextureFormat internalformat, TextureFormat format, + GLenum type, const void* data, GLsizei width, + GLsizei height, GLsizei depth, GLint level = 0, + GLint border = 0) const; + + void tex_sub_image_3d(TextureFormat format, GLenum type, const void* data, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth = 1, + GLint level = 0) const; + + void set_aniso(int aniso) const; + + void gen_mipmap() const; + + void set_linear() const; + void set_nearest_and_minpmap() const; + void set_nearest() const; + void set_repeat(bool r = true, bool s = true, bool t = true) const; + void set_clamp_to_border(bool r = true, bool s = true, bool t = true) const; + void set_clamp_to_edge(bool r = true, bool s = true, bool t = true) const; + + TextureType type() const; + +private: + GLuint m_id = 0; + const TextureType M_TYPE; + + GLenum get_gl_texture_type() const; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/render/vertex_array.hpp b/include/Cubed/render/vertex_array.hpp new file mode 100644 index 0000000..8e55da1 --- /dev/null +++ b/include/Cubed/render/vertex_array.hpp @@ -0,0 +1,26 @@ +#pragma once +#include + +namespace Cubed { +class VertexArray { +public: + VertexArray(); + VertexArray(const VertexArray&) = delete; + VertexArray(VertexArray&&) noexcept; + VertexArray& operator=(const VertexArray&) = delete; + VertexArray& operator=(VertexArray&&) noexcept; + ~VertexArray(); + + void bind() const; + + static void unbind(); + + GLuint id() const; + + void attribute(GLuint index, GLint size, GLenum type, GLsizei stride, + const void* ptr, bool normalized = false) const; + +private: + GLuint m_vao = 0; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/render/vertex_buffer.hpp b/include/Cubed/render/vertex_buffer.hpp new file mode 100644 index 0000000..83b9380 --- /dev/null +++ b/include/Cubed/render/vertex_buffer.hpp @@ -0,0 +1,36 @@ +#pragma once +#include +namespace Cubed { + +enum class BufferType : GLenum { + ARRAY_BUFFER = GL_ARRAY_BUFFER, + ELEMENT_ARRAY_BUFFER = GL_ELEMENT_ARRAY_BUFFER +}; + +enum class BufferUsage : GLenum { + STATIC_DRAW = GL_STATIC_DRAW, + DYNAMIC_DRAW = GL_DYNAMIC_DRAW +}; + +class VertexBuffer { +public: + VertexBuffer(BufferType type = BufferType::ARRAY_BUFFER); + VertexBuffer(const VertexBuffer&) = delete; + VertexBuffer(VertexBuffer&&) noexcept; + VertexBuffer& operator=(const VertexBuffer&) = delete; + VertexBuffer& operator=(VertexBuffer&&) noexcept; + ~VertexBuffer(); + + void bind() const; + static void unbind(); + GLuint id() const; + void buffer_data(const void* data, GLsizeiptr size, + BufferUsage usage = BufferUsage::STATIC_DRAW) const; + +private: + GLuint m_vbo = 0; + BufferType m_type = BufferType::ARRAY_BUFFER; + + GLenum get_buffer_target() const; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/renderer.hpp b/include/Cubed/render/world_renderer.hpp similarity index 50% rename from include/Cubed/renderer.hpp rename to include/Cubed/render/world_renderer.hpp index 7589d28..3a54141 100644 --- a/include/Cubed/renderer.hpp +++ b/include/Cubed/render/world_renderer.hpp @@ -1,65 +1,17 @@ #pragma once - -#include "Cubed/constants.hpp" -#include "Cubed/player_renderer.hpp" -#include "Cubed/primitive_data.hpp" -#include "Cubed/shader.hpp" -#include "Cubed/ui/text.hpp" +#include "Cubed/render/frame_buffer.hpp" +#include "Cubed/render/player_renderer.hpp" +#include "Cubed/render/texture.hpp" #include -#include +#include namespace Cubed { - -class Camera; -class TextureManager; +class Renderer; class ClientWorld; -class DevPanel; -class Renderer { +class TextureManager; +class Camera; +class WorldRenderer { public: - constexpr static int NUM_VAO = 7; - - Renderer(const Camera& camera, ClientWorld& world, - const TextureManager& texture_manager, DevPanel& dev_panel); - ~Renderer(); - void hot_reload(); - void init(bool debug_on); - const Shader& get_shader(const std::string& name) const; - void render(); - void update(float delta_time); - void update_fov(float fov); - void update_proj_matrix(float aspect, float width, float height); - void updata_framebuffer(int width, int height); - float& ambient_strength(); - - bool& discard_transparent(); - bool& shader_on(); - bool& water_perturb(); - bool& water_depth_fade(); - bool& pbr(); - bool& flip_y(); - int& shadow_mode(); - int& light_cull_face(); - int& light_size_uv(); - float& min_radius(); - float& max_radius(); - int& samples(); - float& specular_strength(); - float& cloud_speed(); - float& cloud_threshold_low(); - float& cloud_threshold_high(); - float& refract_strength(); - float& underwater_fog_density(); - float& water_density(); - - const Camera& camera() const; - const ClientWorld& world() const; - ClientWorld& world(); - const glm::mat4& proj_mat() const; - const TextureManager& texture_mamger() const; - - float delta_time() const; - -private: struct ParallelLight { glm::vec3 sundir; // direction from sun to vertex glm::vec3 lightdir; @@ -79,132 +31,121 @@ private: float horizon_sharpness; float cloud_white_mix; }; + WorldRenderer(Renderer& renderer); + ~WorldRenderer(); - static constexpr glm::vec3 SUN_COLOR{1.00f, 0.95f, 0.80f}; - static constexpr glm::vec3 MOON_COLOR{0.75f, 0.80f, 1.00f}; + WorldRenderer(const WorldRenderer&) = delete; + WorldRenderer(WorldRenderer&&) = delete; + WorldRenderer& operator=(const WorldRenderer&) = delete; + WorldRenderer& operator=(WorldRenderer&&) = delete; + void init(); + void render(); + void updata_framebuffer(int width, int height); - static constexpr glm::vec3 SUNSET_SUNLIGHT_COLOR{1.00f, 0.45f, 0.15f}; - static constexpr glm::vec3 NOON_SUNLIGHT_COLOR{1.00f, 0.90f, 0.65f}; - static constexpr glm::vec3 SUNSET_AMBIENT_COLOR{0.18f, 0.12f, 0.35f}; - static constexpr glm::vec3 NOON_AMBIENT_COLOR{0.35f, 0.50f, 0.85f}; - static constexpr glm::vec3 MOONLIGHT_COLOR{0.55f, 0.70f, 1.00f}; - static constexpr glm::vec3 NIGHT_AMBIENT_COLOR{0.08f, 0.10f, 0.18f}; - static constexpr float FAR_PLANE = 1000.0f; - static constexpr float NEAR_PLANE = 0.1f; - static constexpr float SUN_SIZE = 50.0f; - static constexpr float MOON_SIZE = 50.0f; - static constexpr float DEPTH_MAP_SIZE = 4096.0f; - static constexpr float ANGLE_STEP_DEG = 0.5f; - float m_ambient_strength = 0.1f; + float& ambient_strength(); + bool& discard_transparent(); + bool& shader_on(); + bool& water_perturb(); + bool& water_depth_fade(); + bool& pbr(); + bool& flip_y(); + int& shadow_mode(); + int& light_cull_face(); + int& light_size_uv(); + float& min_radius(); + float& max_radius(); + int& samples(); + float& specular_strength(); + float& cloud_speed(); + float& cloud_threshold_low(); + float& cloud_threshold_high(); + float& refract_strength(); + float& underwater_fog_density(); - const Camera& m_camera; - DevPanel& m_dev_panel; - const TextureManager& m_texture_manager; - ClientWorld& m_world; + float& water_density(); + + const FrameBuffer* world_fbo() const; + +private: + Renderer& m_renderer; PlayerRenderer m_player_renderer; - bool m_discard_tranparent = true; - bool m_shader_on = true; - bool m_water_perturb = true; - bool m_water_depth_fade = true; - bool m_pbr = true; - bool m_flip_y = false; + std::unique_ptr m_accum_texture; + std::unique_ptr m_reveal_texture; - bool m_init = false; + std::unique_ptr m_world_fbo; + std::unique_ptr m_screen_texture; + std::unique_ptr m_screen_depth_texture; - int m_shadow_mode = 0; - int m_light_cull_face = 0; - float m_aspect = 0.0f; - float m_fov = DEFAULT_FOV; + std::unique_ptr m_oit_fbo; - float m_delta_time = 0.0f; + std::unique_ptr m_oit_depth_texture; - float m_cloud_time = 0.0f; - float m_cloud_speed = 5.0f; - - float m_width = 0.0f; - float m_height = 0.0f; - - glm::mat4 m_p_mat, m_v_mat, m_m_mat, m_mv_mat, m_mvp_mat, m_norm_mat; - - GLuint m_sky_vbo = 0; - GLuint m_text_vbo = 0; - GLuint m_outline_indices_vbo = 0; - GLuint m_outline_vbo = 0; - GLuint m_ui_vbo = 0; - GLuint m_player_vbo = 0; - GLuint m_fbo = 0; - GLuint m_screen_texture = 0; - GLuint m_screen_depth_texture = 0; - - GLuint m_oit_fbo = 0; - GLuint m_accum_texture = 0; - GLuint m_reveal_texture = 0; - GLuint m_oit_depth_texture = 0; - - GLuint m_depth_map_fbo = 0; - GLuint m_depth_map_texture = 0; - - GLuint m_quad_vbo = 0; - - glm::mat4 m_ui_proj; - glm::mat4 m_ui_m_matrix; - std::unordered_map m_shaders; + std::unique_ptr m_depth_map_fbo; + std::unique_ptr m_depth_map_texture; glm::vec3 m_blend_from_lightdir; glm::vec3 m_blend_to_lightdir; float m_blend_t = 1.0f; bool m_blend_initialized = false; static constexpr float BLEND_DURATION = 0.15f; - int m_light_size_uv = 20; - - float m_min_radius = 2.0f; - float m_max_radius = 20.0f; - int m_samples = 16; - - float m_specular_strength = 0.5f; - - float moon_intensity = 0.3f; - float sun_intensity = 1.00f; - - float m_cloud_threshold_low = 0.5f; - float m_cloud_threshold_high = 0.75f; - - float m_refract_strength = 0.03f; float m_underwater_fog_density = 0.08f; float m_water_density = 0.12f; + float m_ambient_strength = 0.1f; + bool m_discard_tranparent = true; + bool m_shader_on = true; + bool m_water_perturb = true; + bool m_water_depth_fade = true; + bool m_pbr = true; + bool m_flip_y = false; + int m_shadow_mode = 0; + int m_light_size_uv = 20; + float m_min_radius = 2.0f; + float m_max_radius = 20.0f; + int m_samples = 16; + float m_specular_strength = 0.5f; + float m_cloud_threshold_low = 0.5f; + float m_cloud_threshold_high = 0.75f; + float m_cloud_time = 0.0f; + float m_cloud_speed = 5.0f; + float m_refract_strength = 0.03f; + int m_light_cull_face = 0; + + float moon_intensity = 0.3f; + float sun_intensity = 1.00f; + ParallelLight m_parallel_light; SkyUniform m_sky_uniform; - /* - 0 - quad vao - 1 - sky vao - 2 - outline vao - 3 - ui vao - 4 - text vao - */ - std::vector m_vao; - std::vector m_ui; - void init_quad(); - void init_text(); + glm::mat4 view_matrix; + ClientWorld& m_world; + const Camera& m_camera; + const TextureManager& m_texture_manager; void day_night_calculation(); - void render_outline(); void render_sky(); - void render_text(); - void render_ui(); + void render_world(); - void render_player(); + + void shadow_map_generate(); + void render_underwater(); - void render_dev_panel(); + void render_outline(); + void render_player(); + + void render_normal_block(const glm::mat4& model_mat, + const glm::mat4& mv_mat, + const glm::mat4& norm_mat); + + void render_transparent_block(const glm::mat4& mv_mat, + const glm::mat4& norm_mat); glm::vec3 quantize_sun_direction(const glm::vec3& sundir, float angle_step_deg) const; glm::vec3 get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_sundir, float dt); }; - } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/texture_manager.hpp b/include/Cubed/texture_manager.hpp index 130b92d..5807aee 100644 --- a/include/Cubed/texture_manager.hpp +++ b/include/Cubed/texture_manager.hpp @@ -1,7 +1,9 @@ #pragma once #include "Cubed/gameplay/block.hpp" +#include "Cubed/render/texture.hpp" #include +#include namespace Cubed { @@ -9,19 +11,17 @@ class TextureManager { private: bool m_need_reload = false; bool m_init = false; - GLuint m_block_status_array = 0; - GLuint m_texture_array = 0; - GLuint m_cross_plane_array = 0; - GLuint m_ui_array = 0; - GLuint m_normal_texture_array = 0; + std::unique_ptr m_block_status_array; + std::unique_ptr m_texture_array; + std::unique_ptr m_cross_plane_array; + std::unique_ptr m_ui_array; + std::unique_ptr m_normal_texture_array; + std::unique_ptr m_skin; + std::vector> m_item_textures; GLfloat m_max_aniso = 0.0f; - GLuint m_skin = 0; - int m_aniso = 1; - std::vector m_item_textures; - void load_block_status(unsigned status_id); void load_block_texture(unsigned block_id); void load_block_item_texture(unsigned id); @@ -39,14 +39,14 @@ public: TextureManager(); ~TextureManager(); - void delet_texture(); - GLuint get_block_status_array() const; - GLuint get_texture_array() const; - GLuint get_cross_plane_array() const; - GLuint get_ui_array() const; - GLuint get_pbr_texture() const; - const std::vector& item_textures() const; - GLuint get_skin() const; + void delete_texture(); + const Texture* get_block_status_array() const; + const Texture* get_texture_array() const; + const Texture* get_cross_plane_array() const; + const Texture* get_ui_array() const; + const Texture* get_pbr_texture() const; + const std::vector>& item_textures() const; + const Texture* get_skin() const; // Must call after MapTable::init_map() and glfwMakeContextCurrent(window); void init_texture(); diff --git a/include/Cubed/tools/font.hpp b/include/Cubed/tools/font.hpp index fb3a4c1..726f436 100644 --- a/include/Cubed/tools/font.hpp +++ b/include/Cubed/tools/font.hpp @@ -1,5 +1,8 @@ #pragma once +#include "Cubed/render/texture.hpp" + #include +#include #include FT_FREETYPE_H #include "Cubed/primitive_data.hpp" @@ -29,7 +32,7 @@ public: static std::vector vertices(const std::string& text, float x = 0.0f, float y = 0.0f, float scale = 1.0f); - static GLuint text_texture(); + static const Texture* text_texture(); static const std::string& font_path(); private: @@ -39,7 +42,7 @@ private: float m_texture_width = 64; float m_texture_height = 64; - static inline GLuint m_text_texture; + static inline std::unique_ptr m_text_texture; static inline std::string m_font_path{ASSETS_PATH "fonts/IBMPlexSans-Regular.ttf"}; std::unordered_map m_characters; diff --git a/include/Cubed/ui/text.hpp b/include/Cubed/ui/text.hpp index a750363..a7e5aba 100644 --- a/include/Cubed/ui/text.hpp +++ b/include/Cubed/ui/text.hpp @@ -1,6 +1,8 @@ #pragma once #include "Cubed/primitive_data.hpp" +#include "Cubed/render/vertex_array.hpp" +#include "Cubed/render/vertex_buffer.hpp" #include "Cubed/ui/color.hpp" #include @@ -27,8 +29,7 @@ public: Text& text(std::string_view str); std::size_t uuid() const; - static void set_loc(const Shader& shader); - void render(); + void render(const Shader& shader); bool operator==(const Text& other) const; @@ -38,14 +39,14 @@ private: const std::string NAME; const std::size_t UUID; + std::string m_text; glm::vec4 m_color{1.0f, 1.0f, 1.0f, 1.0f}; glm::mat4 m_model_matrix; std::vector m_vertices; - GLuint m_vbo = 0; - static inline GLuint m_color_loc = 0; - static inline GLuint m_mv_loc = 0; + std::unique_ptr m_vbo; + std::unique_ptr m_vao; void update_vertices(); void upload_to_gpu(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 95026a7..0aa2087 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,7 @@ target_sources(${PROJECT_NAME} gameplay/tree.cpp input.cpp map_table.cpp - renderer.cpp + render/renderer.cpp shader.cpp texture_manager.cpp tools/cubed_random.cpp @@ -43,7 +43,7 @@ target_sources(${PROJECT_NAME} gameplay/client_player.cpp gameplay/session.cpp gameplay/network_client.cpp - player_renderer.cpp + render/player_renderer.cpp audio/audio_engine.cpp audio/audio_loader.cpp audio/audio_source.cpp @@ -54,4 +54,10 @@ target_sources(${PROJECT_NAME} audio/audio_filter.cpp audio/audio_effect.cpp audio/audio_effect_slot.cpp + render/vertex_buffer.cpp + render/vertex_array.cpp + render/texture.cpp + render/frame_buffer.cpp + render/shader_manager.cpp + render/world_renderer.cpp ) \ No newline at end of file diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index e46ec54..2f47eb0 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -650,14 +650,23 @@ void DevPanel::show_items_tab_item() { if (ImGui::BeginTabItem("item")) { ImGui::Text("Place Block "); ImGui::SameLine(); - ImGui::Image(static_cast(static_cast( - textures[m_player->place_block()])), - ImVec2{48, 48}); + auto& place_texture = textures[m_player->place_block()]; + if (place_texture) { + ImGui::Image(static_cast( + static_cast(place_texture->id())), + ImVec2{48, 48}); + } + for (size_t i = 1; i < textures.size(); i++) { - if (ImGui::ImageButton(("##item" + std::to_string(i)).c_str(), - static_cast( - static_cast(textures[i])), - ImVec2{48, 48})) { + auto& item_texture = textures[i]; + if (!item_texture) { + continue; + } + if (ImGui::ImageButton( + ("##item" + std::to_string(i)).c_str(), + static_cast( + static_cast(item_texture->id())), + ImVec2{48, 48})) { m_player->set_place_block(i); } if (ImGui::IsItemHovered()) { diff --git a/src/gameplay/client_chunk.cpp b/src/gameplay/client_chunk.cpp index daa122d..11e1b1c 100644 --- a/src/gameplay/client_chunk.cpp +++ b/src/gameplay/client_chunk.cpp @@ -198,7 +198,12 @@ void ClientChunk::gen_vertex_data( m_is_on_gen_vertex_data = false; } -GLuint ClientChunk::get_normal_vao() const { return m_vertex_data[0].m_vao; } +GLuint ClientChunk::get_normal_vao() const { + if (!m_vertex_data[0].m_vao) { + return 0; + } + return m_vertex_data[0].m_vao->id(); +} size_t ClientChunk::get_normal_vertices_sum() const { if (m_vertex_data[0].m_sum == 0) { @@ -207,26 +212,43 @@ size_t ClientChunk::get_normal_vertices_sum() const { return m_vertex_data[0].m_sum.load(); } -GLuint ClientChunk::get_cross_vao() const { return m_vertex_data[1].m_vao; } +GLuint ClientChunk::get_cross_vao() const { + if (!m_vertex_data[1].m_vao) { + return 0; + } + return m_vertex_data[1].m_vao->id(); +} size_t ClientChunk::get_cross_vertices_sum() const { return m_vertex_data[1].m_sum.load(); } GLuint ClientChunk::get_normal_discard_vao() const { - return m_vertex_data[2].m_vao; + if (!m_vertex_data[2].m_vao) { + return 0; + } + return m_vertex_data[2].m_vao->id(); } size_t ClientChunk::get_normal_discard_vertices_sum() const { + return m_vertex_data[2].m_sum.load(); } GLuint ClientChunk::get_normal_blend_vao() const { - return m_vertex_data[3].m_vao; + if (!m_vertex_data[3].m_vao) { + return 0; + } + return m_vertex_data[3].m_vao->id(); } size_t ClientChunk::get_normal_blend_vertices_sum() const { return m_vertex_data[3].m_sum.load(); } -GLuint ClientChunk::get_water_vao() const { return m_vertex_data[4].m_vao; } +GLuint ClientChunk::get_water_vao() const { + if (!m_vertex_data[4].m_vao) { + return 0; + } + return m_vertex_data[4].m_vao->id(); +} size_t ClientChunk::get_water_vertices_sum() const { return m_vertex_data[4].m_sum.load(); } diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index 87c2548..f75b4a8 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -32,16 +32,10 @@ ClientWorld::~ClientWorld() { { std::lock_guard lk(m_delete_vbo_mutex); - for (auto x : m_pending_delete_vbo) { - glDeleteBuffers(1, &x); - } m_pending_delete_vbo.clear(); } { std::lock_guard lk(m_delete_vao_mutex); - for (auto x : m_pending_delete_vao) { - glDeleteVertexArrays(1, &x); - } m_pending_delete_vao.clear(); } m_ticktimers.clear(); @@ -267,13 +261,13 @@ void ClientWorld::set_block(const glm::ivec3& block_pos, unsigned id) { }); } } -void ClientWorld::push_delete_vbo(GLuint vbo) { +void ClientWorld::push_delete_vbo(std::unique_ptr& vbo) { std::lock_guard lk(m_delete_vbo_mutex); - m_pending_delete_vbo.push_back(vbo); + m_pending_delete_vbo.push_back(std::move(vbo)); } -void ClientWorld::push_delete_vao(GLuint vao) { +void ClientWorld::push_delete_vao(std::unique_ptr& vao) { std::lock_guard lk(m_delete_vao_mutex); - m_pending_delete_vao.push_back(vao); + m_pending_delete_vao.push_back(std::move(vao)); } void ClientWorld::report_block_change(const glm::ivec3& pos, @@ -729,17 +723,11 @@ void ClientWorld::update(float delta_time) { m_player.update(delta_time); { std::lock_guard lk(m_delete_vbo_mutex); - for (auto x : m_pending_delete_vbo) { - glDeleteBuffers(1, &x); - } m_pending_delete_vbo.clear(); } { std::lock_guard lk(m_delete_vao_mutex); - for (auto x : m_pending_delete_vao) { - glDeleteVertexArrays(1, &x); - } m_pending_delete_vao.clear(); } diff --git a/src/gameplay/vertex_data.cpp b/src/gameplay/vertex_data.cpp index fba1101..72540b2 100644 --- a/src/gameplay/vertex_data.cpp +++ b/src/gameplay/vertex_data.cpp @@ -5,64 +5,60 @@ namespace Cubed { VertexData::VertexData(ClientWorld& world) : m_world(world) {} VertexData::~VertexData() { - if (m_vbo != 0) { - m_world.push_delete_vbo(m_vbo); - } - if (m_vao != 0) { - m_world.push_delete_vao(m_vao); - } + + m_world.push_delete_vbo(m_vbo); + + m_world.push_delete_vao(m_vao); } VertexData::VertexData(VertexData&& o) noexcept - : m_vertices(std::move(o.m_vertices)), m_vbo(o.m_vbo), m_vao(o.m_vao), - m_sum(o.m_sum.load()), m_world(o.m_world) { - o.m_vbo = 0; - o.m_sum = 0; - o.m_vao = 0; -} + : m_vertices(std::move(o.m_vertices)), m_vbo(std::move(o.m_vbo)), + m_vao(std::move(o.m_vao)), m_sum(o.m_sum.exchange(0)), + m_world(o.m_world) {} VertexData& VertexData::operator=(VertexData&& o) noexcept { - m_vbo = o.m_vbo; - o.m_vbo = 0; - m_sum = o.m_sum.load(); - o.m_sum = 0; + if (this == &o) { + return *this; + } + + m_world.push_delete_vao(m_vao); + m_world.push_delete_vbo(m_vbo); + + m_vbo = std::move(o.m_vbo); + m_vao = std::move(o.m_vao); + + m_sum = o.m_sum.exchange(0); + m_vertices = std::move(o.m_vertices); - m_vao = o.m_vao; - o.m_vao = 0; + return *this; } void VertexData::upload() { if (m_vertices.size() == 0) { return; } - if (m_vao == 0) { - glGenVertexArrays(1, &m_vao); + if (!m_vao) { + m_vao = std::make_unique(); } - if (m_vbo == 0) { - glGenBuffers(1, &m_vbo); + if (!m_vbo) { + m_vbo = std::make_unique(); } - glBindVertexArray(m_vao); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo); - glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex3D), - m_vertices.data(), GL_DYNAMIC_DRAW); + m_vao->bind(); + m_vbo->buffer_data(m_vertices.data(), m_vertices.size() * sizeof(Vertex3D), + BufferUsage::DYNAMIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), (void*)0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), - (void*)offsetof(Vertex3D, s)); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), - (void*)offsetof(Vertex3D, layer)); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), - (void*)offsetof(Vertex3D, nx)); - glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), - (void*)offsetof(Vertex3D, roughness)); - glVertexAttribPointer(5, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), - (void*)offsetof(Vertex3D, tx)); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); - glEnableVertexAttribArray(5); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); + m_vao->attribute(0, 3, GL_FLOAT, sizeof(Vertex3D), (void*)0); + m_vao->attribute(1, 2, GL_FLOAT, sizeof(Vertex3D), + (void*)offsetof(Vertex3D, s)); + m_vao->attribute(2, 1, GL_FLOAT, sizeof(Vertex3D), + (void*)offsetof(Vertex3D, layer)); + m_vao->attribute(3, 3, GL_FLOAT, sizeof(Vertex3D), + (void*)offsetof(Vertex3D, nx)); + m_vao->attribute(4, 1, GL_FLOAT, sizeof(Vertex3D), + (void*)offsetof(Vertex3D, roughness)); + m_vao->attribute(5, 3, GL_FLOAT, sizeof(Vertex3D), + (void*)offsetof(Vertex3D, tx)); + + VertexArray::unbind(); + VertexBuffer::unbind(); // Release memory m_vertices.clear(); diff --git a/src/render/frame_buffer.cpp b/src/render/frame_buffer.cpp new file mode 100644 index 0000000..4949211 --- /dev/null +++ b/src/render/frame_buffer.cpp @@ -0,0 +1,79 @@ +#include "Cubed/render/frame_buffer.hpp" + +#include "Cubed/tools/log.hpp" + +#include + +namespace Cubed { +FrameBuffer::FrameBuffer() { glGenFramebuffers(1, &m_fbo); } +FrameBuffer::~FrameBuffer() { + if (m_fbo) { + glDeleteFramebuffers(1, &m_fbo); + } +} + +FrameBuffer::FrameBuffer(FrameBuffer&& o) noexcept + : m_fbo(std::exchange(o.m_fbo, 0)) {} + +FrameBuffer& FrameBuffer::operator=(FrameBuffer&& o) noexcept { + if (this == &o) { + return *this; + } + if (m_fbo) { + glDeleteFramebuffers(1, &m_fbo); + } + m_fbo = std::exchange(o.m_fbo, 0); + return *this; +} + +GLuint FrameBuffer::id() const { return m_fbo; } + +void FrameBuffer::bind(FrameBufferType type) const { + glBindFramebuffer(std::to_underlying(type), m_fbo); +} +void FrameBuffer::unbind() { + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} +void FrameBuffer::attach(Attachment attachment, const Texture& texture, + GLint level) const { + bind(); + auto type = texture.type(); + if (type == TextureType::TEXTURE_2D) { + glFramebufferTexture2D(GL_FRAMEBUFFER, std::to_underlying(attachment), + std::to_underlying(type), texture.id(), level); + } +} + +bool FrameBuffer::check_status() const { + bind(); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + Logger::error("FBO incomplete after resize!"); + return false; + } else { + Logger::info("Frame Buffer Complete!"); + return true; + } +} + +void FrameBuffer::draw_buffer(GLenum buf) const { + bind(); + glDrawBuffer(buf); +} +void FrameBuffer::read_buffer(GLenum src) const { + bind(); + glReadBuffer(src); +} +void FrameBuffer::draw_buffer(GLsizei n, const GLenum* bufs) const { + bind(); + glDrawBuffers(n, bufs); +} + +void FrameBuffer::draw_buffer(std::span bufs) const { + bind(); + glDrawBuffers(bufs.size(), bufs.data()); +} + +} // namespace Cubed \ No newline at end of file diff --git a/src/player_renderer.cpp b/src/render/player_renderer.cpp similarity index 98% rename from src/player_renderer.cpp rename to src/render/player_renderer.cpp index a40380e..58b937e 100644 --- a/src/player_renderer.cpp +++ b/src/render/player_renderer.cpp @@ -1,9 +1,9 @@ -#include "Cubed/player_renderer.hpp" +#include "Cubed/render/player_renderer.hpp" #include "Cubed/camera.hpp" #include "Cubed/gameplay/client_world.hpp" #include "Cubed/primitive_data.hpp" -#include "Cubed/renderer.hpp" +#include "Cubed/render/renderer.hpp" #include "Cubed/texture_manager.hpp" #include @@ -197,7 +197,7 @@ void PlayerRenderer::render(const Shader& shader) { auto& m_world = m_renderer.world(); auto& m_player = m_world.get_player(); glm::mat4 m_v_mat = m_camera.get_camera_lookat(); - glm::mat4 m_p_mat = m_renderer.proj_mat(); + glm::mat4 m_p_mat = m_renderer.world_proj_matrix(); auto& players = m_world.render_player_data(); shader.set_loc("proj_matrix", m_p_mat); @@ -223,8 +223,7 @@ void PlayerRenderer::render(const Shader& shader) { glm::vec3(0, 1, 0)); model = glm::translate(model, glm::vec3(-0.5f, 0.0f, -0.5f)); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, m_renderer.texture_mamger().get_skin()); + m_renderer.texture_mamger().get_skin()->bind(1); auto make_rotated = [&](glm::vec3 pivot, float angle) { glm::mat4 mat = model; diff --git a/src/render/renderer.cpp b/src/render/renderer.cpp new file mode 100644 index 0000000..8cc4ba1 --- /dev/null +++ b/src/render/renderer.cpp @@ -0,0 +1,298 @@ +#include "Cubed/render/renderer.hpp" + +#include "Cubed/camera.hpp" +#include "Cubed/config.hpp" +#include "Cubed/debug_collector.hpp" +#include "Cubed/dev_panel.hpp" +#include "Cubed/gameplay/client_player.hpp" +#include "Cubed/gameplay/client_world.hpp" +#include "Cubed/primitive_data.hpp" +#include "Cubed/render/renderer_constants.hpp" +#include "Cubed/texture_manager.hpp" +#include "Cubed/tools/font.hpp" +#include "Cubed/tools/log.hpp" +#include "Cubed/tools/shader_tools.hpp" + +#include +#include +#include + +namespace Cubed { + +Renderer::Renderer(const Camera& camera, ClientWorld& world, + const TextureManager& texture_manager, DevPanel& dev_panel) + : m_camera(camera), m_dev_panel(dev_panel), + m_texture_manager(texture_manager), m_world(world), + m_world_renderer(*this) {} + +Renderer::~Renderer() { + if (m_init) { + glBindBuffer(GL_ARRAY_BUFFER, 0); + m_outline_vbo.reset(); + m_outline_indices_vbo.reset(); + m_sky_vbo.reset(); + m_ui_vbo.reset(); + m_player_vbo.reset(); + glBindVertexArray(0); + m_vao.clear(); + } +} + +void Renderer::hot_reload() { + auto& config = Config::get(); + update_fov(config.get("player.fov")); +} + +void Renderer::init(bool debug_on) { + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { + Logger::error("Failed to initialize glad"); + exit(EXIT_FAILURE); + } + Logger::info("OpenGL Version: {}.{}", GLVersion.major, GLVersion.minor); + Logger::info("Renderer: {}", + reinterpret_cast(glGetString(GL_RENDERER))); + + m_shaders.init(); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +#ifdef DEBUG_MODE + if (debug_on) { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback( + [](GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar* message, + const void*) { + Logger::log(Logger::Level::L_DEBUG, + std::source_location::current(), "GL Debug: {}", + reinterpret_cast(message)); + }, + nullptr); + } + +#endif + + m_vao.resize(NUM_VAO); + VertexArray::unbind(); + + m_outline_vbo = std::make_unique(); + m_outline_indices_vbo = + std::make_unique(BufferType::ELEMENT_ARRAY_BUFFER); + m_player_vbo = std::make_unique(); + m_quad_vbo = std::make_unique(); + m_sky_vbo = std::make_unique(); + m_ui_vbo = std::make_unique(); + + m_vao[2].bind(); + + m_outline_vbo->buffer_data(CUBE_VER, sizeof(CUBE_VER)); + m_vao[2].attribute(0, 3, GL_FLOAT, 0, 0); + m_outline_indices_vbo->buffer_data(OUTLINE_CUBE_INDICES, + sizeof(OUTLINE_CUBE_INDICES)); + + m_vao[1].bind(); + m_sky_vbo->buffer_data(VERTICES_POS, sizeof(VERTICES_POS)); + + m_vao[1].attribute(0, 3, GL_FLOAT, 0, 0); + + m_vao[3].bind(); + + for (int i = 0; i < 6; i++) { + Vertex2D vex{SQUARE_VERTICES[i][0], SQUARE_VERTICES[i][1], + SQUARE_TEXTURE_POS[i][0], SQUARE_TEXTURE_POS[i][1], 0}; + m_ui.emplace_back(vex); + } + m_ui_vbo->buffer_data(m_ui.data(), m_ui.size() * sizeof(Vertex2D)); + + m_vao[3].attribute(0, 3, GL_FLOAT, sizeof(Vertex2D), (void*)0); + m_vao[3].attribute(1, 2, GL_FLOAT, sizeof(Vertex2D), + (void*)offsetof(Vertex2D, s)); + m_vao[3].attribute(2, 1, GL_FLOAT, sizeof(Vertex2D), + (void*)offsetof(Vertex2D, layer)); + + init_quad(); + init_text(); + hot_reload(); + + m_world_renderer.init(); + + VertexArray::unbind(); + VertexBuffer::unbind(); + m_init = true; +} + +const Shader& Renderer::get_shader(const std::string& name) const { + return m_shaders.get_shader(name); +} + +void Renderer::init_quad() { + m_vao[0].bind(); + m_quad_vbo->buffer_data(QUAD_VERTICES, sizeof(QUAD_VERTICES)); + + m_vao[0].attribute(0, 2, GL_FLOAT, 4 * sizeof(float), (void*)0); + + m_vao[0].attribute(1, 2, GL_FLOAT, 4 * sizeof(float), + (void*)(2 * sizeof(float))); +} + +void Renderer::init_text() { + m_vao[4].bind(); + + DebugCollector::get().init_text(); +} + +void Renderer::render() { + glDisable(GL_FRAMEBUFFER_SRGB); + // clear screen + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + m_world_renderer.render(); + + render_ui(); + + render_text(); + + render_dev_panel(); +} + +void Renderer::render_text() { + + const auto& shader = get_shader("text"); + + shader.use(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable(GL_DEPTH_TEST); + + shader.set_loc("projection", m_ui_proj_matrix); + + auto& texts = DebugCollector::get().all_texts(); + for (auto& t : texts) { + t.second.render(shader); + } + + glEnable(GL_DEPTH_TEST); +} + +void Renderer::render_ui() { + const auto& shader = get_shader("ui"); + shader.use(); + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + shader.set_loc("m_matrix", m_ui_model_matrix); + shader.set_loc("proj_matrix", m_ui_proj_matrix); + + m_vao[3].bind(); + m_texture_manager.get_ui_array()->bind(0); + + glDrawArrays(GL_TRIANGLES, 0, 6); + Tools::check_opengl_error(); + + glEnable(GL_DEPTH_TEST); +} + +void Renderer::update(float delta_time) { m_delta_time = delta_time; } + +void Renderer::update_fov(float fov) { + m_fov = fov; + + m_world_proj_matrix = + glm::perspective(glm::radians(fov), m_aspect, NEAR_PLANE, FAR_PLANE); +} + +void Renderer::update_proj_matrix(float aspect, float width, float height) { + m_aspect = aspect; + + m_world_proj_matrix = + glm::perspective(glm::radians(m_fov), aspect, NEAR_PLANE, FAR_PLANE); + + m_ui_proj_matrix = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f); + // scale and then translate + m_ui_model_matrix = + glm::translate(glm::mat4(1.0f), + glm::vec3(width / 2.0f, height / 2.0f, 0.0)) * + glm::scale(glm::mat4(1.0f), glm::vec3(50.0f, 50.0f, 1.0f)); +} + +void Renderer::updata_framebuffer(int width, int height) { + if (width <= 0 || height <= 0) + return; + + m_world_renderer.updata_framebuffer(width, height); + + FrameBuffer::unbind(); + + m_width = width; + m_height = height; +} + +void Renderer::render_dev_panel() { + + glDisable(GL_DEPTH_TEST); + m_dev_panel.render(); + glEnable(GL_DEPTH_TEST); +} + +float& Renderer::ambient_strength() { + return m_world_renderer.ambient_strength(); +} +bool& Renderer::discard_transparent() { + return m_world_renderer.discard_transparent(); +} +bool& Renderer::shader_on() { return m_world_renderer.shader_on(); } +bool& Renderer::water_perturb() { return m_world_renderer.water_perturb(); } +bool& Renderer::water_depth_fade() { + return m_world_renderer.water_depth_fade(); +} +bool& Renderer::pbr() { return m_world_renderer.pbr(); } +bool& Renderer::flip_y() { return m_world_renderer.flip_y(); } +int& Renderer::shadow_mode() { return m_world_renderer.shadow_mode(); } +int& Renderer::light_cull_face() { return m_world_renderer.light_cull_face(); } +int& Renderer::light_size_uv() { return m_world_renderer.light_size_uv(); } +float& Renderer::min_radius() { return m_world_renderer.min_radius(); } +float& Renderer::max_radius() { return m_world_renderer.max_radius(); } +int& Renderer::samples() { return m_world_renderer.samples(); } +float& Renderer::specular_strength() { + return m_world_renderer.specular_strength(); +} +float& Renderer::cloud_speed() { return m_world_renderer.cloud_speed(); } +float& Renderer::cloud_threshold_low() { + return m_world_renderer.cloud_threshold_low(); +} +float& Renderer::cloud_threshold_high() { + return m_world_renderer.cloud_threshold_high(); +} +float& Renderer::refract_strength() { + return m_world_renderer.refract_strength(); +} +float& Renderer::underwater_fog_density() { + return m_world_renderer.underwater_fog_density(); +} +float& Renderer::water_density() { return m_world_renderer.water_density(); } + +const Camera& Renderer::camera() const { return m_camera; } +const ClientWorld& Renderer::world() const { return m_world; } +ClientWorld& Renderer::world() { return m_world; } +const glm::mat4& Renderer::world_proj_matrix() const { + return m_world_proj_matrix; +} +const TextureManager& Renderer::texture_mamger() const { + return m_texture_manager; +} + +float Renderer::delta_time() const { return m_delta_time; } + +float Renderer::height() const { return m_height; } +float Renderer::width() const { return m_width; } +const glm::mat4& Renderer::p_mat() const { return m_world_proj_matrix; } +const std::vector& Renderer::vao() const { return m_vao; } +} // namespace Cubed \ No newline at end of file diff --git a/src/render/shader_manager.cpp b/src/render/shader_manager.cpp new file mode 100644 index 0000000..f2e9d28 --- /dev/null +++ b/src/render/shader_manager.cpp @@ -0,0 +1,61 @@ +#include "Cubed/render/shader_manager.hpp" + +#include "Cubed/tools/cubed_assert.hpp" + +namespace Cubed { +ShaderManager::ShaderManager() {} +ShaderManager::~ShaderManager() {} + +void ShaderManager::init() { + register_shader("normal_block", "shaders/block_v_shader.glsl", + "shaders/block_f_shader.glsl"); + register_shader("outline", "shaders/outline_v_shader.glsl", + "shaders/outline_f_shader.glsl"); + register_shader("sky", "shaders/sky_v_shader.glsl", + "shaders/sky_f_shader.glsl"); + register_shader("ui", "shaders/ui_v_shader.glsl", + "shaders/ui_f_shader.glsl"); + register_shader("text", "shaders/text_v_shader.glsl", + "shaders/text_f_shader.glsl"); + register_shader("under_water", "shaders/under_water_v_shader.glsl", + "shaders/under_water_f_shader.glsl"); + register_shader("accum", "shaders/block_accumulation_v_shader.glsl", + "shaders/block_accumulation_f_shader.glsl"); + register_shader("composite", "shaders/block_composite_v_shader.glsl", + "shaders/block_composite_f_shader.glsl"); + register_shader("depth_shader", "shaders/depth_shader.glsl", + "shaders/depth_fragment_shader.glsl"); + register_shader("billboard", "shaders/billboard_v_shader.glsl", + "shaders/billboard_f_shader.glsl"); + register_shader("water", "shaders/water_v_shader.glsl", + "shaders/water_f_shader.glsl"); + register_shader("player", "shaders/player_v_shader.glsl", + "shaders/player_f_shader.glsl"); + register_shader("player_depth", "shaders/depth_player_shader.glsl", + "shaders/depth_player_fragment_shader.glsl"); +} + +void ShaderManager::register_shader(const std::string& name, + const std::string& v_shader, + const std::string& f_shader) { + + auto [_, inserted] = m_shaders.try_emplace(name, name, v_shader, f_shader); + + if (!inserted) { + std::string msg = std::format("Shader name {} already esist!", name); + ASSERT_MSG(false, msg); + throw std::runtime_error(msg); + } +} + +const Shader& ShaderManager::get_shader(const std::string& name) const { + auto it = m_shaders.find(name); + if (it == m_shaders.end()) { + std::string msg = std::format("Shader name {} not find", name); + ASSERT_MSG(false, msg); + throw std::runtime_error(msg); + } + return it->second; +} + +} // namespace Cubed \ No newline at end of file diff --git a/src/render/texture.cpp b/src/render/texture.cpp new file mode 100644 index 0000000..2830472 --- /dev/null +++ b/src/render/texture.cpp @@ -0,0 +1,149 @@ +#include "Cubed/render/texture.hpp" + +#include "Cubed/tools/cubed_assert.hpp" + +#include + +namespace Cubed { +Texture::Texture(TextureType type) : M_TYPE(type) { glGenTextures(1, &m_id); } +Texture::~Texture() { + if (m_id) { + glDeleteTextures(1, &m_id); + } +} +Texture::Texture(Texture&& o) noexcept + : m_id(std::exchange(o.m_id, 0)), M_TYPE(o.M_TYPE) {} + +Texture& Texture::operator=(Texture&& o) noexcept { + if (this == &o) { + return *this; + } + if (M_TYPE != o.M_TYPE) { + ASSERT_MSG(false, "Texture Type is not same"); + } + if (m_id) { + glDeleteTextures(1, &m_id); + } + + m_id = std::exchange(o.m_id, 0); + return *this; +} +void Texture::bind() const { glBindTexture(get_gl_texture_type(), m_id); } + +void Texture::bind(size_t unit) const { + active(unit); + bind(); +} + +GLuint Texture::id() const { return m_id; } + +void Texture::parameter(TexturePname pname, TextureParam param) const { + bind(); + glTexParameteri(get_gl_texture_type(), std::to_underlying(pname), + std::to_underlying(param)); +} +void Texture::parameterfv(TexturePname pname, const float* param) const { + bind(); + glTexParameterfv(get_gl_texture_type(), std::to_underlying(pname), param); +} +void Texture::tex_image_2d(TextureFormat internalformat, TextureFormat format, + GLenum type, const void* data, GLsizei width, + GLsizei height, GLint level, GLint border) const { + bind(); + glTexImage2D(get_gl_texture_type(), level, + std::to_underlying(internalformat), width, height, border, + std::to_underlying(format), type, data); +} + +void Texture::tex_image_3d(TextureFormat internalformat, TextureFormat format, + GLenum type, const void* data, GLsizei width, + GLsizei height, GLsizei depth, GLint level, + GLint border) const { + bind(); + glTexImage3D(get_gl_texture_type(), level, + std::to_underlying(internalformat), width, height, depth, + border, std::to_underlying(format), type, data); +} +void Texture::tex_sub_image_3d(TextureFormat format, GLenum type, + const void* data, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, + GLsizei depth, GLint level) const { + bind(); + glTexSubImage3D(get_gl_texture_type(), level, xoffset, yoffset, zoffset, + width, height, depth, std::to_underlying(format), type, + data); +} +void Texture::set_aniso(int aniso) const { + if (aniso >= 1) { + bind(); + glTexParameterf(get_gl_texture_type(), GL_TEXTURE_MAX_ANISOTROPY, + static_cast(aniso)); + } +} + +void Texture::gen_mipmap() const { + bind(); + glGenerateMipmap(get_gl_texture_type()); +} + +void Texture::set_linear() const { + parameter(TexturePname::MIN_FILTER, TextureParam::LINEAR); + parameter(TexturePname::MAG_FILTER, TextureParam::LINEAR); +} +void Texture::set_nearest_and_minpmap() const { + parameter(TexturePname::MAG_FILTER, TextureParam::NEAREST); + parameter(TexturePname::MIN_FILTER, TextureParam::LINEAR_MIPMAP_LINEAR); + gen_mipmap(); +} +void Texture::set_nearest() const { + parameter(TexturePname::MAG_FILTER, TextureParam::NEAREST); + parameter(TexturePname::MIN_FILTER, TextureParam::NEAREST); +} +void Texture::set_repeat(bool r, bool s, bool t) const { + if (r) { + parameter(TexturePname::WRAP_R, TextureParam::REPEAT); + } + if (s) { + parameter(TexturePname::WRAP_S, TextureParam::REPEAT); + } + if (t) { + parameter(TexturePname::WRAP_T, TextureParam::REPEAT); + } +} +void Texture::set_clamp_to_border(bool r, bool s, bool t) const { + if (r) { + parameter(TexturePname::WRAP_R, TextureParam::CLAMP_TO_BORDER); + } + if (s) { + parameter(TexturePname::WRAP_S, TextureParam::CLAMP_TO_BORDER); + } + if (t) { + parameter(TexturePname::WRAP_T, TextureParam::CLAMP_TO_BORDER); + } +} + +void Texture::set_clamp_to_edge(bool r, bool s, bool t) const { + if (r) { + parameter(TexturePname::WRAP_R, TextureParam::CLAMP_TO_EDGE); + } + if (s) { + parameter(TexturePname::WRAP_S, TextureParam::CLAMP_TO_EDGE); + } + if (t) { + parameter(TexturePname::WRAP_T, TextureParam::CLAMP_TO_EDGE); + } +} + +TextureType Texture::type() const { return M_TYPE; } + +void Texture::unbind() { + glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); +} +void Texture::active(size_t id) { glActiveTexture(GL_TEXTURE0 + id); } + +GLenum Texture::get_gl_texture_type() const { + return std::to_underlying(M_TYPE); +} + +} // namespace Cubed \ No newline at end of file diff --git a/src/render/vertex_array.cpp b/src/render/vertex_array.cpp new file mode 100644 index 0000000..a8122ed --- /dev/null +++ b/src/render/vertex_array.cpp @@ -0,0 +1,39 @@ +#include "Cubed/render/vertex_array.hpp" + +#include + +namespace Cubed { +VertexArray::VertexArray() { glGenVertexArrays(1, &m_vao); } +VertexArray::~VertexArray() { + if (m_vao) { + glDeleteVertexArrays(1, &m_vao); + } +} +VertexArray::VertexArray(VertexArray&& o) noexcept + : m_vao(std::exchange(o.m_vao, 0)) {} + +VertexArray& VertexArray::operator=(VertexArray&& o) noexcept { + if (this != &o) { + if (m_vao) { + glDeleteVertexArrays(1, &m_vao); + } + m_vao = std::exchange(o.m_vao, 0); + } + return *this; +} + +void VertexArray::bind() const { glBindVertexArray(m_vao); } +void VertexArray::unbind() { glBindVertexArray(0); } + +GLuint VertexArray::id() const { return m_vao; } + +void VertexArray::attribute(GLuint index, GLint size, GLenum type, + GLsizei stride, const void* ptr, + bool normalized) const { + bind(); + glVertexAttribPointer(index, size, type, normalized ? GL_TRUE : GL_FALSE, + stride, ptr); + glEnableVertexAttribArray(index); +} + +} // namespace Cubed \ No newline at end of file diff --git a/src/render/vertex_buffer.cpp b/src/render/vertex_buffer.cpp new file mode 100644 index 0000000..83bc540 --- /dev/null +++ b/src/render/vertex_buffer.cpp @@ -0,0 +1,52 @@ +#include "Cubed/render/vertex_buffer.hpp" + +#include + +namespace Cubed { +VertexBuffer::VertexBuffer(BufferType type) : m_type(type) { + glGenBuffers(1, &m_vbo); +} +VertexBuffer::~VertexBuffer() { + if (m_vbo) { + glDeleteBuffers(1, &m_vbo); + } +} + +VertexBuffer::VertexBuffer(VertexBuffer&& o) noexcept + : m_vbo(std::exchange(o.m_vbo, 0)), m_type(o.m_type) {} + +VertexBuffer& VertexBuffer::operator=(VertexBuffer&& o) noexcept { + if (this != &o) { + if (m_vbo) { + glDeleteBuffers(1, &m_vbo); + } + m_vbo = std::exchange(o.m_vbo, 0); + m_type = o.m_type; + } + + return *this; +} + +void VertexBuffer::bind() const { glBindBuffer(get_buffer_target(), m_vbo); } + +void VertexBuffer::unbind() { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +GLuint VertexBuffer::id() const { return m_vbo; } + +GLenum VertexBuffer::get_buffer_target() const { + return std::to_underlying(m_type); +} + +void VertexBuffer::buffer_data(const void* data, GLsizeiptr size, + BufferUsage usage) const { + bind(); + + GLenum target = get_buffer_target(); + + glBufferData(target, size, data, std::to_underlying(usage)); +} + +} // namespace Cubed \ No newline at end of file diff --git a/src/render/world_renderer.cpp b/src/render/world_renderer.cpp new file mode 100644 index 0000000..c699205 --- /dev/null +++ b/src/render/world_renderer.cpp @@ -0,0 +1,851 @@ +#include "Cubed/render/world_renderer.hpp" + +#include "Cubed/camera.hpp" +#include "Cubed/debug_collector.hpp" +#include "Cubed/gameplay/client_world.hpp" +#include "Cubed/render/renderer.hpp" +#include "Cubed/render/renderer_constants.hpp" +#include "Cubed/texture_manager.hpp" +#include "Cubed/tools/math_tools.hpp" +namespace Cubed { +WorldRenderer::WorldRenderer(Renderer& renderer) + : m_renderer(renderer), m_player_renderer(renderer), + m_world(renderer.world()), m_camera(renderer.camera()), + m_texture_manager(renderer.texture_mamger()) {} +WorldRenderer::~WorldRenderer() { + m_accum_texture.reset(); + m_reveal_texture.reset(); + + m_world_fbo.reset(); + m_screen_texture.reset(); + m_screen_depth_texture.reset(); + + m_oit_fbo.reset(); + + m_oit_depth_texture.reset(); + + m_depth_map_fbo.reset(); + m_depth_map_texture.reset(); +} + +void WorldRenderer::init() { m_player_renderer.init(); } + +void WorldRenderer::render() { + // update view matrix; + view_matrix = m_renderer.camera().get_camera_lookat(); + + m_world_fbo->bind(); + // clear world framebuffer + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + day_night_calculation(); + + render_sky(); + render_world(); + render_outline(); + render_player(); + + FrameBuffer::unbind(); + + glEnable(GL_FRAMEBUFFER_SRGB); + + glDisable(GL_DEPTH_TEST); + // clear screen + glClearColor(0.0f, 0.0f, 0.0f, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + render_underwater(); + glDisable(GL_FRAMEBUFFER_SRGB); +} + +void WorldRenderer::day_night_calculation() { + + m_parallel_light.sundir = glm::normalize(m_renderer.world().sunlight_dir()); + m_parallel_light.sun_height = (-m_parallel_light.sundir).y; + m_parallel_light.lightdir = m_parallel_light.sundir; + + m_parallel_light.day_light = + glm::smoothstep(0.15f, 0.3f, m_parallel_light.sun_height); + + m_parallel_light.sun_color = mix(SUNSET_SUNLIGHT_COLOR, NOON_SUNLIGHT_COLOR, + m_parallel_light.day_light); + + glm::vec3 ambient_color = mix(SUNSET_AMBIENT_COLOR, NOON_AMBIENT_COLOR, + m_parallel_light.day_light); + + m_parallel_light.day_factor = + glm::smoothstep(-0.15f, 0.05f, m_parallel_light.sun_height); + + auto day_factor = m_parallel_light.day_factor; + + float light_intensity = + glm::smoothstep(moon_intensity, sun_intensity, day_factor); + + m_parallel_light.directional_light_color = + glm::mix(MOON_COLOR, m_parallel_light.sun_color, day_factor) * + light_intensity; + + m_parallel_light.finnal_ambient_color = + glm::mix(NIGHT_AMBIENT_COLOR, ambient_color, day_factor); + + m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor); +} + +void WorldRenderer::render_sky() { + + glm::vec3 zenith = {0.20f, 0.45f, 0.95f}; + + glm::vec3 horizon = {0.55f, 0.75f, 1.00f}; + + glm::vec3 sunset_zenith = {0.05f, 0.10f, 0.25f}; + + glm::vec3 sunset_horizon = {1.0f, 0.35f, 0.10f}; + + glm::vec3 night_zenith = {0.018f, 0.023f, 0.048f}; + glm::vec3 night_horizon = {0.022f, 0.027f, 0.052f}; + + constexpr float NIGHT_SHARPNESS = 0.35f; + constexpr float SUNSET_SHARPNESS = 0.6f; + constexpr float NOON_SHARPNESS = 0.35f; + + constexpr float NIGHT_CLOUD_MIX = 0.3f; + constexpr float SUNSET_CLOUD_MIX = 0.4f; + constexpr float NOON_CLOUD_MIX = 0.7; + + glm::vec3 day_top = mix(sunset_zenith, zenith, m_parallel_light.day_light); + + glm::vec3 day_bottom = + mix(sunset_horizon, horizon, m_parallel_light.day_light); + + m_sky_uniform.sky_top = + mix(night_zenith, day_top, m_parallel_light.day_factor); + + m_sky_uniform.sky_bottom = + mix(night_horizon, day_bottom, m_parallel_light.day_factor); + + float day_sharpness = + glm::mix(SUNSET_SHARPNESS, NOON_SHARPNESS, m_parallel_light.day_light); + + m_sky_uniform.horizon_sharpness = + glm::mix(NIGHT_SHARPNESS, day_sharpness, m_parallel_light.day_factor); + + float day_cloud_mix = + glm::mix(SUNSET_CLOUD_MIX, NOON_CLOUD_MIX, m_parallel_light.day_light); + + m_sky_uniform.cloud_white_mix = + glm::mix(NIGHT_CLOUD_MIX, day_cloud_mix, m_parallel_light.day_factor); + + m_cloud_time += m_renderer.delta_time() * m_cloud_speed; + + const auto& sky_shader = m_renderer.get_shader("sky"); + + sky_shader.use(); + + glm::mat4 model_mat = + glm::translate(glm::mat4(1.0f), + m_camera.get_camera_pos() - glm::vec3(0.5f, 0.5f, 0.5f)); + + glm::mat4 mv_mat = view_matrix * model_mat; + + auto& proj_mat = m_renderer.p_mat(); + + m_sky_uniform.sun_dir_view = (-m_parallel_light.sundir); + + sky_shader.set_loc("mv_matrix", mv_mat); + sky_shader.set_loc("proj_matrix", proj_mat); + sky_shader.set_loc("skyTop", m_sky_uniform.sky_top); + sky_shader.set_loc("skyBottom", m_sky_uniform.sky_bottom); + sky_shader.set_loc("sunDir", m_sky_uniform.sun_dir_view); + sky_shader.set_loc("sunColor", m_parallel_light.directional_light_color); + sky_shader.set_loc("horizonSharpness", m_sky_uniform.horizon_sharpness); + sky_shader.set_loc("time", m_cloud_time); + sky_shader.set_loc("cloudWhiteMix", m_sky_uniform.cloud_white_mix); + sky_shader.set_loc("cloudThresholdLow", m_cloud_threshold_low); + sky_shader.set_loc("cloudThresholdHigh", m_cloud_threshold_high); + + auto& m_vao = m_renderer.vao(); + + m_vao[1].bind(); + + glDisable(GL_DEPTH_TEST); + + glDrawArrays(GL_TRIANGLES, 0, 36); + glEnable(GL_DEPTH_TEST); + + // draw sun and moon + const auto& billboard = m_renderer.get_shader("billboard"); + billboard.use(); + glDepthMask(GL_FALSE); + + m_vao[0].bind(); + auto billboard_drawer = [this, &billboard, + &proj_mat](const glm::vec3& pos, float size, + const glm::vec3& color) { + glm::vec3 view_pos = glm::vec3(view_matrix * glm::vec4(pos, 1.0f)); + glm::mat4 mv_mat = + glm::translate(glm::mat4(1.0f), view_pos) * + glm::scale(glm::mat4(1.0f), glm::vec3(size)) * + glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, -0.5f, 0.0f)); + + billboard.set_loc("mv_matrix", mv_mat); + billboard.set_loc("proj_matrix", proj_mat); + billboard.set_loc("color", color); + + glDrawArrays(GL_TRIANGLES, 0, 6); + }; + // draw sun + glm::vec3 sun_pos = m_camera.get_camera_pos() + + normalize(-m_world.sunlight_dir()) * (FAR_PLANE * 0.9f); + billboard_drawer(sun_pos, SUN_SIZE, SUN_COLOR); + + // draw moon + + glm::vec3 moon_pos = m_camera.get_camera_pos() + + normalize(m_world.sunlight_dir()) * (FAR_PLANE * 0.9f); + billboard_drawer(moon_pos, MOON_SIZE, MOON_COLOR); + + glDepthMask(GL_TRUE); +} + +void WorldRenderer::render_world() { + + // shader map + + auto m_height = m_renderer.height(); + auto m_width = m_renderer.width(); + + glm::mat4 model_mat = + glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); + + glm::mat4 mv_mat = view_matrix * model_mat; + + glm::mat4 norm_mat = glm::transpose(glm::inverse(mv_mat)); + + if (m_shader_on) { + shadow_map_generate(); + } + + m_world_fbo->bind(); + + glCullFace(GL_BACK); + glViewport(0, 0, m_width, m_height); + + render_normal_block(model_mat, mv_mat, norm_mat); + + // copy depth buffer + m_world_fbo->bind(FrameBufferType::READ_FRAMEBUFFER); + + m_oit_fbo->bind(FrameBufferType::DRAW_FRAMEBUFFER); + + glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, + GL_DEPTH_BUFFER_BIT, GL_NEAREST); + m_oit_fbo->bind(FrameBufferType::DRAW_FRAMEBUFFER); + + // pass one accumulate + m_oit_fbo->bind(); + + glClearBufferfv(GL_COLOR, 0, glm::value_ptr(glm::vec4(0.0f))); + float one = 1.0f; + glClearBufferfv(GL_COLOR, 1, &one); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glEnable(GL_BLEND); + glBlendFunci(0, GL_ONE, GL_ONE); + + glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + render_transparent_block(mv_mat, norm_mat); +} + +void WorldRenderer::render_outline() { + const auto& shader = m_renderer.get_shader("outline"); + shader.use(); + + const auto& block_pos = m_renderer.world().get_look_block_pos(); + + if (block_pos != std::nullopt) { + + glm::mat4 model_mat = + glm::translate(glm::mat4(1.0f), glm::vec3(block_pos.value().pos)); + + glm::mat4 m_mv_mat = view_matrix * model_mat; + auto& proj_mat = m_renderer.p_mat(); + shader.set_loc("mv_matrix", m_mv_mat); + shader.set_loc("proj_matrix", proj_mat); + + auto& m_vao = m_renderer.vao(); + m_vao[2].bind(); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glLineWidth(4.0f); + glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0); + } +} + +void WorldRenderer::shadow_map_generate() { + float texels_per_unit = 0.0f; + const auto& lightdir = m_parallel_light.lightdir; + + auto m_delta_time = m_renderer.delta_time(); + + // shader map + glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix; + + auto& m_render_snapshots = m_world.render_snapshots(); + auto& camera_pos = m_camera.get_camera_pos(); + + const auto& depth_shader = m_renderer.get_shader("depth_shader"); + + depth_shader.use(); + + glm::vec3 cam_pos = m_camera.get_camera_pos(); + glm::vec3 cam_fwd = m_camera.get_camera_front(); + float half_extent = 128.0f; + + glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f); + + glm::vec3 raw_shadow_lightdir = + quantize_sun_direction(lightdir, ANGLE_STEP_DEG); + glm::vec3 shadow_lightdir = + get_smoothed_shadow_lightdir(raw_shadow_lightdir, m_delta_time); + glm::vec3 up = fabs(shadow_lightdir.y) > 0.99f ? glm::vec3(0, 0, 1) + : glm::vec3(0, 1, 0); + + glm::mat4 light_basis = glm::lookAt(glm::vec3(0.0f), shadow_lightdir, up); + texels_per_unit = DEPTH_MAP_SIZE / (half_extent * 2.0f); + glm::vec3 ls_center = glm::vec3(light_basis * glm::vec4(center, 1.0f)); + ls_center.x = std::round(ls_center.x * texels_per_unit) / texels_per_unit; + ls_center.y = std::round(ls_center.y * texels_per_unit) / texels_per_unit; + glm::vec3 snapped_center = + glm::vec3(glm::inverse(light_basis) * glm::vec4(ls_center, 1.0f)); + + float distance = half_extent * 1.5f; + float near_plane = 1.0f; + float far_plane = distance + half_extent * 2.0f; + glm::vec3 light_pos = snapped_center - shadow_lightdir * distance; + glm::mat4 light_view = glm::lookAt(light_pos, snapped_center, up); + glm::mat4 light_projection = + glm::ortho(-half_extent, half_extent, -half_extent, half_extent, + near_plane, far_plane); + + light_space_matrix = light_projection * light_view; + depth_shader.set_loc("lightSpaceMatrix", light_space_matrix); + depth_shader.set_loc("is_discard_tranparent", m_discard_tranparent); + + glViewport(0, 0, DEPTH_MAP_SIZE, DEPTH_MAP_SIZE); + if (m_light_cull_face == 0) { + glCullFace(GL_FRONT); + } else if (m_light_cull_face == 1) { + glCullFace(GL_BACK); + } else { + Logger::warn("Light Cull Face {} Over The Max Selection", + m_light_cull_face); + glCullFace(GL_BACK); + } + + m_depth_map_fbo->bind(); + glClear(GL_DEPTH_BUFFER_BIT); + + glEnable(GL_DEPTH_TEST); + for (const auto& snapshot : m_render_snapshots) { + if (!snapshot) { + continue; + } + m_texture_manager.get_texture_array()->bind(1); + glBindVertexArray(snapshot->normal_vao); + + glDrawArrays(GL_TRIANGLES, 0, snapshot->normal_vertices_count); + } + + // cross_plane and discard + + for (const auto& snapshot : m_render_snapshots) { + if (!snapshot) { + continue; + } + glm::vec2 camera_pos_xz{camera_pos.x, camera_pos.z}; + if (snapshot->cross_vertices_count != 0) { + glm::vec2 center_xz{snapshot->center.x, snapshot->center.z}; + float dist2d = glm::distance(camera_pos_xz, center_xz); + if (dist2d <= CROSS_PLANE_DISTANCE * 16) { + m_texture_manager.get_cross_plane_array()->bind(1); + glBindVertexArray(snapshot->cross_vao); + + glDrawArrays(GL_TRIANGLES, 0, snapshot->cross_vertices_count); + } + } + if (snapshot->normal_discard_vertices_count != 0) { + + m_texture_manager.get_texture_array()->bind(1); + + glBindVertexArray(snapshot->normal_discard_vao); + + glDrawArrays(GL_TRIANGLES, 0, + snapshot->normal_discard_vertices_count); + } + } + // player + auto& player_shadow = m_renderer.get_shader("player_depth"); + m_player_renderer.shadow_render(player_shadow, light_space_matrix); +} + +void WorldRenderer::render_underwater() { + + const auto& shader = m_renderer.get_shader("under_water"); + + shader.use(); + + auto& m_vao = m_renderer.vao(); + + m_vao[0].bind(); + + auto& proj_mat = m_renderer.p_mat(); + + shader.set_loc("u_sceneTexture", 0); + shader.set_loc("u_time", static_cast(glfwGetTime())); + shader.set_loc("u_underwater", m_camera.is_under_water()); + shader.set_loc("u_waterColor", glm::vec3(0.1f, 0.25f, 0.35f)); + shader.set_loc("u_fogDensity", m_underwater_fog_density); + shader.set_loc("cameraPos", m_camera.get_camera_pos()); + shader.set_loc("sunDir", -m_parallel_light.sundir); + shader.set_loc("waterDensity", m_water_density); + shader.set_loc("InverseViewProjection", + glm::inverse(proj_mat * view_matrix)); + shader.set_loc("sunColor", m_parallel_light.sun_color); + shader.set_loc("u_lightSpaceMatrix", m_parallel_light.light_space_matrix); + + m_screen_texture->bind(0); + m_screen_depth_texture->bind(1); + m_depth_map_texture->bind(2); + + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); +} + +void WorldRenderer::render_normal_block(const glm::mat4& model_mat, + const glm::mat4& mv_mat, + const glm::mat4& norm_mat) { + + // shader map + glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix; + + auto& m_render_snapshots = m_world.render_snapshots(); + auto& camera_pos = m_camera.get_camera_pos(); + + const auto& lightdir = m_parallel_light.lightdir; + + const auto& normal_block_shader = m_renderer.get_shader("normal_block"); + + normal_block_shader.use(); + + glm::vec3 light_dir_view = + glm::normalize(glm::mat3(view_matrix) * lightdir); + auto& proj_mat = m_renderer.p_mat(); + auto m_pbr = m_renderer.pbr(); + + normal_block_shader.set_loc("enablePBR", m_pbr); + normal_block_shader.set_loc("model_matrix", model_mat); + normal_block_shader.set_loc("mv_matrix", mv_mat); + normal_block_shader.set_loc("proj_matrix", proj_mat); + normal_block_shader.set_loc("norm_matrix", norm_mat); + normal_block_shader.set_loc("lightSpaceMatrix", light_space_matrix); + normal_block_shader.set_loc("ambientStrength", m_ambient_strength); + normal_block_shader.set_loc("sunlightColor", + m_parallel_light.directional_light_color); + normal_block_shader.set_loc("ambientColor", + m_parallel_light.finnal_ambient_color); + normal_block_shader.set_loc("sunlightDir", light_dir_view); + normal_block_shader.set_loc("shadowMode", m_shadow_mode); + normal_block_shader.set_loc("shader_on", m_shader_on); + normal_block_shader.set_loc("lightSizeUV", + static_cast(m_light_size_uv)); + + normal_block_shader.set_loc("minRadius", m_min_radius); + normal_block_shader.set_loc("maxRadius", m_max_radius); + normal_block_shader.set_loc("samples", m_samples); + normal_block_shader.set_loc("specularStrength", m_specular_strength); + normal_block_shader.set_loc("cameraPos", m_camera.get_camera_pos()); + normal_block_shader.set_loc("flipY", m_flip_y); + normal_block_shader.set_loc("renderDistance", m_world.rendering_distance()); + normal_block_shader.set_loc("skyColor", m_sky_uniform.sky_top); + + glm::mat4 mvp_mat = proj_mat * mv_mat; + + auto& m_planes = m_world.planes(); + + Math::extract_frustum_planes(mvp_mat, m_planes); + + int rendered_sum = 0; + + glEnable(GL_DEPTH_TEST); + + m_depth_map_texture->bind(0); + + m_texture_manager.get_texture_array()->bind(1); + + m_texture_manager.get_pbr_texture()->bind(2); + // normal block + for (const auto& snapshot : m_render_snapshots) { + if (!snapshot) { + continue; + } + if (Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, + m_planes)) { + + glBindVertexArray(snapshot->normal_vao); + + glDrawArrays(GL_TRIANGLES, 0, snapshot->normal_vertices_count); + + rendered_sum++; + } + } + // discard + for (const auto& snapshot : m_render_snapshots) { + if (!snapshot) { + continue; + } + if (!Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, + m_planes)) { + continue; + } + if (snapshot->normal_discard_vertices_count != 0) { + glBindVertexArray(snapshot->normal_discard_vao); + + glDrawArrays(GL_TRIANGLES, 0, + snapshot->normal_discard_vertices_count); + } + } + // cross_plane + m_texture_manager.get_cross_plane_array()->bind(1); + normal_block_shader.set_loc("enablePBR", false); + for (const auto& snapshot : m_render_snapshots) { + if (!snapshot) { + continue; + } + if (!Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, + m_planes)) { + continue; + } + glm::vec2 camera_pos_xz{camera_pos.x, camera_pos.z}; + if (snapshot->cross_vertices_count != 0) { + glm::vec2 center_xz{snapshot->center.x, snapshot->center.z}; + float dist2d = glm::distance(camera_pos_xz, center_xz); + if (dist2d <= CROSS_PLANE_DISTANCE * 16) { + glBindVertexArray(snapshot->cross_vao); + + glDrawArrays(GL_TRIANGLES, 0, snapshot->cross_vertices_count); + } + } + } + DebugCollector::get().report( + "rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum)); +} + +void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat, + const glm::mat4& norm_mat) { + + auto& m_render_snapshots = m_world.render_snapshots(); + + const auto& lightdir = m_parallel_light.lightdir; + glm::vec3 light_dir_view = + glm::normalize(glm::mat3(view_matrix) * lightdir); + + auto& m_p_mat = m_renderer.p_mat(); + + auto set_accum_loc = [&](const Shader& accum_shader) { + accum_shader.set_loc("mv_matrix", mv_mat); + accum_shader.set_loc("proj_matrix", m_p_mat); + accum_shader.set_loc("norm_matrix", norm_mat); + accum_shader.set_loc("ambientStrength", m_ambient_strength); + accum_shader.set_loc("sunlightColor", + m_parallel_light.directional_light_color); + accum_shader.set_loc("ambientColor", + m_parallel_light.finnal_ambient_color); + accum_shader.set_loc("sunlightDir", light_dir_view); + accum_shader.set_loc("shader_on", m_shader_on); + accum_shader.set_loc("specularStrength", m_specular_strength); + }; + // accum pass + auto& accum_shader = m_renderer.get_shader("accum"); + accum_shader.use(); + + set_accum_loc(accum_shader); + accum_shader.set_loc("cameraPos", m_camera.get_camera_pos()); + + m_texture_manager.get_texture_array()->bind(0); + + auto& m_planes = m_world.planes(); + + for (const auto& snapshot : m_render_snapshots) { + if (!snapshot) { + continue; + } + if (!Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, + m_planes)) { + continue; + } + + if (snapshot->normal_blend_vertices_count != 0) { + + glBindVertexArray(snapshot->normal_blend_vao); + + glDrawArrays(GL_TRIANGLES, 0, + snapshot->normal_blend_vertices_count); + } + } + + // use SSR + + auto& water_shader = m_renderer.get_shader("water"); + water_shader.use(); + + set_accum_loc(water_shader); + + water_shader.set_loc("sceneColorTex", 1); + water_shader.set_loc("sceneDepthTex", 2); + water_shader.set_loc("inv_proj_matrix", glm::inverse(m_p_mat)); + water_shader.set_loc("inv_view_matrix", glm::inverse(view_matrix)); + + // sky loc + water_shader.set_loc("skyTop", m_sky_uniform.sky_top); + water_shader.set_loc("skyBottom", m_sky_uniform.sky_bottom); + water_shader.set_loc("sunDir", m_sky_uniform.sun_dir_view); + water_shader.set_loc("sunColor", m_parallel_light.directional_light_color); + water_shader.set_loc("horizonSharpness", m_sky_uniform.horizon_sharpness); + water_shader.set_loc("time", glfwGetTime()); + water_shader.set_loc("cloudWhiteMix", m_sky_uniform.cloud_white_mix); + water_shader.set_loc("cloudThresholdLow", m_cloud_threshold_low); + water_shader.set_loc("cloudThresholdHigh", m_cloud_threshold_high); + water_shader.set_loc("underwater", m_camera.is_under_water()); + water_shader.set_loc("refractStrength", m_refract_strength); + water_shader.set_loc("enablePerturb", m_water_perturb); + water_shader.set_loc("enableDepthFade", m_water_depth_fade); + + m_screen_texture->bind(1); + m_screen_depth_texture->bind(2); + m_texture_manager.get_texture_array()->bind(0); + + for (const auto& snapshot : m_render_snapshots) { + if (!snapshot) { + continue; + } + if (!Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, + m_planes)) { + continue; + } + + if (snapshot->water_vertices_count != 0) { + + glBindVertexArray(snapshot->water_vao); + + glDrawArrays(GL_TRIANGLES, 0, snapshot->water_vertices_count); + } + } + // composite pass + + auto& composite_shader = m_renderer.get_shader("composite"); + glDisable(GL_BLEND); + + composite_shader.use(); + composite_shader.set_loc("u_accumTex", 0); + composite_shader.set_loc("u_revealTex", 1); + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + auto& m_vao = m_renderer.vao(); + m_vao[0].bind(); + + m_accum_texture->bind(0); + m_reveal_texture->bind(1); + + m_world_fbo->bind(); + + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); +} + +void WorldRenderer::render_player() { + auto& shader = m_renderer.get_shader("player"); + shader.use(); + glm::vec3 light_dir_view = + glm::normalize(glm::mat3(view_matrix) * m_parallel_light.lightdir); + + shader.set_loc("lightSpaceMatrix", m_parallel_light.light_space_matrix); + shader.set_loc("ambientStrength", m_ambient_strength); + shader.set_loc("sunlightColor", m_parallel_light.directional_light_color); + shader.set_loc("ambientColor", m_parallel_light.finnal_ambient_color); + shader.set_loc("sunlightDir", light_dir_view); + shader.set_loc("shadowMode", m_shadow_mode); + shader.set_loc("shader_on", m_shader_on); + shader.set_loc("lightSizeUV", static_cast(m_light_size_uv)); + shader.set_loc("minRadius", m_min_radius); + shader.set_loc("maxRadius", m_max_radius); + shader.set_loc("samples", m_samples); + + // shader.set_loc("renderDistance", m_world.rendering_distance()); + // shader.set_loc("skyColor", m_sky_uniform.sky_top); + + m_depth_map_texture->bind(0); + m_player_renderer.render(shader); +} + +glm::vec3 WorldRenderer::quantize_sun_direction(const glm::vec3& lightdir, + float angle_step_deg) const { + float elevation = std::asin(glm::clamp(lightdir.y, -1.0f, 1.0f)); + float azimuth = std::atan2(lightdir.z, lightdir.x); + + float step = glm::radians(angle_step_deg); + + float quantized_elevation = std::round(elevation / step) * step; + float quantized_azimuth = std::round(azimuth / step) * step; + + glm::vec3 quantized_dir; + quantized_dir.x = + std::cos(quantized_elevation) * std::cos(quantized_azimuth); + quantized_dir.z = + std::cos(quantized_elevation) * std::sin(quantized_azimuth); + quantized_dir.y = std::sin(quantized_elevation); + + return glm::normalize(quantized_dir); +} + +glm::vec3 WorldRenderer::get_smoothed_shadow_lightdir( + const glm::vec3& raw_shadow_lightdir, float dt) { + if (!m_blend_initialized) { + + m_blend_from_lightdir = raw_shadow_lightdir; + m_blend_to_lightdir = raw_shadow_lightdir; + m_blend_t = 1.0f; + m_blend_initialized = true; + return raw_shadow_lightdir; + } + + if (raw_shadow_lightdir != m_blend_to_lightdir) { + glm::vec3 current_displayed = glm::normalize( + Math::slerp(m_blend_from_lightdir, m_blend_to_lightdir, m_blend_t)); + + m_blend_from_lightdir = current_displayed; + m_blend_to_lightdir = raw_shadow_lightdir; + m_blend_t = 0.0f; + } + + m_blend_t = glm::min(m_blend_t + dt / BLEND_DURATION, 1.0f); + + return glm::normalize( + Math::slerp(m_blend_from_lightdir, m_blend_to_lightdir, m_blend_t)); +} + +void WorldRenderer::updata_framebuffer(int width, int height) { + if (width <= 0 || height <= 0) + return; + if (m_world_fbo == 0) { + m_world_fbo = std::make_unique(); + } + if (m_oit_fbo == 0) { + m_oit_fbo = std::make_unique(); + } + + m_screen_texture = std::make_unique(TextureType::TEXTURE_2D); + m_screen_texture->tex_image_2d(TextureFormat::RGB, TextureFormat::RGB, + GL_UNSIGNED_BYTE, nullptr, width, height); + + m_screen_texture->set_linear(); + + m_world_fbo->attach(Attachment::COLOR_ATTACHMENT0, *m_screen_texture); + + m_screen_depth_texture = std::make_unique(TextureType::TEXTURE_2D); + m_screen_depth_texture->tex_image_2d(TextureFormat::DEPTH_COMPONENT32F, + TextureFormat::DEPTH_COMPONENT, + GL_FLOAT, nullptr, width, height); + // m_screen_depth_texture->set_nearest(); + m_screen_depth_texture->set_linear(); + m_world_fbo->attach(Attachment::DEPTH_ATTACHMENT, *m_screen_depth_texture); + + m_world_fbo->check_status(); + m_accum_texture = std::make_unique(TextureType::TEXTURE_2D); + m_accum_texture->tex_image_2d(TextureFormat::RGBA16F, TextureFormat::RGBA, + GL_HALF_FLOAT, nullptr, width, height); + m_accum_texture->set_linear(); + + m_oit_fbo->attach(Attachment::COLOR_ATTACHMENT0, *m_accum_texture); + m_reveal_texture = std::make_unique(TextureType::TEXTURE_2D); + m_reveal_texture->tex_image_2d(TextureFormat::R16F, TextureFormat::RED, + GL_HALF_FLOAT, nullptr, width, height); + m_reveal_texture->set_linear(); + m_oit_fbo->attach(Attachment::COLOR_ATTACHMENT1, *m_reveal_texture); + m_oit_depth_texture = std::make_unique(TextureType::TEXTURE_2D); + m_oit_depth_texture->tex_image_2d(TextureFormat::DEPTH_COMPONENT32F, + TextureFormat::DEPTH_COMPONENT, GL_FLOAT, + nullptr, width, height); + // m_oit_depth_texture->set_nearest(); + m_oit_depth_texture->set_linear(); + m_oit_fbo->attach(Attachment::DEPTH_ATTACHMENT, *m_oit_depth_texture); + + std::array draw_buffer = {GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1}; + m_oit_fbo->draw_buffer(draw_buffer); + + m_oit_fbo->check_status(); + + // depth map fbo + if (m_depth_map_fbo == 0) { + m_depth_map_fbo = std::make_unique(); + } + + m_depth_map_texture = std::make_unique(TextureType::TEXTURE_2D); + + m_depth_map_texture->tex_image_2d(TextureFormat::DEPTH_COMPONENT32F, + TextureFormat::DEPTH_COMPONENT, GL_FLOAT, + nullptr, DEPTH_MAP_SIZE, DEPTH_MAP_SIZE); + m_depth_map_texture->set_linear(); + m_depth_map_texture->set_clamp_to_border(false, true, true); + float border_color[] = {1.0f, 1.0f, 1.0f, 1.0f}; + // Manually compare shadows + m_depth_map_texture->parameterfv(TexturePname::BORDER_COLOR, border_color); + m_depth_map_texture->parameter(TexturePname::COMPARE_MODE, + TextureParam::T_NONE); + + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, + // GL_COMPARE_REF_TO_TEXTURE); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + m_depth_map_fbo->attach(Attachment::DEPTH_ATTACHMENT, *m_depth_map_texture); + m_depth_map_fbo->draw_buffer(GL_NONE); + m_depth_map_fbo->read_buffer(GL_NONE); + m_depth_map_fbo->check_status(); + + FrameBuffer::unbind(); +} + +float& WorldRenderer::underwater_fog_density() { + return m_underwater_fog_density; +} +float& WorldRenderer::water_density() { return m_water_density; } +const FrameBuffer* WorldRenderer::world_fbo() const { + return m_world_fbo.get(); +} +float& WorldRenderer::ambient_strength() { return m_ambient_strength; } +bool& WorldRenderer::discard_transparent() { return m_discard_tranparent; } +bool& WorldRenderer::shader_on() { return m_shader_on; } +bool& WorldRenderer::water_perturb() { return m_water_perturb; } +bool& WorldRenderer::water_depth_fade() { return m_water_depth_fade; } +bool& WorldRenderer::pbr() { return m_pbr; } +bool& WorldRenderer::flip_y() { return m_flip_y; } +int& WorldRenderer::shadow_mode() { return m_shadow_mode; } +int& WorldRenderer::light_cull_face() { return m_light_cull_face; } +int& WorldRenderer::light_size_uv() { return m_light_size_uv; } +float& WorldRenderer::min_radius() { return m_min_radius; } +float& WorldRenderer::max_radius() { return m_max_radius; } +int& WorldRenderer::samples() { return m_samples; } +float& WorldRenderer::specular_strength() { return m_specular_strength; } +float& WorldRenderer::cloud_speed() { return m_cloud_speed; } +float& WorldRenderer::cloud_threshold_low() { return m_cloud_threshold_low; } +float& WorldRenderer::cloud_threshold_high() { return m_cloud_threshold_high; } +float& WorldRenderer::refract_strength() { return m_refract_strength; } + +} // namespace Cubed \ No newline at end of file diff --git a/src/renderer.cpp b/src/renderer.cpp deleted file mode 100644 index b0e1f72..0000000 --- a/src/renderer.cpp +++ /dev/null @@ -1,1079 +0,0 @@ -#include "Cubed/renderer.hpp" - -#include "Cubed/camera.hpp" -#include "Cubed/config.hpp" -#include "Cubed/debug_collector.hpp" -#include "Cubed/dev_panel.hpp" -#include "Cubed/gameplay/client_player.hpp" -#include "Cubed/gameplay/client_world.hpp" -#include "Cubed/primitive_data.hpp" -#include "Cubed/texture_manager.hpp" -#include "Cubed/tools/cubed_assert.hpp" -#include "Cubed/tools/cubed_hash.hpp" -#include "Cubed/tools/font.hpp" -#include "Cubed/tools/log.hpp" -#include "Cubed/tools/math_tools.hpp" -#include "Cubed/tools/shader_tools.hpp" - -#include -#include -#include - -namespace Cubed { - -Renderer::Renderer(const Camera& camera, ClientWorld& world, - const TextureManager& texture_manager, DevPanel& dev_panel) - : m_camera(camera), m_dev_panel(dev_panel), - m_texture_manager(texture_manager), m_world(world), - m_player_renderer(*this) {} - -Renderer::~Renderer() { - if (m_init) { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDeleteBuffers(1, &m_outline_vbo); - glDeleteBuffers(1, &m_outline_indices_vbo); - glDeleteBuffers(1, &m_sky_vbo); - glDeleteBuffers(1, &m_ui_vbo); - glDeleteBuffers(1, &m_text_vbo); - glDeleteBuffers(1, &m_player_vbo); - glBindVertexArray(0); - glDeleteVertexArrays(NUM_VAO, m_vao.data()); - glDeleteFramebuffers(1, &m_fbo); - glDeleteTextures(1, &m_screen_texture); - glDeleteTextures(1, &m_screen_depth_texture); - - glDeleteFramebuffers(1, &m_oit_fbo); - glDeleteTextures(1, &m_accum_texture); - glDeleteTextures(1, &m_reveal_texture); - glDeleteTextures(1, &m_oit_depth_texture); - - glDeleteFramebuffers(1, &m_depth_map_fbo); - glDeleteTextures(1, &m_depth_map_texture); - } -} - -void Renderer::hot_reload() { - auto& config = Config::get(); - update_fov(config.get("player.fov")); -} - -void Renderer::init(bool debug_on) { - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { - Logger::error("Failed to initialize glad"); - exit(EXIT_FAILURE); - } - Logger::info("OpenGL Version: {}.{}", GLVersion.major, GLVersion.minor); - Logger::info("Renderer: {}", - reinterpret_cast(glGetString(GL_RENDERER))); - - Shader world_shader{"normal_block", "shaders/block_v_shader.glsl", - "shaders/block_f_shader.glsl"}; - Shader outline_shader{"outline", "shaders/outline_v_shader.glsl", - "shaders/outline_f_shader.glsl"}; - Shader sky_shdaer{"sky", "shaders/sky_v_shader.glsl", - "shaders/sky_f_shader.glsl"}; - Shader ui_shdaer{"ui", "shaders/ui_v_shader.glsl", - "shaders/ui_f_shader.glsl"}; - Shader text_shdaer{"text", "shaders/text_v_shader.glsl", - "shaders/text_f_shader.glsl"}; - Shader under_water_shader{"under_water", - "shaders/under_water_v_shader.glsl", - "shaders/under_water_f_shader.glsl"}; - Shader accum_shader{"accum", "shaders/block_accumulation_v_shader.glsl", - "shaders/block_accumulation_f_shader.glsl"}; - Shader composite_block_shader{"composite", - "shaders/block_composite_v_shader.glsl", - "shaders/block_composite_f_shader.glsl"}; - Shader depth_shader{"depth_shader", "shaders/depth_shader.glsl", - "shaders/depth_fragment_shader.glsl"}; - Shader billboard{"billboard", "shaders/billboard_v_shader.glsl", - "shaders/billboard_f_shader.glsl"}; - Shader water_shader{"water", "shaders/water_v_shader.glsl", - "shaders/water_f_shader.glsl"}; - Shader player_shader{"player", "shaders/player_v_shader.glsl", - "shaders/player_f_shader.glsl"}; - Shader player_depth_shader{"player_depth", - "shaders/depth_player_shader.glsl", - "shaders/depth_player_fragment_shader.glsl"}; - m_shaders.insert({player_shader.hash(), std::move(player_shader)}); - m_shaders.insert({world_shader.hash(), std::move(world_shader)}); - m_shaders.insert({outline_shader.hash(), std::move(outline_shader)}); - m_shaders.insert({sky_shdaer.hash(), std::move(sky_shdaer)}); - m_shaders.insert({ui_shdaer.hash(), std::move(ui_shdaer)}); - m_shaders.insert({text_shdaer.hash(), std::move(text_shdaer)}); - m_shaders.insert( - {under_water_shader.hash(), std::move(under_water_shader)}); - m_shaders.insert({accum_shader.hash(), std::move(accum_shader)}); - m_shaders.insert( - {composite_block_shader.hash(), std::move(composite_block_shader)}); - m_shaders.insert({depth_shader.hash(), std::move(depth_shader)}); - m_shaders.insert({billboard.hash(), std::move(billboard)}); - m_shaders.insert({water_shader.hash(), std::move(water_shader)}); - m_shaders.insert( - {player_depth_shader.hash(), std::move(player_depth_shader)}); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - -#ifdef DEBUG_MODE - if (debug_on) { - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback( - [](GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar* message, - const void*) { - Logger::log(Logger::Level::L_DEBUG, - std::source_location::current(), "GL Debug: {}", - reinterpret_cast(message)); - }, - nullptr); - } - -#endif - - m_vao.resize(NUM_VAO); - glGenVertexArrays(NUM_VAO, m_vao.data()); - glBindVertexArray(0); - - glBindVertexArray(m_vao[2]); - glGenBuffers(1, &m_outline_vbo); - glBindBuffer(GL_ARRAY_BUFFER, m_outline_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(CUBE_VER), CUBE_VER, GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(0); - glGenBuffers(1, &m_outline_indices_vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_outline_indices_vbo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(OUTLINE_CUBE_INDICES), - OUTLINE_CUBE_INDICES, GL_STATIC_DRAW); - - glBindVertexArray(m_vao[1]); - glGenBuffers(1, &m_sky_vbo); - glBindBuffer(GL_ARRAY_BUFFER, m_sky_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES_POS), VERTICES_POS, - GL_STATIC_DRAW); - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(0); - - glBindVertexArray(m_vao[3]); - glGenBuffers(1, &m_ui_vbo); - glBindBuffer(GL_ARRAY_BUFFER, m_ui_vbo); - - for (int i = 0; i < 6; i++) { - Vertex2D vex{SQUARE_VERTICES[i][0], SQUARE_VERTICES[i][1], - SQUARE_TEXTURE_POS[i][0], SQUARE_TEXTURE_POS[i][1], 0}; - m_ui.emplace_back(vex); - } - - glBufferData(GL_ARRAY_BUFFER, m_ui.size() * sizeof(Vertex2D), m_ui.data(), - GL_STATIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, m_ui_vbo); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), - (void*)offsetof(Vertex2D, s)); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), - (void*)offsetof(Vertex2D, layer)); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - init_quad(); - init_text(); - hot_reload(); - - m_player_renderer.init(); - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - m_init = true; -} - -const Shader& Renderer::get_shader(const std::string& name) const { - auto it = m_shaders.find(HASH::str(name)); - ASSERT_MSG(it != m_shaders.end(), "Shader don't find, check the name"); - return it->second; -} - -void Renderer::init_quad() { - glBindVertexArray(m_vao[0]); - glGenBuffers(1, &m_quad_vbo); - glBindBuffer(GL_ARRAY_BUFFER, m_quad_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(QUAD_VERTICES), QUAD_VERTICES, - GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), - (void*)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), - (void*)(2 * sizeof(float))); -} - -void Renderer::init_text() { - glBindVertexArray(m_vao[4]); - glGenBuffers(1, &m_text_vbo); - glBindBuffer(GL_ARRAY_BUFFER, m_text_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW); - - const auto& shader = get_shader("text"); - Text::set_loc(shader); - DebugCollector::get().init_text(); -} - -void Renderer::render() { - glDisable(GL_FRAMEBUFFER_SRGB); - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - day_night_calculation(); - render_sky(); - render_world(); - render_outline(); - render_player(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glEnable(GL_FRAMEBUFFER_SRGB); - glDisable(GL_DEPTH_TEST); - glClearColor(0.0f, 0.0f, 0.0f, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - - render_underwater(); - glDisable(GL_FRAMEBUFFER_SRGB); - render_ui(); - render_text(); - render_dev_panel(); -} - -void Renderer::day_night_calculation() { - m_parallel_light.sundir = glm::normalize(m_world.sunlight_dir()); - m_parallel_light.sun_height = (-m_parallel_light.sundir).y; - m_parallel_light.lightdir = m_parallel_light.sundir; - - m_parallel_light.day_light = - glm::smoothstep(0.15f, 0.3f, m_parallel_light.sun_height); - - m_parallel_light.sun_color = mix(SUNSET_SUNLIGHT_COLOR, NOON_SUNLIGHT_COLOR, - m_parallel_light.day_light); - - glm::vec3 ambient_color = mix(SUNSET_AMBIENT_COLOR, NOON_AMBIENT_COLOR, - m_parallel_light.day_light); - - m_parallel_light.day_factor = - glm::smoothstep(-0.15f, 0.05f, m_parallel_light.sun_height); - auto day_factor = m_parallel_light.day_factor; - float light_intensity = - glm::smoothstep(moon_intensity, sun_intensity, day_factor); - m_parallel_light.directional_light_color = - glm::mix(MOON_COLOR, m_parallel_light.sun_color, day_factor) * - light_intensity; - m_parallel_light.finnal_ambient_color = - glm::mix(NIGHT_AMBIENT_COLOR, ambient_color, day_factor); - - m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor); -} - -void Renderer::render_outline() { - const auto& shader = get_shader("outline"); - shader.use(); - - const auto& block_pos = m_world.get_look_block_pos(); - - if (block_pos != std::nullopt) { - - m_m_mat = - glm::translate(glm::mat4(1.0f), glm::vec3(block_pos.value().pos)); - - m_v_mat = m_camera.get_camera_lookat(); - m_mv_mat = m_v_mat * m_m_mat; - - shader.set_loc("mv_matrix", m_mv_mat); - shader.set_loc("proj_matrix", m_p_mat); - - glBindVertexArray(m_vao[2]); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - glLineWidth(4.0f); - glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0); - } -} - -void Renderer::render_sky() { - - glm::vec3 zenith = {0.20f, 0.45f, 0.95f}; - - glm::vec3 horizon = {0.55f, 0.75f, 1.00f}; - - glm::vec3 sunset_zenith = {0.05f, 0.10f, 0.25f}; - - glm::vec3 sunset_horizon = {1.0f, 0.35f, 0.10f}; - - glm::vec3 night_zenith = {0.018f, 0.023f, 0.048f}; - glm::vec3 night_horizon = {0.022f, 0.027f, 0.052f}; - - constexpr float NIGHT_SHARPNESS = 0.35f; - constexpr float SUNSET_SHARPNESS = 0.6f; - constexpr float NOON_SHARPNESS = 0.35f; - - constexpr float NIGHT_CLOUD_MIX = 0.3f; - constexpr float SUNSET_CLOUD_MIX = 0.4f; - constexpr float NOON_CLOUD_MIX = 0.7; - - glm::vec3 day_top = mix(sunset_zenith, zenith, m_parallel_light.day_light); - glm::vec3 day_bottom = - mix(sunset_horizon, horizon, m_parallel_light.day_light); - - m_sky_uniform.sky_top = - mix(night_zenith, day_top, m_parallel_light.day_factor); - m_sky_uniform.sky_bottom = - mix(night_horizon, day_bottom, m_parallel_light.day_factor); - - float day_sharpness = - glm::mix(SUNSET_SHARPNESS, NOON_SHARPNESS, m_parallel_light.day_light); - - m_sky_uniform.horizon_sharpness = - glm::mix(NIGHT_SHARPNESS, day_sharpness, m_parallel_light.day_factor); - - float day_cloud_mix = - glm::mix(SUNSET_CLOUD_MIX, NOON_CLOUD_MIX, m_parallel_light.day_light); - m_sky_uniform.cloud_white_mix = - glm::mix(NIGHT_CLOUD_MIX, day_cloud_mix, m_parallel_light.day_factor); - - m_cloud_time += m_delta_time * m_cloud_speed; - - const auto& sky_shader = get_shader("sky"); - - sky_shader.use(); - - m_m_mat = glm::translate(glm::mat4(1.0f), m_camera.get_camera_pos() - - glm::vec3(0.5f, 0.5f, 0.5f)); - m_v_mat = m_camera.get_camera_lookat(); - m_mv_mat = m_v_mat * m_m_mat; - - m_sky_uniform.sun_dir_view = (-m_parallel_light.sundir); - sky_shader.set_loc("mv_matrix", m_mv_mat); - sky_shader.set_loc("proj_matrix", m_p_mat); - sky_shader.set_loc("skyTop", m_sky_uniform.sky_top); - sky_shader.set_loc("skyBottom", m_sky_uniform.sky_bottom); - sky_shader.set_loc("sunDir", m_sky_uniform.sun_dir_view); - sky_shader.set_loc("sunColor", m_parallel_light.directional_light_color); - sky_shader.set_loc("horizonSharpness", m_sky_uniform.horizon_sharpness); - sky_shader.set_loc("time", m_cloud_time); - sky_shader.set_loc("cloudWhiteMix", m_sky_uniform.cloud_white_mix); - sky_shader.set_loc("cloudThresholdLow", m_cloud_threshold_low); - sky_shader.set_loc("cloudThresholdHigh", m_cloud_threshold_high); - glBindVertexArray(m_vao[1]); - - glDisable(GL_DEPTH_TEST); - - glDrawArrays(GL_TRIANGLES, 0, 36); - glEnable(GL_DEPTH_TEST); - - // draw sun and moon - const auto& billboard = get_shader("billboard"); - billboard.use(); - glDepthMask(GL_FALSE); - - glBindVertexArray(m_vao[0]); - // draw sun - glm::vec3 sun_pos = m_camera.get_camera_pos() + - normalize(-m_world.sunlight_dir()) * (FAR_PLANE * 0.9f); - glm::vec3 sun_view_pos = glm::vec3(m_v_mat * glm::vec4(sun_pos, 1.0f)); - m_mv_mat = glm::translate(glm::mat4(1.0f), sun_view_pos) * - glm::scale(glm::mat4(1.0f), glm::vec3(SUN_SIZE)) * - glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, -0.5f, 0.0f)); - - billboard.set_loc("mv_matrix", m_mv_mat); - billboard.set_loc("proj_matrix", m_p_mat); - billboard.set_loc("color", SUN_COLOR); - - glDrawArrays(GL_TRIANGLES, 0, 6); - - glm::vec3 moon_pos = m_camera.get_camera_pos() + - normalize(m_world.sunlight_dir()) * (FAR_PLANE * 0.9f); - glm::vec3 moon_view_pos = glm::vec3(m_v_mat * glm::vec4(moon_pos, 1.0f)); - m_mv_mat = glm::translate(glm::mat4(1.0f), moon_view_pos) * - glm::scale(glm::mat4(1.0f), glm::vec3(MOON_SIZE)) * - glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, -0.5f, 0.0f)); - billboard.set_loc("mv_matrix", m_mv_mat); - billboard.set_loc("proj_matrix", m_p_mat); - billboard.set_loc("color", MOON_COLOR); - - glDrawArrays(GL_TRIANGLES, 0, 6); - - glDepthMask(GL_TRUE); -} - -void Renderer::render_text() { - - glBindVertexArray(m_vao[4]); - - const auto& shader = get_shader("text"); - - shader.use(); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glDisable(GL_DEPTH_TEST); - - shader.set_loc("projection", m_ui_proj); - - auto& texts = DebugCollector::get().all_texts(); - for (auto& t : texts) { - t.second.render(); - } - - glEnable(GL_DEPTH_TEST); -} - -void Renderer::render_ui() { - const auto& shader = get_shader("ui"); - shader.use(); - - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - shader.set_loc("m_matrix", m_ui_m_matrix); - shader.set_loc("proj_matrix", m_ui_proj); - - glBindVertexArray(m_vao[3]); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_manager.get_ui_array()); - - glDrawArrays(GL_TRIANGLES, 0, 6); - Tools::check_opengl_error(); - - glEnable(GL_DEPTH_TEST); -} - -void Renderer::render_underwater() { - const auto& shader = get_shader("under_water"); - shader.use(); - - glBindVertexArray(m_vao[0]); - - shader.set_loc("u_sceneTexture", 0); - shader.set_loc("u_time", static_cast(glfwGetTime())); - shader.set_loc("u_underwater", m_camera.is_under_water()); - shader.set_loc("u_waterColor", glm::vec3(0.1f, 0.25f, 0.35f)); - shader.set_loc("u_fogDensity", m_underwater_fog_density); - shader.set_loc("cameraPos", m_camera.get_camera_pos()); - shader.set_loc("sunDir", -m_parallel_light.sundir); - shader.set_loc("waterDensity", m_water_density); - shader.set_loc("InverseViewProjection", glm::inverse(m_p_mat * m_v_mat)); - shader.set_loc("sunColor", m_parallel_light.sun_color); - shader.set_loc("u_lightSpaceMatrix", m_parallel_light.light_space_matrix); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_screen_texture); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, m_screen_depth_texture); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, m_depth_map_texture); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); -} - -void Renderer::update(float delta_time) { m_delta_time = delta_time; } - -void Renderer::update_fov(float fov) { - m_fov = fov; - m_p_mat = glm::perspective(glm::radians(fov), m_aspect, 0.1f, 1000.0f); -} - -void Renderer::update_proj_matrix(float aspect, float width, float height) { - m_aspect = aspect; - m_p_mat = - glm::perspective(glm::radians(m_fov), aspect, NEAR_PLANE, FAR_PLANE); - m_ui_proj = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f); - // scale and then translate - m_ui_m_matrix = - glm::translate(glm::mat4(1.0f), - glm::vec3(width / 2.0f, height / 2.0f, 0.0)) * - glm::scale(glm::mat4(1.0f), glm::vec3(50.0f, 50.0f, 1.0f)); -} - -void Renderer::updata_framebuffer(int width, int height) { - if (width <= 0 || height <= 0) - return; - if (m_fbo == 0) { - glGenFramebuffers(1, &m_fbo); - } - if (m_oit_fbo == 0) { - glGenFramebuffers(1, &m_oit_fbo); - } - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - - glDeleteTextures(1, &m_screen_texture); - glDeleteTextures(1, &m_screen_depth_texture); - - glGenTextures(1, &m_screen_texture); - glBindTexture(GL_TEXTURE_2D, m_screen_texture); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, - GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - m_screen_texture, 0); - - glGenTextures(1, &m_screen_depth_texture); - glBindTexture(GL_TEXTURE_2D, m_screen_depth_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, - GL_DEPTH_COMPONENT, GL_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - m_screen_depth_texture, 0); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - Logger::error("FBO incomplete after resize!"); - } else { - Logger::info("Frame Buffer Complete!"); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, m_oit_fbo); - glDeleteTextures(1, &m_accum_texture); - glDeleteTextures(1, &m_reveal_texture); - glDeleteTextures(1, &m_oit_depth_texture); - glGenTextures(1, &m_accum_texture); - glBindTexture(GL_TEXTURE_2D, m_accum_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, - GL_HALF_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - m_accum_texture, 0); - glGenTextures(1, &m_reveal_texture); - glBindTexture(GL_TEXTURE_2D, m_reveal_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, width, height, 0, GL_RED, - GL_HALF_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, - m_reveal_texture, 0); - glGenTextures(1, &m_oit_depth_texture); - glBindTexture(GL_TEXTURE_2D, m_oit_depth_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, - GL_DEPTH_COMPONENT, GL_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - m_oit_depth_texture, 0); - GLenum draw_buffer[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; - glDrawBuffers(2, draw_buffer); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - Logger::error("FBO incomplete after resize!"); - } else { - Logger::info("Frame Buffer Complete!"); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // depth map fbo - if (m_depth_map_fbo == 0) { - glGenFramebuffers(1, &m_depth_map_fbo); - } - glDeleteTextures(1, &m_depth_map_texture); - glGenTextures(1, &m_depth_map_texture); - - glBindTexture(GL_TEXTURE_2D, m_depth_map_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, DEPTH_MAP_SIZE, - DEPTH_MAP_SIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - float border_color[] = {1.0f, 1.0f, 1.0f, 1.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - // Manually compare shadows - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, - // GL_COMPARE_REF_TO_TEXTURE); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - - glBindFramebuffer(GL_FRAMEBUFFER, m_depth_map_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - m_depth_map_texture, 0); - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - Logger::error("FBO incomplete after resize!"); - } else { - Logger::info("Frame Buffer Complete!"); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - m_width = width; - m_height = height; -} -#pragma region render_world -void Renderer::render_world() { - // shader map - glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix; - auto& m_render_snapshots = m_world.render_snapshots(); - auto& camera_pos = m_camera.get_camera_pos(); - float texels_per_unit = 0.0f; - - const auto& lightdir = m_parallel_light.lightdir; - - if (m_shader_on) { - const auto& depth_shader = get_shader("depth_shader"); - depth_shader.use(); - - glm::vec3 cam_pos = m_camera.get_camera_pos(); - glm::vec3 cam_fwd = m_camera.get_camera_front(); - float half_extent = 128.0f; - - glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f); - - glm::vec3 raw_shadow_lightdir = - quantize_sun_direction(lightdir, ANGLE_STEP_DEG); - glm::vec3 shadow_lightdir = - get_smoothed_shadow_lightdir(raw_shadow_lightdir, m_delta_time); - glm::vec3 up = fabs(shadow_lightdir.y) > 0.99f ? glm::vec3(0, 0, 1) - : glm::vec3(0, 1, 0); - - glm::mat4 light_basis = - glm::lookAt(glm::vec3(0.0f), shadow_lightdir, up); - texels_per_unit = DEPTH_MAP_SIZE / (half_extent * 2.0f); - glm::vec3 ls_center = glm::vec3(light_basis * glm::vec4(center, 1.0f)); - ls_center.x = - std::round(ls_center.x * texels_per_unit) / texels_per_unit; - ls_center.y = - std::round(ls_center.y * texels_per_unit) / texels_per_unit; - glm::vec3 snapped_center = - glm::vec3(glm::inverse(light_basis) * glm::vec4(ls_center, 1.0f)); - - float distance = half_extent * 1.5f; - float near_plane = 1.0f; - float far_plane = distance + half_extent * 2.0f; - glm::vec3 light_pos = snapped_center - shadow_lightdir * distance; - glm::mat4 light_view = glm::lookAt(light_pos, snapped_center, up); - glm::mat4 light_projection = - glm::ortho(-half_extent, half_extent, -half_extent, half_extent, - near_plane, far_plane); - - light_space_matrix = light_projection * light_view; - depth_shader.set_loc("lightSpaceMatrix", light_space_matrix); - depth_shader.set_loc("is_discard_tranparent", m_discard_tranparent); - - glViewport(0, 0, DEPTH_MAP_SIZE, DEPTH_MAP_SIZE); - if (m_light_cull_face == 0) { - glCullFace(GL_FRONT); - } else if (m_light_cull_face == 1) { - glCullFace(GL_BACK); - } else { - Logger::warn("Light Cull Face {} Over The Max Selection", - m_light_cull_face); - glCullFace(GL_BACK); - } - - glBindFramebuffer(GL_FRAMEBUFFER, m_depth_map_fbo); - glClear(GL_DEPTH_BUFFER_BIT); - - glActiveTexture(GL_TEXTURE1); - glEnable(GL_DEPTH_TEST); - for (const auto& snapshot : m_render_snapshots) { - if (!snapshot) { - continue; - } - glBindTexture(GL_TEXTURE_2D_ARRAY, - m_texture_manager.get_texture_array()); - glBindVertexArray(snapshot->normal_vao); - - glDrawArrays(GL_TRIANGLES, 0, snapshot->normal_vertices_count); - } - - // cross_plane and discard - - for (const auto& snapshot : m_render_snapshots) { - if (!snapshot) { - continue; - } - glm::vec2 camera_pos_xz{camera_pos.x, camera_pos.z}; - if (snapshot->cross_vertices_count != 0) { - glm::vec2 center_xz{snapshot->center.x, snapshot->center.z}; - float dist2d = glm::distance(camera_pos_xz, center_xz); - if (dist2d <= CROSS_PLANE_DISTANCE * 16) { - glBindTexture(GL_TEXTURE_2D_ARRAY, - m_texture_manager.get_cross_plane_array()); - glBindVertexArray(snapshot->cross_vao); - - glDrawArrays(GL_TRIANGLES, 0, - snapshot->cross_vertices_count); - } - } - if (snapshot->normal_discard_vertices_count != 0) { - glBindTexture(GL_TEXTURE_2D_ARRAY, - m_texture_manager.get_texture_array()); - glBindVertexArray(snapshot->normal_discard_vao); - - glDrawArrays(GL_TRIANGLES, 0, - snapshot->normal_discard_vertices_count); - } - } - // player - auto& player_shadow = get_shader("player_depth"); - m_player_renderer.shadow_render(player_shadow, light_space_matrix); - } - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - - glCullFace(GL_BACK); - glViewport(0, 0, m_width, m_height); - const auto& normal_block_shader = get_shader("normal_block"); - normal_block_shader.use(); - - m_m_mat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); - m_v_mat = m_camera.get_camera_lookat(); - m_mv_mat = m_v_mat * m_m_mat; - m_norm_mat = glm::transpose(glm::inverse(m_mv_mat)); - glm::vec3 light_dir_view = glm::normalize(glm::mat3(m_v_mat) * lightdir); - normal_block_shader.set_loc("model_matrix", m_m_mat); - normal_block_shader.set_loc("mv_matrix", m_mv_mat); - normal_block_shader.set_loc("proj_matrix", m_p_mat); - normal_block_shader.set_loc("norm_matrix", m_norm_mat); - normal_block_shader.set_loc("lightSpaceMatrix", light_space_matrix); - normal_block_shader.set_loc("ambientStrength", m_ambient_strength); - normal_block_shader.set_loc("sunlightColor", - m_parallel_light.directional_light_color); - normal_block_shader.set_loc("ambientColor", - m_parallel_light.finnal_ambient_color); - normal_block_shader.set_loc("sunlightDir", light_dir_view); - normal_block_shader.set_loc("shadowMode", m_shadow_mode); - normal_block_shader.set_loc("shader_on", m_shader_on); - normal_block_shader.set_loc("lightSizeUV", - static_cast(m_light_size_uv)); - normal_block_shader.set_loc("minRadius", m_min_radius); - normal_block_shader.set_loc("maxRadius", m_max_radius); - normal_block_shader.set_loc("samples", m_samples); - normal_block_shader.set_loc("specularStrength", m_specular_strength); - normal_block_shader.set_loc("cameraPos", m_camera.get_camera_pos()); - normal_block_shader.set_loc("flipY", m_flip_y); - normal_block_shader.set_loc("renderDistance", m_world.rendering_distance()); - normal_block_shader.set_loc("skyColor", m_sky_uniform.sky_top); - m_mvp_mat = m_p_mat * m_mv_mat; - - auto& m_planes = m_world.planes(); - - Math::extract_frustum_planes(m_mvp_mat, m_planes); - - int rendered_sum = 0; - glEnable(GL_DEPTH_TEST); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_depth_map_texture); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_manager.get_texture_array()); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_manager.get_pbr_texture()); - normal_block_shader.set_loc("enablePBR", m_pbr); - for (const auto& snapshot : m_render_snapshots) { - if (!snapshot) { - continue; - } - if (Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, - m_planes)) { - - glBindVertexArray(snapshot->normal_vao); - - glDrawArrays(GL_TRIANGLES, 0, snapshot->normal_vertices_count); - - rendered_sum++; - } - } - // discard - for (const auto& snapshot : m_render_snapshots) { - if (!snapshot) { - continue; - } - if (!Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, - m_planes)) { - continue; - } - if (snapshot->normal_discard_vertices_count != 0) { - glBindVertexArray(snapshot->normal_discard_vao); - - glDrawArrays(GL_TRIANGLES, 0, - snapshot->normal_discard_vertices_count); - } - } - // cross_plane - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D_ARRAY, - m_texture_manager.get_cross_plane_array()); - normal_block_shader.set_loc("enablePBR", false); - for (const auto& snapshot : m_render_snapshots) { - if (!snapshot) { - continue; - } - if (!Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, - m_planes)) { - continue; - } - glm::vec2 camera_pos_xz{camera_pos.x, camera_pos.z}; - if (snapshot->cross_vertices_count != 0) { - glm::vec2 center_xz{snapshot->center.x, snapshot->center.z}; - float dist2d = glm::distance(camera_pos_xz, center_xz); - if (dist2d <= CROSS_PLANE_DISTANCE * 16) { - glBindVertexArray(snapshot->cross_vao); - - glDrawArrays(GL_TRIANGLES, 0, snapshot->cross_vertices_count); - } - } - } - - // copy depth buffer - - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_oit_fbo); - glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, - GL_DEPTH_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_oit_fbo); - - // pass one accumulate - glBindFramebuffer(GL_FRAMEBUFFER, m_oit_fbo); - - glClearBufferfv(GL_COLOR, 0, glm::value_ptr(glm::vec4(0.0f))); - float one = 1.0f; - glClearBufferfv(GL_COLOR, 1, &one); - - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - - glEnable(GL_BLEND); - glBlendFunci(0, GL_ONE, GL_ONE); - - glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - - auto set_accum_loc = [&](const Shader& accum_shader) { - accum_shader.set_loc("mv_matrix", m_mv_mat); - accum_shader.set_loc("proj_matrix", m_p_mat); - accum_shader.set_loc("norm_matrix", m_norm_mat); - accum_shader.set_loc("ambientStrength", m_ambient_strength); - accum_shader.set_loc("sunlightColor", - m_parallel_light.directional_light_color); - accum_shader.set_loc("ambientColor", - m_parallel_light.finnal_ambient_color); - accum_shader.set_loc("sunlightDir", light_dir_view); - accum_shader.set_loc("shader_on", m_shader_on); - accum_shader.set_loc("specularStrength", m_specular_strength); - }; - - auto& accum_shader = get_shader("accum"); - accum_shader.use(); - - set_accum_loc(accum_shader); - accum_shader.set_loc("cameraPos", m_camera.get_camera_pos()); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_manager.get_texture_array()); - for (const auto& snapshot : m_render_snapshots) { - if (!snapshot) { - continue; - } - if (!Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, - m_planes)) { - continue; - } - - if (snapshot->normal_blend_vertices_count != 0) { - - glBindVertexArray(snapshot->normal_blend_vao); - - glDrawArrays(GL_TRIANGLES, 0, - snapshot->normal_blend_vertices_count); - } - } - - // use SSR - - auto& water_shader = get_shader("water"); - water_shader.use(); - - set_accum_loc(water_shader); - - water_shader.set_loc("sceneColorTex", 1); - water_shader.set_loc("sceneDepthTex", 2); - water_shader.set_loc("inv_proj_matrix", glm::inverse(m_p_mat)); - water_shader.set_loc("inv_view_matrix", glm::inverse(m_v_mat)); - - // sky loc - - water_shader.set_loc("skyTop", m_sky_uniform.sky_top); - water_shader.set_loc("skyBottom", m_sky_uniform.sky_bottom); - water_shader.set_loc("sunDir", m_sky_uniform.sun_dir_view); - water_shader.set_loc("sunColor", m_parallel_light.directional_light_color); - water_shader.set_loc("horizonSharpness", m_sky_uniform.horizon_sharpness); - water_shader.set_loc("time", glfwGetTime()); - water_shader.set_loc("cloudWhiteMix", m_sky_uniform.cloud_white_mix); - water_shader.set_loc("cloudThresholdLow", m_cloud_threshold_low); - water_shader.set_loc("cloudThresholdHigh", m_cloud_threshold_high); - water_shader.set_loc("underwater", m_camera.is_under_water()); - water_shader.set_loc("refractStrength", m_refract_strength); - water_shader.set_loc("enablePerturb", m_water_perturb); - water_shader.set_loc("enableDepthFade", m_water_depth_fade); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, m_screen_texture); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, m_screen_depth_texture); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_manager.get_texture_array()); - for (const auto& snapshot : m_render_snapshots) { - if (!snapshot) { - continue; - } - if (!Math::is_aabb_in_frustum(snapshot->center, snapshot->half_extents, - m_planes)) { - continue; - } - - if (snapshot->water_vertices_count != 0) { - - glBindVertexArray(snapshot->water_vao); - - glDrawArrays(GL_TRIANGLES, 0, snapshot->water_vertices_count); - } - } - - auto& composite_shader = get_shader("composite"); - glDisable(GL_BLEND); - - composite_shader.use(); - composite_shader.set_loc("u_accumTex", 0); - composite_shader.set_loc("u_revealTex", 1); - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glBindVertexArray(m_vao[0]); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_accum_texture); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, m_reveal_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - - DebugCollector::get().report( - "rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum)); -} - -void Renderer::render_player() { - auto& shader = get_shader("player"); - shader.use(); - - glm::vec3 light_dir_view = - glm::normalize(glm::mat3(m_v_mat) * m_parallel_light.lightdir); - - shader.set_loc("lightSpaceMatrix", m_parallel_light.light_space_matrix); - shader.set_loc("ambientStrength", m_ambient_strength); - shader.set_loc("sunlightColor", m_parallel_light.directional_light_color); - shader.set_loc("ambientColor", m_parallel_light.finnal_ambient_color); - shader.set_loc("sunlightDir", light_dir_view); - shader.set_loc("shadowMode", m_shadow_mode); - shader.set_loc("shader_on", m_shader_on); - shader.set_loc("lightSizeUV", static_cast(m_light_size_uv)); - shader.set_loc("minRadius", m_min_radius); - shader.set_loc("maxRadius", m_max_radius); - shader.set_loc("samples", m_samples); - shader.set_loc("renderDistance", m_world.rendering_distance()); - shader.set_loc("skyColor", m_sky_uniform.sky_top); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_depth_map_texture); - - m_player_renderer.render(shader); -} - -#pragma endregion -void Renderer::render_dev_panel() { - glDisable(GL_DEPTH_TEST); - m_dev_panel.render(); - glEnable(GL_DEPTH_TEST); -} - -glm::vec3 Renderer::quantize_sun_direction(const glm::vec3& lightdir, - float angle_step_deg) const { - float elevation = std::asin(glm::clamp(lightdir.y, -1.0f, 1.0f)); - float azimuth = std::atan2(lightdir.z, lightdir.x); - - float step = glm::radians(angle_step_deg); - - float quantized_elevation = std::round(elevation / step) * step; - float quantized_azimuth = std::round(azimuth / step) * step; - - glm::vec3 quantized_dir; - quantized_dir.x = - std::cos(quantized_elevation) * std::cos(quantized_azimuth); - quantized_dir.z = - std::cos(quantized_elevation) * std::sin(quantized_azimuth); - quantized_dir.y = std::sin(quantized_elevation); - - return glm::normalize(quantized_dir); -} - -glm::vec3 -Renderer::get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_lightdir, - float dt) { - if (!m_blend_initialized) { - - m_blend_from_lightdir = raw_shadow_lightdir; - m_blend_to_lightdir = raw_shadow_lightdir; - m_blend_t = 1.0f; - m_blend_initialized = true; - return raw_shadow_lightdir; - } - - if (raw_shadow_lightdir != m_blend_to_lightdir) { - glm::vec3 current_displayed = glm::normalize( - Math::slerp(m_blend_from_lightdir, m_blend_to_lightdir, m_blend_t)); - - m_blend_from_lightdir = current_displayed; - m_blend_to_lightdir = raw_shadow_lightdir; - m_blend_t = 0.0f; - } - - m_blend_t = glm::min(m_blend_t + dt / BLEND_DURATION, 1.0f); - - return glm::normalize( - Math::slerp(m_blend_from_lightdir, m_blend_to_lightdir, m_blend_t)); -} - -float& Renderer::ambient_strength() { return m_ambient_strength; } -bool& Renderer::discard_transparent() { return m_discard_tranparent; } -bool& Renderer::shader_on() { return m_shader_on; } -bool& Renderer::water_perturb() { return m_water_perturb; } -bool& Renderer::water_depth_fade() { return m_water_depth_fade; } -bool& Renderer::pbr() { return m_pbr; } -bool& Renderer::flip_y() { return m_flip_y; } -int& Renderer::shadow_mode() { return m_shadow_mode; } -int& Renderer::light_cull_face() { return m_light_cull_face; } -int& Renderer::light_size_uv() { return m_light_size_uv; } -float& Renderer::min_radius() { return m_min_radius; } -float& Renderer::max_radius() { return m_max_radius; } -int& Renderer::samples() { return m_samples; } -float& Renderer::specular_strength() { return m_specular_strength; } -float& Renderer::cloud_speed() { return m_cloud_speed; } -float& Renderer::cloud_threshold_low() { return m_cloud_threshold_low; } -float& Renderer::cloud_threshold_high() { return m_cloud_threshold_high; } -float& Renderer::refract_strength() { return m_refract_strength; } -float& Renderer::underwater_fog_density() { return m_underwater_fog_density; } -float& Renderer::water_density() { return m_water_density; } - -const Camera& Renderer::camera() const { return m_camera; } -const ClientWorld& Renderer::world() const { return m_world; } -ClientWorld& Renderer::world() { return m_world; } -const glm::mat4& Renderer::proj_mat() const { return m_p_mat; } -const TextureManager& Renderer::texture_mamger() const { - return m_texture_manager; -} -float Renderer::delta_time() const { return m_delta_time; } -} // namespace Cubed \ No newline at end of file diff --git a/src/texture_manager.cpp b/src/texture_manager.cpp index 99065fd..7df233a 100644 --- a/src/texture_manager.cpp +++ b/src/texture_manager.cpp @@ -34,53 +34,58 @@ namespace Cubed { TextureManager::TextureManager() {} -TextureManager::~TextureManager() { delet_texture(); } +TextureManager::~TextureManager() { delete_texture(); } -void TextureManager::delet_texture() { +void TextureManager::delete_texture() { if (m_init) { - glDeleteTextures(1, &m_texture_array); - glDeleteTextures(1, &m_block_status_array); - glDeleteTextures(1, &m_cross_plane_array); - glDeleteTextures(1, &m_normal_texture_array); - for (auto& id : m_item_textures) { - glDeleteTextures(1, &id); - } - glDeleteTextures(1, &m_skin); + m_texture_array.reset(); + m_block_status_array.reset(); + m_cross_plane_array.reset(); + m_normal_texture_array.reset(); + m_item_textures.clear(); + m_skin.reset(); Logger::info("Successfully delete all texture"); } } -GLuint TextureManager::get_block_status_array() const { - return m_block_status_array; +const Texture* TextureManager::get_block_status_array() const { + return m_block_status_array.get(); } -GLuint TextureManager::get_texture_array() const { return m_texture_array; } - -GLuint TextureManager::get_cross_plane_array() const { - return m_cross_plane_array; -} -GLuint TextureManager::get_ui_array() const { return m_ui_array; } - -GLuint TextureManager::get_pbr_texture() const { - return m_normal_texture_array; +const Texture* TextureManager::get_texture_array() const { + return m_texture_array.get(); } -const std::vector& TextureManager::item_textures() const { +const Texture* TextureManager::get_cross_plane_array() const { + return m_cross_plane_array.get(); +} +const Texture* TextureManager::get_ui_array() const { return m_ui_array.get(); } + +const Texture* TextureManager::get_pbr_texture() const { + return m_normal_texture_array.get(); +} + +const std::vector>& +TextureManager::item_textures() const { return m_item_textures; } -GLuint TextureManager::get_skin() const { return m_skin; } +const Texture* TextureManager::get_skin() const { return m_skin.get(); } void TextureManager::load_block_status(unsigned id) { ASSERT_MSG(id < MAX_BLOCK_STATUS, "Exceed the max status sum limit"); + std::string path = "texture/status/" + std::to_string(id) + ".png"; + unsigned char* image_data = nullptr; + image_data = (Tools::load_image_data(path)); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_block_status_array); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, id, BLOCK_STATUS_SIZE, - BLOCK_STATUS_SIZE, 1, GL_RGBA, GL_UNSIGNED_BYTE, - image_data); + + m_block_status_array->tex_sub_image_3d( + TextureFormat::RGBA, GL_UNSIGNED_BYTE, image_data, 0, 0, id, + BLOCK_STATUS_SIZE, BLOCK_STATUS_SIZE); + Tools::delete_image_data(image_data); } @@ -107,12 +112,11 @@ void TextureManager::load_block_texture(unsigned id) { image_data[4] = (Tools::load_image_data(block_texture_path + "/top.png")); image_data[5] = (Tools::load_image_data(block_texture_path + "/base.png")); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_array); Tools::check_opengl_error(); for (int i = 0; i < 6; i++) { - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, id * 6 + i, BLOCK_SIZE, - BLOCK_SIZE, 1, GL_RGBA, GL_UNSIGNED_BYTE, - image_data[i]); + m_texture_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE, + image_data[i], 0, 0, id * 6 + i, + BLOCK_SIZE, BLOCK_SIZE); Tools::check_opengl_error(); Tools::delete_image_data(image_data[i]); } @@ -126,21 +130,16 @@ void TextureManager::load_block_item_texture(unsigned id) { std::string path = "texture/item/block/" + name + ".png"; unsigned char* data = nullptr; data = Tools::load_image_data(path); - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BLOCK_ITEM_SIZE, BLOCK_ITEM_SIZE, - 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + std::unique_ptr texture = + std::make_unique(TextureType::TEXTURE_2D); + texture->tex_image_2d(TextureFormat::RGBA8, TextureFormat::RGBA, + GL_UNSIGNED_BYTE, data, BLOCK_ITEM_SIZE, + BLOCK_ITEM_SIZE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); - if (m_aniso >= 1) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, - static_cast(m_aniso)); - } - m_item_textures.push_back(texture); + texture->set_nearest(); + texture->set_clamp_to_border(); + + m_item_textures.push_back(std::move(texture)); Tools::delete_image_data(data); } @@ -148,10 +147,10 @@ void TextureManager::load_cross_plane_texture(unsigned id) { std::string path = "texture/block/" + BlockManager::name_form_id(id) + "/cross.png"; unsigned char* image_data = Tools::load_image_data(path); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_cross_plane_array); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, - BlockManager::cross_plane_index(id), CROSS_PLANE_SIZE, - CROSS_PLANE_SIZE, 1, GL_RGBA, GL_UNSIGNED_BYTE, image_data); + m_cross_plane_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE, + image_data, 0, 0, + BlockManager::cross_plane_index(id), + CROSS_PLANE_SIZE, CROSS_PLANE_SIZE); Tools::delete_image_data(image_data); } @@ -161,9 +160,8 @@ void TextureManager::load_ui_texture(unsigned id) { std::string path = "texture/ui/" + std::to_string(id) + ".png"; unsigned char* image_data = nullptr; image_data = (Tools::load_image_data(path)); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_ui_array); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, id, UI_SIZE, UI_SIZE, 1, - GL_RGBA, GL_UNSIGNED_BYTE, image_data); + m_ui_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE, + image_data, 0, 0, id, UI_SIZE, UI_SIZE); Tools::delete_image_data(image_data); } @@ -189,7 +187,6 @@ void TextureManager::load_pbr_texture(unsigned id) { image_data[4] = (Tools::load_image_data(path + "/top_n.png", false)); image_data[5] = (Tools::load_image_data(path + "/base_n.png", false)); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_normal_texture_array); for (int i = 0; i < 6; i++) { unsigned char* data = image_data[i]; bool is_fallback = false; @@ -197,9 +194,10 @@ void TextureManager::load_pbr_texture(unsigned id) { is_fallback = true; data = generate_flat_normal_map(); } - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, id * 6 + i, - BLOCK_NORMAL_SIZE, BLOCK_NORMAL_SIZE, 1, GL_RGBA, - GL_UNSIGNED_BYTE, data); + m_normal_texture_array->tex_sub_image_3d( + TextureFormat::RGBA, GL_UNSIGNED_BYTE, data, 0, 0, id * 6 + i, + BLOCK_NORMAL_SIZE, BLOCK_NORMAL_SIZE); + if (is_fallback) { delete[] data; } else { @@ -209,125 +207,78 @@ void TextureManager::load_pbr_texture(unsigned id) { } void TextureManager::init_block() { + m_texture_array = std::make_unique(TextureType::TEXTURE_2D_ARRAY); + m_texture_array->tex_image_3d(TextureFormat::RGBA, TextureFormat::RGBA, + GL_UNSIGNED_BYTE, nullptr, BLOCK_SIZE, + BLOCK_SIZE, BlockManager::sums() * 6); - glGenTextures(1, &m_texture_array); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_array); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, BLOCK_SIZE, BLOCK_SIZE, - BlockManager::sums() * 6, 0, GL_RGBA, GL_UNSIGNED_BYTE, - nullptr); + m_cross_plane_array = + std::make_unique(TextureType::TEXTURE_2D_ARRAY); + m_cross_plane_array->tex_image_3d( + TextureFormat::RGBA, TextureFormat::RGBA, GL_UNSIGNED_BYTE, nullptr, + CROSS_PLANE_SIZE, CROSS_PLANE_SIZE, BlockManager::cross_plane_sum()); - glGenTextures(1, &m_cross_plane_array); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_cross_plane_array); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, CROSS_PLANE_SIZE, - CROSS_PLANE_SIZE, BlockManager::cross_plane_sum(), 0, GL_RGBA, - GL_UNSIGNED_BYTE, nullptr); - glGenTextures(1, &m_normal_texture_array); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_normal_texture_array); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, BLOCK_NORMAL_SIZE, - BLOCK_NORMAL_SIZE, BlockManager::sums() * 6, 0, GL_RGBA, - GL_UNSIGNED_BYTE, nullptr); + m_normal_texture_array = + std::make_unique(TextureType::TEXTURE_2D_ARRAY); + m_normal_texture_array->tex_image_3d( + TextureFormat::RGBA8, TextureFormat::RGBA, GL_UNSIGNED_BYTE, nullptr, + BLOCK_NORMAL_SIZE, BLOCK_NORMAL_SIZE, BlockManager::sums() * 6); for (unsigned i = 0; i < BlockManager::sums(); i++) { load_block_texture(i); load_block_item_texture(i); load_pbr_texture(i); } - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_array); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - if (m_aniso >= 1) { - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY, - static_cast(m_aniso)); - } + m_texture_array->set_nearest_and_minpmap(); + m_texture_array->set_repeat(false, true, true); + m_texture_array->set_aniso(m_aniso); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_cross_plane_array); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - if (m_aniso >= 1) { - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY, - static_cast(m_aniso)); - } + m_cross_plane_array->set_nearest_and_minpmap(); + m_texture_array->set_repeat(false, true, true); + m_cross_plane_array->set_clamp_to_edge(m_aniso); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_normal_texture_array); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - if (m_aniso >= 1) { - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY, - static_cast(m_aniso)); - } + m_normal_texture_array->set_nearest_and_minpmap(); + m_normal_texture_array->set_repeat(false, true, true); + m_normal_texture_array->set_aniso(m_aniso); Logger::info("Block Texture Load Success"); } void TextureManager::init_ui() { - glGenTextures(1, &m_ui_array); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_ui_array); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, UI_SIZE, UI_SIZE, MAX_UI_NUM, - 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + m_ui_array = std::make_unique(TextureType::TEXTURE_2D_ARRAY); + m_ui_array->tex_image_3d(TextureFormat::RGBA, TextureFormat::RGBA, + GL_UNSIGNED_BYTE, nullptr, UI_SIZE, UI_SIZE, + MAX_UI_NUM); for (int i = 0; i < MAX_UI_NUM; i++) { load_ui_texture(i); } - glBindTexture(GL_TEXTURE_2D_ARRAY, m_ui_array); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + m_ui_array->set_nearest(); } void TextureManager::init_skin() { - - glGenTextures(1, &m_skin); - glBindTexture(GL_TEXTURE_2D, m_skin); + m_skin = std::make_unique(TextureType::TEXTURE_2D); std::string path = "texture/skin/player001.png"; unsigned char* image_data = nullptr; image_data = (Tools::load_image_data(path)); - glBindTexture(GL_TEXTURE_2D, m_skin); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SKIN_SIZE, SKIN_SIZE, 0, GL_RGBA, - GL_UNSIGNED_BYTE, image_data); + m_skin->tex_image_2d(TextureFormat::RGBA, TextureFormat::RGBA, + GL_UNSIGNED_BYTE, image_data, SKIN_SIZE, SKIN_SIZE); Tools::delete_image_data(image_data); - glBindTexture(GL_TEXTURE_2D, m_skin); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); - - if (m_aniso >= 1) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, - static_cast(m_aniso)); - } + m_skin->set_nearest_and_minpmap(); + m_skin->set_aniso(m_aniso); } void TextureManager::init_block_status() { - glGenTextures(1, &m_block_status_array); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_block_status_array); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, BLOCK_STATUS_SIZE, - BLOCK_STATUS_SIZE, MAX_BLOCK_STATUS, 0, GL_RGBA, - GL_UNSIGNED_BYTE, nullptr); + m_block_status_array = + std::make_unique(TextureType::TEXTURE_2D_ARRAY); + m_block_status_array->tex_image_3d( + TextureFormat::RGBA, TextureFormat::RGBA, GL_UNSIGNED_BYTE, nullptr, + BLOCK_STATUS_SIZE, BLOCK_STATUS_SIZE, MAX_BLOCK_STATUS); for (int i = 0; i < MAX_BLOCK_STATUS; i++) { load_block_status(i); } - glBindTexture(GL_TEXTURE_2D_ARRAY, m_block_status_array); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - - if (m_aniso >= 1) { - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY, - static_cast(m_aniso)); - } + m_block_status_array->set_nearest_and_minpmap(); + m_block_status_array->set_aniso(m_aniso); } void TextureManager::init_texture() { glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &m_max_aniso); @@ -357,7 +308,7 @@ void TextureManager::update() { void TextureManager::need_reload() { m_need_reload = true; } void TextureManager::hot_reload() { - delet_texture(); + delete_texture(); init_texture(); m_need_reload = false; diff --git a/src/tools/font.cpp b/src/tools/font.cpp index 384f803..89a186d 100644 --- a/src/tools/font.cpp +++ b/src/tools/font.cpp @@ -1,9 +1,7 @@ #include "Cubed/tools/font.hpp" #include "Cubed/constants.hpp" -#include "Cubed/shader.hpp" #include "Cubed/tools/log.hpp" -#include "Cubed/tools/shader_tools.hpp" namespace fs = std::filesystem; @@ -26,7 +24,6 @@ Font::~Font() { FT_Done_Face(m_face); FT_Done_FreeType(m_ft); - glDeleteTextures(1, &m_text_texture); } void Font::load_character(char8_t c) { @@ -36,10 +33,9 @@ void Font::load_character(char8_t c) { } const auto& width = m_face->glyph->bitmap.width; const auto& height = m_face->glyph->bitmap.rows; - glBindTexture(GL_TEXTURE_2D_ARRAY, m_text_texture); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, static_cast(c), width, - height, 1, GL_RED, GL_UNSIGNED_BYTE, - m_face->glyph->bitmap.buffer); + m_text_texture->tex_sub_image_3d(TextureFormat::RED, GL_UNSIGNED_BYTE, + m_face->glyph->bitmap.buffer, 0, 0, + static_cast(c), width, height); Character character = { glm::vec2{0.0f, 0.0f}, @@ -54,22 +50,16 @@ void Font::load_character(char8_t c) { void Font::setup_font_character() { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glGenTextures(1, &m_text_texture); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_text_texture); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RED, m_texture_width, - m_texture_height, MAX_CHARACTER, 0, GL_RED, GL_UNSIGNED_BYTE, - nullptr); + m_text_texture = std::make_unique(TextureType::TEXTURE_2D_ARRAY); + m_text_texture->tex_image_3d(TextureFormat::RED, TextureFormat::RED, + GL_UNSIGNED_BYTE, nullptr, m_texture_width, + m_texture_height, MAX_CHARACTER); for (char8_t c = 0; c < 128; c++) { load_character(c); } - - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + m_text_texture->set_linear(); + m_text_texture->set_clamp_to_edge(false, true, true); } std::vector Font::vertices(const std::string& text, float x, float y, @@ -110,7 +100,7 @@ std::vector Font::vertices(const std::string& text, float x, float y, return vertices; } -GLuint Font::text_texture() { return m_text_texture; } +const Texture* Font::text_texture() { return m_text_texture.get(); } const std::string& Font::font_path() { return m_font_path; } diff --git a/src/ui/text.cpp b/src/ui/text.cpp index a81dc93..e34b71c 100644 --- a/src/ui/text.cpp +++ b/src/ui/text.cpp @@ -9,30 +9,30 @@ namespace Cubed { -Text::Text(std::string_view name) : NAME(name), UUID(HASH::str(name)) {} +Text::Text(std::string_view name) + : NAME(name), UUID(HASH::str(name)), + m_vbo(std::make_unique()), + m_vao(std::make_unique()) {} Text::Text(std::string_view name, std::string_view str, glm::vec2 pos, Color color) - : NAME(name), UUID(HASH::str(name)) { + : NAME(name), UUID(HASH::str(name)), + m_vbo(std::make_unique()), + m_vao(std::make_unique()) { m_text.assign(str); m_pos = pos; m_color = color_value(color); update_vertices(); } -Text::~Text() { - if (m_vbo != 0) { - glDeleteBuffers(1, &m_vbo); - } -} +Text::~Text() { m_vbo.reset(); } Text::Text(Text&& other) noexcept : m_scale(other.m_scale), m_pos(other.m_pos), NAME(other.NAME), UUID(other.UUID), m_text(std::move(other.m_text)), m_color(other.m_color), m_model_matrix(other.m_model_matrix), - m_vertices(std::move(other.m_vertices)), m_vbo(other.m_vbo) { - other.m_vbo = 0; -} + m_vertices(std::move(other.m_vertices)), m_vbo(std::move(other.m_vbo)), + m_vao(std::move(other.m_vao)) {} Text& Text::color(Color color) { m_color = color_value(color); @@ -51,45 +51,24 @@ Text& Text::scale(float s) { std::size_t Text::uuid() const { return UUID; } -void Text::set_loc(const Shader& shader) { - m_color_loc = shader.loc("textColor"); - m_mv_loc = shader.loc("mv_matrix"); -} - Text& Text::text(std::string_view str) { m_text.assign(str); update_vertices(); return *this; } -void Text::render() { +void Text::render(const Shader& shader) { ASSERT_MSG(m_vbo != 0, "VBO not initialized!"); ASSERT_MSG(!m_vertices.empty(), "Text String Not Set"); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, Font::text_texture()); - ASSERT_MSG(m_color_loc, "m_color_loc is null"); - + Font::text_texture()->bind(0); + m_vao->bind(); m_model_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(m_pos.x, m_pos.y, 0.0f)) * glm::scale(glm::mat4(1.0f), glm::vec3(m_scale, m_scale, 1.0f)); - glUniform3f(m_color_loc, m_color.x, m_color.y, m_color.z); - glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_model_matrix)); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), - (void*)offsetof(Vertex2D, s)); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), - (void*)offsetof(Vertex2D, layer)); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - + shader.set_loc("textColor", glm::vec3(m_color.x, m_color.y, m_color.z)); + shader.set_loc("mv_matrix", m_model_matrix); glDrawArrays(GL_TRIANGLES, 0, m_vertices.size()); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); } void Text::update_vertices() { @@ -98,13 +77,15 @@ void Text::update_vertices() { } void Text::upload_to_gpu() { - if (m_vbo == 0) { - glGenBuffers(1, &m_vbo); - } ASSERT_MSG(m_vbo, "Vbo Is Not Gen"); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo); - glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex2D), - m_vertices.data(), GL_DYNAMIC_DRAW); + m_vao->bind(); + m_vbo->buffer_data(m_vertices.data(), m_vertices.size() * sizeof(Vertex2D), + BufferUsage::DYNAMIC_DRAW); + m_vao->attribute(0, 2, GL_FLOAT, sizeof(Vertex2D), (void*)0); + m_vao->attribute(1, 2, GL_FLOAT, sizeof(Vertex2D), + (void*)offsetof(Vertex2D, s)); + m_vao->attribute(2, 1, GL_FLOAT, sizeof(Vertex2D), + (void*)offsetof(Vertex2D, layer)); } bool Text::operator==(const Text& other) const { return UUID == other.uuid(); } diff --git a/src/window.cpp b/src/window.cpp index fcaa24f..45e1fd1 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,7 +1,7 @@ #include "Cubed/window.hpp" #include "Cubed/config.hpp" -#include "Cubed/renderer.hpp" +#include "Cubed/render/renderer.hpp" #include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/font.hpp" #include "Cubed/tools/log.hpp"