refactor GLSLExtension.cpp & add 'param' shader preprocessor directive & add PostEffect class (WIP)
This commit is contained in:
+124
-66
@@ -1,23 +1,28 @@
|
||||
#include "GLSLExtension.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "debug/Logger.hpp"
|
||||
#include "io/engine_paths.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "coders/BasicParser.hpp"
|
||||
#include "graphics/core/PostEffect.hpp"
|
||||
|
||||
void GLSLExtension::setVersion(std::string version) {
|
||||
this->version = std::move(version);
|
||||
}
|
||||
static debug::Logger logger("glsl-extension");
|
||||
|
||||
using Type = PostEffect::Param::Type;
|
||||
|
||||
void GLSLExtension::setPaths(const ResPaths* paths) {
|
||||
this->paths = paths;
|
||||
}
|
||||
|
||||
void GLSLExtension::loadHeader(const std::string& name) {
|
||||
if (paths == nullptr) {
|
||||
return;
|
||||
}
|
||||
io::path file = paths->find("shaders/lib/" + name + ".glsl");
|
||||
std::string source = io::read_string(file);
|
||||
addHeader(name, "");
|
||||
@@ -48,6 +53,10 @@ const std::string& GLSLExtension::getDefine(const std::string& name) const {
|
||||
return found->second;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, std::string>& GLSLExtension::getDefines() const {
|
||||
return defines;
|
||||
}
|
||||
|
||||
bool GLSLExtension::hasDefine(const std::string& name) const {
|
||||
return defines.find(name) != defines.end();
|
||||
}
|
||||
@@ -72,76 +81,125 @@ inline std::runtime_error parsing_error(
|
||||
}
|
||||
|
||||
inline void parsing_warning(
|
||||
const io::path& file, uint linenum, const std::string& message
|
||||
std::string_view file, uint linenum, const std::string& message
|
||||
) {
|
||||
std::cerr << "file " + file.string() + ": warning: " + message +
|
||||
" at line " + std::to_string(linenum)
|
||||
<< std::endl;
|
||||
logger.warning() << "file " + std::string(file) + ": warning: " + message +
|
||||
" at line " + std::to_string(linenum);
|
||||
}
|
||||
|
||||
inline void source_line(std::stringstream& ss, uint linenum) {
|
||||
ss << "#line " << linenum << "\n";
|
||||
}
|
||||
|
||||
static std::optional<PostEffect::Param::Type> param_type_from(
|
||||
const std::string& name
|
||||
) {
|
||||
static const std::unordered_map<std::string, PostEffect::Param::Type> typeNames {
|
||||
{"float", Type::FLOAT},
|
||||
{"vec2", Type::VEC2},
|
||||
{"vec3", Type::VEC3},
|
||||
{"vec4", Type::VEC4},
|
||||
};
|
||||
const auto& found = typeNames.find(name);
|
||||
if (found == typeNames.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
class GLSLParser : public BasicParser<char> {
|
||||
public:
|
||||
GLSLParser(GLSLExtension& glsl, std::string_view file, std::string_view source, bool header)
|
||||
: BasicParser(file, source), glsl(glsl) {
|
||||
if (!header) {
|
||||
ss << "#version " << GLSLExtension::VERSION << '\n';
|
||||
}
|
||||
for (auto& entry : glsl.getDefines()) {
|
||||
ss << "#define " << entry.first << " " << entry.second << '\n';
|
||||
}
|
||||
uint linenum = 1;
|
||||
source_line(ss, linenum);
|
||||
|
||||
clikeComment = true;
|
||||
}
|
||||
|
||||
bool processPreprocessorDirective() {
|
||||
skip(1);
|
||||
|
||||
auto name = parseName();
|
||||
|
||||
if (name == "version") {
|
||||
parsing_warning(filename, line, "removed #version directive");
|
||||
source_line(ss, line);
|
||||
skipLine();
|
||||
return false;
|
||||
} else if (name == "include") {
|
||||
skipWhitespace(false);
|
||||
if (peekNoJump() != '<') {
|
||||
throw error("'<' expected");
|
||||
}
|
||||
skip(1);
|
||||
skipWhitespace(false);
|
||||
auto headerName = parseName();
|
||||
skipWhitespace(false);
|
||||
if (peekNoJump() != '>') {
|
||||
throw error("'>' expected");
|
||||
}
|
||||
skip(1);
|
||||
skipWhitespace(false);
|
||||
skipLine();
|
||||
|
||||
if (!glsl.hasHeader(headerName)) {
|
||||
glsl.loadHeader(headerName);
|
||||
}
|
||||
ss << glsl.getHeader(headerName) << '\n';
|
||||
source_line(ss, line);
|
||||
return false;
|
||||
} else if (name == "param") {
|
||||
skipWhitespace(false);
|
||||
auto typeName = parseName();
|
||||
auto type = param_type_from(typeName);
|
||||
if (!type.has_value()) {
|
||||
throw error("unsupported param type " + util::quote(typeName));
|
||||
}
|
||||
skipWhitespace(false);
|
||||
auto paramName = parseName();
|
||||
if (params.find(paramName) != params.end()) {
|
||||
throw error("duplicating param " + util::quote(paramName));
|
||||
}
|
||||
skipLine();
|
||||
|
||||
ss << "uniform " << typeName << " " << paramName << ";\n";
|
||||
params[paramName] = PostEffect::Param(type.value());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string process() {
|
||||
while (hasNext()) {
|
||||
skipWhitespace(false);
|
||||
if (!hasNext()) {
|
||||
break;
|
||||
}
|
||||
if (source[pos] != '#' || processPreprocessorDirective()) {
|
||||
pos = linestart;
|
||||
ss << readUntilEOL() << '\n';
|
||||
skip(1);
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
private:
|
||||
GLSLExtension& glsl;
|
||||
std::unordered_map<std::string, PostEffect::Param> params;
|
||||
std::stringstream ss;
|
||||
};
|
||||
|
||||
std::string GLSLExtension::process(
|
||||
const io::path& file, const std::string& source, bool header
|
||||
) {
|
||||
std::stringstream ss;
|
||||
size_t pos = 0;
|
||||
uint linenum = 1;
|
||||
if (!header) {
|
||||
ss << "#version " << version << '\n';
|
||||
}
|
||||
for (auto& entry : defines) {
|
||||
ss << "#define " << entry.first << " " << entry.second << '\n';
|
||||
}
|
||||
source_line(ss, linenum);
|
||||
while (pos < source.length()) {
|
||||
size_t endline = source.find('\n', pos);
|
||||
if (endline == std::string::npos) {
|
||||
endline = source.length();
|
||||
}
|
||||
// parsing preprocessor directives
|
||||
if (source[pos] == '#') {
|
||||
std::string line = source.substr(pos + 1, endline - pos);
|
||||
util::trim(line);
|
||||
// parsing 'include' directive
|
||||
if (line.find("include") != std::string::npos) {
|
||||
line = line.substr(7);
|
||||
util::trim(line);
|
||||
if (line.length() < 3) {
|
||||
throw parsing_error(
|
||||
file, linenum, "invalid 'include' syntax"
|
||||
);
|
||||
}
|
||||
if (line[0] != '<' || line[line.length() - 1] != '>') {
|
||||
throw parsing_error(
|
||||
file, linenum, "expected '#include <filename>' syntax"
|
||||
);
|
||||
}
|
||||
std::string name = line.substr(1, line.length() - 2);
|
||||
if (!hasHeader(name)) {
|
||||
loadHeader(name);
|
||||
}
|
||||
source_line(ss, 1);
|
||||
ss << getHeader(name) << '\n';
|
||||
pos = endline + 1;
|
||||
linenum++;
|
||||
source_line(ss, linenum);
|
||||
continue;
|
||||
}
|
||||
// removing extra 'include' directives
|
||||
else if (line.find("version") != std::string::npos) {
|
||||
parsing_warning(file, linenum, "removed #version directive");
|
||||
pos = endline + 1;
|
||||
linenum++;
|
||||
source_line(ss, linenum);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
linenum++;
|
||||
ss << source.substr(pos, endline + 1 - pos);
|
||||
pos = endline + 1;
|
||||
}
|
||||
return ss.str();
|
||||
std::string filename = file.string();
|
||||
GLSLParser parser(*this, filename, source, header);
|
||||
return parser.process();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user