From cc6a1f8e32e448a20b93c9aa19b3b11b23ce248d Mon Sep 17 00:00:00 2001 From: mogemimi Date: Mon, 3 Oct 2016 18:01:22 +0900 Subject: [PATCH] Add #include directive support in glsl --- src/Content/AssetBuilders/ShaderBuilder.cpp | 69 +++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/Content/AssetBuilders/ShaderBuilder.cpp b/src/Content/AssetBuilders/ShaderBuilder.cpp index ad76a728e..4aad31db6 100644 --- a/src/Content/AssetBuilders/ShaderBuilder.cpp +++ b/src/Content/AssetBuilders/ShaderBuilder.cpp @@ -11,14 +11,18 @@ #include "Pomdog/Graphics/Shader.hpp" #include "Pomdog/Graphics/ShaderLanguage.hpp" #include "Pomdog/Graphics/ShaderPipelineStage.hpp" +#include "Pomdog/Logging/Log.hpp" #include "Pomdog/Utility/Assert.hpp" #include "Pomdog/Utility/Exception.hpp" #include "Pomdog/Utility/FileSystem.hpp" #include "Pomdog/Utility/Optional.hpp" #include "Pomdog/Utility/PathHelper.hpp" +#include "Pomdog/Utility/StringHelper.hpp" #include #include #include +#include +#include using Pomdog::Detail::BinaryReader; using Pomdog::Detail::ShaderBytecode; @@ -28,7 +32,56 @@ using Pomdog::ShaderCompilers::MetalCompiler; namespace Pomdog { namespace AssetBuilders { +namespace { +Optional IncludeGLSLFilesRecursive( + const std::string& path, std::set & includes) +{ + if (FileSystem::IsDirectory(path)) { + Log::Warning("Pomdog", "error: " + path + "is directory, not text file."); + return NullOpt; + } + + std::ifstream input(path); + if (!input) { + return NullOpt; + } + std::istreambuf_iterator start(input); + std::istreambuf_iterator end; + std::string text(start, end); + input.close(); + + auto currentDirectory = PathHelper::GetDirectoryName(PathHelper::Normalize(path)); + + auto lines = StringHelper::Split(text, '\n'); + text.clear(); + for (const auto& line : lines) { + std::regex includeRegex(R"(\s*#\s*include\s+\"([\w\.\/\\]+)\")"); + std::smatch match; + + bool matched = std::regex_match(line, match, includeRegex); + if (!matched || match.size() != 2) { + text += line; + text += '\n'; + continue; + } + + auto includePath = PathHelper::Join(currentDirectory, match[1]); + if (includes.find(includePath) == includes.end()) { + includes.insert(includePath); + auto result = IncludeGLSLFilesRecursive(includePath, includes); + if (!result) { + return NullOpt; + } + text += *result; + } + text += '\n'; + } + + return text; +} + +} // unnamed namespace // explicit instantiations template class Builder; @@ -115,6 +168,22 @@ Builder & Builder::SetGLSLFromFile(const std::string& assetName) POMDOG_THROW_EXCEPTION(std::runtime_error, "The file is too small"); } + { + // NOTE: Using the #include in GLSL support + std::set includes; + auto includeResult = IncludeGLSLFilesRecursive( + PathHelper::Join(impl->loaderContext.get().RootDirectory, assetName), + includes); + + if (includeResult) { + auto & shaderCode = *includeResult; + impl->shaderBlob.clear(); + impl->shaderBlob.resize(shaderCode.size() + 1); + impl->shaderBlob[shaderCode.size()] = 0; + std::memcpy(impl->shaderBlob.data(), shaderCode.data(), shaderCode.size()); + } + } + impl->shaderBytecode.Code = impl->shaderBlob.data(); impl->shaderBytecode.ByteLength = impl->shaderBlob.size(); impl->shaderFilePath = assetName;