diff --git a/bin/resources/bloom_bright.nzsl b/bin/resources/bloom_bright.nzsl index 3aa31d795..ad9c608c6 100644 --- a/bin/resources/bloom_bright.nzsl +++ b/bin/resources/bloom_bright.nzsl @@ -48,10 +48,10 @@ fn main(input: FragIn) -> FragOut let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize * 10.0; let color = colorTexture.Sample(fragcoord).rgb; - color = color * (BrightMiddleGrey/BrightLuminance); - color = color * (vec3(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold))); - color = color - vec3(0.5, 0.5, 0.5); - color = color / (vec3(1.0, 1.0, 1.0) + color); + color *= BrightMiddleGrey / BrightLuminance; + color *= vec3(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold)); + color -= vec3(0.5, 0.5, 0.5); + color /= vec3(1.0, 1.0, 1.0) + color; let output: FragOut; output.color = vec4(color, 1.0); diff --git a/bin/resources/deferred_frag.nzsl b/bin/resources/deferred_frag.nzsl index 731e77541..0727b6e2a 100644 --- a/bin/resources/deferred_frag.nzsl +++ b/bin/resources/deferred_frag.nzsl @@ -58,8 +58,7 @@ fn main(input: InputData) -> OutputData { let diffuseColor = settings.DiffuseColor; const if (HasDiffuseTexture) - // TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv) - diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv); + diffuseColor *= MaterialDiffuseMap.Sample(input.uv); const if (HasAlphaTexture) // TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x diff --git a/bin/resources/gaussian_blur.nzsl b/bin/resources/gaussian_blur.nzsl index 2a8221d9b..209308710 100644 --- a/bin/resources/gaussian_blur.nzsl +++ b/bin/resources/gaussian_blur.nzsl @@ -48,19 +48,19 @@ fn main(input: FragIn) -> FragOut let filter = vec2(1.0, 0.0); - color = color + colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; - color = color + colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; + color += colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; + color += colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; - color = color + colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; - color = color + colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; + color += colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; + color += colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; filter = vec2(0.0, 1.0); - color = color + colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; - color = color + colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; + color += colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; + color += colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162; - color = color + colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; - color = color + colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; + color += colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; + color += colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703; let output: FragOut; output.color = vec4(color, 1.0); diff --git a/include/Nazara/Shader/Ast/Enums.hpp b/include/Nazara/Shader/Ast/Enums.hpp index f87e8fc19..5ed23a1fe 100644 --- a/include/Nazara/Shader/Ast/Enums.hpp +++ b/include/Nazara/Shader/Ast/Enums.hpp @@ -16,7 +16,13 @@ namespace Nz { enum class AssignType { - Simple //< = + Simple, //< a = b + CompoundAdd, //< a += b + CompoundDivide, //< a /= b + CompoundMultiply, //< a *= b + CompoundLogicalAnd, //< a &&= b + CompoundLogicalOr, //< a ||= b + CompoundSubtract, //< a -= b }; enum class AttributeType diff --git a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp index e5fef4155..73348c894 100644 --- a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp +++ b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp @@ -38,6 +38,7 @@ namespace Nz::ShaderAst std::unordered_set reservedIdentifiers; std::unordered_map optionValues; bool makeVariableNameUnique = false; + bool removeCompoundAssignments = false; bool removeOptionDeclaration = true; }; @@ -76,9 +77,9 @@ namespace Nz::ShaderAst const Identifier* FindIdentifier(const std::string_view& identifierName) const; - Expression& MandatoryExpr(ExpressionPtr& node); - Statement& MandatoryStatement(StatementPtr& node); - void TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right); + Expression& MandatoryExpr(const ExpressionPtr& node); + Statement& MandatoryStatement(const StatementPtr& node); + void TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right); void TypeMustMatch(const ExpressionType& left, const ExpressionType& right); void PushScope(); @@ -111,6 +112,7 @@ namespace Nz::ShaderAst void Validate(AccessIndexExpression& node); void Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration); void Validate(IntrinsicExpression& node); + ExpressionType ValidateBinaryOp(BinaryType op, const ExpressionPtr& leftExpr, const ExpressionPtr& rightExpr); struct FunctionData { diff --git a/include/Nazara/Shader/ShaderLangTokenList.hpp b/include/Nazara/Shader/ShaderLangTokenList.hpp index 05d60d111..3e00e114b 100644 --- a/include/Nazara/Shader/ShaderLangTokenList.hpp +++ b/include/Nazara/Shader/ShaderLangTokenList.hpp @@ -22,6 +22,7 @@ NAZARA_SHADERLANG_TOKEN(Const) NAZARA_SHADERLANG_TOKEN(ConstSelect) NAZARA_SHADERLANG_TOKEN(Discard) NAZARA_SHADERLANG_TOKEN(Divide) +NAZARA_SHADERLANG_TOKEN(DivideAssign) NAZARA_SHADERLANG_TOKEN(Dot) NAZARA_SHADERLANG_TOKEN(Equal) NAZARA_SHADERLANG_TOKEN(Else) @@ -39,12 +40,17 @@ NAZARA_SHADERLANG_TOKEN(LessThan) NAZARA_SHADERLANG_TOKEN(LessThanEqual) NAZARA_SHADERLANG_TOKEN(Let) NAZARA_SHADERLANG_TOKEN(LogicalAnd) +NAZARA_SHADERLANG_TOKEN(LogicalAndAssign) NAZARA_SHADERLANG_TOKEN(LogicalOr) +NAZARA_SHADERLANG_TOKEN(LogicalOrAssign) NAZARA_SHADERLANG_TOKEN(Multiply) +NAZARA_SHADERLANG_TOKEN(MultiplyAssign) NAZARA_SHADERLANG_TOKEN(Minus) +NAZARA_SHADERLANG_TOKEN(MinusAssign) NAZARA_SHADERLANG_TOKEN(Not) NAZARA_SHADERLANG_TOKEN(NotEqual) NAZARA_SHADERLANG_TOKEN(Plus) +NAZARA_SHADERLANG_TOKEN(PlusAssign) NAZARA_SHADERLANG_TOKEN(OpenCurlyBracket) NAZARA_SHADERLANG_TOKEN(OpenSquareBracket) NAZARA_SHADERLANG_TOKEN(OpenParenthesis) diff --git a/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl index 3b98f55fc..7495f75d7 100644 --- a/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl @@ -66,16 +66,13 @@ fn main(input: FragIn) -> FragOut let diffuseColor = settings.DiffuseColor; const if (HasUV) - //TODO: diffuseColor *= TextureOverlay.Sample(input.uv); - diffuseColor = diffuseColor * TextureOverlay.Sample(input.uv); + diffuseColor *= TextureOverlay.Sample(input.uv); const if (HasVertexColor) - //TODO: diffuseColor *= input.color; - diffuseColor = diffuseColor * input.color; + diffuseColor *= input.color; const if (HasDiffuseTexture) - // TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv) - diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv); + diffuseColor *= MaterialDiffuseMap.Sample(input.uv); const if (HasAlphaTexture) // TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x diff --git a/src/Nazara/Graphics/Resources/Shaders/depth_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/depth_material.nzsl index 9bfdc1ae8..779354a02 100644 --- a/src/Nazara/Graphics/Resources/Shaders/depth_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/depth_material.nzsl @@ -54,16 +54,13 @@ fn main(input: FragIn) let alpha = settings.DiffuseColor.a; const if (HasUV) - //TODO: diffuseColor *= TextureOverlay.Sample(input.uv); - alpha = alpha * TextureOverlay.Sample(input.uv).a; + alpha *= TextureOverlay.Sample(input.uv).a; const if (HasDiffuseTexture) - // TODO: alpha *= MaterialDiffuseMap.Sample(input.uv).a; - alpha = alpha * MaterialDiffuseMap.Sample(input.uv).a; + alpha *= MaterialDiffuseMap.Sample(input.uv).a; const if (HasAlphaTexture) - // TODO: alpha *= MaterialAlphaMap.Sample(input.uv).x - alpha = alpha * MaterialAlphaMap.Sample(input.uv).x; + alpha *= MaterialAlphaMap.Sample(input.uv).x; if (alpha < settings.AlphaThreshold) discard; diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp index 279a2c800..4d9894167 100644 --- a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -253,8 +253,35 @@ namespace Nz::ShaderAst auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); - TypeMustMatch(clone->left, clone->right); - clone->cachedExpressionType = GetExpressionType(*clone->right); + std::optional binaryType; + switch (clone->op) + { + case AssignType::Simple: + TypeMustMatch(clone->left, clone->right); + break; + + case AssignType::CompoundAdd: binaryType = BinaryType::Add; break; + case AssignType::CompoundDivide: binaryType = BinaryType::Divide; break; + case AssignType::CompoundMultiply: binaryType = BinaryType::Multiply; break; + case AssignType::CompoundLogicalAnd: binaryType = BinaryType::LogicalAnd; break; + case AssignType::CompoundLogicalOr: binaryType = BinaryType::LogicalOr; break; + case AssignType::CompoundSubtract: binaryType = BinaryType::Subtract; break; + } + + if (binaryType) + { + ExpressionType expressionType = ValidateBinaryOp(*binaryType, clone->left, clone->right); + TypeMustMatch(GetExpressionType(*clone->left), expressionType); + + if (m_context->options.removeCompoundAssignments) + { + clone->op = AssignType::Simple; + clone->right = ShaderBuilder::Binary(*binaryType, AstCloner::Clone(*clone->left), std::move(clone->right)); + clone->right->cachedExpressionType = std::move(expressionType); + } + } + + clone->cachedExpressionType = GetExpressionType(*clone->left); return clone; } @@ -262,191 +289,7 @@ namespace Nz::ShaderAst ExpressionPtr SanitizeVisitor::Clone(BinaryExpression& node) { auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); - - const ExpressionType& leftExprType = GetExpressionType(MandatoryExpr(clone->left)); - if (!IsPrimitiveType(leftExprType) && !IsMatrixType(leftExprType) && !IsVectorType(leftExprType)) - throw AstError{ "left expression type does not support binary operation" }; - - const ExpressionType& rightExprType = GetExpressionType(MandatoryExpr(clone->right)); - if (!IsPrimitiveType(rightExprType) && !IsMatrixType(rightExprType) && !IsVectorType(rightExprType)) - throw AstError{ "right expression type does not support binary operation" }; - - if (IsPrimitiveType(leftExprType)) - { - PrimitiveType leftType = std::get(leftExprType); - switch (clone->op) - { - case BinaryType::CompGe: - case BinaryType::CompGt: - case BinaryType::CompLe: - case BinaryType::CompLt: - if (leftType == PrimitiveType::Boolean) - throw AstError{ "this operation is not supported for booleans" }; - - TypeMustMatch(clone->left, clone->right); - - clone->cachedExpressionType = PrimitiveType::Boolean; - break; - - case BinaryType::Add: - case BinaryType::CompEq: - case BinaryType::CompNe: - case BinaryType::Subtract: - TypeMustMatch(clone->left, clone->right); - - clone->cachedExpressionType = leftExprType; - break; - - case BinaryType::Multiply: - case BinaryType::Divide: - { - switch (leftType) - { - case PrimitiveType::Float32: - case PrimitiveType::Int32: - case PrimitiveType::UInt32: - { - if (IsMatrixType(rightExprType)) - { - TypeMustMatch(leftType, std::get(rightExprType).type); - clone->cachedExpressionType = rightExprType; - } - else if (IsPrimitiveType(rightExprType)) - { - TypeMustMatch(leftType, rightExprType); - clone->cachedExpressionType = leftExprType; - } - else if (IsVectorType(rightExprType)) - { - TypeMustMatch(leftType, std::get(rightExprType).type); - clone->cachedExpressionType = rightExprType; - } - else - throw AstError{ "incompatible types" }; - - break; - } - - case PrimitiveType::Boolean: - throw AstError{ "this operation is not supported for booleans" }; - - default: - throw AstError{ "incompatible types" }; - } - break; - } - - case BinaryType::LogicalAnd: - case BinaryType::LogicalOr: - if (leftType != PrimitiveType::Boolean) - throw AstError{ "logical and/or are only supported on booleans" }; - - TypeMustMatch(clone->left, clone->right); - - clone->cachedExpressionType = PrimitiveType::Boolean; - break; - } - } - else if (IsMatrixType(leftExprType)) - { - const MatrixType& leftType = std::get(leftExprType); - switch (clone->op) - { - case BinaryType::CompGe: - case BinaryType::CompGt: - case BinaryType::CompLe: - case BinaryType::CompLt: - case BinaryType::CompEq: - case BinaryType::CompNe: - TypeMustMatch(clone->left, clone->right); - clone->cachedExpressionType = PrimitiveType::Boolean; - break; - - case BinaryType::Add: - case BinaryType::Subtract: - TypeMustMatch(clone->left, clone->right); - clone->cachedExpressionType = leftExprType; - break; - - case BinaryType::Multiply: - case BinaryType::Divide: - { - if (IsMatrixType(rightExprType)) - { - TypeMustMatch(leftExprType, rightExprType); - clone->cachedExpressionType = leftExprType; //< FIXME - } - else if (IsPrimitiveType(rightExprType)) - { - TypeMustMatch(leftType.type, rightExprType); - clone->cachedExpressionType = leftExprType; - } - else if (IsVectorType(rightExprType)) - { - const VectorType& rightType = std::get(rightExprType); - TypeMustMatch(leftType.type, rightType.type); - - if (leftType.columnCount != rightType.componentCount) - throw AstError{ "incompatible types" }; - - clone->cachedExpressionType = rightExprType; - } - else - throw AstError{ "incompatible types" }; - - break; - } - - case BinaryType::LogicalAnd: - case BinaryType::LogicalOr: - throw AstError{ "logical and/or are only supported on booleans" }; - } - } - else if (IsVectorType(leftExprType)) - { - const VectorType& leftType = std::get(leftExprType); - switch (clone->op) - { - case BinaryType::CompGe: - case BinaryType::CompGt: - case BinaryType::CompLe: - case BinaryType::CompLt: - case BinaryType::CompEq: - case BinaryType::CompNe: - TypeMustMatch(clone->left, clone->right); - clone->cachedExpressionType = PrimitiveType::Boolean; - break; - - case BinaryType::Add: - case BinaryType::Subtract: - TypeMustMatch(clone->left, clone->right); - clone->cachedExpressionType = leftExprType; - break; - - case BinaryType::Multiply: - case BinaryType::Divide: - { - if (IsPrimitiveType(rightExprType)) - { - TypeMustMatch(leftType.type, rightExprType); - clone->cachedExpressionType = leftExprType; - } - else if (IsVectorType(rightExprType)) - { - TypeMustMatch(leftType, rightExprType); - clone->cachedExpressionType = rightExprType; - } - else - throw AstError{ "incompatible types" }; - - break; - } - - case BinaryType::LogicalAnd: - case BinaryType::LogicalOr: - throw AstError{ "logical and/or are only supported on booleans" }; - } - } + clone->cachedExpressionType = ValidateBinaryOp(clone->op, clone->left, clone->right); return clone; } @@ -1116,7 +959,7 @@ namespace Nz::ShaderAst return &*it; } - Expression& SanitizeVisitor::MandatoryExpr(ExpressionPtr& node) + Expression& SanitizeVisitor::MandatoryExpr(const ExpressionPtr& node) { if (!node) throw AstError{ "Invalid expression" }; @@ -1124,7 +967,7 @@ namespace Nz::ShaderAst return *node; } - Statement& SanitizeVisitor::MandatoryStatement(StatementPtr& node) + Statement& SanitizeVisitor::MandatoryStatement(const StatementPtr& node) { if (!node) throw AstError{ "Invalid statement" }; @@ -1640,7 +1483,189 @@ namespace Nz::ShaderAst } } - void SanitizeVisitor::TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right) + ExpressionType SanitizeVisitor::ValidateBinaryOp(BinaryType op, const ExpressionPtr& leftExpr, const ExpressionPtr& rightExpr) + { + const ExpressionType& leftExprType = GetExpressionType(MandatoryExpr(leftExpr)); + const ExpressionType& rightExprType = GetExpressionType(MandatoryExpr(rightExpr)); + + if (!IsPrimitiveType(leftExprType) && !IsMatrixType(leftExprType) && !IsVectorType(leftExprType)) + throw AstError{ "left expression type does not support binary operation" }; + + if (!IsPrimitiveType(rightExprType) && !IsMatrixType(rightExprType) && !IsVectorType(rightExprType)) + throw AstError{ "right expression type does not support binary operation" }; + + if (IsPrimitiveType(leftExprType)) + { + PrimitiveType leftType = std::get(leftExprType); + switch (op) + { + case BinaryType::CompGe: + case BinaryType::CompGt: + case BinaryType::CompLe: + case BinaryType::CompLt: + { + if (leftType == PrimitiveType::Boolean) + throw AstError{ "this operation is not supported for booleans" }; + + TypeMustMatch(leftExpr, rightExpr); + return PrimitiveType::Boolean; + } + + case BinaryType::Add: + case BinaryType::CompEq: + case BinaryType::CompNe: + case BinaryType::Subtract: + TypeMustMatch(leftExpr, rightExpr); + return leftExprType; + + case BinaryType::Multiply: + case BinaryType::Divide: + { + switch (leftType) + { + case PrimitiveType::Float32: + case PrimitiveType::Int32: + case PrimitiveType::UInt32: + { + if (IsMatrixType(rightExprType)) + { + TypeMustMatch(leftType, std::get(rightExprType).type); + return rightExprType; + } + else if (IsPrimitiveType(rightExprType)) + { + TypeMustMatch(leftType, rightExprType); + return leftExprType; + } + else if (IsVectorType(rightExprType)) + { + TypeMustMatch(leftType, std::get(rightExprType).type); + return rightExprType; + } + else + throw AstError{ "incompatible types" }; + + break; + } + + case PrimitiveType::Boolean: + throw AstError{ "this operation is not supported for booleans" }; + + default: + throw AstError{ "incompatible types" }; + } + } + + case BinaryType::LogicalAnd: + case BinaryType::LogicalOr: + { + if (leftType != PrimitiveType::Boolean) + throw AstError{ "logical and/or are only supported on booleans" }; + + TypeMustMatch(leftExpr, rightExpr); + return PrimitiveType::Boolean; + } + } + } + else if (IsMatrixType(leftExprType)) + { + const MatrixType& leftType = std::get(leftExprType); + switch (op) + { + case BinaryType::CompGe: + case BinaryType::CompGt: + case BinaryType::CompLe: + case BinaryType::CompLt: + case BinaryType::CompEq: + case BinaryType::CompNe: + TypeMustMatch(leftExpr, rightExpr); + return PrimitiveType::Boolean; + + case BinaryType::Add: + case BinaryType::Subtract: + TypeMustMatch(leftExpr, rightExpr); + return leftExprType; + + case BinaryType::Multiply: + case BinaryType::Divide: + { + if (IsMatrixType(rightExprType)) + { + TypeMustMatch(leftExprType, rightExprType); + return leftExprType; //< FIXME + } + else if (IsPrimitiveType(rightExprType)) + { + TypeMustMatch(leftType.type, rightExprType); + return leftExprType; + } + else if (IsVectorType(rightExprType)) + { + const VectorType& rightType = std::get(rightExprType); + TypeMustMatch(leftType.type, rightType.type); + + if (leftType.columnCount != rightType.componentCount) + throw AstError{ "incompatible types" }; + + return rightExprType; + } + else + throw AstError{ "incompatible types" }; + } + + case BinaryType::LogicalAnd: + case BinaryType::LogicalOr: + throw AstError{ "logical and/or are only supported on booleans" }; + } + } + else if (IsVectorType(leftExprType)) + { + const VectorType& leftType = std::get(leftExprType); + switch (op) + { + case BinaryType::CompGe: + case BinaryType::CompGt: + case BinaryType::CompLe: + case BinaryType::CompLt: + case BinaryType::CompEq: + case BinaryType::CompNe: + TypeMustMatch(leftExpr, rightExpr); + return PrimitiveType::Boolean; + + case BinaryType::Add: + case BinaryType::Subtract: + TypeMustMatch(leftExpr, rightExpr); + return leftExprType; + + case BinaryType::Multiply: + case BinaryType::Divide: + { + if (IsPrimitiveType(rightExprType)) + { + TypeMustMatch(leftType.type, rightExprType); + return leftExprType; + } + else if (IsVectorType(rightExprType)) + { + TypeMustMatch(leftType, rightExprType); + return rightExprType; + } + else + throw AstError{ "incompatible types" }; + + break; + } + + case BinaryType::LogicalAnd: + case BinaryType::LogicalOr: + throw AstError{ "logical and/or are only supported on booleans" }; + } + } + + throw AstError{ "internal error: unchecked operation" }; + } + + void SanitizeVisitor::TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right) { return TypeMustMatch(GetExpressionType(*left), GetExpressionType(*right)); } diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index 686ac84dd..3fee820e6 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -207,6 +207,7 @@ namespace Nz ShaderAst::SanitizeVisitor::Options options; options.optionValues = std::move(optionValues); options.makeVariableNameUnique = true; + options.removeCompoundAssignments = false; options.reservedIdentifiers = { // All reserved GLSL keywords as of GLSL ES 3.2 "active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer", "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float", "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray", "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube", "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect", "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant", "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect", "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "isubpassInput", "isubpassInputMS", "itexture2D", "itexture2DArray", "itexture2DMS", "itexture2DMSArray", "itexture3D", "itextureBuffer", "itextureCube", "itextureCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump", "namespace", "noinline", "noperspective", "out", "output", "partition", "patch", "precise", "precision", "public", "readonly", "resource", "restrict", "return", "sample", "sampler", "sampler1D", "sampler1DArray", "sampler1DArrayShadow", "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray", "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer", "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "samplerShadow", "shared", "short", "sizeof", "smooth", "static", "struct", "subpassInput", "subpassInputMS", "subroutine", "superp", "switch", "template", "texture2D", "texture2DArray", "texture2DMS", "texture2DMSArray", "texture3D", "textureBuffer", "textureCube", "textureCubeArray", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray", "using", "usubpassInput", "usubpassInputMS", "utexture2D", "utexture2DArray", "utexture2DMS", "utexture2DMSArray", "utexture3D", "utextureBuffer", "utextureCube", "utextureCubeArray", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile", "while", "writeonly" @@ -725,9 +726,13 @@ namespace Nz switch (node.op) { - case ShaderAst::AssignType::Simple: - Append(" = "); - break; + case ShaderAst::AssignType::Simple: Append(" = "); break; + case ShaderAst::AssignType::CompoundAdd: Append(" += "); break; + case ShaderAst::AssignType::CompoundDivide: Append(" /= "); break; + case ShaderAst::AssignType::CompoundMultiply: Append(" *= "); break; + case ShaderAst::AssignType::CompoundLogicalAnd: Append(" &&= "); break; + case ShaderAst::AssignType::CompoundLogicalOr: Append(" ||= "); break; + case ShaderAst::AssignType::CompoundSubtract: Append(" -= "); break; } node.right->Visit(*this); diff --git a/src/Nazara/Shader/LangWriter.cpp b/src/Nazara/Shader/LangWriter.cpp index 64f6813d7..1657568d1 100644 --- a/src/Nazara/Shader/LangWriter.cpp +++ b/src/Nazara/Shader/LangWriter.cpp @@ -541,9 +541,13 @@ namespace Nz switch (node.op) { - case ShaderAst::AssignType::Simple: - Append(" = "); - break; + case ShaderAst::AssignType::Simple: Append(" = "); break; + case ShaderAst::AssignType::CompoundAdd: Append(" += "); break; + case ShaderAst::AssignType::CompoundDivide: Append(" /= "); break; + case ShaderAst::AssignType::CompoundMultiply: Append(" *= "); break; + case ShaderAst::AssignType::CompoundLogicalAnd: Append(" &&= "); break; + case ShaderAst::AssignType::CompoundLogicalOr: Append(" ||= "); break; + case ShaderAst::AssignType::CompoundSubtract: Append(" -= "); break; } node.right->Visit(*this); diff --git a/src/Nazara/Shader/ShaderLangLexer.cpp b/src/Nazara/Shader/ShaderLangLexer.cpp index 875a0e946..0b886b7d5 100644 --- a/src/Nazara/Shader/ShaderLangLexer.cpp +++ b/src/Nazara/Shader/ShaderLangLexer.cpp @@ -106,14 +106,21 @@ namespace Nz::ShaderLang case '-': { - if (Peek() == '>') + char next = Peek(); + if (next == '>') { currentPos++; tokenType = TokenType::FunctionReturn; break; } + else if (next == '=') + { + currentPos++; + tokenType = TokenType::MinusAssign; + } + else + tokenType = TokenType::Minus; - tokenType = TokenType::Minus; break; } @@ -155,6 +162,11 @@ namespace Nz::ShaderLang } while (next != -1); } + else if (next == '=') + { + currentPos++; + tokenType = TokenType::DivideAssign; + } else tokenType = TokenType::Divide; @@ -253,7 +265,14 @@ namespace Nz::ShaderLang if (next == '|') { currentPos++; - tokenType = TokenType::LogicalOr; + next = Peek(); + if (next == '=') + { + currentPos++; + tokenType = TokenType::LogicalOrAssign; + } + else + tokenType = TokenType::LogicalOr; } else throw UnrecognizedToken{}; //< TODO: Add BOR (a | b) @@ -267,7 +286,14 @@ namespace Nz::ShaderLang if (next == '&') { currentPos++; - tokenType = TokenType::LogicalAnd; + next = Peek(); + if (next == '=') + { + currentPos++; + tokenType = TokenType::LogicalAndAssign; + } + else + tokenType = TokenType::LogicalAnd; } else throw UnrecognizedToken{}; //< TODO: Add BAND (a & b) @@ -317,9 +343,34 @@ namespace Nz::ShaderLang break; } + case '+': + { + char next = Peek(); + if (next == '=') + { + currentPos++; + tokenType = TokenType::PlusAssign; + } + else + tokenType = TokenType::Plus; + + break; + } + + case '*': + { + char next = Peek(); + if (next == '=') + { + currentPos++; + tokenType = TokenType::MultiplyAssign; + } + else + tokenType = TokenType::Multiply; + + break; + } - case '+': tokenType = TokenType::Plus; break; - case '*': tokenType = TokenType::Multiply; break; case ':': tokenType = TokenType::Colon; break; case ';': tokenType = TokenType::Semicolon; break; case '.': tokenType = TokenType::Dot; break; diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp index 69afd058c..d9753cffa 100644 --- a/src/Nazara/Shader/ShaderLangParser.cpp +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -860,12 +860,32 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr Parser::ParseVariableAssignation() { + // Variable expression ShaderAst::ExpressionPtr left = ParseExpression(); - Expect(Advance(), TokenType::Assign); + // Assignation type + ShaderAst::AssignType assignType; + + switch (Peek().type) + { + case TokenType::Assign: assignType = ShaderAst::AssignType::Simple; break; + case TokenType::DivideAssign: assignType = ShaderAst::AssignType::CompoundDivide; break; + case TokenType::LogicalAndAssign: assignType = ShaderAst::AssignType::CompoundLogicalAnd; break; + case TokenType::LogicalOrAssign: assignType = ShaderAst::AssignType::CompoundLogicalOr; break; + case TokenType::MultiplyAssign: assignType = ShaderAst::AssignType::CompoundMultiply; break; + case TokenType::MinusAssign: assignType = ShaderAst::AssignType::CompoundSubtract; break; + case TokenType::PlusAssign: assignType = ShaderAst::AssignType::CompoundAdd; break; + + default: + throw UnexpectedToken{}; + } + + Consume(); + + // Value expression ShaderAst::ExpressionPtr right = ParseExpression(); - return ShaderBuilder::Assign(ShaderAst::AssignType::Simple, std::move(left), std::move(right)); + return ShaderBuilder::Assign(assignType, std::move(left), std::move(right)); } ShaderAst::StatementPtr Parser::ParseVariableDeclaration() diff --git a/src/Nazara/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp index 15ee3bf94..8759be164 100644 --- a/src/Nazara/Shader/SpirvAstVisitor.cpp +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -51,6 +51,9 @@ namespace Nz void SpirvAstVisitor::Visit(ShaderAst::AssignExpression& node) { + if (node.op != ShaderAst::AssignType::Simple) + throw std::runtime_error("unexpected assign expression (should have been removed by sanitization)"); + UInt32 resultId = EvaluateExpression(node.right); SpirvExpressionStore storeVisitor(m_writer, *this, *m_currentBlock); diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index 4455f557e..7d69ecb24 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -464,6 +464,7 @@ namespace Nz { ShaderAst::SanitizeVisitor::Options options; options.optionValues = states.optionValues; + options.removeCompoundAssignments = true; sanitizedAst = ShaderAst::Sanitize(shader, options); targetAst = sanitizedAst.get();