Close shader authoring usepass regressions
This commit is contained in:
@@ -4,6 +4,47 @@ namespace XCEngine {
|
||||
namespace Resources {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<std::string> NormalizeDirectiveTokens(
|
||||
const std::vector<std::string>& tokens,
|
||||
size_t startIndex) {
|
||||
std::vector<std::string> normalizedTokens;
|
||||
normalizedTokens.reserve(tokens.size() > startIndex ? tokens.size() - startIndex : 0u);
|
||||
for (size_t tokenIndex = startIndex; tokenIndex < tokens.size(); ++tokenIndex) {
|
||||
if (tokens[tokenIndex] == ",") {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string normalizedToken = tokens[tokenIndex];
|
||||
while (!normalizedToken.empty() && normalizedToken.back() == ',') {
|
||||
normalizedToken.pop_back();
|
||||
}
|
||||
|
||||
if (!normalizedToken.empty()) {
|
||||
normalizedTokens.push_back(std::move(normalizedToken));
|
||||
}
|
||||
}
|
||||
|
||||
return normalizedTokens;
|
||||
}
|
||||
|
||||
bool TryParseUInt8Value(const std::string& token, Core::uint8& outValue) {
|
||||
try {
|
||||
const unsigned long value = std::stoul(token, nullptr, 0);
|
||||
if (value > 0xFFul) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outValue = static_cast<Core::uint8>(value);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MaterialRenderState BuildDefaultAuthoringFixedFunctionState() {
|
||||
MaterialRenderState state = {};
|
||||
state.blendEnable = false;
|
||||
@@ -146,6 +187,68 @@ bool TryParseAuthoringBlendFactor(const std::string& token, MaterialBlendFactor&
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryParseAuthoringBlendOp(const std::string& token, MaterialBlendOp& outOp) {
|
||||
const Containers::String normalized = Containers::String(token.c_str()).Trim().ToLower();
|
||||
if (normalized == "add") {
|
||||
outOp = MaterialBlendOp::Add;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "sub" || normalized == "subtract") {
|
||||
outOp = MaterialBlendOp::Subtract;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "revsub" || normalized == "reverse_subtract" || normalized == "reversesubtract") {
|
||||
outOp = MaterialBlendOp::ReverseSubtract;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "min") {
|
||||
outOp = MaterialBlendOp::Min;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "max") {
|
||||
outOp = MaterialBlendOp::Max;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryParseAuthoringStencilOp(const std::string& token, MaterialStencilOp& outOp) {
|
||||
const Containers::String normalized = Containers::String(token.c_str()).Trim().ToLower();
|
||||
if (normalized == "keep") {
|
||||
outOp = MaterialStencilOp::Keep;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "zero") {
|
||||
outOp = MaterialStencilOp::Zero;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "replace") {
|
||||
outOp = MaterialStencilOp::Replace;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "incrsat" || normalized == "incr_sat") {
|
||||
outOp = MaterialStencilOp::IncrSat;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "decrsat" || normalized == "decr_sat") {
|
||||
outOp = MaterialStencilOp::DecrSat;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "invert") {
|
||||
outOp = MaterialStencilOp::Invert;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "incrwrap" || normalized == "incr_wrap" || normalized == "incr") {
|
||||
outOp = MaterialStencilOp::IncrWrap;
|
||||
return true;
|
||||
}
|
||||
if (normalized == "decrwrap" || normalized == "decr_wrap" || normalized == "decr") {
|
||||
outOp = MaterialStencilOp::DecrWrap;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryParseAuthoringColorMask(const std::string& token, Core::uint8& outMask) {
|
||||
const Containers::String normalized = Containers::String(token.c_str()).Trim().ToUpper();
|
||||
if (normalized == "0") {
|
||||
@@ -180,21 +283,7 @@ bool TryParseAuthoringColorMask(const std::string& token, Core::uint8& outMask)
|
||||
bool TryParseAuthoringBlendDirective(
|
||||
const std::vector<std::string>& tokens,
|
||||
MaterialRenderState& outState) {
|
||||
std::vector<std::string> normalizedTokens;
|
||||
normalizedTokens.reserve(tokens.size());
|
||||
for (const std::string& token : tokens) {
|
||||
if (token == ",") {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string normalizedToken = token;
|
||||
while (!normalizedToken.empty() && normalizedToken.back() == ',') {
|
||||
normalizedToken.pop_back();
|
||||
}
|
||||
if (!normalizedToken.empty()) {
|
||||
normalizedTokens.push_back(std::move(normalizedToken));
|
||||
}
|
||||
}
|
||||
const std::vector<std::string> normalizedTokens = NormalizeDirectiveTokens(tokens, 0u);
|
||||
|
||||
if (normalizedTokens.size() != 2u &&
|
||||
normalizedTokens.size() != 3u &&
|
||||
@@ -242,6 +331,169 @@ bool TryParseAuthoringBlendDirective(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryParseAuthoringBlendOpDirective(
|
||||
const std::vector<std::string>& tokens,
|
||||
MaterialRenderState& outState) {
|
||||
const std::vector<std::string> normalizedTokens = NormalizeDirectiveTokens(tokens, 1u);
|
||||
if (normalizedTokens.size() != 1u && normalizedTokens.size() != 2u) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryParseAuthoringBlendOp(normalizedTokens[0], outState.blendOp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (normalizedTokens.size() == 2u) {
|
||||
return TryParseAuthoringBlendOp(normalizedTokens[1], outState.blendOpAlpha);
|
||||
}
|
||||
|
||||
outState.blendOpAlpha = outState.blendOp;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryParseAuthoringOffsetDirective(
|
||||
const std::vector<std::string>& tokens,
|
||||
MaterialRenderState& outState) {
|
||||
const std::vector<std::string> normalizedTokens = NormalizeDirectiveTokens(tokens, 1u);
|
||||
if (normalizedTokens.size() != 2u) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
outState.depthBiasFactor = std::stof(normalizedTokens[0]);
|
||||
outState.depthBiasUnits = static_cast<Core::int32>(std::stol(normalizedTokens[1]));
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TryParseAuthoringStencilDirective(
|
||||
const std::vector<std::string>& tokens,
|
||||
MaterialStencilState& outState) {
|
||||
if (tokens.size() != 2u && tokens.size() != 3u) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Containers::String directive = Containers::String(tokens[0].c_str()).Trim().ToLower();
|
||||
if (directive == "ref") {
|
||||
Core::uint8 reference = 0;
|
||||
if (!TryParseUInt8Value(tokens[1], reference)) {
|
||||
return false;
|
||||
}
|
||||
outState.reference = reference;
|
||||
outState.enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (directive == "readmask") {
|
||||
Core::uint8 readMask = 0;
|
||||
if (!TryParseUInt8Value(tokens[1], readMask)) {
|
||||
return false;
|
||||
}
|
||||
outState.readMask = readMask;
|
||||
outState.enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (directive == "writemask") {
|
||||
Core::uint8 writeMask = 0;
|
||||
if (!TryParseUInt8Value(tokens[1], writeMask)) {
|
||||
return false;
|
||||
}
|
||||
outState.writeMask = writeMask;
|
||||
outState.enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto applyComparison = [&](MaterialStencilFaceState& faceState) -> bool {
|
||||
return TryParseAuthoringComparisonFunc(tokens[1], faceState.func);
|
||||
};
|
||||
auto applyOperation = [&](MaterialStencilFaceState& faceState, MaterialStencilOp MaterialStencilFaceState::* member) -> bool {
|
||||
MaterialStencilOp op = MaterialStencilOp::Keep;
|
||||
if (!TryParseAuthoringStencilOp(tokens[1], op)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
faceState.*member = op;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (directive == "comp") {
|
||||
outState.enabled = true;
|
||||
return applyComparison(outState.front) && applyComparison(outState.back);
|
||||
}
|
||||
if (directive == "pass") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.front, &MaterialStencilFaceState::passOp) &&
|
||||
applyOperation(outState.back, &MaterialStencilFaceState::passOp);
|
||||
}
|
||||
if (directive == "fail") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.front, &MaterialStencilFaceState::failOp) &&
|
||||
applyOperation(outState.back, &MaterialStencilFaceState::failOp);
|
||||
}
|
||||
if (directive == "zfail") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.front, &MaterialStencilFaceState::depthFailOp) &&
|
||||
applyOperation(outState.back, &MaterialStencilFaceState::depthFailOp);
|
||||
}
|
||||
if (directive == "compfront") {
|
||||
outState.enabled = true;
|
||||
return applyComparison(outState.front);
|
||||
}
|
||||
if (directive == "passfront") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.front, &MaterialStencilFaceState::passOp);
|
||||
}
|
||||
if (directive == "failfront") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.front, &MaterialStencilFaceState::failOp);
|
||||
}
|
||||
if (directive == "zfailfront") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.front, &MaterialStencilFaceState::depthFailOp);
|
||||
}
|
||||
if (directive == "compback") {
|
||||
outState.enabled = true;
|
||||
return applyComparison(outState.back);
|
||||
}
|
||||
if (directive == "passback") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.back, &MaterialStencilFaceState::passOp);
|
||||
}
|
||||
if (directive == "failback") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.back, &MaterialStencilFaceState::failOp);
|
||||
}
|
||||
if (directive == "zfailback") {
|
||||
outState.enabled = true;
|
||||
return applyOperation(outState.back, &MaterialStencilFaceState::depthFailOp);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryParseAuthoringUsePassReference(
|
||||
const Containers::String& reference,
|
||||
Containers::String& outShaderName,
|
||||
Containers::String& outPassName) {
|
||||
outShaderName.Clear();
|
||||
outPassName.Clear();
|
||||
|
||||
const std::string referenceText = reference.Trim().CStr();
|
||||
const size_t slashPos = referenceText.rfind('/');
|
||||
if (slashPos == std::string::npos ||
|
||||
slashPos == 0u ||
|
||||
slashPos + 1u >= referenceText.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outShaderName = Containers::String(referenceText.substr(0, slashPos).c_str());
|
||||
outPassName = Containers::String(referenceText.substr(slashPos + 1u).c_str());
|
||||
return !outShaderName.Empty() && !outPassName.Empty();
|
||||
}
|
||||
|
||||
void SetOrReplaceAuthoringTag(
|
||||
std::vector<ShaderTagIR>& tags,
|
||||
const Containers::String& name,
|
||||
|
||||
Reference in New Issue
Block a user