feat: add shader class

This commit is contained in:
2026-03-29 11:13:34 +08:00
parent b1a5581131
commit 2cfbd1a03b
11 changed files with 216 additions and 90 deletions

View File

@@ -87,6 +87,7 @@ add_executable(${PROJECT_NAME}
src/input.cpp
src/map_table.cpp
src/renderer.cpp
src/shader.cpp
src/texture_manager.cpp
src/tools/math_tools.cpp
src/tools/shader_tools.cpp

View File

@@ -1,6 +1,7 @@
#pragma once
#include <Cubed/config.hpp>
#include <Cubed/shader.hpp>
#include <glad/glad.h>
#include <glm/glm.hpp>
@@ -16,6 +17,7 @@ public:
Renderer(const Camera& camera, World& world, const TextureManager& texture_manager);
~Renderer();
void init();
const Shader& get_shader(const std::string& name) const;
void render();
void update_proj_matrix(float aspect, float width, float height);
private:
@@ -35,21 +37,14 @@ private:
GLuint m_outline_vbo;
GLuint m_ui_vbo;
GLuint m_sky_program;
GLuint m_text_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::unordered_map<std::size_t, Shader> m_shaders;
std::vector<GLuint> m_vao;
std::vector<Vertex2D> m_ui;
void render_outline();
void render_sky();
void render_text();
void render_ui();
void render_world();
};

26
include/Cubed/shader.hpp Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include <glad/glad.h>
#include <string>
class Shader {
public:
Shader();
Shader(const std::string& name, const std::string& v_shader_path, const std::string& f_shader_path);
~Shader();
Shader(const Shader&) = delete;
Shader& operator=(const Shader&) = delete;
Shader(Shader&& shader);
Shader& operator=(Shader&& shader);
void create(const std::string& name, const std::string& v_shader_path, const std::string& f_shader_path);
std::size_t hash() const;
GLuint loc(const std::string& loc) const;
const std::string& name() const;
void use() const;
private:
GLuint m_program = 0;
std::size_t m_hash = 0;
std::string m_name = "-1";
};

View File

@@ -1,7 +1,7 @@
#pragma once
#include <string>
namespace HASH {
inline std::size_t str(std::string value) {
inline std::size_t str(const std::string& value) {
return std::hash<std::string>{}(value);
}

View File

@@ -16,12 +16,14 @@ struct Character {
GLuint advance;
};
class Shader;
class Font {
public:
Font();
~Font();
static void render_text(GLuint program, const std::string& text, float x, float y, float scale, const glm::vec3& color);
static void render_text(const Shader& shader, const std::string& text, float x, float y, float scale, const glm::vec3& color);
private:
FT_Library m_ft;

View File

@@ -4,7 +4,7 @@
#include <SOIL2.h>
#include <string>
namespace Shader {
namespace Tools {
GLuint create_shader_program(const std::string& v_shader_path, const std::string& f_shader_path);
void print_shader_log(GLuint shader);
void print_program_info(int prog);

View File

@@ -5,6 +5,7 @@
#include <Cubed/texture_manager.hpp>
#include <Cubed/renderer.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/shader_tools.hpp>
@@ -28,10 +29,6 @@ Renderer::~Renderer() {
glDeleteBuffers(1, &m_text_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);
}
@@ -44,12 +41,17 @@ void Renderer::init() {
LOG::info("OpenGL Version: {}.{}", GLVersion.major, GLVersion.minor);
LOG::info("Renderer: {}", reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
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");
m_text_program = Shader::create_shader_program("shaders/text_v_shader.glsl", "shaders/text_f_shader.glsl");
Shader world_shader{"world", "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"};
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)});
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
@@ -103,26 +105,20 @@ void Renderer::init() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
const Shader& Renderer::get_shader(const std::string& name) const {
auto it = m_shaders.find(HASH::str(name));
CUBED_ASSERT_MSG(it != m_shaders.end(), "Shader don't find, check the name");
return it->second;
}
void Renderer::render() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glBindVertexArray(m_vao[0]);
render_sky();
glUseProgram(m_world_program);
m_mv_loc = glGetUniformLocation(m_world_program, "mv_matrix");
m_proj_loc = glGetUniformLocation(m_world_program, "proj_matrix");
glActiveTexture(GL_TEXTURE0);
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;
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
glUniformMatrix4fv(m_proj_loc, 1 ,GL_FALSE, glm::value_ptr(m_p_mat));
m_mvp_mat = m_p_mat * m_mv_mat;
m_world.render(m_mvp_mat);
render_world();
render_outline();
@@ -132,10 +128,11 @@ void Renderer::render() {
}
void Renderer::render_outline() {
glUseProgram(m_outline_program);
const auto& shader = get_shader("outline");
shader.use();
m_mv_loc = glGetUniformLocation(m_outline_program, "mv_matrix");
m_proj_loc = glGetUniformLocation(m_outline_program, "proj_matrix");
m_mv_loc = shader.loc("mv_matrix");
m_proj_loc = shader.loc("proj_matrix");
const auto& block_pos = m_world.get_look_block_pos("TestPlayer");
@@ -159,10 +156,12 @@ void Renderer::render_outline() {
}
void Renderer::render_sky() {
glUseProgram(m_sky_program);
const auto& shader = get_shader("sky");
m_mv_loc = glGetUniformLocation(m_sky_program, "mv_matrix");
m_proj_loc = glGetUniformLocation(m_sky_program, "proj_matrix");
shader.use();
m_mv_loc = shader.loc("mv_matrix");
m_proj_loc = shader.loc("proj_matrix");
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();
@@ -182,22 +181,26 @@ void Renderer::render_sky() {
}
void Renderer::render_text() {
glUseProgram(m_text_program);
const auto& shader = get_shader("text");
shader.use();
glDisable(GL_DEPTH_TEST);
m_proj_loc = glGetUniformLocation(m_text_program, "projection");
m_proj_loc = shader.loc("projection");
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_ui_proj));
Font::render_text(m_text_program, std::string{"FPS: " + std::to_string(static_cast<int>(App::get_fps()))}, 0.0f, 50.0f, 1.0f, glm::vec3(1.0f, 1.0f, 1.0f));
Font::render_text(m_text_program, "Version: v0.0.1-Debug", 0.0f, 100.0f, 0.8f, glm::vec3(1.0f, 1.0f, 1.0f));
Font::render_text(shader, std::string{"FPS: " + std::to_string(static_cast<int>(App::get_fps()))}, 0.0f, 50.0f, 1.0f, glm::vec3(1.0f, 1.0f, 1.0f));
Font::render_text(shader, "Version: v0.0.1-Debug", 0.0f, 100.0f, 0.8f, glm::vec3(1.0f, 1.0f, 1.0f));
glEnable(GL_DEPTH_TEST);
}
void Renderer::render_ui() {
glUseProgram(m_ui_program);
const auto& shader = get_shader("ui");
shader.use();
glDisable(GL_DEPTH_TEST);
m_mv_loc = glGetUniformLocation(m_ui_program, "m_matrix");
m_proj_loc = glGetUniformLocation(m_ui_program, "proj_matrix");
m_mv_loc = shader.loc("m_matrix");
m_proj_loc = shader.loc("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));
@@ -215,7 +218,7 @@ void Renderer::render_ui() {
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_manager.get_ui_array());
glDrawArrays(GL_TRIANGLES, 0, 6);
Shader::check_opengl_error();
Tools::check_opengl_error();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnable(GL_DEPTH_TEST);
@@ -230,3 +233,21 @@ void Renderer::update_proj_matrix(float aspect, float width, float height) {
glm::scale(glm::mat4(1.0f), glm::vec3(50.0f, 50.0f, 1.0f));
}
void Renderer::render_world() {
const auto& shader = get_shader("world");
shader.use();
m_mv_loc = shader.loc("mv_matrix");
m_proj_loc = shader.loc("proj_matrix");
glActiveTexture(GL_TEXTURE0);
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;
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat));
glUniformMatrix4fv(m_proj_loc, 1 ,GL_FALSE, glm::value_ptr(m_p_mat));
m_mvp_mat = m_p_mat * m_mv_mat;
m_world.render(m_mvp_mat);
}

80
src/shader.cpp Normal file
View File

@@ -0,0 +1,80 @@
#include <Cubed/shader.hpp>
#include <Cubed/tools/cubed_assert.hpp>
#include <Cubed/tools/cubed_hash.hpp>
#include <Cubed/tools/log.hpp>
#include <Cubed/tools/shader_tools.hpp>
Shader::Shader() {
}
Shader::Shader(const std::string& name, const std::string& v_shader_path, const std::string& f_shader_path) {
m_program = Tools::create_shader_program(v_shader_path, f_shader_path);
m_name = name;
m_hash = HASH::str(name);
}
Shader::Shader(Shader&& shader) :
m_hash(shader.m_hash),
m_program(shader.m_program),
m_name(std::move(shader.m_name))
{
shader.m_hash = 0;
shader.m_program = 0;
}
Shader::~Shader() {
if (m_program) {
glDeleteProgram(m_program);
}
}
Shader& Shader::operator=(Shader&& shader) {
m_hash = shader.m_hash;
m_name = std::move(shader.m_name);
m_program = shader.m_program;
shader.m_hash = 0;
shader.m_program = 0;
return *this;
}
void Shader::create(const std::string& name, const std::string& v_shader_path, const std::string& f_shader_path) {
if (!m_program) {
LOG::warn("Shader has already created !");
return;
}
m_program = Tools::create_shader_program(v_shader_path, f_shader_path);
m_name = name;
m_hash = HASH::str(name);
}
std::size_t Shader::hash() const {
if (!m_hash) {
LOG::warn("Shader has already created !");
return 0;
}
return m_hash;
}
GLuint Shader::loc(const std::string& loc) const {
CUBED_ASSERT_MSG(m_program != 0, "Shader program not created");
GLint pos = glGetUniformLocation(m_program, loc.c_str());
if (pos == -1) {
LOG::info("Shader name {}, loc name {}, pos {}", m_name, loc, pos);
CUBED_ASSERT_MSG(pos == -1, "Can't find UniformLocation");
}
return static_cast<GLuint>(pos);
}
const std::string& Shader::name() const {
if (m_name == "-1") {
LOG::warn("Shader has already created !");
}
return m_name;
}
void Shader::use() const{
CUBED_ASSERT_MSG(m_program, "Shader don't create !");
glUseProgram(m_program);
}

View File

@@ -34,7 +34,7 @@ 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";
unsigned char* image_data = nullptr;
image_data = (Shader::load_image_data(path));
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,
@@ -42,7 +42,7 @@ void TextureManager::load_block_status(unsigned id) {
GL_RGBA, GL_UNSIGNED_BYTE,
image_data
);
Shader::delete_image_data(image_data);
Tools::delete_image_data(image_data);
}
void TextureManager::load_block_texture(unsigned id) {
@@ -55,15 +55,15 @@ void TextureManager::load_block_texture(unsigned id) {
unsigned char* image_data[6];
std::string block_texture_path = "assets/texture/block/" + name;
image_data[0] = (Shader::load_image_data(block_texture_path + "/front.png"));
image_data[1] = (Shader::load_image_data(block_texture_path + "/right.png"));
image_data[2] = (Shader::load_image_data(block_texture_path + "/back.png"));
image_data[3] = (Shader::load_image_data(block_texture_path + "/left.png"));
image_data[4] = (Shader::load_image_data(block_texture_path + "/top.png"));
image_data[5] = (Shader::load_image_data(block_texture_path + "/base.png"));
image_data[0] = (Tools::load_image_data(block_texture_path + "/front.png"));
image_data[1] = (Tools::load_image_data(block_texture_path + "/right.png"));
image_data[2] = (Tools::load_image_data(block_texture_path + "/back.png"));
image_data[3] = (Tools::load_image_data(block_texture_path + "/left.png"));
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);
Shader::check_opengl_error();
Tools::check_opengl_error();
for (int i = 0; i < 6; i++) {
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0,
0, 0, id * 6 + i,
@@ -71,8 +71,8 @@ void TextureManager::load_block_texture(unsigned id) {
GL_RGBA, GL_UNSIGNED_BYTE,
image_data[i]
);
Shader::check_opengl_error();
Shader::delete_image_data(image_data[i]);
Tools::check_opengl_error();
Tools::delete_image_data(image_data[i]);
}
}
@@ -82,7 +82,7 @@ void TextureManager::load_ui_texture(unsigned id) {
std::string path = "assets/texture/ui/" + std::to_string(id) + ".png";
unsigned char* image_data = nullptr;
image_data = (Shader::load_image_data(path));
image_data = (Tools::load_image_data(path));
glBindTexture(GL_TEXTURE_2D_ARRAY, m_ui_array);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0,
0 ,0, id,
@@ -90,7 +90,7 @@ void TextureManager::load_ui_texture(unsigned id) {
GL_RGBA, GL_UNSIGNED_BYTE,
image_data
);
Shader::delete_image_data(image_data);
Tools::delete_image_data(image_data);
}
@@ -99,28 +99,28 @@ void TextureManager::init_texture() {
MapTable::init_map();
glGenTextures(1, &m_texture_array);
Shader::check_opengl_error();
Tools::check_opengl_error();
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_array);
Shader::check_opengl_error();
Tools::check_opengl_error();
glTexImage3D(GL_TEXTURE_2D_ARRAY,
0, GL_RGBA,
16, 16,
MAX_BLOCK_NUM * 6,
0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
Shader::check_opengl_error();
Tools::check_opengl_error();
for (int i = 0; i < MAX_BLOCK_NUM; i++) {
load_block_texture(i);
}
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_array);
Shader::check_opengl_error();
Tools::check_opengl_error();
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Shader::check_opengl_error();
Tools::check_opengl_error();
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
Shader::check_opengl_error();
Tools::check_opengl_error();
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
Shader::check_opengl_error();
Tools::check_opengl_error();
GLfloat max_aniso = 0.0f;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_aniso);
@@ -130,28 +130,28 @@ void TextureManager::init_texture() {
}
glGenTextures(1, &m_block_status_array);
Shader::check_opengl_error();
Tools::check_opengl_error();
glBindTexture(GL_TEXTURE_2D_ARRAY, m_block_status_array);
Shader::check_opengl_error();
Tools::check_opengl_error();
glTexImage3D(GL_TEXTURE_2D_ARRAY,
0, GL_RGBA,
16, 16,
MAX_BLOCK_STATUS,
0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
Shader::check_opengl_error();
Tools::check_opengl_error();
for (int i = 0; i < MAX_BLOCK_STATUS; i++) {
load_block_status(i);
}
glBindTexture(GL_TEXTURE_2D_ARRAY, m_block_status_array);
Shader::check_opengl_error();
Tools::check_opengl_error();
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Shader::check_opengl_error();
Tools::check_opengl_error();
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
Shader::check_opengl_error();
Tools::check_opengl_error();
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
Shader::check_opengl_error();
Tools::check_opengl_error();
if (max_aniso > 0.0f) {
LOG::info("Support anisotropic filtering max_aniso is {}", max_aniso);
@@ -159,16 +159,16 @@ void TextureManager::init_texture() {
}
glGenTextures(1, &m_ui_array);
Shader::check_opengl_error();
Tools::check_opengl_error();
glBindTexture(GL_TEXTURE_2D_ARRAY, m_ui_array);
Shader::check_opengl_error();
Tools::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();
Tools::check_opengl_error();
for (int i = 0; i < MAX_UI_NUM; i++) {
load_ui_texture(i);
}

View File

@@ -1,4 +1,5 @@
#include <Cubed/config.hpp>
#include <Cubed/shader.hpp>
#include <Cubed/tools/font.hpp>
#include <Cubed/tools/log.hpp>
@@ -90,10 +91,10 @@ void Font::setup_font_character() {
void Font::render_text(GLuint program, const std::string& text, float x, float y, float scale, const glm::vec3& color) {
void Font::render_text(const Shader& shader, const std::string& text, float x, float y, float scale, const glm::vec3& color) {
static Font font;
glUseProgram(program);
glUniform3f(glGetUniformLocation(program, "textColor"), color.x, color.y, color.z);
glUniform3f(shader.loc("textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
std::vector<Vertex2D> vertices;

View File

@@ -6,11 +6,11 @@
#include <Cubed/tools/log.hpp>
namespace Shader {
namespace Tools {
GLuint create_shader_program(const std::string& v_shader_path, const std::string& f_shader_path) {
std::string v_shader_str = Shader::read_shader_source(v_shader_path);
std::string f_shader_str = Shader::read_shader_source(f_shader_path);
std::string v_shader_str = Tools::read_shader_source(v_shader_path);
std::string f_shader_str = Tools::read_shader_source(f_shader_path);
const char *v_shader_source = v_shader_str.c_str();
const char *f_shader_source = f_shader_str.c_str();
@@ -21,19 +21,19 @@ namespace Shader {
glShaderSource(v_shader, 1, &v_shader_source, NULL);
glShaderSource(f_shader, 1, &f_shader_source, NULL);
glCompileShader(v_shader);
Shader::check_opengl_error();
Tools::check_opengl_error();
glGetShaderiv(v_shader, GL_COMPILE_STATUS, &vc);
if (vc != 1) {
LOG::error("vertex compilation failed");
Shader::print_shader_log(v_shader);
Tools::print_shader_log(v_shader);
CUBED_ASSERT(0);
}
glCompileShader(f_shader);
Shader::check_opengl_error();
Tools::check_opengl_error();
glGetShaderiv(f_shader, GL_COMPILE_STATUS, &fc);
if (fc != 1) {
LOG::error("vertex compilation failed");
Shader::print_shader_log(f_shader);
Tools::print_shader_log(f_shader);
CUBED_ASSERT(0);
}
GLuint vf_program = glCreateProgram();
@@ -42,11 +42,11 @@ namespace Shader {
glLinkProgram(vf_program);
GLint linked;
Shader::check_opengl_error();
Tools::check_opengl_error();
glGetProgramiv(vf_program, GL_LINK_STATUS, &linked);
if (linked != 1) {
LOG::error("linking failed");
Shader::print_program_info(vf_program);
Tools::print_program_info(vf_program);
CUBED_ASSERT(0);
}
glDeleteShader(v_shader);