Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ dotnet_remove_unnecessary_suppression_exclusions = none

# New line preferences
dotnet_style_allow_multiple_blank_lines_experimental = false
dotnet_style_allow_statement_immediately_after_block_experimental = false
dotnet_style_allow_statement_immediately_after_block_experimental = true

#### C# Coding Conventions ####

Expand Down Expand Up @@ -127,6 +127,7 @@ csharp_prefer_system_threading_lock = true
csharp_style_namespace_declarations = file_scoped
csharp_style_prefer_method_group_conversion = true
csharp_style_prefer_primary_constructors = true
csharp_style_prefer_simple_property_accessors = true
csharp_style_prefer_top_level_statements = true

# Expression-level preferences
Expand Down
2 changes: 1 addition & 1 deletion CustomGeneratorTests/CustomGeneratorTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GodotSharp.SourceGenerators" Version="2.7.0-251025-1634.Release" />
<PackageReference Include="GodotSharp.SourceGenerators" Version="2.7.0-251125-0311.Release" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="[4.8.0]" PrivateAssets="all" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Godot 3 Tests/Godot 3 Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="[7.2.0]" />
<PackageReference Include="GodotSharp.SourceGenerators" Version="2.7.0-251025-1634.Release" />
<PackageReference Include="GodotSharp.SourceGenerators" Version="2.7.0-251125-0311.Release" />
<ProjectReference Include="..\CustomGeneratorTests\CustomGeneratorTests.csproj" OutputItemType="analyzer" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Godot 4 Tests/Godot 4 Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="[7.2.0]" />
<PackageReference Include="GodotSharp.SourceGenerators" Version="2.7.0-251025-1634.Release" />
<PackageReference Include="GodotSharp.SourceGenerators" Version="2.7.0-251125-0311.Release" />
<ProjectReference Include="..\CustomGeneratorTests\CustomGeneratorTests.csproj" OutputItemType="analyzer" />
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions Godot 4 Tests/Run.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ private static IEnumerable<Func<ITest>> Tests
yield return ITest.GetTest<ScriptForSceneWithDifferentName>;
yield return ITest.GetTest<ScriptForSceneWithDifferentPath>;
yield return ITest.GetTest<ShaderAttributeTests>;
yield return ITest.GetTest<ShaderGlobalsAttributeTests>;
yield return ITest.GetTest<SingletonAttributeTests>;
yield return ITest.GetTest<SubNodeSceneTreeTest>;
yield return ITest.GetTest<TranslationAttributeTests>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ void ITest.ReadyTests()
Test(() => My2RpcId(1, 2, 2.2f), "2|2|2.2");
Test(() => My3RpcId(1, 3, 3.3f, EnumTest.C), "3|3|3.3|C");
Test(() => My4RpcId(1), "4|4|4.4|D");
Test(() => MyXRpcId(1), null, ok: false); // Godot logs error if calling self when CallLocal is false
//Test(() => MyXRpcId(1), null, ok: false); // Godot logs error if calling self when CallLocal is false

// Godot logs errors for unknown peer id (but doesn't return error?!?!?)
Test(() => My0RpcId(2), null/*, ok: false*/);
Test(() => My1RpcId(2, 1), null/*, ok: false*/);
Test(() => My2RpcId(2, 2, 2.2f), null/*, ok: false*/);
Test(() => My3RpcId(2, 3, 3.3f, EnumTest.C), null/*, ok: false*/);
Test(() => My4RpcId(2), null/*, ok: false*/);
Test(() => MyXRpcId(2), null/*, ok: false*/);
//Test(() => My0RpcId(2), null/*, ok: false*/);
//Test(() => My1RpcId(2, 1), null/*, ok: false*/);
//Test(() => My2RpcId(2, 2, 2.2f), null/*, ok: false*/);
//Test(() => My3RpcId(2, 3, 3.3f, EnumTest.C), null/*, ok: false*/);
//Test(() => My4RpcId(2), null/*, ok: false*/);
//Test(() => MyXRpcId(2), null/*, ok: false*/);

void Test(Func<Error> sut, string expected, bool ok = true, [CallerArgumentExpression(nameof(sut))] string test = null)
{
Expand Down
6 changes: 6 additions & 0 deletions Godot 4 Tests/TestScenes/Feature164.ShaderGlobals/Noise.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[gd_resource type="NoiseTexture3D" load_steps=2 format=3 uid="uid://8ff1k1aycfdw"]

[sub_resource type="FastNoiseLite" id="FastNoiseLite_lids6"]

[resource]
noise = SubResource("FastNoiseLite_lids6")
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using FluentAssertions;
using Godot;
using GodotSharp.BuildingBlocks.TestRunner;

namespace GodotTests.TestScenes;

[ShaderGlobals]
public static partial class ShaderGlobals;

[SceneTree]
public partial class ShaderGlobalsAttributeTests : Node, ITest
{
void ITest.InitTests()
{
ShaderGlobals.A.Should().BeTrue();
ShaderGlobals.B.Should().Be(2);
ShaderGlobals.C.Should().Be(0);
ShaderGlobals.D.Should().Be(9);
ShaderGlobals.E.Should().Be(875);
ShaderGlobals.F.Should().Be(new Vector2I(565, 0));
ShaderGlobals.G.Should().Be(new Vector3I(0, 410, 0));
ShaderGlobals.H.Should().Be(new Vector4I(0, 475, 0, 180));
ShaderGlobals.I.Should().Be(new Rect2I(50, 0, 145, 0));
ShaderGlobals.J.Should().Be(345);
ShaderGlobals.K.Should().Be(new Vector2I(295, 355));
ShaderGlobals.L.Should().Be(new Vector3I(0, 195, 0));
ShaderGlobals.M.Should().Be(new Vector4I(0, 0, 275, 0));
ShaderGlobals.N.Should().Be(0.205f);
ShaderGlobals.O.Should().Be(new Vector2(0.23f, 0.385f));
ShaderGlobals.P.Should().Be(new Vector3(0.0f, 0.435f, 0.0f));
ShaderGlobals.Q.Should().Be(new Vector4(0.22f, 0.0f, 0.275f, 0.0f));
ShaderGlobals.R.Should().Be(new Color(0.517647f, 0.921569f, 0.52549f, 0.788235f));
ShaderGlobals.S.Should().Be(new Rect2(0.19f, 0.0f, 0.065f, 0.1f));
ShaderGlobals.T.Should().Be(new Vector4(1.36f, 0.44f, 0.22f, 1.0f));
ShaderGlobals.U.Should().Be(new Basis(1.0f, 0.205f, 1.37f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f));
ShaderGlobals.V.Should().Be(new Projection(1.0f, 0.46f, 0.92f, 0.0f, 0.0f, 1.315f, 0.92f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f));
ShaderGlobals.W.Should().Be(new Transform2D(1.0f, 0.0f, 1.885f, 1.0f, 0.755f, 0.0f));
ShaderGlobals.X.Should().Be(new Transform3D(1.0f, 0.0f, 0.0f, 0.0f, 1.35f, 0.59f, 0.0f, 0.0f, 1.0f, 0.0f, 0.54f, 0.0f));
ShaderGlobals.Y.Should().BeNull();
ShaderGlobals.Y.GetDeclaredType().Should().Be(typeof(Texture2D));
ShaderGlobals.Z.Should().BeNull();
ShaderGlobals.Z.GetDeclaredType().Should().Be(typeof(Texture2DArray));
ShaderGlobals.Ä.Should().Be(GD.Load<Texture3D>("res://TestScenes/Feature164.ShaderGlobals/Noise.tres"));
ShaderGlobals.Ö.Should().BeNull();
ShaderGlobals.Ö.GetDeclaredType().Should().Be(typeof(Cubemap));
ShaderGlobals.Ü.Should().BeNull();
ShaderGlobals.Ü.GetDeclaredType().Should().Be(typeof(ExternalTexture));

ShaderGlobals.A = false;
ShaderGlobals.B = 7;
ShaderGlobals.N = .777f;

ShaderGlobals.A.Should().BeFalse();
ShaderGlobals.B.Should().Be(7);
ShaderGlobals.N.Should().Be(.777f);

ShaderGlobals.A = ShaderGlobals.Default.A;
ShaderGlobals.B = ShaderGlobals.Default.B;
ShaderGlobals.N = ShaderGlobals.Default.N;

ShaderGlobals.A.Should().BeTrue();
ShaderGlobals.B.Should().Be(2);
ShaderGlobals.N.Should().Be(.205f);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://dm8vgm0v4e6hi
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://qlum4js31ian"]

[ext_resource type="Script" uid="uid://dm8vgm0v4e6hi" path="res://TestScenes/Feature164.ShaderGlobals/ShaderGlobalsAttributeTests.cs" id="1_y0unj"]

[node name="ShaderGlobalsAttributeTests" type="Node"]
script = ExtResource("1_y0unj")
2 changes: 2 additions & 0 deletions Godot 4 Tests/Utils/Extensions/ReflectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ public static void ShouldContain(this Type t,
if (Properties is not null) t.Properties().Should().Contain(Properties);
if (NestedTypes is not null) t.NestedTypes().Should().Contain(NestedTypes);
}

public static Type GetDeclaredType<T>(this T t) => typeof(T);
}
119 changes: 119 additions & 0 deletions Godot 4 Tests/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,122 @@ avoidance/layer_16="- With Leading - 16"
avoidance/layer_17="7 With Leading Numeric 17"
avoidance/layer_18=". With Leading . 18"
avoidance/layer_19="中文 With Leading Unicode 19"

[shader_globals]

a={
"type": "bool",
"value": true
}
b={
"type": "bvec2",
"value": 2
}
c={
"type": "bvec3",
"value": 0
}
d={
"type": "bvec4",
"value": 9
}
e={
"type": "int",
"value": 875
}
f={
"type": "ivec2",
"value": Vector2i(565, 0)
}
g={
"type": "ivec3",
"value": Vector3i(0, 410, 0)
}
h={
"type": "ivec4",
"value": Vector4i(0, 475, 0, 180)
}
i={
"type": "rect2i",
"value": Rect2i(50, 0, 145, 0)
}
j={
"type": "uint",
"value": 345
}
k={
"type": "uvec2",
"value": Vector2i(295, 355)
}
l={
"type": "uvec3",
"value": Vector3i(0, 195, 0)
}
m={
"type": "uvec4",
"value": Vector4i(0, 0, 275, 0)
}
n={
"type": "float",
"value": 0.205
}
o={
"type": "vec2",
"value": Vector2(0.23, 0.385)
}
p={
"type": "vec3",
"value": Vector3(0, 0.435, 0)
}
q={
"type": "vec4",
"value": Vector4(0.22, 0, 0.275, 0)
}
r={
"type": "color",
"value": Color(0.517647, 0.921569, 0.52549, 0.788235)
}
s={
"type": "rect2",
"value": Rect2(0.19, 0, 0.065, 0.1)
}
t={
"type": "mat2",
"value": PackedFloat32Array(1.36, 0.44, 0.22, 1)
}
u={
"type": "mat3",
"value": Basis(1, 0.205, 1.37, 0, 1, 0, 0, 0, 1)
}
v={
"type": "mat4",
"value": Projection(1, 0.46, 0.92, 0, 0, 1.315, 0.92, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
w={
"type": "transform_2d",
"value": Transform2D(1, 0, 1.885, 1, 0.755, 0)
}
x={
"type": "transform",
"value": Transform3D(1, 0, 0, 0, 1.35, 0.59, 0, 0, 1, 0, 0.54, 0)
}
y={
"type": "sampler2D",
"value": ""
}
z={
"type": "sampler2DArray",
"value": ""
}
"ä"={
"type": "sampler3D",
"value": "res://TestScenes/Feature164.ShaderGlobals/Noise.tres"
}
"ö"={
"type": "samplerCube",
"value": ""
}
"ü"={
"type": "samplerExternalOES",
"value": ""
}
9 changes: 9 additions & 0 deletions SourceGenerators/ShaderGlobalsExtensions/Resources.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Reflection;

namespace GodotSharp.SourceGenerators.ShaderGlobalsExtensions;

internal static class Resources
{
private const string shaderGlobalsTemplate = "GodotSharp.SourceGenerators.ShaderGlobalsExtensions.ShaderGlobalsTemplate.scriban";
public static readonly string ShaderGlobalsTemplate = Assembly.GetExecutingAssembly().GetEmbeddedResource(shaderGlobalsTemplate);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace Godot;

[AttributeUsage(AttributeTargets.Class)]
public sealed class ShaderGlobalsAttribute() : Attribute;
88 changes: 88 additions & 0 deletions SourceGenerators/ShaderGlobalsExtensions/ShaderGlobalsDataModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using Microsoft.CodeAnalysis;

namespace GodotSharp.SourceGenerators.ShaderGlobalsExtensions;

internal class ShaderGlobalsDataModel(INamedTypeSymbol symbol, string gdRoot) : ClassDataModel(symbol)
{
public record ShaderGlobal(string Name, string Type, string Default, string RawName);

public IList<ShaderGlobal> ShaderGlobals { get; } = [..
ShaderGlobalsScraper
.GetShaderGlobals(gdRoot)
.Select(Convert)];

protected override string Str()
=> string.Join("\n", ShaderGlobals);

#region Convert

private static ShaderGlobal Convert(ShaderGlobalsScraper.ShaderGlobal raw)
{
var csType = ConvertType(raw.Type);
var csValue = ConvertValue(raw.Default) ?? "default";
return new(raw.Name.ToPascalCase(), csType, csValue, raw.Name);

string ConvertType(string type) => type switch
{
"bvec2" => "int",
"bvec3" => "int",
"bvec4" => "int",

"ivec2" => "Vector2I",
"ivec3" => "Vector3I",
"ivec4" => "Vector4I",

"uvec2" => "Vector2I",
"uvec3" => "Vector3I",
"uvec4" => "Vector4I",

"vec2" => "Vector2",
"vec3" => "Vector3",
"vec4" => "Vector4",

"color" => "Color",

"rect2" => "Rect2",
"rect2i" => "Rect2I",

"mat2" => "Vector4",
"mat3" => "Basis",
"mat4" => "Projection",

"transform_2d" => "Transform2D",
"transform" => "Transform3D",

"sampler2D" => "Texture2D",
"sampler2DArray" => "Texture2DArray",
"sampler3D" => "Texture3D",
"samplerCube" => "Cubemap",
"samplerExternalOES" => "ExternalTexture",

_ => type,
};

string ConvertValue(string v)
{
return v is null ? null : TryAsRes() ?? TryAsCtor() ?? SafeValue(v);

string TryAsRes()
=> v.StartsWith("res://") ? @$"GD.Load<{csType}>(""{v}"")" : null;

string TryAsCtor()
{
if (v.EndsWith(")"))
{
var args = v.Split('(').Last().TrimEnd(')').Split(',').Select(SafeValue);
return $"new {csType}({string.Join(",", args)})";
}

return null;
}

static string SafeValue(string v)
=> v.Contains('.') ? $"{v}f" : v;
}
}

#endregion
}
Loading