Last active
March 28, 2024 12:26
-
-
Save JuanDiegoMontoya/381dd5be0442b19f314513a2e2dc2194 to your computer and use it in GitHub Desktop.
A shrimple little include handler for glslang that works (doesn't crash lol) for my subset of use cases. Supports nested relative includes with local include syntax (""). Does not support absolute paths for includees or system include syntax (<>).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <glslang/Public/ShaderLang.h> | |
#include <glslang/SPIRV/GlslangToSpv.h> | |
#include <vector> | |
#include <cassert> | |
#include <stdexcept> | |
#include <fstream> | |
#include <stdexcept> | |
#include <memory> | |
std::string LoadFile(const std::filesystem::path& path) | |
{ | |
std::ifstream file{path}; | |
if (!file) | |
{ | |
throw std::runtime_error("File not found"); | |
} | |
return {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()}; | |
} | |
// Hackity hack | |
size_t NumberOfPathComponents(std::filesystem::path path) | |
{ | |
size_t parents = 0; | |
while (!path.empty()) | |
{ | |
parents++; | |
path = path.parent_path(); | |
} | |
return parents > 0 ? parents - 1 : 0; // The path will contain a filename, which we will ignore | |
} | |
class IncludeHandler final : public glslang::TShader::Includer | |
{ | |
public: | |
IncludeHandler(const std::filesystem::path& sourcePath) | |
{ | |
// Seed the "stack" with just the parent directory of the top-level source | |
currentIncluderDir_ /= sourcePath.parent_path(); | |
} | |
glslang::TShader::Includer::IncludeResult* includeLocal( | |
const char* requested_source, | |
[[maybe_unused]] const char* requesting_source, | |
[[maybe_unused]] size_t include_depth) override | |
{ | |
// Everything will explode if this is not relative | |
assert(std::filesystem::path(requested_source).is_relative()); | |
auto fullRequestedSource = currentIncluderDir_ / requested_source; | |
currentIncluderDir_ = fullRequestedSource.parent_path(); | |
auto contentPtr = std::make_unique<std::string>(LoadFile(fullRequestedSource)); | |
auto content = contentPtr.get(); | |
auto sourcePathPtr = std::make_unique<std::string>(requested_source); | |
//auto sourcePath = sourcePathPtr.get(); | |
contentStrings_.emplace_back(std::move(contentPtr)); | |
sourcePathStrings_.emplace_back(std::move(sourcePathPtr)); | |
return new glslang::TShader::Includer::IncludeResult(requested_source, content->c_str(), content->size(), nullptr); | |
} | |
void releaseInclude(glslang::TShader::Includer::IncludeResult* data) override | |
{ | |
for (size_t i = 0; i < NumberOfPathComponents(data->headerName); i++) | |
{ | |
currentIncluderDir_ = currentIncluderDir_.parent_path(); | |
} | |
delete data; | |
} | |
private: | |
// Acts like a stack that we "push" path components to when include{Local, System} are invoked, and "pop" when releaseInclude is invoked | |
std::filesystem::path currentIncluderDir_; | |
std::vector<std::unique_ptr<std::string>> contentStrings_; | |
std::vector<std::unique_ptr<std::string>> sourcePathStrings_; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment