Magpie/Runtime/EffectCompiler.cpp
2021-10-13 16:33:51 +08:00

528 lines
10 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "pch.h"
#include "EffectCompiler.h"
UINT EffectCompiler::Compile(const wchar_t* fileName, EffectDesc& desc) {
desc = {};
std::string source;
Utils::ReadTextFile(fileName, source);
if (source.empty()) {
return 1;
}
// 移除注释
if (_RemoveComments(source)) {
return 1;
}
std::string_view sourceView(source);
// 检查头
if (!_CheckMagic(sourceView)) {
return 2;
}
enum class BlockType {
Header,
Constant,
Texture,
Sampler,
Common,
Pass
};
std::string_view headerBlock;
std::vector<std::string_view> constantBlocks;
std::vector<std::string_view> textureBlocks;
std::vector<std::string_view> samplerBlocks;
std::vector<std::string_view> commonBlocks;
std::vector<std::string_view> passBlocks;
BlockType curBlockType = BlockType::Header;
size_t curBlockOff = 0;
auto completeCurrentBlock = [&](size_t len, BlockType newBlockType) {
switch (curBlockType) {
case BlockType::Header:
headerBlock = sourceView.substr(curBlockOff, len);
break;
case BlockType::Constant:
constantBlocks.push_back(sourceView.substr(curBlockOff, len));
break;
case BlockType::Texture:
textureBlocks.push_back(sourceView.substr(curBlockOff, len));
break;
case BlockType::Sampler:
samplerBlocks.push_back(sourceView.substr(curBlockOff, len));
break;
case BlockType::Common:
commonBlocks.push_back(sourceView.substr(curBlockOff, len));
break;
case BlockType::Pass:
passBlocks.push_back(sourceView.substr(curBlockOff, len));
break;
default:
assert(false);
break;
}
curBlockType = newBlockType;
curBlockOff += len;
};
bool newLine = true;
std::string_view t = sourceView;
while (t.size() > 5) {
if (newLine) {
// 包含换行符
size_t len = t.data() - sourceView.data() - curBlockOff + 1;
if (_CheckNextToken<true>(t, _META_INDICATOR)) {
std::string_view token;
if (_GetNextToken<false>(t, token)) {
return 1;
}
std::string blockType = Utils::ToUpperCase(token);
if (blockType == "CONSTANT") {
completeCurrentBlock(len, BlockType::Constant);
} else if (blockType == "TEXTURE") {
completeCurrentBlock(len, BlockType::Texture);
} else if (blockType == "SAMPLER") {
completeCurrentBlock(len, BlockType::Sampler);
} else if (blockType == "COMMON") {
completeCurrentBlock(len, BlockType::Common);
} else if (blockType == "PASS") {
completeCurrentBlock(len, BlockType::Pass);
}
}
if (t.size() <= 5) {
break;
}
} else {
t.remove_prefix(1);
}
newLine = t[0] == '\n';
}
completeCurrentBlock(sourceView.size() - curBlockOff, BlockType::Header);
if (_ResolveHeader(headerBlock, desc)) {
return 1;
}
for (std::string_view& block : constantBlocks) {
if (_ResolveConstants(block, desc)) {
return 1;
}
}
return 0;
}
UINT EffectCompiler::_RemoveComments(std::string& source) {
// 确保以换行符结尾
if (source.back() != '\n') {
source.push_back('\n');
}
std::string result;
result.reserve(source.size());
int j = 0;
// 单独处理最后两个字符
for (size_t i = 0, end = source.size() - 2; i < end; ++i) {
if (source[i] == '/') {
if (source[i + 1] == '/' && source[i + 2] != '!') {
// 行注释
i += 2;
// 无需处理越界,因为必定以换行符结尾
while (source[i] != '\n') {
++i;
}
// 文件结尾
if (i >= source.size() - 2) {
source.resize(j);
return 0;
}
continue;
} else if (source[i + 1] == '*') {
// 块注释
i += 2;
while(true) {
if (++i >= source.size()) {
// 未闭合
return 1;
}
if (source[i - 1] == '*' && source[i] == '/') {
break;
}
}
// 文件结尾
if (i >= source.size() - 2) {
source.resize(j);
return 0;
}
continue;
}
}
source[j++] = source[i];
}
// 无需复制最后的换行符
source[j++] = source[source.size() - 2];
source.resize(j);
return 0;
}
UINT EffectCompiler::_GetNextExpr(std::string_view& source, std::string& expr) {
_RemoveLeadingBlanks<false>(source);
size_t size = std::min(source.find('\n') + 1, source.size());
// 移除空白字符
expr.resize(size);
size_t j = 0;
for (size_t i = 0; i < size; ++i) {
char c = source[i];
if (!isspace(c)) {
expr[j++] = c;
}
}
expr.resize(j);
if (expr.empty()) {
return 1;
}
source.remove_prefix(size);
return 0;
}
UINT EffectCompiler::_GetNextString(std::string_view& source, std::string_view& value) {
_RemoveLeadingBlanks<false>(source);
size_t pos = source.find('\n');
value = source.substr(0, pos);
Utils::Trim(value);
if (value.empty()) {
return 1;
}
source.remove_prefix(std::min(pos + 1, source.size()));
return 0;
}
bool EffectCompiler::_CheckMagic(std::string_view& source) {
std::string_view token;
if (!_CheckNextToken<true>(source, _META_INDICATOR)) {
return false;
}
if (!_CheckNextToken<false>(source, "MAGPIE")) {
return false;
}
if (!_CheckNextToken<false>(source, "EFFECT")) {
return false;
}
if (_GetNextToken<false>(source, token) != 2) {
return false;
}
if (source.empty()) {
return false;
}
return true;
}
UINT EffectCompiler::_ResolveHeader(std::string_view block, EffectDesc& desc) {
// 必需的选项VERSION
// 可选的选项OUTPUT_WIDTHOUTPUT_HEIGHT
std::vector<bool> processed(3, false);
std::string_view token;
while (true) {
if (!_CheckNextToken<true>(block, _META_INDICATOR)) {
break;
}
if (_GetNextToken<false>(block, token)) {
return 1;
}
std::string t = Utils::ToUpperCase(token);
if (t == "VERSION") {
if (processed[0]) {
return 1;
}
processed[0] = true;
UINT version;
if (_GetNextNumber(block, version)) {
return 1;
}
if (version != 1) {
return 1;
}
desc.version = version;
if (_GetNextToken<false>(block, token) != 2) {
return 1;
}
} else if (t == "OUTPUT_WIDTH") {
if (processed[1]) {
return 1;
}
processed[1] = true;
if (_GetNextExpr(block, desc.outSizeExpr.first)) {
return 1;
}
} else if (t == "OUTPUT_HEIGHT") {
if (processed[2]) {
return 1;
}
processed[2] = true;
if (_GetNextExpr(block, desc.outSizeExpr.second)) {
return 1;
}
} else {
return 1;
}
}
// HEADER 块不含代码部分
if (_GetNextToken<true>(block, token) != 2) {
return 1;
}
if (!processed[0] || (processed[1] ^ processed[2])) {
return 1;
}
return 0;
}
UINT EffectCompiler::_ResolveConstants(std::string_view block, EffectDesc& desc) {
// 可选的选项VALUEDEFAULTLABELMINMAX
// VALUE 与其他选项互斥
std::vector<bool> processed(5, false);
std::string_view token;
if (!_CheckNextToken<true>(block, _META_INDICATOR)) {
return 1;
}
if (!_CheckNextToken<false>(block, "CONSTANT")) {
return 1;
}
if (_GetNextToken<false>(block, token) != 2) {
return 1;
}
EffectConstantDesc desc1{};
EffectValueConstantDesc desc2{};
std::string_view defaultValue;
std::string_view minValue;
std::string_view maxValue;
while (true) {
if (!_CheckNextToken<true>(block, _META_INDICATOR)) {
break;
}
if (_GetNextToken<false>(block, token)) {
return 1;
}
std::string t = Utils::ToUpperCase(token);
if (t == "VALUE") {
for (int i = 0; i < 5; ++i) {
if (processed[i]) {
return 1;
}
}
processed[0] = true;
if (_GetNextExpr(block, desc2.valueExpr)) {
return 1;
}
} else if (t == "DEFAULT") {
if (processed[0] || processed[1]) {
return 1;
}
processed[1] = true;
if (_GetNextString(block, defaultValue)) {
return 1;
}
} else if (t == "LABEL") {
if (processed[0] || processed[2]) {
return 1;
}
processed[2] = true;
std::string_view t;
if (_GetNextString(block, t)) {
return 1;
}
desc1.label = t;
} else if (t == "MIN") {
if (processed[0] || processed[3]) {
return 1;
}
processed[3] = true;
if (_GetNextString(block, minValue)) {
return 1;
}
} else if (t == "MAX") {
if (processed[0] || processed[4]) {
return 1;
}
processed[4] = true;
if (_GetNextString(block, maxValue)) {
return 1;
}
} else {
return 1;
}
}
// 代码部分
if (_GetNextToken<true>(block, token)) {
return 1;
}
if (token == "float") {
if (processed[0]) {
desc2.type = EffectConstantType::Float;
} else {
desc1.type = EffectConstantType::Float;
if (!defaultValue.empty()) {
desc1.defaultValue = 0.0f;
if (_GetNextNumber(defaultValue, std::get<float>(desc1.defaultValue))) {
return 1;
}
}
if (!minValue.empty()) {
float value;
if (_GetNextNumber(minValue, value)) {
return 1;
}
if (!defaultValue.empty() && std::get<float>(desc1.defaultValue) < value) {
return 1;
}
desc1.minValue = value;
}
if (!maxValue.empty()) {
float value;
if (_GetNextNumber(maxValue, value)) {
return 1;
}
if (!defaultValue.empty() && std::get<float>(desc1.defaultValue) > value) {
return 1;
}
if (!minValue.empty() && std::get<float>(desc1.minValue) > value) {
return 1;
}
desc1.maxValue = value;
}
}
} else if (token == "int") {
if (processed[0]) {
desc2.type = EffectConstantType::Int;
} else {
desc1.type = EffectConstantType::Int;
if (!defaultValue.empty()) {
desc1.defaultValue = 0;
if (_GetNextNumber(defaultValue, std::get<int>(desc1.defaultValue))) {
return 1;
}
}
if (!minValue.empty()) {
int value;
if (_GetNextNumber(minValue, value)) {
return 1;
}
if (!defaultValue.empty() && std::get<int>(desc1.defaultValue) < value) {
return 1;
}
desc1.minValue = value;
}
if (!maxValue.empty()) {
int value;
if (_GetNextNumber(maxValue, value)) {
return 1;
}
if (!defaultValue.empty() && std::get<int>(desc1.defaultValue) > value) {
return 1;
}
if (!minValue.empty() && std::get<int>(desc1.minValue) > value) {
return 1;
}
desc1.maxValue = value;
}
}
} else {
return 1;
}
if (_GetNextToken<true>(block, token)) {
return 1;
}
(processed[0] ? desc2.name : desc1.name) = token;
if (!_CheckNextToken<true>(block, ";")) {
return 1;
}
if (_GetNextToken<true>(block, token) != 2) {
return 1;
}
if (processed[0]) {
desc.valueConstants.emplace_back(std::move(desc2));
} else {
desc.constants.emplace_back(std::move(desc1));
}
return 0;
}