87 lines
3.4 KiB
C++
Executable File
87 lines
3.4 KiB
C++
Executable File
/*
|
|
* Created by Brett on 08/02/23.
|
|
* Licensed under GNU General Public License V3.0
|
|
* See LICENSE file for license detail
|
|
*/
|
|
#include <blt/std/loader.h>
|
|
|
|
std::vector<std::string> blt::fs::getLinesFromFile(const std::string& path) {
|
|
std::string shaderSource;
|
|
std::ifstream shaderFile;
|
|
if (!shaderFile.good())
|
|
BLT_ERROR("Input stream not good!\n");
|
|
// ensure ifstream objects can throw exceptions:
|
|
shaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
|
try {
|
|
// open file
|
|
shaderFile.open(path);
|
|
std::stringstream shaderStream;
|
|
// read file's buffer contents into streams
|
|
shaderStream << shaderFile.rdbuf();
|
|
// close file handlers
|
|
shaderFile.close();
|
|
// convert stream into std::string
|
|
shaderSource = shaderStream.str();
|
|
} catch (std::ifstream::failure& e) {
|
|
BLT_WARN("Unable to read file '%s'!\n", path.c_str());
|
|
BLT_WARN("Exception: %s", e.what());
|
|
throw std::runtime_error("Failed to read file!\n");
|
|
}
|
|
|
|
// split the shader into the lines, this way we can get out the #include statements.
|
|
return string::split(shaderSource, "\n");
|
|
}
|
|
|
|
std::vector<std::string> blt::fs::recursiveShaderInclude(const std::string& path) {
|
|
std::string pathOnly = path.substr(0, path.find_last_of('/'));
|
|
|
|
auto mainLines = getLinesFromFile(path);
|
|
std::unordered_map<int, std::vector<std::string>> includes;
|
|
|
|
for (unsigned int i = 0; i < mainLines.size(); i++) {
|
|
auto& line = mainLines[i];
|
|
// if the line is an include statement then we want to add lines recursively.
|
|
if (string::starts_with(line, "#include")) {
|
|
std::vector<std::string> include_statement = string::split(line, "<");
|
|
|
|
if (include_statement.size() <= 1)
|
|
include_statement = string::split(line, "\"");
|
|
|
|
string::trim(line);
|
|
if (!(string::ends_with(line, ">") || string::ends_with(line, "\""))) {
|
|
BLT_FATAL("Shader file contains an invalid #include statement. (Missing terminator)\n");
|
|
std::abort();
|
|
}
|
|
try {
|
|
// filter out the > or " at the end of the include statement.
|
|
std::string file;
|
|
file = include_statement[1];
|
|
if (string::ends_with(include_statement[1], ">"))
|
|
file = file.substr(0, file.size() - 1);
|
|
|
|
BLT_TRACE("Recusing into %s/%s\n", pathOnly.c_str(), file.c_str());
|
|
|
|
includes.insert({i, recursiveShaderInclude((pathOnly + "/" + file))});
|
|
} catch (std::exception& e) {
|
|
BLT_FATAL("Shader file contains an invalid #include statement. (Missing < or \")\n");
|
|
BLT_FATAL("Exception: %s", e.what());
|
|
std::abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> returnLines;
|
|
|
|
// now combine all the loaded files while respecting the include's position in the file.
|
|
for (unsigned int i = 0; i < mainLines.size(); i++) {
|
|
if (!includes[i].empty()) {
|
|
auto includedFileLines = includes[i];
|
|
|
|
for (const auto& line : includedFileLines)
|
|
returnLines.push_back(line);
|
|
} else
|
|
returnLines.push_back(mainLines[i]);
|
|
}
|
|
return returnLines;
|
|
}
|