aboutsummaryrefslogtreecommitdiff
path: root/source/30-game/Shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/30-game/Shader.cpp')
-rw-r--r--source/30-game/Shader.cpp711
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());
- }
-}