feat: recompiling shaders

This commit is contained in:
MihailRis 2025-07-02 23:02:50 +03:00
parent 5751802da2
commit 96a94aa33c
5 changed files with 102 additions and 52 deletions

View File

@ -11,10 +11,7 @@ uniform float u_shadowsOpacity;
uniform float u_shadowsSoftness;
float calc_shadow() {
if (!u_enableShadows) {
return 1.0;
}
#ifdef ENABLE_SHADOWS
float step = 1.0 / float(u_shadowsRes);
float s = pow(abs(cos(u_dayTime * PI2)), 0.25) * u_shadowsOpacity;
vec3 normalOffset = a_realnormal * (a_distance > 64.0 ? 0.2 : 0.04);
@ -39,6 +36,9 @@ float calc_shadow() {
shadow = 0.5;
}
return 0.5 * (1.0 + s * shadow);
#else
return 1.0;
#endif
}
#endif // SHADOWS_GLSL_

View File

@ -76,6 +76,14 @@ static auto process_program(const ResPaths& paths, const std::string& filename)
return std::make_pair(vertex, fragment);
}
static auto read_program(const ResPaths& paths, const std::string& filename) {
io::path vertexFile = paths.find(filename + ".glslv");
io::path fragmentFile = paths.find(filename + ".glslf");
return std::make_pair(
io::read_string(vertexFile), io::read_string(fragmentFile)
);
}
assetload::postfunc assetload::shader(
AssetsLoader*,
const ResPaths& paths,
@ -83,21 +91,18 @@ assetload::postfunc assetload::shader(
const std::string& name,
const std::shared_ptr<AssetCfg>&
) {
auto [vertex, fragment] = process_program(paths, filename);
auto result = read_program(paths, filename);
auto vertex = result.first;
auto fragment = result.second;
io::path vertexFile = paths.find(filename + ".glslv");
io::path fragmentFile = paths.find(filename + ".glslf");
std::string vertexSource = std::move(vertex.code);
std::string fragmentSource = std::move(fragment.code);
return [=](auto assets) {
assets->store(
Shader::create(
vertexFile.string(),
fragmentFile.string(),
vertexSource,
fragmentSource
{vertexFile.string(), vertex},
{fragmentFile.string(), fragment}
),
name
);
@ -127,10 +132,8 @@ assetload::postfunc assetload::posteffect(
return [=](auto assets) {
auto program = Shader::create(
effectFile.string(),
effectFile.string(),
vertexSource,
fragmentSource
{effectFile.string(), vertexSource},
{effectFile.string(), fragmentSource}
);
bool advanced = false;
if (settings) {

View File

@ -12,20 +12,25 @@
#include <GLFW/glfw3.h>
#include "coders/GLSLExtension.hpp"
#include "debug/Logger.hpp"
static debug::Logger logger("gl-shader");
namespace fs = std::filesystem;
GLSLExtension* Shader::preprocessor = new GLSLExtension();
Shader* Shader::used = nullptr;
Shader::Shader(uint id) : id(id){
}
Shader::Shader(uint id, Source&& vertexSource, Source&& fragmentSource)
: id(id),
vertexSource(std::move(vertexSource)),
fragmentSource(std::move(fragmentSource)) {}
Shader::~Shader(){
Shader::~Shader() {
glDeleteProgram(id);
}
void Shader::use(){
void Shader::use() {
used = this;
glUseProgram(id);
}
@ -40,8 +45,10 @@ uint Shader::getUniformLocation(const std::string& name) {
return found->second;
}
void Shader::uniformMatrix(const std::string& name, const glm::mat4& matrix){
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix));
void Shader::uniformMatrix(const std::string& name, const glm::mat4& matrix) {
glUniformMatrix4fv(
getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix)
);
}
void Shader::uniform1i(const std::string& name, int x){
@ -96,7 +103,7 @@ void Shader::uniform4v(const std::string& name, int length, const float* v) {
glUniform4fv(getUniformLocation(name), length, v);
}
inline auto shader_deleter = [](GLuint* shader) {
static inline auto shader_deleter = [](GLuint* shader) {
glDeleteShader(*shader);
delete shader;
};
@ -112,45 +119,73 @@ glshader compile_shader(GLenum type, const GLchar* source, const std::string& fi
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success){
if (!success) {
GLchar infoLog[GL_LOG_LEN];
glGetShaderInfoLog(shader, GL_LOG_LEN, nullptr, infoLog);
glDeleteShader(shader);
throw std::runtime_error(
"vertex shader compilation failed ("+file+"):\n"+std::string(infoLog)
"vertex shader compilation failed (" + file + "):\n" +
std::string(infoLog)
);
}
}
return glshader(new GLuint(shader), shader_deleter); //-V508
}
std::unique_ptr<Shader> Shader::create(
const std::string& vertexFile,
const std::string& fragmentFile,
const std::string& vertexCode,
const std::string& fragmentCode
static GLuint compile_program(
const Shader::Source& vertexSource, const Shader::Source& fragmentSource
) {
auto& preprocessor = *Shader::preprocessor;
auto vertexCode = std::move(
preprocessor.process(vertexSource.file, vertexSource.code).code
);
auto fragmentCode = std::move(
preprocessor.process(fragmentSource.file, fragmentSource.code).code
);
const GLchar* vCode = vertexCode.c_str();
const GLchar* fCode = fragmentCode.c_str();
glshader vertex = compile_shader(GL_VERTEX_SHADER, vCode, vertexFile);
glshader fragment = compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentFile);
glshader vertex =
compile_shader(GL_VERTEX_SHADER, vCode, vertexSource.file);
glshader fragment =
compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentSource.file);
// Shader Program
GLint success;
GLuint id = glCreateProgram();
glAttachShader(id, *vertex);
glAttachShader(id, *fragment);
glLinkProgram(id);
GLuint program = glCreateProgram();
glAttachShader(program, *vertex);
glAttachShader(program, *fragment);
glLinkProgram(program);
glGetProgramiv(id, GL_LINK_STATUS, &success);
if (!success){
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
GLchar infoLog[GL_LOG_LEN];
glGetProgramInfoLog(id, GL_LOG_LEN, nullptr, infoLog);
glGetProgramInfoLog(program, GL_LOG_LEN, nullptr, infoLog);
throw std::runtime_error(
"shader program linking failed:\n"+std::string(infoLog)
"shader program linking failed:\n" + std::string(infoLog)
);
}
return std::make_unique<Shader>(id);
return program;
}
void Shader::recompile() {
GLuint newProgram = compile_program(vertexSource, fragmentSource);
glDeleteProgram(id);
id = newProgram;
uniformLocations.clear();
logger.info() << "shader " << id << " has been recompiled";
}
std::unique_ptr<Shader> Shader::create(
Source&& vertexSource, Source&& fragmentSource
) {
return std::make_unique<Shader>(
compile_program(vertexSource, fragmentSource),
std::move(vertexSource),
std::move(fragmentSource)
);
}
Shader& Shader::getUsed() {

View File

@ -10,15 +10,25 @@
class GLSLExtension;
class Shader {
public:
struct Source {
std::string file;
std::string code;
};
private:
static Shader* used;
uint id;
std::unordered_map<std::string, uint> uniformLocations;
// source code used for re-compiling shaders after updating defines
Source vertexSource;
Source fragmentSource;
uint getUniformLocation(const std::string& name);
public:
static GLSLExtension* preprocessor;
Shader(uint id);
Shader(uint id, Source&& vertexSource, Source&& fragmentSource);
~Shader();
void use();
@ -38,17 +48,13 @@ public:
void uniform3v(const std::string& name, int length, const float* v);
void uniform4v(const std::string& name, int length, const float* v);
/// @brief Re-preprocess source code and re-compile shader program
void recompile();
/// @brief Create shader program using vertex and fragment shaders source.
/// @param vertexFile vertex shader file name
/// @param fragmentFile fragment shader file name
/// @param vertexSource vertex shader source code
/// @param fragmentSource fragment shader source code
/// @return linked shader program containing vertex and fragment shaders
static std::unique_ptr<Shader> create(
const std::string& vertexFile,
const std::string& fragmentFile,
const std::string& vertexSource,
const std::string& fragmentSource
Source&& vertexSource, Source&& fragmentSource
);
static Shader& getUsed();

View File

@ -11,6 +11,7 @@
#include "assets/assets_util.hpp"
#include "content/Content.hpp"
#include "engine/Engine.hpp"
#include "coders/GLSLExtension.hpp"
#include "frontend/LevelFrontend.hpp"
#include "frontend/ContentGfxCache.hpp"
#include "items/Inventory.hpp"
@ -434,6 +435,7 @@ void WorldRenderer::draw(
const auto& vp = pctx.getViewport();
camera.setAspectRatio(vp.x / static_cast<float>(vp.y));
auto& mainShader = assets.require<Shader>("main");
const auto& settings = engine.getSettings();
gbufferPipeline = settings.graphics.advancedRender.get();
int shadowsQuality = settings.graphics.shadowsQuality.get();
@ -442,10 +444,14 @@ void WorldRenderer::draw(
shadowMap = std::make_unique<ShadowMap>(resolution);
wideShadowMap = std::make_unique<ShadowMap>(resolution);
shadows = true;
} else if (shadowsQuality == 0) {
Shader::preprocessor->define("ENABLE_SHADOWS", "true");
mainShader.recompile();
} else if (shadowsQuality == 0 && shadows) {
shadowMap.reset();
wideShadowMap.reset();
shadows = false;
Shader::preprocessor->undefine("ENABLE_SHADOWS");
mainShader.recompile();
}
if (shadows && shadowMap->getResolution() != resolution) {
shadowMap = std::make_unique<ShadowMap>(resolution);