diff options
author | rtk0c <[email protected]> | 2023-10-19 22:50:07 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2023-10-19 22:50:07 -0700 |
commit | 2c92e07f337e42cf58970443f9de678f85a9b2a4 (patch) | |
tree | 075d5407e1e12a9d35cbee6e4c20ad34e0765c42 /source/30-game/Shader.cpp | |
parent | 615809c036f604bce4582cea8ad49c64693f4f45 (diff) |
The great renaming: switch to "module style"
Diffstat (limited to 'source/30-game/Shader.cpp')
-rw-r--r-- | source/30-game/Shader.cpp | 711 |
1 files changed, 0 insertions, 711 deletions
diff --git a/source/30-game/Shader.cpp b/source/30-game/Shader.cpp deleted file mode 100644 index 9bf2e0e..0000000 --- a/source/30-game/Shader.cpp +++ /dev/null @@ -1,711 +0,0 @@ -#include "Shader.hpp" - -#include "AppConfig.hpp" - -#include <Metadata.hpp> -#include <RapidJsonHelper.hpp> -#include <ScopeGuard.hpp> -#include <Utils.hpp> - -#include <fmt/format.h> -#include <imgui.h> -#include <misc/cpp/imgui_stdlib.h> -#include <rapidjson/document.h> -#include <cassert> -#include <cstddef> -#include <cstdlib> -#include <utility> - -using namespace std::literals; - -void ShaderMathVariable::ShowInfo() const { - ImGui::BulletText("Location: %d\nName: %s\nSemantic: %.*s\nType: %.*s %dx%d", - location, - name.c_str(), - PRINTF_STRING_VIEW(Metadata::EnumToString(semantic)), - PRINTF_STRING_VIEW(Tags::GLTypeToString(scalarType)), - width, - height); -} - -void ShaderSamplerVariable::ShowInfo() const { - ImGui::BulletText("Location: %d\nName: %s\nSemantic: %.*s\nType: Sampler", - location, - name.c_str(), - PRINTF_STRING_VIEW(Metadata::EnumToString(semantic))); -} - -namespace ProjectBrussel_UNITY_ID { -GLuint FindLocation(const std::vector<ShaderMathVariable>& vars, Tags::VertexElementSemantic semantic) { - for (auto& var : vars) { - if (var.semantic == semantic) { - return var.location; - } - } - return Tags::kInvalidLocation; -} - -constexpr auto kAfnTransform = "transform"; -constexpr auto kAfnTime = "time"; -constexpr auto kAfnDeltaTime = "deltaTime"; -constexpr auto kAfnTextureAtlas = "textureAtlas"; - -void InitAutoFill(const char* name, GLuint program, GLuint& location) { - GLint result = glGetUniformLocation(program, name); - if (result != -1) { - location = result; - } -} - -void InitAutoFills(Shader& shader) { - GLuint pg = shader.GetProgram(); - InitAutoFill(kAfnTransform, pg, shader.autofill_Transform); - InitAutoFill(kAfnTime, pg, shader.autofill_Time); - InitAutoFill(kAfnDeltaTime, pg, shader.autofill_DeltaTime); - InitAutoFill(kAfnTextureAtlas, pg, shader.autofill_TextureAtlas); -} -} // namespace ProjectBrussel_UNITY_ID - -GLuint ShaderInfo::FindInputLocation(Tags::VertexElementSemantic semantic) { - using namespace ProjectBrussel_UNITY_ID; - return FindLocation(inputs, semantic); -} - -GLuint ShaderInfo::FindOutputLocation(Tags::VertexElementSemantic semantic) { - using namespace ProjectBrussel_UNITY_ID; - return FindLocation(outputs, semantic); -} - -Shader::Shader() { -} - -Shader::~Shader() { - glDeleteProgram(mProgram); -} - -namespace ProjectBrussel_UNITY_ID { -// Grabs section [begin, end) -Shader::ErrorCode CreateShader(GLuint& out, const char* src, int beginIdx, int endIdx, GLenum type) { - out = glCreateShader(type); - - const GLchar* begin = &src[beginIdx]; - const GLint len = endIdx - beginIdx; - glShaderSource(out, 1, &begin, &len); - - glCompileShader(out); - GLint compileStatus; - glGetShaderiv(out, GL_COMPILE_STATUS, &compileStatus); - if (compileStatus == GL_FALSE) { - GLint len; - glGetShaderiv(out, GL_INFO_LOG_LENGTH, &len); - - std::string log(len, '\0'); - glGetShaderInfoLog(out, len, nullptr, log.data()); - - return Shader ::EC_CompilationFailed; - } - - return Shader::EC_Success; -} - -Shader::ErrorCode CreateShader(GLuint& out, std::string_view str, GLenum type) { - return CreateShader(out, str.data(), 0, str.size(), type); -} - -Shader::ErrorCode LinkShaderProgram(GLuint program) { - glLinkProgram(program); - GLint linkStatus; - glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); - if (linkStatus == GL_FALSE) { - GLint len; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len); - - std::string log(len, '\0'); - glGetProgramInfoLog(program, len, nullptr, log.data()); - - return Shader::EC_LinkingFailed; - } - - return Shader::EC_Success; -} -} // namespace ProjectBrussel_UNITY_ID - -#define CATCH_ERROR_IMPL(x, name) \ - auto name = x; \ - if (name != Shader::EC_Success) { \ - return name; \ - } -#define CATCH_ERROR(x) CATCH_ERROR_IMPL(x, UNIQUE_NAME(result)) - -Shader::ErrorCode Shader::InitFromSources(const ShaderSources& sources) { - using namespace ProjectBrussel_UNITY_ID; - - if (IsValid()) { - return EC_AlreadyInitialized; - } - - GLuint program = glCreateProgram(); - ScopeGuard sg = [&]() { glDeleteProgram(program); }; - - GLuint vertex = 0; - DEFER { - glDeleteShader(vertex); - }; - if (!sources.vertex.empty()) { - CATCH_ERROR(CreateShader(vertex, sources.vertex, GL_VERTEX_SHADER)); - glAttachShader(program, vertex); - } - - GLuint geometry = 0; - DEFER { - glDeleteShader(geometry); - }; - if (!sources.geometry.empty()) { - CATCH_ERROR(CreateShader(geometry, sources.geometry, GL_GEOMETRY_SHADER)); - glAttachShader(program, geometry); - } - - GLuint tessControl = 0; - DEFER { - glDeleteShader(tessControl); - }; - if (!sources.tessControl.empty()) { - CATCH_ERROR(CreateShader(tessControl, sources.tessControl, GL_TESS_CONTROL_SHADER)); - glAttachShader(program, tessControl); - } - - GLuint tessEval = 0; - DEFER { - glDeleteShader(tessEval); - }; - if (!sources.tessEval.empty()) { - CATCH_ERROR(CreateShader(tessEval, sources.tessEval, GL_TESS_EVALUATION_SHADER)); - glAttachShader(program, tessEval); - } - - GLuint fragment = 0; - DEFER { - glDeleteShader(fragment); - }; - if (!sources.fragment.empty()) { - CATCH_ERROR(CreateShader(fragment, sources.fragment, GL_FRAGMENT_SHADER)); - glAttachShader(program, fragment); - } - - CATCH_ERROR(LinkShaderProgram(program)); - - sg.Dismiss(); - mProgram = program; - - InitAutoFills(*this); - - return EC_Success; -} - -Shader::ErrorCode Shader::InitFromSource(std::string_view source) { - using namespace ProjectBrussel_UNITY_ID; - - GLuint vertex = 0; - DEFER { - glDeleteShader(vertex); - }; - - GLuint geometry = 0; - DEFER { - glDeleteShader(geometry); - }; - - GLuint tessControl = 0; - DEFER { - glDeleteShader(tessControl); - }; - - GLuint tessEval = 0; - DEFER { - glDeleteShader(tessEval); - }; - - GLuint fragment = 0; - DEFER { - glDeleteShader(fragment); - }; - - int prevBegin = -1; // Excluding #type marker - int prevEnd = -1; // [begin, end) - std::string prevShaderVariant; - - auto CommitSection = [&]() -> ErrorCode { - if (prevBegin == -1 || prevEnd == -1) { - // Not actually "succeeding" here, but we just want to skip this call and continue - return EC_Success; - } - - if (prevShaderVariant == "vertex" && !vertex) { - CATCH_ERROR(CreateShader(vertex, source.data(), prevBegin, prevEnd, GL_VERTEX_SHADER)); - } else if (prevShaderVariant == "geometry" && !geometry) { - CATCH_ERROR(CreateShader(geometry, source.data(), prevBegin, prevEnd, GL_GEOMETRY_SHADER)); - } else if (prevShaderVariant == "tessellation_control" && !tessControl) { - CATCH_ERROR(CreateShader(tessControl, source.data(), prevBegin, prevEnd, GL_TESS_CONTROL_SHADER)); - } else if (prevShaderVariant == "tessellation_evaluation" && !tessEval) { - CATCH_ERROR(CreateShader(tessEval, source.data(), prevBegin, prevEnd, GL_TESS_EVALUATION_SHADER)); - } else if (prevShaderVariant == "fragment" && !fragment) { - CATCH_ERROR(CreateShader(fragment, source.data(), prevBegin, prevEnd, GL_FRAGMENT_SHADER)); - } else { - return EC_InvalidShaderVariant; - } - - prevBegin = -1; - prevEnd = -1; - prevShaderVariant.clear(); - - return EC_Success; - }; - - constexpr const char* kMarker = "#type "; - bool matchingDirective = true; // If true, we are matching marker pattern; if false, we are accumulating shader variant identifier - int matchIndex = 0; // Current index of the pattern trying to match - std::string shaderVariant; - - // Don't use utf8 iterator, shader sources are expected to be ASCII only - for (size_t i = 0; i < source.size(); ++i) { - char c = source[i]; - - if (matchingDirective) { - if (c == kMarker[matchIndex]) { - // Matched the expected character, go to next char in pattern - matchIndex++; - - // If we are at the end of the marker pattern... - if (kMarker[matchIndex] == '\0') { - matchingDirective = false; - matchIndex = 0; - continue; - } - - // This might be a shader variant directive -> might be end of a section - if (c == '#') { - prevEnd = i; - continue; - } - } else { - // Unexpected character, rollback to beginning - matchIndex = 0; - } - } else { - if (c == '\n') { - // Found complete shader variant directive - - CATCH_ERROR(CommitSection()); // Try commit section, for the first apparent of #type this should do nothing, as `prevEnd` will still be -1 - prevBegin = i + 1; // +1 to skip new line (technically not needed) - prevShaderVariant = std::move(shaderVariant); - - matchingDirective = true; - shaderVariant.clear(); - } else { - // Simply accumulate to shader variant buffer - shaderVariant += c; - } - } - } - - // Commit the last section - prevEnd = static_cast<int>(source.size()); - CATCH_ERROR(CommitSection()); - - GLuint program = glCreateProgram(); - ScopeGuard sg = [&]() { glDeleteProgram(program); }; - - if (vertex) glAttachShader(program, vertex); - if (geometry) glAttachShader(program, geometry); - if (tessControl) glAttachShader(program, tessControl); - if (tessEval) glAttachShader(program, tessEval); - if (fragment) glAttachShader(program, fragment); - - CATCH_ERROR(LinkShaderProgram(program)); - - sg.Dismiss(); - mProgram = program; - - InitAutoFills(*this); - - return EC_Success; -} - -#undef CATCH_ERROR - -namespace ProjectBrussel_UNITY_ID { -bool QueryMathInfo(GLenum type, GLenum& scalarType, int& width, int& height) { - auto DoOutput = [&](GLenum scalarTypeIn, int widthIn, int heightIn) { - width = widthIn; - height = heightIn; - scalarType = scalarTypeIn; - }; - - switch (type) { - case GL_FLOAT: - case GL_DOUBLE: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_BOOL: { - DoOutput(type, 1, 1); - return true; - } - - case GL_FLOAT_VEC2: DoOutput(GL_FLOAT, 1, 2); return true; - case GL_FLOAT_VEC3: DoOutput(GL_FLOAT, 1, 3); return true; - case GL_FLOAT_VEC4: DoOutput(GL_FLOAT, 1, 4); return true; - case GL_DOUBLE_VEC2: DoOutput(GL_DOUBLE, 1, 2); return true; - case GL_DOUBLE_VEC3: DoOutput(GL_DOUBLE, 1, 3); return true; - case GL_DOUBLE_VEC4: DoOutput(GL_DOUBLE, 1, 4); return true; - case GL_INT_VEC2: DoOutput(GL_INT, 1, 2); return true; - case GL_INT_VEC3: DoOutput(GL_INT, 1, 3); return true; - case GL_INT_VEC4: DoOutput(GL_INT, 1, 4); return true; - case GL_UNSIGNED_INT_VEC2: DoOutput(GL_UNSIGNED_INT, 1, 2); return true; - case GL_UNSIGNED_INT_VEC3: DoOutput(GL_UNSIGNED_INT, 1, 3); return true; - case GL_UNSIGNED_INT_VEC4: DoOutput(GL_UNSIGNED_INT, 1, 4); return true; - case GL_BOOL_VEC2: DoOutput(GL_BOOL, 1, 2); return true; - case GL_BOOL_VEC3: DoOutput(GL_BOOL, 1, 3); return true; - case GL_BOOL_VEC4: DoOutput(GL_BOOL, 1, 4); return true; - - case GL_FLOAT_MAT2: DoOutput(GL_FLOAT, 2, 2); return true; - case GL_FLOAT_MAT3: DoOutput(GL_FLOAT, 3, 3); return true; - case GL_FLOAT_MAT4: DoOutput(GL_FLOAT, 4, 4); return true; - case GL_FLOAT_MAT2x3: DoOutput(GL_FLOAT, 2, 3); return true; - case GL_FLOAT_MAT2x4: DoOutput(GL_FLOAT, 2, 4); return true; - case GL_FLOAT_MAT3x2: DoOutput(GL_FLOAT, 3, 2); return true; - case GL_FLOAT_MAT3x4: DoOutput(GL_FLOAT, 3, 4); return true; - case GL_FLOAT_MAT4x2: DoOutput(GL_FLOAT, 4, 2); return true; - case GL_FLOAT_MAT4x3: DoOutput(GL_FLOAT, 4, 3); return true; - - case GL_DOUBLE_MAT2: DoOutput(GL_DOUBLE, 2, 2); return true; - case GL_DOUBLE_MAT3: DoOutput(GL_DOUBLE, 3, 3); return true; - case GL_DOUBLE_MAT4: DoOutput(GL_DOUBLE, 4, 4); return true; - case GL_DOUBLE_MAT2x3: DoOutput(GL_DOUBLE, 2, 3); return true; - case GL_DOUBLE_MAT2x4: DoOutput(GL_DOUBLE, 2, 4); return true; - case GL_DOUBLE_MAT3x2: DoOutput(GL_DOUBLE, 3, 2); return true; - case GL_DOUBLE_MAT3x4: DoOutput(GL_DOUBLE, 3, 4); return true; - case GL_DOUBLE_MAT4x2: DoOutput(GL_DOUBLE, 4, 2); return true; - case GL_DOUBLE_MAT4x3: DoOutput(GL_DOUBLE, 4, 3); return true; - - default: break; - } - - return false; -} - -bool QuerySamplerInfo(GLenum type) { - switch (type) { - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_CUBE: - case GL_SAMPLER_1D_SHADOW: - case GL_SAMPLER_2D_SHADOW: - case GL_SAMPLER_1D_ARRAY: - case GL_SAMPLER_2D_ARRAY: - case GL_SAMPLER_1D_ARRAY_SHADOW: - case GL_SAMPLER_2D_ARRAY_SHADOW: - case GL_SAMPLER_2D_MULTISAMPLE: - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_SAMPLER_CUBE_SHADOW: - case GL_SAMPLER_BUFFER: - case GL_SAMPLER_2D_RECT: - case GL_SAMPLER_2D_RECT_SHADOW: - - case GL_INT_SAMPLER_1D: - case GL_INT_SAMPLER_2D: - case GL_INT_SAMPLER_3D: - case GL_INT_SAMPLER_CUBE: - case GL_INT_SAMPLER_1D_ARRAY: - case GL_INT_SAMPLER_2D_ARRAY: - case GL_INT_SAMPLER_2D_MULTISAMPLE: - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_INT_SAMPLER_BUFFER: - case GL_INT_SAMPLER_2D_RECT: - - case GL_UNSIGNED_INT_SAMPLER_1D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_BUFFER: - case GL_UNSIGNED_INT_SAMPLER_2D_RECT: - return true; - - default: break; - } - - return false; -} - -std::variant<ShaderMathVariable, ShaderSamplerVariable> CreateVariable(GLenum type, GLuint loc) { - GLenum scalarType; - int width; - int height; - if (QueryMathInfo(type, scalarType, width, height)) { - ShaderMathVariable res; - res.location = loc; - res.scalarType = type; - res.width = width; - res.height = height; - return res; - } - - if (QuerySamplerInfo(type)) { - ShaderSamplerVariable res; - res.location = loc; - res.samplerType = type; - return res; - } - - throw std::runtime_error(fmt::format("Unknown OpenGL shader uniform type {}", type)); -} -} // namespace ProjectBrussel_UNITY_ID - -bool Shader::GatherInfoShaderIntrospection() { - using namespace ProjectBrussel_UNITY_ID; - - mInfo = {}; - - // TODO handle differnt types of variables with the same name - - // TODO work with OpenGL < 4.3, possibly with glslang - return true; - - int inputCount; - glGetProgramInterfaceiv(mProgram, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &inputCount); - int outputCount; - glGetProgramInterfaceiv(mProgram, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &outputCount); - int uniformBlockCount; - glGetProgramInterfaceiv(mProgram, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &uniformBlockCount); - int uniformCount; - glGetProgramInterfaceiv(mProgram, GL_UNIFORM, GL_ACTIVE_RESOURCES, &uniformCount); - - // Gather inputs - auto GatherMathVars = [&](int count, GLenum resourceType, ShaderThingId::Kind resourceKind, std::vector<ShaderMathVariable>& list) { - for (int i = 0; i < count; ++i) { - const GLenum query[] = { GL_NAME_LENGTH, GL_TYPE, GL_LOCATION, GL_TOP_LEVEL_ARRAY_SIZE }; - GLint props[std::size(query)]; - glGetProgramResourceiv(mProgram, resourceType, i, std::size(query), query, std::size(props), nullptr, props); - auto& nameLength = props[0]; - auto& type = props[1]; - auto& loc = props[2]; - auto& arrayLength = props[3]; - - std::string fieldName(nameLength - 1, '\0'); - glGetProgramResourceName(mProgram, GL_UNIFORM, i, nameLength, nullptr, fieldName.data()); - - mInfo.things.try_emplace(fieldName, ShaderThingId{ resourceKind, i }); - - auto& thing = list.emplace_back(); - thing.name = std::move(fieldName); - thing.arrayLength = arrayLength; - QueryMathInfo(type, thing.scalarType, thing.width, thing.height); - } - }; - GatherMathVars(inputCount, GL_PROGRAM_INPUT, ShaderThingId::KD_Input, mInfo.inputs); - GatherMathVars(outputCount, GL_PROGRAM_OUTPUT, ShaderThingId::KD_Output, mInfo.outputs); - - // Gather uniform variables - for (int i = 0; i < uniformCount; ++i) { - const GLenum query[] = { GL_BLOCK_INDEX, GL_NAME_LENGTH, GL_TYPE, GL_LOCATION, GL_TOP_LEVEL_ARRAY_SIZE }; - GLint props[std::size(query)]; - glGetProgramResourceiv(mProgram, GL_UNIFORM, i, std::size(query), query, std::size(props), nullptr, props); - auto& blockIndex = props[0]; // Index in interface block - if (blockIndex != -1) { // If this is an interface block uniform, skip because it will be handled by our uniform blocks inspector - continue; - } - auto& nameLength = props[1]; - auto& type = props[2]; - auto& loc = props[3]; - auto& arrayLength = props[4]; - - std::string fieldName(nameLength - 1, '\0'); - glGetProgramResourceName(mProgram, GL_UNIFORM, i, nameLength, nullptr, fieldName.data()); - - mInfo.things.try_emplace(fieldName, ShaderThingId{ ShaderThingId::KD_Uniform, i }); - mInfo.uniforms.push_back(CreateVariable(type, loc)); - } - - return true; -} - -bool Shader::IsValid() const { - return mProgram != 0; -} - -IresShader::IresShader() - : IresObject(KD_Shader) { - InvalidateInstance(); -} - -Shader* IresShader::GetInstance() const { - return mInstance.Get(); -} - -void IresShader::InvalidateInstance() { - if (mInstance != nullptr) { - mInstance->mIres = nullptr; - } - mInstance.Attach(new Shader()); - mInstance->mIres = this; -} - -void IresShader::ShowEditor(IEditor& editor) { - using namespace Tags; - using namespace ProjectBrussel_UNITY_ID; - - IresObject::ShowEditor(editor); - - if (ImGui::Button("Gather info")) { - mInstance->GatherInfoShaderIntrospection(); - } - - if (ImGui::InputText("Source file", &mSourceFile, ImGuiInputTextFlags_EnterReturnsTrue)) { - InvalidateInstance(); - } - // In other cases, mSourceFile will be reverted to before edit - - // TODO macros - - ImGui::Separator(); - - auto& info = mInstance->GetInfo(); - if (ImGui::CollapsingHeader("General")) { - ImGui::Text("OpenGL program ID: %u", mInstance->GetProgram()); - } - if (ImGui::CollapsingHeader("Inputs")) { - for (auto& input : info.inputs) { - input.ShowInfo(); - } - } - if (ImGui::CollapsingHeader("Outputs")) { - for (auto& output : info.outputs) { - output.ShowInfo(); - } - } - if (ImGui::CollapsingHeader("Uniforms")) { - for (auto& uniform : info.uniforms) { - std::visit([](auto&& v) { v.ShowInfo(); }, uniform); - } - if (auto loc = mInstance->autofill_Transform; loc != kInvalidLocation) { - ImGui::BulletText("(Autofill)\nLocation: %d\nName: %s", loc, kAfnTransform); - } - if (auto loc = mInstance->autofill_Time; loc != kInvalidLocation) { - ImGui::BulletText("(Autofill)\nLocation: %d\nName: %s", loc, kAfnTime); - } - if (auto loc = mInstance->autofill_DeltaTime; loc != kInvalidLocation) { - ImGui::BulletText("(Autofill)\nLocation: %d\nName: %s", loc, kAfnDeltaTime); - } - if (auto loc = mInstance->autofill_TextureAtlas; loc != kInvalidLocation) { - ImGui::BulletText("(Autofill)\nLocation: %d\nName: %s", loc, kAfnTextureAtlas); - } - } -} - -void IresShader::Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const { - using namespace ProjectBrussel_UNITY_ID; - - IresObject::Write(ctx, value, root); - json_dto::json_output_t out( value, root.GetAllocator() ); - out << mInstance->mInfo; -} - -void IresShader::Read(IresLoadingContext& ctx, const rapidjson::Value& value) { - using namespace ProjectBrussel_UNITY_ID; - - IresObject::Read(ctx, value); - - auto rvSourceFile = rapidjson::GetProperty(value, rapidjson::kStringType, "SourceFile"sv); - if (!rvSourceFile) { - return; - } else { - this->mSourceFile = rapidjson::AsString(*rvSourceFile); - - char shaderFilePath[256]; - snprintf(shaderFilePath, sizeof(shaderFilePath), "%s/%s", AppConfig::assetDir.c_str(), rvSourceFile->GetString()); - - auto shaderFile = Utils::OpenCstdioFile(shaderFilePath, Utils::Read); - if (!shaderFile) return; - DEFER { - fclose(shaderFile); - }; - - fseek(shaderFile, 0, SEEK_END); - auto shaderFileSize = ftell(shaderFile); - rewind(shaderFile); - - // Also add \0 ourselves - auto buffer = std::make_unique<char[]>(shaderFileSize + 1); - fread(buffer.get(), shaderFileSize, 1, shaderFile); - buffer[shaderFileSize] = '\0'; - std::string_view source(buffer.get(), shaderFileSize); - - if (mInstance->InitFromSource(source) != Shader::EC_Success) { - return; - } - } - - auto& shaderInfo = mInstance->mInfo; - auto shaderProgram = mInstance->GetProgram(); - - auto LoadMathVars = [&](std::string_view name, ShaderThingId::Kind kind, std::vector<ShaderMathVariable>& vars) { - auto rvThings = rapidjson::GetProperty(value, rapidjson::kArrayType, name); - if (!rvThings) return; - - for (auto& rv : rvThings->GetArray()) { - if (!rv.IsObject()) continue; - ShaderMathVariable thing; - ReadShaderMathVariable(rv, thing); - - shaderInfo.things.try_emplace(thing.name, ShaderThingId{ kind, (int)vars.size() }); - vars.push_back(std::move(thing)); - } - }; - LoadMathVars("Inputs"sv, ShaderThingId::KD_Input, shaderInfo.inputs); - LoadMathVars("Outputs"sv, ShaderThingId::KD_Output, shaderInfo.outputs); - - auto rvUniforms = rapidjson::GetProperty(value, rapidjson::kArrayType, "Uniforms"sv); - if (!rvUniforms) return; - for (auto& rvUniform : rvUniforms->GetArray()) { - if (!rvUniform.IsObject()) continue; - - auto rvType = rapidjson::GetProperty(rvUniform, rapidjson::kStringType, "Type"sv); - if (!rvType) continue; - auto type = rapidjson::AsStringView(*rvType); - - auto rvValue = rapidjson::GetProperty(rvUniform, rapidjson::kObjectType, "Value"sv); - if (!rvValue) continue; - - bool autoFill; // TODO store autofill uniforms somewhere else - BRUSSEL_JSON_GET_DEFAULT(rvUniform, "AutoFill", bool, autoFill, false); - if (autoFill) continue; - - auto uniform = [&]() -> std::unique_ptr<ShaderVariable> { - if (type == "Math"sv) { - auto uniform = std::make_unique<ShaderMathVariable>(); - ReadShaderMathVariable(*rvValue, *uniform); - - return uniform; - } else if (type == "Sampler"sv) { - auto uniform = std::make_unique<ShaderSamplerVariable>(); - ReadShaderSamplerVariable(*rvValue, *uniform); - - return uniform; - } - - return nullptr; - }(); - if (uniform) { - shaderInfo.things.try_emplace(uniform->name, ShaderThingId{ ShaderThingId::KD_Uniform, (int)shaderInfo.uniforms.size() }); - shaderInfo.uniforms.emplace_back(std::move(uniform)); - } - } - - for (auto& uniform : shaderInfo.uniforms) { - uniform->location = glGetUniformLocation(shaderProgram, uniform->name.c_str()); - } -} |