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; uniform float u_shadowsSoftness;
float calc_shadow() { float calc_shadow() {
if (!u_enableShadows) { #ifdef ENABLE_SHADOWS
return 1.0;
}
float step = 1.0 / float(u_shadowsRes); float step = 1.0 / float(u_shadowsRes);
float s = pow(abs(cos(u_dayTime * PI2)), 0.25) * u_shadowsOpacity; float s = pow(abs(cos(u_dayTime * PI2)), 0.25) * u_shadowsOpacity;
vec3 normalOffset = a_realnormal * (a_distance > 64.0 ? 0.2 : 0.04); vec3 normalOffset = a_realnormal * (a_distance > 64.0 ? 0.2 : 0.04);
@ -39,6 +36,9 @@ float calc_shadow() {
shadow = 0.5; shadow = 0.5;
} }
return 0.5 * (1.0 + s * shadow); return 0.5 * (1.0 + s * shadow);
#else
return 1.0;
#endif
} }
#endif // SHADOWS_GLSL_ #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); 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( assetload::postfunc assetload::shader(
AssetsLoader*, AssetsLoader*,
const ResPaths& paths, const ResPaths& paths,
@ -83,21 +91,18 @@ assetload::postfunc assetload::shader(
const std::string& name, const std::string& name,
const std::shared_ptr<AssetCfg>& 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 vertexFile = paths.find(filename + ".glslv");
io::path fragmentFile = paths.find(filename + ".glslf"); io::path fragmentFile = paths.find(filename + ".glslf");
std::string vertexSource = std::move(vertex.code);
std::string fragmentSource = std::move(fragment.code);
return [=](auto assets) { return [=](auto assets) {
assets->store( assets->store(
Shader::create( Shader::create(
vertexFile.string(), {vertexFile.string(), vertex},
fragmentFile.string(), {fragmentFile.string(), fragment}
vertexSource,
fragmentSource
), ),
name name
); );
@ -127,10 +132,8 @@ assetload::postfunc assetload::posteffect(
return [=](auto assets) { return [=](auto assets) {
auto program = Shader::create( auto program = Shader::create(
effectFile.string(), {effectFile.string(), vertexSource},
effectFile.string(), {effectFile.string(), fragmentSource}
vertexSource,
fragmentSource
); );
bool advanced = false; bool advanced = false;
if (settings) { if (settings) {

View File

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

View File

@ -10,15 +10,25 @@
class GLSLExtension; class GLSLExtension;
class Shader { class Shader {
public:
struct Source {
std::string file;
std::string code;
};
private:
static Shader* used; static Shader* used;
uint id; uint id;
std::unordered_map<std::string, uint> uniformLocations; 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); uint getUniformLocation(const std::string& name);
public: public:
static GLSLExtension* preprocessor; static GLSLExtension* preprocessor;
Shader(uint id); Shader(uint id, Source&& vertexSource, Source&& fragmentSource);
~Shader(); ~Shader();
void use(); void use();
@ -38,17 +48,13 @@ public:
void uniform3v(const std::string& name, int length, const float* v); void uniform3v(const std::string& name, int length, const float* v);
void uniform4v(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. /// @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 /// @return linked shader program containing vertex and fragment shaders
static std::unique_ptr<Shader> create( static std::unique_ptr<Shader> create(
const std::string& vertexFile, Source&& vertexSource, Source&& fragmentSource
const std::string& fragmentFile,
const std::string& vertexSource,
const std::string& fragmentSource
); );
static Shader& getUsed(); static Shader& getUsed();

View File

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