diff options
author | rtk0c <[email protected]> | 2022-05-30 17:03:20 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2022-05-30 17:03:20 -0700 |
commit | e66286ebe30afc9acc4531fc2bea29b7fb924f93 (patch) | |
tree | fa6b76554c3eb88bc8f088fbab68e20c40118ca7 /source/Shader.cpp | |
parent | 366ef5a5450c6e0e680c924c3454943a9ae9814d (diff) |
Changeset: 56 Buildsystem cleanup: change to layered structure for different targets
Diffstat (limited to 'source/Shader.cpp')
-rw-r--r-- | source/Shader.cpp | 767 |
1 files changed, 0 insertions, 767 deletions
diff --git a/source/Shader.cpp b/source/Shader.cpp deleted file mode 100644 index 48881f0..0000000 --- a/source/Shader.cpp +++ /dev/null @@ -1,767 +0,0 @@ -#include "Shader.hpp" - -#include "AppConfig.hpp" -#include "RapidJsonHelper.hpp" -#include "ScopeGuard.hpp" -#include "Utils.hpp" - -#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(), - Tags::NameOf(semantic).data(), - Tags::NameOfGLType(scalarType).data(), - width, - height); -} - -void ShaderSamplerVariable::ShowInfo() const { - ImGui::BulletText("Location: %d\nName: %s\nSemantic: %s\nType: Sampler", - location, - name.c_str(), - Tags::NameOf(semantic).data()); -} - -bool ShaderThingId::IsValid() const { - return kind == KD_Invalid; -} - -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); -} - -ShaderVariable* ShaderInfo::FindVariable(const ShaderThingId& thing) { - switch (thing.kind) { - case ShaderThingId::KD_Input: return &inputs[thing.index]; - case ShaderThingId::KD_Output: return &outputs[thing.index]; - case ShaderThingId::KD_Uniform: return uniforms[thing.index].get(); - case ShaderThingId::KD_Invalid: break; - } - return nullptr; -} - -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; - } - - 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; - } - - return false; -} - -std::unique_ptr<ShaderVariable> CreateVariable(GLenum type, GLuint loc) { - GLenum scalarType; - int width; - int height; - if (QueryMathInfo(type, scalarType, width, height)) { - auto res = std::make_unique<ShaderMathVariable>(); - res->location = loc; - res->scalarType = type; - res->width = width; - res->height = height; - return res; - } - - if (QuerySamplerInfo(type)) { - auto res = std::make_unique<ShaderSamplerVariable>(); - res->location = loc; - res->type = type; - return res; - } - - return nullptr; -} -} // 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; -} - -namespace ProjectBrussel_UNITY_ID { -void WriteShaderVariable(rapidjson::Value& value, rapidjson::Document& root, const ShaderVariable& var) { - value.AddMember("Name", var.name, root.GetAllocator()); - value.AddMember("Semantic", rapidjson::StringRef(Tags::NameOf(var.semantic)), root.GetAllocator()); - value.AddMember("OpenGLLocation", var.location, root.GetAllocator()); -} - -bool ReadShaderVariable(const rapidjson::Value& value, ShaderVariable& var) { - BRUSSEL_JSON_GET(value, "Name", std::string, var.name, return false); - { // Semantic - auto rvSemantic = rapidjson::GetProperty(value, rapidjson::kStringType, "Semantic"sv); - if (!rvSemantic) { - var.semantic = Tags::VES_Generic; - } else { - var.semantic = Tags::FindVertexElementSemantic(rapidjson::AsStringView(*rvSemantic)); - } - } - BRUSSEL_JSON_GET_DEFAULT(value, "OpenGLLocation", int, var.location, 0); - return true; -} - -void WriteShaderMathVariable(rapidjson::Value& value, rapidjson::Document& root, const ShaderMathVariable& var) { - WriteShaderVariable(value, root, var); - value.AddMember("ScalarType", rapidjson::StringRef(Tags::NameOfGLType(var.scalarType)), root.GetAllocator()); - value.AddMember("Width", var.width, root.GetAllocator()); - value.AddMember("Height", var.height, root.GetAllocator()); - value.AddMember("ArrayLength", var.arrayLength, root.GetAllocator()); -} - -bool ReadShaderMathVariable(const rapidjson::Value& value, ShaderMathVariable& var) { - if (!ReadShaderVariable(value, var)) return false; - { - auto rvScalar = rapidjson::GetProperty(value, rapidjson::kStringType, "ScalarType"sv); - if (!rvScalar) return false; - var.scalarType = Tags::FindGLType(rapidjson::AsStringView(*rvScalar)); - } - BRUSSEL_JSON_GET(value, "Width", int, var.width, return false); - BRUSSEL_JSON_GET(value, "Height", int, var.height, return false); - BRUSSEL_JSON_GET_DEFAULT(value, "ArrayLength", int, var.arrayLength, 1); - return true; -} - -void WriteShaderSamplerVariable(rapidjson::Value& value, rapidjson::Document& root, const ShaderSamplerVariable& var) { - WriteShaderVariable(value, root, var); - // TODO -} - -bool ReadShaderSamplerVariable(const rapidjson::Value& value, ShaderSamplerVariable& var) { - if (!ReadShaderVariable(value, var)) return false; - BRUSSEL_JSON_GET_DEFAULT(value, "ArrayLength", int, var.arrayLength, 1); - return true; -} -} // namespace ProjectBrussel_UNITY_ID - -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) { - uniform->ShowInfo(); - } - 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); - - auto& shaderInfo = mInstance->mInfo; - - value.AddMember("SourceFile", mSourceFile, root.GetAllocator()); - - auto SaveMathVars = [&](const char* name, const std::vector<ShaderMathVariable>& vars) { - rapidjson::Value rvThings(rapidjson::kArrayType); - for (auto& thing : vars) { - rapidjson::Value rvThing(rapidjson::kObjectType); - WriteShaderMathVariable(rvThing, root, thing); - - rvThings.PushBack(rvThing, root.GetAllocator()); - } - value.AddMember(rapidjson::StringRef(name), rvThings, root.GetAllocator()); - }; - SaveMathVars("Inputs", shaderInfo.inputs); - SaveMathVars("Outputs", shaderInfo.outputs); - - // TODO uniforms -} - -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()); - } -} |