Shader/Parser: Fix handling of . in rvalues + add support for swizzling
For example: var.field was okay but texture.Sample(uv).x wasn't
This commit is contained in:
parent
eb67990b7b
commit
7d4a084a62
|
|
@ -90,6 +90,61 @@ namespace Nz::ShaderAst
|
||||||
auto structExpr = CloneExpression(MandatoryExpr(node.structExpr));
|
auto structExpr = CloneExpression(MandatoryExpr(node.structExpr));
|
||||||
|
|
||||||
const ExpressionType& exprType = GetExpressionType(*structExpr);
|
const ExpressionType& exprType = GetExpressionType(*structExpr);
|
||||||
|
if (IsVectorType(exprType))
|
||||||
|
{
|
||||||
|
const VectorType& swizzledVec = std::get<VectorType>(exprType);
|
||||||
|
|
||||||
|
// Swizzle expression
|
||||||
|
auto swizzle = std::make_unique<SwizzleExpression>();
|
||||||
|
swizzle->expression = std::move(structExpr);
|
||||||
|
|
||||||
|
// FIXME: Handle properly multiple identifiers (treat recursively)
|
||||||
|
if (node.memberIdentifiers.size() != 1)
|
||||||
|
throw AstError{ "invalid swizzle" };
|
||||||
|
|
||||||
|
const std::string& swizzleStr = node.memberIdentifiers.front();
|
||||||
|
if (swizzleStr.empty() || swizzleStr.size() > swizzle->components.size())
|
||||||
|
throw AstError{ "invalid swizzle" };
|
||||||
|
|
||||||
|
swizzle->componentCount = swizzleStr.size();
|
||||||
|
|
||||||
|
if (swizzle->componentCount > 1)
|
||||||
|
swizzle->cachedExpressionType = VectorType{ swizzle->componentCount, swizzledVec.type };
|
||||||
|
else
|
||||||
|
swizzle->cachedExpressionType = swizzledVec.type;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < swizzle->componentCount; ++i)
|
||||||
|
{
|
||||||
|
switch (swizzleStr[i])
|
||||||
|
{
|
||||||
|
case 'r':
|
||||||
|
case 'x':
|
||||||
|
case 's':
|
||||||
|
swizzle->components[i] = SwizzleComponent::First;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'g':
|
||||||
|
case 'y':
|
||||||
|
case 't':
|
||||||
|
swizzle->components[i] = SwizzleComponent::Second;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
case 'z':
|
||||||
|
case 'p':
|
||||||
|
swizzle->components[i] = SwizzleComponent::Third;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
case 'w':
|
||||||
|
case 'q':
|
||||||
|
swizzle->components[i] = SwizzleComponent::Fourth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return swizzle;
|
||||||
|
}
|
||||||
|
|
||||||
// Transform to AccessMemberIndexExpression
|
// Transform to AccessMemberIndexExpression
|
||||||
auto accessMemberIndex = std::make_unique<AccessMemberIndexExpression>();
|
auto accessMemberIndex = std::make_unique<AccessMemberIndexExpression>();
|
||||||
|
|
@ -284,7 +339,7 @@ namespace Nz::ShaderAst
|
||||||
if (IsPrimitiveType(rightExprType))
|
if (IsPrimitiveType(rightExprType))
|
||||||
{
|
{
|
||||||
TypeMustMatch(leftType.type, rightExprType);
|
TypeMustMatch(leftType.type, rightExprType);
|
||||||
clone->cachedExpressionType = rightExprType;
|
clone->cachedExpressionType = leftExprType;
|
||||||
}
|
}
|
||||||
else if (IsVectorType(rightExprType))
|
else if (IsVectorType(rightExprType))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
#include <Nazara/Shader/ShaderLangParser.hpp>
|
#include <Nazara/Shader/ShaderLangParser.hpp>
|
||||||
|
#include <Nazara/Core/File.hpp>
|
||||||
#include <Nazara/Shader/ShaderBuilder.hpp>
|
#include <Nazara/Shader/ShaderBuilder.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <Nazara/Shader/Debug.hpp>
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
|
@ -696,7 +697,7 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()
|
ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()
|
||||||
{
|
{
|
||||||
ShaderAst::ExpressionPtr left = ParseIdentifier();
|
ShaderAst::ExpressionPtr left = ParseExpression();
|
||||||
Expect(Advance(), TokenType::Assign);
|
Expect(Advance(), TokenType::Assign);
|
||||||
|
|
||||||
ShaderAst::ExpressionPtr right = ParseExpression();
|
ShaderAst::ExpressionPtr right = ParseExpression();
|
||||||
|
|
@ -740,6 +741,36 @@ namespace Nz::ShaderLang
|
||||||
if (tokenPrecedence < exprPrecedence)
|
if (tokenPrecedence < exprPrecedence)
|
||||||
return lhs;
|
return lhs;
|
||||||
|
|
||||||
|
if (currentOp.type == TokenType::Dot)
|
||||||
|
{
|
||||||
|
std::unique_ptr<ShaderAst::AccessMemberIdentifierExpression> accessMemberNode = std::make_unique<ShaderAst::AccessMemberIdentifierExpression>();
|
||||||
|
accessMemberNode->structExpr = std::move(lhs);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Consume();
|
||||||
|
|
||||||
|
accessMemberNode->memberIdentifiers.push_back(ParseIdentifierAsName());
|
||||||
|
}
|
||||||
|
while (Peek().type == TokenType::Dot);
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
if (!accessMemberNode->memberIdentifiers.empty() && accessMemberNode->memberIdentifiers.front() == "Sample")
|
||||||
|
{
|
||||||
|
if (Peek().type == TokenType::OpenParenthesis)
|
||||||
|
{
|
||||||
|
auto parameters = ParseParameters();
|
||||||
|
parameters.insert(parameters.begin(), std::move(accessMemberNode->structExpr));
|
||||||
|
|
||||||
|
lhs = ShaderBuilder::Intrinsic(ShaderAst::IntrinsicType::SampleTexture, std::move(parameters));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = std::move(accessMemberNode);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Consume();
|
Consume();
|
||||||
ShaderAst::ExpressionPtr rhs = ParsePrimaryExpression();
|
ShaderAst::ExpressionPtr rhs = ParsePrimaryExpression();
|
||||||
|
|
||||||
|
|
@ -780,25 +811,8 @@ namespace Nz::ShaderLang
|
||||||
{
|
{
|
||||||
const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
|
const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
|
||||||
const std::string& identifier = std::get<std::string>(identifierToken.data);
|
const std::string& identifier = std::get<std::string>(identifierToken.data);
|
||||||
|
|
||||||
ShaderAst::ExpressionPtr identifierExpr = ShaderBuilder::Identifier(identifier);
|
return ShaderBuilder::Identifier(identifier);
|
||||||
|
|
||||||
if (Peek().type == TokenType::Dot)
|
|
||||||
{
|
|
||||||
std::unique_ptr<ShaderAst::AccessMemberIdentifierExpression> accessMemberNode = std::make_unique<ShaderAst::AccessMemberIdentifierExpression>();
|
|
||||||
accessMemberNode->structExpr = std::move(identifierExpr);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Consume();
|
|
||||||
|
|
||||||
accessMemberNode->memberIdentifiers.push_back(ParseIdentifierAsName());
|
|
||||||
} while (Peek().type == TokenType::Dot);
|
|
||||||
|
|
||||||
identifierExpr = std::move(accessMemberNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return identifierExpr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderAst::ExpressionPtr Parser::ParseIntegerExpression(bool minus)
|
ShaderAst::ExpressionPtr Parser::ParseIntegerExpression(bool minus)
|
||||||
|
|
@ -866,25 +880,7 @@ namespace Nz::ShaderLang
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsVariableInScope(identifier))
|
if (IsVariableInScope(identifier))
|
||||||
{
|
return ParseIdentifier();
|
||||||
auto node = ParseIdentifier();
|
|
||||||
if (node->GetType() == ShaderAst::NodeType::AccessMemberIdentifierExpression)
|
|
||||||
{
|
|
||||||
ShaderAst::AccessMemberIdentifierExpression* memberExpr = static_cast<ShaderAst::AccessMemberIdentifierExpression*>(node.get());
|
|
||||||
if (!memberExpr->memberIdentifiers.empty() && memberExpr->memberIdentifiers.front() == "Sample")
|
|
||||||
{
|
|
||||||
if (Peek().type == TokenType::OpenParenthesis)
|
|
||||||
{
|
|
||||||
auto parameters = ParseParameters();
|
|
||||||
parameters.insert(parameters.begin(), std::move(memberExpr->structExpr));
|
|
||||||
|
|
||||||
return ShaderBuilder::Intrinsic(ShaderAst::IntrinsicType::SampleTexture, std::move(parameters));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
Consume();
|
Consume();
|
||||||
|
|
||||||
|
|
@ -1001,10 +997,11 @@ namespace Nz::ShaderLang
|
||||||
{
|
{
|
||||||
switch (token)
|
switch (token)
|
||||||
{
|
{
|
||||||
case TokenType::Plus: return 20;
|
case TokenType::Plus: return 20;
|
||||||
case TokenType::Divide: return 40;
|
case TokenType::Divide: return 40;
|
||||||
case TokenType::Multiply: return 40;
|
case TokenType::Multiply: return 40;
|
||||||
case TokenType::Minus: return 20;
|
case TokenType::Minus: return 20;
|
||||||
|
case TokenType::Dot: return 50;
|
||||||
default: return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue