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));
|
||||
|
||||
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
|
||||
auto accessMemberIndex = std::make_unique<AccessMemberIndexExpression>();
|
||||
|
|
@ -284,7 +339,7 @@ namespace Nz::ShaderAst
|
|||
if (IsPrimitiveType(rightExprType))
|
||||
{
|
||||
TypeMustMatch(leftType.type, rightExprType);
|
||||
clone->cachedExpressionType = rightExprType;
|
||||
clone->cachedExpressionType = leftExprType;
|
||||
}
|
||||
else if (IsVectorType(rightExprType))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Shader/ShaderLangParser.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Shader/ShaderBuilder.hpp>
|
||||
#include <cassert>
|
||||
#include <Nazara/Shader/Debug.hpp>
|
||||
|
|
@ -696,7 +697,7 @@ namespace Nz::ShaderLang
|
|||
|
||||
ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()
|
||||
{
|
||||
ShaderAst::ExpressionPtr left = ParseIdentifier();
|
||||
ShaderAst::ExpressionPtr left = ParseExpression();
|
||||
Expect(Advance(), TokenType::Assign);
|
||||
|
||||
ShaderAst::ExpressionPtr right = ParseExpression();
|
||||
|
|
@ -740,6 +741,36 @@ namespace Nz::ShaderLang
|
|||
if (tokenPrecedence < exprPrecedence)
|
||||
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();
|
||||
ShaderAst::ExpressionPtr rhs = ParsePrimaryExpression();
|
||||
|
||||
|
|
@ -780,25 +811,8 @@ namespace Nz::ShaderLang
|
|||
{
|
||||
const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
|
||||
const std::string& identifier = std::get<std::string>(identifierToken.data);
|
||||
|
||||
ShaderAst::ExpressionPtr identifierExpr = 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;
|
||||
|
||||
return ShaderBuilder::Identifier(identifier);
|
||||
}
|
||||
|
||||
ShaderAst::ExpressionPtr Parser::ParseIntegerExpression(bool minus)
|
||||
|
|
@ -866,25 +880,7 @@ namespace Nz::ShaderLang
|
|||
}
|
||||
|
||||
if (IsVariableInScope(identifier))
|
||||
{
|
||||
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;
|
||||
}
|
||||
return ParseIdentifier();
|
||||
|
||||
Consume();
|
||||
|
||||
|
|
@ -1001,10 +997,11 @@ namespace Nz::ShaderLang
|
|||
{
|
||||
switch (token)
|
||||
{
|
||||
case TokenType::Plus: return 20;
|
||||
case TokenType::Divide: return 40;
|
||||
case TokenType::Plus: return 20;
|
||||
case TokenType::Divide: 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue