From c62f2baf7c83dadfdc78adb7ef5a068fa8fa4918 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sat, 21 Mar 2026 11:19:23 +0800 Subject: [PATCH] feat: add ui renderer --- assets/texture/ui/0.png | Bin 0 -> 110 bytes include/Cubed/app.hpp | 5 +- include/Cubed/config.hpp | 34 ++++++++++- include/Cubed/gameplay/chunk_status.hpp | 6 +- include/Cubed/renderer.hpp | 20 +++++-- include/Cubed/texture_manager.hpp | 13 ++-- src/app.cpp | 4 +- src/renderer.cpp | 75 ++++++++++++++++++++---- src/shaders/ui_f_shader.glsl | 12 ++++ src/shaders/ui_v_shader.glsl | 18 ++++++ src/texture_manager.cpp | 51 ++++++++++++++-- src/window.cpp | 2 +- 12 files changed, 204 insertions(+), 36 deletions(-) create mode 100644 assets/texture/ui/0.png create mode 100644 src/shaders/ui_f_shader.glsl create mode 100644 src/shaders/ui_v_shader.glsl diff --git a/assets/texture/ui/0.png b/assets/texture/ui/0.png new file mode 100644 index 0000000000000000000000000000000000000000..2e8654547278c9048bd88cea1ab500227e0dca2e GIT binary patch literal 110 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|G(24#Lo9le z6Am!{b7r(N_4%RF$+(y;;2?vW(?yqJ@dvDnIWt#CFfd%I65;4Axxo+A!{F)a=d#Wz Gp$Pzi=^bYP literal 0 HcmV?d00001 diff --git a/include/Cubed/app.hpp b/include/Cubed/app.hpp index 464cd70..07f253b 100644 --- a/include/Cubed/app.hpp +++ b/include/Cubed/app.hpp @@ -20,15 +20,16 @@ public: private: Camera m_camera; + TextureManager m_texture_manager; World m_world; - Renderer m_renderer{m_camera, m_world}; + Renderer m_renderer{m_camera, m_world, m_texture_manager}; Window m_window{m_renderer}; GLuint m_texture_array; - TextureManager m_texture_manager; + void init(); diff --git a/include/Cubed/config.hpp b/include/Cubed/config.hpp index e621bc8..c63c3f7 100644 --- a/include/Cubed/config.hpp +++ b/include/Cubed/config.hpp @@ -3,7 +3,7 @@ constexpr int WORLD_SIZE_X = 32; constexpr int WORLD_SIZE_Z = 32; constexpr int WORLD_SIZE_Y = 16; constexpr int MAX_BLOCK_NUM = 2; - +constexpr int MAX_UI_NUM = 1; constexpr int CHUCK_SIZE = 16; constexpr int DISTANCE = 8; @@ -82,4 +82,34 @@ constexpr int OUTLINE_CUBE_INDICES[24] = { 0,1, 1,2, 2,3, 3,0, 4,5, 5,6, 6,7, 7,4, 0,4, 1,5, 2,6, 3,7 - }; \ No newline at end of file + }; + +constexpr float SQUARE_VERTICES[6][2] = { + -0.5f, -0.5f, // bottom left + -0.5f, 0.5f, // top left + 0.5f, 0.5f, // top right + 0.5f, 0.5f, // top right + 0.5f, -0.5f, // bottom right + -0.5f, -0.5f // bottom left + }; + +constexpr float SQUARE_TEXTURE_POS[6][2] = { + 0.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 0.0f, + 0.0f, 0.0f, + }; + +struct Vertex { + float x, y, z; + float s, t; + float layer; +}; + +struct Vertex2D { + float x, y; + float s, t; + float layer; +}; \ No newline at end of file diff --git a/include/Cubed/gameplay/chunk_status.hpp b/include/Cubed/gameplay/chunk_status.hpp index 0a8bd18..165c537 100644 --- a/include/Cubed/gameplay/chunk_status.hpp +++ b/include/Cubed/gameplay/chunk_status.hpp @@ -13,8 +13,4 @@ struct ChunkPos { }; }; -struct Vertex { - float x, y, z; - float s, t; - float layer; -}; + diff --git a/include/Cubed/renderer.hpp b/include/Cubed/renderer.hpp index 6198806..6a1887f 100644 --- a/include/Cubed/renderer.hpp +++ b/include/Cubed/renderer.hpp @@ -1,22 +1,27 @@ #pragma once + +#include + #include #include #include class Camera; +class TextureManager; class World; class Renderer { public: constexpr static int NUM_VAO = 1; - Renderer(const Camera& camera, World& world); + Renderer(const Camera& camera, World& world, const TextureManager& texture_manager); ~Renderer(); void init(); - void render(GLuint texture_array); - void update_proj_matrix(float aspect); + void render(); + void update_proj_matrix(float aspect, float width, float height); private: const Camera& m_camera; + const TextureManager& m_texture_manager; World& m_world; glm::mat4 m_p_mat, m_v_mat, m_m_mat, m_mv_mat, m_mvp_mat; @@ -27,13 +32,20 @@ private: GLuint m_sky_vbo; GLuint m_outline_indices_vbo; GLuint m_outline_vbo; + GLuint m_ui_vbo; GLuint m_sky_program; GLuint m_outline_program; + GLuint m_ui_program; GLuint m_world_program; + + glm::mat4 m_ui_proj; + glm::mat4 m_ui_m_matrix; + std::vector m_vao; - + std::vector m_ui; void render_outline(); void render_sky(); + void render_ui(); }; \ No newline at end of file diff --git a/include/Cubed/texture_manager.hpp b/include/Cubed/texture_manager.hpp index 2fc44f2..a8c5b69 100644 --- a/include/Cubed/texture_manager.hpp +++ b/include/Cubed/texture_manager.hpp @@ -6,19 +6,20 @@ class TextureManager { private: - GLuint m_texture_array; GLuint m_block_status_array; - void load_block_status(int status_id); + GLuint m_texture_array; + GLuint m_ui_array; + void load_block_status(unsigned status_id); void load_block_texture(unsigned block_id); - + void load_ui_texture(unsigned id); public: TextureManager(); ~TextureManager(); void delet_texture(); - GLuint get_block_status_array(); - GLuint get_texture_array(); - + GLuint get_block_status_array() const; + GLuint get_texture_array() const; + GLuint get_ui_array() const; // Must call after MapTable::init_map() and glfwMakeContextCurrent(window); void init_texture(); }; \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index 8fdd7ac..4e86c1e 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -36,7 +36,7 @@ void App::init() { m_renderer.init(); m_window.update_viewport(); - MapTable::init_map(); + //MapTable::init_map(); m_texture_manager.init_texture(); m_world.init_world(); m_texture_array = m_texture_manager.get_texture_array(); @@ -98,7 +98,7 @@ void App::window_reshape_callback(GLFWwindow* window, int new_width, int new_hei void App::render() { - m_renderer.render(m_texture_array); + m_renderer.render(); glfwSwapBuffers(m_window.get_glfw_window()); diff --git a/src/renderer.cpp b/src/renderer.cpp index 0cd60ec..b705126 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -8,8 +9,9 @@ #include #include -Renderer::Renderer(const Camera& camera, World& world): +Renderer::Renderer(const Camera& camera, World& world, const TextureManager& texture_manager): m_camera(camera), + m_texture_manager(texture_manager), m_world(world) { @@ -20,11 +22,13 @@ Renderer::~Renderer() { glDeleteBuffers(1, &m_outline_vbo); glDeleteBuffers(1, &m_outline_indices_vbo); glDeleteBuffers(1, &m_sky_vbo); + glDeleteBuffers(1, &m_ui_vbo); glBindVertexArray(0); glDeleteVertexArrays(NUM_VAO, m_vao.data()); glDeleteProgram(m_world_program); glDeleteProgram(m_outline_program); glDeleteProgram(m_sky_program); + glDeleteProgram(m_ui_program); } @@ -40,10 +44,12 @@ void Renderer::init() { m_world_program = Shader::create_shader_program("shaders/block_v_shader.glsl", "shaders/block_f_shader.glsl"); m_outline_program = Shader::create_shader_program("shaders/outline_v_shader.glsl", "shaders/outline_f_shader.glsl"); m_sky_program = Shader::create_shader_program("shaders/sky_v_shader.glsl", "shaders/sky_f_shader.glsl"); - + m_ui_program = Shader::create_shader_program("shaders/ui_v_shader.glsl", "shaders/ui_f_shader.glsl"); + glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); - + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #ifndef NDEBUG glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* user_param) { @@ -69,14 +75,26 @@ void Renderer::init() { glBindBuffer(GL_ARRAY_BUFFER, m_sky_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES_POS), VERTICES_POS, GL_STATIC_DRAW); + 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, 0); - - - - } -void Renderer::render(GLuint texture_array) { +void Renderer::render() { glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT); @@ -88,7 +106,7 @@ void Renderer::render(GLuint texture_array) { m_proj_loc = glGetUniformLocation(m_world_program, "proj_matrix"); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, texture_array); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_manager.get_texture_array()); 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; @@ -98,6 +116,8 @@ void Renderer::render(GLuint texture_array) { m_world.render(m_mvp_mat); render_outline(); + + render_ui(); } void Renderer::render_outline() { @@ -150,6 +170,41 @@ void Renderer::render_sky() { } -void Renderer::update_proj_matrix(float aspect) { +void Renderer::render_ui() { + glUseProgram(m_ui_program); + glDisable(GL_DEPTH_TEST); + + m_mv_loc = glGetUniformLocation(m_ui_program, "m_matrix"); + m_proj_loc = glGetUniformLocation(m_ui_program, "proj_matrix"); + + glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_ui_m_matrix)); + glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_ui_proj)); + + 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); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_manager.get_ui_array()); + + glDrawArrays(GL_TRIANGLES, 0, 6); + Shader::check_opengl_error(); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glEnable(GL_DEPTH_TEST); + +} + +void Renderer::update_proj_matrix(float aspect, float width, float height) { m_p_mat = glm::perspective(glm::radians(FOV), aspect, 0.1f, 1000.0f); + 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)); + } \ No newline at end of file diff --git a/src/shaders/ui_f_shader.glsl b/src/shaders/ui_f_shader.glsl new file mode 100644 index 0000000..eee4617 --- /dev/null +++ b/src/shaders/ui_f_shader.glsl @@ -0,0 +1,12 @@ +#version 460 + +in vec2 tc; +flat in int tex_layer; + +out vec4 color; + +layout (binding = 0) uniform sampler2DArray samp; + +void main(void) { + color = texture(samp, vec3(tc, tex_layer)); +} \ No newline at end of file diff --git a/src/shaders/ui_v_shader.glsl b/src/shaders/ui_v_shader.glsl new file mode 100644 index 0000000..ae600c3 --- /dev/null +++ b/src/shaders/ui_v_shader.glsl @@ -0,0 +1,18 @@ +#version 460 + +layout (location = 0) in vec2 pos; +layout (location = 1) in vec2 texCoord; +layout (location = 2) in float layer; + +out vec2 tc; + +flat out int tex_layer; + +uniform mat4 m_matrix; +uniform mat4 proj_matrix; + +void main(void) { + gl_Position = proj_matrix * m_matrix * vec4(pos, 0.0, 1.0); + tc = texCoord; + tex_layer = int(layer); +} diff --git a/src/texture_manager.cpp b/src/texture_manager.cpp index 3fa16c7..1e32362 100644 --- a/src/texture_manager.cpp +++ b/src/texture_manager.cpp @@ -17,14 +17,19 @@ void TextureManager::delet_texture() { LOG::info("Successfully delete all texture"); } -GLuint TextureManager::get_block_status_array() { +GLuint TextureManager::get_block_status_array() const{ return m_block_status_array; } -GLuint TextureManager::get_texture_array() { +GLuint TextureManager::get_texture_array() const{ return m_texture_array; } -void TextureManager::load_block_status(int id) { + +GLuint TextureManager::get_ui_array() const{ + return m_ui_array; +} + +void TextureManager::load_block_status(unsigned id) { CUBED_ASSERT_MSG(id < MAX_BLOCK_STATUS, "Exceed the max status sum limit"); std::string path = "assets/texture/status/" + std::to_string(id) + ".png"; @@ -39,6 +44,7 @@ void TextureManager::load_block_status(int id) { ); Shader::delete_image_data(image_data); } + void TextureManager::load_block_texture(unsigned id) { CUBED_ASSERT_MSG(id < MAX_BLOCK_NUM, "Exceed the max block sum limit"); const std::string& name = MapTable::get_name_from_id(id); @@ -71,6 +77,23 @@ void TextureManager::load_block_texture(unsigned id) { } +void TextureManager::load_ui_texture(unsigned id) { + CUBED_ASSERT_MSG(id < MAX_UI_NUM, "Exceed the max ui sum limit"); + + std::string path = "assets/texture/ui/" + std::to_string(id) + ".png"; + unsigned char* image_data = nullptr; + image_data = (Shader::load_image_data(path)); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_ui_array); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, + 0 ,0, id, + 16, 16, 1, + GL_RGBA, GL_UNSIGNED_BYTE, + image_data + ); + Shader::delete_image_data(image_data); + +} + void TextureManager::init_texture() { MapTable::init_map(); @@ -133,6 +156,26 @@ void TextureManager::init_texture() { if (max_aniso > 0.0f) { LOG::info("Support anisotropic filtering max_aniso is {}", max_aniso); glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY, max_aniso); - } + } + + glGenTextures(1, &m_ui_array); + Shader::check_opengl_error(); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_ui_array); + Shader::check_opengl_error(); + glTexImage3D(GL_TEXTURE_2D_ARRAY, + 0, GL_RGBA, + 16, 16, + MAX_UI_NUM, + 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + Shader::check_opengl_error(); + 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); + } \ No newline at end of file diff --git a/src/window.cpp b/src/window.cpp index bfb4fcc..6d98e51 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -27,7 +27,7 @@ void Window::update_viewport() { glfwGetFramebufferSize(m_window, &m_width, &m_height); m_aspect = (float)m_width / (float)m_height; glViewport(0, 0, m_width, m_height); - m_renderer.update_proj_matrix(m_aspect); + m_renderer.update_proj_matrix(m_aspect, m_width, m_height) ; }