summaryrefslogtreecommitdiff
path: root/modules/mono/glue/GodotSharp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/glue/GodotSharp')
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs2
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs4
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs28
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs26
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj1
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/Main.cs34
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs24
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs)457
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs1107
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs23
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotClassNameAttribute.cs24
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RpcAttribute.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs)16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs509
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs33
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs131
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs26
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs238
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs649
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs299
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs330
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/GodotObjectExtensions.cs86
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs9
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs48
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs450
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs)26
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.exceptions.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs)2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs44
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs1151
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs117
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs103
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs583
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs70
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs1057
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs33
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs180
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs414
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs34
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs169
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs764
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs288
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs42
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs151
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs)308
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs104
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Signal.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs)16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs759
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs317
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs279
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Variant.cs)204
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs356
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs)448
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs407
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs)463
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs388
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs)412
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj28
77 files changed, 8202 insertions, 6224 deletions
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs
index 686023a077..ae51c07386 100644
--- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs
@@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis;
namespace Godot.SourceGenerators.Internal;
-internal struct CallbacksData
+internal readonly struct CallbacksData
{
public CallbacksData(INamedTypeSymbol nativeTypeSymbol, INamedTypeSymbol funcStructSymbol)
{
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs
index 16e96c725a..d3726d69f0 100644
--- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs
@@ -12,7 +12,7 @@ internal static class Common
{
string message =
"Missing partial modifier on declaration of type '" +
- $"{symbol.FullQualifiedName()}' which has attribute '{GeneratorClasses.GenerateUnmanagedCallbacksAttr}'";
+ $"{symbol.FullQualifiedNameOmitGlobal()}' which has attribute '{GeneratorClasses.GenerateUnmanagedCallbacksAttr}'";
string description = $"{message}. Classes with attribute '{GeneratorClasses.GenerateUnmanagedCallbacksAttr}' " +
"must be declared with the partial modifier.";
@@ -39,7 +39,7 @@ internal static class Common
.GetDeclaredSymbol(outerTypeDeclSyntax);
string fullQualifiedName = outerSymbol is INamedTypeSymbol namedTypeSymbol ?
- namedTypeSymbol.FullQualifiedName() :
+ namedTypeSymbol.FullQualifiedNameOmitGlobal() :
"type not found";
string message =
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs
index fac362479a..37f7005d01 100644
--- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs
@@ -94,13 +94,6 @@ internal static class ExtensionMethods
};
}
- private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } =
- SymbolDisplayFormat.FullyQualifiedFormat
- .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);
-
- public static string FullQualifiedName(this ITypeSymbol symbol)
- => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
-
public static string NameWithTypeParameters(this INamedTypeSymbol symbol)
{
return symbol.IsGenericType ?
@@ -108,8 +101,25 @@ internal static class ExtensionMethods
symbol.Name;
}
- public static string FullQualifiedName(this INamespaceSymbol symbol)
- => symbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+ private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } =
+ SymbolDisplayFormat.FullyQualifiedFormat
+ .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);
+
+ private static SymbolDisplayFormat FullyQualifiedFormatIncludeGlobal { get; } =
+ SymbolDisplayFormat.FullyQualifiedFormat
+ .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Included);
+
+ public static string FullQualifiedNameOmitGlobal(this ITypeSymbol symbol)
+ => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
+
+ public static string FullQualifiedNameOmitGlobal(this INamespaceSymbol namespaceSymbol)
+ => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+
+ public static string FullQualifiedNameIncludeGlobal(this ITypeSymbol symbol)
+ => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatIncludeGlobal);
+
+ public static string FullQualifiedNameIncludeGlobal(this INamespaceSymbol namespaceSymbol)
+ => namespaceSymbol.ToDisplayString(FullyQualifiedFormatIncludeGlobal);
public static string SanitizeQualifiedNameForUniqueHint(this string qualifiedName)
=> qualifiedName
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs
index da578309bc..3226ca79e5 100644
--- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs
@@ -96,7 +96,7 @@ internal class GenerateUnmanagedCallbacksAttribute : Attribute
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
- namespaceSymbol.FullQualifiedName() :
+ namespaceSymbol.FullQualifiedNameOmitGlobal() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
@@ -144,7 +144,7 @@ using Godot.NativeInterop;
source.Append("[System.Runtime.CompilerServices.SkipLocalsInit]\n");
source.Append($"unsafe partial class {symbol.Name}\n");
source.Append("{\n");
- source.Append($" private static {data.FuncStructSymbol.FullQualifiedName()} _unmanagedCallbacks;\n\n");
+ source.Append($" private static {data.FuncStructSymbol.FullQualifiedNameIncludeGlobal()} _unmanagedCallbacks;\n\n");
foreach (var callback in data.Methods)
{
@@ -159,7 +159,7 @@ using Godot.NativeInterop;
source.Append("static ");
source.Append("partial ");
- source.Append(callback.ReturnType.FullQualifiedName());
+ source.Append(callback.ReturnType.FullQualifiedNameIncludeGlobal());
source.Append(' ');
source.Append(callback.Name);
source.Append('(');
@@ -228,7 +228,7 @@ using Godot.NativeInterop;
if (!callback.ReturnsVoid)
{
if (methodSourceAfterCall.Length != 0)
- source.Append($"{callback.ReturnType.FullQualifiedName()} ret = ");
+ source.Append($"{callback.ReturnType.FullQualifiedNameIncludeGlobal()} ret = ");
else
source.Append("return ");
}
@@ -267,7 +267,7 @@ using Godot.NativeInterop;
source.Append("\n\n#pragma warning restore CA1707\n");
- context.AddSource($"{data.NativeTypeSymbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()}.generated",
+ context.AddSource($"{data.NativeTypeSymbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()}.generated",
SourceText.From(source.ToString(), Encoding.UTF8));
}
@@ -277,7 +277,7 @@ using Godot.NativeInterop;
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
- namespaceSymbol.FullQualifiedName() :
+ namespaceSymbol.FullQualifiedNameOmitGlobal() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
@@ -338,18 +338,18 @@ using Godot.NativeInterop;
// just pass it by-ref and let it be pinned.
AppendRefKind(source, parameter.RefKind)
.Append(' ')
- .Append(parameter.Type.FullQualifiedName());
+ .Append(parameter.Type.FullQualifiedNameIncludeGlobal());
}
}
else
{
- source.Append(parameter.Type.FullQualifiedName());
+ source.Append(parameter.Type.FullQualifiedNameIncludeGlobal());
}
source.Append(", ");
}
- source.Append(callback.ReturnType.FullQualifiedName());
+ source.Append(callback.ReturnType.FullQualifiedNameIncludeGlobal());
source.Append($"> {callback.Name};\n");
}
@@ -372,12 +372,12 @@ using Godot.NativeInterop;
source.Append("\n#pragma warning restore CA1707\n");
- context.AddSource($"{symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()}.generated",
+ context.AddSource($"{symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()}.generated",
SourceText.From(source.ToString(), Encoding.UTF8));
}
private static bool IsGodotInteropStruct(ITypeSymbol type) =>
- GodotInteropStructs.Contains(type.FullQualifiedName());
+ GodotInteropStructs.Contains(type.FullQualifiedNameOmitGlobal());
private static bool IsByRefParameter(IParameterSymbol parameter) =>
parameter.RefKind is RefKind.In or RefKind.Out or RefKind.Ref;
@@ -393,7 +393,7 @@ using Godot.NativeInterop;
private static void AppendPointerType(StringBuilder source, ITypeSymbol type)
{
- source.Append(type.FullQualifiedName());
+ source.Append(type.FullQualifiedNameIncludeGlobal());
source.Append('*');
}
@@ -426,7 +426,7 @@ using Godot.NativeInterop;
{
varName = $"{parameter.Name}_copy";
- source.Append(parameter.Type.FullQualifiedName());
+ source.Append(parameter.Type.FullQualifiedNameIncludeGlobal());
source.Append(' ');
source.Append(varName);
if (parameter.RefKind is RefKind.In or RefKind.Ref)
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj b/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj
index e720d3878c..e58d730ee3 100644
--- a/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj
@@ -8,6 +8,7 @@
<!-- To generate the .runtimeconfig.json file-->
<EnableDynamicLoading>true</EnableDynamicLoading>
+ <RollForward>LatestMajor</RollForward>
</PropertyGroup>
<ItemGroup>
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
index 8308bada24..2a72b7c53e 100644
--- a/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
@@ -28,17 +28,24 @@ namespace GodotPlugins
get => _pluginLoadContext?.AssemblyLoadedPath;
}
+ public bool IsCollectible
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ get => _pluginLoadContext?.IsCollectible ?? false;
+ }
+
[MethodImpl(MethodImplOptions.NoInlining)]
public static (Assembly, PluginLoadContextWrapper) CreateAndLoadFromAssemblyName(
AssemblyName assemblyName,
string pluginPath,
ICollection<string> sharedAssemblies,
- AssemblyLoadContext mainLoadContext
+ AssemblyLoadContext mainLoadContext,
+ bool isCollectible
)
{
var wrapper = new PluginLoadContextWrapper();
wrapper._pluginLoadContext = new PluginLoadContext(
- pluginPath, sharedAssemblies, mainLoadContext);
+ pluginPath, sharedAssemblies, mainLoadContext, isCollectible);
var assembly = wrapper._pluginLoadContext.LoadFromAssemblyName(assemblyName);
return (assembly, wrapper);
}
@@ -58,9 +65,10 @@ namespace GodotPlugins
}
private static readonly List<AssemblyName> SharedAssemblies = new();
- private static readonly Assembly CoreApiAssembly = typeof(Godot.Object).Assembly;
+ private static readonly Assembly CoreApiAssembly = typeof(global::Godot.GodotObject).Assembly;
private static Assembly? _editorApiAssembly;
private static PluginLoadContextWrapper? _projectLoadContext;
+ private static bool _editorHint = false;
private static readonly AssemblyLoadContext MainLoadContext =
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
@@ -77,15 +85,17 @@ namespace GodotPlugins
{
try
{
+ _editorHint = editorHint.ToBool();
+
_dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport;
SharedAssemblies.Add(CoreApiAssembly.GetName());
NativeLibrary.SetDllImportResolver(CoreApiAssembly, _dllImportResolver);
- AlcReloadCfg.Configure(alcReloadEnabled: editorHint.ToBool());
+ AlcReloadCfg.Configure(alcReloadEnabled: _editorHint);
NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
- if (editorHint.ToBool())
+ if (_editorHint)
{
_editorApiAssembly = Assembly.Load("GodotSharpEditor");
SharedAssemblies.Add(_editorApiAssembly.GetName());
@@ -128,7 +138,7 @@ namespace GodotPlugins
string assemblyPath = new(nAssemblyPath);
- (var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath);
+ (var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath, isCollectible: _editorHint);
string loadedAssemblyPath = _projectLoadContext.AssemblyLoadedPath ?? assemblyPath;
*outLoadedAssemblyPath = Marshaling.ConvertStringToNative(loadedAssemblyPath);
@@ -155,7 +165,7 @@ namespace GodotPlugins
if (_editorApiAssembly == null)
throw new InvalidOperationException("The Godot editor API assembly is not loaded.");
- var (assembly, _) = LoadPlugin(assemblyPath);
+ var (assembly, _) = LoadPlugin(assemblyPath, isCollectible: _editorHint);
NativeLibrary.SetDllImportResolver(assembly, _dllImportResolver!);
@@ -180,7 +190,7 @@ namespace GodotPlugins
}
}
- private static (Assembly, PluginLoadContextWrapper) LoadPlugin(string assemblyPath)
+ private static (Assembly, PluginLoadContextWrapper) LoadPlugin(string assemblyPath, bool isCollectible)
{
string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
@@ -194,7 +204,7 @@ namespace GodotPlugins
}
return PluginLoadContextWrapper.CreateAndLoadFromAssemblyName(
- new AssemblyName(assemblyName), assemblyPath, sharedAssemblies, MainLoadContext);
+ new AssemblyName(assemblyName), assemblyPath, sharedAssemblies, MainLoadContext, isCollectible);
}
[UnmanagedCallersOnly]
@@ -218,6 +228,12 @@ namespace GodotPlugins
if (pluginLoadContext == null)
return true;
+ if (!pluginLoadContext.IsCollectible)
+ {
+ Console.Error.WriteLine("Cannot unload a non-collectible assembly load context.");
+ return false;
+ }
+
Console.WriteLine("Unloading assembly load context...");
var alcWeakReference = pluginLoadContext.CreateWeakReference();
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
index dcd572c65e..93baf4e51c 100644
--- a/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
@@ -15,12 +15,32 @@ namespace GodotPlugins
public string? AssemblyLoadedPath { get; private set; }
public PluginLoadContext(string pluginPath, ICollection<string> sharedAssemblies,
- AssemblyLoadContext mainLoadContext)
- : base(isCollectible: true)
+ AssemblyLoadContext mainLoadContext, bool isCollectible)
+ : base(isCollectible)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
_sharedAssemblies = sharedAssemblies;
_mainLoadContext = mainLoadContext;
+
+ if (string.IsNullOrEmpty(AppContext.BaseDirectory))
+ {
+ // See https://github.com/dotnet/runtime/blob/v6.0.0/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs#L17-L35
+ // but Assembly.Location is unavailable, because we load assemblies from memory.
+ string? baseDirectory = Path.GetDirectoryName(pluginPath);
+ if (baseDirectory != null)
+ {
+ if (!Path.EndsInDirectorySeparator(baseDirectory))
+ baseDirectory += Path.DirectorySeparatorChar;
+ // This SetData call effectively sets AppContext.BaseDirectory
+ // See https://github.com/dotnet/runtime/blob/v6.0.0/src/libraries/System.Private.CoreLib/src/System/AppContext.cs#L21-L25
+ AppDomain.CurrentDomain.SetData("APP_CONTEXT_BASE_DIRECTORY", baseDirectory);
+ }
+ else
+ {
+ // TODO: How to log from GodotPlugins? (delegate pointer?)
+ Console.Error.WriteLine("Failed to set AppContext.BaseDirectory. Dynamic loading of libraries may fail.");
+ }
+ }
}
protected override Assembly? Load(AssemblyName assemblyName)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
index ba65b61e95..65f33e43a8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
+++ b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
@@ -1,7 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=alcs/@EntryIndexedValue">True</s:Boolean>
- <s:Boolean x:Key="/Default/UserDictionary/Words/=gdnative/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=gdextension/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=godotsharp/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=icall/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=quat/@EntryIndexedValue">True</s:Boolean>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs
index d8a6644a66..af83cc24bf 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs
@@ -9,7 +9,7 @@ namespace Godot
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
- public struct AABB : IEquatable<AABB>
+ public struct Aabb : IEquatable<Aabb>
{
private Vector3 _position;
private Vector3 _size;
@@ -20,7 +20,7 @@ namespace Godot
/// <value>Directly uses a private field.</value>
public Vector3 Position
{
- get { return _position; }
+ readonly get { return _position; }
set { _position = value; }
}
@@ -31,7 +31,7 @@ namespace Godot
/// <value>Directly uses a private field.</value>
public Vector3 Size
{
- get { return _size; }
+ readonly get { return _size; }
set { _size = value; }
}
@@ -45,121 +45,130 @@ namespace Godot
/// </value>
public Vector3 End
{
- get { return _position + _size; }
+ readonly get { return _position + _size; }
set { _size = value - _position; }
}
/// <summary>
- /// Returns an <see cref="AABB"/> with equivalent position and size, modified so that
+ /// The volume of this <see cref="Aabb"/>.
+ /// See also <see cref="HasVolume"/>.
+ /// </summary>
+ public readonly real_t Volume
+ {
+ get { return _size.X * _size.Y * _size.Z; }
+ }
+
+ /// <summary>
+ /// Returns an <see cref="Aabb"/> with equivalent position and size, modified so that
/// the most-negative corner is the origin and the size is positive.
/// </summary>
- /// <returns>The modified <see cref="AABB"/>.</returns>
- public AABB Abs()
+ /// <returns>The modified <see cref="Aabb"/>.</returns>
+ public readonly Aabb Abs()
{
Vector3 end = End;
- Vector3 topLeft = new Vector3(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y), Mathf.Min(_position.z, end.z));
- return new AABB(topLeft, _size.Abs());
+ Vector3 topLeft = new Vector3(Mathf.Min(_position.X, end.X), Mathf.Min(_position.Y, end.Y), Mathf.Min(_position.Z, end.Z));
+ return new Aabb(topLeft, _size.Abs());
}
/// <summary>
- /// Returns the center of the <see cref="AABB"/>, which is equal
+ /// Returns the center of the <see cref="Aabb"/>, which is equal
/// to <see cref="Position"/> + (<see cref="Size"/> / 2).
/// </summary>
/// <returns>The center.</returns>
- public Vector3 GetCenter()
+ public readonly Vector3 GetCenter()
{
return _position + (_size * 0.5f);
}
/// <summary>
- /// Returns <see langword="true"/> if this <see cref="AABB"/> completely encloses another one.
+ /// Returns <see langword="true"/> if this <see cref="Aabb"/> completely encloses another one.
/// </summary>
- /// <param name="with">The other <see cref="AABB"/> that may be enclosed.</param>
+ /// <param name="with">The other <see cref="Aabb"/> that may be enclosed.</param>
/// <returns>
- /// A <see langword="bool"/> for whether or not this <see cref="AABB"/> encloses <paramref name="with"/>.
+ /// A <see langword="bool"/> for whether or not this <see cref="Aabb"/> encloses <paramref name="with"/>.
/// </returns>
- public bool Encloses(AABB with)
+ public readonly bool Encloses(Aabb with)
{
Vector3 srcMin = _position;
Vector3 srcMax = _position + _size;
Vector3 dstMin = with._position;
Vector3 dstMax = with._position + with._size;
- return srcMin.x <= dstMin.x &&
- srcMax.x > dstMax.x &&
- srcMin.y <= dstMin.y &&
- srcMax.y > dstMax.y &&
- srcMin.z <= dstMin.z &&
- srcMax.z > dstMax.z;
+ return srcMin.X <= dstMin.X &&
+ srcMax.X > dstMax.X &&
+ srcMin.Y <= dstMin.Y &&
+ srcMax.Y > dstMax.Y &&
+ srcMin.Z <= dstMin.Z &&
+ srcMax.Z > dstMax.Z;
}
/// <summary>
- /// Returns this <see cref="AABB"/> expanded to include a given point.
+ /// Returns this <see cref="Aabb"/> expanded to include a given point.
/// </summary>
/// <param name="point">The point to include.</param>
- /// <returns>The expanded <see cref="AABB"/>.</returns>
- public AABB Expand(Vector3 point)
+ /// <returns>The expanded <see cref="Aabb"/>.</returns>
+ public readonly Aabb Expand(Vector3 point)
{
Vector3 begin = _position;
Vector3 end = _position + _size;
- if (point.x < begin.x)
+ if (point.X < begin.X)
{
- begin.x = point.x;
+ begin.X = point.X;
}
- if (point.y < begin.y)
+ if (point.Y < begin.Y)
{
- begin.y = point.y;
+ begin.Y = point.Y;
}
- if (point.z < begin.z)
+ if (point.Z < begin.Z)
{
- begin.z = point.z;
+ begin.Z = point.Z;
}
- if (point.x > end.x)
+ if (point.X > end.X)
{
- end.x = point.x;
+ end.X = point.X;
}
- if (point.y > end.y)
+ if (point.Y > end.Y)
{
- end.y = point.y;
+ end.Y = point.Y;
}
- if (point.z > end.z)
+ if (point.Z > end.Z)
{
- end.z = point.z;
+ end.Z = point.Z;
}
- return new AABB(begin, end - begin);
+ return new Aabb(begin, end - begin);
}
/// <summary>
- /// Gets the position of one of the 8 endpoints of the <see cref="AABB"/>.
+ /// Gets the position of one of the 8 endpoints of the <see cref="Aabb"/>.
/// </summary>
/// <param name="idx">Which endpoint to get.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="idx"/> is less than 0 or greater than 7.
/// </exception>
- /// <returns>An endpoint of the <see cref="AABB"/>.</returns>
- public Vector3 GetEndpoint(int idx)
+ /// <returns>An endpoint of the <see cref="Aabb"/>.</returns>
+ public readonly Vector3 GetEndpoint(int idx)
{
switch (idx)
{
case 0:
- return new Vector3(_position.x, _position.y, _position.z);
+ return new Vector3(_position.X, _position.Y, _position.Z);
case 1:
- return new Vector3(_position.x, _position.y, _position.z + _size.z);
+ return new Vector3(_position.X, _position.Y, _position.Z + _size.Z);
case 2:
- return new Vector3(_position.x, _position.y + _size.y, _position.z);
+ return new Vector3(_position.X, _position.Y + _size.Y, _position.Z);
case 3:
- return new Vector3(_position.x, _position.y + _size.y, _position.z + _size.z);
+ return new Vector3(_position.X, _position.Y + _size.Y, _position.Z + _size.Z);
case 4:
- return new Vector3(_position.x + _size.x, _position.y, _position.z);
+ return new Vector3(_position.X + _size.X, _position.Y, _position.Z);
case 5:
- return new Vector3(_position.x + _size.x, _position.y, _position.z + _size.z);
+ return new Vector3(_position.X + _size.X, _position.Y, _position.Z + _size.Z);
case 6:
- return new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z);
+ return new Vector3(_position.X + _size.X, _position.Y + _size.Y, _position.Z);
case 7:
- return new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z + _size.z);
+ return new Vector3(_position.X + _size.X, _position.Y + _size.Y, _position.Z + _size.Z);
default:
{
throw new ArgumentOutOfRangeException(nameof(idx),
@@ -169,21 +178,21 @@ namespace Godot
}
/// <summary>
- /// Returns the normalized longest axis of the <see cref="AABB"/>.
+ /// Returns the normalized longest axis of the <see cref="Aabb"/>.
/// </summary>
- /// <returns>A vector representing the normalized longest axis of the <see cref="AABB"/>.</returns>
- public Vector3 GetLongestAxis()
+ /// <returns>A vector representing the normalized longest axis of the <see cref="Aabb"/>.</returns>
+ public readonly Vector3 GetLongestAxis()
{
var axis = new Vector3(1f, 0f, 0f);
- real_t maxSize = _size.x;
+ real_t maxSize = _size.X;
- if (_size.y > maxSize)
+ if (_size.Y > maxSize)
{
axis = new Vector3(0f, 1f, 0f);
- maxSize = _size.y;
+ maxSize = _size.Y;
}
- if (_size.z > maxSize)
+ if (_size.Z > maxSize)
{
axis = new Vector3(0f, 0f, 1f);
}
@@ -192,21 +201,21 @@ namespace Godot
}
/// <summary>
- /// Returns the <see cref="Vector3.Axis"/> index of the longest axis of the <see cref="AABB"/>.
+ /// Returns the <see cref="Vector3.Axis"/> index of the longest axis of the <see cref="Aabb"/>.
/// </summary>
/// <returns>A <see cref="Vector3.Axis"/> index for which axis is longest.</returns>
- public Vector3.Axis GetLongestAxisIndex()
+ public readonly Vector3.Axis GetLongestAxisIndex()
{
var axis = Vector3.Axis.X;
- real_t maxSize = _size.x;
+ real_t maxSize = _size.X;
- if (_size.y > maxSize)
+ if (_size.Y > maxSize)
{
axis = Vector3.Axis.Y;
- maxSize = _size.y;
+ maxSize = _size.Y;
}
- if (_size.z > maxSize)
+ if (_size.Z > maxSize)
{
axis = Vector3.Axis.Z;
}
@@ -215,38 +224,38 @@ namespace Godot
}
/// <summary>
- /// Returns the scalar length of the longest axis of the <see cref="AABB"/>.
+ /// Returns the scalar length of the longest axis of the <see cref="Aabb"/>.
/// </summary>
- /// <returns>The scalar length of the longest axis of the <see cref="AABB"/>.</returns>
- public real_t GetLongestAxisSize()
+ /// <returns>The scalar length of the longest axis of the <see cref="Aabb"/>.</returns>
+ public readonly real_t GetLongestAxisSize()
{
- real_t maxSize = _size.x;
+ real_t maxSize = _size.X;
- if (_size.y > maxSize)
- maxSize = _size.y;
+ if (_size.Y > maxSize)
+ maxSize = _size.Y;
- if (_size.z > maxSize)
- maxSize = _size.z;
+ if (_size.Z > maxSize)
+ maxSize = _size.Z;
return maxSize;
}
/// <summary>
- /// Returns the normalized shortest axis of the <see cref="AABB"/>.
+ /// Returns the normalized shortest axis of the <see cref="Aabb"/>.
/// </summary>
- /// <returns>A vector representing the normalized shortest axis of the <see cref="AABB"/>.</returns>
- public Vector3 GetShortestAxis()
+ /// <returns>A vector representing the normalized shortest axis of the <see cref="Aabb"/>.</returns>
+ public readonly Vector3 GetShortestAxis()
{
var axis = new Vector3(1f, 0f, 0f);
- real_t maxSize = _size.x;
+ real_t maxSize = _size.X;
- if (_size.y < maxSize)
+ if (_size.Y < maxSize)
{
axis = new Vector3(0f, 1f, 0f);
- maxSize = _size.y;
+ maxSize = _size.Y;
}
- if (_size.z < maxSize)
+ if (_size.Z < maxSize)
{
axis = new Vector3(0f, 0f, 1f);
}
@@ -255,21 +264,21 @@ namespace Godot
}
/// <summary>
- /// Returns the <see cref="Vector3.Axis"/> index of the shortest axis of the <see cref="AABB"/>.
+ /// Returns the <see cref="Vector3.Axis"/> index of the shortest axis of the <see cref="Aabb"/>.
/// </summary>
/// <returns>A <see cref="Vector3.Axis"/> index for which axis is shortest.</returns>
- public Vector3.Axis GetShortestAxisIndex()
+ public readonly Vector3.Axis GetShortestAxisIndex()
{
var axis = Vector3.Axis.X;
- real_t maxSize = _size.x;
+ real_t maxSize = _size.X;
- if (_size.y < maxSize)
+ if (_size.Y < maxSize)
{
axis = Vector3.Axis.Y;
- maxSize = _size.y;
+ maxSize = _size.Y;
}
- if (_size.z < maxSize)
+ if (_size.Z < maxSize)
{
axis = Vector3.Axis.Z;
}
@@ -278,18 +287,18 @@ namespace Godot
}
/// <summary>
- /// Returns the scalar length of the shortest axis of the <see cref="AABB"/>.
+ /// Returns the scalar length of the shortest axis of the <see cref="Aabb"/>.
/// </summary>
- /// <returns>The scalar length of the shortest axis of the <see cref="AABB"/>.</returns>
- public real_t GetShortestAxisSize()
+ /// <returns>The scalar length of the shortest axis of the <see cref="Aabb"/>.</returns>
+ public readonly real_t GetShortestAxisSize()
{
- real_t maxSize = _size.x;
+ real_t maxSize = _size.X;
- if (_size.y < maxSize)
- maxSize = _size.y;
+ if (_size.Y < maxSize)
+ maxSize = _size.Y;
- if (_size.z < maxSize)
- maxSize = _size.z;
+ if (_size.Z < maxSize)
+ maxSize = _size.Z;
return maxSize;
}
@@ -300,105 +309,96 @@ namespace Godot
/// </summary>
/// <param name="dir">The direction to find support for.</param>
/// <returns>A vector representing the support.</returns>
- public Vector3 GetSupport(Vector3 dir)
+ public readonly Vector3 GetSupport(Vector3 dir)
{
Vector3 halfExtents = _size * 0.5f;
Vector3 ofs = _position + halfExtents;
return ofs + new Vector3(
- dir.x > 0f ? -halfExtents.x : halfExtents.x,
- dir.y > 0f ? -halfExtents.y : halfExtents.y,
- dir.z > 0f ? -halfExtents.z : halfExtents.z);
- }
-
- /// <summary>
- /// Returns the volume of the <see cref="AABB"/>.
- /// </summary>
- /// <returns>The volume.</returns>
- public real_t GetVolume()
- {
- return _size.x * _size.y * _size.z;
+ dir.X > 0f ? -halfExtents.X : halfExtents.X,
+ dir.Y > 0f ? -halfExtents.Y : halfExtents.Y,
+ dir.Z > 0f ? -halfExtents.Z : halfExtents.Z);
}
/// <summary>
- /// Returns a copy of the <see cref="AABB"/> grown a given amount of units towards all the sides.
+ /// Returns a copy of the <see cref="Aabb"/> grown a given amount of units towards all the sides.
/// </summary>
/// <param name="by">The amount to grow by.</param>
- /// <returns>The grown <see cref="AABB"/>.</returns>
- public AABB Grow(real_t by)
+ /// <returns>The grown <see cref="Aabb"/>.</returns>
+ public readonly Aabb Grow(real_t by)
{
- AABB res = this;
+ Aabb res = this;
- res._position.x -= by;
- res._position.y -= by;
- res._position.z -= by;
- res._size.x += 2.0f * by;
- res._size.y += 2.0f * by;
- res._size.z += 2.0f * by;
+ res._position.X -= by;
+ res._position.Y -= by;
+ res._position.Z -= by;
+ res._size.X += 2.0f * by;
+ res._size.Y += 2.0f * by;
+ res._size.Z += 2.0f * by;
return res;
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="AABB"/> contains a point,
+ /// Returns <see langword="true"/> if the <see cref="Aabb"/> contains a point,
/// or <see langword="false"/> otherwise.
/// </summary>
/// <param name="point">The point to check.</param>
/// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> contains <paramref name="point"/>.
+ /// A <see langword="bool"/> for whether or not the <see cref="Aabb"/> contains <paramref name="point"/>.
/// </returns>
- public bool HasPoint(Vector3 point)
+ public readonly bool HasPoint(Vector3 point)
{
- if (point.x < _position.x)
+ if (point.X < _position.X)
return false;
- if (point.y < _position.y)
+ if (point.Y < _position.Y)
return false;
- if (point.z < _position.z)
+ if (point.Z < _position.Z)
return false;
- if (point.x > _position.x + _size.x)
+ if (point.X > _position.X + _size.X)
return false;
- if (point.y > _position.y + _size.y)
+ if (point.Y > _position.Y + _size.Y)
return false;
- if (point.z > _position.z + _size.z)
+ if (point.Z > _position.Z + _size.Z)
return false;
return true;
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="AABB"/>
+ /// Returns <see langword="true"/> if the <see cref="Aabb"/>
/// has a surface or a length, and <see langword="false"/>
- /// if the <see cref="AABB"/> is empty (all components
+ /// if the <see cref="Aabb"/> is empty (all components
/// of <see cref="Size"/> are zero or negative).
/// </summary>
/// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has surface.
+ /// A <see langword="bool"/> for whether or not the <see cref="Aabb"/> has surface.
/// </returns>
- public bool HasSurface()
+ public readonly bool HasSurface()
{
- return _size.x > 0.0f || _size.y > 0.0f || _size.z > 0.0f;
+ return _size.X > 0.0f || _size.Y > 0.0f || _size.Z > 0.0f;
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="AABB"/> has
- /// area, and <see langword="false"/> if the <see cref="AABB"/>
+ /// Returns <see langword="true"/> if the <see cref="Aabb"/> has
+ /// area, and <see langword="false"/> if the <see cref="Aabb"/>
/// is linear, empty, or has a negative <see cref="Size"/>.
- /// See also <see cref="GetVolume"/>.
+ /// See also <see cref="Volume"/>.
/// </summary>
/// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has volume.
+ /// A <see langword="bool"/> for whether or not the <see cref="Aabb"/> has volume.
/// </returns>
- public bool HasVolume()
+ public readonly bool HasVolume()
{
- return _size.x > 0.0f && _size.y > 0.0f && _size.z > 0.0f;
+ return _size.X > 0.0f && _size.Y > 0.0f && _size.Z > 0.0f;
}
/// <summary>
- /// Returns the intersection of this <see cref="AABB"/> and <paramref name="with"/>.
+ /// Returns the intersection of this <see cref="Aabb"/> and <paramref name="with"/>.
/// </summary>
- /// <param name="with">The other <see cref="AABB"/>.</param>
- /// <returns>The clipped <see cref="AABB"/>.</returns>
- public AABB Intersection(AABB with)
+ /// <param name="with">The other <see cref="Aabb"/>.</param>
+ /// <returns>The clipped <see cref="Aabb"/>.</returns>
+ public readonly Aabb Intersection(Aabb with)
{
Vector3 srcMin = _position;
Vector3 srcMax = _position + _size;
@@ -407,101 +407,78 @@ namespace Godot
Vector3 min, max;
- if (srcMin.x > dstMax.x || srcMax.x < dstMin.x)
+ if (srcMin.X > dstMax.X || srcMax.X < dstMin.X)
{
- return new AABB();
+ return new Aabb();
}
- min.x = srcMin.x > dstMin.x ? srcMin.x : dstMin.x;
- max.x = srcMax.x < dstMax.x ? srcMax.x : dstMax.x;
+ min.X = srcMin.X > dstMin.X ? srcMin.X : dstMin.X;
+ max.X = srcMax.X < dstMax.X ? srcMax.X : dstMax.X;
- if (srcMin.y > dstMax.y || srcMax.y < dstMin.y)
+ if (srcMin.Y > dstMax.Y || srcMax.Y < dstMin.Y)
{
- return new AABB();
+ return new Aabb();
}
- min.y = srcMin.y > dstMin.y ? srcMin.y : dstMin.y;
- max.y = srcMax.y < dstMax.y ? srcMax.y : dstMax.y;
+ min.Y = srcMin.Y > dstMin.Y ? srcMin.Y : dstMin.Y;
+ max.Y = srcMax.Y < dstMax.Y ? srcMax.Y : dstMax.Y;
- if (srcMin.z > dstMax.z || srcMax.z < dstMin.z)
+ if (srcMin.Z > dstMax.Z || srcMax.Z < dstMin.Z)
{
- return new AABB();
+ return new Aabb();
}
- min.z = srcMin.z > dstMin.z ? srcMin.z : dstMin.z;
- max.z = srcMax.z < dstMax.z ? srcMax.z : dstMax.z;
+ min.Z = srcMin.Z > dstMin.Z ? srcMin.Z : dstMin.Z;
+ max.Z = srcMax.Z < dstMax.Z ? srcMax.Z : dstMax.Z;
- return new AABB(min, max - min);
+ return new Aabb(min, max - min);
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="AABB"/> overlaps with <paramref name="with"/>
+ /// Returns <see langword="true"/> if the <see cref="Aabb"/> overlaps with <paramref name="with"/>
/// (i.e. they have at least one point in common).
- ///
- /// If <paramref name="includeBorders"/> is <see langword="true"/>,
- /// they will also be considered overlapping if their borders touch,
- /// even without intersection.
/// </summary>
- /// <param name="with">The other <see cref="AABB"/> to check for intersections with.</param>
- /// <param name="includeBorders">Whether or not to consider borders.</param>
+ /// <param name="with">The other <see cref="Aabb"/> to check for intersections with.</param>
/// <returns>
/// A <see langword="bool"/> for whether or not they are intersecting.
/// </returns>
- public bool Intersects(AABB with, bool includeBorders = false)
+ public readonly bool Intersects(Aabb with)
{
- if (includeBorders)
- {
- if (_position.x > with._position.x + with._size.x)
- return false;
- if (_position.x + _size.x < with._position.x)
- return false;
- if (_position.y > with._position.y + with._size.y)
- return false;
- if (_position.y + _size.y < with._position.y)
- return false;
- if (_position.z > with._position.z + with._size.z)
- return false;
- if (_position.z + _size.z < with._position.z)
- return false;
- }
- else
- {
- if (_position.x >= with._position.x + with._size.x)
- return false;
- if (_position.x + _size.x <= with._position.x)
- return false;
- if (_position.y >= with._position.y + with._size.y)
- return false;
- if (_position.y + _size.y <= with._position.y)
- return false;
- if (_position.z >= with._position.z + with._size.z)
- return false;
- if (_position.z + _size.z <= with._position.z)
- return false;
- }
+ if (_position.X >= with._position.X + with._size.X)
+ return false;
+ if (_position.X + _size.X <= with._position.X)
+ return false;
+ if (_position.Y >= with._position.Y + with._size.Y)
+ return false;
+ if (_position.Y + _size.Y <= with._position.Y)
+ return false;
+ if (_position.Z >= with._position.Z + with._size.Z)
+ return false;
+ if (_position.Z + _size.Z <= with._position.Z)
+ return false;
return true;
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="AABB"/> is on both sides of <paramref name="plane"/>.
+ /// Returns <see langword="true"/> if the <see cref="Aabb"/> is on both sides of <paramref name="plane"/>.
/// </summary>
/// <param name="plane">The <see cref="Plane"/> to check for intersection.</param>
/// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> intersects the <see cref="Plane"/>.
+ /// A <see langword="bool"/> for whether or not the <see cref="Aabb"/> intersects the <see cref="Plane"/>.
/// </returns>
- public bool IntersectsPlane(Plane plane)
+ public readonly bool IntersectsPlane(Plane plane)
{
Vector3[] points =
{
- new Vector3(_position.x, _position.y, _position.z),
- new Vector3(_position.x, _position.y, _position.z + _size.z),
- new Vector3(_position.x, _position.y + _size.y, _position.z),
- new Vector3(_position.x, _position.y + _size.y, _position.z + _size.z),
- new Vector3(_position.x + _size.x, _position.y, _position.z),
- new Vector3(_position.x + _size.x, _position.y, _position.z + _size.z),
- new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z),
- new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z + _size.z)
+ new Vector3(_position.X, _position.Y, _position.Z),
+ new Vector3(_position.X, _position.Y, _position.Z + _size.Z),
+ new Vector3(_position.X, _position.Y + _size.Y, _position.Z),
+ new Vector3(_position.X, _position.Y + _size.Y, _position.Z + _size.Z),
+ new Vector3(_position.X + _size.X, _position.Y, _position.Z),
+ new Vector3(_position.X + _size.X, _position.Y, _position.Z + _size.Z),
+ new Vector3(_position.X + _size.X, _position.Y + _size.Y, _position.Z),
+ new Vector3(_position.X + _size.X, _position.Y + _size.Y, _position.Z + _size.Z)
};
bool over = false;
@@ -523,15 +500,15 @@ namespace Godot
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="AABB"/> intersects
+ /// Returns <see langword="true"/> if the <see cref="Aabb"/> intersects
/// the line segment between <paramref name="from"/> and <paramref name="to"/>.
/// </summary>
/// <param name="from">The start of the line segment.</param>
/// <param name="to">The end of the line segment.</param>
/// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> intersects the line segment.
+ /// A <see langword="bool"/> for whether or not the <see cref="Aabb"/> intersects the line segment.
/// </returns>
- public bool IntersectsSegment(Vector3 from, Vector3 to)
+ public readonly bool IntersectsSegment(Vector3 from, Vector3 to)
{
real_t min = 0f;
real_t max = 1f;
@@ -586,73 +563,83 @@ namespace Godot
}
/// <summary>
- /// Returns a larger <see cref="AABB"/> that contains this <see cref="AABB"/> and <paramref name="with"/>.
+ /// Returns <see langword="true"/> if this <see cref="Aabb"/> is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return _position.IsFinite() && _size.IsFinite();
+ }
+
+ /// <summary>
+ /// Returns a larger <see cref="Aabb"/> that contains this <see cref="Aabb"/> and <paramref name="with"/>.
/// </summary>
- /// <param name="with">The other <see cref="AABB"/>.</param>
- /// <returns>The merged <see cref="AABB"/>.</returns>
- public AABB Merge(AABB with)
+ /// <param name="with">The other <see cref="Aabb"/>.</param>
+ /// <returns>The merged <see cref="Aabb"/>.</returns>
+ public readonly Aabb Merge(Aabb with)
{
Vector3 beg1 = _position;
Vector3 beg2 = with._position;
- var end1 = new Vector3(_size.x, _size.y, _size.z) + beg1;
- var end2 = new Vector3(with._size.x, with._size.y, with._size.z) + beg2;
+ var end1 = new Vector3(_size.X, _size.Y, _size.Z) + beg1;
+ var end2 = new Vector3(with._size.X, with._size.Y, with._size.Z) + beg2;
var min = new Vector3(
- beg1.x < beg2.x ? beg1.x : beg2.x,
- beg1.y < beg2.y ? beg1.y : beg2.y,
- beg1.z < beg2.z ? beg1.z : beg2.z
+ beg1.X < beg2.X ? beg1.X : beg2.X,
+ beg1.Y < beg2.Y ? beg1.Y : beg2.Y,
+ beg1.Z < beg2.Z ? beg1.Z : beg2.Z
);
var max = new Vector3(
- end1.x > end2.x ? end1.x : end2.x,
- end1.y > end2.y ? end1.y : end2.y,
- end1.z > end2.z ? end1.z : end2.z
+ end1.X > end2.X ? end1.X : end2.X,
+ end1.Y > end2.Y ? end1.Y : end2.Y,
+ end1.Z > end2.Z ? end1.Z : end2.Z
);
- return new AABB(min, max - min);
+ return new Aabb(min, max - min);
}
/// <summary>
- /// Constructs an <see cref="AABB"/> from a position and size.
+ /// Constructs an <see cref="Aabb"/> from a position and size.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="size">The size, typically positive.</param>
- public AABB(Vector3 position, Vector3 size)
+ public Aabb(Vector3 position, Vector3 size)
{
_position = position;
_size = size;
}
/// <summary>
- /// Constructs an <see cref="AABB"/> from a <paramref name="position"/>,
+ /// Constructs an <see cref="Aabb"/> from a <paramref name="position"/>,
/// <paramref name="width"/>, <paramref name="height"/>, and <paramref name="depth"/>.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="width">The width, typically positive.</param>
/// <param name="height">The height, typically positive.</param>
/// <param name="depth">The depth, typically positive.</param>
- public AABB(Vector3 position, real_t width, real_t height, real_t depth)
+ public Aabb(Vector3 position, real_t width, real_t height, real_t depth)
{
_position = position;
_size = new Vector3(width, height, depth);
}
/// <summary>
- /// Constructs an <see cref="AABB"/> from <paramref name="x"/>,
+ /// Constructs an <see cref="Aabb"/> from <paramref name="x"/>,
/// <paramref name="y"/>, <paramref name="z"/>, and <paramref name="size"/>.
/// </summary>
/// <param name="x">The position's X coordinate.</param>
/// <param name="y">The position's Y coordinate.</param>
/// <param name="z">The position's Z coordinate.</param>
/// <param name="size">The size, typically positive.</param>
- public AABB(real_t x, real_t y, real_t z, Vector3 size)
+ public Aabb(real_t x, real_t y, real_t z, Vector3 size)
{
_position = new Vector3(x, y, z);
_size = size;
}
/// <summary>
- /// Constructs an <see cref="AABB"/> from <paramref name="x"/>,
+ /// Constructs an <see cref="Aabb"/> from <paramref name="x"/>,
/// <paramref name="y"/>, <paramref name="z"/>, <paramref name="width"/>,
/// <paramref name="height"/>, and <paramref name="depth"/>.
/// </summary>
@@ -662,7 +649,7 @@ namespace Godot
/// <param name="width">The width, typically positive.</param>
/// <param name="height">The height, typically positive.</param>
/// <param name="depth">The depth, typically positive.</param>
- public AABB(real_t x, real_t y, real_t z, real_t width, real_t height, real_t depth)
+ public Aabb(real_t x, real_t y, real_t z, real_t width, real_t height, real_t depth)
{
_position = new Vector3(x, y, z);
_size = new Vector3(width, height, depth);
@@ -676,7 +663,7 @@ namespace Godot
/// <param name="left">The left AABB.</param>
/// <param name="right">The right AABB.</param>
/// <returns>Whether or not the AABBs are exactly equal.</returns>
- public static bool operator ==(AABB left, AABB right)
+ public static bool operator ==(Aabb left, Aabb right)
{
return left.Equals(right);
}
@@ -689,7 +676,7 @@ namespace Godot
/// <param name="left">The left AABB.</param>
/// <param name="right">The right AABB.</param>
/// <returns>Whether or not the AABBs are not equal.</returns>
- public static bool operator !=(AABB left, AABB right)
+ public static bool operator !=(Aabb left, Aabb right)
{
return !left.Equals(right);
}
@@ -702,9 +689,9 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the AABB and the object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
- return obj is AABB other && Equals(other);
+ return obj is Aabb other && Equals(other);
}
/// <summary>
@@ -714,7 +701,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other AABB.</param>
/// <returns>Whether or not the AABBs are exactly equal.</returns>
- public bool Equals(AABB other)
+ public readonly bool Equals(Aabb other)
{
return _position == other._position && _size == other._size;
}
@@ -725,34 +712,34 @@ namespace Godot
/// </summary>
/// <param name="other">The other AABB to compare.</param>
/// <returns>Whether or not the AABBs structures are approximately equal.</returns>
- public bool IsEqualApprox(AABB other)
+ public readonly bool IsEqualApprox(Aabb other)
{
return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other._size);
}
/// <summary>
- /// Serves as the hash function for <see cref="AABB"/>.
+ /// Serves as the hash function for <see cref="Aabb"/>.
/// </summary>
/// <returns>A hash code for this AABB.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
return _position.GetHashCode() ^ _size.GetHashCode();
}
/// <summary>
- /// Converts this <see cref="AABB"/> to a string.
+ /// Converts this <see cref="Aabb"/> to a string.
/// </summary>
/// <returns>A string representation of this AABB.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
return $"{_position}, {_size}";
}
/// <summary>
- /// Converts this <see cref="AABB"/> to a string with the given <paramref name="format"/>.
+ /// Converts this <see cref="Aabb"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this AABB.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
return $"{_position.ToString(format)}, {_size.ToString(format)}";
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index f1b46e293b..8598c32760 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
@@ -99,7 +100,7 @@ namespace Godot.Collections
this[i] = array[i];
}
- public Array(Span<RID> array) : this()
+ public Array(Span<Rid> array) : this()
{
if (array == null)
throw new ArgumentNullException(nameof(array));
@@ -120,7 +121,7 @@ namespace Godot.Collections
// fine as long as the array is not mutated. However, Span does this type checking at
// instantiation, so it's not possible to use it even when not mutating anything.
// ReSharper disable once RedundantNameQualifier
- public Array(ReadOnlySpan<Godot.Object> array) : this()
+ public Array(ReadOnlySpan<GodotObject> array) : this()
{
if (array == null)
throw new ArgumentNullException(nameof(array));
@@ -174,7 +175,15 @@ namespace Godot.Collections
}
/// <summary>
- /// Duplicates this <see cref="Array"/>.
+ /// Returns a copy of the <see cref="Array"/>.
+ /// If <paramref name="deep"/> is <see langword="true"/>, a deep copy if performed:
+ /// all nested arrays and dictionaries are duplicated and will not be shared with
+ /// the original array. If <see langword="false"/>, a shallow copy is made and
+ /// references to the original nested arrays and dictionaries are kept, so that
+ /// modifying a sub-array or dictionary in the copy will also impact those
+ /// referenced in the source array. Note that any <see cref="GodotObject"/> derived
+ /// elements will be shallow copied regardless of the <paramref name="deep"/>
+ /// setting.
/// </summary>
/// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
/// <returns>A new Godot Array.</returns>
@@ -187,27 +196,247 @@ namespace Godot.Collections
}
/// <summary>
- /// Resizes this <see cref="Array"/> to the given size.
+ /// Assigns the given value to all elements in the array. This can typically be
+ /// used together with <see cref="Resize(int)"/> to create an array with a given
+ /// size and initialized elements.
+ /// Note: If <paramref name="value"/> is of a reference type (<see cref="GodotObject"/>
+ /// derived, <see cref="Array"/> or <see cref="Dictionary"/>, etc.) then the array
+ /// is filled with the references to the same object, i.e. no duplicates are
+ /// created.
/// </summary>
+ /// <example>
+ /// <code>
+ /// var array = new Godot.Collections.Array();
+ /// array.Resize(10);
+ /// array.Fill(0); // Initialize the 10 elements to 0.
+ /// </code>
+ /// </example>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <param name="value">The value to fill the array with.</param>
+ public void Fill(Variant value)
+ {
+ ThrowIfReadOnly();
+
+ godot_variant variantValue = (godot_variant)value.NativeVar;
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_fill(ref self, variantValue);
+ }
+
+ /// <summary>
+ /// Returns the maximum value contained in the array if all elements are of
+ /// comparable types. If the elements can't be compared, <see langword="null"/>
+ /// is returned.
+ /// </summary>
+ /// <returns>The maximum value contained in the array.</returns>
+ public Variant Max()
+ {
+ godot_variant resVariant;
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_max(ref self, out resVariant);
+ return Variant.CreateTakingOwnershipOfDisposableValue(resVariant);
+ }
+
+ /// <summary>
+ /// Returns the minimum value contained in the array if all elements are of
+ /// comparable types. If the elements can't be compared, <see langword="null"/>
+ /// is returned.
+ /// </summary>
+ /// <returns>The minimum value contained in the array.</returns>
+ public Variant Min()
+ {
+ godot_variant resVariant;
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_min(ref self, out resVariant);
+ return Variant.CreateTakingOwnershipOfDisposableValue(resVariant);
+ }
+
+ /// <summary>
+ /// Returns a random value from the target array.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// var array = new Godot.Collections.Array { 1, 2, 3, 4 };
+ /// GD.Print(array.PickRandom()); // Prints either of the four numbers.
+ /// </code>
+ /// </example>
+ /// <returns>A random element from the array.</returns>
+ public Variant PickRandom()
+ {
+ godot_variant resVariant;
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_pick_random(ref self, out resVariant);
+ return Variant.CreateTakingOwnershipOfDisposableValue(resVariant);
+ }
+
+ /// <summary>
+ /// Compares this <see cref="Array"/> against the <paramref name="other"/>
+ /// <see cref="Array"/> recursively. Returns <see langword="true"/> if the
+ /// sizes and contents of the arrays are equal, <see langword="false"/>
+ /// otherwise.
+ /// </summary>
+ /// <param name="other">The other array to compare against.</param>
+ /// <returns>
+ /// <see langword="true"/> if the sizes and contents of the arrays are equal,
+ /// <see langword="false"/> otherwise.
+ /// </returns>
+ public bool RecursiveEqual(Array other)
+ {
+ var self = (godot_array)NativeValue;
+ var otherVariant = (godot_array)other.NativeValue;
+ return NativeFuncs.godotsharp_array_recursive_equal(ref self, otherVariant).ToBool();
+ }
+
+ /// <summary>
+ /// Resizes the array to contain a different number of elements. If the array
+ /// size is smaller, elements are cleared, if bigger, new elements are
+ /// <see langword="null"/>.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
/// <param name="newSize">The new size of the array.</param>
/// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns>
public Error Resize(int newSize)
{
+ ThrowIfReadOnly();
+
var self = (godot_array)NativeValue;
return NativeFuncs.godotsharp_array_resize(ref self, newSize);
}
/// <summary>
- /// Shuffles the contents of this <see cref="Array"/> into a random order.
+ /// Reverses the order of the elements in the array.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ public void Reverse()
+ {
+ ThrowIfReadOnly();
+
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_reverse(ref self);
+ }
+
+ /// <summary>
+ /// Shuffles the array such that the items will have a random order.
+ /// This method uses the global random number generator common to methods
+ /// such as <see cref="GD.Randi"/>. Call <see cref="GD.Randomize"/> to
+ /// ensure that a new seed will be used each time if you want
+ /// non-reproducible shuffling.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
public void Shuffle()
{
+ ThrowIfReadOnly();
+
var self = (godot_array)NativeValue;
NativeFuncs.godotsharp_array_shuffle(ref self);
}
/// <summary>
- /// Concatenates these two <see cref="Array"/>s.
+ /// Creates a shallow copy of a range of elements in the source <see cref="Array"/>.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="start"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <param name="start">The zero-based index at which the range starts.</param>
+ /// <returns>A new array that contains the elements inside the slice range.</returns>
+ public Array Slice(int start)
+ {
+ if (start < 0 || start > Count)
+ throw new ArgumentOutOfRangeException(nameof(start));
+
+ return GetSliceRange(start, Count, step: 1, deep: false);
+ }
+
+ /// <summary>
+ /// Creates a shallow copy of a range of elements in the source <see cref="Array"/>.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="start"/> is less than 0 or greater than the array's size.
+ /// -or-
+ /// <paramref name="length"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <param name="start">The zero-based index at which the range starts.</param>
+ /// <param name="length">The length of the range.</param>
+ /// <returns>A new array that contains the elements inside the slice range.</returns>
+ // The Slice method must have this signature to get implicit Range support.
+ public Array Slice(int start, int length)
+ {
+ if (start < 0 || start > Count)
+ throw new ArgumentOutOfRangeException(nameof(start));
+
+ if (length < 0 || length > Count)
+ throw new ArgumentOutOfRangeException(nameof(start));
+
+ return GetSliceRange(start, start + length, step: 1, deep: false);
+ }
+
+ /// <summary>
+ /// Returns the slice of the <see cref="Array"/>, from <paramref name="start"/>
+ /// (inclusive) to <paramref name="end"/> (exclusive), as a new <see cref="Array"/>.
+ /// The absolute value of <paramref name="start"/> and <paramref name="end"/>
+ /// will be clamped to the array size.
+ /// If either <paramref name="start"/> or <paramref name="end"/> are negative, they
+ /// will be relative to the end of the array (i.e. <c>arr.GetSliceRange(0, -2)</c>
+ /// is a shorthand for <c>arr.GetSliceRange(0, arr.Count - 2)</c>).
+ /// If specified, <paramref name="step"/> is the relative index between source
+ /// elements. It can be negative, then <paramref name="start"/> must be higher than
+ /// <paramref name="end"/>. For example, <c>[0, 1, 2, 3, 4, 5].GetSliceRange(5, 1, -2)</c>
+ /// returns <c>[5, 3]</c>.
+ /// If <paramref name="deep"/> is true, each element will be copied by value
+ /// rather than by reference.
+ /// </summary>
+ /// <param name="start">The zero-based index at which the range starts.</param>
+ /// <param name="end">The zero-based index at which the range ends.</param>
+ /// <param name="step">The relative index between source elements to take.</param>
+ /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
+ /// <returns>A new array that contains the elements inside the slice range.</returns>
+ public Array GetSliceRange(int start, int end, int step = 1, bool deep = false)
+ {
+ godot_array newArray;
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_slice(ref self, start, end, step, deep.ToGodotBool(), out newArray);
+ return CreateTakingOwnershipOfDisposableValue(newArray);
+ }
+
+ /// <summary>
+ /// Sorts the array.
+ /// Note: The sorting algorithm used is not stable. This means that values
+ /// considered equal may have their order changed when using <see cref="Sort"/>.
+ /// Note: Strings are sorted in alphabetical order (as opposed to natural order).
+ /// This may lead to unexpected behavior when sorting an array of strings ending
+ /// with a sequence of numbers.
+ /// To sort with a custom predicate use
+ /// <see cref="Enumerable.OrderBy{TSource, TKey}(IEnumerable{TSource}, Func{TSource, TKey})"/>.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// var strings = new Godot.Collections.Array { "string1", "string2", "string10", "string11" };
+ /// strings.Sort();
+ /// GD.Print(strings); // Prints [string1, string10, string11, string2]
+ /// </code>
+ /// </example>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ public void Sort()
+ {
+ ThrowIfReadOnly();
+
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_sort(ref self);
+ }
+
+ /// <summary>
+ /// Concatenates two <see cref="Array"/>s together, with the <paramref name="right"/>
+ /// being added to the end of the <see cref="Array"/> specified in <paramref name="left"/>.
+ /// For example, <c>[1, 2] + [3, 4]</c> results in <c>[1, 2, 3, 4]</c>.
/// </summary>
/// <param name="left">The first array.</param>
/// <param name="right">The second array.</param>
@@ -240,6 +469,12 @@ namespace Godot.Collections
/// <summary>
/// Returns the item at the given <paramref name="index"/>.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The property is assigned and the array is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
/// <value>The <see cref="Variant"/> item at the given <paramref name="index"/>.</value>
public unsafe Variant this[int index]
{
@@ -250,8 +485,11 @@ namespace Godot.Collections
}
set
{
+ ThrowIfReadOnly();
+
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));
+
var self = (godot_array)NativeValue;
godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
godot_variant* itemPtr = &ptrw[index];
@@ -264,49 +502,271 @@ namespace Godot.Collections
/// Adds an item to the end of this <see cref="Array"/>.
/// This is the same as <c>append</c> or <c>push_back</c> in GDScript.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
/// <param name="item">The <see cref="Variant"/> item to add.</param>
public void Add(Variant item)
{
+ ThrowIfReadOnly();
+
godot_variant variantValue = (godot_variant)item.NativeVar;
var self = (godot_array)NativeValue;
_ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
}
/// <summary>
- /// Checks if this <see cref="Array"/> contains the given item.
+ /// Adds the elements of the specified collection to the end of this <see cref="Array"/>.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="collection"/> is <see langword="null"/>.
+ /// </exception>
+ /// <param name="collection">Collection of <see cref="Variant"/> items to add.</param>
+ public void AddRange<[MustBeVariant] T>(IEnumerable<T> collection)
+ {
+ ThrowIfReadOnly();
+
+ if (collection == null)
+ throw new ArgumentNullException(nameof(collection), "Value cannot be null.");
+
+ // If the collection is another Godot Array, we can add the items
+ // with a single interop call.
+ if (collection is Array array)
+ {
+ var self = (godot_array)NativeValue;
+ var collectionNative = (godot_array)array.NativeValue;
+ _ = NativeFuncs.godotsharp_array_add_range(ref self, collectionNative);
+ return;
+ }
+ if (collection is Array<T> typedArray)
+ {
+ var self = (godot_array)NativeValue;
+ var collectionNative = (godot_array)typedArray.NativeValue;
+ _ = NativeFuncs.godotsharp_array_add_range(ref self, collectionNative);
+ return;
+ }
+
+ // If we can retrieve the count of the collection without enumerating it
+ // (e.g.: the collections is a List<T>), use it to resize the array once
+ // instead of growing it as we add items.
+ if (collection.TryGetNonEnumeratedCount(out int count))
+ {
+ Resize(Count + count);
+
+ using var enumerator = collection.GetEnumerator();
+
+ for (int i = 0; i < count; i++)
+ {
+ enumerator.MoveNext();
+ this[count + i] = Variant.From(enumerator.Current);
+ }
+
+ return;
+ }
+
+ foreach (var item in collection)
+ {
+ Add(Variant.From(item));
+ }
+ }
+
+ /// <summary>
+ /// Finds the index of an existing value using binary search.
+ /// If the value is not present in the array, it returns the bitwise
+ /// complement of the insertion index that maintains sorting order.
+ /// Note: Calling <see cref="BinarySearch(int, int, Variant)"/> on an
+ /// unsorted array results in unexpected behavior.
/// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0.
+ /// -or-
+ /// <paramref name="count"/> is less than 0.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// <paramref name="index"/> and <paramref name="count"/> do not denote
+ /// a valid range in the <see cref="Array"/>.
+ /// </exception>
+ /// <param name="index">The starting index of the range to search.</param>
+ /// <param name="count">The length of the range to search.</param>
+ /// <param name="item">The object to locate.</param>
+ /// <returns>
+ /// The index of the item in the array, if <paramref name="item"/> is found;
+ /// otherwise, a negative number that is the bitwise complement of the index
+ /// of the next element that is larger than <paramref name="item"/> or, if
+ /// there is no larger element, the bitwise complement of <see cref="Count"/>.
+ /// </returns>
+ public int BinarySearch(int index, int count, Variant item)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index), "index cannot be negative.");
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(count), "count cannot be negative.");
+ if (Count - index < count)
+ throw new ArgumentException("length is out of bounds or count is greater than the number of elements.");
+
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ godot_variant variantValue = (godot_variant)item.NativeVar;
+ var self = (godot_array)NativeValue;
+ return NativeFuncs.godotsharp_array_binary_search(ref self, index, count, variantValue);
+ }
+
+ /// <summary>
+ /// Finds the index of an existing value using binary search.
+ /// If the value is not present in the array, it returns the bitwise
+ /// complement of the insertion index that maintains sorting order.
+ /// Note: Calling <see cref="BinarySearch(Variant)"/> on an unsorted
+ /// array results in unexpected behavior.
+ /// </summary>
+ /// <param name="item">The object to locate.</param>
+ /// <returns>
+ /// The index of the item in the array, if <paramref name="item"/> is found;
+ /// otherwise, a negative number that is the bitwise complement of the index
+ /// of the next element that is larger than <paramref name="item"/> or, if
+ /// there is no larger element, the bitwise complement of <see cref="Count"/>.
+ /// </returns>
+ public int BinarySearch(Variant item)
+ {
+ return BinarySearch(0, Count, item);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the array contains the given value.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// var arr = new Godot.Collections.Array { "inside", 7 };
+ /// GD.Print(arr.Contains("inside")); // True
+ /// GD.Print(arr.Contains("outside")); // False
+ /// GD.Print(arr.Contains(7)); // True
+ /// GD.Print(arr.Contains("7")); // False
+ /// </code>
+ /// </example>
/// <param name="item">The <see cref="Variant"/> item to look for.</param>
/// <returns>Whether or not this array contains the given item.</returns>
public bool Contains(Variant item) => IndexOf(item) != -1;
/// <summary>
- /// Erases all items from this <see cref="Array"/>.
+ /// Clears the array. This is the equivalent to using <see cref="Resize(int)"/>
+ /// with a size of <c>0</c>
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
public void Clear() => Resize(0);
/// <summary>
- /// Searches this <see cref="Array"/> for an item
- /// and returns its index or -1 if not found.
+ /// Searches the array for a value and returns its index or <c>-1</c> if not found.
/// </summary>
/// <param name="item">The <see cref="Variant"/> item to search for.</param>
/// <returns>The index of the item, or -1 if not found.</returns>
public int IndexOf(Variant item)
{
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
godot_variant variantValue = (godot_variant)item.NativeVar;
var self = (godot_array)NativeValue;
return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
}
/// <summary>
- /// Inserts a new item at a given position in the array.
- /// The position must be a valid position of an existing item,
- /// or the position at the end of the array.
+ /// Searches the array for a value and returns its index or <c>-1</c> if not found.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <param name="item">The <see cref="Variant"/> item to search for.</param>
+ /// <param name="index">The initial search index to start from.</param>
+ /// <returns>The index of the item, or -1 if not found.</returns>
+ public int IndexOf(Variant item, int index)
+ {
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ godot_variant variantValue = (godot_variant)item.NativeVar;
+ var self = (godot_array)NativeValue;
+ return NativeFuncs.godotsharp_array_index_of(ref self, variantValue, index);
+ }
+
+ /// <summary>
+ /// Searches the array for a value in reverse order and returns its index
+ /// or <c>-1</c> if not found.
+ /// </summary>
+ /// <param name="item">The <see cref="Variant"/> item to search for.</param>
+ /// <returns>The index of the item, or -1 if not found.</returns>
+ public int LastIndexOf(Variant item)
+ {
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ godot_variant variantValue = (godot_variant)item.NativeVar;
+ var self = (godot_array)NativeValue;
+ return NativeFuncs.godotsharp_array_last_index_of(ref self, variantValue, Count - 1);
+ }
+
+ /// <summary>
+ /// Searches the array for a value in reverse order and returns its index
+ /// or <c>-1</c> if not found.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <param name="item">The <see cref="Variant"/> item to search for.</param>
+ /// <param name="index">The initial search index to start from.</param>
+ /// <returns>The index of the item, or -1 if not found.</returns>
+ public int LastIndexOf(Variant item, int index)
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ godot_variant variantValue = (godot_variant)item.NativeVar;
+ var self = (godot_array)NativeValue;
+ return NativeFuncs.godotsharp_array_last_index_of(ref self, variantValue, index);
+ }
+
+ /// <summary>
+ /// Inserts a new element at a given position in the array. The position
+ /// must be valid, or at the end of the array (<c>pos == Count - 1</c>).
/// Existing items will be moved to the right.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
/// <param name="index">The index to insert at.</param>
/// <param name="item">The <see cref="Variant"/> item to insert.</param>
public void Insert(int index, Variant item)
{
+ ThrowIfReadOnly();
+
if (index < 0 || index > Count)
throw new ArgumentOutOfRangeException(nameof(index));
@@ -319,9 +779,14 @@ namespace Godot.Collections
/// Removes the first occurrence of the specified <paramref name="item"/>
/// from this <see cref="Array"/>.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
/// <param name="item">The value to remove.</param>
public bool Remove(Variant item)
{
+ ThrowIfReadOnly();
+
int index = IndexOf(item);
if (index >= 0)
{
@@ -333,11 +798,21 @@ namespace Godot.Collections
}
/// <summary>
- /// Removes an element from this <see cref="Array"/> by index.
+ /// Removes an element from the array by index.
+ /// To remove an element by searching for its value, use
+ /// <see cref="Remove(Variant)"/> instead.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
/// <param name="index">The index of the element to remove.</param>
public void RemoveAt(int index)
{
+ ThrowIfReadOnly();
+
if (index < 0 || index > Count)
throw new ArgumentOutOfRangeException(nameof(index));
@@ -358,12 +833,36 @@ namespace Godot.Collections
object ICollection.SyncRoot => false;
- bool ICollection<Variant>.IsReadOnly => false;
+ /// <summary>
+ /// Returns <see langword="true"/> if the array is read-only.
+ /// See <see cref="MakeReadOnly"/>.
+ /// </summary>
+ public bool IsReadOnly => NativeValue.DangerousSelfRef.IsReadOnly;
+
+ /// <summary>
+ /// Makes the <see cref="Array"/> read-only, i.e. disabled modying of the
+ /// array's elements. Does not apply to nested content, e.g. content of
+ /// nested arrays.
+ /// </summary>
+ public void MakeReadOnly()
+ {
+ if (IsReadOnly)
+ {
+ // Avoid interop call when the array is already read-only.
+ return;
+ }
+
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_make_read_only(ref self);
+ }
/// <summary>
/// Copies the elements of this <see cref="Array"/> to the given
/// <see cref="Variant"/> C# array, starting at the given index.
/// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="arrayIndex"/> is less than 0 or greater than the array's size.
+ /// </exception>
/// <param name="array">The array to copy to.</param>
/// <param name="arrayIndex">The index to start at.</param>
public void CopyTo(Variant[] array, int arrayIndex)
@@ -418,8 +917,8 @@ namespace Godot.Collections
{
for (int i = 0; i < count; i++)
{
- object obj = Marshaling.ConvertVariantToManagedObject(NativeValue.DangerousSelfRef.Elements[i]);
- array.SetValue(obj, index);
+ object boxedVariant = Variant.CreateCopyingBorrowed(NativeValue.DangerousSelfRef.Elements[i]);
+ array.SetValue(boxedVariant, index);
index++;
}
}
@@ -458,6 +957,9 @@ namespace Godot.Collections
/// <summary>
/// The variant returned via the <paramref name="elem"/> parameter is owned by the Array and must not be disposed.
/// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
internal void GetVariantBorrowElementAt(int index, out godot_variant elem)
{
if (index < 0 || index >= Count)
@@ -472,6 +974,19 @@ namespace Godot.Collections
{
elem = NativeValue.DangerousSelfRef.Elements[index];
}
+
+ private void ThrowIfReadOnly()
+ {
+ if (IsReadOnly)
+ {
+ throw new InvalidOperationException("Array instance is read-only.");
+ }
+ }
+ }
+
+ internal interface IGenericGodotArray
+ {
+ public Array UnderlyingArray { get; }
}
/// <summary>
@@ -487,47 +1002,25 @@ namespace Godot.Collections
IList<T>,
IReadOnlyList<T>,
ICollection<T>,
- IEnumerable<T>
+ IEnumerable<T>,
+ IGenericGodotArray
{
private static godot_variant ToVariantFunc(in Array<T> godotArray) =>
VariantUtils.CreateFromArray(godotArray);
private static Array<T> FromVariantFunc(in godot_variant variant) =>
- VariantUtils.ConvertToArrayObject<T>(variant);
-
- // ReSharper disable StaticMemberInGenericType
- // Warning is about unique static fields being created for each generic type combination:
- // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
- // In our case this is exactly what we want.
-
- private static readonly unsafe delegate* managed<in T, godot_variant> ConvertToVariantCallback;
- private static readonly unsafe delegate* managed<in godot_variant, T> ConvertToManagedCallback;
-
- // ReSharper restore StaticMemberInGenericType
+ VariantUtils.ConvertToArray<T>(variant);
static unsafe Array()
{
- VariantConversionCallbacks.GenericConversionCallbacks[typeof(Array<T>)] =
- (
- (IntPtr)(delegate* managed<in Array<T>, godot_variant>)&ToVariantFunc,
- (IntPtr)(delegate* managed<in godot_variant, Array<T>>)&FromVariantFunc
- );
-
- ConvertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
- ConvertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
- }
-
- private static unsafe void ValidateVariantConversionCallbacks()
- {
- if (ConvertToVariantCallback == null || ConvertToManagedCallback == null)
- {
- throw new InvalidOperationException(
- $"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'.");
- }
+ VariantUtils.GenericConversion<Array<T>>.ToVariantCb = &ToVariantFunc;
+ VariantUtils.GenericConversion<Array<T>>.FromVariantCb = &FromVariantFunc;
}
private readonly Array _underlyingArray;
+ Array IGenericGodotArray.UnderlyingArray => _underlyingArray;
+
internal ref godot_array.movable NativeValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -539,8 +1032,6 @@ namespace Godot.Collections
/// </summary>
public Array()
{
- ValidateVariantConversionCallbacks();
-
_underlyingArray = new Array();
}
@@ -551,8 +1042,6 @@ namespace Godot.Collections
/// <returns>A new Godot Array.</returns>
public Array(IEnumerable<T> collection)
{
- ValidateVariantConversionCallbacks();
-
if (collection == null)
throw new ArgumentNullException(nameof(collection));
@@ -569,8 +1058,6 @@ namespace Godot.Collections
/// <returns>A new Godot Array.</returns>
public Array(T[] array) : this()
{
- ValidateVariantConversionCallbacks();
-
if (array == null)
throw new ArgumentNullException(nameof(array));
@@ -586,8 +1073,6 @@ namespace Godot.Collections
/// <param name="array">The untyped array to construct from.</param>
public Array(Array array)
{
- ValidateVariantConversionCallbacks();
-
_underlyingArray = array;
}
@@ -615,8 +1100,102 @@ namespace Godot.Collections
}
/// <summary>
+ /// Assigns the given value to all elements in the array. This can typically be
+ /// used together with <see cref="Resize(int)"/> to create an array with a given
+ /// size and initialized elements.
+ /// Note: If <paramref name="value"/> is of a reference type (<see cref="GodotObject"/>
+ /// derived, <see cref="Array"/> or <see cref="Dictionary"/>, etc.) then the array
+ /// is filled with the references to the same object, i.e. no duplicates are
+ /// created.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// var array = new Godot.Collections.Array&lt;int&gt;();
+ /// array.Resize(10);
+ /// array.Fill(0); // Initialize the 10 elements to 0.
+ /// </code>
+ /// </example>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <param name="value">The value to fill the array with.</param>
+ public void Fill(T value)
+ {
+ ThrowIfReadOnly();
+
+ godot_variant variantValue = VariantUtils.CreateFrom(value);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ NativeFuncs.godotsharp_array_fill(ref self, variantValue);
+ }
+
+ /// <summary>
+ /// Returns the maximum value contained in the array if all elements are of
+ /// comparable types. If the elements can't be compared, <see langword="default"/>
+ /// is returned.
+ /// </summary>
+ /// <returns>The maximum value contained in the array.</returns>
+ public T Max()
+ {
+ godot_variant resVariant;
+ var self = (godot_array)_underlyingArray.NativeValue;
+ NativeFuncs.godotsharp_array_max(ref self, out resVariant);
+ return VariantUtils.ConvertTo<T>(resVariant);
+ }
+
+ /// <summary>
+ /// Returns the minimum value contained in the array if all elements are of
+ /// comparable types. If the elements can't be compared, <see langword="default"/>
+ /// is returned.
+ /// </summary>
+ /// <returns>The minimum value contained in the array.</returns>
+ public T Min()
+ {
+ godot_variant resVariant;
+ var self = (godot_array)_underlyingArray.NativeValue;
+ NativeFuncs.godotsharp_array_min(ref self, out resVariant);
+ return VariantUtils.ConvertTo<T>(resVariant);
+ }
+
+ /// <summary>
+ /// Returns a random value from the target array.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// var array = new Godot.Collections.Array&lt;int&gt; { 1, 2, 3, 4 };
+ /// GD.Print(array.PickRandom()); // Prints either of the four numbers.
+ /// </code>
+ /// </example>
+ /// <returns>A random element from the array.</returns>
+ public T PickRandom()
+ {
+ godot_variant resVariant;
+ var self = (godot_array)_underlyingArray.NativeValue;
+ NativeFuncs.godotsharp_array_pick_random(ref self, out resVariant);
+ return VariantUtils.ConvertTo<T>(resVariant);
+ }
+
+ /// <summary>
+ /// Compares this <see cref="Array{T}"/> against the <paramref name="other"/>
+ /// <see cref="Array{T}"/> recursively. Returns <see langword="true"/> if the
+ /// sizes and contents of the arrays are equal, <see langword="false"/>
+ /// otherwise.
+ /// </summary>
+ /// <param name="other">The other array to compare against.</param>
+ /// <returns>
+ /// <see langword="true"/> if the sizes and contents of the arrays are equal,
+ /// <see langword="false"/> otherwise.
+ /// </returns>
+ public bool RecursiveEqual(Array<T> other)
+ {
+ return _underlyingArray.RecursiveEqual(other._underlyingArray);
+ }
+
+ /// <summary>
/// Resizes this <see cref="Array{T}"/> to the given size.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
/// <param name="newSize">The new size of the array.</param>
/// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns>
public Error Resize(int newSize)
@@ -625,15 +1204,115 @@ namespace Godot.Collections
}
/// <summary>
- /// Shuffles the contents of this <see cref="Array{T}"/> into a random order.
+ /// Reverses the order of the elements in the array.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ public void Reverse()
+ {
+ _underlyingArray.Reverse();
+ }
+
+ /// <summary>
+ /// Shuffles the array such that the items will have a random order.
+ /// This method uses the global random number generator common to methods
+ /// such as <see cref="GD.Randi"/>. Call <see cref="GD.Randomize"/> to
+ /// ensure that a new seed will be used each time if you want
+ /// non-reproducible shuffling.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
public void Shuffle()
{
_underlyingArray.Shuffle();
}
/// <summary>
- /// Concatenates these two <see cref="Array{T}"/>s.
+ /// Creates a shallow copy of a range of elements in the source <see cref="Array{T}"/>.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="start"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <param name="start">The zero-based index at which the range starts.</param>
+ /// <returns>A new array that contains the elements inside the slice range.</returns>
+ public Array<T> Slice(int start)
+ {
+ return GetSliceRange(start, Count, step: 1, deep: false);
+ }
+
+ /// <summary>
+ /// Creates a shallow copy of a range of elements in the source <see cref="Array{T}"/>.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="start"/> is less than 0 or greater than the array's size.
+ /// -or-
+ /// <paramref name="length"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <param name="start">The zero-based index at which the range starts.</param>
+ /// <param name="length">The length of the range.</param>
+ /// <returns>A new array that contains the elements inside the slice range.</returns>
+ // The Slice method must have this signature to get implicit Range support.
+ public Array<T> Slice(int start, int length)
+ {
+ return GetSliceRange(start, start + length, step: 1, deep: false);
+ }
+
+ /// <summary>
+ /// Returns the slice of the <see cref="Array{T}"/>, from <paramref name="start"/>
+ /// (inclusive) to <paramref name="end"/> (exclusive), as a new <see cref="Array{T}"/>.
+ /// The absolute value of <paramref name="start"/> and <paramref name="end"/>
+ /// will be clamped to the array size.
+ /// If either <paramref name="start"/> or <paramref name="end"/> are negative, they
+ /// will be relative to the end of the array (i.e. <c>arr.GetSliceRange(0, -2)</c>
+ /// is a shorthand for <c>arr.GetSliceRange(0, arr.Count - 2)</c>).
+ /// If specified, <paramref name="step"/> is the relative index between source
+ /// elements. It can be negative, then <paramref name="start"/> must be higher than
+ /// <paramref name="end"/>. For example, <c>[0, 1, 2, 3, 4, 5].GetSliceRange(5, 1, -2)</c>
+ /// returns <c>[5, 3]</c>.
+ /// If <paramref name="deep"/> is true, each element will be copied by value
+ /// rather than by reference.
+ /// </summary>
+ /// <param name="start">The zero-based index at which the range starts.</param>
+ /// <param name="end">The zero-based index at which the range ends.</param>
+ /// <param name="step">The relative index between source elements to take.</param>
+ /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
+ /// <returns>A new array that contains the elements inside the slice range.</returns>
+ public Array<T> GetSliceRange(int start, int end, int step = 1, bool deep = false)
+ {
+ return new Array<T>(_underlyingArray.GetSliceRange(start, end, step, deep));
+ }
+
+ /// <summary>
+ /// Sorts the array.
+ /// Note: The sorting algorithm used is not stable. This means that values
+ /// considered equal may have their order changed when using <see cref="Sort"/>.
+ /// Note: Strings are sorted in alphabetical order (as opposed to natural order).
+ /// This may lead to unexpected behavior when sorting an array of strings ending
+ /// with a sequence of numbers.
+ /// To sort with a custom predicate use
+ /// <see cref="Enumerable.OrderBy{TSource, TKey}(IEnumerable{TSource}, Func{TSource, TKey})"/>.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// var strings = new Godot.Collections.Array&lt;string&gt; { "string1", "string2", "string10", "string11" };
+ /// strings.Sort();
+ /// GD.Print(strings); // Prints [string1, string10, string11, string2]
+ /// </code>
+ /// </example>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ public void Sort()
+ {
+ _underlyingArray.Sort();
+ }
+
+ /// <summary>
+ /// Concatenates two <see cref="Array{T}"/>s together, with the <paramref name="right"/>
+ /// being added to the end of the <see cref="Array{T}"/> specified in <paramref name="left"/>.
+ /// For example, <c>[1, 2] + [3, 4]</c> results in <c>[1, 2, 3, 4]</c>.
/// </summary>
/// <param name="left">The first array.</param>
/// <param name="right">The second array.</param>
@@ -657,62 +1336,161 @@ namespace Godot.Collections
// IList<T>
/// <summary>
- /// Returns the value at the given <paramref name="index"/>.
+ /// Returns the item at the given <paramref name="index"/>.
/// </summary>
- /// <value>The value at the given <paramref name="index"/>.</value>
+ /// <exception cref="InvalidOperationException">
+ /// The property is assigned and the array is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <value>The <see cref="Variant"/> item at the given <paramref name="index"/>.</value>
public unsafe T this[int index]
{
get
{
_underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem);
- return ConvertToManagedCallback(borrowElem);
+ return VariantUtils.ConvertTo<T>(borrowElem);
}
set
{
+ ThrowIfReadOnly();
+
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));
+
var self = (godot_array)_underlyingArray.NativeValue;
godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
godot_variant* itemPtr = &ptrw[index];
(*itemPtr).Dispose();
- *itemPtr = ConvertToVariantCallback(value);
+ *itemPtr = VariantUtils.CreateFrom(value);
}
}
/// <summary>
- /// Searches this <see cref="Array{T}"/> for an item
- /// and returns its index or -1 if not found.
+ /// Searches the array for a value and returns its index or <c>-1</c> if not found.
/// </summary>
- /// <param name="item">The item to search for.</param>
+ /// <param name="item">The <see cref="Variant"/> item to search for.</param>
/// <returns>The index of the item, or -1 if not found.</returns>
- public unsafe int IndexOf(T item)
+ public int IndexOf(T item)
{
- using var variantValue = ConvertToVariantCallback(item);
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ using var variantValue = VariantUtils.CreateFrom(item);
var self = (godot_array)_underlyingArray.NativeValue;
return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
}
/// <summary>
- /// Inserts a new item at a given position in the <see cref="Array{T}"/>.
- /// The position must be a valid position of an existing item,
- /// or the position at the end of the array.
+ /// Searches the array for a value and returns its index or <c>-1</c> if not found.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <param name="item">The <see cref="Variant"/> item to search for.</param>
+ /// <param name="index">The initial search index to start from.</param>
+ /// <returns>The index of the item, or -1 if not found.</returns>
+ public int IndexOf(T item, int index)
+ {
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ godot_variant variantValue = VariantUtils.CreateFrom(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ return NativeFuncs.godotsharp_array_index_of(ref self, variantValue, index);
+ }
+
+ /// <summary>
+ /// Searches the array for a value in reverse order and returns its index
+ /// or <c>-1</c> if not found.
+ /// </summary>
+ /// <param name="item">The <see cref="Variant"/> item to search for.</param>
+ /// <returns>The index of the item, or -1 if not found.</returns>
+ public int LastIndexOf(Variant item)
+ {
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ godot_variant variantValue = VariantUtils.CreateFrom(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ return NativeFuncs.godotsharp_array_last_index_of(ref self, variantValue, Count - 1);
+ }
+
+ /// <summary>
+ /// Searches the array for a value in reverse order and returns its index
+ /// or <c>-1</c> if not found.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <param name="item">The <see cref="Variant"/> item to search for.</param>
+ /// <param name="index">The initial search index to start from.</param>
+ /// <returns>The index of the item, or -1 if not found.</returns>
+ public int LastIndexOf(Variant item, int index)
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ godot_variant variantValue = VariantUtils.CreateFrom(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ return NativeFuncs.godotsharp_array_last_index_of(ref self, variantValue, index);
+ }
+
+ /// <summary>
+ /// Inserts a new element at a given position in the array. The position
+ /// must be valid, or at the end of the array (<c>pos == Count - 1</c>).
/// Existing items will be moved to the right.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
/// <param name="index">The index to insert at.</param>
- /// <param name="item">The item to insert.</param>
- public unsafe void Insert(int index, T item)
+ /// <param name="item">The <see cref="Variant"/> item to insert.</param>
+ public void Insert(int index, T item)
{
+ ThrowIfReadOnly();
+
if (index < 0 || index > Count)
throw new ArgumentOutOfRangeException(nameof(index));
- using var variantValue = ConvertToVariantCallback(item);
+ using var variantValue = VariantUtils.CreateFrom(item);
var self = (godot_array)_underlyingArray.NativeValue;
NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
}
/// <summary>
- /// Removes an element from this <see cref="Array{T}"/> by index.
+ /// Removes an element from the array by index.
+ /// To remove an element by searching for its value, use
+ /// <see cref="Remove(T)"/> instead.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0 or greater than the array's size.
+ /// </exception>
/// <param name="index">The index of the element to remove.</param>
public void RemoveAt(int index)
{
@@ -728,32 +1506,185 @@ namespace Godot.Collections
/// <returns>The number of elements.</returns>
public int Count => _underlyingArray.Count;
- bool ICollection<T>.IsReadOnly => false;
+ /// <summary>
+ /// Returns <see langword="true"/> if the array is read-only.
+ /// See <see cref="MakeReadOnly"/>.
+ /// </summary>
+ public bool IsReadOnly => _underlyingArray.IsReadOnly;
+
+ /// <summary>
+ /// Makes the <see cref="Array{T}"/> read-only, i.e. disabled modying of the
+ /// array's elements. Does not apply to nested content, e.g. content of
+ /// nested arrays.
+ /// </summary>
+ public void MakeReadOnly()
+ {
+ _underlyingArray.MakeReadOnly();
+ }
/// <summary>
/// Adds an item to the end of this <see cref="Array{T}"/>.
/// This is the same as <c>append</c> or <c>push_back</c> in GDScript.
/// </summary>
- /// <param name="item">The item to add.</param>
- /// <returns>The new size after adding the item.</returns>
- public unsafe void Add(T item)
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <param name="item">The <see cref="Variant"/> item to add.</param>
+ public void Add(T item)
{
- using var variantValue = ConvertToVariantCallback(item);
+ ThrowIfReadOnly();
+
+ using var variantValue = VariantUtils.CreateFrom(item);
var self = (godot_array)_underlyingArray.NativeValue;
_ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
}
/// <summary>
- /// Erases all items from this <see cref="Array{T}"/>.
+ /// Adds the elements of the specified collection to the end of this <see cref="Array{T}"/>.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="collection"/> is <see langword="null"/>.
+ /// </exception>
+ /// <param name="collection">Collection of <see cref="Variant"/> items to add.</param>
+ public void AddRange(IEnumerable<T> collection)
+ {
+ ThrowIfReadOnly();
+
+ if (collection == null)
+ throw new ArgumentNullException(nameof(collection), "Value cannot be null.");
+
+ // If the collection is another Godot Array, we can add the items
+ // with a single interop call.
+ if (collection is Array array)
+ {
+ var self = (godot_array)_underlyingArray.NativeValue;
+ var collectionNative = (godot_array)array.NativeValue;
+ _ = NativeFuncs.godotsharp_array_add_range(ref self, collectionNative);
+ return;
+ }
+ if (collection is Array<T> typedArray)
+ {
+ var self = (godot_array)_underlyingArray.NativeValue;
+ var collectionNative = (godot_array)typedArray._underlyingArray.NativeValue;
+ _ = NativeFuncs.godotsharp_array_add_range(ref self, collectionNative);
+ return;
+ }
+
+ // If we can retrieve the count of the collection without enumerating it
+ // (e.g.: the collections is a List<T>), use it to resize the array once
+ // instead of growing it as we add items.
+ if (collection.TryGetNonEnumeratedCount(out int count))
+ {
+ Resize(Count + count);
+
+ using var enumerator = collection.GetEnumerator();
+
+ for (int i = 0; i < count; i++)
+ {
+ enumerator.MoveNext();
+ this[count + i] = enumerator.Current;
+ }
+
+ return;
+ }
+
+ foreach (var item in collection)
+ {
+ Add(item);
+ }
+ }
+
+ /// <summary>
+ /// Finds the index of an existing value using binary search.
+ /// If the value is not present in the array, it returns the bitwise
+ /// complement of the insertion index that maintains sorting order.
+ /// Note: Calling <see cref="BinarySearch(int, int, T)"/> on an unsorted
+ /// array results in unexpected behavior.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is less than 0.
+ /// -or-
+ /// <paramref name="count"/> is less than 0.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// <paramref name="index"/> and <paramref name="count"/> do not denote
+ /// a valid range in the <see cref="Array{T}"/>.
+ /// </exception>
+ /// <param name="index">The starting index of the range to search.</param>
+ /// <param name="count">The length of the range to search.</param>
+ /// <param name="item">The object to locate.</param>
+ /// <returns>
+ /// The index of the item in the array, if <paramref name="item"/> is found;
+ /// otherwise, a negative number that is the bitwise complement of the index
+ /// of the next element that is larger than <paramref name="item"/> or, if
+ /// there is no larger element, the bitwise complement of <see cref="Count"/>.
+ /// </returns>
+ public int BinarySearch(int index, int count, T item)
+ {
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index), "index cannot be negative.");
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(count), "count cannot be negative.");
+ if (Count - index < count)
+ throw new ArgumentException("length is out of bounds or count is greater than the number of elements.");
+
+ if (Count == 0)
+ {
+ // Special case for empty array to avoid an interop call.
+ return -1;
+ }
+
+ using var variantValue = VariantUtils.CreateFrom(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ return NativeFuncs.godotsharp_array_binary_search(ref self, index, count, variantValue);
+ }
+
+ /// <summary>
+ /// Finds the index of an existing value using binary search.
+ /// If the value is not present in the array, it returns the bitwise
+ /// complement of the insertion index that maintains sorting order.
+ /// Note: Calling <see cref="BinarySearch(T)"/> on an unsorted
+ /// array results in unexpected behavior.
+ /// </summary>
+ /// <param name="item">The object to locate.</param>
+ /// <returns>
+ /// The index of the item in the array, if <paramref name="item"/> is found;
+ /// otherwise, a negative number that is the bitwise complement of the index
+ /// of the next element that is larger than <paramref name="item"/> or, if
+ /// there is no larger element, the bitwise complement of <see cref="Count"/>.
+ /// </returns>
+ public int BinarySearch(T item)
+ {
+ return BinarySearch(0, Count, item);
+ }
+
+ /// <summary>
+ /// Clears the array. This is the equivalent to using <see cref="Resize(int)"/>
+ /// with a size of <c>0</c>
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
public void Clear()
{
_underlyingArray.Clear();
}
/// <summary>
- /// Checks if this <see cref="Array{T}"/> contains the given item.
+ /// Returns <see langword="true"/> if the array contains the given value.
/// </summary>
+ /// <example>
+ /// <code>
+ /// var arr = new Godot.Collections.Array&lt;string&gt; { "inside", "7" };
+ /// GD.Print(arr.Contains("inside")); // True
+ /// GD.Print(arr.Contains("outside")); // False
+ /// GD.Print(arr.Contains(7)); // False
+ /// GD.Print(arr.Contains("7")); // True
+ /// </code>
+ /// </example>
/// <param name="item">The item to look for.</param>
/// <returns>Whether or not this array contains the given item.</returns>
public bool Contains(T item) => IndexOf(item) != -1;
@@ -762,6 +1693,9 @@ namespace Godot.Collections
/// Copies the elements of this <see cref="Array{T}"/> to the given
/// C# array, starting at the given index.
/// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="arrayIndex"/> is less than 0 or greater than the array's size.
+ /// </exception>
/// <param name="array">The C# array to copy to.</param>
/// <param name="arrayIndex">The index to start at.</param>
public void CopyTo(T[] array, int arrayIndex)
@@ -791,13 +1725,18 @@ namespace Godot.Collections
}
/// <summary>
- /// Removes the first occurrence of the specified value
+ /// Removes the first occurrence of the specified <paramref name="item"/>
/// from this <see cref="Array{T}"/>.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The array is read-only.
+ /// </exception>
/// <param name="item">The value to remove.</param>
/// <returns>A <see langword="bool"/> indicating success or failure.</returns>
public bool Remove(T item)
{
+ ThrowIfReadOnly();
+
int index = IndexOf(item);
if (index >= 0)
{
@@ -837,5 +1776,13 @@ namespace Godot.Collections
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Array<T>(Variant from) => from.AsGodotArray<T>();
+
+ private void ThrowIfReadOnly()
+ {
+ if (IsReadOnly)
+ {
+ throw new InvalidOperationException("Array instance is read-only.");
+ }
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
index b7d633517a..81659f74de 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
@@ -1,20 +1,32 @@
using System;
+using System.Diagnostics.CodeAnalysis;
#nullable enable
namespace Godot
{
/// <summary>
- /// An attribute that determines if an assembly has scripts. If so, what types of scripts the assembly has.
+ /// Attribute that determines that the assembly contains Godot scripts and, optionally, the
+ /// collection of types that implement scripts; otherwise, retrieving the types requires lookup.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
- public class AssemblyHasScriptsAttribute : Attribute
+ public sealed class AssemblyHasScriptsAttribute : Attribute
{
+ /// <summary>
+ /// If the Godot scripts contained in the assembly require lookup
+ /// and can't rely on <see cref="ScriptTypes"/>.
+ /// </summary>
+ [MemberNotNullWhen(false, nameof(ScriptTypes))]
public bool RequiresLookup { get; }
+
+ /// <summary>
+ /// The collection of types that implement a Godot script.
+ /// </summary>
public Type[]? ScriptTypes { get; }
/// <summary>
- /// Constructs a new AssemblyHasScriptsAttribute instance.
+ /// Constructs a new AssemblyHasScriptsAttribute instance
+ /// that requires lookup to get the Godot scripts.
/// </summary>
public AssemblyHasScriptsAttribute()
{
@@ -23,9 +35,10 @@ namespace Godot
}
/// <summary>
- /// Constructs a new AssemblyHasScriptsAttribute instance.
+ /// Constructs a new AssemblyHasScriptsAttribute instance
+ /// that includes the Godot script types and requires no lookup.
/// </summary>
- /// <param name="scriptTypes">The specified type(s) of scripts.</param>
+ /// <param name="scriptTypes">The collection of types that implement a Godot script.</param>
public AssemblyHasScriptsAttribute(Type[] scriptTypes)
{
RequiresLookup = false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
index 3d204bdf9f..a48d79091f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
@@ -3,23 +3,30 @@ using System;
namespace Godot
{
/// <summary>
- /// An attribute used to export objects.
+ /// Exports the annotated member as a property of the Godot Object.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ExportAttribute : Attribute
{
- private PropertyHint hint;
- private string hintString;
+ /// <summary>
+ /// Optional hint that determines how the property should be handled by the editor.
+ /// </summary>
+ public PropertyHint Hint { get; }
+
+ /// <summary>
+ /// Optional string that can contain additional metadata for the <see cref="Hint"/>.
+ /// </summary>
+ public string HintString { get; }
/// <summary>
/// Constructs a new ExportAttribute Instance.
/// </summary>
- /// <param name="hint">A hint to the exported object.</param>
- /// <param name="hintString">A string representing the exported object.</param>
+ /// <param name="hint">The hint for the exported property.</param>
+ /// <param name="hintString">A string that may contain additional metadata for the hint.</param>
public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "")
{
- this.hint = hint;
- this.hintString = hintString;
+ Hint = hint;
+ HintString = hintString;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs
index 101e56f8d3..2ae55acd3e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs
@@ -8,7 +8,10 @@ namespace Godot
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ExportCategoryAttribute : Attribute
{
- private string name;
+ /// <summary>
+ /// Name of the category.
+ /// </summary>
+ public string Name { get; }
/// <summary>
/// Define a new category for the following exported properties.
@@ -16,7 +19,7 @@ namespace Godot
/// <param name="name">The name of the category.</param>
public ExportCategoryAttribute(string name)
{
- this.name = name;
+ Name = name;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs
index 3bd532cec1..82bd446640 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs
@@ -1,5 +1,7 @@
using System;
+#nullable enable
+
namespace Godot
{
/// <summary>
@@ -8,8 +10,15 @@ namespace Godot
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ExportGroupAttribute : Attribute
{
- private string name;
- private string prefix;
+ /// <summary>
+ /// Name of the group.
+ /// </summary>
+ public string Name { get; }
+
+ /// <summary>
+ /// If provided, the prefix that all properties must have to be considered part of the group.
+ /// </summary>
+ public string? Prefix { get; }
/// <summary>
/// Define a new group for the following exported properties.
@@ -18,8 +27,8 @@ namespace Godot
/// <param name="prefix">If provided, the group would make group to only consider properties that have this prefix.</param>
public ExportGroupAttribute(string name, string prefix = "")
{
- this.name = name;
- this.prefix = prefix;
+ Name = name;
+ Prefix = prefix;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs
index 2ae6eb0b68..3282b466f6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs
@@ -1,5 +1,7 @@
using System;
+#nullable enable
+
namespace Godot
{
/// <summary>
@@ -8,8 +10,15 @@ namespace Godot
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ExportSubgroupAttribute : Attribute
{
- private string name;
- private string prefix;
+ /// <summary>
+ /// Name of the subgroup.
+ /// </summary>
+ public string Name { get; }
+
+ /// <summary>
+ /// If provided, the prefix that all properties must have to be considered part of the subgroup.
+ /// </summary>
+ public string? Prefix { get; }
/// <summary>
/// Define a new subgroup for the following exported properties. This helps to organize properties in the Inspector dock.
@@ -18,8 +27,8 @@ namespace Godot
/// <param name="prefix">If provided, the subgroup would make group to only consider properties that have this prefix.</param>
public ExportSubgroupAttribute(string name, string prefix = "")
{
- this.name = name;
- this.prefix = prefix;
+ Name = name;
+ Prefix = prefix;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotClassNameAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotClassNameAttribute.cs
new file mode 100644
index 0000000000..b19427f60d
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotClassNameAttribute.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Godot
+{
+ /// <summary>
+ /// Attribute that specifies the engine class name when it's not the same
+ /// as the generated C# class name. This allows introspection code to find
+ /// the name associated with the class. If the attribute is not present,
+ /// the C# class name can be used instead.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class)]
+ public class GodotClassNameAttribute : Attribute
+ {
+ /// <summary>
+ /// Original engine class name.
+ /// </summary>
+ public string Name { get; }
+
+ public GodotClassNameAttribute(string name)
+ {
+ Name = name;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs
index 23088378d1..0070223c95 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs
@@ -7,5 +7,5 @@ namespace Godot
/// that can be marshaled from/to a <see cref="Variant"/>.
/// </summary>
[AttributeUsage(AttributeTargets.GenericParameter)]
- public class MustBeVariantAttribute : Attribute { }
+ public sealed class MustBeVariantAttribute : Attribute { }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RpcAttribute.cs
index fb37838ffa..6a73d6f70c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RpcAttribute.cs
@@ -5,37 +5,37 @@ namespace Godot
/// <summary>
/// Attribute that changes the RPC mode for the annotated <c>method</c> to the given <see cref="Mode"/>,
/// optionally specifying the <see cref="TransferMode"/> and <see cref="TransferChannel"/> (on supported peers).
- /// See <see cref="MultiplayerAPI.RPCMode"/> and <see cref="MultiplayerPeer.TransferModeEnum"/>.
+ /// See <see cref="MultiplayerApi.RpcMode"/> and <see cref="MultiplayerPeer.TransferModeEnum"/>.
/// By default, methods are not exposed to networking (and RPCs).
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
- public class RPCAttribute : Attribute
+ public sealed class RpcAttribute : Attribute
{
/// <summary>
/// RPC mode for the annotated method.
/// </summary>
- public MultiplayerAPI.RPCMode Mode { get; } = MultiplayerAPI.RPCMode.Disabled;
+ public MultiplayerApi.RpcMode Mode { get; } = MultiplayerApi.RpcMode.Disabled;
/// <summary>
/// If the method will also be called locally; otherwise, it is only called remotely.
/// </summary>
- public bool CallLocal { get; set; } = false;
+ public bool CallLocal { get; init; } = false;
/// <summary>
/// Transfer mode for the annotated method.
/// </summary>
- public MultiplayerPeer.TransferModeEnum TransferMode { get; set; } = MultiplayerPeer.TransferModeEnum.Reliable;
+ public MultiplayerPeer.TransferModeEnum TransferMode { get; init; } = MultiplayerPeer.TransferModeEnum.Reliable;
/// <summary>
/// Transfer channel for the annotated mode.
/// </summary>
- public int TransferChannel { get; set; } = 0;
+ public int TransferChannel { get; init; } = 0;
/// <summary>
- /// Constructs a <see cref="RPCAttribute"/> instance.
+ /// Constructs a <see cref="RpcAttribute"/> instance.
/// </summary>
/// <param name="mode">The RPC mode to use.</param>
- public RPCAttribute(MultiplayerAPI.RPCMode mode = MultiplayerAPI.RPCMode.Authority)
+ public RpcAttribute(MultiplayerApi.RpcMode mode = MultiplayerApi.RpcMode.Authority)
{
Mode = mode;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
index 2c8a53ae1c..d363e14c5d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
@@ -6,8 +6,11 @@ namespace Godot
/// An attribute that contains the path to the object's script.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
- public class ScriptPathAttribute : Attribute
+ public sealed class ScriptPathAttribute : Attribute
{
+ /// <summary>
+ /// File path to the script.
+ /// </summary>
public string Path { get; }
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
index 38e68a89d5..0a08bb5df8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
@@ -3,5 +3,5 @@ using System;
namespace Godot
{
[AttributeUsage(AttributeTargets.Delegate)]
- public class SignalAttribute : Attribute { }
+ public sealed class SignalAttribute : Attribute { }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs
index d2344389f4..4c56201727 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs
@@ -3,5 +3,5 @@ using System;
namespace Godot
{
[AttributeUsage(AttributeTargets.Class)]
- public class ToolAttribute : Attribute { }
+ public sealed class ToolAttribute : Attribute { }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index bb1d6e1661..ca963cbf4f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -27,9 +27,9 @@ namespace Godot
/// The basis matrix's X vector (column 0).
/// </summary>
/// <value>Equivalent to <see cref="Column0"/> and array index <c>[0]</c>.</value>
- public Vector3 x
+ public Vector3 X
{
- get => Column0;
+ readonly get => Column0;
set => Column0 = value;
}
@@ -37,9 +37,9 @@ namespace Godot
/// The basis matrix's Y vector (column 1).
/// </summary>
/// <value>Equivalent to <see cref="Column1"/> and array index <c>[1]</c>.</value>
- public Vector3 y
+ public Vector3 Y
{
- get => Column1;
+ readonly get => Column1;
set => Column1 = value;
}
@@ -47,9 +47,9 @@ namespace Godot
/// The basis matrix's Z vector (column 2).
/// </summary>
/// <value>Equivalent to <see cref="Column2"/> and array index <c>[2]</c>.</value>
- public Vector3 z
+ public Vector3 Z
{
- get => Column2;
+ readonly get => Column2;
set => Column2 = value;
}
@@ -77,53 +77,53 @@ namespace Godot
/// <summary>
/// Column 0 of the basis matrix (the X vector).
/// </summary>
- /// <value>Equivalent to <see cref="x"/> and array index <c>[0]</c>.</value>
+ /// <value>Equivalent to <see cref="X"/> and array index <c>[0]</c>.</value>
public Vector3 Column0
{
- get => new Vector3(Row0.x, Row1.x, Row2.x);
+ readonly get => new Vector3(Row0.X, Row1.X, Row2.X);
set
{
- Row0.x = value.x;
- Row1.x = value.y;
- Row2.x = value.z;
+ Row0.X = value.X;
+ Row1.X = value.Y;
+ Row2.X = value.Z;
}
}
/// <summary>
/// Column 1 of the basis matrix (the Y vector).
/// </summary>
- /// <value>Equivalent to <see cref="y"/> and array index <c>[1]</c>.</value>
+ /// <value>Equivalent to <see cref="Y"/> and array index <c>[1]</c>.</value>
public Vector3 Column1
{
- get => new Vector3(Row0.y, Row1.y, Row2.y);
+ readonly get => new Vector3(Row0.Y, Row1.Y, Row2.Y);
set
{
- Row0.y = value.x;
- Row1.y = value.y;
- Row2.y = value.z;
+ Row0.Y = value.X;
+ Row1.Y = value.Y;
+ Row2.Y = value.Z;
}
}
/// <summary>
/// Column 2 of the basis matrix (the Z vector).
/// </summary>
- /// <value>Equivalent to <see cref="z"/> and array index <c>[2]</c>.</value>
+ /// <value>Equivalent to <see cref="Z"/> and array index <c>[2]</c>.</value>
public Vector3 Column2
{
- get => new Vector3(Row0.z, Row1.z, Row2.z);
+ readonly get => new Vector3(Row0.Z, Row1.Z, Row2.Z);
set
{
- Row0.z = value.x;
- Row1.z = value.y;
- Row2.z = value.z;
+ Row0.Z = value.X;
+ Row1.Z = value.Y;
+ Row2.Z = value.Z;
}
}
/// <summary>
- /// The scale of this basis.
+ /// Assuming that the matrix is the combination of a rotation and scaling,
+ /// return the absolute value of scaling factors along each axis.
/// </summary>
- /// <value>Equivalent to the lengths of each column vector, but negative if the determinant is negative.</value>
- public Vector3 Scale
+ public readonly Vector3 Scale
{
get
{
@@ -135,13 +135,6 @@ namespace Godot
Column2.Length()
);
}
- set
- {
- value /= Scale; // Value becomes what's called "delta_scale" in core.
- Column0 *= value.x;
- Column1 *= value.y;
- Column2 *= value.z;
- }
}
/// <summary>
@@ -154,7 +147,7 @@ namespace Godot
/// <value>The basis column.</value>
public Vector3 this[int column]
{
- get
+ readonly get
{
switch (column)
{
@@ -195,7 +188,7 @@ namespace Godot
/// <value>The matrix element.</value>
public real_t this[int column, int row]
{
- get
+ readonly get
{
return this[column][row];
}
@@ -220,9 +213,9 @@ namespace Godot
private void SetDiagonal(Vector3 diagonal)
{
- Row0 = new Vector3(diagonal.x, 0, 0);
- Row1 = new Vector3(0, diagonal.y, 0);
- Row2 = new Vector3(0, 0, diagonal.z);
+ Row0 = new Vector3(diagonal.X, 0, 0);
+ Row1 = new Vector3(0, diagonal.Y, 0);
+ Row2 = new Vector3(0, 0, diagonal.Z);
}
/// <summary>
@@ -234,7 +227,7 @@ namespace Godot
/// and is usually considered invalid.
/// </summary>
/// <returns>The determinant of the basis matrix.</returns>
- public real_t Determinant()
+ public readonly real_t Determinant()
{
real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2];
@@ -255,7 +248,7 @@ namespace Godot
/// </summary>
/// <param name="order">The Euler order to use. By default, use YXZ order (most common).</param>
/// <returns>A <see cref="Vector3"/> representing the basis rotation in Euler angles.</returns>
- public Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz)
+ public readonly Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz)
{
switch (order)
{
@@ -277,29 +270,29 @@ namespace Godot
if (Row1[0] == 0 && Row0[1] == 0 && Row1[2] == 0 && Row2[1] == 0 && Row1[1] == 1)
{
// return the simplest form (human friendlier in editor and scripts)
- euler.x = 0;
- euler.y = Mathf.Atan2(Row0[2], Row0[0]);
- euler.z = 0;
+ euler.X = 0;
+ euler.Y = Mathf.Atan2(Row0[2], Row0[0]);
+ euler.Z = 0;
}
else
{
- euler.x = Mathf.Atan2(-Row1[2], Row2[2]);
- euler.y = Mathf.Asin(sy);
- euler.z = Mathf.Atan2(-Row0[1], Row0[0]);
+ euler.X = Mathf.Atan2(-Row1[2], Row2[2]);
+ euler.Y = Mathf.Asin(sy);
+ euler.Z = Mathf.Atan2(-Row0[1], Row0[0]);
}
}
else
{
- euler.x = Mathf.Atan2(Row2[1], Row1[1]);
- euler.y = -Mathf.Tau / 4.0f;
- euler.z = 0.0f;
+ euler.X = Mathf.Atan2(Row2[1], Row1[1]);
+ euler.Y = -Mathf.Tau / 4.0f;
+ euler.Z = 0.0f;
}
}
else
{
- euler.x = Mathf.Atan2(Row2[1], Row1[1]);
- euler.y = Mathf.Tau / 4.0f;
- euler.z = 0.0f;
+ euler.X = Mathf.Atan2(Row2[1], Row1[1]);
+ euler.Y = Mathf.Tau / 4.0f;
+ euler.Z = 0.0f;
}
return euler;
}
@@ -317,24 +310,24 @@ namespace Godot
{
if (sz > -(1.0f - Mathf.Epsilon))
{
- euler.x = Mathf.Atan2(Row2[1], Row1[1]);
- euler.y = Mathf.Atan2(Row0[2], Row0[0]);
- euler.z = Mathf.Asin(-sz);
+ euler.X = Mathf.Atan2(Row2[1], Row1[1]);
+ euler.Y = Mathf.Atan2(Row0[2], Row0[0]);
+ euler.Z = Mathf.Asin(-sz);
}
else
{
// It's -1
- euler.x = -Mathf.Atan2(Row1[2], Row2[2]);
- euler.y = 0.0f;
- euler.z = Mathf.Tau / 4.0f;
+ euler.X = -Mathf.Atan2(Row1[2], Row2[2]);
+ euler.Y = 0.0f;
+ euler.Z = Mathf.Tau / 4.0f;
}
}
else
{
// It's 1
- euler.x = -Mathf.Atan2(Row1[2], Row2[2]);
- euler.y = 0.0f;
- euler.z = -Mathf.Tau / 4.0f;
+ euler.X = -Mathf.Atan2(Row1[2], Row2[2]);
+ euler.Y = 0.0f;
+ euler.Z = -Mathf.Tau / 4.0f;
}
return euler;
}
@@ -356,29 +349,29 @@ namespace Godot
if (Row1[0] == 0 && Row0[1] == 0 && Row0[2] == 0 && Row2[0] == 0 && Row0[0] == 1)
{
// return the simplest form (human friendlier in editor and scripts)
- euler.x = Mathf.Atan2(-m12, Row1[1]);
- euler.y = 0;
- euler.z = 0;
+ euler.X = Mathf.Atan2(-m12, Row1[1]);
+ euler.Y = 0;
+ euler.Z = 0;
}
else
{
- euler.x = Mathf.Asin(-m12);
- euler.y = Mathf.Atan2(Row0[2], Row2[2]);
- euler.z = Mathf.Atan2(Row1[0], Row1[1]);
+ euler.X = Mathf.Asin(-m12);
+ euler.Y = Mathf.Atan2(Row0[2], Row2[2]);
+ euler.Z = Mathf.Atan2(Row1[0], Row1[1]);
}
}
else
{ // m12 == -1
- euler.x = Mathf.Tau / 4.0f;
- euler.y = Mathf.Atan2(Row0[1], Row0[0]);
- euler.z = 0;
+ euler.X = Mathf.Tau / 4.0f;
+ euler.Y = Mathf.Atan2(Row0[1], Row0[0]);
+ euler.Z = 0;
}
}
else
{ // m12 == 1
- euler.x = -Mathf.Tau / 4.0f;
- euler.y = -Mathf.Atan2(Row0[1], Row0[0]);
- euler.z = 0;
+ euler.X = -Mathf.Tau / 4.0f;
+ euler.Y = -Mathf.Atan2(Row0[1], Row0[0]);
+ euler.Z = 0;
}
return euler;
@@ -397,24 +390,24 @@ namespace Godot
{
if (sz > -(1.0f - Mathf.Epsilon))
{
- euler.x = Mathf.Atan2(-Row1[2], Row1[1]);
- euler.y = Mathf.Atan2(-Row2[0], Row0[0]);
- euler.z = Mathf.Asin(sz);
+ euler.X = Mathf.Atan2(-Row1[2], Row1[1]);
+ euler.Y = Mathf.Atan2(-Row2[0], Row0[0]);
+ euler.Z = Mathf.Asin(sz);
}
else
{
// It's -1
- euler.x = Mathf.Atan2(Row2[1], Row2[2]);
- euler.y = 0.0f;
- euler.z = -Mathf.Tau / 4.0f;
+ euler.X = Mathf.Atan2(Row2[1], Row2[2]);
+ euler.Y = 0.0f;
+ euler.Z = -Mathf.Tau / 4.0f;
}
}
else
{
// It's 1
- euler.x = Mathf.Atan2(Row2[1], Row2[2]);
- euler.y = 0.0f;
- euler.z = Mathf.Tau / 4.0f;
+ euler.X = Mathf.Atan2(Row2[1], Row2[2]);
+ euler.Y = 0.0f;
+ euler.Z = Mathf.Tau / 4.0f;
}
return euler;
}
@@ -432,24 +425,24 @@ namespace Godot
{
if (sx > -(1.0f - Mathf.Epsilon))
{
- euler.x = Mathf.Asin(sx);
- euler.y = Mathf.Atan2(-Row2[0], Row2[2]);
- euler.z = Mathf.Atan2(-Row0[1], Row1[1]);
+ euler.X = Mathf.Asin(sx);
+ euler.Y = Mathf.Atan2(-Row2[0], Row2[2]);
+ euler.Z = Mathf.Atan2(-Row0[1], Row1[1]);
}
else
{
// It's -1
- euler.x = -Mathf.Tau / 4.0f;
- euler.y = Mathf.Atan2(Row0[2], Row0[0]);
- euler.z = 0;
+ euler.X = -Mathf.Tau / 4.0f;
+ euler.Y = Mathf.Atan2(Row0[2], Row0[0]);
+ euler.Z = 0;
}
}
else
{
// It's 1
- euler.x = Mathf.Tau / 4.0f;
- euler.y = Mathf.Atan2(Row0[2], Row0[0]);
- euler.z = 0;
+ euler.X = Mathf.Tau / 4.0f;
+ euler.Y = Mathf.Atan2(Row0[2], Row0[0]);
+ euler.Z = 0;
}
return euler;
}
@@ -467,24 +460,24 @@ namespace Godot
{
if (sy > -(1.0f - Mathf.Epsilon))
{
- euler.x = Mathf.Atan2(Row2[1], Row2[2]);
- euler.y = Mathf.Asin(-sy);
- euler.z = Mathf.Atan2(Row1[0], Row0[0]);
+ euler.X = Mathf.Atan2(Row2[1], Row2[2]);
+ euler.Y = Mathf.Asin(-sy);
+ euler.Z = Mathf.Atan2(Row1[0], Row0[0]);
}
else
{
// It's -1
- euler.x = 0;
- euler.y = Mathf.Tau / 4.0f;
- euler.z = -Mathf.Atan2(Row0[1], Row1[1]);
+ euler.X = 0;
+ euler.Y = Mathf.Tau / 4.0f;
+ euler.Z = -Mathf.Atan2(Row0[1], Row1[1]);
}
}
else
{
// It's 1
- euler.x = 0;
- euler.y = -Mathf.Tau / 4.0f;
- euler.z = -Mathf.Atan2(Row0[1], Row1[1]);
+ euler.X = 0;
+ euler.Y = -Mathf.Tau / 4.0f;
+ euler.Z = -Mathf.Atan2(Row0[1], Row1[1]);
}
return euler;
}
@@ -493,13 +486,7 @@ namespace Godot
}
}
- /// <summary>
- /// Returns the basis's rotation in the form of a quaternion.
- /// See <see cref="GetEuler"/> if you need Euler angles, but keep in
- /// mind that quaternions should generally be preferred to Euler angles.
- /// </summary>
- /// <returns>A <see cref="Quaternion"/> representing the basis's rotation.</returns>
- internal Quaternion GetQuaternion()
+ internal readonly Quaternion GetQuaternion()
{
real_t trace = Row0[0] + Row1[1] + Row2[2];
@@ -558,7 +545,7 @@ namespace Godot
/// be preferred to Euler angles.
/// </summary>
/// <returns>The basis rotation.</returns>
- public Quaternion GetRotationQuaternion()
+ public readonly Quaternion GetRotationQuaternion()
{
Basis orthonormalizedBasis = Orthonormalized();
real_t det = orthonormalizedBasis.Determinant();
@@ -573,113 +560,10 @@ namespace Godot
}
/// <summary>
- /// Get rows by index. Rows are not very useful for user code,
- /// but are more efficient for some internal calculations.
- /// </summary>
- /// <param name="index">Which row.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="index"/> is not 0, 1 or 2.
- /// </exception>
- /// <returns>One of <c>Row0</c>, <c>Row1</c>, or <c>Row2</c>.</returns>
- public Vector3 GetRow(int index)
- {
- switch (index)
- {
- case 0:
- return Row0;
- case 1:
- return Row1;
- case 2:
- return Row2;
- default:
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- }
-
- /// <summary>
- /// Sets rows by index. Rows are not very useful for user code,
- /// but are more efficient for some internal calculations.
- /// </summary>
- /// <param name="index">Which row.</param>
- /// <param name="value">The vector to set the row to.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="index"/> is not 0, 1 or 2.
- /// </exception>
- public void SetRow(int index, Vector3 value)
- {
- switch (index)
- {
- case 0:
- Row0 = value;
- return;
- case 1:
- Row1 = value;
- return;
- case 2:
- Row2 = value;
- return;
- default:
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- }
-
- /// <summary>
- /// This function considers a discretization of rotations into
- /// 24 points on unit sphere, lying along the vectors (x, y, z) with
- /// each component being either -1, 0, or 1, and returns the index
- /// of the point best representing the orientation of the object.
- /// It is mainly used by the <see cref="GridMap"/> editor.
- ///
- /// For further details, refer to the Godot source code.
- /// </summary>
- /// <returns>The orthogonal index.</returns>
- public int GetOrthogonalIndex()
- {
- var orth = this;
-
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- var row = orth.GetRow(i);
-
- real_t v = row[j];
-
- if (v > 0.5f)
- {
- v = 1.0f;
- }
- else if (v < -0.5f)
- {
- v = -1.0f;
- }
- else
- {
- v = 0f;
- }
-
- row[j] = v;
-
- orth.SetRow(i, row);
- }
- }
-
- for (int i = 0; i < 24; i++)
- {
- if (orth == _orthoBases[i])
- {
- return i;
- }
- }
-
- return 0;
- }
-
- /// <summary>
/// Returns the inverse of the matrix.
/// </summary>
/// <returns>The inverse matrix.</returns>
- public Basis Inverse()
+ public readonly Basis Inverse()
{
real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2];
@@ -709,7 +593,17 @@ namespace Godot
);
}
- internal Basis Lerp(Basis to, real_t weight)
+ /// <summary>
+ /// Returns <see langword="true"/> if this basis is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Row0.IsFinite() && Row1.IsFinite() && Row2.IsFinite();
+ }
+
+ internal readonly Basis Lerp(Basis to, real_t weight)
{
Basis b = this;
b.Row0 = Row0.Lerp(to.Row0, weight);
@@ -724,7 +618,7 @@ namespace Godot
/// This performs a Gram-Schmidt orthonormalization on the basis of the matrix.
/// </summary>
/// <returns>An orthonormalized basis matrix.</returns>
- public Basis Orthonormalized()
+ public readonly Basis Orthonormalized()
{
Vector3 column0 = this[0];
Vector3 column1 = this[1];
@@ -746,7 +640,7 @@ namespace Godot
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated basis matrix.</returns>
- public Basis Rotated(Vector3 axis, real_t angle)
+ public readonly Basis Rotated(Vector3 axis, real_t angle)
{
return new Basis(axis, angle) * this;
}
@@ -756,12 +650,12 @@ namespace Godot
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled basis matrix.</returns>
- public Basis Scaled(Vector3 scale)
+ public readonly Basis Scaled(Vector3 scale)
{
Basis b = this;
- b.Row0 *= scale.x;
- b.Row1 *= scale.y;
- b.Row2 *= scale.z;
+ b.Row0 *= scale.X;
+ b.Row1 *= scale.Y;
+ b.Row2 *= scale.Z;
return b;
}
@@ -772,7 +666,7 @@ namespace Godot
/// <param name="target">The destination basis for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting basis matrix of the interpolation.</returns>
- public Basis Slerp(Basis target, real_t weight)
+ public readonly Basis Slerp(Basis target, real_t weight)
{
Quaternion from = new Quaternion(this);
Quaternion to = new Quaternion(target);
@@ -790,7 +684,7 @@ namespace Godot
/// </summary>
/// <param name="with">A vector to calculate the dot product with.</param>
/// <returns>The resulting dot product.</returns>
- public real_t Tdotx(Vector3 with)
+ public readonly real_t Tdotx(Vector3 with)
{
return Row0[0] * with[0] + Row1[0] * with[1] + Row2[0] * with[2];
}
@@ -800,7 +694,7 @@ namespace Godot
/// </summary>
/// <param name="with">A vector to calculate the dot product with.</param>
/// <returns>The resulting dot product.</returns>
- public real_t Tdoty(Vector3 with)
+ public readonly real_t Tdoty(Vector3 with)
{
return Row0[1] * with[0] + Row1[1] * with[1] + Row2[1] * with[2];
}
@@ -810,7 +704,7 @@ namespace Godot
/// </summary>
/// <param name="with">A vector to calculate the dot product with.</param>
/// <returns>The resulting dot product.</returns>
- public real_t Tdotz(Vector3 with)
+ public readonly real_t Tdotz(Vector3 with)
{
return Row0[2] * with[0] + Row1[2] * with[1] + Row2[2] * with[2];
}
@@ -819,21 +713,18 @@ namespace Godot
/// Returns the transposed version of the basis matrix.
/// </summary>
/// <returns>The transposed basis matrix.</returns>
- public Basis Transposed()
+ public readonly Basis Transposed()
{
Basis tr = this;
- real_t temp = tr.Row0[1];
- tr.Row0[1] = tr.Row1[0];
- tr.Row1[0] = temp;
+ tr.Row0[1] = Row1[0];
+ tr.Row1[0] = Row0[1];
- temp = tr.Row0[2];
- tr.Row0[2] = tr.Row2[0];
- tr.Row2[0] = temp;
+ tr.Row0[2] = Row2[0];
+ tr.Row2[0] = Row0[2];
- temp = tr.Row1[2];
- tr.Row1[2] = tr.Row2[1];
- tr.Row2[1] = temp;
+ tr.Row1[2] = Row2[1];
+ tr.Row2[1] = Row1[2];
return tr;
}
@@ -899,20 +790,20 @@ namespace Godot
/// <param name="quaternion">The quaternion to create the basis from.</param>
public Basis(Quaternion quaternion)
{
- real_t s = 2.0f / quaternion.LengthSquared;
-
- real_t xs = quaternion.x * s;
- real_t ys = quaternion.y * s;
- real_t zs = quaternion.z * s;
- real_t wx = quaternion.w * xs;
- real_t wy = quaternion.w * ys;
- real_t wz = quaternion.w * zs;
- real_t xx = quaternion.x * xs;
- real_t xy = quaternion.x * ys;
- real_t xz = quaternion.x * zs;
- real_t yy = quaternion.y * ys;
- real_t yz = quaternion.y * zs;
- real_t zz = quaternion.z * zs;
+ real_t s = 2.0f / quaternion.LengthSquared();
+
+ real_t xs = quaternion.X * s;
+ real_t ys = quaternion.Y * s;
+ real_t zs = quaternion.Z * s;
+ real_t wx = quaternion.W * xs;
+ real_t wy = quaternion.W * ys;
+ real_t wz = quaternion.W * zs;
+ real_t xx = quaternion.X * xs;
+ real_t xy = quaternion.X * ys;
+ real_t xz = quaternion.X * zs;
+ real_t yy = quaternion.Y * ys;
+ real_t yz = quaternion.Y * zs;
+ real_t zz = quaternion.Z * zs;
Row0 = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
Row1 = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
@@ -927,29 +818,29 @@ namespace Godot
/// <param name="angle">The angle to rotate, in radians.</param>
public Basis(Vector3 axis, real_t angle)
{
- Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
- real_t cosine = Mathf.Cos(angle);
- Row0.x = axisSq.x + cosine * (1.0f - axisSq.x);
- Row1.y = axisSq.y + cosine * (1.0f - axisSq.y);
- Row2.z = axisSq.z + cosine * (1.0f - axisSq.z);
-
- real_t sine = Mathf.Sin(angle);
- real_t t = 1.0f - cosine;
-
- real_t xyzt = axis.x * axis.y * t;
- real_t zyxs = axis.z * sine;
- Row0.y = xyzt - zyxs;
- Row1.x = xyzt + zyxs;
-
- xyzt = axis.x * axis.z * t;
- zyxs = axis.y * sine;
- Row0.z = xyzt + zyxs;
- Row2.x = xyzt - zyxs;
-
- xyzt = axis.y * axis.z * t;
- zyxs = axis.x * sine;
- Row1.z = xyzt - zyxs;
- Row2.y = xyzt + zyxs;
+ Vector3 axisSq = new Vector3(axis.X * axis.X, axis.Y * axis.Y, axis.Z * axis.Z);
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+
+ Row0.X = axisSq.X + cos * (1.0f - axisSq.X);
+ Row1.Y = axisSq.Y + cos * (1.0f - axisSq.Y);
+ Row2.Z = axisSq.Z + cos * (1.0f - axisSq.Z);
+
+ real_t t = 1.0f - cos;
+
+ real_t xyzt = axis.X * axis.Y * t;
+ real_t zyxs = axis.Z * sin;
+ Row0.Y = xyzt - zyxs;
+ Row1.X = xyzt + zyxs;
+
+ xyzt = axis.X * axis.Z * t;
+ zyxs = axis.Y * sin;
+ Row0.Z = xyzt + zyxs;
+ Row2.X = xyzt - zyxs;
+
+ xyzt = axis.Y * axis.Z * t;
+ zyxs = axis.X * sin;
+ Row1.Z = xyzt - zyxs;
+ Row2.Y = xyzt + zyxs;
}
/// <summary>
@@ -960,9 +851,9 @@ namespace Godot
/// <param name="column2">The Z vector, or Column2.</param>
public Basis(Vector3 column0, Vector3 column1, Vector3 column2)
{
- Row0 = new Vector3(column0.x, column1.x, column2.x);
- Row1 = new Vector3(column0.y, column1.y, column2.y);
- Row2 = new Vector3(column0.z, column1.z, column2.z);
+ Row0 = new Vector3(column0.X, column1.X, column2.X);
+ Row1 = new Vector3(column0.Y, column1.Y, column2.Y);
+ Row2 = new Vector3(column0.Z, column1.Z, column2.Z);
// Same as:
// Column0 = column0;
// Column1 = column1;
@@ -970,8 +861,20 @@ namespace Godot
// We need to assign the struct fields here first so we can't do it that way...
}
- // Arguments are named such that xy is equal to calling x.y
- internal Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz)
+ /// <summary>
+ /// Constructs a transformation matrix from the given components.
+ /// Arguments are named such that xy is equal to calling <c>X.Y</c>.
+ /// </summary>
+ /// <param name="xx">The X component of the X column vector, accessed via <c>b.X.X</c> or <c>[0][0]</c>.</param>
+ /// <param name="yx">The X component of the Y column vector, accessed via <c>b.Y.X</c> or <c>[1][0]</c>.</param>
+ /// <param name="zx">The X component of the Z column vector, accessed via <c>b.Z.X</c> or <c>[2][0]</c>.</param>
+ /// <param name="xy">The Y component of the X column vector, accessed via <c>b.X.Y</c> or <c>[0][1]</c>.</param>
+ /// <param name="yy">The Y component of the Y column vector, accessed via <c>b.Y.Y</c> or <c>[1][1]</c>.</param>
+ /// <param name="zy">The Y component of the Z column vector, accessed via <c>b.Y.Y</c> or <c>[2][1]</c>.</param>
+ /// <param name="xz">The Z component of the X column vector, accessed via <c>b.X.Y</c> or <c>[0][2]</c>.</param>
+ /// <param name="yz">The Z component of the Y column vector, accessed via <c>b.Y.Y</c> or <c>[1][2]</c>.</param>
+ /// <param name="zz">The Z component of the Z column vector, accessed via <c>b.Y.Y</c> or <c>[2][2]</c>.</param>
+ public Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz)
{
Row0 = new Vector3(xx, yx, zx);
Row1 = new Vector3(xy, yy, zy);
@@ -985,19 +888,29 @@ namespace Godot
/// <param name="order">The order to compose the Euler angles.</param>
public static Basis FromEuler(Vector3 euler, EulerOrder order = EulerOrder.Yxz)
{
- real_t c, s;
-
- c = Mathf.Cos(euler.x);
- s = Mathf.Sin(euler.x);
- Basis xmat = new Basis(new Vector3(1, 0, 0), new Vector3(0, c, s), new Vector3(0, -s, c));
+ (real_t sin, real_t cos) = Mathf.SinCos(euler.X);
+ Basis xmat = new Basis
+ (
+ new Vector3(1, 0, 0),
+ new Vector3(0, cos, sin),
+ new Vector3(0, -sin, cos)
+ );
- c = Mathf.Cos(euler.y);
- s = Mathf.Sin(euler.y);
- Basis ymat = new Basis(new Vector3(c, 0, -s), new Vector3(0, 1, 0), new Vector3(s, 0, c));
+ (sin, cos) = Mathf.SinCos(euler.Y);
+ Basis ymat = new Basis
+ (
+ new Vector3(cos, 0, -sin),
+ new Vector3(0, 1, 0),
+ new Vector3(sin, 0, cos)
+ );
- c = Mathf.Cos(euler.z);
- s = Mathf.Sin(euler.z);
- Basis zmat = new Basis(new Vector3(c, s, 0), new Vector3(-s, c, 0), new Vector3(0, 0, 1));
+ (sin, cos) = Mathf.SinCos(euler.Z);
+ Basis zmat = new Basis
+ (
+ new Vector3(cos, sin, 0),
+ new Vector3(-sin, cos, 0),
+ new Vector3(0, 0, 1)
+ );
switch (order)
{
@@ -1028,9 +941,9 @@ namespace Godot
public static Basis FromScale(Vector3 scale)
{
return new Basis(
- scale.x, 0, 0,
- 0, scale.y, 0,
- 0, 0, scale.z
+ scale.X, 0, 0,
+ 0, scale.Y, 0,
+ 0, 0, scale.Z
);
}
@@ -1081,9 +994,9 @@ namespace Godot
{
return new Vector3
(
- basis.Row0[0] * vector.x + basis.Row1[0] * vector.y + basis.Row2[0] * vector.z,
- basis.Row0[1] * vector.x + basis.Row1[1] * vector.y + basis.Row2[1] * vector.z,
- basis.Row0[2] * vector.x + basis.Row1[2] * vector.y + basis.Row2[2] * vector.z
+ basis.Row0[0] * vector.X + basis.Row1[0] * vector.Y + basis.Row2[0] * vector.Z,
+ basis.Row0[1] * vector.X + basis.Row1[1] * vector.Y + basis.Row2[1] * vector.Z,
+ basis.Row0[2] * vector.X + basis.Row1[2] * vector.Y + basis.Row2[2] * vector.Z
);
}
@@ -1121,7 +1034,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the basis matrix and the object are exactly equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Basis other && Equals(other);
}
@@ -1133,7 +1046,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other basis.</param>
/// <returns>Whether or not the basis matrices are exactly equal.</returns>
- public bool Equals(Basis other)
+ public readonly bool Equals(Basis other)
{
return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2);
}
@@ -1144,7 +1057,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other basis to compare.</param>
/// <returns>Whether or not the bases are approximately equal.</returns>
- public bool IsEqualApprox(Basis other)
+ public readonly bool IsEqualApprox(Basis other)
{
return Row0.IsEqualApprox(other.Row0) && Row1.IsEqualApprox(other.Row1) && Row2.IsEqualApprox(other.Row2);
}
@@ -1153,7 +1066,7 @@ namespace Godot
/// Serves as the hash function for <see cref="Basis"/>.
/// </summary>
/// <returns>A hash code for this basis.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode();
}
@@ -1162,18 +1075,18 @@ namespace Godot
/// Converts this <see cref="Basis"/> to a string.
/// </summary>
/// <returns>A string representation of this basis.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"[X: {x}, Y: {y}, Z: {z}]";
+ return $"[X: {X}, Y: {Y}, Z: {Z}]";
}
/// <summary>
/// Converts this <see cref="Basis"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this basis.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"[X: {x.ToString(format)}, Y: {y.ToString(format)}, Z: {z.ToString(format)}]";
+ return $"[X: {X.ToString(format)}, Y: {Y.ToString(format)}, Z: {Z.ToString(format)}]";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
index 354212da1b..16be494d99 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
@@ -12,7 +12,7 @@ namespace Godot.Bridge
{
try
{
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ var godotObject = (GodotObject)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
{
@@ -49,7 +49,7 @@ namespace Godot.Bridge
{
try
{
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ var godotObject = (GodotObject)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
throw new InvalidOperationException();
@@ -79,17 +79,34 @@ namespace Godot.Bridge
{
try
{
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ var godotObject = (GodotObject)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
throw new InvalidOperationException();
+ // Properties
if (godotObject.GetGodotClassPropertyValue(CustomUnsafe.AsRef(name), out godot_variant outRetValue))
{
*outRet = outRetValue;
return godot_bool.True;
}
+ // Signals
+ if (godotObject.HasGodotClassSignal(CustomUnsafe.AsRef(name)))
+ {
+ godot_signal signal = new godot_signal(*name, godotObject.GetInstanceId());
+ *outRet = VariantUtils.CreateFromSignalTakingOwnershipOfDisposableValue(signal);
+ return godot_bool.True;
+ }
+
+ // Methods
+ if (godotObject.HasGodotClassMethod(CustomUnsafe.AsRef(name)))
+ {
+ godot_callable method = new godot_callable(*name, godotObject.GetInstanceId());
+ *outRet = VariantUtils.CreateFromCallableTakingOwnershipOfDisposableValue(method);
+ return godot_bool.True;
+ }
+
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
@@ -117,7 +134,7 @@ namespace Godot.Bridge
{
try
{
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ var godotObject = (GodotObject)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (okIfNull.ToBool())
godotObject?.Dispose();
@@ -135,7 +152,7 @@ namespace Godot.Bridge
{
try
{
- var self = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ var self = (GodotObject)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (self == null)
{
@@ -169,7 +186,7 @@ namespace Godot.Bridge
{
try
{
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ var godotObject = (GodotObject)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
return godot_bool.False;
@@ -192,7 +209,7 @@ namespace Godot.Bridge
{
try
{
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ var godotObject = (GodotObject)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
return;
@@ -225,7 +242,7 @@ namespace Godot.Bridge
{
try
{
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ var godotObject = (GodotObject)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
if (godotObject == null)
return;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs
index 6d20f95007..47feb1902f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs
@@ -48,7 +48,7 @@ public sealed class GodotSerializationInfo : IDisposable
{
_signalEvents[name] = serializedData;
}
- else if (OS.IsStdoutVerbose())
+ else if (OS.IsStdOutVerbose())
{
Console.WriteLine($"Failed to serialize event signal delegate: {name}");
}
@@ -72,7 +72,7 @@ public sealed class GodotSerializationInfo : IDisposable
return true;
}
- else if (OS.IsStdoutVerbose())
+ else if (OS.IsStdOutVerbose())
{
Console.WriteLine($"Failed to deserialize event signal delegate: {name}");
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs
index 647ae436ff..85d38f9727 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs
@@ -4,7 +4,7 @@ namespace Godot.Bridge;
#nullable enable
-public struct MethodInfo
+public readonly struct MethodInfo
{
public StringName Name { get; init; }
public PropertyInfo ReturnVal { get; init; }
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
index 80d6f7b4a5..0f447b93c8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
@@ -2,7 +2,7 @@ namespace Godot.Bridge;
#nullable enable
-public struct PropertyInfo
+public readonly struct PropertyInfo
{
public Variant.Type Type { get; init; }
public StringName Name { get; init; }
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index d83cf43eb2..ec2728140e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -100,7 +100,7 @@ namespace Godot.Bridge
Type nativeType = TypeGetProxyClass(nativeTypeNameStr) ?? throw new InvalidOperationException(
"Wrapper class not found for type: " + nativeTypeNameStr);
- var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
+ var obj = (GodotObject)FormatterServices.GetUninitializedObject(nativeType);
var ctor = nativeType.GetConstructor(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
@@ -150,7 +150,7 @@ namespace Godot.Bridge
}
}
- var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
+ var obj = (GodotObject)FormatterServices.GetUninitializedObject(scriptType);
var parameters = ctor.GetParameters();
int paramCount = parameters.Length;
@@ -159,7 +159,7 @@ namespace Godot.Bridge
for (int i = 0; i < paramCount; i++)
{
- invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType(
+ invokeParams[i] = DelegateUtils.RuntimeTypeConversionHelper.ConvertToObjectOfType(
*args[i], parameters[i].ParameterType);
}
@@ -189,7 +189,7 @@ namespace Godot.Bridge
return;
}
- var native = Object.InternalGetClassNativeBase(scriptType);
+ var native = GodotObject.InternalGetClassNativeBase(scriptType);
var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
BindingFlags.Public | BindingFlags.NonPublic);
@@ -222,7 +222,7 @@ namespace Godot.Bridge
{
try
{
- var target = (Object?)GCHandle.FromIntPtr(gcHandlePtr).Target;
+ var target = (GodotObject?)GCHandle.FromIntPtr(gcHandlePtr).Target;
if (target != null)
target.NativePtr = newPtr;
}
@@ -239,21 +239,45 @@ namespace Godot.Bridge
if (nativeTypeNameStr[0] == '_')
nativeTypeNameStr = nativeTypeNameStr.Substring(1);
- Type? wrapperType = typeof(Object).Assembly.GetType("Godot." + nativeTypeNameStr);
+ Type? wrapperType = typeof(GodotObject).Assembly.GetType("Godot." + nativeTypeNameStr);
if (wrapperType == null)
{
- wrapperType = AppDomain.CurrentDomain.GetAssemblies()
- .FirstOrDefault(a => a.GetName().Name == "GodotSharpEditor")?
- .GetType("Godot." + nativeTypeNameStr);
+ wrapperType = GetTypeByGodotClassAttr(typeof(GodotObject).Assembly, nativeTypeNameStr);
+ }
+
+ if (wrapperType == null)
+ {
+ var editorAssembly = AppDomain.CurrentDomain.GetAssemblies()
+ .FirstOrDefault(a => a.GetName().Name == "GodotSharpEditor");
+ wrapperType = editorAssembly?.GetType("Godot." + nativeTypeNameStr);
+
+ if (wrapperType == null)
+ {
+ wrapperType = GetTypeByGodotClassAttr(editorAssembly, nativeTypeNameStr);
+ }
+ }
+
+ static Type? GetTypeByGodotClassAttr(Assembly assembly, string nativeTypeNameStr)
+ {
+ var types = assembly.GetTypes();
+ foreach (var type in types)
+ {
+ var attr = type.GetCustomAttribute<GodotClassNameAttribute>();
+ if (attr?.Name == nativeTypeNameStr)
+ {
+ return type;
+ }
+ }
+ return null;
}
static bool IsStatic(Type type) => type.IsAbstract && type.IsSealed;
if (wrapperType != null && IsStatic(wrapperType))
{
- // A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object.
- return typeof(Object);
+ // A static class means this is a Godot singleton class. If an instance is needed we use GodotObject.
+ return typeof(GodotObject);
}
return wrapperType;
@@ -293,11 +317,11 @@ namespace Godot.Bridge
// such as when disabling C# source generators (for whatever reason) or when using a
// language other than C# that has nothing similar to source generators to automate it.
- var typeOfGodotObject = typeof(Object);
+ var typeOfGodotObject = typeof(GodotObject);
foreach (var type in assembly.GetTypes())
{
- if (type.IsNested)
+ if (type.IsNested || type.IsGenericType)
continue;
if (!typeOfGodotObject.IsAssignableFrom(type))
@@ -314,9 +338,12 @@ namespace Godot.Bridge
if (scriptTypes != null)
{
- for (int i = 0; i < scriptTypes.Length; i++)
+ foreach (var type in scriptTypes)
{
- LookupScriptForClass(scriptTypes[i]);
+ if (type.IsGenericType)
+ continue;
+
+ LookupScriptForClass(type);
}
}
}
@@ -328,7 +355,7 @@ namespace Godot.Bridge
{
try
{
- var owner = (Object?)GCHandle.FromIntPtr(ownerGCHandlePtr).Target;
+ var owner = (GodotObject?)GCHandle.FromIntPtr(ownerGCHandlePtr).Target;
if (owner == null)
{
@@ -536,9 +563,9 @@ namespace Godot.Bridge
}
// ReSharper disable once RedundantNameQualifier
- if (!typeof(Godot.Object).IsAssignableFrom(scriptType))
+ if (!typeof(GodotObject).IsAssignableFrom(scriptType))
{
- // The class no longer inherits Godot.Object, can't reload
+ // The class no longer inherits GodotObject, can't reload
return godot_bool.False;
}
@@ -586,7 +613,7 @@ namespace Godot.Bridge
using var methods = new Collections.Array();
Type? top = scriptType;
- Type native = Object.InternalGetClassNativeBase(top);
+ Type native = GodotObject.InternalGetClassNativeBase(top);
while (top != null && top != native)
{
@@ -647,7 +674,7 @@ namespace Godot.Bridge
continue;
var rpcAttr = method.GetCustomAttributes(inherit: false)
- .OfType<RPCAttribute>().FirstOrDefault();
+ .OfType<RpcAttribute>().FirstOrDefault();
if (rpcAttr == null)
continue;
@@ -729,6 +756,7 @@ namespace Godot.Bridge
{
ExceptionUtils.LogException(e);
*outTool = godot_bool.False;
+ *outMethodsDest = NativeFuncs.godotsharp_array_new();
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
*outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new();
*outBaseScript = default;
@@ -827,12 +855,13 @@ namespace Godot.Bridge
{
// Weird limitation, hence the need for aux:
// "In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable."
- var aux = stackalloc godotsharp_property_info[length];
+ var aux = stackalloc godotsharp_property_info[stackMaxLength];
interopProperties = aux;
}
else
{
- interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_info)))!;
+ interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc(
+ (nuint)length, (nuint)sizeof(godotsharp_property_info)))!;
}
try
@@ -858,8 +887,8 @@ namespace Godot.Bridge
addPropInfoFunc(scriptPtr, &currentClassName, interopProperties, length);
- // We're borrowing the StringName's without making an owning copy, so the
- // managed collection needs to be kept alive until `addPropInfoFunc` returns.
+ // We're borrowing the native value of the StringName entries.
+ // The dictionary needs to be kept alive until `addPropInfoFunc` returns.
GC.KeepAlive(properties);
}
finally
@@ -884,12 +913,7 @@ namespace Godot.Bridge
{
// Careful with padding...
public godot_string_name Name; // Not owned
- public godot_variant Value;
-
- public void Dispose()
- {
- Value.Dispose();
- }
+ public godot_variant Value; // Not owned
}
[UnmanagedCallersOnly]
@@ -899,7 +923,7 @@ namespace Godot.Bridge
try
{
Type? top = _scriptTypeBiMap.GetScriptType(scriptPtr);
- Type native = Object.InternalGetClassNativeBase(top);
+ Type native = GodotObject.InternalGetClassNativeBase(top);
while (top != null && top != native)
{
@@ -928,10 +952,35 @@ namespace Godot.Bridge
if (getGodotPropertyDefaultValuesMethod == null)
return;
- var defaultValues = (Dictionary<StringName, object>?)
- getGodotPropertyDefaultValuesMethod.Invoke(null, null);
+ var defaultValuesObj = getGodotPropertyDefaultValuesMethod.Invoke(null, null);
+
+ if (defaultValuesObj == null)
+ return;
+
+ Dictionary<StringName, Variant> defaultValues;
+
+ if (defaultValuesObj is Dictionary<StringName, object> defaultValuesLegacy)
+ {
+ // We have to support this for some time, otherwise this could cause data loss for projects
+ // built with previous releases. Ideally, we should remove this before Godot 4.0 stable.
+
+ if (defaultValuesLegacy.Count <= 0)
+ return;
+
+ defaultValues = new();
- if (defaultValues == null || defaultValues.Count <= 0)
+ foreach (var pair in defaultValuesLegacy)
+ {
+ defaultValues[pair.Key] = Variant.CreateTakingOwnershipOfDisposableValue(
+ DelegateUtils.RuntimeTypeConversionHelper.ConvertToVariant(pair.Value));
+ }
+ }
+ else
+ {
+ defaultValues = (Dictionary<StringName, Variant>)defaultValuesObj;
+ }
+
+ if (defaultValues.Count <= 0)
return;
int length = defaultValues.Count;
@@ -947,12 +996,13 @@ namespace Godot.Bridge
{
// Weird limitation, hence the need for aux:
// "In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable."
- var aux = stackalloc godotsharp_property_def_val_pair[length];
+ var aux = stackalloc godotsharp_property_def_val_pair[stackMaxLength];
interopDefaultValues = aux;
}
else
{
- interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_def_val_pair)))!;
+ interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc(
+ (nuint)length, (nuint)sizeof(godotsharp_property_def_val_pair)))!;
}
try
@@ -963,7 +1013,7 @@ namespace Godot.Bridge
godotsharp_property_def_val_pair interopProperty = new()
{
Name = (godot_string_name)defaultValuePair.Key.NativeValue, // Not owned
- Value = Marshaling.ConvertManagedObjectToVariant(defaultValuePair.Value)
+ Value = (godot_variant)defaultValuePair.Value.NativeVar // Not owned
};
interopDefaultValues[i] = interopProperty;
@@ -973,15 +1023,12 @@ namespace Godot.Bridge
addDefValFunc(scriptPtr, interopDefaultValues, length);
- // We're borrowing the StringName's without making an owning copy, so the
- // managed collection needs to be kept alive until `addDefValFunc` returns.
+ // We're borrowing the native value of the StringName and Variant entries.
+ // The dictionary needs to be kept alive until `addDefValFunc` returns.
GC.KeepAlive(defaultValues);
}
finally
{
- for (int i = 0; i < length; i++)
- interopDefaultValues[i].Dispose();
-
if (!useStack)
NativeMemory.Free(interopDefaultValues);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
index f9309ca13e..219a9a8c15 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
@@ -28,7 +28,7 @@ namespace Godot
/// </example>
public readonly partial struct Callable
{
- private readonly Object _target;
+ private readonly GodotObject _target;
private readonly StringName _method;
private readonly Delegate _delegate;
private readonly unsafe delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> _trampoline;
@@ -36,7 +36,7 @@ namespace Godot
/// <summary>
/// Object that contains the method.
/// </summary>
- public Object Target => _target;
+ public GodotObject Target => _target;
/// <summary>
/// Name of the method that will be called.
@@ -60,7 +60,7 @@ namespace Godot
/// </summary>
/// <param name="target">Object that contains the method.</param>
/// <param name="method">Name of the method that will be called.</param>
- public unsafe Callable(Object target, StringName method)
+ public unsafe Callable(GodotObject target, StringName method)
{
_target = target;
_method = method;
@@ -71,13 +71,13 @@ namespace Godot
private unsafe Callable(Delegate @delegate,
delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> trampoline)
{
- _target = @delegate?.Target as Object;
+ _target = @delegate?.Target as GodotObject;
_method = null;
_delegate = @delegate;
_trampoline = trampoline;
}
- private const int VarArgsSpanThreshold = 5;
+ private const int VarArgsSpanThreshold = 10;
/// <summary>
/// Calls the method represented by this <see cref="Callable"/>.
@@ -92,15 +92,13 @@ namespace Godot
int argc = args.Length;
Span<godot_variant.movable> argsStoreSpan = argc <= VarArgsSpanThreshold ?
- stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :
+ stackalloc godot_variant.movable[VarArgsSpanThreshold] :
new godot_variant.movable[argc];
- Span<IntPtr> argsSpan = argc <= 10 ?
- stackalloc IntPtr[argc] :
+ Span<IntPtr> argsSpan = argc <= VarArgsSpanThreshold ?
+ stackalloc IntPtr[VarArgsSpanThreshold] :
new IntPtr[argc];
- using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan);
-
fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef)
fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan))
{
@@ -128,15 +126,13 @@ namespace Godot
int argc = args.Length;
Span<godot_variant.movable> argsStoreSpan = argc <= VarArgsSpanThreshold ?
- stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :
+ stackalloc godot_variant.movable[VarArgsSpanThreshold] :
new godot_variant.movable[argc];
- Span<IntPtr> argsSpan = argc <= 10 ?
- stackalloc IntPtr[argc] :
+ Span<IntPtr> argsSpan = argc <= VarArgsSpanThreshold ?
+ stackalloc IntPtr[VarArgsSpanThreshold] :
new IntPtr[argc];
- using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan);
-
fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef)
fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan))
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs
index 6c6a104019..3005582bea 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs
@@ -45,7 +45,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0>(
+ public static unsafe Callable From<[MustBeVariant] T0>(
Action<T0> action
)
{
@@ -54,7 +54,7 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 1);
((Action<T0>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
+ VariantUtils.ConvertTo<T0>(args[0])
);
ret = default;
@@ -64,7 +64,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0, T1>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1>(
Action<T0, T1> action
)
{
@@ -73,8 +73,8 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 2);
((Action<T0, T1>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1])
);
ret = default;
@@ -84,7 +84,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0, T1, T2>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2>(
Action<T0, T1, T2> action
)
{
@@ -93,9 +93,9 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 3);
((Action<T0, T1, T2>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2])
);
ret = default;
@@ -105,7 +105,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0, T1, T2, T3>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3>(
Action<T0, T1, T2, T3> action
)
{
@@ -114,10 +114,10 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 4);
((Action<T0, T1, T2, T3>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3])
);
ret = default;
@@ -127,7 +127,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4>(
Action<T0, T1, T2, T3, T4> action
)
{
@@ -136,11 +136,11 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 5);
((Action<T0, T1, T2, T3, T4>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4])
);
ret = default;
@@ -150,7 +150,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, T5>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] T5>(
Action<T0, T1, T2, T3, T4, T5> action
)
{
@@ -159,12 +159,12 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 6);
((Action<T0, T1, T2, T3, T4, T5>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
- VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4]),
+ VariantUtils.ConvertTo<T5>(args[5])
);
ret = default;
@@ -174,7 +174,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] T5, [MustBeVariant] T6>(
Action<T0, T1, T2, T3, T4, T5, T6> action
)
{
@@ -183,13 +183,13 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 7);
((Action<T0, T1, T2, T3, T4, T5, T6>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
- VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
- VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4]),
+ VariantUtils.ConvertTo<T5>(args[5]),
+ VariantUtils.ConvertTo<T6>(args[6])
);
ret = default;
@@ -199,7 +199,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] T5, [MustBeVariant] T6, [MustBeVariant] T7>(
Action<T0, T1, T2, T3, T4, T5, T6, T7> action
)
{
@@ -208,14 +208,14 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 8);
((Action<T0, T1, T2, T3, T4, T5, T6, T7>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
- VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
- VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
- VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4]),
+ VariantUtils.ConvertTo<T5>(args[5]),
+ VariantUtils.ConvertTo<T6>(args[6]),
+ VariantUtils.ConvertTo<T7>(args[7])
);
ret = default;
@@ -225,7 +225,7 @@ public readonly partial struct Callable
}
/// <inheritdoc cref="From(Action)"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, T8>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] T5, [MustBeVariant] T6, [MustBeVariant] T7, [MustBeVariant] T8>(
Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> action
)
{
@@ -234,15 +234,15 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 9);
((Action<T0, T1, T2, T3, T4, T5, T6, T7, T8>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
- VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
- VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
- VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]),
- VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4]),
+ VariantUtils.ConvertTo<T5>(args[5]),
+ VariantUtils.ConvertTo<T6>(args[6]),
+ VariantUtils.ConvertTo<T7>(args[7]),
+ VariantUtils.ConvertTo<T8>(args[8])
);
ret = default;
@@ -255,7 +255,7 @@ public readonly partial struct Callable
/// Constructs a new <see cref="Callable"/> for the given <paramref name="func"/>.
/// </summary>
/// <param name="func">Action method that will be called.</param>
- public static unsafe Callable From<TResult>(
+ public static unsafe Callable From<[MustBeVariant] TResult>(
Func<TResult> func
)
{
@@ -265,14 +265,14 @@ public readonly partial struct Callable
TResult res = ((Func<TResult>)delegateObj)();
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] TResult>(
Func<T0, TResult> func
)
{
@@ -281,17 +281,17 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 1);
TResult res = ((Func<T0, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
+ VariantUtils.ConvertTo<T0>(args[0])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, T1, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] TResult>(
Func<T0, T1, TResult> func
)
{
@@ -300,18 +300,18 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 2);
TResult res = ((Func<T0, T1, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, T1, T2, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] TResult>(
Func<T0, T1, T2, TResult> func
)
{
@@ -320,19 +320,19 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 3);
TResult res = ((Func<T0, T1, T2, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, T1, T2, T3, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] TResult>(
Func<T0, T1, T2, T3, TResult> func
)
{
@@ -341,20 +341,20 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 4);
TResult res = ((Func<T0, T1, T2, T3, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] TResult>(
Func<T0, T1, T2, T3, T4, TResult> func
)
{
@@ -363,21 +363,21 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 5);
TResult res = ((Func<T0, T1, T2, T3, T4, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, T5, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] T5, [MustBeVariant] TResult>(
Func<T0, T1, T2, T3, T4, T5, TResult> func
)
{
@@ -386,22 +386,22 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 6);
TResult res = ((Func<T0, T1, T2, T3, T4, T5, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
- VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4]),
+ VariantUtils.ConvertTo<T5>(args[5])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] T5, [MustBeVariant] T6, [MustBeVariant] TResult>(
Func<T0, T1, T2, T3, T4, T5, T6, TResult> func
)
{
@@ -410,23 +410,23 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 7);
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
- VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
- VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4]),
+ VariantUtils.ConvertTo<T5>(args[5]),
+ VariantUtils.ConvertTo<T6>(args[6])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] T5, [MustBeVariant] T6, [MustBeVariant] T7, [MustBeVariant] TResult>(
Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult> func
)
{
@@ -435,24 +435,24 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 8);
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
- VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
- VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
- VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4]),
+ VariantUtils.ConvertTo<T5>(args[5]),
+ VariantUtils.ConvertTo<T6>(args[6]),
+ VariantUtils.ConvertTo<T7>(args[7])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
}
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
- public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>(
+ public static unsafe Callable From<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3, [MustBeVariant] T4, [MustBeVariant] T5, [MustBeVariant] T6, [MustBeVariant] T7, [MustBeVariant] T8, [MustBeVariant] TResult>(
Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult> func
)
{
@@ -461,18 +461,18 @@ public readonly partial struct Callable
ThrowIfArgCountMismatch(args, 9);
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>)delegateObj)(
- VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
- VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
- VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
- VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
- VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
- VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
- VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
- VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]),
- VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8])
+ VariantUtils.ConvertTo<T0>(args[0]),
+ VariantUtils.ConvertTo<T1>(args[1]),
+ VariantUtils.ConvertTo<T2>(args[2]),
+ VariantUtils.ConvertTo<T3>(args[3]),
+ VariantUtils.ConvertTo<T4>(args[4]),
+ VariantUtils.ConvertTo<T5>(args[5]),
+ VariantUtils.ConvertTo<T6>(args[6]),
+ VariantUtils.ConvertTo<T7>(args[7]),
+ VariantUtils.ConvertTo<T8>(args[8])
);
- ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ ret = VariantUtils.CreateFrom(res);
}
return CreateWithUnsafeTrampoline(func, &Trampoline);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index ee9e59f9fa..555811bab2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -20,97 +21,97 @@ namespace Godot
/// <summary>
/// The color's red component, typically on the range of 0 to 1.
/// </summary>
- public float r;
+ public float R;
/// <summary>
/// The color's green component, typically on the range of 0 to 1.
/// </summary>
- public float g;
+ public float G;
/// <summary>
/// The color's blue component, typically on the range of 0 to 1.
/// </summary>
- public float b;
+ public float B;
/// <summary>
/// The color's alpha (transparency) component, typically on the range of 0 to 1.
/// </summary>
- public float a;
+ public float A;
/// <summary>
- /// Wrapper for <see cref="r"/> that uses the range 0 to 255 instead of 0 to 1.
+ /// Wrapper for <see cref="R"/> that uses the range 0 to 255 instead of 0 to 1.
/// </summary>
/// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
- public int r8
+ public int R8
{
- get
+ readonly get
{
- return (int)Math.Round(r * 255.0f);
+ return (int)Math.Round(R * 255.0f);
}
set
{
- r = value / 255.0f;
+ R = value / 255.0f;
}
}
/// <summary>
- /// Wrapper for <see cref="g"/> that uses the range 0 to 255 instead of 0 to 1.
+ /// Wrapper for <see cref="G"/> that uses the range 0 to 255 instead of 0 to 1.
/// </summary>
/// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
- public int g8
+ public int G8
{
- get
+ readonly get
{
- return (int)Math.Round(g * 255.0f);
+ return (int)Math.Round(G * 255.0f);
}
set
{
- g = value / 255.0f;
+ G = value / 255.0f;
}
}
/// <summary>
- /// Wrapper for <see cref="b"/> that uses the range 0 to 255 instead of 0 to 1.
+ /// Wrapper for <see cref="B"/> that uses the range 0 to 255 instead of 0 to 1.
/// </summary>
/// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
- public int b8
+ public int B8
{
- get
+ readonly get
{
- return (int)Math.Round(b * 255.0f);
+ return (int)Math.Round(B * 255.0f);
}
set
{
- b = value / 255.0f;
+ B = value / 255.0f;
}
}
/// <summary>
- /// Wrapper for <see cref="a"/> that uses the range 0 to 255 instead of 0 to 1.
+ /// Wrapper for <see cref="A"/> that uses the range 0 to 255 instead of 0 to 1.
/// </summary>
/// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
- public int a8
+ public int A8
{
- get
+ readonly get
{
- return (int)Math.Round(a * 255.0f);
+ return (int)Math.Round(A * 255.0f);
}
set
{
- a = value / 255.0f;
+ A = value / 255.0f;
}
}
/// <summary>
/// The HSV hue of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHSV"/>.</value>
- public float h
+ /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHsv"/>.</value>
+ public float H
{
- get
+ readonly get
{
- float max = Math.Max(r, Math.Max(g, b));
- float min = Math.Min(r, Math.Min(g, b));
+ float max = Math.Max(R, Math.Max(G, B));
+ float min = Math.Min(R, Math.Min(G, B));
float delta = max - min;
@@ -121,17 +122,17 @@ namespace Godot
float h;
- if (r == max)
+ if (R == max)
{
- h = (g - b) / delta; // Between yellow & magenta
+ h = (G - B) / delta; // Between yellow & magenta
}
- else if (g == max)
+ else if (G == max)
{
- h = 2 + ((b - r) / delta); // Between cyan & yellow
+ h = 2 + ((B - R) / delta); // Between cyan & yellow
}
else
{
- h = 4 + ((r - g) / delta); // Between magenta & cyan
+ h = 4 + ((R - G) / delta); // Between magenta & cyan
}
h /= 6.0f;
@@ -145,20 +146,20 @@ namespace Godot
}
set
{
- this = FromHSV(value, s, v, a);
+ this = FromHsv(value, S, V, A);
}
}
/// <summary>
/// The HSV saturation of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHSV"/>.</value>
- public float s
+ /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHsv"/>.</value>
+ public float S
{
- get
+ readonly get
{
- float max = Math.Max(r, Math.Max(g, b));
- float min = Math.Min(r, Math.Min(g, b));
+ float max = Math.Max(R, Math.Max(G, B));
+ float min = Math.Min(R, Math.Min(G, B));
float delta = max - min;
@@ -166,49 +167,62 @@ namespace Godot
}
set
{
- this = FromHSV(h, value, v, a);
+ this = FromHsv(H, value, V, A);
}
}
/// <summary>
/// The HSV value (brightness) of this color, on the range 0 to 1.
/// </summary>
- /// <value>Getting is equivalent to using <see cref="Math.Max(float, float)"/> on the RGB components. Setting uses <see cref="FromHSV"/>.</value>
- public float v
+ /// <value>Getting is equivalent to using <see cref="Math.Max(float, float)"/> on the RGB components. Setting uses <see cref="FromHsv"/>.</value>
+ public float V
{
- get
+ readonly get
{
- return Math.Max(r, Math.Max(g, b));
+ return Math.Max(R, Math.Max(G, B));
}
set
{
- this = FromHSV(h, s, value, a);
+ this = FromHsv(H, S, value, A);
}
}
/// <summary>
+ /// Returns the light intensity of the color, as a value between 0.0 and 1.0 (inclusive).
+ /// This is useful when determining light or dark color. Colors with a luminance smaller
+ /// than 0.5 can be generally considered dark.
+ /// Note: <see cref="Luminance"/> relies on the color being in the linear color space to
+ /// return an accurate relative luminance value. If the color is in the sRGB color space
+ /// use <see cref="SrgbToLinear"/> to convert it to the linear color space first.
+ /// </summary>
+ public readonly float Luminance
+ {
+ get { return 0.2126f * R + 0.7152f * G + 0.0722f * B; }
+ }
+
+ /// <summary>
/// Access color components using their index.
/// </summary>
/// <value>
- /// <c>[0]</c> is equivalent to <see cref="r"/>,
- /// <c>[1]</c> is equivalent to <see cref="g"/>,
- /// <c>[2]</c> is equivalent to <see cref="b"/>,
- /// <c>[3]</c> is equivalent to <see cref="a"/>.
+ /// <c>[0]</c> is equivalent to <see cref="R"/>,
+ /// <c>[1]</c> is equivalent to <see cref="G"/>,
+ /// <c>[2]</c> is equivalent to <see cref="B"/>,
+ /// <c>[3]</c> is equivalent to <see cref="A"/>.
/// </value>
public float this[int index]
{
- get
+ readonly get
{
switch (index)
{
case 0:
- return r;
+ return R;
case 1:
- return g;
+ return G;
case 2:
- return b;
+ return B;
case 3:
- return a;
+ return A;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
@@ -218,16 +232,16 @@ namespace Godot
switch (index)
{
case 0:
- r = value;
+ R = value;
return;
case 1:
- g = value;
+ G = value;
return;
case 2:
- b = value;
+ B = value;
return;
case 3:
- a = value;
+ A = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(index));
@@ -242,21 +256,21 @@ namespace Godot
/// </summary>
/// <param name="over">The color to blend over.</param>
/// <returns>This color blended over <paramref name="over"/>.</returns>
- public Color Blend(Color over)
+ public readonly Color Blend(Color over)
{
Color res;
- float sa = 1.0f - over.a;
- res.a = (a * sa) + over.a;
+ float sa = 1.0f - over.A;
+ res.A = (A * sa) + over.A;
- if (res.a == 0)
+ if (res.A == 0)
{
return new Color(0, 0, 0, 0);
}
- res.r = ((r * a * sa) + (over.r * over.a)) / res.a;
- res.g = ((g * a * sa) + (over.g * over.a)) / res.a;
- res.b = ((b * a * sa) + (over.b * over.a)) / res.a;
+ res.R = ((R * A * sa) + (over.R * over.A)) / res.A;
+ res.G = ((G * A * sa) + (over.G * over.A)) / res.A;
+ res.B = ((B * A * sa) + (over.B * over.A)) / res.A;
return res;
}
@@ -269,16 +283,16 @@ namespace Godot
/// <param name="min">The color with minimum allowed values.</param>
/// <param name="max">The color with maximum allowed values.</param>
/// <returns>The color with all components clamped.</returns>
- public Color Clamp(Color? min = null, Color? max = null)
+ public readonly Color Clamp(Color? min = null, Color? max = null)
{
Color minimum = min ?? new Color(0, 0, 0, 0);
Color maximum = max ?? new Color(1, 1, 1, 1);
return new Color
(
- (float)Mathf.Clamp(r, minimum.r, maximum.r),
- (float)Mathf.Clamp(g, minimum.g, maximum.g),
- (float)Mathf.Clamp(b, minimum.b, maximum.b),
- (float)Mathf.Clamp(a, minimum.a, maximum.a)
+ (float)Mathf.Clamp(R, minimum.R, maximum.R),
+ (float)Mathf.Clamp(G, minimum.G, maximum.G),
+ (float)Mathf.Clamp(B, minimum.B, maximum.B),
+ (float)Mathf.Clamp(A, minimum.A, maximum.A)
);
}
@@ -288,12 +302,12 @@ namespace Godot
/// </summary>
/// <param name="amount">The ratio to darken by.</param>
/// <returns>The darkened color.</returns>
- public Color Darkened(float amount)
+ public readonly Color Darkened(float amount)
{
Color res = this;
- res.r *= 1.0f - amount;
- res.g *= 1.0f - amount;
- res.b *= 1.0f - amount;
+ res.R *= 1.0f - amount;
+ res.G *= 1.0f - amount;
+ res.B *= 1.0f - amount;
return res;
}
@@ -301,13 +315,13 @@ namespace Godot
/// Returns the inverted color: <c>(1 - r, 1 - g, 1 - b, a)</c>.
/// </summary>
/// <returns>The inverted color.</returns>
- public Color Inverted()
+ public readonly Color Inverted()
{
return new Color(
- 1.0f - r,
- 1.0f - g,
- 1.0f - b,
- a
+ 1.0f - R,
+ 1.0f - G,
+ 1.0f - B,
+ A
);
}
@@ -317,12 +331,12 @@ namespace Godot
/// </summary>
/// <param name="amount">The ratio to lighten by.</param>
/// <returns>The darkened color.</returns>
- public Color Lightened(float amount)
+ public readonly Color Lightened(float amount)
{
Color res = this;
- res.r += (1.0f - res.r) * amount;
- res.g += (1.0f - res.g) * amount;
- res.b += (1.0f - res.b) * amount;
+ res.R += (1.0f - res.R) * amount;
+ res.G += (1.0f - res.G) * amount;
+ res.B += (1.0f - res.B) * amount;
return res;
}
@@ -333,33 +347,44 @@ namespace Godot
/// <param name="to">The destination color for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting color of the interpolation.</returns>
- public Color Lerp(Color to, real_t weight)
+ public readonly Color Lerp(Color to, real_t weight)
{
return new Color
(
- (float)Mathf.Lerp(r, to.r, weight),
- (float)Mathf.Lerp(g, to.g, weight),
- (float)Mathf.Lerp(b, to.b, weight),
- (float)Mathf.Lerp(a, to.a, weight)
+ (float)Mathf.Lerp(R, to.R, weight),
+ (float)Mathf.Lerp(G, to.G, weight),
+ (float)Mathf.Lerp(B, to.B, weight),
+ (float)Mathf.Lerp(A, to.A, weight)
);
}
/// <summary>
- /// Returns the result of the linear interpolation between
- /// this color and <paramref name="to"/> by color amount <paramref name="weight"/>.
+ /// Returns the color converted to the sRGB color space.
+ /// This method assumes the original color is in the linear color space.
+ /// See also <see cref="SrgbToLinear"/> which performs the opposite operation.
/// </summary>
- /// <param name="to">The destination color for interpolation.</param>
- /// <param name="weight">A color with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The resulting color of the interpolation.</returns>
- public Color Lerp(Color to, Color weight)
+ /// <returns>The sRGB color.</returns>
+ public readonly Color LinearToSrgb()
{
- return new Color
- (
- (float)Mathf.Lerp(r, to.r, weight.r),
- (float)Mathf.Lerp(g, to.g, weight.g),
- (float)Mathf.Lerp(b, to.b, weight.b),
- (float)Mathf.Lerp(a, to.a, weight.a)
- );
+ return new Color(
+ R < 0.0031308f ? 12.92f * R : (1.0f + 0.055f) * (float)Mathf.Pow(R, 1.0f / 2.4f) - 0.055f,
+ G < 0.0031308f ? 12.92f * G : (1.0f + 0.055f) * (float)Mathf.Pow(G, 1.0f / 2.4f) - 0.055f,
+ B < 0.0031308f ? 12.92f * B : (1.0f + 0.055f) * (float)Mathf.Pow(B, 1.0f / 2.4f) - 0.055f, A);
+ }
+
+ /// <summary>
+ /// Returns the color converted to linear color space.
+ /// This method assumes the original color already is in sRGB color space.
+ /// See also <see cref="LinearToSrgb"/> which performs the opposite operation.
+ /// </summary>
+ /// <returns>The color in linear color space.</returns>
+ public readonly Color SrgbToLinear()
+ {
+ return new Color(
+ R < 0.04045f ? R * (1.0f / 12.92f) : (float)Mathf.Pow((R + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ G < 0.04045f ? G * (1.0f / 12.92f) : (float)Mathf.Pow((G + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ B < 0.04045f ? B * (1.0f / 12.92f) : (float)Mathf.Pow((B + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ A);
}
/// <summary>
@@ -368,15 +393,15 @@ namespace Godot
/// ABGR is the reversed version of the default format.
/// </summary>
/// <returns>A <see langword="uint"/> representing this color in ABGR32 format.</returns>
- public uint ToAbgr32()
+ public readonly uint ToAbgr32()
{
- uint c = (byte)Math.Round(a * 255);
+ uint c = (byte)Math.Round(A * 255);
c <<= 8;
- c |= (byte)Math.Round(b * 255);
+ c |= (byte)Math.Round(B * 255);
c <<= 8;
- c |= (byte)Math.Round(g * 255);
+ c |= (byte)Math.Round(G * 255);
c <<= 8;
- c |= (byte)Math.Round(r * 255);
+ c |= (byte)Math.Round(R * 255);
return c;
}
@@ -387,15 +412,15 @@ namespace Godot
/// ABGR is the reversed version of the default format.
/// </summary>
/// <returns>A <see langword="ulong"/> representing this color in ABGR64 format.</returns>
- public ulong ToAbgr64()
+ public readonly ulong ToAbgr64()
{
- ulong c = (ushort)Math.Round(a * 65535);
+ ulong c = (ushort)Math.Round(A * 65535);
c <<= 16;
- c |= (ushort)Math.Round(b * 65535);
+ c |= (ushort)Math.Round(B * 65535);
c <<= 16;
- c |= (ushort)Math.Round(g * 65535);
+ c |= (ushort)Math.Round(G * 65535);
c <<= 16;
- c |= (ushort)Math.Round(r * 65535);
+ c |= (ushort)Math.Round(R * 65535);
return c;
}
@@ -406,15 +431,15 @@ namespace Godot
/// ARGB is more compatible with DirectX, but not used much in Godot.
/// </summary>
/// <returns>A <see langword="uint"/> representing this color in ARGB32 format.</returns>
- public uint ToArgb32()
+ public readonly uint ToArgb32()
{
- uint c = (byte)Math.Round(a * 255);
+ uint c = (byte)Math.Round(A * 255);
c <<= 8;
- c |= (byte)Math.Round(r * 255);
+ c |= (byte)Math.Round(R * 255);
c <<= 8;
- c |= (byte)Math.Round(g * 255);
+ c |= (byte)Math.Round(G * 255);
c <<= 8;
- c |= (byte)Math.Round(b * 255);
+ c |= (byte)Math.Round(B * 255);
return c;
}
@@ -425,15 +450,15 @@ namespace Godot
/// ARGB is more compatible with DirectX, but not used much in Godot.
/// </summary>
/// <returns>A <see langword="ulong"/> representing this color in ARGB64 format.</returns>
- public ulong ToArgb64()
+ public readonly ulong ToArgb64()
{
- ulong c = (ushort)Math.Round(a * 65535);
+ ulong c = (ushort)Math.Round(A * 65535);
c <<= 16;
- c |= (ushort)Math.Round(r * 65535);
+ c |= (ushort)Math.Round(R * 65535);
c <<= 16;
- c |= (ushort)Math.Round(g * 65535);
+ c |= (ushort)Math.Round(G * 65535);
c <<= 16;
- c |= (ushort)Math.Round(b * 65535);
+ c |= (ushort)Math.Round(B * 65535);
return c;
}
@@ -444,15 +469,15 @@ namespace Godot
/// RGBA is Godot's default and recommended format.
/// </summary>
/// <returns>A <see langword="uint"/> representing this color in RGBA32 format.</returns>
- public uint ToRgba32()
+ public readonly uint ToRgba32()
{
- uint c = (byte)Math.Round(r * 255);
+ uint c = (byte)Math.Round(R * 255);
c <<= 8;
- c |= (byte)Math.Round(g * 255);
+ c |= (byte)Math.Round(G * 255);
c <<= 8;
- c |= (byte)Math.Round(b * 255);
+ c |= (byte)Math.Round(B * 255);
c <<= 8;
- c |= (byte)Math.Round(a * 255);
+ c |= (byte)Math.Round(A * 255);
return c;
}
@@ -463,15 +488,15 @@ namespace Godot
/// RGBA is Godot's default and recommended format.
/// </summary>
/// <returns>A <see langword="ulong"/> representing this color in RGBA64 format.</returns>
- public ulong ToRgba64()
+ public readonly ulong ToRgba64()
{
- ulong c = (ushort)Math.Round(r * 65535);
+ ulong c = (ushort)Math.Round(R * 65535);
c <<= 16;
- c |= (ushort)Math.Round(g * 65535);
+ c |= (ushort)Math.Round(G * 65535);
c <<= 16;
- c |= (ushort)Math.Round(b * 65535);
+ c |= (ushort)Math.Round(B * 65535);
c <<= 16;
- c |= (ushort)Math.Round(a * 65535);
+ c |= (ushort)Math.Round(A * 65535);
return c;
}
@@ -483,17 +508,17 @@ namespace Godot
/// Whether or not to include alpha. If <see langword="false"/>, the color is RGB instead of RGBA.
/// </param>
/// <returns>A string for the HTML hexadecimal representation of this color.</returns>
- public string ToHTML(bool includeAlpha = true)
+ public readonly string ToHtml(bool includeAlpha = true)
{
string txt = string.Empty;
- txt += ToHex32(r);
- txt += ToHex32(g);
- txt += ToHex32(b);
+ txt += ToHex32(R);
+ txt += ToHex32(G);
+ txt += ToHex32(B);
if (includeAlpha)
{
- txt += ToHex32(a);
+ txt += ToHex32(A);
}
return txt;
@@ -508,10 +533,10 @@ namespace Godot
/// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param>
public Color(float r, float g, float b, float a = 1.0f)
{
- this.r = r;
- this.g = g;
- this.b = b;
- this.a = a;
+ R = r;
+ G = g;
+ B = b;
+ A = a;
}
/// <summary>
@@ -521,10 +546,10 @@ namespace Godot
/// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param>
public Color(Color c, float a = 1.0f)
{
- r = c.r;
- g = c.g;
- b = c.b;
- this.a = a;
+ R = c.R;
+ G = c.G;
+ B = c.B;
+ A = a;
}
/// <summary>
@@ -534,13 +559,13 @@ namespace Godot
/// <param name="rgba">The <see langword="uint"/> representing the color.</param>
public Color(uint rgba)
{
- a = (rgba & 0xFF) / 255.0f;
+ A = (rgba & 0xFF) / 255.0f;
rgba >>= 8;
- b = (rgba & 0xFF) / 255.0f;
+ B = (rgba & 0xFF) / 255.0f;
rgba >>= 8;
- g = (rgba & 0xFF) / 255.0f;
+ G = (rgba & 0xFF) / 255.0f;
rgba >>= 8;
- r = (rgba & 0xFF) / 255.0f;
+ R = (rgba & 0xFF) / 255.0f;
}
/// <summary>
@@ -550,13 +575,13 @@ namespace Godot
/// <param name="rgba">The <see langword="ulong"/> representing the color.</param>
public Color(ulong rgba)
{
- a = (rgba & 0xFFFF) / 65535.0f;
+ A = (rgba & 0xFFFF) / 65535.0f;
rgba >>= 16;
- b = (rgba & 0xFFFF) / 65535.0f;
+ B = (rgba & 0xFFFF) / 65535.0f;
rgba >>= 16;
- g = (rgba & 0xFFFF) / 65535.0f;
+ G = (rgba & 0xFFFF) / 65535.0f;
rgba >>= 16;
- r = (rgba & 0xFFFF) / 65535.0f;
+ R = (rgba & 0xFFFF) / 65535.0f;
}
/// <summary>
@@ -565,11 +590,15 @@ namespace Godot
/// <see cref="Colors"/> constants.
/// </summary>
/// <param name="code">The HTML color code or color name to construct from.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// A color cannot be inferred from the given <paramref name="code"/>.
+ /// It was invalid HTML and a color with that name was not found.
+ /// </exception>
public Color(string code)
{
if (HtmlIsValid(code))
{
- this = FromHTML(code);
+ this = FromHtml(code);
}
else
{
@@ -587,7 +616,7 @@ namespace Godot
public Color(string code, float alpha)
{
this = new Color(code);
- a = alpha;
+ A = alpha;
}
/// <summary>
@@ -597,15 +626,15 @@ namespace Godot
/// <exception name="ArgumentOutOfRangeException">
/// <paramref name="rgba"/> color code is invalid.
/// </exception>
- private static Color FromHTML(ReadOnlySpan<char> rgba)
+ public static Color FromHtml(ReadOnlySpan<char> rgba)
{
Color c;
if (rgba.Length == 0)
{
- c.r = 0f;
- c.g = 0f;
- c.b = 0f;
- c.a = 1.0f;
+ c.R = 0f;
+ c.G = 0f;
+ c.B = 0f;
+ c.A = 1.0f;
return c;
}
@@ -641,44 +670,44 @@ namespace Godot
$"Invalid color code. Length is {rgba.Length}, but a length of 6 or 8 is expected: {rgba}");
}
- c.a = 1.0f;
+ c.A = 1.0f;
if (isShorthand)
{
- c.r = ParseCol4(rgba, 0) / 15f;
- c.g = ParseCol4(rgba, 1) / 15f;
- c.b = ParseCol4(rgba, 2) / 15f;
+ c.R = ParseCol4(rgba, 0) / 15f;
+ c.G = ParseCol4(rgba, 1) / 15f;
+ c.B = ParseCol4(rgba, 2) / 15f;
if (alpha)
{
- c.a = ParseCol4(rgba, 3) / 15f;
+ c.A = ParseCol4(rgba, 3) / 15f;
}
}
else
{
- c.r = ParseCol8(rgba, 0) / 255f;
- c.g = ParseCol8(rgba, 2) / 255f;
- c.b = ParseCol8(rgba, 4) / 255f;
+ c.R = ParseCol8(rgba, 0) / 255f;
+ c.G = ParseCol8(rgba, 2) / 255f;
+ c.B = ParseCol8(rgba, 4) / 255f;
if (alpha)
{
- c.a = ParseCol8(rgba, 6) / 255f;
+ c.A = ParseCol8(rgba, 6) / 255f;
}
}
- if (c.r < 0)
+ if (c.R < 0)
{
throw new ArgumentOutOfRangeException($"Invalid color code. Red part is not valid hexadecimal: {rgba}");
}
- if (c.g < 0)
+ if (c.G < 0)
{
throw new ArgumentOutOfRangeException($"Invalid color code. Green part is not valid hexadecimal: {rgba}");
}
- if (c.b < 0)
+ if (c.B < 0)
{
throw new ArgumentOutOfRangeException($"Invalid color code. Blue part is not valid hexadecimal: {rgba}");
}
- if (c.a < 0)
+ if (c.A < 0)
{
throw new ArgumentOutOfRangeException($"Invalid color code. Alpha part is not valid hexadecimal: {rgba}");
}
@@ -705,39 +734,70 @@ namespace Godot
/// the constants defined in <see cref="Colors"/>.
/// </summary>
/// <param name="name">The name of the color.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// A color with the given name is not found.
+ /// </exception>
/// <returns>The constructed color.</returns>
private static Color Named(string name)
{
+ if (!FindNamedColor(name, out Color color))
+ {
+ throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
+ }
+
+ return color;
+ }
+
+ /// <summary>
+ /// Returns a color according to the standardized name, with the
+ /// specified alpha value. Supported color names are the same as
+ /// the constants defined in <see cref="Colors"/>.
+ /// If a color with the given name is not found, it returns
+ /// <paramref name="default"/>.
+ /// </summary>
+ /// <param name="name">The name of the color.</param>
+ /// <param name="default">
+ /// The default color to return when a color with the given name
+ /// is not found.
+ /// </param>
+ /// <returns>The constructed color.</returns>
+ private static Color Named(string name, Color @default)
+ {
+ if (!FindNamedColor(name, out Color color))
+ {
+ return @default;
+ }
+
+ return color;
+ }
+
+ private static bool FindNamedColor(string name, out Color color)
+ {
name = name.Replace(" ", string.Empty);
name = name.Replace("-", string.Empty);
name = name.Replace("_", string.Empty);
name = name.Replace("'", string.Empty);
name = name.Replace(".", string.Empty);
- name = name.ToUpper();
-
- if (!Colors.namedColors.ContainsKey(name))
- {
- throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
- }
+ name = name.ToUpperInvariant();
- return Colors.namedColors[name];
+ return Colors.namedColors.TryGetValue(name, out color);
}
/// <summary>
- /// Constructs a color from an HSV profile, with values on the
- /// range of 0 to 1. This is equivalent to using each of
- /// the <c>h</c>/<c>s</c>/<c>v</c> properties, but much more efficient.
+ /// Constructs a color from an HSV profile. The <paramref name="hue"/>,
+ /// <paramref name="saturation"/>, and <paramref name="value"/> are typically
+ /// between 0.0 and 1.0.
/// </summary>
/// <param name="hue">The HSV hue, typically on the range of 0 to 1.</param>
/// <param name="saturation">The HSV saturation, typically on the range of 0 to 1.</param>
/// <param name="value">The HSV value (brightness), typically on the range of 0 to 1.</param>
/// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
/// <returns>The constructed color.</returns>
- public static Color FromHSV(float hue, float saturation, float value, float alpha = 1.0f)
+ public static Color FromHsv(float hue, float saturation, float value, float alpha = 1.0f)
{
if (saturation == 0)
{
- // Achromatic (grey)
+ // Achromatic (gray)
return new Color(value, value, value, alpha);
}
@@ -777,10 +837,10 @@ namespace Godot
/// <param name="hue">Output parameter for the HSV hue.</param>
/// <param name="saturation">Output parameter for the HSV saturation.</param>
/// <param name="value">Output parameter for the HSV value.</param>
- public void ToHSV(out float hue, out float saturation, out float value)
+ public readonly void ToHsv(out float hue, out float saturation, out float value)
{
- float max = (float)Mathf.Max(r, Mathf.Max(g, b));
- float min = (float)Mathf.Min(r, Mathf.Min(g, b));
+ float max = (float)Mathf.Max(R, Mathf.Max(G, B));
+ float min = (float)Mathf.Min(R, Mathf.Min(G, B));
float delta = max - min;
@@ -790,17 +850,17 @@ namespace Godot
}
else
{
- if (r == max)
+ if (R == max)
{
- hue = (g - b) / delta; // Between yellow & magenta
+ hue = (G - B) / delta; // Between yellow & magenta
}
- else if (g == max)
+ else if (G == max)
{
- hue = 2 + ((b - r) / delta); // Between cyan & yellow
+ hue = 2 + ((B - R) / delta); // Between cyan & yellow
}
else
{
- hue = 4 + ((r - g) / delta); // Between magenta & cyan
+ hue = 4 + ((R - G) / delta); // Between magenta & cyan
}
hue /= 6.0f;
@@ -841,13 +901,78 @@ namespace Godot
return ParseCol4(str, index) * 16 + ParseCol4(str, index + 1);
}
+ /// <summary>
+ /// Constructs a color from an OK HSL profile. The <paramref name="hue"/>,
+ /// <paramref name="saturation"/>, and <paramref name="lightness"/> are typically
+ /// between 0.0 and 1.0.
+ /// </summary>
+ /// <param name="hue">The OK HSL hue, typically on the range of 0 to 1.</param>
+ /// <param name="saturation">The OK HSL saturation, typically on the range of 0 to 1.</param>
+ /// <param name="lightness">The OK HSL lightness, typically on the range of 0 to 1.</param>
+ /// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
+ /// <returns>The constructed color.</returns>
+ public static Color FromOkHsl(float hue, float saturation, float lightness, float alpha = 1.0f)
+ {
+ return NativeFuncs.godotsharp_color_from_ok_hsl(hue, saturation, lightness, alpha);
+ }
+
+ /// <summary>
+ /// Encodes a <see cref="Color"/> from a RGBE9995 format integer.
+ /// See <see cref="Image.Format.Rgbe9995"/>.
+ /// </summary>
+ /// <param name="rgbe">The RGBE9995 encoded color.</param>
+ /// <returns>The constructed color.</returns>
+ public static Color FromRgbe9995(uint rgbe)
+ {
+ float r = rgbe & 0x1ff;
+ float g = (rgbe >> 9) & 0x1ff;
+ float b = (rgbe >> 18) & 0x1ff;
+ float e = rgbe >> 27;
+ float m = (float)Mathf.Pow(2.0f, e - 15.0f - 9.0f);
+
+ float rd = r * m;
+ float gd = g * m;
+ float bd = b * m;
+
+ return new Color(rd, gd, bd, 1.0f);
+ }
+
+ /// <summary>
+ /// Constructs a color from the given string, which can be either an HTML color
+ /// code or a named color. Returns <paramref name="default"/> if the color cannot
+ /// be inferred from the string. Supported color names are the same as the
+ /// <see cref="Colors"/> constants.
+ /// </summary>
+ /// <param name="str">The HTML color code or color name.</param>
+ /// <param name="default">The fallback color to return if the color cannot be inferred.</param>
+ /// <returns>The constructed color.</returns>
+ public static Color FromString(string str, Color @default)
+ {
+ if (HtmlIsValid(str))
+ {
+ return FromHtml(str);
+ }
+ else
+ {
+ return Named(str, @default);
+ }
+ }
+
private static string ToHex32(float val)
{
byte b = (byte)Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255));
return b.HexEncode();
}
- internal static bool HtmlIsValid(ReadOnlySpan<char> color)
+ /// <summary>
+ /// Returns <see langword="true"/> if <paramref name="color"/> is a valid HTML hexadecimal
+ /// color string. The string must be a hexadecimal value (case-insensitive) of either 3,
+ /// 4, 6 or 8 digits, and may be prefixed by a hash sign (<c>#</c>). This method is
+ /// identical to <see cref="StringExtensions.IsValidHtmlColor(string)"/>.
+ /// </summary>
+ /// <param name="color">The HTML hexadecimal color string.</param>
+ /// <returns>Whether or not the string was a valid HTML hexadecimal color string.</returns>
+ public static bool HtmlIsValid(ReadOnlySpan<char> color)
{
if (color.IsEmpty)
{
@@ -887,10 +1012,10 @@ namespace Godot
/// <returns>The added color.</returns>
public static Color operator +(Color left, Color right)
{
- left.r += right.r;
- left.g += right.g;
- left.b += right.b;
- left.a += right.a;
+ left.R += right.R;
+ left.G += right.G;
+ left.B += right.B;
+ left.A += right.A;
return left;
}
@@ -903,17 +1028,17 @@ namespace Godot
/// <returns>The subtracted color.</returns>
public static Color operator -(Color left, Color right)
{
- left.r -= right.r;
- left.g -= right.g;
- left.b -= right.b;
- left.a -= right.a;
+ left.R -= right.R;
+ left.G -= right.G;
+ left.B -= right.B;
+ left.A -= right.A;
return left;
}
/// <summary>
/// Inverts the given color. This is equivalent to
/// <c>Colors.White - c</c> or
- /// <c>new Color(1 - c.r, 1 - c.g, 1 - c.b, 1 - c.a)</c>.
+ /// <c>new Color(1 - c.R, 1 - c.G, 1 - c.B, 1 - c.A)</c>.
/// </summary>
/// <param name="color">The color to invert.</param>
/// <returns>The inverted color.</returns>
@@ -931,10 +1056,10 @@ namespace Godot
/// <returns>The multiplied color.</returns>
public static Color operator *(Color color, float scale)
{
- color.r *= scale;
- color.g *= scale;
- color.b *= scale;
- color.a *= scale;
+ color.R *= scale;
+ color.G *= scale;
+ color.B *= scale;
+ color.A *= scale;
return color;
}
@@ -947,10 +1072,10 @@ namespace Godot
/// <returns>The multiplied color.</returns>
public static Color operator *(float scale, Color color)
{
- color.r *= scale;
- color.g *= scale;
- color.b *= scale;
- color.a *= scale;
+ color.R *= scale;
+ color.G *= scale;
+ color.B *= scale;
+ color.A *= scale;
return color;
}
@@ -963,10 +1088,10 @@ namespace Godot
/// <returns>The multiplied color.</returns>
public static Color operator *(Color left, Color right)
{
- left.r *= right.r;
- left.g *= right.g;
- left.b *= right.b;
- left.a *= right.a;
+ left.R *= right.R;
+ left.G *= right.G;
+ left.B *= right.B;
+ left.A *= right.A;
return left;
}
@@ -979,10 +1104,10 @@ namespace Godot
/// <returns>The divided color.</returns>
public static Color operator /(Color color, float scale)
{
- color.r /= scale;
- color.g /= scale;
- color.b /= scale;
- color.a /= scale;
+ color.R /= scale;
+ color.G /= scale;
+ color.B /= scale;
+ color.A /= scale;
return color;
}
@@ -995,10 +1120,10 @@ namespace Godot
/// <returns>The divided color.</returns>
public static Color operator /(Color left, Color right)
{
- left.r /= right.r;
- left.g /= right.g;
- left.b /= right.b;
- left.a /= right.a;
+ left.R /= right.R;
+ left.G /= right.G;
+ left.B /= right.B;
+ left.A /= right.A;
return left;
}
@@ -1042,19 +1167,19 @@ namespace Godot
/// <returns>Whether or not the left is less than the right.</returns>
public static bool operator <(Color left, Color right)
{
- if (left.r == right.r)
+ if (left.R == right.R)
{
- if (left.g == right.g)
+ if (left.G == right.G)
{
- if (left.b == right.b)
+ if (left.B == right.B)
{
- return left.a < right.a;
+ return left.A < right.A;
}
- return left.b < right.b;
+ return left.B < right.B;
}
- return left.g < right.g;
+ return left.G < right.G;
}
- return left.r < right.r;
+ return left.R < right.R;
}
/// <summary>
@@ -1071,19 +1196,19 @@ namespace Godot
/// <returns>Whether or not the left is greater than the right.</returns>
public static bool operator >(Color left, Color right)
{
- if (left.r == right.r)
+ if (left.R == right.R)
{
- if (left.g == right.g)
+ if (left.G == right.G)
{
- if (left.b == right.b)
+ if (left.B == right.B)
{
- return left.a > right.a;
+ return left.A > right.A;
}
- return left.b > right.b;
+ return left.B > right.B;
}
- return left.g > right.g;
+ return left.G > right.G;
}
- return left.r > right.r;
+ return left.R > right.R;
}
/// <summary>
@@ -1100,19 +1225,19 @@ namespace Godot
/// <returns>Whether or not the left is less than or equal to the right.</returns>
public static bool operator <=(Color left, Color right)
{
- if (left.r == right.r)
+ if (left.R == right.R)
{
- if (left.g == right.g)
+ if (left.G == right.G)
{
- if (left.b == right.b)
+ if (left.B == right.B)
{
- return left.a <= right.a;
+ return left.A <= right.A;
}
- return left.b < right.b;
+ return left.B < right.B;
}
- return left.g < right.g;
+ return left.G < right.G;
}
- return left.r < right.r;
+ return left.R < right.R;
}
/// <summary>
@@ -1129,19 +1254,19 @@ namespace Godot
/// <returns>Whether or not the left is greater than or equal to the right.</returns>
public static bool operator >=(Color left, Color right)
{
- if (left.r == right.r)
+ if (left.R == right.R)
{
- if (left.g == right.g)
+ if (left.G == right.G)
{
- if (left.b == right.b)
+ if (left.B == right.B)
{
- return left.a >= right.a;
+ return left.A >= right.A;
}
- return left.b > right.b;
+ return left.B > right.B;
}
- return left.g > right.g;
+ return left.G > right.G;
}
- return left.r > right.r;
+ return left.R > right.R;
}
/// <summary>
@@ -1149,7 +1274,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The other object to compare.</param>
/// <returns>Whether or not the color and the other object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Color other && Equals(other);
}
@@ -1161,9 +1286,9 @@ namespace Godot
/// </summary>
/// <param name="other">The other color.</param>
/// <returns>Whether or not the colors are equal.</returns>
- public bool Equals(Color other)
+ public readonly bool Equals(Color other)
{
- return r == other.r && g == other.g && b == other.b && a == other.a;
+ return R == other.R && G == other.G && B == other.B && A == other.A;
}
/// <summary>
@@ -1172,36 +1297,36 @@ namespace Godot
/// </summary>
/// <param name="other">The other color to compare.</param>
/// <returns>Whether or not the colors are approximately equal.</returns>
- public bool IsEqualApprox(Color other)
+ public readonly bool IsEqualApprox(Color other)
{
- return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a);
+ return Mathf.IsEqualApprox(R, other.R) && Mathf.IsEqualApprox(G, other.G) && Mathf.IsEqualApprox(B, other.B) && Mathf.IsEqualApprox(A, other.A);
}
/// <summary>
/// Serves as the hash function for <see cref="Color"/>.
/// </summary>
/// <returns>A hash code for this color.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode();
+ return R.GetHashCode() ^ G.GetHashCode() ^ B.GetHashCode() ^ A.GetHashCode();
}
/// <summary>
/// Converts this <see cref="Color"/> to a string.
/// </summary>
/// <returns>A string representation of this color.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"({r}, {g}, {b}, {a})";
+ return $"({R}, {G}, {B}, {A})";
}
/// <summary>
/// Converts this <see cref="Color"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this color.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"({r.ToString(format)}, {g.ToString(format)}, {b.ToString(format)}, {a.ToString(format)})";
+ return $"({R.ToString(format)}, {G.ToString(format)}, {B.ToString(format)}, {A.ToString(format)})";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index d19e0c08f2..4a54f67cc9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -126,7 +126,7 @@ namespace Godot
}
}
// ReSharper disable once RedundantNameQualifier
- case Godot.Object godotObject:
+ case GodotObject godotObject:
{
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
@@ -186,7 +186,7 @@ namespace Godot
writer.Write(field.Name);
var fieldValue = field.GetValue(target);
- using var fieldValueVariant = Marshaling.ConvertManagedObjectToVariant(fieldValue);
+ using var fieldValueVariant = RuntimeTypeConversionHelper.ConvertToVariant(fieldValue);
byte[] valueBuffer = VarToBytes(fieldValueVariant);
writer.Write(valueBuffer.Length);
writer.Write(valueBuffer);
@@ -399,7 +399,7 @@ namespace Godot
{
ulong objectId = reader.ReadUInt64();
// ReSharper disable once RedundantNameQualifier
- Godot.Object godotObject = GD.InstanceFromId(objectId);
+ GodotObject godotObject = GodotObject.InstanceFromId(objectId);
if (godotObject == null)
return false;
@@ -443,7 +443,14 @@ namespace Godot
FieldInfo? fieldInfo = targetType.GetField(name,
BindingFlags.Instance | BindingFlags.Public);
- fieldInfo?.SetValue(recreatedTarget, GD.BytesToVar(valueBuffer));
+
+ if (fieldInfo != null)
+ {
+ var variantValue = GD.BytesToVar(valueBuffer);
+ object? managedValue = RuntimeTypeConversionHelper.ConvertToObjectOfType(
+ (godot_variant)variantValue.NativeVar, fieldInfo.FieldType);
+ fieldInfo.SetValue(recreatedTarget, managedValue);
+ }
}
@delegate = Delegate.CreateDelegate(delegateType, recreatedTarget, methodInfo,
@@ -537,5 +544,289 @@ namespace Godot
return type;
}
+
+ internal static class RuntimeTypeConversionHelper
+ {
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ public static godot_variant ConvertToVariant(object? obj)
+ {
+ if (obj == null)
+ return default;
+
+ switch (obj)
+ {
+ case bool @bool:
+ return VariantUtils.CreateFrom(@bool);
+ case char @char:
+ return VariantUtils.CreateFrom(@char);
+ case sbyte int8:
+ return VariantUtils.CreateFrom(int8);
+ case short int16:
+ return VariantUtils.CreateFrom(int16);
+ case int int32:
+ return VariantUtils.CreateFrom(int32);
+ case long int64:
+ return VariantUtils.CreateFrom(int64);
+ case byte uint8:
+ return VariantUtils.CreateFrom(uint8);
+ case ushort uint16:
+ return VariantUtils.CreateFrom(uint16);
+ case uint uint32:
+ return VariantUtils.CreateFrom(uint32);
+ case ulong uint64:
+ return VariantUtils.CreateFrom(uint64);
+ case float @float:
+ return VariantUtils.CreateFrom(@float);
+ case double @double:
+ return VariantUtils.CreateFrom(@double);
+ case Vector2 vector2:
+ return VariantUtils.CreateFrom(vector2);
+ case Vector2I vector2I:
+ return VariantUtils.CreateFrom(vector2I);
+ case Rect2 rect2:
+ return VariantUtils.CreateFrom(rect2);
+ case Rect2I rect2I:
+ return VariantUtils.CreateFrom(rect2I);
+ case Transform2D transform2D:
+ return VariantUtils.CreateFrom(transform2D);
+ case Vector3 vector3:
+ return VariantUtils.CreateFrom(vector3);
+ case Vector3I vector3I:
+ return VariantUtils.CreateFrom(vector3I);
+ case Vector4 vector4:
+ return VariantUtils.CreateFrom(vector4);
+ case Vector4I vector4I:
+ return VariantUtils.CreateFrom(vector4I);
+ case Basis basis:
+ return VariantUtils.CreateFrom(basis);
+ case Quaternion quaternion:
+ return VariantUtils.CreateFrom(quaternion);
+ case Transform3D transform3D:
+ return VariantUtils.CreateFrom(transform3D);
+ case Projection projection:
+ return VariantUtils.CreateFrom(projection);
+ case Aabb aabb:
+ return VariantUtils.CreateFrom(aabb);
+ case Color color:
+ return VariantUtils.CreateFrom(color);
+ case Plane plane:
+ return VariantUtils.CreateFrom(plane);
+ case Callable callable:
+ return VariantUtils.CreateFrom(callable);
+ case Signal signal:
+ return VariantUtils.CreateFrom(signal);
+ case string @string:
+ return VariantUtils.CreateFrom(@string);
+ case byte[] byteArray:
+ return VariantUtils.CreateFrom(byteArray);
+ case int[] int32Array:
+ return VariantUtils.CreateFrom(int32Array);
+ case long[] int64Array:
+ return VariantUtils.CreateFrom(int64Array);
+ case float[] floatArray:
+ return VariantUtils.CreateFrom(floatArray);
+ case double[] doubleArray:
+ return VariantUtils.CreateFrom(doubleArray);
+ case string[] stringArray:
+ return VariantUtils.CreateFrom(stringArray);
+ case Vector2[] vector2Array:
+ return VariantUtils.CreateFrom(vector2Array);
+ case Vector3[] vector3Array:
+ return VariantUtils.CreateFrom(vector3Array);
+ case Color[] colorArray:
+ return VariantUtils.CreateFrom(colorArray);
+ case StringName[] stringNameArray:
+ return VariantUtils.CreateFrom(stringNameArray);
+ case NodePath[] nodePathArray:
+ return VariantUtils.CreateFrom(nodePathArray);
+ case Rid[] ridArray:
+ return VariantUtils.CreateFrom(ridArray);
+ case GodotObject[] godotObjectArray:
+ return VariantUtils.CreateFrom(godotObjectArray);
+ case StringName stringName:
+ return VariantUtils.CreateFrom(stringName);
+ case NodePath nodePath:
+ return VariantUtils.CreateFrom(nodePath);
+ case Rid rid:
+ return VariantUtils.CreateFrom(rid);
+ case Collections.Dictionary godotDictionary:
+ return VariantUtils.CreateFrom(godotDictionary);
+ case Collections.Array godotArray:
+ return VariantUtils.CreateFrom(godotArray);
+ case Variant variant:
+ return VariantUtils.CreateFrom(variant);
+ case GodotObject godotObject:
+ return VariantUtils.CreateFrom(godotObject);
+ case Enum @enum:
+ return VariantUtils.CreateFrom(Convert.ToInt64(@enum));
+ case Collections.IGenericGodotDictionary godotDictionary:
+ return VariantUtils.CreateFrom(godotDictionary.UnderlyingDictionary);
+ case Collections.IGenericGodotArray godotArray:
+ return VariantUtils.CreateFrom(godotArray.UnderlyingArray);
+ }
+
+ GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" +
+ obj.GetType().FullName + ".");
+ return new godot_variant();
+ }
+
+ private delegate object? ConvertToSystemObjectFunc(in godot_variant managed);
+
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ // ReSharper disable once RedundantNameQualifier
+ private static readonly System.Collections.Generic.Dictionary<Type, ConvertToSystemObjectFunc>
+ ToSystemObjectFuncByType = new()
+ {
+ [typeof(bool)] = (in godot_variant variant) => VariantUtils.ConvertTo<bool>(variant),
+ [typeof(char)] = (in godot_variant variant) => VariantUtils.ConvertTo<char>(variant),
+ [typeof(sbyte)] = (in godot_variant variant) => VariantUtils.ConvertTo<sbyte>(variant),
+ [typeof(short)] = (in godot_variant variant) => VariantUtils.ConvertTo<short>(variant),
+ [typeof(int)] = (in godot_variant variant) => VariantUtils.ConvertTo<int>(variant),
+ [typeof(long)] = (in godot_variant variant) => VariantUtils.ConvertTo<long>(variant),
+ [typeof(byte)] = (in godot_variant variant) => VariantUtils.ConvertTo<byte>(variant),
+ [typeof(ushort)] = (in godot_variant variant) => VariantUtils.ConvertTo<ushort>(variant),
+ [typeof(uint)] = (in godot_variant variant) => VariantUtils.ConvertTo<uint>(variant),
+ [typeof(ulong)] = (in godot_variant variant) => VariantUtils.ConvertTo<ulong>(variant),
+ [typeof(float)] = (in godot_variant variant) => VariantUtils.ConvertTo<float>(variant),
+ [typeof(double)] = (in godot_variant variant) => VariantUtils.ConvertTo<double>(variant),
+ [typeof(Vector2)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2>(variant),
+ [typeof(Vector2I)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2I>(variant),
+ [typeof(Rect2)] = (in godot_variant variant) => VariantUtils.ConvertTo<Rect2>(variant),
+ [typeof(Rect2I)] = (in godot_variant variant) => VariantUtils.ConvertTo<Rect2I>(variant),
+ [typeof(Transform2D)] = (in godot_variant variant) => VariantUtils.ConvertTo<Transform2D>(variant),
+ [typeof(Vector3)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3>(variant),
+ [typeof(Vector3I)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3I>(variant),
+ [typeof(Basis)] = (in godot_variant variant) => VariantUtils.ConvertTo<Basis>(variant),
+ [typeof(Quaternion)] = (in godot_variant variant) => VariantUtils.ConvertTo<Quaternion>(variant),
+ [typeof(Transform3D)] = (in godot_variant variant) => VariantUtils.ConvertTo<Transform3D>(variant),
+ [typeof(Vector4)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector4>(variant),
+ [typeof(Vector4I)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector4I>(variant),
+ [typeof(Aabb)] = (in godot_variant variant) => VariantUtils.ConvertTo<Aabb>(variant),
+ [typeof(Color)] = (in godot_variant variant) => VariantUtils.ConvertTo<Color>(variant),
+ [typeof(Plane)] = (in godot_variant variant) => VariantUtils.ConvertTo<Plane>(variant),
+ [typeof(Callable)] = (in godot_variant variant) => VariantUtils.ConvertTo<Callable>(variant),
+ [typeof(Signal)] = (in godot_variant variant) => VariantUtils.ConvertTo<Signal>(variant),
+ [typeof(string)] = (in godot_variant variant) => VariantUtils.ConvertTo<string>(variant),
+ [typeof(byte[])] = (in godot_variant variant) => VariantUtils.ConvertTo<byte[]>(variant),
+ [typeof(int[])] = (in godot_variant variant) => VariantUtils.ConvertTo<int[]>(variant),
+ [typeof(long[])] = (in godot_variant variant) => VariantUtils.ConvertTo<long[]>(variant),
+ [typeof(float[])] = (in godot_variant variant) => VariantUtils.ConvertTo<float[]>(variant),
+ [typeof(double[])] = (in godot_variant variant) => VariantUtils.ConvertTo<double[]>(variant),
+ [typeof(string[])] = (in godot_variant variant) => VariantUtils.ConvertTo<string[]>(variant),
+ [typeof(Vector2[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2[]>(variant),
+ [typeof(Vector3[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3[]>(variant),
+ [typeof(Color[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Color[]>(variant),
+ [typeof(StringName[])] =
+ (in godot_variant variant) => VariantUtils.ConvertTo<StringName[]>(variant),
+ [typeof(NodePath[])] = (in godot_variant variant) => VariantUtils.ConvertTo<NodePath[]>(variant),
+ [typeof(Rid[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Rid[]>(variant),
+ [typeof(StringName)] = (in godot_variant variant) => VariantUtils.ConvertTo<StringName>(variant),
+ [typeof(NodePath)] = (in godot_variant variant) => VariantUtils.ConvertTo<NodePath>(variant),
+ [typeof(Rid)] = (in godot_variant variant) => VariantUtils.ConvertTo<Rid>(variant),
+ [typeof(Godot.Collections.Dictionary)] = (in godot_variant variant) =>
+ VariantUtils.ConvertTo<Godot.Collections.Dictionary>(variant),
+ [typeof(Godot.Collections.Array)] =
+ (in godot_variant variant) => VariantUtils.ConvertTo<Godot.Collections.Array>(variant),
+ [typeof(Variant)] = (in godot_variant variant) => VariantUtils.ConvertTo<Variant>(variant),
+ };
+
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ public static object? ConvertToObjectOfType(in godot_variant variant, Type type)
+ {
+ if (ToSystemObjectFuncByType.TryGetValue(type, out var func))
+ return func(variant);
+
+ if (typeof(GodotObject).IsAssignableFrom(type))
+ return Convert.ChangeType(VariantUtils.ConvertTo<GodotObject>(variant), type);
+
+ if (typeof(GodotObject[]).IsAssignableFrom(type))
+ {
+ static GodotObject[] ConvertToSystemArrayOfGodotObject(in godot_array nativeArray, Type type)
+ {
+ var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(nativeArray));
+
+ int length = array.Count;
+ var ret = (GodotObject[])Activator.CreateInstance(type, length)!;
+
+ for (int i = 0; i < length; i++)
+ ret[i] = array[i].AsGodotObject();
+
+ return ret;
+ }
+
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(variant);
+ return Convert.ChangeType(ConvertToSystemArrayOfGodotObject(godotArray, type), type);
+ }
+
+ if (type.IsEnum)
+ {
+ var enumUnderlyingType = type.GetEnumUnderlyingType();
+
+ switch (Type.GetTypeCode(enumUnderlyingType))
+ {
+ case TypeCode.SByte:
+ return Enum.ToObject(type, VariantUtils.ConvertToInt8(variant));
+ case TypeCode.Int16:
+ return Enum.ToObject(type, VariantUtils.ConvertToInt16(variant));
+ case TypeCode.Int32:
+ return Enum.ToObject(type, VariantUtils.ConvertToInt32(variant));
+ case TypeCode.Int64:
+ return Enum.ToObject(type, VariantUtils.ConvertToInt64(variant));
+ case TypeCode.Byte:
+ return Enum.ToObject(type, VariantUtils.ConvertToUInt8(variant));
+ case TypeCode.UInt16:
+ return Enum.ToObject(type, VariantUtils.ConvertToUInt16(variant));
+ case TypeCode.UInt32:
+ return Enum.ToObject(type, VariantUtils.ConvertToUInt32(variant));
+ case TypeCode.UInt64:
+ return Enum.ToObject(type, VariantUtils.ConvertToUInt64(variant));
+ default:
+ {
+ GD.PushError(
+ "Attempted to convert Variant to enum value of unsupported underlying type. Name: " +
+ type.FullName + " : " + enumUnderlyingType.FullName + ".");
+ return null;
+ }
+ }
+ }
+
+ if (type.IsGenericType)
+ {
+ var genericTypeDef = type.GetGenericTypeDefinition();
+
+ if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>))
+ {
+ var ctor = type.GetConstructor(BindingFlags.Default,
+ new[] { typeof(Godot.Collections.Dictionary) });
+
+ if (ctor == null)
+ throw new InvalidOperationException("Dictionary constructor not found");
+
+ return ctor.Invoke(new object?[]
+ {
+ VariantUtils.ConvertTo<Godot.Collections.Dictionary>(variant)
+ });
+ }
+
+ if (genericTypeDef == typeof(Godot.Collections.Array<>))
+ {
+ var ctor = type.GetConstructor(BindingFlags.Default,
+ new[] { typeof(Godot.Collections.Array) });
+
+ if (ctor == null)
+ throw new InvalidOperationException("Array constructor not found");
+
+ return ctor.Invoke(new object?[]
+ {
+ VariantUtils.ConvertTo<Godot.Collections.Array>(variant)
+ });
+ }
+ }
+
+ GD.PushError($"Attempted to convert Variant to unsupported type. Name: {type.FullName}.");
+ return null;
+ }
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index f8793332a0..923b2adafd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -68,7 +68,15 @@ namespace Godot.Collections
}
/// <summary>
- /// Duplicates this <see cref="Dictionary"/>.
+ /// Returns a copy of the <see cref="Dictionary"/>.
+ /// If <paramref name="deep"/> is <see langword="true"/>, a deep copy is performed:
+ /// all nested arrays and dictionaries are duplicated and will not be shared with
+ /// the original dictionary. If <see langword="false"/>, a shallow copy is made and
+ /// references to the original nested arrays and dictionaries are kept, so that
+ /// modifying a sub-array or dictionary in the copy will also impact those
+ /// referenced in the source dictionary. Note that any <see cref="GodotObject"/> derived
+ /// elements will be shallow copied regardless of the <paramref name="deep"/>
+ /// setting.
/// </summary>
/// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
/// <returns>A new Godot Dictionary.</returns>
@@ -80,6 +88,44 @@ namespace Godot.Collections
return CreateTakingOwnershipOfDisposableValue(newDictionary);
}
+ /// <summary>
+ /// Adds entries from <paramref name="dictionary"/> to this dictionary.
+ /// By default, duplicate keys are not copied over, unless <paramref name="overwrite"/>
+ /// is <see langword="true"/>.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The dictionary is read-only.
+ /// </exception>
+ /// <param name="dictionary">Dictionary to copy entries from.</param>
+ /// <param name="overwrite">If duplicate keys should be copied over as well.</param>
+ public void Merge(Dictionary dictionary, bool overwrite = false)
+ {
+ ThrowIfReadOnly();
+
+ var self = (godot_dictionary)NativeValue;
+ var other = (godot_dictionary)dictionary.NativeValue;
+ NativeFuncs.godotsharp_dictionary_merge(ref self, in other, overwrite.ToGodotBool());
+ }
+
+ /// <summary>
+ /// Compares this <see cref="Dictionary"/> against the <paramref name="other"/>
+ /// <see cref="Dictionary"/> recursively. Returns <see langword="true"/> if the
+ /// two dictionaries contain the same keys and values. The order of the entries
+ /// does not matter.
+ /// otherwise.
+ /// </summary>
+ /// <param name="other">The other dictionary to compare against.</param>
+ /// <returns>
+ /// <see langword="true"/> if the dictionaries contain the same keys and values,
+ /// <see langword="false"/> otherwise.
+ /// </returns>
+ public bool RecursiveEqual(Dictionary other)
+ {
+ var self = (godot_dictionary)NativeValue;
+ var otherVariant = (godot_dictionary)other.NativeValue;
+ return NativeFuncs.godotsharp_dictionary_recursive_equal(ref self, otherVariant).ToBool();
+ }
+
// IDictionary
/// <summary>
@@ -134,6 +180,13 @@ namespace Godot.Collections
/// <summary>
/// Returns the value at the given <paramref name="key"/>.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The property is assigned and the dictionary is read-only.
+ /// </exception>
+ /// <exception cref="KeyNotFoundException">
+ /// The property is retrieved and an entry for <paramref name="key"/>
+ /// does not exist in the dictionary.
+ /// </exception>
/// <value>The value at the given <paramref name="key"/>.</value>
public Variant this[Variant key]
{
@@ -153,6 +206,8 @@ namespace Godot.Collections
}
set
{
+ ThrowIfReadOnly();
+
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_set_value(ref self,
(godot_variant)key.NativeVar, (godot_variant)value.NativeVar);
@@ -163,10 +218,18 @@ namespace Godot.Collections
/// Adds an value <paramref name="value"/> at key <paramref name="key"/>
/// to this <see cref="Dictionary"/>.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The dictionary is read-only.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// An entry for <paramref name="key"/> already exists in the dictionary.
+ /// </exception>
/// <param name="key">The key at which to add the value.</param>
/// <param name="value">The value to add.</param>
public void Add(Variant key, Variant value)
{
+ ThrowIfReadOnly();
+
var variantKey = (godot_variant)key.NativeVar;
var self = (godot_dictionary)NativeValue;
@@ -181,10 +244,15 @@ namespace Godot.Collections
=> Add(item.Key, item.Value);
/// <summary>
- /// Erases all items from this <see cref="Dictionary"/>.
+ /// Clears the dictionary, removing all entries from it.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The dictionary is read-only.
+ /// </exception>
public void Clear()
{
+ ThrowIfReadOnly();
+
var self = (godot_dictionary)NativeValue;
NativeFuncs.godotsharp_dictionary_clear(ref self);
}
@@ -200,7 +268,7 @@ namespace Godot.Collections
return NativeFuncs.godotsharp_dictionary_contains_key(ref self, (godot_variant)key.NativeVar).ToBool();
}
- public bool Contains(KeyValuePair<Variant, Variant> item)
+ bool ICollection<KeyValuePair<Variant, Variant>>.Contains(KeyValuePair<Variant, Variant> item)
{
godot_variant variantKey = (godot_variant)item.Key.NativeVar;
var self = (godot_dictionary)NativeValue;
@@ -220,15 +288,22 @@ namespace Godot.Collections
/// <summary>
/// Removes an element from this <see cref="Dictionary"/> by key.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The dictionary is read-only.
+ /// </exception>
/// <param name="key">The key of the element to remove.</param>
public bool Remove(Variant key)
{
+ ThrowIfReadOnly();
+
var self = (godot_dictionary)NativeValue;
return NativeFuncs.godotsharp_dictionary_remove_key(ref self, (godot_variant)key.NativeVar).ToBool();
}
- public bool Remove(KeyValuePair<Variant, Variant> item)
+ bool ICollection<KeyValuePair<Variant, Variant>>.Remove(KeyValuePair<Variant, Variant> item)
{
+ ThrowIfReadOnly();
+
godot_variant variantKey = (godot_variant)item.Key.NativeVar;
var self = (godot_dictionary)NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
@@ -264,8 +339,37 @@ namespace Godot.Collections
}
}
- bool ICollection<KeyValuePair<Variant, Variant>>.IsReadOnly => false;
+ /// <summary>
+ /// Returns <see langword="true"/> if the dictionary is read-only.
+ /// See <see cref="MakeReadOnly"/>.
+ /// </summary>
+ public bool IsReadOnly => NativeValue.DangerousSelfRef.IsReadOnly;
+ /// <summary>
+ /// Makes the <see cref="Dictionary"/> read-only, i.e. disabled modying of the
+ /// dictionary's elements. Does not apply to nested content, e.g. content of
+ /// nested dictionaries.
+ /// </summary>
+ public void MakeReadOnly()
+ {
+ if (IsReadOnly)
+ {
+ // Avoid interop call when the dictionary is already read-only.
+ return;
+ }
+
+ var self = (godot_dictionary)NativeValue;
+ NativeFuncs.godotsharp_dictionary_make_read_only(ref self);
+ }
+
+ /// <summary>
+ /// Gets the value for the given <paramref name="key"/> in the dictionary.
+ /// Returns <see langword="true"/> if an entry for the given key exists in
+ /// the dictionary; otherwise, returns <see langword="false"/>.
+ /// </summary>
+ /// <param name="key">The key of the element to get.</param>
+ /// <param name="value">The value at the given <paramref name="key"/>.</param>
+ /// <returns>If an entry was found for the given <paramref name="key"/>.</returns>
public bool TryGetValue(Variant key, out Variant value)
{
var self = (godot_dictionary)NativeValue;
@@ -283,7 +387,7 @@ namespace Godot.Collections
/// </summary>
/// <param name="array">The array to copy to.</param>
/// <param name="arrayIndex">The index to start at.</param>
- public void CopyTo(KeyValuePair<Variant, Variant>[] array, int arrayIndex)
+ void ICollection<KeyValuePair<Variant, Variant>>.CopyTo(KeyValuePair<Variant, Variant>[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
@@ -342,6 +446,19 @@ namespace Godot.Collections
using (str)
return Marshaling.ConvertStringToManaged(str);
}
+
+ private void ThrowIfReadOnly()
+ {
+ if (IsReadOnly)
+ {
+ throw new InvalidOperationException("Dictionary instance is read-only.");
+ }
+ }
+ }
+
+ internal interface IGenericGodotDictionary
+ {
+ public Dictionary UnderlyingDictionary { get; }
}
/// <summary>
@@ -354,57 +471,25 @@ namespace Godot.Collections
/// <typeparam name="TValue">The type of the dictionary's values.</typeparam>
public class Dictionary<[MustBeVariant] TKey, [MustBeVariant] TValue> :
IDictionary<TKey, TValue>,
- IReadOnlyDictionary<TKey, TValue>
+ IReadOnlyDictionary<TKey, TValue>,
+ IGenericGodotDictionary
{
private static godot_variant ToVariantFunc(in Dictionary<TKey, TValue> godotDictionary) =>
VariantUtils.CreateFromDictionary(godotDictionary);
private static Dictionary<TKey, TValue> FromVariantFunc(in godot_variant variant) =>
- VariantUtils.ConvertToDictionaryObject<TKey, TValue>(variant);
-
- // ReSharper disable StaticMemberInGenericType
- // Warning is about unique static fields being created for each generic type combination:
- // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
- // In our case this is exactly what we want.
-
- private static readonly unsafe delegate* managed<in TKey, godot_variant> ConvertKeyToVariantCallback;
- private static readonly unsafe delegate* managed<in godot_variant, TKey> ConvertKeyToManagedCallback;
- private static readonly unsafe delegate* managed<in TValue, godot_variant> ConvertValueToVariantCallback;
- private static readonly unsafe delegate* managed<in godot_variant, TValue> ConvertValueToManagedCallback;
-
- // ReSharper restore StaticMemberInGenericType
+ VariantUtils.ConvertToDictionary<TKey, TValue>(variant);
static unsafe Dictionary()
{
- VariantConversionCallbacks.GenericConversionCallbacks[typeof(Dictionary<TKey, TValue>)] =
- (
- (IntPtr)(delegate* managed<in Dictionary<TKey, TValue>, godot_variant>)&ToVariantFunc,
- (IntPtr)(delegate* managed<in godot_variant, Dictionary<TKey, TValue>>)&FromVariantFunc
- );
-
- ConvertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
- ConvertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
- ConvertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
- ConvertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
- }
-
- private static unsafe void ValidateVariantConversionCallbacks()
- {
- if (ConvertKeyToVariantCallback == null || ConvertKeyToManagedCallback == null)
- {
- throw new InvalidOperationException(
- $"The dictionary key type is not supported for conversion to Variant: '{typeof(TKey).FullName}'.");
- }
-
- if (ConvertValueToVariantCallback == null || ConvertValueToManagedCallback == null)
- {
- throw new InvalidOperationException(
- $"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'.");
- }
+ VariantUtils.GenericConversion<Dictionary<TKey, TValue>>.ToVariantCb = &ToVariantFunc;
+ VariantUtils.GenericConversion<Dictionary<TKey, TValue>>.FromVariantCb = &FromVariantFunc;
}
private readonly Dictionary _underlyingDict;
+ Dictionary IGenericGodotDictionary.UnderlyingDictionary => _underlyingDict;
+
internal ref godot_dictionary.movable NativeValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -416,8 +501,6 @@ namespace Godot.Collections
/// </summary>
public Dictionary()
{
- ValidateVariantConversionCallbacks();
-
_underlyingDict = new Dictionary();
}
@@ -428,8 +511,6 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(IDictionary<TKey, TValue> dictionary)
{
- ValidateVariantConversionCallbacks();
-
if (dictionary == null)
throw new ArgumentNullException(nameof(dictionary));
@@ -446,8 +527,6 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(Dictionary dictionary)
{
- ValidateVariantConversionCallbacks();
-
_underlyingDict = dictionary;
}
@@ -466,33 +545,77 @@ namespace Godot.Collections
}
/// <summary>
- /// Duplicates this <see cref="Dictionary{TKey, TValue}"/>.
+ /// Returns a copy of the <see cref="Dictionary{TKey, TValue}"/>.
+ /// If <paramref name="deep"/> is <see langword="true"/>, a deep copy is performed:
+ /// all nested arrays and dictionaries are duplicated and will not be shared with
+ /// the original dictionary. If <see langword="false"/>, a shallow copy is made and
+ /// references to the original nested arrays and dictionaries are kept, so that
+ /// modifying a sub-array or dictionary in the copy will also impact those
+ /// referenced in the source dictionary. Note that any <see cref="GodotObject"/> derived
+ /// elements will be shallow copied regardless of the <paramref name="deep"/>
+ /// setting.
/// </summary>
- /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
- /// <returns>A new Godot Dictionary.</returns>
public Dictionary<TKey, TValue> Duplicate(bool deep = false)
{
return new Dictionary<TKey, TValue>(_underlyingDict.Duplicate(deep));
}
+ /// <summary>
+ /// Adds entries from <paramref name="dictionary"/> to this dictionary.
+ /// By default, duplicate keys are not copied over, unless <paramref name="overwrite"/>
+ /// is <see langword="true"/>.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The dictionary is read-only.
+ /// </exception>
+ /// <param name="dictionary">Dictionary to copy entries from.</param>
+ /// <param name="overwrite">If duplicate keys should be copied over as well.</param>
+ public void Merge(Dictionary<TKey, TValue> dictionary, bool overwrite = false)
+ {
+ _underlyingDict.Merge(dictionary._underlyingDict, overwrite);
+ }
+
+ /// <summary>
+ /// Compares this <see cref="Dictionary{TKey, TValue}"/> against the <paramref name="other"/>
+ /// <see cref="Dictionary{TKey, TValue}"/> recursively. Returns <see langword="true"/> if the
+ /// two dictionaries contain the same keys and values. The order of the entries does not matter.
+ /// otherwise.
+ /// </summary>
+ /// <param name="other">The other dictionary to compare against.</param>
+ /// <returns>
+ /// <see langword="true"/> if the dictionaries contain the same keys and values,
+ /// <see langword="false"/> otherwise.
+ /// </returns>
+ public bool RecursiveEqual(Dictionary<TKey, TValue> other)
+ {
+ return _underlyingDict.RecursiveEqual(other._underlyingDict);
+ }
+
// IDictionary<TKey, TValue>
/// <summary>
/// Returns the value at the given <paramref name="key"/>.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The property is assigned and the dictionary is read-only.
+ /// </exception>
+ /// <exception cref="KeyNotFoundException">
+ /// The property is retrieved and an entry for <paramref name="key"/>
+ /// does not exist in the dictionary.
+ /// </exception>
/// <value>The value at the given <paramref name="key"/>.</value>
- public unsafe TValue this[TKey key]
+ public TValue this[TKey key]
{
get
{
- using var variantKey = ConvertKeyToVariantCallback(key);
+ using var variantKey = VariantUtils.CreateFrom(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant value).ToBool())
{
using (value)
- return ConvertValueToManagedCallback(value);
+ return VariantUtils.ConvertTo<TValue>(value);
}
else
{
@@ -501,8 +624,10 @@ namespace Godot.Collections
}
set
{
- using var variantKey = ConvertKeyToVariantCallback(key);
- using var variantValue = ConvertValueToVariantCallback(value);
+ ThrowIfReadOnly();
+
+ using var variantKey = VariantUtils.CreateFrom(key);
+ using var variantValue = VariantUtils.CreateFrom(value);
var self = (godot_dictionary)_underlyingDict.NativeValue;
NativeFuncs.godotsharp_dictionary_set_value(ref self,
variantKey, variantValue);
@@ -541,7 +666,7 @@ namespace Godot.Collections
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
- private unsafe KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
+ private KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
{
var self = (godot_dictionary)_underlyingDict.NativeValue;
NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index,
@@ -551,8 +676,8 @@ namespace Godot.Collections
using (value)
{
return new KeyValuePair<TKey, TValue>(
- ConvertKeyToManagedCallback(key),
- ConvertValueToManagedCallback(value));
+ VariantUtils.ConvertTo<TKey>(key),
+ VariantUtils.ConvertTo<TValue>(value));
}
}
@@ -560,17 +685,22 @@ namespace Godot.Collections
/// Adds an object <paramref name="value"/> at key <paramref name="key"/>
/// to this <see cref="Dictionary{TKey, TValue}"/>.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The dictionary is read-only.
+ /// </exception>
/// <param name="key">The key at which to add the object.</param>
/// <param name="value">The object to add.</param>
- public unsafe void Add(TKey key, TValue value)
+ public void Add(TKey key, TValue value)
{
- using var variantKey = ConvertKeyToVariantCallback(key);
+ ThrowIfReadOnly();
+
+ using var variantKey = VariantUtils.CreateFrom(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool())
throw new ArgumentException("An element with the same key already exists.", nameof(key));
- using var variantValue = ConvertValueToVariantCallback(value);
+ using var variantValue = VariantUtils.CreateFrom(value);
NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
}
@@ -579,9 +709,9 @@ namespace Godot.Collections
/// </summary>
/// <param name="key">The key to look for.</param>
/// <returns>Whether or not this dictionary contains the given key.</returns>
- public unsafe bool ContainsKey(TKey key)
+ public bool ContainsKey(TKey key)
{
- using var variantKey = ConvertKeyToVariantCallback(key);
+ using var variantKey = VariantUtils.CreateFrom(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool();
}
@@ -589,29 +719,36 @@ namespace Godot.Collections
/// <summary>
/// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The dictionary is read-only.
+ /// </exception>
/// <param name="key">The key of the element to remove.</param>
- public unsafe bool Remove(TKey key)
+ public bool Remove(TKey key)
{
- using var variantKey = ConvertKeyToVariantCallback(key);
+ ThrowIfReadOnly();
+
+ using var variantKey = VariantUtils.CreateFrom(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool();
}
/// <summary>
- /// Gets the object at the given <paramref name="key"/>.
+ /// Gets the value for the given <paramref name="key"/> in the dictionary.
+ /// Returns <see langword="true"/> if an entry for the given key exists in
+ /// the dictionary; otherwise, returns <see langword="false"/>.
/// </summary>
/// <param name="key">The key of the element to get.</param>
/// <param name="value">The value at the given <paramref name="key"/>.</param>
- /// <returns>If an object was found for the given <paramref name="key"/>.</returns>
- public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
+ /// <returns>If an entry was found for the given <paramref name="key"/>.</returns>
+ public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
- using var variantKey = ConvertKeyToVariantCallback(key);
+ using var variantKey = VariantUtils.CreateFrom(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
using (retValue)
- value = found ? ConvertValueToManagedCallback(retValue) : default;
+ value = found ? VariantUtils.ConvertTo<TValue>(retValue) : default;
return found;
}
@@ -625,19 +762,36 @@ namespace Godot.Collections
/// <returns>The number of elements.</returns>
public int Count => _underlyingDict.Count;
- bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
+ /// <summary>
+ /// Returns <see langword="true"/> if the dictionary is read-only.
+ /// See <see cref="MakeReadOnly"/>.
+ /// </summary>
+ public bool IsReadOnly => _underlyingDict.IsReadOnly;
+
+ /// <summary>
+ /// Makes the <see cref="Dictionary{TKey, TValue}"/> read-only, i.e. disabled
+ /// modying of the dictionary's elements. Does not apply to nested content,
+ /// e.g. content of nested dictionaries.
+ /// </summary>
+ public void MakeReadOnly()
+ {
+ _underlyingDict.MakeReadOnly();
+ }
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
=> Add(item.Key, item.Value);
/// <summary>
- /// Erases all the items from this <see cref="Dictionary{TKey, TValue}"/>.
+ /// Clears the dictionary, removing all entries from it.
/// </summary>
+ /// <exception cref="InvalidOperationException">
+ /// The dictionary is read-only.
+ /// </exception>
public void Clear() => _underlyingDict.Clear();
- unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
+ bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
- using var variantKey = ConvertKeyToVariantCallback(item.Key);
+ using var variantKey = VariantUtils.CreateFrom(item.Key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
@@ -647,7 +801,7 @@ namespace Godot.Collections
if (!found)
return false;
- using var variantValue = ConvertValueToVariantCallback(item.Value);
+ using var variantValue = VariantUtils.CreateFrom(item.Value);
return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
}
}
@@ -658,7 +812,7 @@ namespace Godot.Collections
/// </summary>
/// <param name="array">The array to copy to.</param>
/// <param name="arrayIndex">The index to start at.</param>
- public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
@@ -680,9 +834,11 @@ namespace Godot.Collections
}
}
- unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
+ bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
- using var variantKey = ConvertKeyToVariantCallback(item.Key);
+ ThrowIfReadOnly();
+
+ using var variantKey = VariantUtils.CreateFrom(item.Key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
@@ -692,7 +848,7 @@ namespace Godot.Collections
if (!found)
return false;
- using var variantValue = ConvertValueToVariantCallback(item.Value);
+ using var variantValue = VariantUtils.CreateFrom(item.Value);
if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
{
return NativeFuncs.godotsharp_dictionary_remove_key(
@@ -731,5 +887,13 @@ namespace Godot.Collections
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Dictionary<TKey, TValue>(Variant from) =>
from.AsGodotDictionary<TKey, TValue>();
+
+ private void ThrowIfReadOnly()
+ {
+ if (IsReadOnly)
+ {
+ throw new InvalidOperationException("Dictionary instance is read-only.");
+ }
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
index e6cb4171a7..e7370b2b05 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
@@ -9,7 +9,10 @@ namespace Godot
internal static GodotTaskScheduler DefaultGodotTaskScheduler;
internal static void InitializeDefaultGodotTaskScheduler()
- => DefaultGodotTaskScheduler = new GodotTaskScheduler();
+ {
+ DefaultGodotTaskScheduler?.Dispose();
+ DefaultGodotTaskScheduler = new GodotTaskScheduler();
+ }
public static GodotSynchronizationContext SynchronizationContext => DefaultGodotTaskScheduler.Context;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs
index 421b588560..53292e10cf 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs
@@ -28,7 +28,7 @@ namespace Godot
try
{
- isStdoutVerbose = OS.IsStdoutVerbose();
+ isStdoutVerbose = OS.IsStdOutVerbose();
}
catch (ObjectDisposedException)
{
@@ -43,9 +43,9 @@ namespace Godot
// like StringName, NodePath, Godot.Collections.Array/Dictionary, etc.
// The Godot Object Dispose() method may need any of the later instances.
- foreach (WeakReference<Object> item in GodotObjectInstances.Keys)
+ foreach (WeakReference<GodotObject> item in GodotObjectInstances.Keys)
{
- if (item.TryGetTarget(out Object? self))
+ if (item.TryGetTarget(out GodotObject? self))
self.Dispose();
}
@@ -60,15 +60,15 @@ namespace Godot
}
// ReSharper disable once RedundantNameQualifier
- private static ConcurrentDictionary<WeakReference<Godot.Object>, byte> GodotObjectInstances { get; } =
+ private static ConcurrentDictionary<WeakReference<GodotObject>, byte> GodotObjectInstances { get; } =
new();
private static ConcurrentDictionary<WeakReference<IDisposable>, byte> OtherInstances { get; } =
new();
- public static WeakReference<Object> RegisterGodotObject(Object godotObject)
+ public static WeakReference<GodotObject> RegisterGodotObject(GodotObject godotObject)
{
- var weakReferenceToSelf = new WeakReference<Object>(godotObject);
+ var weakReferenceToSelf = new WeakReference<GodotObject>(godotObject);
GodotObjectInstances.TryAdd(weakReferenceToSelf, 0);
return weakReferenceToSelf;
}
@@ -80,7 +80,7 @@ namespace Godot
return weakReferenceToSelf;
}
- public static void UnregisterGodotObject(Object godotObject, WeakReference<Object> weakReferenceToSelf)
+ public static void UnregisterGodotObject(GodotObject godotObject, WeakReference<GodotObject> weakReferenceToSelf)
{
if (!GodotObjectInstances.TryRemove(weakReferenceToSelf, out _))
throw new ArgumentException("Godot Object not registered.", nameof(weakReferenceToSelf));
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/GodotObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/GodotObjectExtensions.cs
new file mode 100644
index 0000000000..6c90c17078
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/GodotObjectExtensions.cs
@@ -0,0 +1,86 @@
+using System;
+using Godot.NativeInterop;
+
+namespace Godot
+{
+ public partial class GodotObject
+ {
+ /// <summary>
+ /// Returns the <see cref="GodotObject"/> that corresponds to <paramref name="instanceId"/>.
+ /// All Objects have a unique instance ID. See also <see cref="GetInstanceId"/>.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// public partial class MyNode : Node
+ /// {
+ /// public string Foo { get; set; } = "bar";
+ ///
+ /// public override void _Ready()
+ /// {
+ /// ulong id = GetInstanceId();
+ /// var inst = (MyNode)InstanceFromId(Id);
+ /// GD.Print(inst.Foo); // Prints bar
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ /// <param name="instanceId">Instance ID of the Object to retrieve.</param>
+ /// <returns>The <see cref="GodotObject"/> instance.</returns>
+ public static GodotObject InstanceFromId(ulong instanceId)
+ {
+ return InteropUtils.UnmanagedGetManaged(NativeFuncs.godotsharp_instance_from_id(instanceId));
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the <see cref="GodotObject"/> that corresponds
+ /// to <paramref name="id"/> is a valid object (e.g. has not been deleted from
+ /// memory). All Objects have a unique instance ID.
+ /// </summary>
+ /// <param name="id">The Object ID to check.</param>
+ /// <returns>If the instance with the given ID is a valid object.</returns>
+ public static bool IsInstanceIdValid(ulong id)
+ {
+ return IsInstanceValid(InstanceFromId(id));
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if <paramref name="instance"/> is a
+ /// valid <see cref="GodotObject"/> (e.g. has not been deleted from memory).
+ /// </summary>
+ /// <param name="instance">The instance to check.</param>
+ /// <returns>If the instance is a valid object.</returns>
+ public static bool IsInstanceValid(GodotObject instance)
+ {
+ return instance != null && instance.NativeInstance != IntPtr.Zero;
+ }
+
+ /// <summary>
+ /// Returns a weak reference to an object, or <see langword="null"/>
+ /// if the argument is invalid.
+ /// A weak reference to an object is not enough to keep the object alive:
+ /// when the only remaining references to a referent are weak references,
+ /// garbage collection is free to destroy the referent and reuse its memory
+ /// for something else. However, until the object is actually destroyed the
+ /// weak reference may return the object even if there are no strong references
+ /// to it.
+ /// </summary>
+ /// <param name="obj">The object.</param>
+ /// <returns>
+ /// The <see cref="WeakRef"/> reference to the object or <see langword="null"/>.
+ /// </returns>
+ public static WeakRef WeakRef(GodotObject obj)
+ {
+ if (!IsInstanceValid(obj))
+ return null;
+
+ NativeFuncs.godotsharp_weakref(GetPtr(obj), out godot_ref weakRef);
+ using (weakRef)
+ {
+ if (weakRef.IsNull)
+ return null;
+
+ return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef.Reference);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
index 03996bafdd..8325af034c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
@@ -48,13 +48,8 @@ namespace Godot
}
/// <summary>
- /// Fetches a node. The <see cref="NodePath"/> can be either a relative path (from
- /// the current node) or an absolute path (in the scene tree) to a node. If the path
- /// does not exist, a <see langword="null"/> instance is returned and an error
- /// is logged. Attempts to access methods on the return value will result in an
- /// "Attempt to call &lt;method&gt; on a null instance." error.
- /// Note: Fetching absolute paths only works when the node is inside the scene tree
- /// (see <see cref="IsInsideTree"/>).
+ /// Similar to <see cref="GetNode"/>, but does not log an error if <paramref name="path"/>
+ /// does not point to a valid <see cref="Node"/>.
/// </summary>
/// <example>
/// Example: Assume your current node is Character and the following tree:
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs
deleted file mode 100644
index 4094ceeb22..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-using Godot.NativeInterop;
-
-namespace Godot
-{
- public partial class Object
- {
- /// <summary>
- /// Returns whether <paramref name="instance"/> is a valid object
- /// (e.g. has not been deleted from memory).
- /// </summary>
- /// <param name="instance">The instance to check.</param>
- /// <returns>If the instance is a valid object.</returns>
- public static bool IsInstanceValid(Object instance)
- {
- return instance != null && instance.NativeInstance != IntPtr.Zero;
- }
-
- /// <summary>
- /// Returns a weak reference to an object, or <see langword="null"/>
- /// if the argument is invalid.
- /// A weak reference to an object is not enough to keep the object alive:
- /// when the only remaining references to a referent are weak references,
- /// garbage collection is free to destroy the referent and reuse its memory
- /// for something else. However, until the object is actually destroyed the
- /// weak reference may return the object even if there are no strong references
- /// to it.
- /// </summary>
- /// <param name="obj">The object.</param>
- /// <returns>
- /// The <see cref="WeakRef"/> reference to the object or <see langword="null"/>.
- /// </returns>
- public static WeakRef WeakRef(Object obj)
- {
- if (!IsInstanceValid(obj))
- return null;
-
- NativeFuncs.godotsharp_weakref(GetPtr(obj), out godot_ref weakRef);
- using (weakRef)
- {
- if (weakRef.IsNull)
- return null;
-
- return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef.Reference);
- }
- }
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs
index 8463403096..4610761bdb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs
@@ -7,7 +7,7 @@ namespace Godot
/// <summary>
/// Instantiates the scene's node hierarchy, erroring on failure.
/// Triggers child scene instantiation(s). Triggers a
- /// <see cref="Node.NotificationInstanced"/> notification on the root node.
+ /// <see cref="Node.NotificationSceneInstantiated"/> notification on the root node.
/// </summary>
/// <seealso cref="InstantiateOrNull{T}(GenEditState)"/>
/// <exception cref="InvalidCastException">
@@ -23,7 +23,7 @@ namespace Godot
/// <summary>
/// Instantiates the scene's node hierarchy, returning <see langword="null"/> on failure.
/// Triggers child scene instantiation(s). Triggers a
- /// <see cref="Node.NotificationInstanced"/> notification on the root node.
+ /// <see cref="Node.NotificationSceneInstantiated"/> notification on the root node.
/// </summary>
/// <seealso cref="Instantiate{T}(GenEditState)"/>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index e4b79e7ec4..9425b7424c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Text;
using Godot.NativeInterop;
namespace Godot
@@ -10,36 +11,45 @@ namespace Godot
public static partial class GD
{
/// <summary>
- /// Decodes a byte array back to a <c>Variant</c> value.
- /// If <paramref name="allowObjects"/> is <see langword="true"/> decoding objects is allowed.
- ///
- /// WARNING: Deserialized object can contain code which gets executed.
- /// Do not set <paramref name="allowObjects"/> to <see langword="true"/>
- /// if the serialized object comes from untrusted sources to avoid
- /// potential security threats (remote code execution).
+ /// Decodes a byte array back to a <see cref="Variant"/> value, without decoding objects.
+ /// Note: If you need object deserialization, see <see cref="BytesToVarWithObjects"/>.
/// </summary>
- /// <param name="bytes">Byte array that will be decoded to a <c>Variant</c>.</param>
- /// <param name="allowObjects">If objects should be decoded.</param>
- /// <returns>The decoded <c>Variant</c>.</returns>
- public static Variant BytesToVar(Span<byte> bytes, bool allowObjects = false)
+ /// <param name="bytes">Byte array that will be decoded to a <see cref="Variant"/>.</param>
+ /// <returns>The decoded <see cref="Variant"/>.</returns>
+ public static Variant BytesToVar(Span<byte> bytes)
{
using var varBytes = Marshaling.ConvertSystemArrayToNativePackedByteArray(bytes);
- NativeFuncs.godotsharp_bytes_to_var(varBytes, allowObjects.ToGodotBool(), out godot_variant ret);
+ NativeFuncs.godotsharp_bytes_to_var(varBytes, godot_bool.False, out godot_variant ret);
return Variant.CreateTakingOwnershipOfDisposableValue(ret);
}
/// <summary>
- /// Converts from a <c>Variant</c> type to another in the best way possible.
+ /// Decodes a byte array back to a <see cref="Variant"/> value. Decoding objects is allowed.
+ /// Warning: Deserialized object can contain code which gets executed. Do not use this
+ /// option if the serialized object comes from untrusted sources to avoid potential security
+ /// threats (remote code execution).
+ /// </summary>
+ /// <param name="bytes">Byte array that will be decoded to a <see cref="Variant"/>.</param>
+ /// <returns>The decoded <see cref="Variant"/>.</returns>
+ public static Variant BytesToVarWithObjects(Span<byte> bytes)
+ {
+ using var varBytes = Marshaling.ConvertSystemArrayToNativePackedByteArray(bytes);
+ NativeFuncs.godotsharp_bytes_to_var(varBytes, godot_bool.True, out godot_variant ret);
+ return Variant.CreateTakingOwnershipOfDisposableValue(ret);
+ }
+
+ /// <summary>
+ /// Converts <paramref name="what"/> to <paramref name="type"/> in the best way possible.
/// The <paramref name="type"/> parameter uses the <see cref="Variant.Type"/> values.
/// </summary>
/// <example>
/// <code>
- /// var a = new Vector2(1, 0);
- /// // Prints 1
- /// GD.Print(a.Length());
- /// var b = GD.Convert(a, Variant.Type.String)
- /// // Prints 6 as "(1, 0)" is 6 characters
- /// GD.Print(b.Length);
+ /// Variant a = new Godot.Collections.Array { 4, 2.5, 1.2 };
+ /// GD.Print(a.VariantType == Variant.Type.Array); // Prints true
+ ///
+ /// var b = GD.Convert(a, Variant.Type.PackedByteArray);
+ /// GD.Print(b); // Prints [4, 2, 1]
+ /// GD.Print(b.VariantType == Variant.Type.Array); // Prints false
/// </code>
/// </example>
/// <returns>The <c>Variant</c> converted to the given <paramref name="type"/>.</returns>
@@ -50,28 +60,7 @@ namespace Godot
}
/// <summary>
- /// Converts from decibels to linear energy (audio).
- /// </summary>
- /// <seealso cref="LinearToDb(real_t)"/>
- /// <param name="db">Decibels to convert.</param>
- /// <returns>Audio volume as linear energy.</returns>
- public static real_t DbToLinear(real_t db)
- {
- return (real_t)Math.Exp(db * 0.11512925464970228420089957273422);
- }
-
- private static string[] GetPrintParams(object[] parameters)
- {
- if (parameters == null)
- {
- return new[] { "null" };
- }
-
- return Array.ConvertAll(parameters, x => x?.ToString() ?? "null");
- }
-
- /// <summary>
- /// Returns the integer hash of the variable passed.
+ /// Returns the integer hash of the passed <paramref name="var"/>.
/// </summary>
/// <example>
/// <code>
@@ -86,52 +75,6 @@ namespace Godot
}
/// <summary>
- /// Returns the <see cref="Object"/> that corresponds to <paramref name="instanceId"/>.
- /// All Objects have a unique instance ID.
- /// </summary>
- /// <example>
- /// <code>
- /// public class MyNode : Node
- /// {
- /// public string foo = "bar";
- ///
- /// public override void _Ready()
- /// {
- /// ulong id = GetInstanceId();
- /// var inst = (MyNode)GD.InstanceFromId(Id);
- /// GD.Print(inst.foo); // Prints bar
- /// }
- /// }
- /// </code>
- /// </example>
- /// <param name="instanceId">Instance ID of the Object to retrieve.</param>
- /// <returns>The <see cref="Object"/> instance.</returns>
- public static Object InstanceFromId(ulong instanceId)
- {
- return InteropUtils.UnmanagedGetManaged(NativeFuncs.godotsharp_instance_from_id(instanceId));
- }
-
- /// <summary>
- /// Converts from linear energy to decibels (audio).
- /// This can be used to implement volume sliders that behave as expected (since volume isn't linear).
- /// </summary>
- /// <seealso cref="DbToLinear(real_t)"/>
- /// <example>
- /// <code>
- /// // "slider" refers to a node that inherits Range such as HSlider or VSlider.
- /// // Its range must be configured to go from 0 to 1.
- /// // Change the bus name if you'd like to change the volume of a specific bus only.
- /// AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), GD.LinearToDb(slider.value));
- /// </code>
- /// </example>
- /// <param name="linear">The linear energy to convert.</param>
- /// <returns>Audio as decibels.</returns>
- public static real_t LinearToDb(real_t linear)
- {
- return (real_t)(Math.Log(linear) * 8.6858896380650365530225783783321);
- }
-
- /// <summary>
/// Loads a resource from the filesystem located at <paramref name="path"/>.
/// The resource is loaded on the method call (unless it's referenced already
/// elsewhere, e.g. in another script or in the scene), which might cause slight delay,
@@ -185,57 +128,96 @@ namespace Godot
return ResourceLoader.Load<T>(path);
}
- /// <summary>
- /// Pushes an error message to Godot's built-in debugger and to the OS terminal.
- ///
- /// Note: Errors printed this way will not pause project execution.
- /// </summary>
- /// <example>
- /// <code>
- /// GD.PushError("test_error"); // Prints "test error" to debugger and terminal as error call
- /// </code>
- /// </example>
- /// <param name="message">Error message.</param>
- public static void PushError(string message)
+ private static string AppendPrintParams(object[] parameters)
{
- using var godotStr = Marshaling.ConvertStringToNative(message);
- NativeFuncs.godotsharp_pusherror(godotStr);
+ if (parameters == null)
+ {
+ return "null";
+ }
+
+ var sb = new StringBuilder();
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ sb.Append(parameters[i]?.ToString() ?? "null");
+ }
+ return sb.ToString();
+ }
+
+ private static string AppendPrintParams(char separator, object[] parameters)
+ {
+ if (parameters == null)
+ {
+ return "null";
+ }
+
+ var sb = new StringBuilder();
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ if (i != 0)
+ sb.Append(separator);
+ sb.Append(parameters[i]?.ToString() ?? "null");
+ }
+ return sb.ToString();
}
/// <summary>
- /// Pushes a warning message to Godot's built-in debugger and to the OS terminal.
+ /// Prints a message to the console.
+ ///
+ /// Note: Consider using <see cref="PushError(string)"/> and <see cref="PushWarning(string)"/>
+ /// to print error and warning messages instead of <see cref="Print(string)"/>.
+ /// This distinguishes them from print messages used for debugging purposes,
+ /// while also displaying a stack trace when an error or warning is printed.
/// </summary>
- /// <example>
- /// GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call
- /// </example>
- /// <param name="message">Warning message.</param>
- public static void PushWarning(string message)
+ /// <param name="what">Message that will be printed.</param>
+ public static void Print(string what)
{
- using var godotStr = Marshaling.ConvertStringToNative(message);
- NativeFuncs.godotsharp_pushwarning(godotStr);
+ using var godotStr = Marshaling.ConvertStringToNative(what);
+ NativeFuncs.godotsharp_print(godotStr);
}
/// <summary>
/// Converts one or more arguments of any type to string in the best way possible
/// and prints them to the console.
///
- /// Note: Consider using <see cref="PushError(string)"/> and <see cref="PushWarning(string)"/>
+ /// Note: Consider using <see cref="PushError(object[])"/> and <see cref="PushWarning(object[])"/>
/// to print error and warning messages instead of <see cref="Print(object[])"/>.
/// This distinguishes them from print messages used for debugging purposes,
/// while also displaying a stack trace when an error or warning is printed.
/// </summary>
/// <example>
/// <code>
- /// var a = new int[] { 1, 2, 3 };
+ /// var a = new Godot.Collections.Array { 1, 2, 3 };
/// GD.Print("a", "b", a); // Prints ab[1, 2, 3]
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static void Print(params object[] what)
{
- string str = string.Concat(GetPrintParams(what));
- using var godotStr = Marshaling.ConvertStringToNative(str);
- NativeFuncs.godotsharp_print(godotStr);
+ Print(AppendPrintParams(what));
+ }
+
+ /// <summary>
+ /// Prints a message to the console.
+ /// The following BBCode tags are supported: b, i, u, s, indent, code, url, center,
+ /// right, color, bgcolor, fgcolor.
+ /// Color tags only support named colors such as <c>red</c>, not hexadecimal color codes.
+ /// Unsupported tags will be left as-is in standard output.
+ /// When printing to standard output, the supported subset of BBCode is converted to
+ /// ANSI escape codes for the terminal emulator to display. Displaying ANSI escape codes
+ /// is currently only supported on Linux and macOS. Support for ANSI escape codes may vary
+ /// across terminal emulators, especially for italic and strikethrough.
+ ///
+ /// Note: Consider using <see cref="PushError(string)"/> and <see cref="PushWarning(string)"/>
+ /// to print error and warning messages instead of <see cref="Print(string)"/> or
+ /// <see cref="PrintRich(string)"/>.
+ /// This distinguishes them from print messages used for debugging purposes,
+ /// while also displaying a stack trace when an error or warning is printed.
+ /// </summary>
+ /// <param name="what">Message that will be printed.</param>
+ public static void PrintRich(string what)
+ {
+ using var godotStr = Marshaling.ConvertStringToNative(what);
+ NativeFuncs.godotsharp_print_rich(godotStr);
}
/// <summary>
@@ -250,7 +232,7 @@ namespace Godot
/// is currently only supported on Linux and macOS. Support for ANSI escape codes may vary
/// across terminal emulators, especially for italic and strikethrough.
///
- /// Note: Consider using <see cref="PushError(string)"/> and <see cref="PushWarning(string)"/>
+ /// Note: Consider using <see cref="PushError(object[])"/> and <see cref="PushWarning(object[])"/>
/// to print error and warning messages instead of <see cref="Print(object[])"/> or
/// <see cref="PrintRich(object[])"/>.
/// This distinguishes them from print messages used for debugging purposes,
@@ -258,23 +240,23 @@ namespace Godot
/// </summary>
/// <example>
/// <code>
- /// GD.PrintRich("[b]Hello world![/b]"); // Prints out "Hello world!" in bold.
+ /// GD.PrintRich("[code][b]Hello world![/b][/code]"); // Prints out: [b]Hello world![/b]
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static void PrintRich(params object[] what)
{
- string str = string.Concat(GetPrintParams(what));
- using var godotStr = Marshaling.ConvertStringToNative(str);
- NativeFuncs.godotsharp_print_rich(godotStr);
+ PrintRich(AppendPrintParams(what));
}
/// <summary>
- /// Prints the current stack trace information to the console.
+ /// Prints a message to standard error line.
/// </summary>
- public static void PrintStack()
+ /// <param name="what">Message that will be printed.</param>
+ public static void PrintErr(string what)
{
- Print(System.Environment.StackTrace);
+ using var godotStr = Marshaling.ConvertStringToNative(what);
+ NativeFuncs.godotsharp_printerr(godotStr);
}
/// <summary>
@@ -288,31 +270,36 @@ namespace Godot
/// <param name="what">Arguments that will be printed.</param>
public static void PrintErr(params object[] what)
{
- string str = string.Concat(GetPrintParams(what));
- using var godotStr = Marshaling.ConvertStringToNative(str);
- NativeFuncs.godotsharp_printerr(godotStr);
+ PrintErr(AppendPrintParams(what));
}
/// <summary>
- /// Prints one or more arguments to strings in the best way possible to console.
- /// No newline is added at the end.
- ///
- /// Note: Due to limitations with Godot's built-in console, this only prints to the terminal.
- /// If you need to print in the editor, use another method, such as <see cref="Print(object[])"/>.
+ /// Prints a message to the OS terminal.
+ /// Unlike <see cref="Print(string)"/>, no newline is added at the end.
+ /// </summary>
+ /// <param name="what">Message that will be printed.</param>
+ public static void PrintRaw(string what)
+ {
+ using var godotStr = Marshaling.ConvertStringToNative(what);
+ NativeFuncs.godotsharp_printraw(godotStr);
+ }
+
+ /// <summary>
+ /// Prints one or more arguments to strings in the best way possible to the OS terminal.
+ /// Unlike <see cref="Print(object[])"/>, no newline is added at the end.
/// </summary>
/// <example>
/// <code>
/// GD.PrintRaw("A");
/// GD.PrintRaw("B");
- /// // Prints AB
+ /// GD.PrintRaw("C");
+ /// // Prints ABC to terminal
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
public static void PrintRaw(params object[] what)
{
- string str = string.Concat(GetPrintParams(what));
- using var godotStr = Marshaling.ConvertStringToNative(str);
- NativeFuncs.godotsharp_printraw(godotStr);
+ PrintRaw(AppendPrintParams(what));
}
/// <summary>
@@ -326,8 +313,8 @@ namespace Godot
/// <param name="what">Arguments that will be printed.</param>
public static void PrintS(params object[] what)
{
- string str = string.Join(' ', GetPrintParams(what));
- using var godotStr = Marshaling.ConvertStringToNative(str);
+ string message = AppendPrintParams(' ', what);
+ using var godotStr = Marshaling.ConvertStringToNative(message);
NativeFuncs.godotsharp_prints(godotStr);
}
@@ -342,12 +329,74 @@ namespace Godot
/// <param name="what">Arguments that will be printed.</param>
public static void PrintT(params object[] what)
{
- string str = string.Join('\t', GetPrintParams(what));
- using var godotStr = Marshaling.ConvertStringToNative(str);
+ string message = AppendPrintParams('\t', what);
+ using var godotStr = Marshaling.ConvertStringToNative(message);
NativeFuncs.godotsharp_printt(godotStr);
}
/// <summary>
+ /// Pushes an error message to Godot's built-in debugger and to the OS terminal.
+ ///
+ /// Note: Errors printed this way will not pause project execution.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.PushError("test error"); // Prints "test error" to debugger and terminal as error call
+ /// </code>
+ /// </example>
+ /// <param name="message">Error message.</param>
+ public static void PushError(string message)
+ {
+ using var godotStr = Marshaling.ConvertStringToNative(message);
+ NativeFuncs.godotsharp_pusherror(godotStr);
+ }
+
+ /// <summary>
+ /// Pushes an error message to Godot's built-in debugger and to the OS terminal.
+ ///
+ /// Note: Errors printed this way will not pause project execution.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.PushError("test_error"); // Prints "test error" to debugger and terminal as error call
+ /// </code>
+ /// </example>
+ /// <param name="what">Arguments that form the error message.</param>
+ public static void PushError(params object[] what)
+ {
+ PushError(AppendPrintParams(what));
+ }
+
+ /// <summary>
+ /// Pushes a warning message to Godot's built-in debugger and to the OS terminal.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call
+ /// </code>
+ /// </example>
+ /// <param name="message">Warning message.</param>
+ public static void PushWarning(string message)
+ {
+ using var godotStr = Marshaling.ConvertStringToNative(message);
+ NativeFuncs.godotsharp_pushwarning(godotStr);
+ }
+
+ /// <summary>
+ /// Pushes a warning message to Godot's built-in debugger and to the OS terminal.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call
+ /// </code>
+ /// </example>
+ /// <param name="what">Arguments that form the warning message.</param>
+ public static void PushWarning(params object[] what)
+ {
+ PushWarning(AppendPrintParams(what));
+ }
+
+ /// <summary>
/// Returns a random floating point value between <c>0.0</c> and <c>1.0</c> (inclusive).
/// </summary>
/// <example>
@@ -362,7 +411,9 @@ namespace Godot
}
/// <summary>
- /// Returns a normally-distributed pseudo-random number, using Box-Muller transform with the specified <c>mean</c> and a standard <c>deviation</c>.
+ /// Returns a normally-distributed pseudo-random floating point value
+ /// using Box-Muller transform with the specified <pararmref name="mean"/>
+ /// and a standard <paramref name="deviation"/>.
/// This is also called Gaussian distribution.
/// </summary>
/// <returns>A random normally-distributed <see langword="float"/> number.</returns>
@@ -373,7 +424,8 @@ namespace Godot
/// <summary>
/// Returns a random unsigned 32-bit integer.
- /// Use remainder to obtain a random value in the interval <c>[0, N - 1]</c> (where N is smaller than 2^32).
+ /// Use remainder to obtain a random value in the interval <c>[0, N - 1]</c>
+ /// (where N is smaller than 2^32).
/// </summary>
/// <example>
/// <code>
@@ -391,11 +443,11 @@ namespace Godot
/// <summary>
/// Randomizes the seed (or the internal state) of the random number generator.
- /// Current implementation reseeds using a number based on time.
+ /// The current implementation uses a number based on the device's time.
///
/// Note: This method is called automatically when the project is run.
- /// If you need to fix the seed to have reproducible results, use <see cref="Seed(ulong)"/>
- /// to initialize the random number generator.
+ /// If you need to fix the seed to have consistent, reproducible results,
+ /// use <see cref="Seed(ulong)"/> to initialize the random number generator.
/// </summary>
public static void Randomize()
{
@@ -403,12 +455,13 @@ namespace Godot
}
/// <summary>
- /// Returns a random floating point value on the interval between <paramref name="from"/>
+ /// Returns a random floating point value between <paramref name="from"/>
/// and <paramref name="to"/> (inclusive).
/// </summary>
/// <example>
/// <code>
- /// GD.PrintS(GD.RandRange(-10.0, 10.0), GD.RandRange(-10.0, 10.0)); // Prints e.g. -3.844535 7.45315
+ /// GD.RandRange(0.0, 20.5); // Returns e.g. 7.45315
+ /// GD.RandRange(-10.0, 10.0); // Returns e.g. -3.844535
/// </code>
/// </example>
/// <returns>A random <see langword="double"/> number inside the given range.</returns>
@@ -424,8 +477,8 @@ namespace Godot
/// </summary>
/// <example>
/// <code>
- /// GD.Print(GD.RandRange(0, 1)); // Prints 0 or 1
- /// GD.Print(GD.RandRange(-10, 1000)); // Prints any number from -10 to 1000
+ /// GD.RandRange(0, 1); // Returns either 0 or 1
+ /// GD.RandRange(-10, 1000); // Returns random integer between -10 and 1000
/// </code>
/// </example>
/// <returns>A random <see langword="int"/> number inside the given range.</returns>
@@ -435,8 +488,18 @@ namespace Godot
}
/// <summary>
- /// Returns a random unsigned 32-bit integer, using the given <paramref name="seed"/>.
+ /// Given a <paramref name="seed"/>, returns a randomized <see langword="uint"/>
+ /// value. The <paramref name="seed"/> may be modified.
+ /// Passing the same <paramref name="seed"/> consistently returns the same value.
+ ///
+ /// Note: "Seed" here refers to the internal state of the pseudo random number
+ /// generator, currently implemented as a 64 bit integer.
/// </summary>
+ /// <example>
+ /// <code>
+ /// var a = GD.RandFromSeed(4);
+ /// </code>
+ /// </example>
/// <param name="seed">
/// Seed to use to generate the random number.
/// If a different seed is used, its value will be modified.
@@ -449,7 +512,8 @@ namespace Godot
/// <summary>
/// Returns a <see cref="IEnumerable{T}"/> that iterates from
- /// <c>0</c> to <paramref name="end"/> in steps of <c>1</c>.
+ /// <c>0</c> (inclusive) to <paramref name="end"/> (exclusive)
+ /// in steps of <c>1</c>.
/// </summary>
/// <param name="end">The last index.</param>
public static IEnumerable<int> Range(int end)
@@ -459,7 +523,8 @@ namespace Godot
/// <summary>
/// Returns a <see cref="IEnumerable{T}"/> that iterates from
- /// <paramref name="start"/> to <paramref name="end"/> in steps of <c>1</c>.
+ /// <paramref name="start"/> (inclusive) to <paramref name="end"/> (exclusive)
+ /// in steps of <c>1</c>.
/// </summary>
/// <param name="start">The first index.</param>
/// <param name="end">The last index.</param>
@@ -470,13 +535,21 @@ namespace Godot
/// <summary>
/// Returns a <see cref="IEnumerable{T}"/> that iterates from
- /// <paramref name="start"/> to <paramref name="end"/> in steps of <paramref name="step"/>.
+ /// <paramref name="start"/> (inclusive) to <paramref name="end"/> (exclusive)
+ /// in steps of <paramref name="step"/>.
+ /// The argument <paramref name="step"/> can be negative, but not <c>0</c>.
/// </summary>
+ /// <exception cref="ArgumentException">
+ /// <paramref name="step"/> is 0.
+ /// </exception>
/// <param name="start">The first index.</param>
/// <param name="end">The last index.</param>
/// <param name="step">The amount by which to increment the index on each iteration.</param>
public static IEnumerable<int> Range(int start, int end, int step)
{
+ if (step == 0)
+ throw new ArgumentException("step cannot be 0.", nameof(step));
+
if (end < start && step > 0)
yield break;
@@ -496,8 +569,20 @@ namespace Godot
}
/// <summary>
- /// Sets seed for the random number generator.
+ /// Sets seed for the random number generator to <paramref name="seed"/>.
+ /// Setting the seed manually can ensure consistent, repeatable results for
+ /// most random functions.
/// </summary>
+ /// <example>
+ /// <code>
+ /// ulong mySeed = (ulong)GD.Hash("Godot Rocks");
+ /// GD.Seed(mySeed);
+ /// var a = GD.Randf() + GD.Randi();
+ /// GD.Seed(mySeed);
+ /// var b = GD.Randf() + GD.Randi();
+ /// // a and b are now identical
+ /// </code>
+ /// </example>
/// <param name="seed">Seed that will be used.</param>
public static void Seed(ulong seed)
{
@@ -505,26 +590,14 @@ namespace Godot
}
/// <summary>
- /// Converts one or more arguments of any type to string in the best way possible.
- /// </summary>
- /// <param name="what">Arguments that will converted to string.</param>
- /// <returns>The string formed by the given arguments.</returns>
- public static string Str(params Variant[] what)
- {
- using var whatGodot = new Godot.Collections.Array(what);
- NativeFuncs.godotsharp_str((godot_array)whatGodot.NativeValue, out godot_string ret);
- using (ret)
- return Marshaling.ConvertStringToManaged(ret);
- }
-
- /// <summary>
- /// Converts a formatted string that was returned by <see cref="VarToStr(Variant)"/> to the original value.
+ /// Converts a formatted string that was returned by <see cref="VarToStr(Variant)"/>
+ /// to the original value.
/// </summary>
/// <example>
/// <code>
- /// string a = "{\"a\": 1, \"b\": 2 }";
- /// var b = (Godot.Collections.Dictionary)GD.StrToVar(a);
- /// GD.Print(b["a"]); // Prints 1
+ /// string a = "{ \"a\": 1, \"b\": 2 }"; // a is a string
+ /// var b = GD.StrToVar(a).AsGodotDictionary(); // b is a Dictionary
+ /// GD.Print(b["a"]); // Prints 1
/// </code>
/// </example>
/// <param name="str">String that will be converted to Variant.</param>
@@ -537,38 +610,49 @@ namespace Godot
}
/// <summary>
- /// Encodes a <c>Variant</c> value to a byte array.
- /// If <paramref name="fullObjects"/> is <see langword="true"/> encoding objects is allowed
- /// (and can potentially include code).
- /// Deserialization can be done with <see cref="BytesToVar(Span{byte}, bool)"/>.
+ /// Encodes a <see cref="Variant"/> value to a byte array, without encoding objects.
+ /// Deserialization can be done with <see cref="BytesToVar"/>.
+ /// Note: If you need object serialization, see <see cref="VarToBytesWithObjects"/>.
+ /// </summary>
+ /// <param name="var"><see cref="Variant"/> that will be encoded.</param>
+ /// <returns>The <see cref="Variant"/> encoded as an array of bytes.</returns>
+ public static byte[] VarToBytes(Variant var)
+ {
+ NativeFuncs.godotsharp_var_to_bytes((godot_variant)var.NativeVar, godot_bool.False, out var varBytes);
+ using (varBytes)
+ return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes);
+ }
+
+ /// <summary>
+ /// Encodes a <see cref="Variant"/>. Encoding objects is allowed (and can potentially
+ /// include executable code). Deserialization can be done with <see cref="BytesToVarWithObjects"/>.
/// </summary>
- /// <param name="var">Variant that will be encoded.</param>
- /// <param name="fullObjects">If objects should be serialized.</param>
- /// <returns>The <c>Variant</c> encoded as an array of bytes.</returns>
- public static byte[] VarToBytes(Variant var, bool fullObjects = false)
+ /// <param name="var"><see cref="Variant"/> that will be encoded.</param>
+ /// <returns>The <see cref="Variant"/> encoded as an array of bytes.</returns>
+ public static byte[] VarToBytesWithObjects(Variant var)
{
- NativeFuncs.godotsharp_var_to_bytes((godot_variant)var.NativeVar, fullObjects.ToGodotBool(), out var varBytes);
+ NativeFuncs.godotsharp_var_to_bytes((godot_variant)var.NativeVar, godot_bool.True, out var varBytes);
using (varBytes)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes);
}
/// <summary>
- /// Converts a <c>Variant</c> <paramref name="var"/> to a formatted string that
+ /// Converts a <see cref="Variant"/> <paramref name="var"/> to a formatted string that
/// can later be parsed using <see cref="StrToVar(string)"/>.
/// </summary>
/// <example>
/// <code>
/// var a = new Godot.Collections.Dictionary { ["a"] = 1, ["b"] = 2 };
/// GD.Print(GD.VarToStr(a));
- /// // Prints
+ /// // Prints:
/// // {
- /// // "a": 1,
- /// // "b": 2
+ /// // "a": 1,
+ /// // "b": 2
/// // }
/// </code>
/// </example>
/// <param name="var">Variant that will be converted to string.</param>
- /// <returns>The <c>Variant</c> encoded as a string.</returns>
+ /// <returns>The <see cref="Variant"/> encoded as a string.</returns>
public static string VarToStr(Variant var)
{
NativeFuncs.godotsharp_var_to_str((godot_variant)var.NativeVar, out godot_string ret);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
index 60ee6eb6f4..b9a5ac82d1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
@@ -5,20 +5,20 @@ using Godot.NativeInterop;
namespace Godot
{
- public partial class Object : IDisposable
+ public partial class GodotObject : IDisposable
{
private bool _disposed = false;
- private static readonly Type CachedType = typeof(Object);
+ private static readonly Type CachedType = typeof(GodotObject);
internal IntPtr NativePtr;
private bool _memoryOwn;
- private WeakReference<Object> _weakReferenceToSelf;
+ private WeakReference<GodotObject> _weakReferenceToSelf;
/// <summary>
- /// Constructs a new <see cref="Object"/>.
+ /// Constructs a new <see cref="GodotObject"/>.
/// </summary>
- public Object() : this(false)
+ public GodotObject() : this(false)
{
unsafe
{
@@ -49,17 +49,17 @@ namespace Godot
_weakReferenceToSelf = DisposablesTracker.RegisterGodotObject(this);
}
- internal Object(bool memoryOwn)
+ internal GodotObject(bool memoryOwn)
{
_memoryOwn = memoryOwn;
}
/// <summary>
- /// The pointer to the native instance of this <see cref="Object"/>.
+ /// The pointer to the native instance of this <see cref="GodotObject"/>.
/// </summary>
public IntPtr NativeInstance => NativePtr;
- internal static IntPtr GetPtr(Object instance)
+ internal static IntPtr GetPtr(GodotObject instance)
{
if (instance == null)
return IntPtr.Zero;
@@ -75,13 +75,13 @@ namespace Godot
return instance.NativePtr;
}
- ~Object()
+ ~GodotObject()
{
Dispose(false);
}
/// <summary>
- /// Disposes of this <see cref="Object"/>.
+ /// Disposes of this <see cref="GodotObject"/>.
/// </summary>
public void Dispose()
{
@@ -90,7 +90,7 @@ namespace Godot
}
/// <summary>
- /// Disposes implementation of this <see cref="Object"/>.
+ /// Disposes implementation of this <see cref="GodotObject"/>.
/// </summary>
protected virtual void Dispose(bool disposing)
{
@@ -129,7 +129,7 @@ namespace Godot
}
/// <summary>
- /// Converts this <see cref="Object"/> to a string.
+ /// Converts this <see cref="GodotObject"/> to a string.
/// </summary>
/// <returns>A string representation of this object.</returns>
public override string ToString()
@@ -166,7 +166,7 @@ namespace Godot
/// A <see cref="SignalAwaiter"/> that completes when
/// <paramref name="source"/> emits the <paramref name="signal"/>.
/// </returns>
- public SignalAwaiter ToSignal(Object source, StringName signal)
+ public SignalAwaiter ToSignal(GodotObject source, StringName signal)
{
return new SignalAwaiter(source, signal, this);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.exceptions.cs
index 0fcc4ee01b..a7640043ce 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.exceptions.cs
@@ -5,7 +5,7 @@ using System.Text;
namespace Godot
{
- public partial class Object
+ public partial class GodotObject
{
public class NativeMemberNotFoundException : Exception
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
index 1b599beab5..79030c79cc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
@@ -1,17 +1,44 @@
+using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.Threading;
+using System.Threading.Tasks;
namespace Godot
{
- public class GodotSynchronizationContext : SynchronizationContext
+ public sealed class GodotSynchronizationContext : SynchronizationContext, IDisposable
{
- private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> _queue =
- new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
+ private readonly BlockingCollection<(SendOrPostCallback Callback, object State)> _queue = new();
+
+ public override void Send(SendOrPostCallback d, object state)
+ {
+ // Shortcut if we're already on this context
+ // Also necessary to avoid a deadlock, since Send is blocking
+ if (Current == this)
+ {
+ d(state);
+ return;
+ }
+
+ var source = new TaskCompletionSource();
+
+ _queue.Add((st =>
+ {
+ try
+ {
+ d(st);
+ }
+ finally
+ {
+ source.SetResult();
+ }
+ }, state));
+
+ source.Task.Wait();
+ }
public override void Post(SendOrPostCallback d, object state)
{
- _queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
+ _queue.Add((d, state));
}
/// <summary>
@@ -21,8 +48,13 @@ namespace Godot
{
while (_queue.TryTake(out var workItem))
{
- workItem.Key(workItem.Value);
+ workItem.Callback(workItem.State);
}
}
+
+ public void Dispose()
+ {
+ _queue.Dispose();
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
index 408bed71b2..f6c36455b2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
@@ -10,7 +10,7 @@ namespace Godot
/// GodotTaskScheduler contains a linked list of tasks to perform as a queue. Methods
/// within the class are used to control the queue and perform the contained tasks.
/// </summary>
- public class GodotTaskScheduler : TaskScheduler
+ public sealed class GodotTaskScheduler : TaskScheduler, IDisposable
{
/// <summary>
/// The current synchronization context.
@@ -108,5 +108,10 @@ namespace Godot
}
}
}
+
+ public void Dispose()
+ {
+ Context.Dispose();
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index f2667c6807..ca0032df73 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.CompilerServices;
namespace Godot
{
@@ -35,15 +36,18 @@ namespace Godot
public const real_t NaN = real_t.NaN;
// 0.0174532924f and 0.0174532925199433
- private const real_t _degToRadConst = (real_t)0.0174532925199432957692369077M;
+ private const float _degToRadConstF = (float)0.0174532925199432957692369077M;
+ private const double _degToRadConstD = (double)0.0174532925199432957692369077M;
// 57.29578f and 57.2957795130823
- private const real_t _radToDegConst = (real_t)57.295779513082320876798154814M;
+ private const float _radToDegConstF = (float)57.295779513082320876798154814M;
+ private const double _radToDegConstD = (double)57.295779513082320876798154814M;
/// <summary>
/// Returns the absolute value of <paramref name="s"/> (i.e. positive value).
/// </summary>
/// <param name="s">The input number.</param>
/// <returns>The absolute value of <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Abs(int s)
{
return Math.Abs(s);
@@ -54,7 +58,19 @@ namespace Godot
/// </summary>
/// <param name="s">The input number.</param>
/// <returns>The absolute value of <paramref name="s"/>.</returns>
- public static real_t Abs(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Abs(float s)
+ {
+ return Math.Abs(s);
+ }
+
+ /// <summary>
+ /// Returns the absolute value of <paramref name="s"/> (i.e. positive value).
+ /// </summary>
+ /// <param name="s">The input number.</param>
+ /// <returns>The absolute value of <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Abs(double s)
{
return Math.Abs(s);
}
@@ -67,9 +83,38 @@ namespace Godot
/// <returns>
/// An angle that would result in the given cosine value. On the range <c>0</c> to <c>Tau/2</c>.
/// </returns>
- public static real_t Acos(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Acos(float s)
{
- return (real_t)Math.Acos(s);
+ return MathF.Acos(s);
+ }
+
+ /// <summary>
+ /// Returns the arc cosine of <paramref name="s"/> in radians.
+ /// Use to get the angle of cosine <paramref name="s"/>.
+ /// </summary>
+ /// <param name="s">The input cosine value. Must be on the range of -1.0 to 1.0.</param>
+ /// <returns>
+ /// An angle that would result in the given cosine value. On the range <c>0</c> to <c>Tau/2</c>.
+ /// </returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Acos(double s)
+ {
+ return Math.Acos(s);
+ }
+
+ /// <summary>
+ /// Returns the arc sine of <paramref name="s"/> in radians.
+ /// Use to get the angle of sine <paramref name="s"/>.
+ /// </summary>
+ /// <param name="s">The input sine value. Must be on the range of -1.0 to 1.0.</param>
+ /// <returns>
+ /// An angle that would result in the given sine value. On the range <c>-Tau/4</c> to <c>Tau/4</c>.
+ /// </returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Asin(float s)
+ {
+ return MathF.Asin(s);
}
/// <summary>
@@ -80,9 +125,27 @@ namespace Godot
/// <returns>
/// An angle that would result in the given sine value. On the range <c>-Tau/4</c> to <c>Tau/4</c>.
/// </returns>
- public static real_t Asin(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Asin(double s)
+ {
+ return Math.Asin(s);
+ }
+
+ /// <summary>
+ /// Returns the arc tangent of <paramref name="s"/> in radians.
+ /// Use to get the angle of tangent <paramref name="s"/>.
+ ///
+ /// The method cannot know in which quadrant the angle should fall.
+ /// See <see cref="Atan2(float, float)"/> if you have both <c>y</c> and <c>x</c>.
+ /// </summary>
+ /// <param name="s">The input tangent value.</param>
+ /// <returns>
+ /// An angle that would result in the given tangent value. On the range <c>-Tau/4</c> to <c>Tau/4</c>.
+ /// </returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Atan(float s)
{
- return (real_t)Math.Asin(s);
+ return MathF.Atan(s);
}
/// <summary>
@@ -90,15 +153,16 @@ namespace Godot
/// Use to get the angle of tangent <paramref name="s"/>.
///
/// The method cannot know in which quadrant the angle should fall.
- /// See <see cref="Atan2(real_t, real_t)"/> if you have both <c>y</c> and <c>x</c>.
+ /// See <see cref="Atan2(double, double)"/> if you have both <c>y</c> and <c>x</c>.
/// </summary>
/// <param name="s">The input tangent value.</param>
/// <returns>
/// An angle that would result in the given tangent value. On the range <c>-Tau/4</c> to <c>Tau/4</c>.
/// </returns>
- public static real_t Atan(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Atan(double s)
{
- return (real_t)Math.Atan(s);
+ return Math.Atan(s);
}
/// <summary>
@@ -113,9 +177,39 @@ namespace Godot
/// <returns>
/// An angle that would result in the given tangent value. On the range <c>-Tau/2</c> to <c>Tau/2</c>.
/// </returns>
- public static real_t Atan2(real_t y, real_t x)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Atan2(float y, float x)
{
- return (real_t)Math.Atan2(y, x);
+ return MathF.Atan2(y, x);
+ }
+
+ /// <summary>
+ /// Returns the arc tangent of <paramref name="y"/> and <paramref name="x"/> in radians.
+ /// Use to get the angle of the tangent of <c>y/x</c>. To compute the value, the method takes into
+ /// account the sign of both arguments in order to determine the quadrant.
+ ///
+ /// Important note: The Y coordinate comes first, by convention.
+ /// </summary>
+ /// <param name="y">The Y coordinate of the point to find the angle to.</param>
+ /// <param name="x">The X coordinate of the point to find the angle to.</param>
+ /// <returns>
+ /// An angle that would result in the given tangent value. On the range <c>-Tau/2</c> to <c>Tau/2</c>.
+ /// </returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Atan2(double y, double x)
+ {
+ return Math.Atan2(y, x);
+ }
+
+ /// <summary>
+ /// Rounds <paramref name="s"/> upward (towards positive infinity).
+ /// </summary>
+ /// <param name="s">The number to ceil.</param>
+ /// <returns>The smallest whole number that is not less than <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Ceil(float s)
+ {
+ return MathF.Ceiling(s);
}
/// <summary>
@@ -123,9 +217,10 @@ namespace Godot
/// </summary>
/// <param name="s">The number to ceil.</param>
/// <returns>The smallest whole number that is not less than <paramref name="s"/>.</returns>
- public static real_t Ceil(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Ceil(double s)
{
- return (real_t)Math.Ceiling(s);
+ return Math.Ceiling(s);
}
/// <summary>
@@ -136,9 +231,10 @@ namespace Godot
/// <param name="min">The minimum allowed value.</param>
/// <param name="max">The maximum allowed value.</param>
/// <returns>The clamped value.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Clamp(int value, int min, int max)
{
- return value < min ? min : value > max ? max : value;
+ return Math.Clamp(value, min, max);
}
/// <summary>
@@ -149,9 +245,24 @@ namespace Godot
/// <param name="min">The minimum allowed value.</param>
/// <param name="max">The maximum allowed value.</param>
/// <returns>The clamped value.</returns>
- public static real_t Clamp(real_t value, real_t min, real_t max)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Clamp(float value, float min, float max)
{
- return value < min ? min : value > max ? max : value;
+ return Math.Clamp(value, min, max);
+ }
+
+ /// <summary>
+ /// Clamps a <paramref name="value"/> so that it is not less than <paramref name="min"/>
+ /// and not more than <paramref name="max"/>.
+ /// </summary>
+ /// <param name="value">The value to clamp.</param>
+ /// <param name="min">The minimum allowed value.</param>
+ /// <param name="max">The maximum allowed value.</param>
+ /// <returns>The clamped value.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Clamp(double value, double min, double max)
+ {
+ return Math.Clamp(value, min, max);
}
/// <summary>
@@ -159,9 +270,21 @@ namespace Godot
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The cosine of that angle.</returns>
- public static real_t Cos(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Cos(float s)
{
- return (real_t)Math.Cos(s);
+ return MathF.Cos(s);
+ }
+
+ /// <summary>
+ /// Returns the cosine of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The cosine of that angle.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Cos(double s)
+ {
+ return Math.Cos(s);
}
/// <summary>
@@ -169,9 +292,21 @@ namespace Godot
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The hyperbolic cosine of that angle.</returns>
- public static real_t Cosh(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Cosh(float s)
{
- return (real_t)Math.Cosh(s);
+ return MathF.Cosh(s);
+ }
+
+ /// <summary>
+ /// Returns the hyperbolic cosine of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The hyperbolic cosine of that angle.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Cosh(double s)
+ {
+ return Math.Cosh(s);
}
/// <summary>
@@ -184,7 +319,7 @@ namespace Godot
/// <param name="post">The value which after "to" value for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting value of the interpolation.</returns>
- public static real_t CubicInterpolate(real_t from, real_t to, real_t pre, real_t post, real_t weight)
+ public static float CubicInterpolate(float from, float to, float pre, float post, float weight)
{
return 0.5f *
((from * 2.0f) +
@@ -194,9 +329,28 @@ namespace Godot
}
/// <summary>
+ /// Cubic interpolates between two values by the factor defined in <paramref name="weight"/>
+ /// with pre and post values.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="pre">The value which before "from" value for interpolation.</param>
+ /// <param name="post">The value which after "to" value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static double CubicInterpolate(double from, double to, double pre, double post, double weight)
+ {
+ return 0.5 *
+ ((from * 2.0) +
+ (-pre + to) * weight +
+ (2.0 * pre - 5.0 * from + 4.0 * to - post) * (weight * weight) +
+ (-pre + 3.0 * from - 3.0 * to + post) * (weight * weight * weight));
+ }
+
+ /// <summary>
/// Cubic interpolates between two rotation values with shortest path
/// by the factor defined in <paramref name="weight"/> with pre and post values.
- /// See also <see cref="LerpAngle"/>.
+ /// See also <see cref="LerpAngle(float, float, float)"/>.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
/// <param name="to">The destination value for interpolation.</param>
@@ -204,18 +358,45 @@ namespace Godot
/// <param name="post">The value which after "to" value for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting value of the interpolation.</returns>
- public static real_t CubicInterpolateAngle(real_t from, real_t to, real_t pre, real_t post, real_t weight)
+ public static float CubicInterpolateAngle(float from, float to, float pre, float post, float weight)
{
- real_t fromRot = from % Mathf.Tau;
+ float fromRot = from % MathF.Tau;
- real_t preDiff = (pre - fromRot) % Mathf.Tau;
- real_t preRot = fromRot + (2.0f * preDiff) % Mathf.Tau - preDiff;
+ float preDiff = (pre - fromRot) % MathF.Tau;
+ float preRot = fromRot + (2.0f * preDiff) % MathF.Tau - preDiff;
- real_t toDiff = (to - fromRot) % Mathf.Tau;
- real_t toRot = fromRot + (2.0f * toDiff) % Mathf.Tau - toDiff;
+ float toDiff = (to - fromRot) % MathF.Tau;
+ float toRot = fromRot + (2.0f * toDiff) % MathF.Tau - toDiff;
- real_t postDiff = (post - toRot) % Mathf.Tau;
- real_t postRot = toRot + (2.0f * postDiff) % Mathf.Tau - postDiff;
+ float postDiff = (post - toRot) % MathF.Tau;
+ float postRot = toRot + (2.0f * postDiff) % MathF.Tau - postDiff;
+
+ return CubicInterpolate(fromRot, toRot, preRot, postRot, weight);
+ }
+
+ /// <summary>
+ /// Cubic interpolates between two rotation values with shortest path
+ /// by the factor defined in <paramref name="weight"/> with pre and post values.
+ /// See also <see cref="LerpAngle(double, double, double)"/>.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="pre">The value which before "from" value for interpolation.</param>
+ /// <param name="post">The value which after "to" value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static double CubicInterpolateAngle(double from, double to, double pre, double post, double weight)
+ {
+ double fromRot = from % Math.Tau;
+
+ double preDiff = (pre - fromRot) % Math.Tau;
+ double preRot = fromRot + (2.0 * preDiff) % Math.Tau - preDiff;
+
+ double toDiff = (to - fromRot) % Math.Tau;
+ double toRot = fromRot + (2.0 * toDiff) % Math.Tau - toDiff;
+
+ double postDiff = (post - toRot) % Math.Tau;
+ double postRot = toRot + (2.0 * postDiff) % Math.Tau - postDiff;
return CubicInterpolate(fromRot, toRot, preRot, postRot, weight);
}
@@ -223,7 +404,8 @@ namespace Godot
/// <summary>
/// Cubic interpolates between two values by the factor defined in <paramref name="weight"/>
/// with pre and post values.
- /// It can perform smoother interpolation than <see cref="CubicInterpolate"/>
+ /// It can perform smoother interpolation than
+ /// <see cref="CubicInterpolate(float, float, float, float, float)"/>
/// by the time values.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
@@ -235,23 +417,52 @@ namespace Godot
/// <param name="preT"></param>
/// <param name="postT"></param>
/// <returns>The resulting value of the interpolation.</returns>
- public static real_t CubicInterpolateInTime(real_t from, real_t to, real_t pre, real_t post, real_t weight, real_t toT, real_t preT, real_t postT)
+ public static float CubicInterpolateInTime(float from, float to, float pre, float post, float weight, float toT, float preT, float postT)
{
/* Barry-Goldman method */
- real_t t = Lerp(0.0f, toT, weight);
- real_t a1 = Lerp(pre, from, preT == 0 ? 0.0f : (t - preT) / -preT);
- real_t a2 = Lerp(from, to, toT == 0 ? 0.5f : t / toT);
- real_t a3 = Lerp(to, post, postT - toT == 0 ? 1.0f : (t - toT) / (postT - toT));
- real_t b1 = Lerp(a1, a2, toT - preT == 0 ? 0.0f : (t - preT) / (toT - preT));
- real_t b2 = Lerp(a2, a3, postT == 0 ? 1.0f : t / postT);
+ float t = Lerp(0.0f, toT, weight);
+ float a1 = Lerp(pre, from, preT == 0 ? 0.0f : (t - preT) / -preT);
+ float a2 = Lerp(from, to, toT == 0 ? 0.5f : t / toT);
+ float a3 = Lerp(to, post, postT - toT == 0 ? 1.0f : (t - toT) / (postT - toT));
+ float b1 = Lerp(a1, a2, toT - preT == 0 ? 0.0f : (t - preT) / (toT - preT));
+ float b2 = Lerp(a2, a3, postT == 0 ? 1.0f : t / postT);
return Lerp(b1, b2, toT == 0 ? 0.5f : t / toT);
}
/// <summary>
+ /// Cubic interpolates between two values by the factor defined in <paramref name="weight"/>
+ /// with pre and post values.
+ /// It can perform smoother interpolation than
+ /// <see cref="CubicInterpolate(double, double, double, double, double)"/>
+ /// by the time values.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="pre">The value which before "from" value for interpolation.</param>
+ /// <param name="post">The value which after "to" value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="toT"></param>
+ /// <param name="preT"></param>
+ /// <param name="postT"></param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static double CubicInterpolateInTime(double from, double to, double pre, double post, double weight, double toT, double preT, double postT)
+ {
+ /* Barry-Goldman method */
+ double t = Lerp(0.0, toT, weight);
+ double a1 = Lerp(pre, from, preT == 0 ? 0.0 : (t - preT) / -preT);
+ double a2 = Lerp(from, to, toT == 0 ? 0.5 : t / toT);
+ double a3 = Lerp(to, post, postT - toT == 0 ? 1.0 : (t - toT) / (postT - toT));
+ double b1 = Lerp(a1, a2, toT - preT == 0 ? 0.0 : (t - preT) / (toT - preT));
+ double b2 = Lerp(a2, a3, postT == 0 ? 1.0 : t / postT);
+ return Lerp(b1, b2, toT == 0 ? 0.5 : t / toT);
+ }
+
+ /// <summary>
/// Cubic interpolates between two rotation values with shortest path
/// by the factor defined in <paramref name="weight"/> with pre and post values.
- /// See also <see cref="LerpAngle"/>.
- /// It can perform smoother interpolation than <see cref="CubicInterpolateAngle"/>
+ /// See also <see cref="LerpAngle(float, float, float)"/>.
+ /// It can perform smoother interpolation than
+ /// <see cref="CubicInterpolateAngle(float, float, float, float, float)"/>
/// by the time values.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
@@ -263,26 +474,58 @@ namespace Godot
/// <param name="preT"></param>
/// <param name="postT"></param>
/// <returns>The resulting value of the interpolation.</returns>
- public static real_t CubicInterpolateAngleInTime(real_t from, real_t to, real_t pre, real_t post, real_t weight,
- real_t toT, real_t preT, real_t postT)
+ public static float CubicInterpolateAngleInTime(float from, float to, float pre, float post, float weight, float toT, float preT, float postT)
{
- real_t fromRot = from % Mathf.Tau;
+ float fromRot = from % MathF.Tau;
- real_t preDiff = (pre - fromRot) % Mathf.Tau;
- real_t preRot = fromRot + (2.0f * preDiff) % Mathf.Tau - preDiff;
+ float preDiff = (pre - fromRot) % MathF.Tau;
+ float preRot = fromRot + (2.0f * preDiff) % MathF.Tau - preDiff;
- real_t toDiff = (to - fromRot) % Mathf.Tau;
- real_t toRot = fromRot + (2.0f * toDiff) % Mathf.Tau - toDiff;
+ float toDiff = (to - fromRot) % MathF.Tau;
+ float toRot = fromRot + (2.0f * toDiff) % MathF.Tau - toDiff;
- real_t postDiff = (post - toRot) % Mathf.Tau;
- real_t postRot = toRot + (2.0f * postDiff) % Mathf.Tau - postDiff;
+ float postDiff = (post - toRot) % MathF.Tau;
+ float postRot = toRot + (2.0f * postDiff) % MathF.Tau - postDiff;
+
+ return CubicInterpolateInTime(fromRot, toRot, preRot, postRot, weight, toT, preT, postT);
+ }
+
+ /// <summary>
+ /// Cubic interpolates between two rotation values with shortest path
+ /// by the factor defined in <paramref name="weight"/> with pre and post values.
+ /// See also <see cref="LerpAngle(double, double, double)"/>.
+ /// It can perform smoother interpolation than
+ /// <see cref="CubicInterpolateAngle(double, double, double, double, double)"/>
+ /// by the time values.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="pre">The value which before "from" value for interpolation.</param>
+ /// <param name="post">The value which after "to" value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="toT"></param>
+ /// <param name="preT"></param>
+ /// <param name="postT"></param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static double CubicInterpolateAngleInTime(double from, double to, double pre, double post, double weight, double toT, double preT, double postT)
+ {
+ double fromRot = from % Math.Tau;
+
+ double preDiff = (pre - fromRot) % Math.Tau;
+ double preRot = fromRot + (2.0 * preDiff) % Math.Tau - preDiff;
+
+ double toDiff = (to - fromRot) % Math.Tau;
+ double toRot = fromRot + (2.0 * toDiff) % Math.Tau - toDiff;
+
+ double postDiff = (post - toRot) % Math.Tau;
+ double postRot = toRot + (2.0 * postDiff) % Math.Tau - postDiff;
return CubicInterpolateInTime(fromRot, toRot, preRot, postRot, weight, toT, preT, postT);
}
/// <summary>
/// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by
- /// the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
+ /// the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
/// </summary>
/// <param name="start">The start value for the interpolation.</param>
/// <param name="control1">Control point that defines the bezier curve.</param>
@@ -290,16 +533,112 @@ namespace Godot
/// <param name="end">The destination value for the interpolation.</param>
/// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting value of the interpolation.</returns>
- public static real_t BezierInterpolate(real_t start, real_t control1, real_t control2, real_t end, real_t t)
+ public static float BezierInterpolate(float start, float control1, float control2, float end, float t)
{
// Formula from Wikipedia article on Bezier curves
- real_t omt = 1 - t;
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- real_t t3 = t2 * t;
+ float omt = 1.0f - t;
+ float omt2 = omt * omt;
+ float omt3 = omt2 * omt;
+ float t2 = t * t;
+ float t3 = t2 * t;
- return start * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3;
+ return start * omt3 + control1 * omt2 * t * 3.0f + control2 * omt * t2 * 3.0f + end * t3;
+ }
+
+ /// <summary>
+ /// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by
+ /// the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
+ /// </summary>
+ /// <param name="start">The start value for the interpolation.</param>
+ /// <param name="control1">Control point that defines the bezier curve.</param>
+ /// <param name="control2">Control point that defines the bezier curve.</param>
+ /// <param name="end">The destination value for the interpolation.</param>
+ /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static double BezierInterpolate(double start, double control1, double control2, double end, double t)
+ {
+ // Formula from Wikipedia article on Bezier curves
+ double omt = 1.0 - t;
+ double omt2 = omt * omt;
+ double omt3 = omt2 * omt;
+ double t2 = t * t;
+ double t3 = t2 * t;
+
+ return start * omt3 + control1 * omt2 * t * 3.0 + control2 * omt * t2 * 3.0 + end * t3;
+ }
+
+ /// <summary>
+ /// Returns the derivative at the given <paramref name="t"/> on a one dimensional Bezier curve defined by
+ /// the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
+ /// </summary>
+ /// <param name="start">The start value for the interpolation.</param>
+ /// <param name="control1">Control point that defines the bezier curve.</param>
+ /// <param name="control2">Control point that defines the bezier curve.</param>
+ /// <param name="end">The destination value for the interpolation.</param>
+ /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static float BezierDerivative(float start, float control1, float control2, float end, float t)
+ {
+ // Formula from Wikipedia article on Bezier curves
+ float omt = 1.0f - t;
+ float omt2 = omt * omt;
+ float t2 = t * t;
+
+ float d = (control1 - start) * 3.0f * omt2 + (control2 - control1) * 6.0f * omt * t + (end - control2) * 3.0f * t2;
+ return d;
+ }
+
+ /// <summary>
+ /// Returns the derivative at the given <paramref name="t"/> on a one dimensional Bezier curve defined by
+ /// the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
+ /// </summary>
+ /// <param name="start">The start value for the interpolation.</param>
+ /// <param name="control1">Control point that defines the bezier curve.</param>
+ /// <param name="control2">Control point that defines the bezier curve.</param>
+ /// <param name="end">The destination value for the interpolation.</param>
+ /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static double BezierDerivative(double start, double control1, double control2, double end, double t)
+ {
+ // Formula from Wikipedia article on Bezier curves
+ double omt = 1.0 - t;
+ double omt2 = omt * omt;
+ double t2 = t * t;
+
+ double d = (control1 - start) * 3.0 * omt2 + (control2 - control1) * 6.0 * omt * t + (end - control2) * 3.0 * t2;
+ return d;
+ }
+
+ /// <summary>
+ /// Converts from decibels to linear energy (audio).
+ /// </summary>
+ /// <seealso cref="LinearToDb(float)"/>
+ /// <param name="db">Decibels to convert.</param>
+ /// <returns>Audio volume as linear energy.</returns>
+ public static float DbToLinear(float db)
+ {
+ return MathF.Exp(db * 0.11512925464970228420089957273422f);
+ }
+
+ /// <summary>
+ /// Converts from decibels to linear energy (audio).
+ /// </summary>
+ /// <seealso cref="LinearToDb(double)"/>
+ /// <param name="db">Decibels to convert.</param>
+ /// <returns>Audio volume as linear energy.</returns>
+ public static double DbToLinear(double db)
+ {
+ return Math.Exp(db * 0.11512925464970228420089957273422);
+ }
+
+ /// <summary>
+ /// Converts an angle expressed in degrees to radians.
+ /// </summary>
+ /// <param name="deg">An angle expressed in degrees.</param>
+ /// <returns>The same angle expressed in radians.</returns>
+ public static float DegToRad(float deg)
+ {
+ return deg * _degToRadConstF;
}
/// <summary>
@@ -307,9 +646,9 @@ namespace Godot
/// </summary>
/// <param name="deg">An angle expressed in degrees.</param>
/// <returns>The same angle expressed in radians.</returns>
- public static real_t DegToRad(real_t deg)
+ public static double DegToRad(double deg)
{
- return deg * _degToRadConst;
+ return deg * _degToRadConstD;
}
/// <summary>
@@ -322,38 +661,82 @@ namespace Godot
/// <c>0</c> is constant, <c>1</c> is linear, <c>0</c> to <c>1</c> is ease-in, <c>1</c> or more is ease-out.
/// </param>
/// <returns>The eased value.</returns>
- public static real_t Ease(real_t s, real_t curve)
+ public static float Ease(float s, float curve)
{
- if (s < 0f)
+ if (s < 0.0f)
{
- s = 0f;
+ s = 0.0f;
}
else if (s > 1.0f)
{
s = 1.0f;
}
- if (curve > 0f)
+ if (curve > 0.0f)
{
if (curve < 1.0f)
{
- return 1.0f - Pow(1.0f - s, 1.0f / curve);
+ return 1.0f - MathF.Pow(1.0f - s, 1.0f / curve);
}
- return Pow(s, curve);
+ return MathF.Pow(s, curve);
}
- if (curve < 0f)
+ if (curve < 0.0f)
{
if (s < 0.5f)
{
- return Pow(s * 2.0f, -curve) * 0.5f;
+ return MathF.Pow(s * 2.0f, -curve) * 0.5f;
}
- return ((1.0f - Pow(1.0f - ((s - 0.5f) * 2.0f), -curve)) * 0.5f) + 0.5f;
+ return ((1.0f - MathF.Pow(1.0f - ((s - 0.5f) * 2.0f), -curve)) * 0.5f) + 0.5f;
}
- return 0f;
+ return 0.0f;
+ }
+
+ /// <summary>
+ /// Easing function, based on exponent. The <paramref name="curve"/> values are:
+ /// <c>0</c> is constant, <c>1</c> is linear, <c>0</c> to <c>1</c> is ease-in, <c>1</c> or more is ease-out.
+ /// Negative values are in-out/out-in.
+ /// </summary>
+ /// <param name="s">The value to ease.</param>
+ /// <param name="curve">
+ /// <c>0</c> is constant, <c>1</c> is linear, <c>0</c> to <c>1</c> is ease-in, <c>1</c> or more is ease-out.
+ /// </param>
+ /// <returns>The eased value.</returns>
+ public static double Ease(double s, double curve)
+ {
+ if (s < 0.0)
+ {
+ s = 0.0;
+ }
+ else if (s > 1.0)
+ {
+ s = 1.0;
+ }
+
+ if (curve > 0)
+ {
+ if (curve < 1.0)
+ {
+ return 1.0 - Math.Pow(1.0 - s, 1.0 / curve);
+ }
+
+ return Math.Pow(s, curve);
+ }
+
+ if (curve < 0.0)
+ {
+ if (s < 0.5)
+ {
+ return Math.Pow(s * 2.0, -curve) * 0.5;
+ }
+
+ return ((1.0 - Math.Pow(1.0 - ((s - 0.5) * 2.0), -curve)) * 0.5) + 0.5;
+ }
+
+ return 0.0;
}
/// <summary>
@@ -362,9 +745,33 @@ namespace Godot
/// </summary>
/// <param name="s">The exponent to raise <c>e</c> to.</param>
/// <returns><c>e</c> raised to the power of <paramref name="s"/>.</returns>
- public static real_t Exp(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Exp(float s)
{
- return (real_t)Math.Exp(s);
+ return MathF.Exp(s);
+ }
+
+ /// <summary>
+ /// The natural exponential function. It raises the mathematical
+ /// constant <c>e</c> to the power of <paramref name="s"/> and returns it.
+ /// </summary>
+ /// <param name="s">The exponent to raise <c>e</c> to.</param>
+ /// <returns><c>e</c> raised to the power of <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Exp(double s)
+ {
+ return Math.Exp(s);
+ }
+
+ /// <summary>
+ /// Rounds <paramref name="s"/> downward (towards negative infinity).
+ /// </summary>
+ /// <param name="s">The number to floor.</param>
+ /// <returns>The largest whole number that is not more than <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Floor(float s)
+ {
+ return MathF.Floor(s);
}
/// <summary>
@@ -372,14 +779,32 @@ namespace Godot
/// </summary>
/// <param name="s">The number to floor.</param>
/// <returns>The largest whole number that is not more than <paramref name="s"/>.</returns>
- public static real_t Floor(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Floor(double s)
+ {
+ return Math.Floor(s);
+ }
+
+ /// <summary>
+ /// Returns a normalized value considering the given range.
+ /// This is the opposite of <see cref="Lerp(float, float, float)"/>.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="weight">The interpolated value.</param>
+ /// <returns>
+ /// The resulting value of the inverse interpolation.
+ /// The returned value will be between 0.0 and 1.0 if <paramref name="weight"/> is
+ /// between <paramref name="from"/> and <paramref name="to"/> (inclusive).
+ /// </returns>
+ public static float InverseLerp(float from, float to, float weight)
{
- return (real_t)Math.Floor(s);
+ return (weight - from) / (to - from);
}
/// <summary>
/// Returns a normalized value considering the given range.
- /// This is the opposite of <see cref="Lerp(real_t, real_t, real_t)"/>.
+ /// This is the opposite of <see cref="Lerp(double, double, double)"/>.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
/// <param name="to">The destination value for interpolation.</param>
@@ -389,7 +814,7 @@ namespace Godot
/// The returned value will be between 0.0 and 1.0 if <paramref name="weight"/> is
/// between <paramref name="from"/> and <paramref name="to"/> (inclusive).
/// </returns>
- public static real_t InverseLerp(real_t from, real_t to, real_t weight)
+ public static double InverseLerp(double from, double to, double weight)
{
return (weight - from) / (to - from);
}
@@ -402,7 +827,31 @@ namespace Godot
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>A <see langword="bool"/> for whether or not the two values are approximately equal.</returns>
- public static bool IsEqualApprox(real_t a, real_t b)
+ public static bool IsEqualApprox(float a, float b)
+ {
+ // Check for exact equality first, required to handle "infinity" values.
+ if (a == b)
+ {
+ return true;
+ }
+ // Then check for approximate equality.
+ float tolerance = _epsilonF * Math.Abs(a);
+ if (tolerance < _epsilonF)
+ {
+ tolerance = _epsilonF;
+ }
+ return Math.Abs(a - b) < tolerance;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately equal
+ /// to each other.
+ /// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>.
+ /// </summary>
+ /// <param name="a">One of the values.</param>
+ /// <param name="b">The other value.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the two values are approximately equal.</returns>
+ public static bool IsEqualApprox(double a, double b)
{
// Check for exact equality first, required to handle "infinity" values.
if (a == b)
@@ -410,12 +859,47 @@ namespace Godot
return true;
}
// Then check for approximate equality.
- real_t tolerance = Epsilon * Abs(a);
- if (tolerance < Epsilon)
+ double tolerance = _epsilonD * Math.Abs(a);
+ if (tolerance < _epsilonD)
{
- tolerance = Epsilon;
+ tolerance = _epsilonD;
}
- return Abs(a - b) < tolerance;
+ return Math.Abs(a - b) < tolerance;
+ }
+
+ /// <summary>
+ /// Returns whether <paramref name="s"/> is a finite value, i.e. it is not
+ /// <see cref="NaN"/>, positive infinite, or negative infinity.
+ /// </summary>
+ /// <param name="s">The value to check.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the value is a finite value.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsFinite(float s)
+ {
+ return float.IsFinite(s);
+ }
+
+ /// <summary>
+ /// Returns whether <paramref name="s"/> is a finite value, i.e. it is not
+ /// <see cref="NaN"/>, positive infinite, or negative infinity.
+ /// </summary>
+ /// <param name="s">The value to check.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the value is a finite value.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsFinite(double s)
+ {
+ return double.IsFinite(s);
+ }
+
+ /// <summary>
+ /// Returns whether <paramref name="s"/> is an infinity value (either positive infinity or negative infinity).
+ /// </summary>
+ /// <param name="s">The value to check.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the value is an infinity value.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsInf(float s)
+ {
+ return float.IsInfinity(s);
}
/// <summary>
@@ -423,9 +907,21 @@ namespace Godot
/// </summary>
/// <param name="s">The value to check.</param>
/// <returns>A <see langword="bool"/> for whether or not the value is an infinity value.</returns>
- public static bool IsInf(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsInf(double s)
+ {
+ return double.IsInfinity(s);
+ }
+
+ /// <summary>
+ /// Returns whether <paramref name="s"/> is a <c>NaN</c> ("Not a Number" or invalid) value.
+ /// </summary>
+ /// <param name="s">The value to check.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the value is a <c>NaN</c> value.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsNaN(float s)
{
- return real_t.IsInfinity(s);
+ return float.IsNaN(s);
}
/// <summary>
@@ -433,64 +929,166 @@ namespace Godot
/// </summary>
/// <param name="s">The value to check.</param>
/// <returns>A <see langword="bool"/> for whether or not the value is a <c>NaN</c> value.</returns>
- public static bool IsNaN(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsNaN(double s)
{
- return real_t.IsNaN(s);
+ return double.IsNaN(s);
}
/// <summary>
- /// Returns <see langword="true"/> if <paramref name="s"/> is approximately zero.
+ /// Returns <see langword="true"/> if <paramref name="s"/> is zero or almost zero.
/// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>.
///
- /// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with one value as zero.
+ /// This method is faster than using <see cref="IsEqualApprox(float, float)"/> with
+ /// one value as zero.
/// </summary>
/// <param name="s">The value to check.</param>
/// <returns>A <see langword="bool"/> for whether or not the value is nearly zero.</returns>
- public static bool IsZeroApprox(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsZeroApprox(float s)
{
- return Abs(s) < Epsilon;
+ return Math.Abs(s) < _epsilonF;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if <paramref name="s"/> is zero or almost zero.
+ /// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>.
+ ///
+ /// This method is faster than using <see cref="IsEqualApprox(double, double)"/> with
+ /// one value as zero.
+ /// </summary>
+ /// <param name="s">The value to check.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the value is nearly zero.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsZeroApprox(double s)
+ {
+ return Math.Abs(s) < _epsilonD;
}
/// <summary>
/// Linearly interpolates between two values by a normalized value.
- /// This is the opposite <see cref="InverseLerp(real_t, real_t, real_t)"/>.
+ /// This is the opposite <see cref="InverseLerp(float, float, float)"/>.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
/// <param name="to">The destination value for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting value of the interpolation.</returns>
- public static real_t Lerp(real_t from, real_t to, real_t weight)
+ public static float Lerp(float from, float to, float weight)
{
return from + ((to - from) * weight);
}
/// <summary>
+ /// Linearly interpolates between two values by a normalized value.
+ /// This is the opposite <see cref="InverseLerp(double, double, double)"/>.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static double Lerp(double from, double to, double weight)
+ {
+ return from + ((to - from) * weight);
+ }
+
+ /// <summary>
+ /// Linearly interpolates between two angles (in radians) by a normalized value.
+ ///
+ /// Similar to <see cref="Lerp(float, float, float)"/>,
+ /// but interpolates correctly when the angles wrap around <see cref="Tau"/>.
+ /// </summary>
+ /// <param name="from">The start angle for interpolation.</param>
+ /// <param name="to">The destination angle for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting angle of the interpolation.</returns>
+ public static float LerpAngle(float from, float to, float weight)
+ {
+ float difference = (to - from) % MathF.Tau;
+ float distance = ((2 * difference) % MathF.Tau) - difference;
+ return from + (distance * weight);
+ }
+
+ /// <summary>
/// Linearly interpolates between two angles (in radians) by a normalized value.
///
- /// Similar to <see cref="Lerp(real_t, real_t, real_t)"/>,
+ /// Similar to <see cref="Lerp(double, double, double)"/>,
/// but interpolates correctly when the angles wrap around <see cref="Tau"/>.
/// </summary>
/// <param name="from">The start angle for interpolation.</param>
/// <param name="to">The destination angle for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting angle of the interpolation.</returns>
- public static real_t LerpAngle(real_t from, real_t to, real_t weight)
+ public static double LerpAngle(double from, double to, double weight)
{
- real_t difference = (to - from) % Mathf.Tau;
- real_t distance = ((2 * difference) % Mathf.Tau) - difference;
+ double difference = (to - from) % Math.Tau;
+ double distance = ((2 * difference) % Math.Tau) - difference;
return from + (distance * weight);
}
/// <summary>
+ /// Converts from linear energy to decibels (audio).
+ /// This can be used to implement volume sliders that behave as expected (since volume isn't linear).
+ /// </summary>
+ /// <seealso cref="DbToLinear(float)"/>
+ /// <example>
+ /// <code>
+ /// // "slider" refers to a node that inherits Range such as HSlider or VSlider.
+ /// // Its range must be configured to go from 0 to 1.
+ /// // Change the bus name if you'd like to change the volume of a specific bus only.
+ /// AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), GD.LinearToDb(slider.value));
+ /// </code>
+ /// </example>
+ /// <param name="linear">The linear energy to convert.</param>
+ /// <returns>Audio as decibels.</returns>
+ public static float LinearToDb(float linear)
+ {
+ return MathF.Log(linear) * 8.6858896380650365530225783783321f;
+ }
+
+ /// <summary>
+ /// Converts from linear energy to decibels (audio).
+ /// This can be used to implement volume sliders that behave as expected (since volume isn't linear).
+ /// </summary>
+ /// <seealso cref="DbToLinear(double)"/>
+ /// <example>
+ /// <code>
+ /// // "slider" refers to a node that inherits Range such as HSlider or VSlider.
+ /// // Its range must be configured to go from 0 to 1.
+ /// // Change the bus name if you'd like to change the volume of a specific bus only.
+ /// AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), GD.LinearToDb(slider.value));
+ /// </code>
+ /// </example>
+ /// <param name="linear">The linear energy to convert.</param>
+ /// <returns>Audio as decibels.</returns>
+ public static double LinearToDb(double linear)
+ {
+ return Math.Log(linear) * 8.6858896380650365530225783783321;
+ }
+
+ /// <summary>
+ /// Natural logarithm. The amount of time needed to reach a certain level of continuous growth.
+ ///
+ /// Note: This is not the same as the "log" function on most calculators, which uses a base 10 logarithm.
+ /// </summary>
+ /// <param name="s">The input value.</param>
+ /// <returns>The natural log of <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Log(float s)
+ {
+ return MathF.Log(s);
+ }
+
+ /// <summary>
/// Natural logarithm. The amount of time needed to reach a certain level of continuous growth.
///
/// Note: This is not the same as the "log" function on most calculators, which uses a base 10 logarithm.
/// </summary>
/// <param name="s">The input value.</param>
/// <returns>The natural log of <paramref name="s"/>.</returns>
- public static real_t Log(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Log(double s)
{
- return (real_t)Math.Log(s);
+ return Math.Log(s);
}
/// <summary>
@@ -499,9 +1097,10 @@ namespace Godot
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>Whichever of the two values is higher.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Max(int a, int b)
{
- return a > b ? a : b;
+ return Math.Max(a, b);
}
/// <summary>
@@ -510,9 +1109,22 @@ namespace Godot
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>Whichever of the two values is higher.</returns>
- public static real_t Max(real_t a, real_t b)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Max(float a, float b)
{
- return a > b ? a : b;
+ return Math.Max(a, b);
+ }
+
+ /// <summary>
+ /// Returns the maximum of two values.
+ /// </summary>
+ /// <param name="a">One of the values.</param>
+ /// <param name="b">The other value.</param>
+ /// <returns>Whichever of the two values is higher.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Max(double a, double b)
+ {
+ return Math.Max(a, b);
}
/// <summary>
@@ -521,9 +1133,22 @@ namespace Godot
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>Whichever of the two values is lower.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Min(int a, int b)
{
- return a < b ? a : b;
+ return Math.Min(a, b);
+ }
+
+ /// <summary>
+ /// Returns the minimum of two values.
+ /// </summary>
+ /// <param name="a">One of the values.</param>
+ /// <param name="b">The other value.</param>
+ /// <returns>Whichever of the two values is lower.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Min(float a, float b)
+ {
+ return Math.Min(a, b);
}
/// <summary>
@@ -532,9 +1157,10 @@ namespace Godot
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>Whichever of the two values is lower.</returns>
- public static real_t Min(real_t a, real_t b)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Min(double a, double b)
{
- return a < b ? a : b;
+ return Math.Min(a, b);
}
/// <summary>
@@ -546,12 +1172,29 @@ namespace Godot
/// <param name="to">The value to move towards.</param>
/// <param name="delta">The amount to move by.</param>
/// <returns>The value after moving.</returns>
- public static real_t MoveToward(real_t from, real_t to, real_t delta)
+ public static float MoveToward(float from, float to, float delta)
{
- if (Abs(to - from) <= delta)
+ if (Math.Abs(to - from) <= delta)
return to;
- return from + (Sign(to - from) * delta);
+ return from + (Math.Sign(to - from) * delta);
+ }
+
+ /// <summary>
+ /// Moves <paramref name="from"/> toward <paramref name="to"/> by the <paramref name="delta"/> value.
+ ///
+ /// Use a negative <paramref name="delta"/> value to move away.
+ /// </summary>
+ /// <param name="from">The start value.</param>
+ /// <param name="to">The value to move towards.</param>
+ /// <param name="delta">The amount to move by.</param>
+ /// <returns>The value after moving.</returns>
+ public static double MoveToward(double from, double to, double delta)
+ {
+ if (Math.Abs(to - from) <= delta)
+ return to;
+
+ return from + (Math.Sign(to - from) * delta);
}
/// <summary>
@@ -593,9 +1236,25 @@ namespace Godot
/// <param name="a">The dividend, the primary input.</param>
/// <param name="b">The divisor. The output is on the range [0, <paramref name="b"/>).</param>
/// <returns>The resulting output.</returns>
- public static real_t PosMod(real_t a, real_t b)
+ public static float PosMod(float a, float b)
+ {
+ float c = a % b;
+ if ((c < 0 && b > 0) || (c > 0 && b < 0))
+ {
+ c += b;
+ }
+ return c;
+ }
+
+ /// <summary>
+ /// Performs a canonical Modulus operation, where the output is on the range [0, <paramref name="b"/>).
+ /// </summary>
+ /// <param name="a">The dividend, the primary input.</param>
+ /// <param name="b">The divisor. The output is on the range [0, <paramref name="b"/>).</param>
+ /// <returns>The resulting output.</returns>
+ public static double PosMod(double a, double b)
{
- real_t c = a % b;
+ double c = a % b;
if ((c < 0 && b > 0) || (c > 0 && b < 0))
{
c += b;
@@ -609,9 +1268,33 @@ namespace Godot
/// <param name="x">The base.</param>
/// <param name="y">The exponent.</param>
/// <returns><paramref name="x"/> raised to the power of <paramref name="y"/>.</returns>
- public static real_t Pow(real_t x, real_t y)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Pow(float x, float y)
{
- return (real_t)Math.Pow(x, y);
+ return MathF.Pow(x, y);
+ }
+
+ /// <summary>
+ /// Returns the result of <paramref name="x"/> raised to the power of <paramref name="y"/>.
+ /// </summary>
+ /// <param name="x">The base.</param>
+ /// <param name="y">The exponent.</param>
+ /// <returns><paramref name="x"/> raised to the power of <paramref name="y"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Pow(double x, double y)
+ {
+ return Math.Pow(x, y);
+ }
+
+ /// <summary>
+ /// Converts an angle expressed in radians to degrees.
+ /// </summary>
+ /// <param name="rad">An angle expressed in radians.</param>
+ /// <returns>The same angle expressed in degrees.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float RadToDeg(float rad)
+ {
+ return rad * _radToDegConstF;
}
/// <summary>
@@ -619,9 +1302,10 @@ namespace Godot
/// </summary>
/// <param name="rad">An angle expressed in radians.</param>
/// <returns>The same angle expressed in degrees.</returns>
- public static real_t RadToDeg(real_t rad)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double RadToDeg(double rad)
{
- return rad * _radToDegConst;
+ return rad * _radToDegConstD;
}
/// <summary>
@@ -634,20 +1318,48 @@ namespace Godot
/// <param name="outFrom">The start value for the output interpolation.</param>
/// <param name="outTo">The destination value for the output interpolation.</param>
/// <returns>The resulting mapped value mapped.</returns>
- public static real_t Remap(real_t value, real_t inFrom, real_t inTo, real_t outFrom, real_t outTo)
+ public static float Remap(float value, float inFrom, float inTo, float outFrom, float outTo)
{
return Lerp(outFrom, outTo, InverseLerp(inFrom, inTo, value));
}
/// <summary>
+ /// Maps a <paramref name="value"/> from [<paramref name="inFrom"/>, <paramref name="inTo"/>]
+ /// to [<paramref name="outFrom"/>, <paramref name="outTo"/>].
+ /// </summary>
+ /// <param name="value">The value to map.</param>
+ /// <param name="inFrom">The start value for the input interpolation.</param>
+ /// <param name="inTo">The destination value for the input interpolation.</param>
+ /// <param name="outFrom">The start value for the output interpolation.</param>
+ /// <param name="outTo">The destination value for the output interpolation.</param>
+ /// <returns>The resulting mapped value mapped.</returns>
+ public static double Remap(double value, double inFrom, double inTo, double outFrom, double outTo)
+ {
+ return Lerp(outFrom, outTo, InverseLerp(inFrom, inTo, value));
+ }
+
+ /// <summary>
+ /// Rounds <paramref name="s"/> to the nearest whole number,
+ /// with halfway cases rounded towards the nearest multiple of two.
+ /// </summary>
+ /// <param name="s">The number to round.</param>
+ /// <returns>The rounded number.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Round(float s)
+ {
+ return MathF.Round(s);
+ }
+
+ /// <summary>
/// Rounds <paramref name="s"/> to the nearest whole number,
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
/// <param name="s">The number to round.</param>
/// <returns>The rounded number.</returns>
- public static real_t Round(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Round(double s)
{
- return (real_t)Math.Round(s);
+ return Math.Round(s);
}
/// <summary>
@@ -656,11 +1368,10 @@ namespace Godot
/// </summary>
/// <param name="s">The input number.</param>
/// <returns>One of three possible values: <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Sign(int s)
{
- if (s == 0)
- return 0;
- return s < 0 ? -1 : 1;
+ return Math.Sign(s);
}
/// <summary>
@@ -669,11 +1380,33 @@ namespace Godot
/// </summary>
/// <param name="s">The input number.</param>
/// <returns>One of three possible values: <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
- public static int Sign(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int Sign(float s)
{
- if (s == 0)
- return 0;
- return s < 0 ? -1 : 1;
+ return Math.Sign(s);
+ }
+
+ /// <summary>
+ /// Returns the sign of <paramref name="s"/>: <c>-1</c> or <c>1</c>.
+ /// Returns <c>0</c> if <paramref name="s"/> is <c>0</c>.
+ /// </summary>
+ /// <param name="s">The input number.</param>
+ /// <returns>One of three possible values: <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int Sign(double s)
+ {
+ return Math.Sign(s);
+ }
+
+ /// <summary>
+ /// Returns the sine of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The sine of that angle.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Sin(float s)
+ {
+ return MathF.Sin(s);
}
/// <summary>
@@ -681,9 +1414,21 @@ namespace Godot
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The sine of that angle.</returns>
- public static real_t Sin(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Sin(double s)
+ {
+ return Math.Sin(s);
+ }
+
+ /// <summary>
+ /// Returns the hyperbolic sine of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The hyperbolic sine of that angle.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Sinh(float s)
{
- return (real_t)Math.Sin(s);
+ return MathF.Sinh(s);
}
/// <summary>
@@ -691,27 +1436,47 @@ namespace Godot
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The hyperbolic sine of that angle.</returns>
- public static real_t Sinh(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Sinh(double s)
+ {
+ return Math.Sinh(s);
+ }
+
+ /// <summary>
+ /// Returns a number smoothly interpolated between <paramref name="from"/> and <paramref name="to"/>,
+ /// based on the <paramref name="weight"/>. Similar to <see cref="Lerp(float, float, float)"/>,
+ /// but interpolates faster at the beginning and slower at the end.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="weight">A value representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static float SmoothStep(float from, float to, float weight)
{
- return (real_t)Math.Sinh(s);
+ if (IsEqualApprox(from, to))
+ {
+ return from;
+ }
+ float x = Math.Clamp((weight - from) / (to - from), 0.0f, 1.0f);
+ return x * x * (3 - (2 * x));
}
/// <summary>
/// Returns a number smoothly interpolated between <paramref name="from"/> and <paramref name="to"/>,
- /// based on the <paramref name="weight"/>. Similar to <see cref="Lerp(real_t, real_t, real_t)"/>,
+ /// based on the <paramref name="weight"/>. Similar to <see cref="Lerp(double, double, double)"/>,
/// but interpolates faster at the beginning and slower at the end.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
/// <param name="to">The destination value for interpolation.</param>
/// <param name="weight">A value representing the amount of interpolation.</param>
/// <returns>The resulting value of the interpolation.</returns>
- public static real_t SmoothStep(real_t from, real_t to, real_t weight)
+ public static double SmoothStep(double from, double to, double weight)
{
if (IsEqualApprox(from, to))
{
return from;
}
- real_t x = Clamp((weight - from) / (to - from), (real_t)0.0, (real_t)1.0);
+ double x = Math.Clamp((weight - from) / (to - from), 0.0, 1.0);
return x * x * (3 - (2 * x));
}
@@ -722,9 +1487,23 @@ namespace Godot
/// </summary>
/// <param name="s">The input number. Must not be negative.</param>
/// <returns>The square root of <paramref name="s"/>.</returns>
- public static real_t Sqrt(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Sqrt(float s)
{
- return (real_t)Math.Sqrt(s);
+ return MathF.Sqrt(s);
+ }
+
+ /// <summary>
+ /// Returns the square root of <paramref name="s"/>, where <paramref name="s"/> is a non-negative number.
+ ///
+ /// If you need negative inputs, use <see cref="System.Numerics.Complex"/>.
+ /// </summary>
+ /// <param name="s">The input number. Must not be negative.</param>
+ /// <returns>The square root of <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Sqrt(double s)
+ {
+ return Math.Sqrt(s);
}
/// <summary>
@@ -734,7 +1513,7 @@ namespace Godot
/// </summary>
/// <param name="step">The input value.</param>
/// <returns>The position of the first non-zero digit.</returns>
- public static int StepDecimals(real_t step)
+ public static int StepDecimals(double step)
{
double[] sd = new double[]
{
@@ -748,7 +1527,7 @@ namespace Godot
0.00000009999,
0.000000009999,
};
- double abs = Abs(step);
+ double abs = Math.Abs(step);
double decs = abs - (int)abs; // Strip away integer part
for (int i = 0; i < sd.Length; i++)
{
@@ -767,24 +1546,53 @@ namespace Godot
/// <param name="s">The value to snap.</param>
/// <param name="step">The step size to snap to.</param>
/// <returns>The snapped value.</returns>
- public static real_t Snapped(real_t s, real_t step)
+ public static float Snapped(float s, float step)
{
if (step != 0f)
{
- return Floor((s / step) + 0.5f) * step;
+ return MathF.Floor((s / step) + 0.5f) * step;
}
return s;
}
/// <summary>
+ /// Snaps float value <paramref name="s"/> to a given <paramref name="step"/>.
+ /// This can also be used to round a floating point number to an arbitrary number of decimals.
+ /// </summary>
+ /// <param name="s">The value to snap.</param>
+ /// <param name="step">The step size to snap to.</param>
+ /// <returns>The snapped value.</returns>
+ public static double Snapped(double s, double step)
+ {
+ if (step != 0f)
+ {
+ return Math.Floor((s / step) + 0.5f) * step;
+ }
+
+ return s;
+ }
+
+ /// <summary>
+ /// Returns the tangent of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The tangent of that angle.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Tan(float s)
+ {
+ return MathF.Tan(s);
+ }
+
+ /// <summary>
/// Returns the tangent of angle <paramref name="s"/> in radians.
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The tangent of that angle.</returns>
- public static real_t Tan(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Tan(double s)
{
- return (real_t)Math.Tan(s);
+ return Math.Tan(s);
}
/// <summary>
@@ -792,9 +1600,21 @@ namespace Godot
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The hyperbolic tangent of that angle.</returns>
- public static real_t Tanh(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Tanh(float s)
{
- return (real_t)Math.Tanh(s);
+ return MathF.Tanh(s);
+ }
+
+ /// <summary>
+ /// Returns the hyperbolic tangent of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The hyperbolic tangent of that angle.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double Tanh(double s)
+ {
+ return Math.Tanh(s);
}
/// <summary>
@@ -820,15 +1640,35 @@ namespace Godot
/// Wraps <paramref name="value"/> between <paramref name="min"/> and <paramref name="max"/>.
/// Usable for creating loop-alike behavior or infinite surfaces.
/// If <paramref name="min"/> is <c>0</c>, this is equivalent
- /// to <see cref="PosMod(real_t, real_t)"/>, so prefer using that instead.
+ /// to <see cref="PosMod(float, float)"/>, so prefer using that instead.
+ /// </summary>
+ /// <param name="value">The value to wrap.</param>
+ /// <param name="min">The minimum allowed value and lower bound of the range.</param>
+ /// <param name="max">The maximum allowed value and upper bound of the range.</param>
+ /// <returns>The wrapped value.</returns>
+ public static float Wrap(float value, float min, float max)
+ {
+ float range = max - min;
+ if (IsZeroApprox(range))
+ {
+ return min;
+ }
+ return min + ((((value - min) % range) + range) % range);
+ }
+
+ /// <summary>
+ /// Wraps <paramref name="value"/> between <paramref name="min"/> and <paramref name="max"/>.
+ /// Usable for creating loop-alike behavior or infinite surfaces.
+ /// If <paramref name="min"/> is <c>0</c>, this is equivalent
+ /// to <see cref="PosMod(double, double)"/>, so prefer using that instead.
/// </summary>
/// <param name="value">The value to wrap.</param>
/// <param name="min">The minimum allowed value and lower bound of the range.</param>
/// <param name="max">The maximum allowed value and upper bound of the range.</param>
/// <returns>The wrapped value.</returns>
- public static real_t Wrap(real_t value, real_t min, real_t max)
+ public static double Wrap(double value, double min, double max)
{
- real_t range = max - min;
+ double range = max - min;
if (IsZeroApprox(range))
{
return min;
@@ -836,9 +1676,23 @@ namespace Godot
return min + ((((value - min) % range) + range) % range);
}
- private static real_t Fract(real_t value)
+ /// <summary>
+ /// Returns the <paramref name="value"/> wrapped between <c>0</c> and the <paramref name="length"/>.
+ /// If the limit is reached, the next value the function returned is decreased to the <c>0</c> side
+ /// or increased to the <paramref name="length"/> side (like a triangle wave).
+ /// If <paramref name="length"/> is less than zero, it becomes positive.
+ /// </summary>
+ /// <param name="value">The value to pingpong.</param>
+ /// <param name="length">The maximum value of the function.</param>
+ /// <returns>The ping-ponged value.</returns>
+ public static float PingPong(float value, float length)
{
- return value - (real_t)Math.Floor(value);
+ return (length != 0.0f) ? Math.Abs(Fract((value - length) / (length * 2.0f)) * length * 2.0f - length) : 0.0f;
+
+ static float Fract(float value)
+ {
+ return value - MathF.Floor(value);
+ }
}
/// <summary>
@@ -850,9 +1704,14 @@ namespace Godot
/// <param name="value">The value to pingpong.</param>
/// <param name="length">The maximum value of the function.</param>
/// <returns>The ping-ponged value.</returns>
- public static real_t PingPong(real_t value, real_t length)
+ public static double PingPong(double value, double length)
{
- return (length != (real_t)0.0) ? Abs(Fract((value - length) / (length * (real_t)2.0)) * length * (real_t)2.0 - length) : (real_t)0.0;
+ return (length != 0.0) ? Math.Abs(Fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0;
+
+ static double Fract(double value)
+ {
+ return value - Math.Floor(value);
+ }
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
index ea05c1547c..cc2d61f58d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
@@ -1,4 +1,8 @@
using System;
+using System.Runtime.CompilerServices;
+
+// This file contains extra members for the Mathf class that aren't part of Godot's Core API.
+// Math API that is also part of Core should go into Mathf.cs.
namespace Godot
{
@@ -16,14 +20,18 @@ namespace Godot
/// </summary>
public const real_t Sqrt2 = (real_t)1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095
+ // Epsilon size should depend on the precision used.
+ private const float _epsilonF = 1e-06f;
+ private const double _epsilonD = 1e-14;
+
/// <summary>
/// A very small number used for float comparison with error tolerance.
/// 1e-06 with single-precision floats, but 1e-14 if <c>REAL_T_IS_DOUBLE</c>.
/// </summary>
#if REAL_T_IS_DOUBLE
- public const real_t Epsilon = 1e-14; // Epsilon size should depend on the precision used.
+ public const real_t Epsilon = _epsilonD;
#else
- public const real_t Epsilon = 1e-06f;
+ public const real_t Epsilon = _epsilonF;
#endif
/// <summary>
@@ -31,7 +39,8 @@ namespace Godot
/// </summary>
/// <param name="s">The input value.</param>
/// <returns>The amount of digits.</returns>
- public static int DecimalCount(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int DecimalCount(double s)
{
return DecimalCount((decimal)s);
}
@@ -41,6 +50,7 @@ namespace Godot
/// </summary>
/// <param name="s">The input <see langword="decimal"/> value.</param>
/// <returns>The amount of digits.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int DecimalCount(decimal s)
{
return BitConverter.GetBytes(decimal.GetBits(s)[3])[2];
@@ -49,11 +59,25 @@ namespace Godot
/// <summary>
/// Rounds <paramref name="s"/> upward (towards positive infinity).
///
- /// This is the same as <see cref="Ceil(real_t)"/>, but returns an <see langword="int"/>.
+ /// This is the same as <see cref="Ceil(float)"/>, but returns an <see langword="int"/>.
/// </summary>
/// <param name="s">The number to ceil.</param>
/// <returns>The smallest whole number that is not less than <paramref name="s"/>.</returns>
- public static int CeilToInt(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int CeilToInt(float s)
+ {
+ return (int)MathF.Ceiling(s);
+ }
+
+ /// <summary>
+ /// Rounds <paramref name="s"/> upward (towards positive infinity).
+ ///
+ /// This is the same as <see cref="Ceil(double)"/>, but returns an <see langword="int"/>.
+ /// </summary>
+ /// <param name="s">The number to ceil.</param>
+ /// <returns>The smallest whole number that is not less than <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int CeilToInt(double s)
{
return (int)Math.Ceiling(s);
}
@@ -61,11 +85,25 @@ namespace Godot
/// <summary>
/// Rounds <paramref name="s"/> downward (towards negative infinity).
///
- /// This is the same as <see cref="Floor(real_t)"/>, but returns an <see langword="int"/>.
+ /// This is the same as <see cref="Floor(float)"/>, but returns an <see langword="int"/>.
/// </summary>
/// <param name="s">The number to floor.</param>
/// <returns>The largest whole number that is not more than <paramref name="s"/>.</returns>
- public static int FloorToInt(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int FloorToInt(float s)
+ {
+ return (int)MathF.Floor(s);
+ }
+
+ /// <summary>
+ /// Rounds <paramref name="s"/> downward (towards negative infinity).
+ ///
+ /// This is the same as <see cref="Floor(double)"/>, but returns an <see langword="int"/>.
+ /// </summary>
+ /// <param name="s">The number to floor.</param>
+ /// <returns>The largest whole number that is not more than <paramref name="s"/>.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int FloorToInt(double s)
{
return (int)Math.Floor(s);
}
@@ -73,26 +111,81 @@ namespace Godot
/// <summary>
/// Rounds <paramref name="s"/> to the nearest whole number.
///
- /// This is the same as <see cref="Round(real_t)"/>, but returns an <see langword="int"/>.
+ /// This is the same as <see cref="Round(float)"/>, but returns an <see langword="int"/>.
+ /// </summary>
+ /// <param name="s">The number to round.</param>
+ /// <returns>The rounded number.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int RoundToInt(float s)
+ {
+ return (int)MathF.Round(s);
+ }
+
+ /// <summary>
+ /// Rounds <paramref name="s"/> to the nearest whole number.
+ ///
+ /// This is the same as <see cref="Round(double)"/>, but returns an <see langword="int"/>.
/// </summary>
/// <param name="s">The number to round.</param>
/// <returns>The rounded number.</returns>
- public static int RoundToInt(real_t s)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int RoundToInt(double s)
{
return (int)Math.Round(s);
}
/// <summary>
+ /// Returns the sine and cosine of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The sine and cosine of that angle.</returns>
+ public static (float Sin, float Cos) SinCos(float s)
+ {
+ return MathF.SinCos(s);
+ }
+
+ /// <summary>
+ /// Returns the sine and cosine of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The sine and cosine of that angle.</returns>
+ public static (double Sin, double Cos) SinCos(double s)
+ {
+ return Math.SinCos(s);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately
+ /// equal to each other.
+ /// The comparison is done using the provided tolerance value.
+ /// If you want the tolerance to be calculated for you, use <see cref="IsEqualApprox(float, float)"/>.
+ /// </summary>
+ /// <param name="a">One of the values.</param>
+ /// <param name="b">The other value.</param>
+ /// <param name="tolerance">The pre-calculated tolerance value.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the two values are equal.</returns>
+ public static bool IsEqualApprox(float a, float b, float tolerance)
+ {
+ // Check for exact equality first, required to handle "infinity" values.
+ if (a == b)
+ {
+ return true;
+ }
+ // Then check for approximate equality.
+ return Math.Abs(a - b) < tolerance;
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately
/// equal to each other.
/// The comparison is done using the provided tolerance value.
- /// If you want the tolerance to be calculated for you, use <see cref="IsEqualApprox(real_t, real_t)"/>.
+ /// If you want the tolerance to be calculated for you, use <see cref="IsEqualApprox(double, double)"/>.
/// </summary>
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <param name="tolerance">The pre-calculated tolerance value.</param>
/// <returns>A <see langword="bool"/> for whether or not the two values are equal.</returns>
- public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance)
+ public static bool IsEqualApprox(double a, double b, double tolerance)
{
// Check for exact equality first, required to handle "infinity" values.
if (a == b)
@@ -100,7 +193,7 @@ namespace Godot
return true;
}
// Then check for approximate equality.
- return Abs(a - b) < tolerance;
+ return Math.Abs(a - b) < tolerance;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
index 5a0ea2ba13..71a2adadcb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
@@ -68,7 +68,7 @@ namespace Godot.NativeInterop
string file = globalFrames.Count > 0 ? globalFrames[0].File ?? "" : "";
string func = globalFrames.Count > 0 ? globalFrames[0].Func : "";
int line = globalFrames.Count > 0 ? globalFrames[0].Line : 0;
- string errorMsg = "Exception";
+ string errorMsg = e.GetType().FullName ?? "";
using godot_string nFile = Marshaling.ConvertStringToNative(file);
using godot_string nFunc = Marshaling.ConvertStringToNative(func);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
index fa79c2efbc..43e7c7eb9a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
@@ -104,7 +104,7 @@ namespace Godot.NativeInterop
}
}
- [StructLayout(LayoutKind.Explicit)]
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
// ReSharper disable once InconsistentNaming
public ref struct godot_variant
{
@@ -113,11 +113,11 @@ namespace Godot.NativeInterop
=> (godot_variant*)Unsafe.AsPointer(ref Unsafe.AsRef(in _typeField));
// Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits.
- [FieldOffset(0)] private int _typeField;
+ private int _typeField;
// There's padding here
- [FieldOffset(8)] private godot_variant_data _data;
+ private godot_variant_data _data;
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
@@ -126,10 +126,10 @@ namespace Godot.NativeInterop
[FieldOffset(0)] public godot_bool _bool;
[FieldOffset(0)] public long _int;
[FieldOffset(0)] public double _float;
- [FieldOffset(0)] public Transform2D* _transform2D;
- [FieldOffset(0)] public AABB* _aabb;
+ [FieldOffset(0)] public Transform2D* _transform2d;
+ [FieldOffset(0)] public Aabb* _aabb;
[FieldOffset(0)] public Basis* _basis;
- [FieldOffset(0)] public Transform3D* _transform3D;
+ [FieldOffset(0)] public Transform3D* _transform3d;
[FieldOffset(0)] public Projection* _projection;
[FieldOffset(0)] private godot_variant_data_mem _mem;
@@ -137,18 +137,18 @@ namespace Godot.NativeInterop
[FieldOffset(0)] public godot_string_name _m_string_name;
[FieldOffset(0)] public godot_string _m_string;
[FieldOffset(0)] public Vector4 _m_vector4;
- [FieldOffset(0)] public Vector4i _m_vector4i;
+ [FieldOffset(0)] public Vector4I _m_vector4i;
[FieldOffset(0)] public Vector3 _m_vector3;
- [FieldOffset(0)] public Vector3i _m_vector3i;
+ [FieldOffset(0)] public Vector3I _m_vector3i;
[FieldOffset(0)] public Vector2 _m_vector2;
- [FieldOffset(0)] public Vector2i _m_vector2i;
+ [FieldOffset(0)] public Vector2I _m_vector2i;
[FieldOffset(0)] public Rect2 _m_rect2;
- [FieldOffset(0)] public Rect2i _m_rect2i;
+ [FieldOffset(0)] public Rect2I _m_rect2i;
[FieldOffset(0)] public Plane _m_plane;
[FieldOffset(0)] public Quaternion _m_quaternion;
[FieldOffset(0)] public Color _m_color;
[FieldOffset(0)] public godot_node_path _m_node_path;
- [FieldOffset(0)] public RID _m_rid;
+ [FieldOffset(0)] public Rid _m_rid;
[FieldOffset(0)] public godot_variant_obj_data _m_obj_data;
[FieldOffset(0)] public godot_callable _m_callable;
[FieldOffset(0)] public godot_signal _m_signal;
@@ -211,10 +211,10 @@ namespace Godot.NativeInterop
public readonly unsafe Transform2D* Transform2D
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => _data._transform2D;
+ get => _data._transform2d;
}
- public readonly unsafe AABB* AABB
+ public readonly unsafe Aabb* Aabb
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _data._aabb;
@@ -229,7 +229,7 @@ namespace Godot.NativeInterop
public readonly unsafe Transform3D* Transform3D
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => _data._transform3D;
+ get => _data._transform3d;
}
public readonly unsafe Projection* Projection
@@ -262,7 +262,7 @@ namespace Godot.NativeInterop
set => _data._m_vector4 = value;
}
- public Vector4i Vector4i
+ public Vector4I Vector4I
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_vector4i;
@@ -278,7 +278,7 @@ namespace Godot.NativeInterop
set => _data._m_vector3 = value;
}
- public Vector3i Vector3i
+ public Vector3I Vector3I
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_vector3i;
@@ -294,7 +294,7 @@ namespace Godot.NativeInterop
set => _data._m_vector2 = value;
}
- public Vector2i Vector2i
+ public Vector2I Vector2I
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_vector2i;
@@ -310,7 +310,7 @@ namespace Godot.NativeInterop
set => _data._m_rect2 = value;
}
- public Rect2i Rect2i
+ public Rect2I Rect2I
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_rect2i;
@@ -350,7 +350,7 @@ namespace Godot.NativeInterop
set => _data._m_node_path = value;
}
- public RID RID
+ public Rid Rid
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => _data._m_rid;
@@ -405,13 +405,13 @@ namespace Godot.NativeInterop
case Variant.Type.Int:
case Variant.Type.Float:
case Variant.Type.Vector2:
- case Variant.Type.Vector2i:
+ case Variant.Type.Vector2I:
case Variant.Type.Rect2:
- case Variant.Type.Rect2i:
+ case Variant.Type.Rect2I:
case Variant.Type.Vector3:
- case Variant.Type.Vector3i:
+ case Variant.Type.Vector3I:
case Variant.Type.Vector4:
- case Variant.Type.Vector4i:
+ case Variant.Type.Vector4I:
case Variant.Type.Plane:
case Variant.Type.Quaternion:
case Variant.Type.Color:
@@ -697,6 +697,9 @@ namespace Godot.NativeInterop
private uint _safeRefCount;
public VariantVector _arrayVector;
+
+ private unsafe godot_variant* _readOnly;
+
// There are more fields here, but we don't care as we never store this in C#
public readonly int Size
@@ -704,6 +707,12 @@ namespace Godot.NativeInterop
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _arrayVector.Size;
}
+
+ public readonly unsafe bool IsReadOnly
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _readOnly != null;
+ }
}
[StructLayout(LayoutKind.Sequential)]
@@ -737,6 +746,12 @@ namespace Godot.NativeInterop
get => _p != null ? _p->Size : 0;
}
+ public readonly unsafe bool IsReadOnly
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _p != null && _p->IsReadOnly;
+ }
+
public unsafe void Dispose()
{
if (_p == null)
@@ -766,35 +781,59 @@ namespace Godot.NativeInterop
// A correctly constructed value needs to call the native default constructor to allocate `_p`.
// Don't pass a C# default constructed `godot_dictionary` to native code, unless it's going to
// be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine).
- [StructLayout(LayoutKind.Sequential)]
+ [StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
public ref struct godot_dictionary
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal readonly unsafe godot_dictionary* GetUnsafeAddress()
- => (godot_dictionary*)Unsafe.AsPointer(ref Unsafe.AsRef(in _p));
+ => (godot_dictionary*)Unsafe.AsPointer(ref Unsafe.AsRef(in _getUnsafeAddressHelper));
- private IntPtr _p;
+ [FieldOffset(0)] private byte _getUnsafeAddressHelper;
- public readonly bool IsAllocated
+ [FieldOffset(0)] private unsafe DictionaryPrivate* _p;
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct DictionaryPrivate
+ {
+ private uint _safeRefCount;
+
+ private unsafe godot_variant* _readOnly;
+
+ // There are more fields here, but we don't care as we never store this in C#
+
+ public readonly unsafe bool IsReadOnly
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _readOnly != null;
+ }
+ }
+
+ public readonly unsafe bool IsAllocated
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => _p != IntPtr.Zero;
+ get => _p != null;
}
- public void Dispose()
+ public readonly unsafe bool IsReadOnly
{
- if (_p == IntPtr.Zero)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _p != null && _p->IsReadOnly;
+ }
+
+ public unsafe void Dispose()
+ {
+ if (_p == null)
return;
NativeFuncs.godotsharp_dictionary_destroy(ref this);
- _p = IntPtr.Zero;
+ _p = null;
}
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
internal struct movable
{
- private IntPtr _p;
+ private unsafe DictionaryPrivate* _p;
public static unsafe explicit operator movable(in godot_dictionary value)
=> *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
index 82f1c04d40..cc308bfdb3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
@@ -8,7 +8,7 @@ namespace Godot.NativeInterop
{
internal static class InteropUtils
{
- public static Object UnmanagedGetManaged(IntPtr unmanaged)
+ public static GodotObject UnmanagedGetManaged(IntPtr unmanaged)
{
// The native pointer may be null
if (unmanaged == IntPtr.Zero)
@@ -23,7 +23,7 @@ namespace Godot.NativeInterop
unmanaged, out hasCsScriptInstance);
if (gcHandlePtr != IntPtr.Zero)
- return (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
+ return (GodotObject)GCHandle.FromIntPtr(gcHandlePtr).Target;
// Otherwise, if the object has a CSharpInstance script instance, return null
@@ -37,17 +37,17 @@ namespace Godot.NativeInterop
object target = gcHandlePtr != IntPtr.Zero ? GCHandle.FromIntPtr(gcHandlePtr).Target : null;
if (target != null)
- return (Object)target;
+ return (GodotObject)target;
// If the native instance binding GC handle target was collected, create a new one
gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_instance_binding_create_managed(
unmanaged, gcHandlePtr);
- return gcHandlePtr != IntPtr.Zero ? (Object)GCHandle.FromIntPtr(gcHandlePtr).Target : null;
+ return gcHandlePtr != IntPtr.Zero ? (GodotObject)GCHandle.FromIntPtr(gcHandlePtr).Target : null;
}
- public static void TieManagedToUnmanaged(Object managed, IntPtr unmanaged,
+ public static void TieManagedToUnmanaged(GodotObject managed, IntPtr unmanaged,
StringName nativeName, bool refCounted, Type type, Type nativeType)
{
var gcHandle = refCounted ?
@@ -76,7 +76,7 @@ namespace Godot.NativeInterop
}
}
- public static void TieManagedToUnmanagedWithPreSetup(Object managed, IntPtr unmanaged,
+ public static void TieManagedToUnmanagedWithPreSetup(GodotObject managed, IntPtr unmanaged,
Type type, Type nativeType)
{
if (type == nativeType)
@@ -87,7 +87,7 @@ namespace Godot.NativeInterop
GCHandle.ToIntPtr(strongGCHandle), unmanaged);
}
- public static Object EngineGetSingleton(string name)
+ public static GodotObject EngineGetSingleton(string name)
{
using godot_string src = Marshaling.ConvertStringToNative(name);
return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(src));
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
index 649661ee06..93a83b701b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -1,5 +1,7 @@
using System;
using System.Runtime.InteropServices;
+using Godot.Collections;
+using Array = System.Array;
// ReSharper disable InconsistentNaming
@@ -49,29 +51,29 @@ namespace Godot.NativeInterop
if (type == typeof(Vector2))
return Variant.Type.Vector2;
- if (type == typeof(Vector2i))
- return Variant.Type.Vector2i;
+ if (type == typeof(Vector2I))
+ return Variant.Type.Vector2I;
if (type == typeof(Rect2))
return Variant.Type.Rect2;
- if (type == typeof(Rect2i))
- return Variant.Type.Rect2i;
+ if (type == typeof(Rect2I))
+ return Variant.Type.Rect2I;
if (type == typeof(Transform2D))
- return Variant.Type.Transform2d;
+ return Variant.Type.Transform2D;
if (type == typeof(Vector3))
return Variant.Type.Vector3;
- if (type == typeof(Vector3i))
- return Variant.Type.Vector3i;
+ if (type == typeof(Vector3I))
+ return Variant.Type.Vector3I;
if (type == typeof(Vector4))
return Variant.Type.Vector4;
- if (type == typeof(Vector4i))
- return Variant.Type.Vector4i;
+ if (type == typeof(Vector4I))
+ return Variant.Type.Vector4I;
if (type == typeof(Basis))
return Variant.Type.Basis;
@@ -80,12 +82,12 @@ namespace Godot.NativeInterop
return Variant.Type.Quaternion;
if (type == typeof(Transform3D))
- return Variant.Type.Transform3d;
+ return Variant.Type.Transform3D;
if (type == typeof(Projection))
return Variant.Type.Projection;
- if (type == typeof(AABB))
+ if (type == typeof(Aabb))
return Variant.Type.Aabb;
if (type == typeof(Color))
@@ -97,7 +99,7 @@ namespace Godot.NativeInterop
if (type == typeof(Callable))
return Variant.Type.Callable;
- if (type == typeof(SignalInfo))
+ if (type == typeof(Signal))
return Variant.Type.Signal;
if (type.IsEnum)
@@ -138,16 +140,25 @@ namespace Godot.NativeInterop
if (type == typeof(NodePath[]))
return Variant.Type.Array;
- if (type == typeof(RID[]))
+ if (type == typeof(Rid[]))
return Variant.Type.Array;
- if (typeof(Godot.Object[]).IsAssignableFrom(type))
+ if (typeof(GodotObject[]).IsAssignableFrom(type))
return Variant.Type.Array;
}
else if (type.IsGenericType)
{
- if (typeof(Godot.Object).IsAssignableFrom(type))
+ if (typeof(GodotObject).IsAssignableFrom(type))
return Variant.Type.Object;
+
+ // We use `IsAssignableFrom` with our helper interfaces to detect generic Godot collections
+ // because `GetGenericTypeDefinition` is not supported in NativeAOT reflection-free mode.
+
+ if (typeof(IGenericGodotDictionary).IsAssignableFrom(type))
+ return Variant.Type.Dictionary;
+
+ if (typeof(IGenericGodotArray).IsAssignableFrom(type))
+ return Variant.Type.Array;
}
else if (type == typeof(Variant))
{
@@ -156,7 +167,7 @@ namespace Godot.NativeInterop
}
else
{
- if (typeof(Godot.Object).IsAssignableFrom(type))
+ if (typeof(GodotObject).IsAssignableFrom(type))
return Variant.Type.Object;
if (typeof(StringName) == type)
@@ -165,7 +176,7 @@ namespace Godot.NativeInterop
if (typeof(NodePath) == type)
return Variant.Type.NodePath;
- if (typeof(RID) == type)
+ if (typeof(Rid) == type)
return Variant.Type.Rid;
if (typeof(Collections.Dictionary) == type)
@@ -183,508 +194,6 @@ namespace Godot.NativeInterop
return Variant.Type.Nil;
}
- /* TODO: Reflection and type checking each time is slow. This will be replaced with source generators. */
- public static godot_variant ConvertManagedObjectToVariant(object? p_obj)
- {
- if (p_obj == null)
- return new godot_variant();
-
- switch (p_obj)
- {
- case bool @bool:
- return VariantUtils.CreateFromBool(@bool);
- case char @char:
- return VariantUtils.CreateFromInt(@char);
- case sbyte @int8:
- return VariantUtils.CreateFromInt(@int8);
- case short @int16:
- return VariantUtils.CreateFromInt(@int16);
- case int @int32:
- return VariantUtils.CreateFromInt(@int32);
- case long @int64:
- return VariantUtils.CreateFromInt(@int64);
- case byte @uint8:
- return VariantUtils.CreateFromInt(@uint8);
- case ushort @uint16:
- return VariantUtils.CreateFromInt(@uint16);
- case uint @uint32:
- return VariantUtils.CreateFromInt(@uint32);
- case ulong @uint64:
- return VariantUtils.CreateFromInt(@uint64);
- case float @float:
- return VariantUtils.CreateFromFloat(@float);
- case double @double:
- return VariantUtils.CreateFromFloat(@double);
- case Vector2 @vector2:
- return VariantUtils.CreateFromVector2(@vector2);
- case Vector2i @vector2i:
- return VariantUtils.CreateFromVector2i(@vector2i);
- case Rect2 @rect2:
- return VariantUtils.CreateFromRect2(@rect2);
- case Rect2i @rect2i:
- return VariantUtils.CreateFromRect2i(@rect2i);
- case Transform2D @transform2D:
- return VariantUtils.CreateFromTransform2D(@transform2D);
- case Vector3 @vector3:
- return VariantUtils.CreateFromVector3(@vector3);
- case Vector3i @vector3i:
- return VariantUtils.CreateFromVector3i(@vector3i);
- case Vector4 @vector4:
- return VariantUtils.CreateFromVector4(@vector4);
- case Vector4i @vector4i:
- return VariantUtils.CreateFromVector4i(@vector4i);
- case Basis @basis:
- return VariantUtils.CreateFromBasis(@basis);
- case Quaternion @quaternion:
- return VariantUtils.CreateFromQuaternion(@quaternion);
- case Transform3D @transform3d:
- return VariantUtils.CreateFromTransform3D(@transform3d);
- case Projection @projection:
- return VariantUtils.CreateFromProjection(@projection);
- case AABB @aabb:
- return VariantUtils.CreateFromAABB(@aabb);
- case Color @color:
- return VariantUtils.CreateFromColor(@color);
- case Plane @plane:
- return VariantUtils.CreateFromPlane(@plane);
- case Callable @callable:
- return VariantUtils.CreateFromCallable(@callable);
- case SignalInfo @signalInfo:
- return VariantUtils.CreateFromSignalInfo(@signalInfo);
- case Enum @enum:
- return VariantUtils.CreateFromInt(Convert.ToInt64(@enum));
- case string @string:
- return VariantUtils.CreateFromString(@string);
- case byte[] byteArray:
- return VariantUtils.CreateFromPackedByteArray(byteArray);
- case int[] int32Array:
- return VariantUtils.CreateFromPackedInt32Array(int32Array);
- case long[] int64Array:
- return VariantUtils.CreateFromPackedInt64Array(int64Array);
- case float[] floatArray:
- return VariantUtils.CreateFromPackedFloat32Array(floatArray);
- case double[] doubleArray:
- return VariantUtils.CreateFromPackedFloat64Array(doubleArray);
- case string[] stringArray:
- return VariantUtils.CreateFromPackedStringArray(stringArray);
- case Vector2[] vector2Array:
- return VariantUtils.CreateFromPackedVector2Array(vector2Array);
- case Vector3[] vector3Array:
- return VariantUtils.CreateFromPackedVector3Array(vector3Array);
- case Color[] colorArray:
- return VariantUtils.CreateFromPackedColorArray(colorArray);
- case StringName[] stringNameArray:
- return VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray);
- case NodePath[] nodePathArray:
- return VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray);
- case RID[] ridArray:
- return VariantUtils.CreateFromSystemArrayOfRID(ridArray);
- case Godot.Object[] godotObjectArray:
- return VariantUtils.CreateFromSystemArrayOfGodotObject(godotObjectArray);
- case Godot.Object godotObject:
- return VariantUtils.CreateFromGodotObject(godotObject);
- case StringName stringName:
- return VariantUtils.CreateFromStringName(stringName);
- case NodePath nodePath:
- return VariantUtils.CreateFromNodePath(nodePath);
- case RID rid:
- return VariantUtils.CreateFromRID(rid);
- case Collections.Dictionary godotDictionary:
- return VariantUtils.CreateFromDictionary(godotDictionary);
- case Collections.Array godotArray:
- return VariantUtils.CreateFromArray(godotArray);
- case Variant variant:
- return NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar);
- }
-
- GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" +
- p_obj.GetType().FullName + ".");
- return new godot_variant();
- }
-
- public static object? ConvertVariantToManagedObjectOfType(in godot_variant p_var, Type type)
- {
- // This function is only needed to set the value of properties. Fields have their own implementation, set_value_from_variant.
- switch (Type.GetTypeCode(type))
- {
- case TypeCode.Boolean:
- return VariantUtils.ConvertToBool(p_var);
- case TypeCode.Char:
- return VariantUtils.ConvertToChar(p_var);
- case TypeCode.SByte:
- return VariantUtils.ConvertToInt8(p_var);
- case TypeCode.Int16:
- return VariantUtils.ConvertToInt16(p_var);
- case TypeCode.Int32:
- return VariantUtils.ConvertToInt32(p_var);
- case TypeCode.Int64:
- return VariantUtils.ConvertToInt64(p_var);
- case TypeCode.Byte:
- return VariantUtils.ConvertToUInt8(p_var);
- case TypeCode.UInt16:
- return VariantUtils.ConvertToUInt16(p_var);
- case TypeCode.UInt32:
- return VariantUtils.ConvertToUInt32(p_var);
- case TypeCode.UInt64:
- return VariantUtils.ConvertToUInt64(p_var);
- case TypeCode.Single:
- return VariantUtils.ConvertToFloat32(p_var);
- case TypeCode.Double:
- return VariantUtils.ConvertToFloat64(p_var);
- case TypeCode.String:
- return VariantUtils.ConvertToStringObject(p_var);
- default:
- {
- if (type == typeof(Vector2))
- return VariantUtils.ConvertToVector2(p_var);
-
- if (type == typeof(Vector2i))
- return VariantUtils.ConvertToVector2i(p_var);
-
- if (type == typeof(Rect2))
- return VariantUtils.ConvertToRect2(p_var);
-
- if (type == typeof(Rect2i))
- return VariantUtils.ConvertToRect2i(p_var);
-
- if (type == typeof(Transform2D))
- return VariantUtils.ConvertToTransform2D(p_var);
-
- if (type == typeof(Vector3))
- return VariantUtils.ConvertToVector3(p_var);
-
- if (type == typeof(Vector3i))
- return VariantUtils.ConvertToVector3i(p_var);
-
- if (type == typeof(Vector4))
- return VariantUtils.ConvertToVector4(p_var);
-
- if (type == typeof(Vector4i))
- return VariantUtils.ConvertToVector4i(p_var);
-
- if (type == typeof(Basis))
- return VariantUtils.ConvertToBasis(p_var);
-
- if (type == typeof(Quaternion))
- return VariantUtils.ConvertToQuaternion(p_var);
-
- if (type == typeof(Transform3D))
- return VariantUtils.ConvertToTransform3D(p_var);
-
- if (type == typeof(Projection))
- return VariantUtils.ConvertToProjection(p_var);
-
- if (type == typeof(AABB))
- return VariantUtils.ConvertToAABB(p_var);
-
- if (type == typeof(Color))
- return VariantUtils.ConvertToColor(p_var);
-
- if (type == typeof(Plane))
- return VariantUtils.ConvertToPlane(p_var);
-
- if (type == typeof(Callable))
- return VariantUtils.ConvertToCallableManaged(p_var);
-
- if (type == typeof(SignalInfo))
- return VariantUtils.ConvertToSignalInfo(p_var);
-
- if (type.IsEnum)
- {
- var enumUnderlyingType = type.GetEnumUnderlyingType();
- switch (Type.GetTypeCode(enumUnderlyingType))
- {
- case TypeCode.SByte:
- return VariantUtils.ConvertToInt8(p_var);
- case TypeCode.Int16:
- return VariantUtils.ConvertToInt16(p_var);
- case TypeCode.Int32:
- return VariantUtils.ConvertToInt32(p_var);
- case TypeCode.Int64:
- return VariantUtils.ConvertToInt64(p_var);
- case TypeCode.Byte:
- return VariantUtils.ConvertToUInt8(p_var);
- case TypeCode.UInt16:
- return VariantUtils.ConvertToUInt16(p_var);
- case TypeCode.UInt32:
- return VariantUtils.ConvertToUInt32(p_var);
- case TypeCode.UInt64:
- return VariantUtils.ConvertToUInt64(p_var);
- default:
- {
- GD.PushError(
- "Attempted to convert Variant to enum value of unsupported underlying type. Name: " +
- type.FullName + " : " + enumUnderlyingType.FullName + ".");
- return null;
- }
- }
- }
-
- if (type.IsArray || type.IsSZArray)
- {
- return ConvertVariantToSystemArrayOfType(p_var, type);
- }
- else if (type.IsGenericType)
- {
- if (typeof(Godot.Object).IsAssignableFrom(type))
- {
- var godotObject = VariantUtils.ConvertToGodotObject(p_var);
-
- if (!type.IsInstanceOfType(godotObject))
- {
- GD.PushError("Invalid cast when marshaling Godot.Object type." +
- $" `{godotObject.GetType()}` is not assignable to `{type.FullName}`.");
- return null;
- }
-
- return godotObject;
- }
-
- return null;
- }
- else if (type == typeof(Variant))
- {
- return Variant.CreateCopyingBorrowed(p_var);
- }
-
- if (ConvertVariantToManagedObjectOfClass(p_var, type, out object? res))
- return res;
-
- break;
- }
- }
-
- GD.PushError("Attempted to convert Variant to unsupported type. Name: " +
- type.FullName + ".");
- return null;
- }
-
- private static object? ConvertVariantToSystemArrayOfType(in godot_variant p_var, Type type)
- {
- if (type == typeof(byte[]))
- return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var);
-
- if (type == typeof(int[]))
- return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var);
-
- if (type == typeof(long[]))
- return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var);
-
- if (type == typeof(float[]))
- return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var);
-
- if (type == typeof(double[]))
- return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var);
-
- if (type == typeof(string[]))
- return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var);
-
- if (type == typeof(Vector2[]))
- return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var);
-
- if (type == typeof(Vector3[]))
- return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var);
-
- if (type == typeof(Color[]))
- return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var);
-
- if (type == typeof(StringName[]))
- return VariantUtils.ConvertToSystemArrayOfStringName(p_var);
-
- if (type == typeof(NodePath[]))
- return VariantUtils.ConvertToSystemArrayOfNodePath(p_var);
-
- if (type == typeof(RID[]))
- return VariantUtils.ConvertToSystemArrayOfRID(p_var);
-
- if (typeof(Godot.Object[]).IsAssignableFrom(type))
- return VariantUtils.ConvertToSystemArrayOfGodotObject(p_var, type);
-
- GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " +
- type.GetElementType()!.FullName + ".");
- return null;
- }
-
- private static bool ConvertVariantToManagedObjectOfClass(in godot_variant p_var, Type type,
- out object? res)
- {
- if (typeof(Godot.Object).IsAssignableFrom(type))
- {
- if (p_var.Type == Variant.Type.Nil)
- {
- res = null;
- return true;
- }
-
- if (p_var.Type != Variant.Type.Object)
- {
- GD.PushError("Invalid cast when marshaling Godot.Object type." +
- $" Variant type is `{p_var.Type}`; expected `{p_var.Object}`.");
- res = null;
- return true;
- }
-
- var godotObjectPtr = VariantUtils.ConvertToGodotObjectPtr(p_var);
-
- if (godotObjectPtr == IntPtr.Zero)
- {
- res = null;
- return true;
- }
-
- var godotObject = InteropUtils.UnmanagedGetManaged(godotObjectPtr);
-
- if (!type.IsInstanceOfType(godotObject))
- {
- GD.PushError("Invalid cast when marshaling Godot.Object type." +
- $" `{godotObject.GetType()}` is not assignable to `{type.FullName}`.");
- res = null;
- return false;
- }
-
- res = godotObject;
- return true;
- }
-
- if (typeof(StringName) == type)
- {
- res = VariantUtils.ConvertToStringNameObject(p_var);
- return true;
- }
-
- if (typeof(NodePath) == type)
- {
- res = VariantUtils.ConvertToNodePathObject(p_var);
- return true;
- }
-
- if (typeof(RID) == type)
- {
- res = VariantUtils.ConvertToRID(p_var);
- return true;
- }
-
- if (typeof(Collections.Dictionary) == type)
- {
- res = VariantUtils.ConvertToDictionaryObject(p_var);
- return true;
- }
-
- if (typeof(Collections.Array) == type)
- {
- res = VariantUtils.ConvertToArrayObject(p_var);
- return true;
- }
-
- res = null;
- return false;
- }
-
- public static unsafe object? ConvertVariantToManagedObject(in godot_variant p_var)
- {
- switch (p_var.Type)
- {
- case Variant.Type.Bool:
- return p_var.Bool.ToBool();
- case Variant.Type.Int:
- return p_var.Int;
- case Variant.Type.Float:
- {
-#if REAL_T_IS_DOUBLE
- return p_var.Float;
-#else
- return (float)p_var.Float;
-#endif
- }
- case Variant.Type.String:
- return ConvertStringToManaged(p_var.String);
- case Variant.Type.Vector2:
- return p_var.Vector2;
- case Variant.Type.Vector2i:
- return p_var.Vector2i;
- case Variant.Type.Rect2:
- return p_var.Rect2;
- case Variant.Type.Rect2i:
- return p_var.Rect2i;
- case Variant.Type.Vector3:
- return p_var.Vector3;
- case Variant.Type.Vector3i:
- return p_var.Vector3i;
- case Variant.Type.Transform2d:
- return *p_var.Transform2D;
- case Variant.Type.Vector4:
- return p_var.Vector4;
- case Variant.Type.Vector4i:
- return p_var.Vector4i;
- case Variant.Type.Plane:
- return p_var.Plane;
- case Variant.Type.Quaternion:
- return p_var.Quaternion;
- case Variant.Type.Aabb:
- return *p_var.AABB;
- case Variant.Type.Basis:
- return *p_var.Basis;
- case Variant.Type.Transform3d:
- return *p_var.Transform3D;
- case Variant.Type.Projection:
- return *p_var.Projection;
- case Variant.Type.Color:
- return p_var.Color;
- case Variant.Type.StringName:
- {
- // The Variant owns the value, so we need to make a copy
- return StringName.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName));
- }
- case Variant.Type.NodePath:
- {
- // The Variant owns the value, so we need to make a copy
- return NodePath.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath));
- }
- case Variant.Type.Rid:
- return p_var.RID;
- case Variant.Type.Object:
- return InteropUtils.UnmanagedGetManaged(p_var.Object);
- case Variant.Type.Callable:
- return ConvertCallableToManaged(p_var.Callable);
- case Variant.Type.Signal:
- return ConvertSignalToManaged(p_var.Signal);
- case Variant.Type.Dictionary:
- {
- // The Variant owns the value, so we need to make a copy
- return Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary));
- }
- case Variant.Type.Array:
- {
- // The Variant owns the value, so we need to make a copy
- return Collections.Array.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_array_new_copy(p_var.Array));
- }
- case Variant.Type.PackedByteArray:
- return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var);
- case Variant.Type.PackedInt32Array:
- return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var);
- case Variant.Type.PackedInt64Array:
- return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var);
- case Variant.Type.PackedFloat32Array:
- return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var);
- case Variant.Type.PackedFloat64Array:
- return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var);
- case Variant.Type.PackedStringArray:
- return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var);
- case Variant.Type.PackedVector2Array:
- return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var);
- case Variant.Type.PackedVector3Array:
- return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var);
- case Variant.Type.PackedColorArray:
- return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var);
- default:
- return null;
- }
- }
-
// String
public static unsafe godot_string ConvertStringToNative(string? p_mono_string)
@@ -723,7 +232,7 @@ namespace Godot.NativeInterop
var gcHandle = CustomGCHandle.AllocStrong(p_managed_callable.Delegate);
IntPtr objectPtr = p_managed_callable.Target != null ?
- Object.GetPtr(p_managed_callable.Target) :
+ GodotObject.GetPtr(p_managed_callable.Target) :
IntPtr.Zero;
unsafe
@@ -779,9 +288,9 @@ namespace Godot.NativeInterop
return new Callable();
}
- // SignalInfo
+ // Signal
- public static godot_signal ConvertSignalToNative(in SignalInfo p_managed_signal)
+ public static godot_signal ConvertSignalToNative(in Signal p_managed_signal)
{
ulong ownerId = p_managed_signal.Owner.GetInstanceId();
godot_string_name name;
@@ -799,18 +308,18 @@ namespace Godot.NativeInterop
return new godot_signal(name, ownerId);
}
- public static SignalInfo ConvertSignalToManaged(in godot_signal p_signal)
+ public static Signal ConvertSignalToManaged(in godot_signal p_signal)
{
- var owner = GD.InstanceFromId(p_signal.ObjectId);
+ var owner = GodotObject.InstanceFromId(p_signal.ObjectId);
var name = StringName.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_string_name_new_copy(p_signal.Name));
- return new SignalInfo(owner, name);
+ return new Signal(owner, name);
}
// Array
internal static T[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType<T>(in godot_array p_array)
- where T : Godot.Object
+ where T : GodotObject
{
var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_array_new_copy(p_array));
@@ -824,22 +333,6 @@ namespace Godot.NativeInterop
return ret;
}
- // TODO: This needs reflection. Look for an alternative.
- internal static Godot.Object[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(in godot_array p_array,
- Type type)
- {
- var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_array_new_copy(p_array));
-
- int length = array.Count;
- var ret = (Godot.Object[])Activator.CreateInstance(type, length)!;
-
- for (int i = 0; i < length; i++)
- ret[i] = array[i].AsGodotObject();
-
- return ret;
- }
-
internal static StringName[] ConvertNativeGodotArrayToSystemArrayOfStringName(in godot_array p_array)
{
var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
@@ -868,16 +361,16 @@ namespace Godot.NativeInterop
return ret;
}
- internal static RID[] ConvertNativeGodotArrayToSystemArrayOfRID(in godot_array p_array)
+ internal static Rid[] ConvertNativeGodotArrayToSystemArrayOfRid(in godot_array p_array)
{
var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_array_new_copy(p_array));
int length = array.Count;
- var ret = new RID[length];
+ var ret = new Rid[length];
for (int i = 0; i < length; i++)
- ret[i] = array[i].AsRID();
+ ret[i] = array[i].AsRid();
return ret;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index b30b6a0752..3d72ee0036 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -153,6 +153,8 @@ namespace Godot.NativeInterop
internal static partial void godotsharp_callable_call_deferred(in godot_callable p_callable,
godot_variant** p_args, int p_arg_count);
+ internal static partial Color godotsharp_color_from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha);
+
// GDNative functions
// gdnative.h
@@ -182,7 +184,7 @@ namespace Godot.NativeInterop
public static partial void godotsharp_variant_new_projection(out godot_variant r_dest, in Projection p_proj);
- public static partial void godotsharp_variant_new_aabb(out godot_variant r_dest, in AABB p_aabb);
+ public static partial void godotsharp_variant_new_aabb(out godot_variant r_dest, in Aabb p_aabb);
public static partial void godotsharp_variant_new_dictionary(out godot_variant r_dest,
in godot_dictionary p_dict);
@@ -226,27 +228,27 @@ namespace Godot.NativeInterop
public static partial Vector2 godotsharp_variant_as_vector2(in godot_variant p_self);
- public static partial Vector2i godotsharp_variant_as_vector2i(in godot_variant p_self);
+ public static partial Vector2I godotsharp_variant_as_vector2i(in godot_variant p_self);
public static partial Rect2 godotsharp_variant_as_rect2(in godot_variant p_self);
- public static partial Rect2i godotsharp_variant_as_rect2i(in godot_variant p_self);
+ public static partial Rect2I godotsharp_variant_as_rect2i(in godot_variant p_self);
public static partial Vector3 godotsharp_variant_as_vector3(in godot_variant p_self);
- public static partial Vector3i godotsharp_variant_as_vector3i(in godot_variant p_self);
+ public static partial Vector3I godotsharp_variant_as_vector3i(in godot_variant p_self);
public static partial Transform2D godotsharp_variant_as_transform2d(in godot_variant p_self);
public static partial Vector4 godotsharp_variant_as_vector4(in godot_variant p_self);
- public static partial Vector4i godotsharp_variant_as_vector4i(in godot_variant p_self);
+ public static partial Vector4I godotsharp_variant_as_vector4i(in godot_variant p_self);
public static partial Plane godotsharp_variant_as_plane(in godot_variant p_self);
public static partial Quaternion godotsharp_variant_as_quaternion(in godot_variant p_self);
- public static partial AABB godotsharp_variant_as_aabb(in godot_variant p_self);
+ public static partial Aabb godotsharp_variant_as_aabb(in godot_variant p_self);
public static partial Basis godotsharp_variant_as_basis(in godot_variant p_self);
@@ -260,7 +262,7 @@ namespace Godot.NativeInterop
public static partial godot_node_path godotsharp_variant_as_node_path(in godot_variant p_self);
- public static partial RID godotsharp_variant_as_rid(in godot_variant p_self);
+ public static partial Rid godotsharp_variant_as_rid(in godot_variant p_self);
public static partial godot_callable godotsharp_variant_as_callable(in godot_variant p_self);
@@ -363,19 +365,44 @@ namespace Godot.NativeInterop
public static partial int godotsharp_array_add(ref godot_array p_self, in godot_variant p_item);
+ public static partial int godotsharp_array_add_range(ref godot_array p_self, in godot_array p_collection);
+
+ public static partial int godotsharp_array_binary_search(ref godot_array p_self, int p_index, int p_count, in godot_variant p_value);
+
public static partial void
godotsharp_array_duplicate(ref godot_array p_self, godot_bool p_deep, out godot_array r_dest);
- public static partial int godotsharp_array_index_of(ref godot_array p_self, in godot_variant p_item);
+ public static partial void godotsharp_array_fill(ref godot_array p_self, in godot_variant p_value);
+
+ public static partial int godotsharp_array_index_of(ref godot_array p_self, in godot_variant p_item, int p_index = 0);
public static partial void godotsharp_array_insert(ref godot_array p_self, int p_index, in godot_variant p_item);
+ public static partial int godotsharp_array_last_index_of(ref godot_array p_self, in godot_variant p_item, int p_index);
+
+ public static partial void godotsharp_array_make_read_only(ref godot_array p_self);
+
+ public static partial void godotsharp_array_max(ref godot_array p_self, out godot_variant r_value);
+
+ public static partial void godotsharp_array_min(ref godot_array p_self, out godot_variant r_value);
+
+ public static partial void godotsharp_array_pick_random(ref godot_array p_self, out godot_variant r_value);
+
+ public static partial godot_bool godotsharp_array_recursive_equal(ref godot_array p_self, in godot_array p_other);
+
public static partial void godotsharp_array_remove_at(ref godot_array p_self, int p_index);
public static partial Error godotsharp_array_resize(ref godot_array p_self, int p_new_size);
+ public static partial void godotsharp_array_reverse(ref godot_array p_self);
+
public static partial void godotsharp_array_shuffle(ref godot_array p_self);
+ public static partial void godotsharp_array_slice(ref godot_array p_self, int p_start, int p_end,
+ int p_step, godot_bool p_deep, out godot_array r_dest);
+
+ public static partial void godotsharp_array_sort(ref godot_array p_self);
+
public static partial void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str);
// Dictionary
@@ -407,28 +434,19 @@ namespace Godot.NativeInterop
public static partial void godotsharp_dictionary_duplicate(ref godot_dictionary p_self, godot_bool p_deep,
out godot_dictionary r_dest);
+ public static partial void godotsharp_dictionary_merge(ref godot_dictionary p_self, in godot_dictionary p_dictionary, godot_bool p_overwrite);
+
+ public static partial godot_bool godotsharp_dictionary_recursive_equal(ref godot_dictionary p_self, in godot_dictionary p_other);
+
public static partial godot_bool godotsharp_dictionary_remove_key(ref godot_dictionary p_self,
in godot_variant p_key);
+ public static partial void godotsharp_dictionary_make_read_only(ref godot_dictionary p_self);
+
public static partial void godotsharp_dictionary_to_string(ref godot_dictionary p_self, out godot_string r_str);
// StringExtensions
- public static partial void godotsharp_string_md5_buffer(in godot_string p_self,
- out godot_packed_byte_array r_md5_buffer);
-
- public static partial void godotsharp_string_md5_text(in godot_string p_self, out godot_string r_md5_text);
-
- public static partial int godotsharp_string_rfind(in godot_string p_self, in godot_string p_what, int p_from);
-
- public static partial int godotsharp_string_rfindn(in godot_string p_self, in godot_string p_what, int p_from);
-
- public static partial void godotsharp_string_sha256_buffer(in godot_string p_self,
- out godot_packed_byte_array r_sha256_buffer);
-
- public static partial void godotsharp_string_sha256_text(in godot_string p_self,
- out godot_string r_sha256_text);
-
public static partial void godotsharp_string_simplify_path(in godot_string p_self,
out godot_string r_simplified_path);
@@ -464,6 +482,10 @@ namespace Godot.NativeInterop
public static partial godot_bool godotsharp_node_path_is_absolute(in godot_node_path p_self);
+ public static partial godot_bool godotsharp_node_path_equals(in godot_node_path p_self, in godot_node_path p_other);
+
+ public static partial int godotsharp_node_path_hash(in godot_node_path p_self);
+
// GD, etc
internal static partial void godotsharp_bytes_to_var(in godot_packed_byte_array p_bytes,
@@ -507,8 +529,6 @@ namespace Godot.NativeInterop
internal static partial void godotsharp_weakref(IntPtr p_obj, out godot_ref r_weak_ref);
- internal static partial void godotsharp_str(in godot_array p_what, out godot_string r_ret);
-
internal static partial void godotsharp_str_to_var(in godot_string p_str, out godot_variant r_ret);
internal static partial void godotsharp_var_to_bytes(in godot_variant p_what, godot_bool p_full_objects,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
index 9f0b55431b..44ec16dca9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
@@ -18,20 +18,20 @@ namespace Godot.NativeInterop
return new godot_variant() { Float = src.Float, Type = Variant.Type.Float };
case Variant.Type.Vector2:
return new godot_variant() { Vector2 = src.Vector2, Type = Variant.Type.Vector2 };
- case Variant.Type.Vector2i:
- return new godot_variant() { Vector2i = src.Vector2i, Type = Variant.Type.Vector2i };
+ case Variant.Type.Vector2I:
+ return new godot_variant() { Vector2I = src.Vector2I, Type = Variant.Type.Vector2I };
case Variant.Type.Rect2:
return new godot_variant() { Rect2 = src.Rect2, Type = Variant.Type.Rect2 };
- case Variant.Type.Rect2i:
- return new godot_variant() { Rect2i = src.Rect2i, Type = Variant.Type.Rect2i };
+ case Variant.Type.Rect2I:
+ return new godot_variant() { Rect2I = src.Rect2I, Type = Variant.Type.Rect2I };
case Variant.Type.Vector3:
return new godot_variant() { Vector3 = src.Vector3, Type = Variant.Type.Vector3 };
- case Variant.Type.Vector3i:
- return new godot_variant() { Vector3i = src.Vector3i, Type = Variant.Type.Vector3i };
+ case Variant.Type.Vector3I:
+ return new godot_variant() { Vector3I = src.Vector3I, Type = Variant.Type.Vector3I };
case Variant.Type.Vector4:
return new godot_variant() { Vector4 = src.Vector4, Type = Variant.Type.Vector4 };
- case Variant.Type.Vector4i:
- return new godot_variant() { Vector4i = src.Vector4i, Type = Variant.Type.Vector4i };
+ case Variant.Type.Vector4I:
+ return new godot_variant() { Vector4I = src.Vector4I, Type = Variant.Type.Vector4I };
case Variant.Type.Plane:
return new godot_variant() { Plane = src.Plane, Type = Variant.Type.Plane };
case Variant.Type.Quaternion:
@@ -39,7 +39,7 @@ namespace Godot.NativeInterop
case Variant.Type.Color:
return new godot_variant() { Color = src.Color, Type = Variant.Type.Color };
case Variant.Type.Rid:
- return new godot_variant() { RID = src.RID, Type = Variant.Type.Rid };
+ return new godot_variant() { Rid = src.Rid, Type = Variant.Type.Rid };
}
godotsharp_variant_new_copy(out godot_variant ret, src);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
deleted file mode 100644
index 4b3db0c01a..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
+++ /dev/null
@@ -1,1057 +0,0 @@
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
-
-namespace Godot.NativeInterop;
-
-// TODO: Change VariantConversionCallbacks<T>. Store the callback in a static field for quick repeated access, instead of checking every time.
-internal static unsafe class VariantConversionCallbacks
-{
- internal static System.Collections.Generic.Dictionary<Type, (IntPtr ToVariant, IntPtr FromVariant)>
- GenericConversionCallbacks = new();
-
- [SuppressMessage("ReSharper", "RedundantNameQualifier")]
- internal static delegate*<in T, godot_variant> GetToVariantCallback<T>()
- {
- static godot_variant FromBool(in bool @bool) =>
- VariantUtils.CreateFromBool(@bool);
-
- static godot_variant FromChar(in char @char) =>
- VariantUtils.CreateFromInt(@char);
-
- static godot_variant FromInt8(in sbyte @int8) =>
- VariantUtils.CreateFromInt(@int8);
-
- static godot_variant FromInt16(in short @int16) =>
- VariantUtils.CreateFromInt(@int16);
-
- static godot_variant FromInt32(in int @int32) =>
- VariantUtils.CreateFromInt(@int32);
-
- static godot_variant FromInt64(in long @int64) =>
- VariantUtils.CreateFromInt(@int64);
-
- static godot_variant FromUInt8(in byte @uint8) =>
- VariantUtils.CreateFromInt(@uint8);
-
- static godot_variant FromUInt16(in ushort @uint16) =>
- VariantUtils.CreateFromInt(@uint16);
-
- static godot_variant FromUInt32(in uint @uint32) =>
- VariantUtils.CreateFromInt(@uint32);
-
- static godot_variant FromUInt64(in ulong @uint64) =>
- VariantUtils.CreateFromInt(@uint64);
-
- static godot_variant FromFloat(in float @float) =>
- VariantUtils.CreateFromFloat(@float);
-
- static godot_variant FromDouble(in double @double) =>
- VariantUtils.CreateFromFloat(@double);
-
- static godot_variant FromVector2(in Vector2 @vector2) =>
- VariantUtils.CreateFromVector2(@vector2);
-
- static godot_variant FromVector2I(in Vector2i vector2I) =>
- VariantUtils.CreateFromVector2i(vector2I);
-
- static godot_variant FromRect2(in Rect2 @rect2) =>
- VariantUtils.CreateFromRect2(@rect2);
-
- static godot_variant FromRect2I(in Rect2i rect2I) =>
- VariantUtils.CreateFromRect2i(rect2I);
-
- static godot_variant FromTransform2D(in Transform2D @transform2D) =>
- VariantUtils.CreateFromTransform2D(@transform2D);
-
- static godot_variant FromVector3(in Vector3 @vector3) =>
- VariantUtils.CreateFromVector3(@vector3);
-
- static godot_variant FromVector3I(in Vector3i vector3I) =>
- VariantUtils.CreateFromVector3i(vector3I);
-
- static godot_variant FromBasis(in Basis @basis) =>
- VariantUtils.CreateFromBasis(@basis);
-
- static godot_variant FromQuaternion(in Quaternion @quaternion) =>
- VariantUtils.CreateFromQuaternion(@quaternion);
-
- static godot_variant FromTransform3D(in Transform3D @transform3d) =>
- VariantUtils.CreateFromTransform3D(@transform3d);
-
- static godot_variant FromVector4(in Vector4 @vector4) =>
- VariantUtils.CreateFromVector4(@vector4);
-
- static godot_variant FromVector4I(in Vector4i vector4I) =>
- VariantUtils.CreateFromVector4i(vector4I);
-
- static godot_variant FromAabb(in AABB @aabb) =>
- VariantUtils.CreateFromAABB(@aabb);
-
- static godot_variant FromColor(in Color @color) =>
- VariantUtils.CreateFromColor(@color);
-
- static godot_variant FromPlane(in Plane @plane) =>
- VariantUtils.CreateFromPlane(@plane);
-
- static godot_variant FromCallable(in Callable @callable) =>
- VariantUtils.CreateFromCallable(@callable);
-
- static godot_variant FromSignalInfo(in SignalInfo @signalInfo) =>
- VariantUtils.CreateFromSignalInfo(@signalInfo);
-
- static godot_variant FromString(in string @string) =>
- VariantUtils.CreateFromString(@string);
-
- static godot_variant FromByteArray(in byte[] byteArray) =>
- VariantUtils.CreateFromPackedByteArray(byteArray);
-
- static godot_variant FromInt32Array(in int[] int32Array) =>
- VariantUtils.CreateFromPackedInt32Array(int32Array);
-
- static godot_variant FromInt64Array(in long[] int64Array) =>
- VariantUtils.CreateFromPackedInt64Array(int64Array);
-
- static godot_variant FromFloatArray(in float[] floatArray) =>
- VariantUtils.CreateFromPackedFloat32Array(floatArray);
-
- static godot_variant FromDoubleArray(in double[] doubleArray) =>
- VariantUtils.CreateFromPackedFloat64Array(doubleArray);
-
- static godot_variant FromStringArray(in string[] stringArray) =>
- VariantUtils.CreateFromPackedStringArray(stringArray);
-
- static godot_variant FromVector2Array(in Vector2[] vector2Array) =>
- VariantUtils.CreateFromPackedVector2Array(vector2Array);
-
- static godot_variant FromVector3Array(in Vector3[] vector3Array) =>
- VariantUtils.CreateFromPackedVector3Array(vector3Array);
-
- static godot_variant FromColorArray(in Color[] colorArray) =>
- VariantUtils.CreateFromPackedColorArray(colorArray);
-
- static godot_variant FromStringNameArray(in StringName[] stringNameArray) =>
- VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray);
-
- static godot_variant FromNodePathArray(in NodePath[] nodePathArray) =>
- VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray);
-
- static godot_variant FromRidArray(in RID[] ridArray) =>
- VariantUtils.CreateFromSystemArrayOfRID(ridArray);
-
- static godot_variant FromGodotObject(in Godot.Object godotObject) =>
- VariantUtils.CreateFromGodotObject(godotObject);
-
- static godot_variant FromStringName(in StringName stringName) =>
- VariantUtils.CreateFromStringName(stringName);
-
- static godot_variant FromNodePath(in NodePath nodePath) =>
- VariantUtils.CreateFromNodePath(nodePath);
-
- static godot_variant FromRid(in RID rid) =>
- VariantUtils.CreateFromRID(rid);
-
- static godot_variant FromGodotDictionary(in Collections.Dictionary godotDictionary) =>
- VariantUtils.CreateFromDictionary(godotDictionary);
-
- static godot_variant FromGodotArray(in Collections.Array godotArray) =>
- VariantUtils.CreateFromArray(godotArray);
-
- static godot_variant FromVariant(in Variant variant) =>
- NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar);
-
- var typeOfT = typeof(T);
-
- if (typeOfT == typeof(bool))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in bool, godot_variant>)
- &FromBool;
- }
-
- if (typeOfT == typeof(char))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in char, godot_variant>)
- &FromChar;
- }
-
- if (typeOfT == typeof(sbyte))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in sbyte, godot_variant>)
- &FromInt8;
- }
-
- if (typeOfT == typeof(short))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in short, godot_variant>)
- &FromInt16;
- }
-
- if (typeOfT == typeof(int))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in int, godot_variant>)
- &FromInt32;
- }
-
- if (typeOfT == typeof(long))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in long, godot_variant>)
- &FromInt64;
- }
-
- if (typeOfT == typeof(byte))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in byte, godot_variant>)
- &FromUInt8;
- }
-
- if (typeOfT == typeof(ushort))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in ushort, godot_variant>)
- &FromUInt16;
- }
-
- if (typeOfT == typeof(uint))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in uint, godot_variant>)
- &FromUInt32;
- }
-
- if (typeOfT == typeof(ulong))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in ulong, godot_variant>)
- &FromUInt64;
- }
-
- if (typeOfT == typeof(float))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in float, godot_variant>)
- &FromFloat;
- }
-
- if (typeOfT == typeof(double))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in double, godot_variant>)
- &FromDouble;
- }
-
- if (typeOfT == typeof(Vector2))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Vector2, godot_variant>)
- &FromVector2;
- }
-
- if (typeOfT == typeof(Vector2i))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Vector2i, godot_variant>)
- &FromVector2I;
- }
-
- if (typeOfT == typeof(Rect2))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Rect2, godot_variant>)
- &FromRect2;
- }
-
- if (typeOfT == typeof(Rect2i))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Rect2i, godot_variant>)
- &FromRect2I;
- }
-
- if (typeOfT == typeof(Transform2D))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Transform2D, godot_variant>)
- &FromTransform2D;
- }
-
- if (typeOfT == typeof(Vector3))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Vector3, godot_variant>)
- &FromVector3;
- }
-
- if (typeOfT == typeof(Vector3i))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Vector3i, godot_variant>)
- &FromVector3I;
- }
-
- if (typeOfT == typeof(Basis))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Basis, godot_variant>)
- &FromBasis;
- }
-
- if (typeOfT == typeof(Quaternion))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Quaternion, godot_variant>)
- &FromQuaternion;
- }
-
- if (typeOfT == typeof(Transform3D))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Transform3D, godot_variant>)
- &FromTransform3D;
- }
-
- if (typeOfT == typeof(Vector4))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Vector4, godot_variant>)
- &FromVector4;
- }
-
- if (typeOfT == typeof(Vector4i))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Vector4i, godot_variant>)
- &FromVector4I;
- }
-
- if (typeOfT == typeof(AABB))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in AABB, godot_variant>)
- &FromAabb;
- }
-
- if (typeOfT == typeof(Color))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Color, godot_variant>)
- &FromColor;
- }
-
- if (typeOfT == typeof(Plane))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Plane, godot_variant>)
- &FromPlane;
- }
-
- if (typeOfT == typeof(Callable))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Callable, godot_variant>)
- &FromCallable;
- }
-
- if (typeOfT == typeof(SignalInfo))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in SignalInfo, godot_variant>)
- &FromSignalInfo;
- }
-
- if (typeOfT.IsEnum)
- {
- var enumUnderlyingType = typeOfT.GetEnumUnderlyingType();
-
- switch (Type.GetTypeCode(enumUnderlyingType))
- {
- case TypeCode.SByte:
- {
- return (delegate*<in T, godot_variant>)(delegate*<in sbyte, godot_variant>)
- &FromInt8;
- }
- case TypeCode.Int16:
- {
- return (delegate*<in T, godot_variant>)(delegate*<in short, godot_variant>)
- &FromInt16;
- }
- case TypeCode.Int32:
- {
- return (delegate*<in T, godot_variant>)(delegate*<in int, godot_variant>)
- &FromInt32;
- }
- case TypeCode.Int64:
- {
- return (delegate*<in T, godot_variant>)(delegate*<in long, godot_variant>)
- &FromInt64;
- }
- case TypeCode.Byte:
- {
- return (delegate*<in T, godot_variant>)(delegate*<in byte, godot_variant>)
- &FromUInt8;
- }
- case TypeCode.UInt16:
- {
- return (delegate*<in T, godot_variant>)(delegate*<in ushort, godot_variant>)
- &FromUInt16;
- }
- case TypeCode.UInt32:
- {
- return (delegate*<in T, godot_variant>)(delegate*<in uint, godot_variant>)
- &FromUInt32;
- }
- case TypeCode.UInt64:
- {
- return (delegate*<in T, godot_variant>)(delegate*<in ulong, godot_variant>)
- &FromUInt64;
- }
- default:
- return null;
- }
- }
-
- if (typeOfT == typeof(string))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in string, godot_variant>)
- &FromString;
- }
-
- if (typeOfT == typeof(byte[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in byte[], godot_variant>)
- &FromByteArray;
- }
-
- if (typeOfT == typeof(int[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in int[], godot_variant>)
- &FromInt32Array;
- }
-
- if (typeOfT == typeof(long[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in long[], godot_variant>)
- &FromInt64Array;
- }
-
- if (typeOfT == typeof(float[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in float[], godot_variant>)
- &FromFloatArray;
- }
-
- if (typeOfT == typeof(double[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in double[], godot_variant>)
- &FromDoubleArray;
- }
-
- if (typeOfT == typeof(string[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in string[], godot_variant>)
- &FromStringArray;
- }
-
- if (typeOfT == typeof(Vector2[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Vector2[], godot_variant>)
- &FromVector2Array;
- }
-
- if (typeOfT == typeof(Vector3[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Vector3[], godot_variant>)
- &FromVector3Array;
- }
-
- if (typeOfT == typeof(Color[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Color[], godot_variant>)
- &FromColorArray;
- }
-
- if (typeOfT == typeof(StringName[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in StringName[], godot_variant>)
- &FromStringNameArray;
- }
-
- if (typeOfT == typeof(NodePath[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in NodePath[], godot_variant>)
- &FromNodePathArray;
- }
-
- if (typeOfT == typeof(RID[]))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in RID[], godot_variant>)
- &FromRidArray;
- }
-
- if (typeof(Godot.Object).IsAssignableFrom(typeOfT))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Godot.Object, godot_variant>)
- &FromGodotObject;
- }
-
- if (typeOfT == typeof(StringName))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in StringName, godot_variant>)
- &FromStringName;
- }
-
- if (typeOfT == typeof(NodePath))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in NodePath, godot_variant>)
- &FromNodePath;
- }
-
- if (typeOfT == typeof(RID))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in RID, godot_variant>)
- &FromRid;
- }
-
- if (typeOfT == typeof(Godot.Collections.Dictionary))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Godot.Collections.Dictionary, godot_variant>)
- &FromGodotDictionary;
- }
-
- if (typeOfT == typeof(Godot.Collections.Array))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Godot.Collections.Array, godot_variant>)
- &FromGodotArray;
- }
-
- if (typeOfT == typeof(Variant))
- {
- return (delegate*<in T, godot_variant>)(delegate*<in Variant, godot_variant>)
- &FromVariant;
- }
-
- // TODO:
- // IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode.
- // We could make the Godot collections implement an interface and use IsAssignableFrom instead.
- // Or we could just skip the check and always look for a conversion callback for the type.
- if (typeOfT.IsGenericType)
- {
- var genericTypeDef = typeOfT.GetGenericTypeDefinition();
-
- if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) ||
- genericTypeDef == typeof(Godot.Collections.Array<>))
- {
- RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle);
-
- if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion))
- {
- return (delegate*<in T, godot_variant>)genericConversion.ToVariant;
- }
- }
- }
-
- return null;
- }
-
- [SuppressMessage("ReSharper", "RedundantNameQualifier")]
- internal static delegate*<in godot_variant, T> GetToManagedCallback<T>()
- {
- static bool ToBool(in godot_variant variant) =>
- VariantUtils.ConvertToBool(variant);
-
- static char ToChar(in godot_variant variant) =>
- VariantUtils.ConvertToChar(variant);
-
- static sbyte ToInt8(in godot_variant variant) =>
- VariantUtils.ConvertToInt8(variant);
-
- static short ToInt16(in godot_variant variant) =>
- VariantUtils.ConvertToInt16(variant);
-
- static int ToInt32(in godot_variant variant) =>
- VariantUtils.ConvertToInt32(variant);
-
- static long ToInt64(in godot_variant variant) =>
- VariantUtils.ConvertToInt64(variant);
-
- static byte ToUInt8(in godot_variant variant) =>
- VariantUtils.ConvertToUInt8(variant);
-
- static ushort ToUInt16(in godot_variant variant) =>
- VariantUtils.ConvertToUInt16(variant);
-
- static uint ToUInt32(in godot_variant variant) =>
- VariantUtils.ConvertToUInt32(variant);
-
- static ulong ToUInt64(in godot_variant variant) =>
- VariantUtils.ConvertToUInt64(variant);
-
- static float ToFloat(in godot_variant variant) =>
- VariantUtils.ConvertToFloat32(variant);
-
- static double ToDouble(in godot_variant variant) =>
- VariantUtils.ConvertToFloat64(variant);
-
- static Vector2 ToVector2(in godot_variant variant) =>
- VariantUtils.ConvertToVector2(variant);
-
- static Vector2i ToVector2I(in godot_variant variant) =>
- VariantUtils.ConvertToVector2i(variant);
-
- static Rect2 ToRect2(in godot_variant variant) =>
- VariantUtils.ConvertToRect2(variant);
-
- static Rect2i ToRect2I(in godot_variant variant) =>
- VariantUtils.ConvertToRect2i(variant);
-
- static Transform2D ToTransform2D(in godot_variant variant) =>
- VariantUtils.ConvertToTransform2D(variant);
-
- static Vector3 ToVector3(in godot_variant variant) =>
- VariantUtils.ConvertToVector3(variant);
-
- static Vector3i ToVector3I(in godot_variant variant) =>
- VariantUtils.ConvertToVector3i(variant);
-
- static Basis ToBasis(in godot_variant variant) =>
- VariantUtils.ConvertToBasis(variant);
-
- static Quaternion ToQuaternion(in godot_variant variant) =>
- VariantUtils.ConvertToQuaternion(variant);
-
- static Transform3D ToTransform3D(in godot_variant variant) =>
- VariantUtils.ConvertToTransform3D(variant);
-
- static Vector4 ToVector4(in godot_variant variant) =>
- VariantUtils.ConvertToVector4(variant);
-
- static Vector4i ToVector4I(in godot_variant variant) =>
- VariantUtils.ConvertToVector4i(variant);
-
- static AABB ToAabb(in godot_variant variant) =>
- VariantUtils.ConvertToAABB(variant);
-
- static Color ToColor(in godot_variant variant) =>
- VariantUtils.ConvertToColor(variant);
-
- static Plane ToPlane(in godot_variant variant) =>
- VariantUtils.ConvertToPlane(variant);
-
- static Callable ToCallable(in godot_variant variant) =>
- VariantUtils.ConvertToCallableManaged(variant);
-
- static SignalInfo ToSignalInfo(in godot_variant variant) =>
- VariantUtils.ConvertToSignalInfo(variant);
-
- static string ToString(in godot_variant variant) =>
- VariantUtils.ConvertToStringObject(variant);
-
- static byte[] ToByteArray(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedByteArrayToSystemArray(variant);
-
- static int[] ToInt32Array(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(variant);
-
- static long[] ToInt64Array(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(variant);
-
- static float[] ToFloatArray(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(variant);
-
- static double[] ToDoubleArray(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(variant);
-
- static string[] ToStringArray(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedStringArrayToSystemArray(variant);
-
- static Vector2[] ToVector2Array(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(variant);
-
- static Vector3[] ToVector3Array(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(variant);
-
- static Color[] ToColorArray(in godot_variant variant) =>
- VariantUtils.ConvertAsPackedColorArrayToSystemArray(variant);
-
- static StringName[] ToStringNameArray(in godot_variant variant) =>
- VariantUtils.ConvertToSystemArrayOfStringName(variant);
-
- static NodePath[] ToNodePathArray(in godot_variant variant) =>
- VariantUtils.ConvertToSystemArrayOfNodePath(variant);
-
- static RID[] ToRidArray(in godot_variant variant) =>
- VariantUtils.ConvertToSystemArrayOfRID(variant);
-
- static Godot.Object ToGodotObject(in godot_variant variant) =>
- VariantUtils.ConvertToGodotObject(variant);
-
- static StringName ToStringName(in godot_variant variant) =>
- VariantUtils.ConvertToStringNameObject(variant);
-
- static NodePath ToNodePath(in godot_variant variant) =>
- VariantUtils.ConvertToNodePathObject(variant);
-
- static RID ToRid(in godot_variant variant) =>
- VariantUtils.ConvertToRID(variant);
-
- static Collections.Dictionary ToGodotDictionary(in godot_variant variant) =>
- VariantUtils.ConvertToDictionaryObject(variant);
-
- static Collections.Array ToGodotArray(in godot_variant variant) =>
- VariantUtils.ConvertToArrayObject(variant);
-
- static Variant ToVariant(in godot_variant variant) =>
- Variant.CreateCopyingBorrowed(variant);
-
- var typeOfT = typeof(T);
-
- // ReSharper disable RedundantCast
- // Rider is being stupid here. These casts are definitely needed. We get build errors without them.
-
- if (typeOfT == typeof(bool))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, bool>)
- &ToBool;
- }
-
- if (typeOfT == typeof(char))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, char>)
- &ToChar;
- }
-
- if (typeOfT == typeof(sbyte))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, sbyte>)
- &ToInt8;
- }
-
- if (typeOfT == typeof(short))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, short>)
- &ToInt16;
- }
-
- if (typeOfT == typeof(int))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int>)
- &ToInt32;
- }
-
- if (typeOfT == typeof(long))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long>)
- &ToInt64;
- }
-
- if (typeOfT == typeof(byte))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte>)
- &ToUInt8;
- }
-
- if (typeOfT == typeof(ushort))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ushort>)
- &ToUInt16;
- }
-
- if (typeOfT == typeof(uint))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, uint>)
- &ToUInt32;
- }
-
- if (typeOfT == typeof(ulong))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ulong>)
- &ToUInt64;
- }
-
- if (typeOfT == typeof(float))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, float>)
- &ToFloat;
- }
-
- if (typeOfT == typeof(double))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, double>)
- &ToDouble;
- }
-
- if (typeOfT == typeof(Vector2))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2>)
- &ToVector2;
- }
-
- if (typeOfT == typeof(Vector2i))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2i>)
- &ToVector2I;
- }
-
- if (typeOfT == typeof(Rect2))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Rect2>)
- &ToRect2;
- }
-
- if (typeOfT == typeof(Rect2i))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Rect2i>)
- &ToRect2I;
- }
-
- if (typeOfT == typeof(Transform2D))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Transform2D>)
- &ToTransform2D;
- }
-
- if (typeOfT == typeof(Vector3))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3>)
- &ToVector3;
- }
-
- if (typeOfT == typeof(Vector3i))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3i>)
- &ToVector3I;
- }
-
- if (typeOfT == typeof(Basis))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Basis>)
- &ToBasis;
- }
-
- if (typeOfT == typeof(Quaternion))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Quaternion>)
- &ToQuaternion;
- }
-
- if (typeOfT == typeof(Transform3D))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Transform3D>)
- &ToTransform3D;
- }
-
- if (typeOfT == typeof(Vector4))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector4>)
- &ToVector4;
- }
-
- if (typeOfT == typeof(Vector4i))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector4i>)
- &ToVector4I;
- }
-
- if (typeOfT == typeof(AABB))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, AABB>)
- &ToAabb;
- }
-
- if (typeOfT == typeof(Color))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Color>)
- &ToColor;
- }
-
- if (typeOfT == typeof(Plane))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Plane>)
- &ToPlane;
- }
-
- if (typeOfT == typeof(Callable))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Callable>)
- &ToCallable;
- }
-
- if (typeOfT == typeof(SignalInfo))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, SignalInfo>)
- &ToSignalInfo;
- }
-
- if (typeOfT.IsEnum)
- {
- var enumUnderlyingType = typeOfT.GetEnumUnderlyingType();
-
- switch (Type.GetTypeCode(enumUnderlyingType))
- {
- case TypeCode.SByte:
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, sbyte>)
- &ToInt8;
- }
- case TypeCode.Int16:
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, short>)
- &ToInt16;
- }
- case TypeCode.Int32:
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int>)
- &ToInt32;
- }
- case TypeCode.Int64:
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long>)
- &ToInt64;
- }
- case TypeCode.Byte:
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte>)
- &ToUInt8;
- }
- case TypeCode.UInt16:
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ushort>)
- &ToUInt16;
- }
- case TypeCode.UInt32:
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, uint>)
- &ToUInt32;
- }
- case TypeCode.UInt64:
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ulong>)
- &ToUInt64;
- }
- default:
- return null;
- }
- }
-
- if (typeOfT == typeof(string))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, string>)
- &ToString;
- }
-
- if (typeOfT == typeof(byte[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte[]>)
- &ToByteArray;
- }
-
- if (typeOfT == typeof(int[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int[]>)
- &ToInt32Array;
- }
-
- if (typeOfT == typeof(long[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long[]>)
- &ToInt64Array;
- }
-
- if (typeOfT == typeof(float[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, float[]>)
- &ToFloatArray;
- }
-
- if (typeOfT == typeof(double[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, double[]>)
- &ToDoubleArray;
- }
-
- if (typeOfT == typeof(string[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, string[]>)
- &ToStringArray;
- }
-
- if (typeOfT == typeof(Vector2[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2[]>)
- &ToVector2Array;
- }
-
- if (typeOfT == typeof(Vector3[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3[]>)
- &ToVector3Array;
- }
-
- if (typeOfT == typeof(Color[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Color[]>)
- &ToColorArray;
- }
-
- if (typeOfT == typeof(StringName[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, StringName[]>)
- &ToStringNameArray;
- }
-
- if (typeOfT == typeof(NodePath[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, NodePath[]>)
- &ToNodePathArray;
- }
-
- if (typeOfT == typeof(RID[]))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, RID[]>)
- &ToRidArray;
- }
-
- if (typeof(Godot.Object).IsAssignableFrom(typeOfT))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Object>)
- &ToGodotObject;
- }
-
- if (typeOfT == typeof(StringName))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, StringName>)
- &ToStringName;
- }
-
- if (typeOfT == typeof(NodePath))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, NodePath>)
- &ToNodePath;
- }
-
- if (typeOfT == typeof(RID))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, RID>)
- &ToRid;
- }
-
- if (typeOfT == typeof(Godot.Collections.Dictionary))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Collections.Dictionary>)
- &ToGodotDictionary;
- }
-
- if (typeOfT == typeof(Godot.Collections.Array))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Collections.Array>)
- &ToGodotArray;
- }
-
- if (typeOfT == typeof(Variant))
- {
- return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Variant>)
- &ToVariant;
- }
-
- // TODO:
- // IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode.
- // We could make the Godot collections implement an interface and use IsAssignableFrom instead.
- // Or we could just skip the check and always look for a conversion callback for the type.
- if (typeOfT.IsGenericType)
- {
- var genericTypeDef = typeOfT.GetGenericTypeDefinition();
-
- if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) ||
- genericTypeDef == typeof(Godot.Collections.Array<>))
- {
- RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle);
-
- if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion))
- {
- return (delegate*<in godot_variant, T>)genericConversion.FromVariant;
- }
- }
- }
-
- // ReSharper restore RedundantCast
-
- return null;
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs
deleted file mode 100644
index 46f31bbf4e..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-
-namespace Godot.NativeInterop
-{
- internal readonly ref struct VariantSpanDisposer
- {
- private readonly Span<godot_variant.movable> _variantSpan;
-
- // IMPORTANT: The span element must be default initialized.
- // Make sure call Clear() on the span if it was created with stackalloc.
- public VariantSpanDisposer(Span<godot_variant.movable> variantSpan)
- {
- _variantSpan = variantSpan;
- }
-
- public void Dispose()
- {
- for (int i = 0; i < _variantSpan.Length; i++)
- _variantSpan[i].DangerousSelfRef.Dispose();
- }
- }
-
- internal static class VariantSpanExtensions
- {
- // Used to make sure we always initialize the span values to the default,
- // as we need that in order to safely dispose all elements after.
- public static Span<godot_variant.movable> Cleared(this Span<godot_variant.movable> span)
- {
- span.Clear();
- return span;
- }
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
index 57f9ec7d95..e6bcd9393d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -8,10 +8,10 @@ using Godot.Collections;
namespace Godot.NativeInterop
{
- public static class VariantUtils
+ public static partial class VariantUtils
{
- public static godot_variant CreateFromRID(RID from)
- => new() { Type = Variant.Type.Rid, RID = from };
+ public static godot_variant CreateFromRid(Rid from)
+ => new() { Type = Variant.Type.Rid, Rid = from };
public static godot_variant CreateFromBool(bool from)
=> new() { Type = Variant.Type.Bool, Bool = from.ToGodotBool() };
@@ -28,26 +28,26 @@ namespace Godot.NativeInterop
public static godot_variant CreateFromVector2(Vector2 from)
=> new() { Type = Variant.Type.Vector2, Vector2 = from };
- public static godot_variant CreateFromVector2i(Vector2i from)
- => new() { Type = Variant.Type.Vector2i, Vector2i = from };
+ public static godot_variant CreateFromVector2I(Vector2I from)
+ => new() { Type = Variant.Type.Vector2I, Vector2I = from };
public static godot_variant CreateFromVector3(Vector3 from)
=> new() { Type = Variant.Type.Vector3, Vector3 = from };
- public static godot_variant CreateFromVector3i(Vector3i from)
- => new() { Type = Variant.Type.Vector3i, Vector3i = from };
+ public static godot_variant CreateFromVector3I(Vector3I from)
+ => new() { Type = Variant.Type.Vector3I, Vector3I = from };
public static godot_variant CreateFromVector4(Vector4 from)
=> new() { Type = Variant.Type.Vector4, Vector4 = from };
- public static godot_variant CreateFromVector4i(Vector4i from)
- => new() { Type = Variant.Type.Vector4i, Vector4i = from };
+ public static godot_variant CreateFromVector4I(Vector4I from)
+ => new() { Type = Variant.Type.Vector4I, Vector4I = from };
public static godot_variant CreateFromRect2(Rect2 from)
=> new() { Type = Variant.Type.Rect2, Rect2 = from };
- public static godot_variant CreateFromRect2i(Rect2i from)
- => new() { Type = Variant.Type.Rect2i, Rect2i = from };
+ public static godot_variant CreateFromRect2I(Rect2I from)
+ => new() { Type = Variant.Type.Rect2I, Rect2I = from };
public static godot_variant CreateFromQuaternion(Quaternion from)
=> new() { Type = Variant.Type.Quaternion, Quaternion = from };
@@ -82,7 +82,7 @@ namespace Godot.NativeInterop
return ret;
}
- public static godot_variant CreateFromAABB(AABB from)
+ public static godot_variant CreateFromAabb(Aabb from)
{
NativeFuncs.godotsharp_variant_new_aabb(out godot_variant ret, from);
return ret;
@@ -102,7 +102,7 @@ namespace Godot.NativeInterop
=> new() { Type = Variant.Type.Signal, Signal = from };
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static godot_variant CreateFromSignalInfo(SignalInfo from)
+ public static godot_variant CreateFromSignal(Signal from)
=> CreateFromSignalTakingOwnershipOfDisposableValue(
Marshaling.ConvertSignalToNative(from));
@@ -170,39 +170,66 @@ namespace Godot.NativeInterop
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedByteArray(Span<byte> from)
- => CreateFromPackedByteArray(Marshaling.ConvertSystemArrayToNativePackedByteArray(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedByteArray(from);
+ return CreateFromPackedByteArray(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedInt32Array(Span<int> from)
- => CreateFromPackedInt32Array(Marshaling.ConvertSystemArrayToNativePackedInt32Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedInt32Array(from);
+ return CreateFromPackedInt32Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedInt64Array(Span<long> from)
- => CreateFromPackedInt64Array(Marshaling.ConvertSystemArrayToNativePackedInt64Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedInt64Array(from);
+ return CreateFromPackedInt64Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedFloat32Array(Span<float> from)
- => CreateFromPackedFloat32Array(Marshaling.ConvertSystemArrayToNativePackedFloat32Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedFloat32Array(from);
+ return CreateFromPackedFloat32Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedFloat64Array(Span<double> from)
- => CreateFromPackedFloat64Array(Marshaling.ConvertSystemArrayToNativePackedFloat64Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedFloat64Array(from);
+ return CreateFromPackedFloat64Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedStringArray(Span<string> from)
- => CreateFromPackedStringArray(Marshaling.ConvertSystemArrayToNativePackedStringArray(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedStringArray(from);
+ return CreateFromPackedStringArray(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedVector2Array(Span<Vector2> from)
- => CreateFromPackedVector2Array(Marshaling.ConvertSystemArrayToNativePackedVector2Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedVector2Array(from);
+ return CreateFromPackedVector2Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedVector3Array(Span<Vector3> from)
- => CreateFromPackedVector3Array(Marshaling.ConvertSystemArrayToNativePackedVector3Array(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedVector3Array(from);
+ return CreateFromPackedVector3Array(nativePackedArray);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_variant CreateFromPackedColorArray(Span<Color> from)
- => CreateFromPackedColorArray(Marshaling.ConvertSystemArrayToNativePackedColorArray(from));
+ {
+ using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedColorArray(from);
+ return CreateFromPackedColorArray(nativePackedArray);
+ }
public static godot_variant CreateFromSystemArrayOfStringName(Span<StringName> from)
=> CreateFromArray(new Collections.Array(from));
@@ -210,11 +237,11 @@ namespace Godot.NativeInterop
public static godot_variant CreateFromSystemArrayOfNodePath(Span<NodePath> from)
=> CreateFromArray(new Collections.Array(from));
- public static godot_variant CreateFromSystemArrayOfRID(Span<RID> from)
+ public static godot_variant CreateFromSystemArrayOfRid(Span<Rid> from)
=> CreateFromArray(new Collections.Array(from));
// ReSharper disable once RedundantNameQualifier
- public static godot_variant CreateFromSystemArrayOfGodotObject(Godot.Object[]? from)
+ public static godot_variant CreateFromSystemArrayOfGodotObject(GodotObject[]? from)
{
if (from == null)
return default; // Nil
@@ -233,7 +260,7 @@ namespace Godot.NativeInterop
=> from != null ? CreateFromArray((godot_array)from.NativeValue) : default;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static godot_variant CreateFromArray<T>(Array<T>? from)
+ public static godot_variant CreateFromArray<[MustBeVariant] T>(Array<T>? from)
=> from != null ? CreateFromArray((godot_array)((Collections.Array)from).NativeValue) : default;
public static godot_variant CreateFromDictionary(godot_dictionary from)
@@ -247,7 +274,7 @@ namespace Godot.NativeInterop
=> from != null ? CreateFromDictionary((godot_dictionary)from.NativeValue) : default;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static godot_variant CreateFromDictionary<TKey, TValue>(Dictionary<TKey, TValue>? from)
+ public static godot_variant CreateFromDictionary<[MustBeVariant] TKey, [MustBeVariant] TValue>(Dictionary<TKey, TValue>? from)
=> from != null ? CreateFromDictionary((godot_dictionary)((Dictionary)from).NativeValue) : default;
public static godot_variant CreateFromStringName(godot_string_name from)
@@ -280,8 +307,8 @@ namespace Godot.NativeInterop
[MethodImpl(MethodImplOptions.AggressiveInlining)]
// ReSharper disable once RedundantNameQualifier
- public static godot_variant CreateFromGodotObject(Godot.Object? from)
- => from != null ? CreateFromGodotObjectPtr(Object.GetPtr(from)) : default;
+ public static godot_variant CreateFromGodotObject(GodotObject? from)
+ => from != null ? CreateFromGodotObjectPtr(GodotObject.GetPtr(from)) : default;
// We avoid the internal call if the stored type is the same we want.
@@ -348,9 +375,9 @@ namespace Godot.NativeInterop
p_var.Vector2 :
NativeFuncs.godotsharp_variant_as_vector2(p_var);
- public static Vector2i ConvertToVector2i(in godot_variant p_var)
- => p_var.Type == Variant.Type.Vector2i ?
- p_var.Vector2i :
+ public static Vector2I ConvertToVector2I(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector2I ?
+ p_var.Vector2I :
NativeFuncs.godotsharp_variant_as_vector2i(p_var);
public static Rect2 ConvertToRect2(in godot_variant p_var)
@@ -358,13 +385,13 @@ namespace Godot.NativeInterop
p_var.Rect2 :
NativeFuncs.godotsharp_variant_as_rect2(p_var);
- public static Rect2i ConvertToRect2i(in godot_variant p_var)
- => p_var.Type == Variant.Type.Rect2i ?
- p_var.Rect2i :
+ public static Rect2I ConvertToRect2I(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Rect2I ?
+ p_var.Rect2I :
NativeFuncs.godotsharp_variant_as_rect2i(p_var);
public static unsafe Transform2D ConvertToTransform2D(in godot_variant p_var)
- => p_var.Type == Variant.Type.Transform2d ?
+ => p_var.Type == Variant.Type.Transform2D ?
*p_var.Transform2D :
NativeFuncs.godotsharp_variant_as_transform2d(p_var);
@@ -373,9 +400,9 @@ namespace Godot.NativeInterop
p_var.Vector3 :
NativeFuncs.godotsharp_variant_as_vector3(p_var);
- public static Vector3i ConvertToVector3i(in godot_variant p_var)
- => p_var.Type == Variant.Type.Vector3i ?
- p_var.Vector3i :
+ public static Vector3I ConvertToVector3I(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector3I ?
+ p_var.Vector3I :
NativeFuncs.godotsharp_variant_as_vector3i(p_var);
public static unsafe Vector4 ConvertToVector4(in godot_variant p_var)
@@ -383,9 +410,9 @@ namespace Godot.NativeInterop
p_var.Vector4 :
NativeFuncs.godotsharp_variant_as_vector4(p_var);
- public static unsafe Vector4i ConvertToVector4i(in godot_variant p_var)
- => p_var.Type == Variant.Type.Vector4i ?
- p_var.Vector4i :
+ public static unsafe Vector4I ConvertToVector4I(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector4I ?
+ p_var.Vector4I :
NativeFuncs.godotsharp_variant_as_vector4i(p_var);
public static unsafe Basis ConvertToBasis(in godot_variant p_var)
@@ -399,7 +426,7 @@ namespace Godot.NativeInterop
NativeFuncs.godotsharp_variant_as_quaternion(p_var);
public static unsafe Transform3D ConvertToTransform3D(in godot_variant p_var)
- => p_var.Type == Variant.Type.Transform3d ?
+ => p_var.Type == Variant.Type.Transform3D ?
*p_var.Transform3D :
NativeFuncs.godotsharp_variant_as_transform3d(p_var);
@@ -408,9 +435,9 @@ namespace Godot.NativeInterop
*p_var.Projection :
NativeFuncs.godotsharp_variant_as_projection(p_var);
- public static unsafe AABB ConvertToAABB(in godot_variant p_var)
+ public static unsafe Aabb ConvertToAabb(in godot_variant p_var)
=> p_var.Type == Variant.Type.Aabb ?
- *p_var.AABB :
+ *p_var.Aabb :
NativeFuncs.godotsharp_variant_as_aabb(p_var);
public static Color ConvertToColor(in godot_variant p_var)
@@ -423,9 +450,9 @@ namespace Godot.NativeInterop
p_var.Plane :
NativeFuncs.godotsharp_variant_as_plane(p_var);
- public static RID ConvertToRID(in godot_variant p_var)
+ public static Rid ConvertToRid(in godot_variant p_var)
=> p_var.Type == Variant.Type.Rid ?
- p_var.RID :
+ p_var.Rid :
NativeFuncs.godotsharp_variant_as_rid(p_var);
public static IntPtr ConvertToGodotObjectPtr(in godot_variant p_var)
@@ -433,10 +460,10 @@ namespace Godot.NativeInterop
[MethodImpl(MethodImplOptions.AggressiveInlining)]
// ReSharper disable once RedundantNameQualifier
- public static Godot.Object ConvertToGodotObject(in godot_variant p_var)
+ public static GodotObject ConvertToGodotObject(in godot_variant p_var)
=> InteropUtils.UnmanagedGetManaged(ConvertToGodotObjectPtr(p_var));
- public static string ConvertToStringObject(in godot_variant p_var)
+ public static string ConvertToString(in godot_variant p_var)
{
switch (p_var.Type)
{
@@ -455,65 +482,65 @@ namespace Godot.NativeInterop
}
}
- public static godot_string_name ConvertToStringName(in godot_variant p_var)
+ public static godot_string_name ConvertToNativeStringName(in godot_variant p_var)
=> p_var.Type == Variant.Type.StringName ?
NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) :
NativeFuncs.godotsharp_variant_as_string_name(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static StringName ConvertToStringNameObject(in godot_variant p_var)
- => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToStringName(p_var));
+ public static StringName ConvertToStringName(in godot_variant p_var)
+ => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToNativeStringName(p_var));
- public static godot_node_path ConvertToNodePath(in godot_variant p_var)
+ public static godot_node_path ConvertToNativeNodePath(in godot_variant p_var)
=> p_var.Type == Variant.Type.NodePath ?
NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) :
NativeFuncs.godotsharp_variant_as_node_path(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static NodePath ConvertToNodePathObject(in godot_variant p_var)
- => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNodePath(p_var));
+ public static NodePath ConvertToNodePath(in godot_variant p_var)
+ => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNativeNodePath(p_var));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static godot_callable ConvertToCallable(in godot_variant p_var)
+ public static godot_callable ConvertToNativeCallable(in godot_variant p_var)
=> NativeFuncs.godotsharp_variant_as_callable(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Callable ConvertToCallableManaged(in godot_variant p_var)
- => Marshaling.ConvertCallableToManaged(ConvertToCallable(p_var));
+ public static Callable ConvertToCallable(in godot_variant p_var)
+ => Marshaling.ConvertCallableToManaged(ConvertToNativeCallable(p_var));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static godot_signal ConvertToSignal(in godot_variant p_var)
+ public static godot_signal ConvertToNativeSignal(in godot_variant p_var)
=> NativeFuncs.godotsharp_variant_as_signal(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static SignalInfo ConvertToSignalInfo(in godot_variant p_var)
- => Marshaling.ConvertSignalToManaged(ConvertToSignal(p_var));
+ public static Signal ConvertToSignal(in godot_variant p_var)
+ => Marshaling.ConvertSignalToManaged(ConvertToNativeSignal(p_var));
- public static godot_array ConvertToArray(in godot_variant p_var)
+ public static godot_array ConvertToNativeArray(in godot_variant p_var)
=> p_var.Type == Variant.Type.Array ?
NativeFuncs.godotsharp_array_new_copy(p_var.Array) :
NativeFuncs.godotsharp_variant_as_array(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Collections.Array ConvertToArrayObject(in godot_variant p_var)
- => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var));
+ public static Collections.Array ConvertToArray(in godot_variant p_var)
+ => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToNativeArray(p_var));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Array<T> ConvertToArrayObject<T>(in godot_variant p_var)
- => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var));
+ public static Array<T> ConvertToArray<[MustBeVariant] T>(in godot_variant p_var)
+ => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToNativeArray(p_var));
- public static godot_dictionary ConvertToDictionary(in godot_variant p_var)
+ public static godot_dictionary ConvertToNativeDictionary(in godot_variant p_var)
=> p_var.Type == Variant.Type.Dictionary ?
NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) :
NativeFuncs.godotsharp_variant_as_dictionary(p_var);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Dictionary ConvertToDictionaryObject(in godot_variant p_var)
- => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var));
+ public static Dictionary ConvertToDictionary(in godot_variant p_var)
+ => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToNativeDictionary(p_var));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Dictionary<TKey, TValue> ConvertToDictionaryObject<TKey, TValue>(in godot_variant p_var)
- => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var));
+ public static Dictionary<TKey, TValue> ConvertToDictionary<[MustBeVariant] TKey, [MustBeVariant] TValue>(in godot_variant p_var)
+ => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToNativeDictionary(p_var));
public static byte[] ConvertAsPackedByteArrayToSystemArray(in godot_variant p_var)
{
@@ -581,25 +608,18 @@ namespace Godot.NativeInterop
return Marshaling.ConvertNativeGodotArrayToSystemArrayOfNodePath(godotArray);
}
- public static RID[] ConvertToSystemArrayOfRID(in godot_variant p_var)
+ public static Rid[] ConvertToSystemArrayOfRid(in godot_variant p_var)
{
using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
- return Marshaling.ConvertNativeGodotArrayToSystemArrayOfRID(godotArray);
+ return Marshaling.ConvertNativeGodotArrayToSystemArrayOfRid(godotArray);
}
public static T[] ConvertToSystemArrayOfGodotObject<T>(in godot_variant p_var)
// ReSharper disable once RedundantNameQualifier
- where T : Godot.Object
+ where T : GodotObject
{
using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType<T>(godotArray);
}
-
- // ReSharper disable once RedundantNameQualifier
- public static Godot.Object[] ConvertToSystemArrayOfGodotObject(in godot_variant p_var, Type type)
- {
- using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
- return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(godotArray, type);
- }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs
new file mode 100644
index 0000000000..12b0a47079
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs
@@ -0,0 +1,414 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+
+namespace Godot.NativeInterop;
+
+#nullable enable
+
+public partial class VariantUtils
+{
+ private static Exception UnsupportedType<T>() => new InvalidOperationException(
+ $"The type is not supported for conversion to/from Variant: '{typeof(T).FullName}'");
+
+ internal static class GenericConversion<T>
+ {
+ public static unsafe godot_variant ToVariant(in T from) =>
+ ToVariantCb != null ? ToVariantCb(from) : throw UnsupportedType<T>();
+
+ public static unsafe T FromVariant(in godot_variant variant) =>
+ FromVariantCb != null ? FromVariantCb(variant) : throw UnsupportedType<T>();
+
+ // ReSharper disable once StaticMemberInGenericType
+ internal static unsafe delegate*<in T, godot_variant> ToVariantCb;
+
+ // ReSharper disable once StaticMemberInGenericType
+ internal static unsafe delegate*<in godot_variant, T> FromVariantCb;
+
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ static GenericConversion()
+ {
+ RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ public static godot_variant CreateFrom<[MustBeVariant] T>(in T from)
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static TTo UnsafeAs<TTo>(in T f) => Unsafe.As<T, TTo>(ref Unsafe.AsRef(f));
+
+ // `typeof(T) == typeof(X)` is optimized away. We cannot cache `typeof(T)` in a local variable, as it's not optimized when done like that.
+
+ if (typeof(T) == typeof(bool))
+ return CreateFromBool(UnsafeAs<bool>(from));
+
+ if (typeof(T) == typeof(char))
+ return CreateFromInt(UnsafeAs<char>(from));
+
+ if (typeof(T) == typeof(sbyte))
+ return CreateFromInt(UnsafeAs<sbyte>(from));
+
+ if (typeof(T) == typeof(short))
+ return CreateFromInt(UnsafeAs<short>(from));
+
+ if (typeof(T) == typeof(int))
+ return CreateFromInt(UnsafeAs<int>(from));
+
+ if (typeof(T) == typeof(long))
+ return CreateFromInt(UnsafeAs<long>(from));
+
+ if (typeof(T) == typeof(byte))
+ return CreateFromInt(UnsafeAs<byte>(from));
+
+ if (typeof(T) == typeof(ushort))
+ return CreateFromInt(UnsafeAs<ushort>(from));
+
+ if (typeof(T) == typeof(uint))
+ return CreateFromInt(UnsafeAs<uint>(from));
+
+ if (typeof(T) == typeof(ulong))
+ return CreateFromInt(UnsafeAs<ulong>(from));
+
+ if (typeof(T) == typeof(float))
+ return CreateFromFloat(UnsafeAs<float>(from));
+
+ if (typeof(T) == typeof(double))
+ return CreateFromFloat(UnsafeAs<double>(from));
+
+ if (typeof(T) == typeof(Vector2))
+ return CreateFromVector2(UnsafeAs<Vector2>(from));
+
+ if (typeof(T) == typeof(Vector2I))
+ return CreateFromVector2I(UnsafeAs<Vector2I>(from));
+
+ if (typeof(T) == typeof(Rect2))
+ return CreateFromRect2(UnsafeAs<Rect2>(from));
+
+ if (typeof(T) == typeof(Rect2I))
+ return CreateFromRect2I(UnsafeAs<Rect2I>(from));
+
+ if (typeof(T) == typeof(Transform2D))
+ return CreateFromTransform2D(UnsafeAs<Transform2D>(from));
+
+ if (typeof(T) == typeof(Projection))
+ return CreateFromProjection(UnsafeAs<Projection>(from));
+
+ if (typeof(T) == typeof(Vector3))
+ return CreateFromVector3(UnsafeAs<Vector3>(from));
+
+ if (typeof(T) == typeof(Vector3I))
+ return CreateFromVector3I(UnsafeAs<Vector3I>(from));
+
+ if (typeof(T) == typeof(Basis))
+ return CreateFromBasis(UnsafeAs<Basis>(from));
+
+ if (typeof(T) == typeof(Quaternion))
+ return CreateFromQuaternion(UnsafeAs<Quaternion>(from));
+
+ if (typeof(T) == typeof(Transform3D))
+ return CreateFromTransform3D(UnsafeAs<Transform3D>(from));
+
+ if (typeof(T) == typeof(Vector4))
+ return CreateFromVector4(UnsafeAs<Vector4>(from));
+
+ if (typeof(T) == typeof(Vector4I))
+ return CreateFromVector4I(UnsafeAs<Vector4I>(from));
+
+ if (typeof(T) == typeof(Aabb))
+ return CreateFromAabb(UnsafeAs<Aabb>(from));
+
+ if (typeof(T) == typeof(Color))
+ return CreateFromColor(UnsafeAs<Color>(from));
+
+ if (typeof(T) == typeof(Plane))
+ return CreateFromPlane(UnsafeAs<Plane>(from));
+
+ if (typeof(T) == typeof(Callable))
+ return CreateFromCallable(UnsafeAs<Callable>(from));
+
+ if (typeof(T) == typeof(Signal))
+ return CreateFromSignal(UnsafeAs<Signal>(from));
+
+ if (typeof(T) == typeof(string))
+ return CreateFromString(UnsafeAs<string>(from));
+
+ if (typeof(T) == typeof(byte[]))
+ return CreateFromPackedByteArray(UnsafeAs<byte[]>(from));
+
+ if (typeof(T) == typeof(int[]))
+ return CreateFromPackedInt32Array(UnsafeAs<int[]>(from));
+
+ if (typeof(T) == typeof(long[]))
+ return CreateFromPackedInt64Array(UnsafeAs<long[]>(from));
+
+ if (typeof(T) == typeof(float[]))
+ return CreateFromPackedFloat32Array(UnsafeAs<float[]>(from));
+
+ if (typeof(T) == typeof(double[]))
+ return CreateFromPackedFloat64Array(UnsafeAs<double[]>(from));
+
+ if (typeof(T) == typeof(string[]))
+ return CreateFromPackedStringArray(UnsafeAs<string[]>(from));
+
+ if (typeof(T) == typeof(Vector2[]))
+ return CreateFromPackedVector2Array(UnsafeAs<Vector2[]>(from));
+
+ if (typeof(T) == typeof(Vector3[]))
+ return CreateFromPackedVector3Array(UnsafeAs<Vector3[]>(from));
+
+ if (typeof(T) == typeof(Color[]))
+ return CreateFromPackedColorArray(UnsafeAs<Color[]>(from));
+
+ if (typeof(T) == typeof(StringName[]))
+ return CreateFromSystemArrayOfStringName(UnsafeAs<StringName[]>(from));
+
+ if (typeof(T) == typeof(NodePath[]))
+ return CreateFromSystemArrayOfNodePath(UnsafeAs<NodePath[]>(from));
+
+ if (typeof(T) == typeof(Rid[]))
+ return CreateFromSystemArrayOfRid(UnsafeAs<Rid[]>(from));
+
+ if (typeof(T) == typeof(StringName))
+ return CreateFromStringName(UnsafeAs<StringName>(from));
+
+ if (typeof(T) == typeof(NodePath))
+ return CreateFromNodePath(UnsafeAs<NodePath>(from));
+
+ if (typeof(T) == typeof(Rid))
+ return CreateFromRid(UnsafeAs<Rid>(from));
+
+ if (typeof(T) == typeof(Godot.Collections.Dictionary))
+ return CreateFromDictionary(UnsafeAs<Godot.Collections.Dictionary>(from));
+
+ if (typeof(T) == typeof(Godot.Collections.Array))
+ return CreateFromArray(UnsafeAs<Godot.Collections.Array>(from));
+
+ if (typeof(T) == typeof(Variant))
+ return NativeFuncs.godotsharp_variant_new_copy((godot_variant)UnsafeAs<Variant>(from).NativeVar);
+
+ // More complex checks here at the end, to avoid screwing the simple ones in case they're not optimized away.
+
+ // `typeof(X).IsAssignableFrom(typeof(T))` is optimized away
+
+ if (typeof(GodotObject).IsAssignableFrom(typeof(T)))
+ return CreateFromGodotObject(UnsafeAs<GodotObject>(from));
+
+ // `typeof(T).IsValueType` is optimized away
+ // `typeof(T).IsEnum` is NOT optimized away: https://github.com/dotnet/runtime/issues/67113
+ // Fortunately, `typeof(System.Enum).IsAssignableFrom(typeof(T))` does the job!
+
+ if (typeof(T).IsValueType && typeof(System.Enum).IsAssignableFrom(typeof(T)))
+ {
+ // `Type.GetTypeCode(typeof(T).GetEnumUnderlyingType())` is not optimized away.
+ // Fortunately, `Unsafe.SizeOf<T>()` works and is optimized away.
+ // We don't need to know whether it's signed or unsigned.
+
+ if (Unsafe.SizeOf<T>() == 1)
+ return CreateFromInt(UnsafeAs<sbyte>(from));
+
+ if (Unsafe.SizeOf<T>() == 2)
+ return CreateFromInt(UnsafeAs<short>(from));
+
+ if (Unsafe.SizeOf<T>() == 4)
+ return CreateFromInt(UnsafeAs<int>(from));
+
+ if (Unsafe.SizeOf<T>() == 8)
+ return CreateFromInt(UnsafeAs<long>(from));
+
+ throw UnsupportedType<T>();
+ }
+
+ return GenericConversion<T>.ToVariant(from);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ public static T ConvertTo<[MustBeVariant] T>(in godot_variant variant)
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static T UnsafeAsT<TFrom>(TFrom f) => Unsafe.As<TFrom, T>(ref Unsafe.AsRef(f));
+
+ if (typeof(T) == typeof(bool))
+ return UnsafeAsT(ConvertToBool(variant));
+
+ if (typeof(T) == typeof(char))
+ return UnsafeAsT(ConvertToChar(variant));
+
+ if (typeof(T) == typeof(sbyte))
+ return UnsafeAsT(ConvertToInt8(variant));
+
+ if (typeof(T) == typeof(short))
+ return UnsafeAsT(ConvertToInt16(variant));
+
+ if (typeof(T) == typeof(int))
+ return UnsafeAsT(ConvertToInt32(variant));
+
+ if (typeof(T) == typeof(long))
+ return UnsafeAsT(ConvertToInt64(variant));
+
+ if (typeof(T) == typeof(byte))
+ return UnsafeAsT(ConvertToUInt8(variant));
+
+ if (typeof(T) == typeof(ushort))
+ return UnsafeAsT(ConvertToUInt16(variant));
+
+ if (typeof(T) == typeof(uint))
+ return UnsafeAsT(ConvertToUInt32(variant));
+
+ if (typeof(T) == typeof(ulong))
+ return UnsafeAsT(ConvertToUInt64(variant));
+
+ if (typeof(T) == typeof(float))
+ return UnsafeAsT(ConvertToFloat32(variant));
+
+ if (typeof(T) == typeof(double))
+ return UnsafeAsT(ConvertToFloat64(variant));
+
+ if (typeof(T) == typeof(Vector2))
+ return UnsafeAsT(ConvertToVector2(variant));
+
+ if (typeof(T) == typeof(Vector2I))
+ return UnsafeAsT(ConvertToVector2I(variant));
+
+ if (typeof(T) == typeof(Rect2))
+ return UnsafeAsT(ConvertToRect2(variant));
+
+ if (typeof(T) == typeof(Rect2I))
+ return UnsafeAsT(ConvertToRect2I(variant));
+
+ if (typeof(T) == typeof(Transform2D))
+ return UnsafeAsT(ConvertToTransform2D(variant));
+
+ if (typeof(T) == typeof(Vector3))
+ return UnsafeAsT(ConvertToVector3(variant));
+
+ if (typeof(T) == typeof(Vector3I))
+ return UnsafeAsT(ConvertToVector3I(variant));
+
+ if (typeof(T) == typeof(Basis))
+ return UnsafeAsT(ConvertToBasis(variant));
+
+ if (typeof(T) == typeof(Quaternion))
+ return UnsafeAsT(ConvertToQuaternion(variant));
+
+ if (typeof(T) == typeof(Transform3D))
+ return UnsafeAsT(ConvertToTransform3D(variant));
+
+ if (typeof(T) == typeof(Projection))
+ return UnsafeAsT(ConvertToProjection(variant));
+
+ if (typeof(T) == typeof(Vector4))
+ return UnsafeAsT(ConvertToVector4(variant));
+
+ if (typeof(T) == typeof(Vector4I))
+ return UnsafeAsT(ConvertToVector4I(variant));
+
+ if (typeof(T) == typeof(Aabb))
+ return UnsafeAsT(ConvertToAabb(variant));
+
+ if (typeof(T) == typeof(Color))
+ return UnsafeAsT(ConvertToColor(variant));
+
+ if (typeof(T) == typeof(Plane))
+ return UnsafeAsT(ConvertToPlane(variant));
+
+ if (typeof(T) == typeof(Callable))
+ return UnsafeAsT(ConvertToCallable(variant));
+
+ if (typeof(T) == typeof(Signal))
+ return UnsafeAsT(ConvertToSignal(variant));
+
+ if (typeof(T) == typeof(string))
+ return UnsafeAsT(ConvertToString(variant));
+
+ if (typeof(T) == typeof(byte[]))
+ return UnsafeAsT(ConvertAsPackedByteArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(int[]))
+ return UnsafeAsT(ConvertAsPackedInt32ArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(long[]))
+ return UnsafeAsT(ConvertAsPackedInt64ArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(float[]))
+ return UnsafeAsT(ConvertAsPackedFloat32ArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(double[]))
+ return UnsafeAsT(ConvertAsPackedFloat64ArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(string[]))
+ return UnsafeAsT(ConvertAsPackedStringArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(Vector2[]))
+ return UnsafeAsT(ConvertAsPackedVector2ArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(Vector3[]))
+ return UnsafeAsT(ConvertAsPackedVector3ArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(Color[]))
+ return UnsafeAsT(ConvertAsPackedColorArrayToSystemArray(variant));
+
+ if (typeof(T) == typeof(StringName[]))
+ return UnsafeAsT(ConvertToSystemArrayOfStringName(variant));
+
+ if (typeof(T) == typeof(NodePath[]))
+ return UnsafeAsT(ConvertToSystemArrayOfNodePath(variant));
+
+ if (typeof(T) == typeof(Rid[]))
+ return UnsafeAsT(ConvertToSystemArrayOfRid(variant));
+
+ if (typeof(T) == typeof(StringName))
+ return UnsafeAsT(ConvertToStringName(variant));
+
+ if (typeof(T) == typeof(NodePath))
+ return UnsafeAsT(ConvertToNodePath(variant));
+
+ if (typeof(T) == typeof(Rid))
+ return UnsafeAsT(ConvertToRid(variant));
+
+ if (typeof(T) == typeof(Godot.Collections.Dictionary))
+ return UnsafeAsT(ConvertToDictionary(variant));
+
+ if (typeof(T) == typeof(Godot.Collections.Array))
+ return UnsafeAsT(ConvertToArray(variant));
+
+ if (typeof(T) == typeof(Variant))
+ return UnsafeAsT(Variant.CreateCopyingBorrowed(variant));
+
+ // More complex checks here at the end, to avoid screwing the simple ones in case they're not optimized away.
+
+ // `typeof(X).IsAssignableFrom(typeof(T))` is optimized away
+
+ if (typeof(GodotObject).IsAssignableFrom(typeof(T)))
+ return (T)(object)ConvertToGodotObject(variant);
+
+ // `typeof(T).IsValueType` is optimized away
+ // `typeof(T).IsEnum` is NOT optimized away: https://github.com/dotnet/runtime/issues/67113
+ // Fortunately, `typeof(System.Enum).IsAssignableFrom(typeof(T))` does the job!
+
+ if (typeof(T).IsValueType && typeof(System.Enum).IsAssignableFrom(typeof(T)))
+ {
+ // `Type.GetTypeCode(typeof(T).GetEnumUnderlyingType())` is not optimized away.
+ // Fortunately, `Unsafe.SizeOf<T>()` works and is optimized away.
+ // We don't need to know whether it's signed or unsigned.
+
+ if (Unsafe.SizeOf<T>() == 1)
+ return UnsafeAsT(ConvertToInt8(variant));
+
+ if (Unsafe.SizeOf<T>() == 2)
+ return UnsafeAsT(ConvertToInt16(variant));
+
+ if (Unsafe.SizeOf<T>() == 4)
+ return UnsafeAsT(ConvertToInt32(variant));
+
+ if (Unsafe.SizeOf<T>() == 8)
+ return UnsafeAsT(ConvertToInt64(variant));
+
+ throw UnsupportedType<T>();
+ }
+
+ return GenericConversion<T>.FromVariant(variant);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
index b02bd167a1..f216fb7ea3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
@@ -39,7 +39,7 @@ namespace Godot
/// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene.
/// </code>
/// </example>
- public sealed class NodePath : IDisposable
+ public sealed class NodePath : IDisposable, IEquatable<NodePath>
{
internal godot_node_path.movable NativeValue;
@@ -288,5 +288,37 @@ namespace Godot
/// </summary>
/// <returns>If the <see cref="NodePath"/> is empty.</returns>
public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;
+
+ public static bool operator ==(NodePath left, NodePath right)
+ {
+ if (left is null)
+ return right is null;
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(NodePath left, NodePath right)
+ {
+ return !(left == right);
+ }
+
+ public bool Equals(NodePath other)
+ {
+ if (other is null)
+ return false;
+ var self = (godot_node_path)NativeValue;
+ var otherNative = (godot_node_path)other.NativeValue;
+ return NativeFuncs.godotsharp_node_path_equals(self, otherNative).ToBool();
+ }
+
+ public override bool Equals(object obj)
+ {
+ return ReferenceEquals(this, obj) || (obj is NodePath other && Equals(other));
+ }
+
+ public override int GetHashCode()
+ {
+ var self = (godot_node_path)NativeValue;
+ return NativeFuncs.godotsharp_node_path_hash(self);
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index 664b2e0f34..55b7a83fc2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -13,32 +13,47 @@ namespace Godot
public struct Plane : IEquatable<Plane>
{
private Vector3 _normal;
+ private real_t _d;
/// <summary>
- /// The normal of the plane, which must be normalized.
+ /// The normal of the plane, which must be a unit vector.
/// In the scalar equation of the plane <c>ax + by + cz = d</c>, this is
/// the vector <c>(a, b, c)</c>, where <c>d</c> is the <see cref="D"/> property.
/// </summary>
- /// <value>Equivalent to <see cref="x"/>, <see cref="y"/>, and <see cref="z"/>.</value>
+ /// <value>Equivalent to <see cref="X"/>, <see cref="Y"/>, and <see cref="Z"/>.</value>
public Vector3 Normal
{
- get { return _normal; }
+ readonly get { return _normal; }
set { _normal = value; }
}
/// <summary>
+ /// The distance from the origin to the plane (in the direction of
+ /// <see cref="Normal"/>). This value is typically non-negative.
+ /// In the scalar equation of the plane <c>ax + by + cz = d</c>,
+ /// this is <c>d</c>, while the <c>(a, b, c)</c> coordinates are represented
+ /// by the <see cref="Normal"/> property.
+ /// </summary>
+ /// <value>The plane's distance from the origin.</value>
+ public real_t D
+ {
+ readonly get { return _d; }
+ set { _d = value; }
+ }
+
+ /// <summary>
/// The X component of the plane's normal vector.
/// </summary>
/// <value>Equivalent to <see cref="Normal"/>'s X value.</value>
- public real_t x
+ public real_t X
{
- get
+ readonly get
{
- return _normal.x;
+ return _normal.X;
}
set
{
- _normal.x = value;
+ _normal.X = value;
}
}
@@ -46,15 +61,15 @@ namespace Godot
/// The Y component of the plane's normal vector.
/// </summary>
/// <value>Equivalent to <see cref="Normal"/>'s Y value.</value>
- public real_t y
+ public real_t Y
{
- get
+ readonly get
{
- return _normal.y;
+ return _normal.Y;
}
set
{
- _normal.y = value;
+ _normal.Y = value;
}
}
@@ -62,53 +77,36 @@ namespace Godot
/// The Z component of the plane's normal vector.
/// </summary>
/// <value>Equivalent to <see cref="Normal"/>'s Z value.</value>
- public real_t z
+ public real_t Z
{
- get
+ readonly get
{
- return _normal.z;
+ return _normal.Z;
}
set
{
- _normal.z = value;
+ _normal.Z = value;
}
}
/// <summary>
- /// The distance from the origin to the plane (in the direction of
- /// <see cref="Normal"/>). This value is typically non-negative.
- /// In the scalar equation of the plane <c>ax + by + cz = d</c>,
- /// this is <c>d</c>, while the <c>(a, b, c)</c> coordinates are represented
- /// by the <see cref="Normal"/> property.
- /// </summary>
- /// <value>The plane's distance from the origin.</value>
- public real_t D { get; set; }
-
- /// <summary>
- /// The center of the plane, the point where the normal line intersects the plane.
+ /// Returns the shortest distance from this plane to the position <paramref name="point"/>.
/// </summary>
- /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value>
- public Vector3 Center
+ /// <param name="point">The position to use for the calculation.</param>
+ /// <returns>The shortest distance.</returns>
+ public readonly real_t DistanceTo(Vector3 point)
{
- get
- {
- return _normal * D;
- }
- set
- {
- _normal = value.Normalized();
- D = value.Length();
- }
+ return _normal.Dot(point) - _d;
}
/// <summary>
- /// Returns the shortest distance from this plane to the position <paramref name="point"/>.
+ /// Returns the center of the plane, the point on the plane closest to the origin.
+ /// The point where the normal line going through the origin intersects the plane.
/// </summary>
- /// <param name="point">The position to use for the calculation.</param>
- /// <returns>The shortest distance.</returns>
- public real_t DistanceTo(Vector3 point)
+ /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value>
+ public readonly Vector3 GetCenter()
{
- return _normal.Dot(point) - D;
+ return _normal * _d;
}
/// <summary>
@@ -118,9 +116,9 @@ namespace Godot
/// <param name="point">The point to check.</param>
/// <param name="tolerance">The tolerance threshold.</param>
/// <returns>A <see langword="bool"/> for whether or not the plane has the point.</returns>
- public bool HasPoint(Vector3 point, real_t tolerance = Mathf.Epsilon)
+ public readonly bool HasPoint(Vector3 point, real_t tolerance = Mathf.Epsilon)
{
- real_t dist = _normal.Dot(point) - D;
+ real_t dist = _normal.Dot(point) - _d;
return Mathf.Abs(dist) <= tolerance;
}
@@ -131,7 +129,7 @@ namespace Godot
/// <param name="b">One of the three planes to use in the calculation.</param>
/// <param name="c">One of the three planes to use in the calculation.</param>
/// <returns>The intersection, or <see langword="null"/> if none is found.</returns>
- public Vector3? Intersect3(Plane b, Plane c)
+ public readonly Vector3? Intersect3(Plane b, Plane c)
{
real_t denom = _normal.Cross(b._normal).Dot(c._normal);
@@ -140,9 +138,9 @@ namespace Godot
return null;
}
- Vector3 result = (b._normal.Cross(c._normal) * D) +
- (c._normal.Cross(_normal) * b.D) +
- (_normal.Cross(b._normal) * c.D);
+ Vector3 result = (b._normal.Cross(c._normal) * _d) +
+ (c._normal.Cross(_normal) * b._d) +
+ (_normal.Cross(b._normal) * c._d);
return result / denom;
}
@@ -155,7 +153,7 @@ namespace Godot
/// <param name="from">The start of the ray.</param>
/// <param name="dir">The direction of the ray, normalized.</param>
/// <returns>The intersection, or <see langword="null"/> if none is found.</returns>
- public Vector3? IntersectRay(Vector3 from, Vector3 dir)
+ public readonly Vector3? IntersectsRay(Vector3 from, Vector3 dir)
{
real_t den = _normal.Dot(dir);
@@ -164,7 +162,7 @@ namespace Godot
return null;
}
- real_t dist = (_normal.Dot(from) - D) / den;
+ real_t dist = (_normal.Dot(from) - _d) / den;
// This is a ray, before the emitting pos (from) does not exist
if (dist > Mathf.Epsilon)
@@ -183,7 +181,7 @@ namespace Godot
/// <param name="begin">The start of the line segment.</param>
/// <param name="end">The end of the line segment.</param>
/// <returns>The intersection, or <see langword="null"/> if none is found.</returns>
- public Vector3? IntersectSegment(Vector3 begin, Vector3 end)
+ public readonly Vector3? IntersectsSegment(Vector3 begin, Vector3 end)
{
Vector3 segment = begin - end;
real_t den = _normal.Dot(segment);
@@ -193,7 +191,7 @@ namespace Godot
return null;
}
- real_t dist = (_normal.Dot(begin) - D) / den;
+ real_t dist = (_normal.Dot(begin) - _d) / den;
// Only allow dist to be in the range of 0 to 1, with tolerance.
if (dist < -Mathf.Epsilon || dist > 1.0f + Mathf.Epsilon)
@@ -205,20 +203,30 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this plane is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return _normal.IsFinite() && Mathf.IsFinite(D);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if <paramref name="point"/> is located above the plane.
/// </summary>
/// <param name="point">The point to check.</param>
/// <returns>A <see langword="bool"/> for whether or not the point is above the plane.</returns>
- public bool IsPointOver(Vector3 point)
+ public readonly bool IsPointOver(Vector3 point)
{
- return _normal.Dot(point) > D;
+ return _normal.Dot(point) > _d;
}
/// <summary>
/// Returns the plane scaled to unit length.
/// </summary>
/// <returns>A normalized version of the plane.</returns>
- public Plane Normalized()
+ public readonly Plane Normalized()
{
real_t len = _normal.Length();
@@ -227,7 +235,7 @@ namespace Godot
return new Plane(0, 0, 0, 0);
}
- return new Plane(_normal / len, D / len);
+ return new Plane(_normal / len, _d / len);
}
/// <summary>
@@ -235,7 +243,7 @@ namespace Godot
/// </summary>
/// <param name="point">The point to project.</param>
/// <returns>The projected point.</returns>
- public Vector3 Project(Vector3 point)
+ public readonly Vector3 Project(Vector3 point)
{
return point - (_normal * DistanceTo(point));
}
@@ -276,31 +284,42 @@ namespace Godot
public Plane(real_t a, real_t b, real_t c, real_t d)
{
_normal = new Vector3(a, b, c);
- D = d;
+ _d = d;
+ }
+
+ /// <summary>
+ /// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector.
+ /// The plane will intersect the origin.
+ /// </summary>
+ /// <param name="normal">The normal of the plane, must be a unit vector.</param>
+ public Plane(Vector3 normal)
+ {
+ _normal = normal;
+ _d = 0;
}
/// <summary>
/// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and
/// the plane's distance to the origin <paramref name="d"/>.
/// </summary>
- /// <param name="normal">The normal of the plane, must be normalized.</param>
+ /// <param name="normal">The normal of the plane, must be a unit vector.</param>
/// <param name="d">The plane's distance from the origin. This value is typically non-negative.</param>
public Plane(Vector3 normal, real_t d)
{
_normal = normal;
- D = d;
+ _d = d;
}
/// <summary>
/// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and
/// a <paramref name="point"/> on the plane.
/// </summary>
- /// <param name="normal">The normal of the plane, must be normalized.</param>
+ /// <param name="normal">The normal of the plane, must be a unit vector.</param>
/// <param name="point">The point on the plane.</param>
public Plane(Vector3 normal, Vector3 point)
{
_normal = normal;
- D = _normal.Dot(point);
+ _d = _normal.Dot(point);
}
/// <summary>
@@ -313,7 +332,7 @@ namespace Godot
{
_normal = (v1 - v3).Cross(v1 - v2);
_normal.Normalize();
- D = _normal.Dot(v1);
+ _d = _normal.Dot(v1);
}
/// <summary>
@@ -327,7 +346,7 @@ namespace Godot
/// <returns>The negated/flipped plane.</returns>
public static Plane operator -(Plane plane)
{
- return new Plane(-plane._normal, -plane.D);
+ return new Plane(-plane._normal, -plane._d);
}
/// <summary>
@@ -363,7 +382,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The other object to compare.</param>
/// <returns>Whether or not the plane and the other object are exactly equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Plane other && Equals(other);
}
@@ -373,9 +392,9 @@ namespace Godot
/// </summary>
/// <param name="other">The other plane to compare.</param>
/// <returns>Whether or not the planes are exactly equal.</returns>
- public bool Equals(Plane other)
+ public readonly bool Equals(Plane other)
{
- return _normal == other._normal && D == other.D;
+ return _normal == other._normal && _d == other._d;
}
/// <summary>
@@ -384,36 +403,36 @@ namespace Godot
/// </summary>
/// <param name="other">The other plane to compare.</param>
/// <returns>Whether or not the planes are approximately equal.</returns>
- public bool IsEqualApprox(Plane other)
+ public readonly bool IsEqualApprox(Plane other)
{
- return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(D, other.D);
+ return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(_d, other._d);
}
/// <summary>
/// Serves as the hash function for <see cref="Plane"/>.
/// </summary>
/// <returns>A hash code for this plane.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return _normal.GetHashCode() ^ D.GetHashCode();
+ return _normal.GetHashCode() ^ _d.GetHashCode();
}
/// <summary>
/// Converts this <see cref="Plane"/> to a string.
/// </summary>
/// <returns>A string representation of this plane.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"{_normal}, {D}";
+ return $"{_normal}, {_d}";
}
/// <summary>
/// Converts this <see cref="Plane"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this plane.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"{_normal.ToString(format)}, {D.ToString(format)}";
+ return $"{_normal.ToString(format)}, {_d.ToString(format)}";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
index da895fd121..84fc73b87a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -3,6 +3,14 @@ using System.Runtime.InteropServices;
namespace Godot
{
+ /// <summary>
+ /// A 4x4 matrix used for 3D projective transformations. It can represent transformations such as
+ /// translation, rotation, scaling, shearing, and perspective division. It consists of four
+ /// <see cref="Vector4"/> columns.
+ /// For purely linear transformations (translation, rotation, and scale), it is recommended to use
+ /// <see cref="Transform3D"/>, as it is more performant and has a lower memory footprint.
+ /// Used internally as <see cref="Camera3D"/>'s projection matrix.
+ /// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Projection : IEquatable<Projection>
@@ -41,66 +49,125 @@ namespace Godot
/// <summary>
/// The projection's X column. Also accessible by using the index position <c>[0]</c>.
/// </summary>
- public Vector4 x;
+ public Vector4 X;
/// <summary>
/// The projection's Y column. Also accessible by using the index position <c>[1]</c>.
/// </summary>
- public Vector4 y;
+ public Vector4 Y;
/// <summary>
/// The projection's Z column. Also accessible by using the index position <c>[2]</c>.
/// </summary>
- public Vector4 z;
+ public Vector4 Z;
/// <summary>
/// The projection's W column. Also accessible by using the index position <c>[3]</c>.
/// </summary>
- public Vector4 w;
+ public Vector4 W;
/// <summary>
- /// Constructs a projection from 4 vectors (matrix columns).
+ /// Access whole columns in the form of <see cref="Vector4"/>.
/// </summary>
- /// <param name="x">The X column, or column index 0.</param>
- /// <param name="y">The Y column, or column index 1.</param>
- /// <param name="z">The Z column, or column index 2.</param>
- /// <param name="w">The W column, or column index 3.</param>
- public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w)
+ /// <param name="column">Which column vector.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="column"/> is not 0, 1, 2 or 3.
+ /// </exception>
+ public Vector4 this[int column]
{
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
+ readonly get
+ {
+ switch (column)
+ {
+ case 0:
+ return X;
+ case 1:
+ return Y;
+ case 2:
+ return Z;
+ case 3:
+ return W;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(column));
+ }
+ }
+ set
+ {
+ switch (column)
+ {
+ case 0:
+ X = value;
+ return;
+ case 1:
+ Y = value;
+ return;
+ case 2:
+ Z = value;
+ return;
+ case 3:
+ W = value;
+ return;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(column));
+ }
+ }
}
/// <summary>
- /// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>.
+ /// Access single values.
/// </summary>
- /// <param name="transform">The <see cref="Transform3D"/>.</param>
- public Projection(Transform3D transform)
+ /// <param name="column">Which column vector.</param>
+ /// <param name="row">Which row of the column.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="column"/> or <paramref name="row"/> are not 0, 1, 2 or 3.
+ /// </exception>
+ public real_t this[int column, int row]
{
- x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0);
- y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0);
- z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0);
- w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1);
+ readonly get
+ {
+ switch (column)
+ {
+ case 0:
+ return X[row];
+ case 1:
+ return Y[row];
+ case 2:
+ return Z[row];
+ case 3:
+ return W[row];
+ default:
+ throw new ArgumentOutOfRangeException(nameof(column));
+ }
+ }
+ set
+ {
+ switch (column)
+ {
+ case 0:
+ X[row] = value;
+ return;
+ case 1:
+ Y[row] = value;
+ return;
+ case 2:
+ Z[row] = value;
+ return;
+ case 3:
+ W[row] = value;
+ return;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(column));
+ }
+ }
}
/// <summary>
- /// Constructs a new <see cref="Transform3D"/> from the <see cref="Projection"/>.
+ /// Creates a new <see cref="Projection"/> that projects positions from a depth range of
+ /// <c>-1</c> to <c>1</c> to one that ranges from <c>0</c> to <c>1</c>, and flips the projected
+ /// positions vertically, according to <paramref name="flipY"/>.
/// </summary>
- /// <param name="proj">The <see cref="Projection"/>.</param>
- public static explicit operator Transform3D(Projection proj)
- {
- return new Transform3D(
- new Basis(
- new Vector3(proj.x.x, proj.x.y, proj.x.z),
- new Vector3(proj.y.x, proj.y.y, proj.y.z),
- new Vector3(proj.z.x, proj.z.y, proj.z.z)
- ),
- new Vector3(proj.w.x, proj.w.y, proj.w.z)
- );
- }
-
+ /// <param name="flipY">If the projection should be flipped vertically.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreateDepthCorrection(bool flipY)
{
return new Projection(
@@ -111,19 +178,44 @@ namespace Godot
);
}
- public static Projection CreateFitAabb(AABB aabb)
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> that scales a given projection to fit around
+ /// a given <see cref="Aabb"/> in projection space.
+ /// </summary>
+ /// <param name="aabb">The Aabb to fit the projection around.</param>
+ /// <returns>The created projection.</returns>
+ public static Projection CreateFitAabb(Aabb aabb)
{
Vector3 min = aabb.Position;
Vector3 max = aabb.Position + aabb.Size;
return new Projection(
- new Vector4(2 / (max.x - min.x), 0, 0, 0),
- new Vector4(0, 2 / (max.y - min.y), 0, 0),
- new Vector4(0, 0, 2 / (max.z - min.z), 0),
- new Vector4(-(max.x + min.x) / (max.x - min.x), -(max.y + min.y) / (max.y - min.y), -(max.z + min.z) / (max.z - min.z), 1)
+ new Vector4(2 / (max.X - min.X), 0, 0, 0),
+ new Vector4(0, 2 / (max.Y - min.Y), 0, 0),
+ new Vector4(0, 0, 2 / (max.Z - min.Z), 0),
+ new Vector4(-(max.X + min.X) / (max.X - min.X), -(max.Y + min.Y) / (max.Y - min.Y), -(max.Z + min.Z) / (max.Z - min.Z), 1)
);
}
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> for projecting positions onto a head-mounted display with
+ /// the given X:Y aspect ratio, distance between eyes, display width, distance to lens, oversampling factor,
+ /// and depth clipping planes.
+ /// <paramref name="eye"/> creates the projection for the left eye when set to 1,
+ /// or the right eye when set to 2.
+ /// </summary>
+ /// <param name="eye">
+ /// The eye to create the projection for.
+ /// The left eye when set to 1, the right eye when set to 2.
+ /// </param>
+ /// <param name="aspect">The aspect ratio.</param>
+ /// <param name="intraocularDist">The distance between the eyes.</param>
+ /// <param name="displayWidth">The display width.</param>
+ /// <param name="displayToLens">The distance to the lens.</param>
+ /// <param name="oversample">The oversampling factor.</param>
+ /// <param name="zNear">The near clipping distance.</param>
+ /// <param name="zFar">The far clipping distance.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreateForHmd(int eye, real_t aspect, real_t intraocularDist, real_t displayWidth, real_t displayToLens, real_t oversample, real_t zNear, real_t zFar)
{
real_t f1 = (intraocularDist * (real_t)0.5) / displayToLens;
@@ -148,6 +240,17 @@ namespace Godot
}
}
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> that projects positions in a frustum with
+ /// the given clipping planes.
+ /// </summary>
+ /// <param name="left">The left clipping distance.</param>
+ /// <param name="right">The right clipping distance.</param>
+ /// <param name="bottom">The bottom clipping distance.</param>
+ /// <param name="top">The top clipping distance.</param>
+ /// <param name="near">The near clipping distance.</param>
+ /// <param name="far">The far clipping distance.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreateFrustum(real_t left, real_t right, real_t bottom, real_t top, real_t near, real_t far)
{
if (right <= left)
@@ -179,38 +282,77 @@ namespace Godot
);
}
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> that projects positions in a frustum with
+ /// the given size, X:Y aspect ratio, offset, and clipping planes.
+ /// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal.
+ /// </summary>
+ /// <param name="size">The frustum size.</param>
+ /// <param name="aspect">The aspect ratio.</param>
+ /// <param name="offset">The offset to apply.</param>
+ /// <param name="near">The near clipping distance.</param>
+ /// <param name="far">The far clipping distance.</param>
+ /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreateFrustumAspect(real_t size, real_t aspect, Vector2 offset, real_t near, real_t far, bool flipFov)
{
if (!flipFov)
{
size *= aspect;
}
- return CreateFrustum(-size / 2 + offset.x, +size / 2 + offset.x, -size / aspect / 2 + offset.y, +size / aspect / 2 + offset.y, near, far);
+ return CreateFrustum(-size / 2 + offset.X, +size / 2 + offset.X, -size / aspect / 2 + offset.Y, +size / aspect / 2 + offset.Y, near, far);
}
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> that projects positions into the given <see cref="Rect2"/>.
+ /// </summary>
+ /// <param name="rect">The Rect2 to project positions into.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreateLightAtlasRect(Rect2 rect)
{
return new Projection(
- new Vector4(rect.Size.x, 0, 0, 0),
- new Vector4(0, rect.Size.y, 0, 0),
+ new Vector4(rect.Size.X, 0, 0, 0),
+ new Vector4(0, rect.Size.Y, 0, 0),
new Vector4(0, 0, 1, 0),
- new Vector4(rect.Position.x, rect.Position.y, 0, 1)
+ new Vector4(rect.Position.X, rect.Position.Y, 0, 1)
);
}
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> that projects positions using an orthogonal projection with
+ /// the given clipping planes.
+ /// </summary>
+ /// <param name="left">The left clipping distance.</param>
+ /// <param name="right">The right clipping distance.</param>
+ /// <param name="bottom">The bottom clipping distance.</param>
+ /// <param name="top">The top clipping distance.</param>
+ /// <param name="zNear">The near clipping distance.</param>
+ /// <param name="zFar">The far clipping distance.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreateOrthogonal(real_t left, real_t right, real_t bottom, real_t top, real_t zNear, real_t zFar)
{
Projection proj = Projection.Identity;
- proj.x.x = (real_t)2.0 / (right - left);
- proj.w.x = -((right + left) / (right - left));
- proj.y.y = (real_t)2.0 / (top - bottom);
- proj.w.y = -((top + bottom) / (top - bottom));
- proj.z.z = (real_t)(-2.0) / (zFar - zNear);
- proj.w.z = -((zFar + zNear) / (zFar - zNear));
- proj.w.w = (real_t)1.0;
+ proj.X.X = (real_t)2.0 / (right - left);
+ proj.W.X = -((right + left) / (right - left));
+ proj.Y.Y = (real_t)2.0 / (top - bottom);
+ proj.W.Y = -((top + bottom) / (top - bottom));
+ proj.Z.Z = (real_t)(-2.0) / (zFar - zNear);
+ proj.W.Z = -((zFar + zNear) / (zFar - zNear));
+ proj.W.W = (real_t)1.0;
return proj;
}
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> that projects positions using an orthogonal projection with
+ /// the given size, X:Y aspect ratio, and clipping planes.
+ /// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal.
+ /// </summary>
+ /// <param name="size">The frustum size.</param>
+ /// <param name="aspect">The aspect ratio.</param>
+ /// <param name="zNear">The near clipping distance.</param>
+ /// <param name="zFar">The far clipping distance.</param>
+ /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreateOrthogonalAspect(real_t size, real_t aspect, real_t zNear, real_t zFar, bool flipFov)
{
if (!flipFov)
@@ -220,6 +362,17 @@ namespace Godot
return CreateOrthogonal(-size / 2, +size / 2, -size / aspect / 2, +size / aspect / 2, zNear, zFar);
}
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> that projects positions using a perspective projection with
+ /// the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping planes.
+ /// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal.
+ /// </summary>
+ /// <param name="fovyDegrees">The vertical field of view (in degrees).</param>
+ /// <param name="aspect">The aspect ratio.</param>
+ /// <param name="zNear">The near clipping distance.</param>
+ /// <param name="zFar">The far clipping distance.</param>
+ /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreatePerspective(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov)
{
if (flipFov)
@@ -228,27 +381,48 @@ namespace Godot
}
real_t radians = Mathf.DegToRad(fovyDegrees / (real_t)2.0);
real_t deltaZ = zFar - zNear;
- real_t sine = Mathf.Sin(radians);
+ (real_t sin, real_t cos) = Mathf.SinCos(radians);
- if ((deltaZ == 0) || (sine == 0) || (aspect == 0))
+ if ((deltaZ == 0) || (sin == 0) || (aspect == 0))
{
return Zero;
}
- real_t cotangent = Mathf.Cos(radians) / sine;
+ real_t cotangent = cos / sin;
Projection proj = Projection.Identity;
- proj.x.x = cotangent / aspect;
- proj.y.y = cotangent;
- proj.z.z = -(zFar + zNear) / deltaZ;
- proj.z.w = -1;
- proj.w.z = -2 * zNear * zFar / deltaZ;
- proj.w.w = 0;
+ proj.X.X = cotangent / aspect;
+ proj.Y.Y = cotangent;
+ proj.Z.Z = -(zFar + zNear) / deltaZ;
+ proj.Z.W = -1;
+ proj.W.Z = -2 * zNear * zFar / deltaZ;
+ proj.W.W = 0;
return proj;
}
+ /// <summary>
+ /// Creates a new <see cref="Projection"/> that projects positions using a perspective projection with
+ /// the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping distances.
+ /// The projection is adjusted for a head-mounted display with the given distance between eyes and distance
+ /// to a point that can be focused on.
+ /// <paramref name="eye"/> creates the projection for the left eye when set to 1,
+ /// or the right eye when set to 2.
+ /// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal.
+ /// </summary>
+ /// <param name="fovyDegrees">The vertical field of view (in degrees).</param>
+ /// <param name="aspect">The aspect ratio.</param>
+ /// <param name="zNear">The near clipping distance.</param>
+ /// <param name="zFar">The far clipping distance.</param>
+ /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param>
+ /// <param name="eye">
+ /// The eye to create the projection for.
+ /// The left eye when set to 1, the right eye when set to 2.
+ /// </param>
+ /// <param name="intraocularDist">The distance between the eyes.</param>
+ /// <param name="convergenceDist">The distance to a point of convergence that can be focused on.</param>
+ /// <returns>The created projection.</returns>
public static Projection CreatePerspectiveHmd(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov, int eye, real_t intraocularDist, real_t convergenceDist)
{
if (flipFov)
@@ -282,137 +456,217 @@ namespace Godot
}
Projection proj = CreateFrustum(left, right, -ymax, ymax, zNear, zFar);
Projection cm = Projection.Identity;
- cm.w.x = modeltranslation;
+ cm.W.X = modeltranslation;
return proj * cm;
}
- public real_t Determinant()
+ /// <summary>
+ /// Returns a scalar value that is the signed factor by which areas are scaled by this matrix.
+ /// If the sign is negative, the matrix flips the orientation of the area.
+ /// The determinant can be used to calculate the invertibility of a matrix or solve linear systems
+ /// of equations involving the matrix, among other applications.
+ /// </summary>
+ /// <returns>The determinant calculated from this projection.</returns>
+ public readonly real_t Determinant()
{
- return x.w * y.z * z.y * w.x - x.z * y.w * z.y * w.x -
- x.w * y.y * z.z * w.x + x.y * y.w * z.z * w.x +
- x.z * y.y * z.w * w.x - x.y * y.z * z.w * w.x -
- x.w * y.z * z.x * w.y + x.z * y.w * z.x * w.y +
- x.w * y.x * z.z * w.y - x.x * y.w * z.z * w.y -
- x.z * y.x * z.w * w.y + x.x * y.z * z.w * w.y +
- x.w * y.y * z.x * w.z - x.y * y.w * z.x * w.z -
- x.w * y.x * z.y * w.z + x.x * y.w * z.y * w.z +
- x.y * y.x * z.w * w.z - x.x * y.y * z.w * w.z -
- x.z * y.y * z.x * w.w + x.y * y.z * z.x * w.w +
- x.z * y.x * z.y * w.w - x.x * y.z * z.y * w.w -
- x.y * y.x * z.z * w.w + x.x * y.y * z.z * w.w;
+ return X.W * Y.Z * Z.Y * W.X - X.Z * Y.W * Z.Y * W.X -
+ X.W * Y.Y * Z.Z * W.X + X.Y * Y.W * Z.Z * W.X +
+ X.Z * Y.Y * Z.W * W.X - X.Y * Y.Z * Z.W * W.X -
+ X.W * Y.Z * Z.X * W.Y + X.Z * Y.W * Z.X * W.Y +
+ X.W * Y.X * Z.Z * W.Y - X.X * Y.W * Z.Z * W.Y -
+ X.Z * Y.X * Z.W * W.Y + X.X * Y.Z * Z.W * W.Y +
+ X.W * Y.Y * Z.X * W.Z - X.Y * Y.W * Z.X * W.Z -
+ X.W * Y.X * Z.Y * W.Z + X.X * Y.W * Z.Y * W.Z +
+ X.Y * Y.X * Z.W * W.Z - X.X * Y.Y * Z.W * W.Z -
+ X.Z * Y.Y * Z.X * W.W + X.Y * Y.Z * Z.X * W.W +
+ X.Z * Y.X * Z.Y * W.W - X.X * Y.Z * Z.Y * W.W -
+ X.Y * Y.X * Z.Z * W.W + X.X * Y.Y * Z.Z * W.W;
}
- public real_t GetAspect()
+ /// <summary>
+ /// Returns the X:Y aspect ratio of this <see cref="Projection"/>'s viewport.
+ /// </summary>
+ /// <returns>The aspect ratio from this projection's viewport.</returns>
+ public readonly real_t GetAspect()
{
Vector2 vpHe = GetViewportHalfExtents();
- return vpHe.x / vpHe.y;
+ return vpHe.X / vpHe.Y;
}
- public real_t GetFov()
+ /// <summary>
+ /// Returns the horizontal field of view of the projection (in degrees).
+ /// </summary>
+ /// <returns>The horizontal field of view of this projection.</returns>
+ public readonly real_t GetFov()
{
- Plane rightPlane = new Plane(x.w - x.x, y.w - y.x, z.w - z.x, -w.w + w.x).Normalized();
- if (z.x == 0 && z.y == 0)
+ Plane rightPlane = new Plane(X.W - X.X, Y.W - Y.X, Z.W - Z.X, -W.W + W.X).Normalized();
+ if (Z.X == 0 && Z.Y == 0)
{
- return Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x))) * (real_t)2.0;
+ return Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.X))) * (real_t)2.0;
}
else
{
- Plane leftPlane = new Plane(x.w + x.x, y.w + y.x, z.w + z.x, w.w + w.x).Normalized();
- return Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(leftPlane.Normal.x))) + Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x)));
+ Plane leftPlane = new Plane(X.W + X.X, Y.W + Y.X, Z.W + Z.X, W.W + W.X).Normalized();
+ return Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(leftPlane.Normal.X))) + Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.X)));
}
}
+ /// <summary>
+ /// Returns the vertical field of view of the projection (in degrees) associated with
+ /// the given horizontal field of view (in degrees) and aspect ratio.
+ /// </summary>
+ /// <param name="fovx">The horizontal field of view (in degrees).</param>
+ /// <param name="aspect">The aspect ratio.</param>
+ /// <returns>The vertical field of view of this projection.</returns>
public static real_t GetFovy(real_t fovx, real_t aspect)
{
return Mathf.RadToDeg(Mathf.Atan(aspect * Mathf.Tan(Mathf.DegToRad(fovx) * (real_t)0.5)) * (real_t)2.0);
}
- public real_t GetLodMultiplier()
+ /// <summary>
+ /// Returns the factor by which the visible level of detail is scaled by this <see cref="Projection"/>.
+ /// </summary>
+ /// <returns>The level of detail factor for this projection.</returns>
+ public readonly real_t GetLodMultiplier()
{
if (IsOrthogonal())
{
- return GetViewportHalfExtents().x;
+ return GetViewportHalfExtents().X;
}
else
{
real_t zn = GetZNear();
- real_t width = GetViewportHalfExtents().x * (real_t)2.0;
+ real_t width = GetViewportHalfExtents().X * (real_t)2.0;
return (real_t)1.0 / (zn / width);
}
}
- public int GetPixelsPerMeter(int forPixelWidth)
+ /// <summary>
+ /// Returns the number of pixels with the given pixel width displayed per meter, after
+ /// this <see cref="Projection"/> is applied.
+ /// </summary>
+ /// <param name="forPixelWidth">The width for each pixel (in meters).</param>
+ /// <returns>The number of pixels per meter.</returns>
+ public readonly int GetPixelsPerMeter(int forPixelWidth)
{
Vector3 result = this * new Vector3(1, 0, -1);
- return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth);
+ return (int)((result.X * (real_t)0.5 + (real_t)0.5) * forPixelWidth);
}
- public Plane GetProjectionPlane(Planes plane)
+ /// <summary>
+ /// Returns the clipping plane of this <see cref="Projection"/> whose index is given
+ /// by <paramref name="plane"/>.
+ /// <paramref name="plane"/> should be equal to one of <see cref="Planes.Near"/>,
+ /// <see cref="Planes.Far"/>, <see cref="Planes.Left"/>, <see cref="Planes.Top"/>,
+ /// <see cref="Planes.Right"/>, or <see cref="Planes.Bottom"/>.
+ /// </summary>
+ /// <param name="plane">The kind of clipping plane to get from the projection.</param>
+ /// <returns>The clipping plane of this projection.</returns>
+ public readonly Plane GetProjectionPlane(Planes plane)
{
Plane newPlane = plane switch
{
- Planes.Near => new Plane(x.w + x.z, y.w + y.z, z.w + z.z, w.w + w.z),
- Planes.Far => new Plane(x.w - x.z, y.w - y.z, z.w - z.z, w.w - w.z),
- Planes.Left => new Plane(x.w + x.x, y.w + y.x, z.w + z.x, w.w + w.x),
- Planes.Top => new Plane(x.w - x.y, y.w - y.y, z.w - z.y, w.w - w.y),
- Planes.Right => new Plane(x.w - x.x, y.w - y.x, z.w - z.x, w.w - w.x),
- Planes.Bottom => new Plane(x.w + x.y, y.w + y.y, z.w + z.y, w.w + w.y),
+ Planes.Near => new Plane(X.W + X.Z, Y.W + Y.Z, Z.W + Z.Z, W.W + W.Z),
+ Planes.Far => new Plane(X.W - X.Z, Y.W - Y.Z, Z.W - Z.Z, W.W - W.Z),
+ Planes.Left => new Plane(X.W + X.X, Y.W + Y.X, Z.W + Z.X, W.W + W.X),
+ Planes.Top => new Plane(X.W - X.Y, Y.W - Y.Y, Z.W - Z.Y, W.W - W.Y),
+ Planes.Right => new Plane(X.W - X.X, Y.W - Y.X, Z.W - Z.X, W.W - W.X),
+ Planes.Bottom => new Plane(X.W + X.Y, Y.W + Y.Y, Z.W + Z.Y, W.W + W.Y),
_ => new Plane(),
};
newPlane.Normal = -newPlane.Normal;
return newPlane.Normalized();
}
- public Vector2 GetFarPlaneHalfExtents()
+ /// <summary>
+ /// Returns the dimensions of the far clipping plane of the projection, divided by two.
+ /// </summary>
+ /// <returns>The half extents for this projection's far plane.</returns>
+ public readonly Vector2 GetFarPlaneHalfExtents()
{
var res = GetProjectionPlane(Planes.Far).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top));
- return new Vector2(res.Value.x, res.Value.y);
+ return new Vector2(res.Value.X, res.Value.Y);
}
- public Vector2 GetViewportHalfExtents()
+ /// <summary>
+ /// Returns the dimensions of the viewport plane that this <see cref="Projection"/>
+ /// projects positions onto, divided by two.
+ /// </summary>
+ /// <returns>The half extents for this projection's viewport plane.</returns>
+ public readonly Vector2 GetViewportHalfExtents()
{
var res = GetProjectionPlane(Planes.Near).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top));
- return new Vector2(res.Value.x, res.Value.y);
+ return new Vector2(res.Value.X, res.Value.Y);
}
- public real_t GetZFar()
+ /// <summary>
+ /// Returns the distance for this <see cref="Projection"/> beyond which positions are clipped.
+ /// </summary>
+ /// <returns>The distance beyond which positions are clipped.</returns>
+ public readonly real_t GetZFar()
{
return GetProjectionPlane(Planes.Far).D;
}
- public real_t GetZNear()
+ /// <summary>
+ /// Returns the distance for this <see cref="Projection"/> before which positions are clipped.
+ /// </summary>
+ /// <returns>The distance before which positions are clipped.</returns>
+ public readonly real_t GetZNear()
{
return -GetProjectionPlane(Planes.Near).D;
}
- public Projection FlippedY()
+ /// <summary>
+ /// Returns a copy of this <see cref="Projection"/> with the signs of the values of the Y column flipped.
+ /// </summary>
+ /// <returns>The flipped projection.</returns>
+ public readonly Projection FlippedY()
{
Projection proj = this;
- proj.y = -proj.y;
+ proj.Y = -proj.Y;
return proj;
}
- public Projection PerspectiveZNearAdjusted(real_t newZNear)
+ /// <summary>
+ /// Returns a <see cref="Projection"/> with the near clipping distance adjusted to be
+ /// <paramref name="newZNear"/>.
+ /// Note: The original <see cref="Projection"/> must be a perspective projection.
+ /// </summary>
+ /// <param name="newZNear">The near clipping distance to adjust the projection to.</param>
+ /// <returns>The adjusted projection.</returns>
+ public readonly Projection PerspectiveZNearAdjusted(real_t newZNear)
{
Projection proj = this;
real_t zFar = GetZFar();
real_t zNear = newZNear;
real_t deltaZ = zFar - zNear;
- proj.z.z = -(zFar + zNear) / deltaZ;
- proj.w.z = -2 * zNear * zFar / deltaZ;
+ proj.Z.Z = -(zFar + zNear) / deltaZ;
+ proj.W.Z = -2 * zNear * zFar / deltaZ;
return proj;
}
- public Projection JitterOffseted(Vector2 offset)
+ /// <summary>
+ /// Returns a <see cref="Projection"/> with the X and Y values from the given <see cref="Vector2"/>
+ /// added to the first and second values of the final column respectively.
+ /// </summary>
+ /// <param name="offset">The offset to apply to the projection.</param>
+ /// <returns>The offsetted projection.</returns>
+ public readonly Projection JitterOffseted(Vector2 offset)
{
Projection proj = this;
- proj.w.x += offset.x;
- proj.w.y += offset.y;
+ proj.W.X += offset.X;
+ proj.W.Y += offset.Y;
return proj;
}
- public Projection Inverse()
+ /// <summary>
+ /// Returns a <see cref="Projection"/> that performs the inverse of this <see cref="Projection"/>'s
+ /// projective transformation.
+ /// </summary>
+ /// <returns>The inverted projection.</returns>
+ public readonly Projection Inverse()
{
Projection proj = this;
int i, j, k;
@@ -535,9 +789,68 @@ namespace Godot
return proj;
}
- public bool IsOrthogonal()
+ /// <summary>
+ /// Returns <see langword="true"/> if this <see cref="Projection"/> performs an orthogonal projection.
+ /// </summary>
+ /// <returns>If the projection performs an orthogonal projection.</returns>
+ public readonly bool IsOrthogonal()
+ {
+ return W.W == (real_t)1.0;
+ }
+
+ // Constants
+ private static readonly Projection _zero = new Projection(
+ new Vector4(0, 0, 0, 0),
+ new Vector4(0, 0, 0, 0),
+ new Vector4(0, 0, 0, 0),
+ new Vector4(0, 0, 0, 0)
+ );
+ private static readonly Projection _identity = new Projection(
+ new Vector4(1, 0, 0, 0),
+ new Vector4(0, 1, 0, 0),
+ new Vector4(0, 0, 1, 0),
+ new Vector4(0, 0, 0, 1)
+ );
+
+ /// <summary>
+ /// Zero projection, a projection with all components set to <c>0</c>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero)</c>.</value>
+ public static Projection Zero { get { return _zero; } }
+
+ /// <summary>
+ /// The identity projection, with no distortion applied.
+ /// This is used as a replacement for <c>Projection()</c> in GDScript.
+ /// Do not use <c>new Projection()</c> with no arguments in C#, because it sets all values to zero.
+ /// </summary>
+ /// <value>Equivalent to <c>new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1))</c>.</value>
+ public static Projection Identity { get { return _identity; } }
+
+ /// <summary>
+ /// Constructs a projection from 4 vectors (matrix columns).
+ /// </summary>
+ /// <param name="x">The X column, or column index 0.</param>
+ /// <param name="y">The Y column, or column index 1.</param>
+ /// <param name="z">The Z column, or column index 2.</param>
+ /// <param name="w">The W column, or column index 3.</param>
+ public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ W = w;
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>.
+ /// </summary>
+ /// <param name="transform">The <see cref="Transform3D"/>.</param>
+ public Projection(Transform3D transform)
{
- return w.w == (real_t)1.0;
+ X = new Vector4(transform.Basis.Row0.X, transform.Basis.Row1.X, transform.Basis.Row2.X, 0);
+ Y = new Vector4(transform.Basis.Row0.Y, transform.Basis.Row1.Y, transform.Basis.Row2.Y, 0);
+ Z = new Vector4(transform.Basis.Row0.Z, transform.Basis.Row1.Z, transform.Basis.Row2.Z, 0);
+ W = new Vector4(transform.Origin.X, transform.Origin.Y, transform.Origin.Z, 1);
}
/// <summary>
@@ -552,25 +865,25 @@ namespace Godot
{
return new Projection(
new Vector4(
- left.x.x * right.x.x + left.y.x * right.x.y + left.z.x * right.x.z + left.w.x * right.x.w,
- left.x.y * right.x.x + left.y.y * right.x.y + left.z.y * right.x.z + left.w.y * right.x.w,
- left.x.z * right.x.x + left.y.z * right.x.y + left.z.z * right.x.z + left.w.z * right.x.w,
- left.x.w * right.x.x + left.y.w * right.x.y + left.z.w * right.x.z + left.w.w * right.x.w
+ left.X.X * right.X.X + left.Y.X * right.X.Y + left.Z.X * right.X.Z + left.W.X * right.X.W,
+ left.X.Y * right.X.X + left.Y.Y * right.X.Y + left.Z.Y * right.X.Z + left.W.Y * right.X.W,
+ left.X.Z * right.X.X + left.Y.Z * right.X.Y + left.Z.Z * right.X.Z + left.W.Z * right.X.W,
+ left.X.W * right.X.X + left.Y.W * right.X.Y + left.Z.W * right.X.Z + left.W.W * right.X.W
), new Vector4(
- left.x.x * right.y.x + left.y.x * right.y.y + left.z.x * right.y.z + left.w.x * right.y.w,
- left.x.y * right.y.x + left.y.y * right.y.y + left.z.y * right.y.z + left.w.y * right.y.w,
- left.x.z * right.y.x + left.y.z * right.y.y + left.z.z * right.y.z + left.w.z * right.y.w,
- left.x.w * right.y.x + left.y.w * right.y.y + left.z.w * right.y.z + left.w.w * right.y.w
+ left.X.X * right.Y.X + left.Y.X * right.Y.Y + left.Z.X * right.Y.Z + left.W.X * right.Y.W,
+ left.X.Y * right.Y.X + left.Y.Y * right.Y.Y + left.Z.Y * right.Y.Z + left.W.Y * right.Y.W,
+ left.X.Z * right.Y.X + left.Y.Z * right.Y.Y + left.Z.Z * right.Y.Z + left.W.Z * right.Y.W,
+ left.X.W * right.Y.X + left.Y.W * right.Y.Y + left.Z.W * right.Y.Z + left.W.W * right.Y.W
), new Vector4(
- left.x.x * right.z.x + left.y.x * right.z.y + left.z.x * right.z.z + left.w.x * right.z.w,
- left.x.y * right.z.x + left.y.y * right.z.y + left.z.y * right.z.z + left.w.y * right.z.w,
- left.x.z * right.z.x + left.y.z * right.z.y + left.z.z * right.z.z + left.w.z * right.z.w,
- left.x.w * right.z.x + left.y.w * right.z.y + left.z.w * right.z.z + left.w.w * right.z.w
+ left.X.X * right.Z.X + left.Y.X * right.Z.Y + left.Z.X * right.Z.Z + left.W.X * right.Z.W,
+ left.X.Y * right.Z.X + left.Y.Y * right.Z.Y + left.Z.Y * right.Z.Z + left.W.Y * right.Z.W,
+ left.X.Z * right.Z.X + left.Y.Z * right.Z.Y + left.Z.Z * right.Z.Z + left.W.Z * right.Z.W,
+ left.X.W * right.Z.X + left.Y.W * right.Z.Y + left.Z.W * right.Z.Z + left.W.W * right.Z.W
), new Vector4(
- left.x.x * right.w.x + left.y.x * right.w.y + left.z.x * right.w.z + left.w.x * right.w.w,
- left.x.y * right.w.x + left.y.y * right.w.y + left.z.y * right.w.z + left.w.y * right.w.w,
- left.x.z * right.w.x + left.y.z * right.w.y + left.z.z * right.w.z + left.w.z * right.w.w,
- left.x.w * right.w.x + left.y.w * right.w.y + left.z.w * right.w.z + left.w.w * right.w.w
+ left.X.X * right.W.X + left.Y.X * right.W.Y + left.Z.X * right.W.Z + left.W.X * right.W.W,
+ left.X.Y * right.W.X + left.Y.Y * right.W.Y + left.Z.Y * right.W.Z + left.W.Y * right.W.W,
+ left.X.Z * right.W.X + left.Y.Z * right.W.Y + left.Z.Z * right.W.Z + left.W.Z * right.W.W,
+ left.X.W * right.W.X + left.Y.W * right.W.Y + left.Z.W * right.W.Z + left.W.W * right.W.W
)
);
}
@@ -584,10 +897,10 @@ namespace Godot
public static Vector4 operator *(Projection proj, Vector4 vector)
{
return new Vector4(
- proj.x.x * vector.x + proj.y.x * vector.y + proj.z.x * vector.z + proj.w.x * vector.w,
- proj.x.y * vector.x + proj.y.y * vector.y + proj.z.y * vector.z + proj.w.y * vector.w,
- proj.x.z * vector.x + proj.y.z * vector.y + proj.z.z * vector.z + proj.w.z * vector.w,
- proj.x.w * vector.x + proj.y.w * vector.y + proj.z.w * vector.z + proj.w.w * vector.w
+ proj.X.X * vector.X + proj.Y.X * vector.Y + proj.Z.X * vector.Z + proj.W.X * vector.W,
+ proj.X.Y * vector.X + proj.Y.Y * vector.Y + proj.Z.Y * vector.Z + proj.W.Y * vector.W,
+ proj.X.Z * vector.X + proj.Y.Z * vector.Y + proj.Z.Z * vector.Z + proj.W.Z * vector.W,
+ proj.X.W * vector.X + proj.Y.W * vector.Y + proj.Z.W * vector.Z + proj.W.W * vector.W
);
}
@@ -600,10 +913,10 @@ namespace Godot
public static Vector4 operator *(Vector4 vector, Projection proj)
{
return new Vector4(
- proj.x.x * vector.x + proj.x.y * vector.y + proj.x.z * vector.z + proj.x.w * vector.w,
- proj.y.x * vector.x + proj.y.y * vector.y + proj.y.z * vector.z + proj.y.w * vector.w,
- proj.z.x * vector.x + proj.z.y * vector.y + proj.z.z * vector.z + proj.z.w * vector.w,
- proj.w.x * vector.x + proj.w.y * vector.y + proj.w.z * vector.z + proj.w.w * vector.w
+ proj.X.X * vector.X + proj.X.Y * vector.Y + proj.X.Z * vector.Z + proj.X.W * vector.W,
+ proj.Y.X * vector.X + proj.Y.Y * vector.Y + proj.Y.Z * vector.Z + proj.Y.W * vector.W,
+ proj.Z.X * vector.X + proj.Z.Y * vector.Y + proj.Z.Z * vector.Z + proj.Z.W * vector.W,
+ proj.W.X * vector.X + proj.W.Y * vector.Y + proj.W.Z * vector.Z + proj.W.W * vector.W
);
}
@@ -616,11 +929,11 @@ namespace Godot
public static Vector3 operator *(Projection proj, Vector3 vector)
{
Vector3 ret = new Vector3(
- proj.x.x * vector.x + proj.y.x * vector.y + proj.z.x * vector.z + proj.w.x,
- proj.x.y * vector.x + proj.y.y * vector.y + proj.z.y * vector.z + proj.w.y,
- proj.x.z * vector.x + proj.y.z * vector.y + proj.z.z * vector.z + proj.w.z
+ proj.X.X * vector.X + proj.Y.X * vector.Y + proj.Z.X * vector.Z + proj.W.X,
+ proj.X.Y * vector.X + proj.Y.Y * vector.Y + proj.Z.Y * vector.Z + proj.W.Y,
+ proj.X.Z * vector.X + proj.Y.Z * vector.Y + proj.Z.Z * vector.Z + proj.W.Z
);
- return ret / (proj.x.w * vector.x + proj.y.w * vector.y + proj.z.w * vector.z + proj.w.w);
+ return ret / (proj.X.W * vector.X + proj.Y.W * vector.Y + proj.Z.W * vector.Z + proj.W.W);
}
/// <summary>
@@ -646,177 +959,70 @@ namespace Godot
}
/// <summary>
- /// Access whole columns in the form of <see cref="Vector4"/>.
+ /// Constructs a new <see cref="Transform3D"/> from the <see cref="Projection"/>.
/// </summary>
- /// <param name="column">Which column vector.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="column"/> is not 0, 1, 2 or 3.
- /// </exception>
- public Vector4 this[int column]
+ /// <param name="proj">The <see cref="Projection"/>.</param>
+ public static explicit operator Transform3D(Projection proj)
{
- get
- {
- switch (column)
- {
- case 0:
- return x;
- case 1:
- return y;
- case 2:
- return z;
- case 3:
- return w;
- default:
- throw new ArgumentOutOfRangeException(nameof(column));
- }
- }
- set
- {
- switch (column)
- {
- case 0:
- x = value;
- return;
- case 1:
- y = value;
- return;
- case 2:
- z = value;
- return;
- case 3:
- w = value;
- return;
- default:
- throw new ArgumentOutOfRangeException(nameof(column));
- }
- }
+ return new Transform3D(
+ new Basis(
+ new Vector3(proj.X.X, proj.X.Y, proj.X.Z),
+ new Vector3(proj.Y.X, proj.Y.Y, proj.Y.Z),
+ new Vector3(proj.Z.X, proj.Z.Y, proj.Z.Z)
+ ),
+ new Vector3(proj.W.X, proj.W.Y, proj.W.Z)
+ );
}
/// <summary>
- /// Access single values.
+ /// Returns <see langword="true"/> if the projection is exactly equal
+ /// to the given object (<see paramref="obj"/>).
/// </summary>
- /// <param name="column">Which column vector.</param>
- /// <param name="row">Which row of the column.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="column"/> or <paramref name="row"/> are not 0, 1, 2 or 3.
- /// </exception>
- public real_t this[int column, int row]
+ /// <param name="obj">The object to compare with.</param>
+ /// <returns>Whether or not the vector and the object are equal.</returns>
+ public override readonly bool Equals(object obj)
{
- get
- {
- switch (column)
- {
- case 0:
- return x[row];
- case 1:
- return y[row];
- case 2:
- return z[row];
- case 3:
- return w[row];
- default:
- throw new ArgumentOutOfRangeException(nameof(column));
- }
- }
- set
- {
- switch (column)
- {
- case 0:
- x[row] = value;
- return;
- case 1:
- y[row] = value;
- return;
- case 2:
- z[row] = value;
- return;
- case 3:
- w[row] = value;
- return;
- default:
- throw new ArgumentOutOfRangeException(nameof(column));
- }
- }
+ return obj is Projection other && Equals(other);
}
- // Constants
- private static readonly Projection _zero = new Projection(
- new Vector4(0, 0, 0, 0),
- new Vector4(0, 0, 0, 0),
- new Vector4(0, 0, 0, 0),
- new Vector4(0, 0, 0, 0)
- );
- private static readonly Projection _identity = new Projection(
- new Vector4(1, 0, 0, 0),
- new Vector4(0, 1, 0, 0),
- new Vector4(0, 0, 1, 0),
- new Vector4(0, 0, 0, 1)
- );
-
- /// <summary>
- /// Zero projection, a projection with all components set to <c>0</c>.
- /// </summary>
- /// <value>Equivalent to <c>new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero)</c>.</value>
- public static Projection Zero { get { return _zero; } }
-
/// <summary>
- /// The identity projection, with no distortion applied.
- /// This is used as a replacement for <c>Projection()</c> in GDScript.
- /// Do not use <c>new Projection()</c> with no arguments in C#, because it sets all values to zero.
+ /// Returns <see langword="true"/> if the projections are exactly equal.
/// </summary>
- /// <value>Equivalent to <c>new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1))</c>.</value>
- public static Projection Identity { get { return _identity; } }
+ /// <param name="other">The other projection.</param>
+ /// <returns>Whether or not the projections are exactly equal.</returns>
+ public readonly bool Equals(Projection other)
+ {
+ return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
+ }
/// <summary>
/// Serves as the hash function for <see cref="Projection"/>.
/// </summary>
/// <returns>A hash code for this projection.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ return Y.GetHashCode() ^ X.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode();
}
/// <summary>
/// Converts this <see cref="Projection"/> to a string.
/// </summary>
/// <returns>A string representation of this projection.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"{x.x}, {x.y}, {x.z}, {x.w}\n{y.x}, {y.y}, {y.z}, {y.w}\n{z.x}, {z.y}, {z.z}, {z.w}\n{w.x}, {w.y}, {w.z}, {w.w}\n";
+ return $"{X.X}, {X.Y}, {X.Z}, {X.W}\n{Y.X}, {Y.Y}, {Y.Z}, {Y.W}\n{Z.X}, {Z.Y}, {Z.Z}, {Z.W}\n{W.X}, {W.Y}, {W.Z}, {W.W}\n";
}
/// <summary>
/// Converts this <see cref="Projection"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this projection.</returns>
- public string ToString(string format)
- {
- return $"{x.x.ToString(format)}, {x.y.ToString(format)}, {x.z.ToString(format)}, {x.w.ToString(format)}\n" +
- $"{y.x.ToString(format)}, {y.y.ToString(format)}, {y.z.ToString(format)}, {y.w.ToString(format)}\n" +
- $"{z.x.ToString(format)}, {z.y.ToString(format)}, {z.z.ToString(format)}, {z.w.ToString(format)}\n" +
- $"{w.x.ToString(format)}, {w.y.ToString(format)}, {w.z.ToString(format)}, {w.w.ToString(format)}\n";
- }
-
- /// <summary>
- /// Returns <see langword="true"/> if the projection is exactly equal
- /// to the given object (<see paramref="obj"/>).
- /// </summary>
- /// <param name="obj">The object to compare with.</param>
- /// <returns>Whether or not the vector and the object are equal.</returns>
- public override bool Equals(object obj)
- {
- return obj is Projection other && Equals(other);
- }
-
- /// <summary>
- /// Returns <see langword="true"/> if the projections are exactly equal.
- /// </summary>
- /// <param name="other">The other projection.</param>
- /// <returns>Whether or not the projections are exactly equal.</returns>
- public bool Equals(Projection other)
+ public readonly string ToString(string format)
{
- return x == other.x && y == other.y && z == other.z && w == other.w;
+ return $"{X.X.ToString(format)}, {X.Y.ToString(format)}, {X.Z.ToString(format)}, {X.W.ToString(format)}\n" +
+ $"{Y.X.ToString(format)}, {Y.Y.ToString(format)}, {Y.Z.ToString(format)}, {Y.W.ToString(format)}\n" +
+ $"{Z.X.ToString(format)}, {Z.Y.ToString(format)}, {Z.Z.ToString(format)}, {Z.W.ToString(format)}\n" +
+ $"{W.X.ToString(format)}, {W.Y.ToString(format)}, {W.Z.ToString(format)}, {W.W.ToString(format)}\n";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index f01f0be985..9c2a6fc654 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -24,25 +24,25 @@ namespace Godot
/// X component of the quaternion (imaginary <c>i</c> axis part).
/// Quaternion components should usually not be manipulated directly.
/// </summary>
- public real_t x;
+ public real_t X;
/// <summary>
/// Y component of the quaternion (imaginary <c>j</c> axis part).
/// Quaternion components should usually not be manipulated directly.
/// </summary>
- public real_t y;
+ public real_t Y;
/// <summary>
/// Z component of the quaternion (imaginary <c>k</c> axis part).
/// Quaternion components should usually not be manipulated directly.
/// </summary>
- public real_t z;
+ public real_t Z;
/// <summary>
/// W component of the quaternion (real part).
/// Quaternion components should usually not be manipulated directly.
/// </summary>
- public real_t w;
+ public real_t W;
/// <summary>
/// Access quaternion components using their index.
@@ -51,25 +51,25 @@ namespace Godot
/// <paramref name="index"/> is not 0, 1, 2 or 3.
/// </exception>
/// <value>
- /// <c>[0]</c> is equivalent to <see cref="x"/>,
- /// <c>[1]</c> is equivalent to <see cref="y"/>,
- /// <c>[2]</c> is equivalent to <see cref="z"/>,
- /// <c>[3]</c> is equivalent to <see cref="w"/>.
+ /// <c>[0]</c> is equivalent to <see cref="X"/>,
+ /// <c>[1]</c> is equivalent to <see cref="Y"/>,
+ /// <c>[2]</c> is equivalent to <see cref="Z"/>,
+ /// <c>[3]</c> is equivalent to <see cref="W"/>.
/// </value>
public real_t this[int index]
{
- get
+ readonly get
{
switch (index)
{
case 0:
- return x;
+ return X;
case 1:
- return y;
+ return Y;
case 2:
- return z;
+ return Z;
case 3:
- return w;
+ return W;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
@@ -79,16 +79,16 @@ namespace Godot
switch (index)
{
case 0:
- x = value;
+ X = value;
break;
case 1:
- y = value;
+ Y = value;
break;
case 2:
- z = value;
+ Z = value;
break;
case 3:
- w = value;
+ W = value;
break;
default:
throw new ArgumentOutOfRangeException(nameof(index));
@@ -97,27 +97,6 @@ namespace Godot
}
/// <summary>
- /// Returns the length (magnitude) of the quaternion.
- /// </summary>
- /// <seealso cref="LengthSquared"/>
- /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value>
- public real_t Length
- {
- get { return Mathf.Sqrt(LengthSquared); }
- }
-
- /// <summary>
- /// Returns the squared length (squared magnitude) of the quaternion.
- /// This method runs faster than <see cref="Length"/>, so prefer it if
- /// you need to compare quaternions or need the squared length for some formula.
- /// </summary>
- /// <value>Equivalent to <c>Dot(this)</c>.</value>
- public real_t LengthSquared
- {
- get { return Dot(this); }
- }
-
- /// <summary>
/// Returns the angle between this quaternion and <paramref name="to"/>.
/// This is the magnitude of the angle you would need to rotate
/// by to get from one to the other.
@@ -128,7 +107,7 @@ namespace Godot
/// </summary>
/// <param name="to">The other quaternion.</param>
/// <returns>The angle between the quaternions.</returns>
- public real_t AngleTo(Quaternion to)
+ public readonly real_t AngleTo(Quaternion to)
{
real_t dot = Dot(to);
return Mathf.Acos(Mathf.Clamp(dot * dot * 2 - 1, -1, 1));
@@ -143,7 +122,7 @@ namespace Godot
/// <param name="postB">A quaternion after <paramref name="b"/>.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated quaternion.</returns>
- public Quaternion SphericalCubicInterpolate(Quaternion b, Quaternion preA, Quaternion postB, real_t weight)
+ public readonly Quaternion SphericalCubicInterpolate(Quaternion b, Quaternion preA, Quaternion postB, real_t weight)
{
#if DEBUG
if (!IsNormalized())
@@ -176,9 +155,9 @@ namespace Godot
Quaternion lnPre = (fromQ.Inverse() * preQ).Log();
Quaternion lnPost = (fromQ.Inverse() * postQ).Log();
Quaternion ln = new Quaternion(
- Mathf.CubicInterpolate(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight),
- Mathf.CubicInterpolate(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight),
- Mathf.CubicInterpolate(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight),
+ Mathf.CubicInterpolate(lnFrom.X, lnTo.X, lnPre.X, lnPost.X, weight),
+ Mathf.CubicInterpolate(lnFrom.Y, lnTo.Y, lnPre.Y, lnPost.Y, weight),
+ Mathf.CubicInterpolate(lnFrom.Z, lnTo.Z, lnPre.Z, lnPost.Z, weight),
0);
Quaternion q1 = fromQ * ln.Exp();
@@ -188,13 +167,13 @@ namespace Godot
lnPre = (toQ.Inverse() * preQ).Log();
lnPost = (toQ.Inverse() * postQ).Log();
ln = new Quaternion(
- Mathf.CubicInterpolate(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight),
- Mathf.CubicInterpolate(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight),
- Mathf.CubicInterpolate(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight),
+ Mathf.CubicInterpolate(lnFrom.X, lnTo.X, lnPre.X, lnPost.X, weight),
+ Mathf.CubicInterpolate(lnFrom.Y, lnTo.Y, lnPre.Y, lnPost.Y, weight),
+ Mathf.CubicInterpolate(lnFrom.Z, lnTo.Z, lnPre.Z, lnPost.Z, weight),
0);
Quaternion q2 = toQ * ln.Exp();
- // To cancel error made by Expmap ambiguity, do blends.
+ // To cancel error made by Expmap ambiguity, do blending.
return q1.Slerp(q2, weight);
}
@@ -212,7 +191,7 @@ namespace Godot
/// <param name="preAT"></param>
/// <param name="postBT"></param>
/// <returns>The interpolated quaternion.</returns>
- public Quaternion SphericalCubicInterpolateInTime(Quaternion b, Quaternion preA, Quaternion postB, real_t weight, real_t bT, real_t preAT, real_t postBT)
+ public readonly Quaternion SphericalCubicInterpolateInTime(Quaternion b, Quaternion preA, Quaternion postB, real_t weight, real_t bT, real_t preAT, real_t postBT)
{
#if DEBUG
if (!IsNormalized())
@@ -245,9 +224,9 @@ namespace Godot
Quaternion lnPre = (fromQ.Inverse() * preQ).Log();
Quaternion lnPost = (fromQ.Inverse() * postQ).Log();
Quaternion ln = new Quaternion(
- Mathf.CubicInterpolateInTime(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight, bT, preAT, postBT),
- Mathf.CubicInterpolateInTime(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight, bT, preAT, postBT),
- Mathf.CubicInterpolateInTime(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.X, lnTo.X, lnPre.X, lnPost.X, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.Y, lnTo.Y, lnPre.Y, lnPost.Y, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.Z, lnTo.Z, lnPre.Z, lnPost.Z, weight, bT, preAT, postBT),
0);
Quaternion q1 = fromQ * ln.Exp();
@@ -257,13 +236,13 @@ namespace Godot
lnPre = (toQ.Inverse() * preQ).Log();
lnPost = (toQ.Inverse() * postQ).Log();
ln = new Quaternion(
- Mathf.CubicInterpolateInTime(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight, bT, preAT, postBT),
- Mathf.CubicInterpolateInTime(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight, bT, preAT, postBT),
- Mathf.CubicInterpolateInTime(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.X, lnTo.X, lnPre.X, lnPost.X, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.Y, lnTo.Y, lnPre.Y, lnPost.Y, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.Z, lnTo.Z, lnPre.Z, lnPost.Z, weight, bT, preAT, postBT),
0);
Quaternion q2 = toQ * ln.Exp();
- // To cancel error made by Expmap ambiguity, do blends.
+ // To cancel error made by Expmap ambiguity, do blending.
return q1.Slerp(q2, weight);
}
@@ -272,14 +251,14 @@ namespace Godot
/// </summary>
/// <param name="b">The other quaternion.</param>
/// <returns>The dot product.</returns>
- public real_t Dot(Quaternion b)
+ public readonly real_t Dot(Quaternion b)
{
- return (x * b.x) + (y * b.y) + (z * b.z) + (w * b.w);
+ return (X * b.X) + (Y * b.Y) + (Z * b.Z) + (W * b.W);
}
- public Quaternion Exp()
+ public readonly Quaternion Exp()
{
- Vector3 v = new Vector3(x, y, z);
+ Vector3 v = new Vector3(X, Y, Z);
real_t theta = v.Length();
v = v.Normalized();
if (theta < Mathf.Epsilon || !v.IsNormalized())
@@ -289,20 +268,20 @@ namespace Godot
return new Quaternion(v, theta);
}
- public real_t GetAngle()
+ public readonly real_t GetAngle()
{
- return 2 * Mathf.Acos(w);
+ return 2 * Mathf.Acos(W);
}
- public Vector3 GetAxis()
+ public readonly Vector3 GetAxis()
{
- if (Mathf.Abs(w) > 1 - Mathf.Epsilon)
+ if (Mathf.Abs(W) > 1 - Mathf.Epsilon)
{
- return new Vector3(x, y, z);
+ return new Vector3(X, Y, Z);
}
- real_t r = 1 / Mathf.Sqrt(1 - w * w);
- return new Vector3(x * r, y * r, z * r);
+ real_t r = 1 / Mathf.Sqrt(1 - W * W);
+ return new Vector3(X * r, Y * r, Z * r);
}
/// <summary>
@@ -312,7 +291,7 @@ namespace Godot
/// the rotation angles in the format (X angle, Y angle, Z angle).
/// </summary>
/// <returns>The Euler angle representation of this quaternion.</returns>
- public Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz)
+ public readonly Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz)
{
#if DEBUG
if (!IsNormalized())
@@ -328,7 +307,7 @@ namespace Godot
/// Returns the inverse of the quaternion.
/// </summary>
/// <returns>The inverse quaternion.</returns>
- public Quaternion Inverse()
+ public readonly Quaternion Inverse()
{
#if DEBUG
if (!IsNormalized())
@@ -336,31 +315,62 @@ namespace Godot
throw new InvalidOperationException("Quaternion is not normalized.");
}
#endif
- return new Quaternion(-x, -y, -z, w);
+ return new Quaternion(-X, -Y, -Z, W);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this quaternion is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(X) && Mathf.IsFinite(Y) && Mathf.IsFinite(Z) && Mathf.IsFinite(W);
}
/// <summary>
/// Returns whether the quaternion is normalized or not.
/// </summary>
/// <returns>A <see langword="bool"/> for whether the quaternion is normalized or not.</returns>
- public bool IsNormalized()
+ public readonly bool IsNormalized()
{
- return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon;
+ return Mathf.Abs(LengthSquared() - 1) <= Mathf.Epsilon;
}
- public Quaternion Log()
+ public readonly Quaternion Log()
{
Vector3 v = GetAxis() * GetAngle();
- return new Quaternion(v.x, v.y, v.z, 0);
+ return new Quaternion(v.X, v.Y, v.Z, 0);
+ }
+
+ /// <summary>
+ /// Returns the length (magnitude) of the quaternion.
+ /// </summary>
+ /// <seealso cref="LengthSquared"/>
+ /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value>
+ public readonly real_t Length()
+ {
+ return Mathf.Sqrt(LengthSquared());
+ }
+
+ /// <summary>
+ /// Returns the squared length (squared magnitude) of the quaternion.
+ /// This method runs faster than <see cref="Length"/>, so prefer it if
+ /// you need to compare quaternions or need the squared length for some formula.
+ /// </summary>
+ /// <value>Equivalent to <c>Dot(this)</c>.</value>
+ public readonly real_t LengthSquared()
+ {
+ return Dot(this);
}
/// <summary>
/// Returns a copy of the quaternion, normalized to unit length.
/// </summary>
/// <returns>The normalized quaternion.</returns>
- public Quaternion Normalized()
+ public readonly Quaternion Normalized()
{
- return this / Length;
+ return this / Length();
}
/// <summary>
@@ -372,7 +382,7 @@ namespace Godot
/// <param name="to">The destination quaternion for interpolation. Must be normalized.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting quaternion of the interpolation.</returns>
- public Quaternion Slerp(Quaternion to, real_t weight)
+ public readonly Quaternion Slerp(Quaternion to, real_t weight)
{
#if DEBUG
if (!IsNormalized())
@@ -422,10 +432,10 @@ namespace Godot
// Calculate final values.
return new Quaternion
(
- (scale0 * x) + (scale1 * to1.x),
- (scale0 * y) + (scale1 * to1.y),
- (scale0 * z) + (scale1 * to1.z),
- (scale0 * w) + (scale1 * to1.w)
+ (scale0 * X) + (scale1 * to1.X),
+ (scale0 * Y) + (scale1 * to1.Y),
+ (scale0 * Z) + (scale1 * to1.Z),
+ (scale0 * W) + (scale1 * to1.W)
);
}
@@ -437,7 +447,7 @@ namespace Godot
/// <param name="to">The destination quaternion for interpolation. Must be normalized.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting quaternion of the interpolation.</returns>
- public Quaternion Slerpni(Quaternion to, real_t weight)
+ public readonly Quaternion Slerpni(Quaternion to, real_t weight)
{
#if DEBUG
if (!IsNormalized())
@@ -464,10 +474,10 @@ namespace Godot
return new Quaternion
(
- (invFactor * x) + (newFactor * to.x),
- (invFactor * y) + (newFactor * to.y),
- (invFactor * z) + (newFactor * to.z),
- (invFactor * w) + (newFactor * to.w)
+ (invFactor * X) + (newFactor * to.X),
+ (invFactor * Y) + (newFactor * to.Y),
+ (invFactor * Z) + (newFactor * to.Z),
+ (invFactor * W) + (newFactor * to.W)
);
}
@@ -491,10 +501,10 @@ namespace Godot
/// <param name="w">W component of the quaternion (real part).</param>
public Quaternion(real_t x, real_t y, real_t z, real_t w)
{
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
+ X = x;
+ Y = y;
+ Z = z;
+ W = w;
}
/// <summary>
@@ -525,21 +535,20 @@ namespace Godot
if (d == 0f)
{
- x = 0f;
- y = 0f;
- z = 0f;
- w = 0f;
+ X = 0f;
+ Y = 0f;
+ Z = 0f;
+ W = 0f;
}
else
{
- real_t sinAngle = Mathf.Sin(angle * 0.5f);
- real_t cosAngle = Mathf.Cos(angle * 0.5f);
- real_t s = sinAngle / d;
-
- x = axis.x * s;
- y = axis.y * s;
- z = axis.z * s;
- w = cosAngle;
+ (real_t sin, real_t cos) = Mathf.SinCos(angle * 0.5f);
+ real_t s = sin / d;
+
+ X = axis.X * s;
+ Y = axis.Y * s;
+ Z = axis.Z * s;
+ W = cos;
}
}
@@ -550,20 +559,20 @@ namespace Godot
if (d < -1.0f + Mathf.Epsilon)
{
- x = 0f;
- y = 1f;
- z = 0f;
- w = 0f;
+ X = 0f;
+ Y = 1f;
+ Z = 0f;
+ W = 0f;
}
else
{
real_t s = Mathf.Sqrt((1.0f + d) * 2.0f);
real_t rs = 1.0f / s;
- x = c.x * rs;
- y = c.y * rs;
- z = c.z * rs;
- w = s * 0.5f;
+ X = c.X * rs;
+ Y = c.Y * rs;
+ Z = c.Z * rs;
+ W = s * 0.5f;
}
}
@@ -575,20 +584,17 @@ namespace Godot
/// <param name="eulerYXZ">Euler angles that the quaternion will be rotated by.</param>
public static Quaternion FromEuler(Vector3 eulerYXZ)
{
- real_t halfA1 = eulerYXZ.y * 0.5f;
- real_t halfA2 = eulerYXZ.x * 0.5f;
- real_t halfA3 = eulerYXZ.z * 0.5f;
+ real_t halfA1 = eulerYXZ.Y * 0.5f;
+ real_t halfA2 = eulerYXZ.X * 0.5f;
+ real_t halfA3 = eulerYXZ.Z * 0.5f;
// R = Y(a1).X(a2).Z(a3) convention for Euler angles.
// Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6)
// a3 is the angle of the first rotation, following the notation in this reference.
- real_t cosA1 = Mathf.Cos(halfA1);
- real_t sinA1 = Mathf.Sin(halfA1);
- real_t cosA2 = Mathf.Cos(halfA2);
- real_t sinA2 = Mathf.Sin(halfA2);
- real_t cosA3 = Mathf.Cos(halfA3);
- real_t sinA3 = Mathf.Sin(halfA3);
+ (real_t sinA1, real_t cosA1) = Mathf.SinCos(halfA1);
+ (real_t sinA2, real_t cosA2) = Mathf.SinCos(halfA2);
+ (real_t sinA3, real_t cosA3) = Mathf.SinCos(halfA3);
return new Quaternion(
(sinA1 * cosA2 * sinA3) + (cosA1 * sinA2 * cosA3),
@@ -610,10 +616,10 @@ namespace Godot
{
return new Quaternion
(
- (left.w * right.x) + (left.x * right.w) + (left.y * right.z) - (left.z * right.y),
- (left.w * right.y) + (left.y * right.w) + (left.z * right.x) - (left.x * right.z),
- (left.w * right.z) + (left.z * right.w) + (left.x * right.y) - (left.y * right.x),
- (left.w * right.w) - (left.x * right.x) - (left.y * right.y) - (left.z * right.z)
+ (left.W * right.X) + (left.X * right.W) + (left.Y * right.Z) - (left.Z * right.Y),
+ (left.W * right.Y) + (left.Y * right.W) + (left.Z * right.X) - (left.X * right.Z),
+ (left.W * right.Z) + (left.Z * right.W) + (left.X * right.Y) - (left.Y * right.X),
+ (left.W * right.W) - (left.X * right.X) - (left.Y * right.Y) - (left.Z * right.Z)
);
}
@@ -631,9 +637,9 @@ namespace Godot
throw new InvalidOperationException("Quaternion is not normalized.");
}
#endif
- var u = new Vector3(quaternion.x, quaternion.y, quaternion.z);
+ var u = new Vector3(quaternion.X, quaternion.Y, quaternion.Z);
Vector3 uv = u.Cross(vector);
- return vector + (((uv * quaternion.w) + u.Cross(uv)) * 2);
+ return vector + (((uv * quaternion.W) + u.Cross(uv)) * 2);
}
/// <summary>
@@ -659,7 +665,7 @@ namespace Godot
/// <returns>The added quaternion.</returns>
public static Quaternion operator +(Quaternion left, Quaternion right)
{
- return new Quaternion(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
+ return new Quaternion(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
}
/// <summary>
@@ -673,20 +679,20 @@ namespace Godot
/// <returns>The subtracted quaternion.</returns>
public static Quaternion operator -(Quaternion left, Quaternion right)
{
- return new Quaternion(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
+ return new Quaternion(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W);
}
/// <summary>
/// Returns the negative value of the <see cref="Quaternion"/>.
/// This is the same as writing
- /// <c>new Quaternion(-q.x, -q.y, -q.z, -q.w)</c>. This operation
+ /// <c>new Quaternion(-q.X, -q.Y, -q.Z, -q.W)</c>. This operation
/// results in a quaternion that represents the same rotation.
/// </summary>
/// <param name="quat">The quaternion to negate.</param>
/// <returns>The negated quaternion.</returns>
public static Quaternion operator -(Quaternion quat)
{
- return new Quaternion(-quat.x, -quat.y, -quat.z, -quat.w);
+ return new Quaternion(-quat.X, -quat.Y, -quat.Z, -quat.W);
}
/// <summary>
@@ -700,7 +706,7 @@ namespace Godot
/// <returns>The multiplied quaternion.</returns>
public static Quaternion operator *(Quaternion left, real_t right)
{
- return new Quaternion(left.x * right, left.y * right, left.z * right, left.w * right);
+ return new Quaternion(left.X * right, left.Y * right, left.Z * right, left.W * right);
}
/// <summary>
@@ -714,7 +720,7 @@ namespace Godot
/// <returns>The multiplied quaternion.</returns>
public static Quaternion operator *(real_t left, Quaternion right)
{
- return new Quaternion(right.x * left, right.y * left, right.z * left, right.w * left);
+ return new Quaternion(right.X * left, right.Y * left, right.Z * left, right.W * left);
}
/// <summary>
@@ -762,7 +768,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The other object to compare.</param>
/// <returns>Whether or not the quaternion and the other object are exactly equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Quaternion other && Equals(other);
}
@@ -772,9 +778,9 @@ namespace Godot
/// </summary>
/// <param name="other">The other quaternion to compare.</param>
/// <returns>Whether or not the quaternions are exactly equal.</returns>
- public bool Equals(Quaternion other)
+ public readonly bool Equals(Quaternion other)
{
- return x == other.x && y == other.y && z == other.z && w == other.w;
+ return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
}
/// <summary>
@@ -783,36 +789,36 @@ namespace Godot
/// </summary>
/// <param name="other">The other quaternion to compare.</param>
/// <returns>Whether or not the quaternions are approximately equal.</returns>
- public bool IsEqualApprox(Quaternion other)
+ public readonly bool IsEqualApprox(Quaternion other)
{
- return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);
+ return Mathf.IsEqualApprox(X, other.X) && Mathf.IsEqualApprox(Y, other.Y) && Mathf.IsEqualApprox(Z, other.Z) && Mathf.IsEqualApprox(W, other.W);
}
/// <summary>
/// Serves as the hash function for <see cref="Quaternion"/>.
/// </summary>
/// <returns>A hash code for this quaternion.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ return Y.GetHashCode() ^ X.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode();
}
/// <summary>
/// Converts this <see cref="Quaternion"/> to a string.
/// </summary>
/// <returns>A string representation of this quaternion.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"({x}, {y}, {z}, {w})";
+ return $"({X}, {Y}, {Z}, {W})";
}
/// <summary>
/// Converts this <see cref="Quaternion"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this quaternion.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}, {w.ToString(format)})";
+ return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
deleted file mode 100644
index a31fef8360..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using Godot.NativeInterop;
-
-namespace Godot
-{
- /// <summary>
- /// The RID type is used to access the unique integer ID of a resource.
- /// They are opaque, which means they do not grant access to the associated
- /// resource by themselves. They are used by and with the low-level Server
- /// classes such as <see cref="RenderingServer"/>.
- /// </summary>
- [StructLayout(LayoutKind.Sequential)]
- public struct RID
- {
- private ulong _id; // Default is 0
-
- internal RID(ulong id)
- {
- _id = id;
- }
-
- /// <summary>
- /// Constructs a new <see cref="RID"/> for the given <see cref="Object"/> <paramref name="from"/>.
- /// </summary>
- public RID(Object from)
- => _id = from is Resource res ? res.GetRid()._id : default;
-
- /// <summary>
- /// Returns the ID of the referenced resource.
- /// </summary>
- /// <returns>The ID of the referenced resource.</returns>
- public ulong Id => _id;
-
- /// <summary>
- /// Converts this <see cref="RID"/> to a string.
- /// </summary>
- /// <returns>A string representation of this RID.</returns>
- public override string ToString() => $"RID({Id})";
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index e80d75dacf..69444f8035 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -20,7 +20,7 @@ namespace Godot
/// <value>Directly uses a private field.</value>
public Vector2 Position
{
- get { return _position; }
+ readonly get { return _position; }
set { _position = value; }
}
@@ -31,7 +31,7 @@ namespace Godot
/// <value>Directly uses a private field.</value>
public Vector2 Size
{
- get { return _size; }
+ readonly get { return _size; }
set { _size = value; }
}
@@ -45,17 +45,17 @@ namespace Godot
/// </value>
public Vector2 End
{
- get { return _position + _size; }
+ readonly get { return _position + _size; }
set { _size = value - _position; }
}
/// <summary>
/// The area of this <see cref="Rect2"/>.
+ /// See also <see cref="HasArea"/>.
/// </summary>
- /// <value>Equivalent to <see cref="GetArea()"/>.</value>
- public real_t Area
+ public readonly real_t Area
{
- get { return GetArea(); }
+ get { return _size.X * _size.Y; }
}
/// <summary>
@@ -63,10 +63,10 @@ namespace Godot
/// the top-left corner is the origin and width and height are positive.
/// </summary>
/// <returns>The modified <see cref="Rect2"/>.</returns>
- public Rect2 Abs()
+ public readonly Rect2 Abs()
{
Vector2 end = End;
- Vector2 topLeft = new Vector2(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y));
+ Vector2 topLeft = new Vector2(Mathf.Min(_position.X, end.X), Mathf.Min(_position.Y, end.Y));
return new Rect2(topLeft, _size.Abs());
}
@@ -79,7 +79,7 @@ namespace Godot
/// The intersection of this <see cref="Rect2"/> and <paramref name="b"/>,
/// or an empty <see cref="Rect2"/> if they do not intersect.
/// </returns>
- public Rect2 Intersection(Rect2 b)
+ public readonly Rect2 Intersection(Rect2 b)
{
Rect2 newRect = b;
@@ -88,30 +88,40 @@ namespace Godot
return new Rect2();
}
- newRect._position.x = Mathf.Max(b._position.x, _position.x);
- newRect._position.y = Mathf.Max(b._position.y, _position.y);
+ newRect._position.X = Mathf.Max(b._position.X, _position.X);
+ newRect._position.Y = Mathf.Max(b._position.Y, _position.Y);
Vector2 bEnd = b._position + b._size;
Vector2 end = _position + _size;
- newRect._size.x = Mathf.Min(bEnd.x, end.x) - newRect._position.x;
- newRect._size.y = Mathf.Min(bEnd.y, end.y) - newRect._position.y;
+ newRect._size.X = Mathf.Min(bEnd.X, end.X) - newRect._position.X;
+ newRect._size.Y = Mathf.Min(bEnd.Y, end.Y) - newRect._position.Y;
return newRect;
}
/// <summary>
+ /// Returns <see langword="true"/> if this <see cref="Rect2"/> is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public bool IsFinite()
+ {
+ return _position.IsFinite() && _size.IsFinite();
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if this <see cref="Rect2"/> completely encloses another one.
/// </summary>
/// <param name="b">The other <see cref="Rect2"/> that may be enclosed.</param>
/// <returns>
/// A <see langword="bool"/> for whether or not this <see cref="Rect2"/> encloses <paramref name="b"/>.
/// </returns>
- public bool Encloses(Rect2 b)
+ public readonly bool Encloses(Rect2 b)
{
- return b._position.x >= _position.x && b._position.y >= _position.y &&
- b._position.x + b._size.x < _position.x + _size.x &&
- b._position.y + b._size.y < _position.y + _size.y;
+ return b._position.X >= _position.X && b._position.Y >= _position.Y &&
+ b._position.X + b._size.X < _position.X + _size.X &&
+ b._position.Y + b._size.Y < _position.Y + _size.Y;
}
/// <summary>
@@ -119,29 +129,29 @@ namespace Godot
/// </summary>
/// <param name="to">The point to include.</param>
/// <returns>The expanded <see cref="Rect2"/>.</returns>
- public Rect2 Expand(Vector2 to)
+ public readonly Rect2 Expand(Vector2 to)
{
Rect2 expanded = this;
Vector2 begin = expanded._position;
Vector2 end = expanded._position + expanded._size;
- if (to.x < begin.x)
+ if (to.X < begin.X)
{
- begin.x = to.x;
+ begin.X = to.X;
}
- if (to.y < begin.y)
+ if (to.Y < begin.Y)
{
- begin.y = to.y;
+ begin.Y = to.Y;
}
- if (to.x > end.x)
+ if (to.X > end.X)
{
- end.x = to.x;
+ end.X = to.X;
}
- if (to.y > end.y)
+ if (to.Y > end.Y)
{
- end.y = to.y;
+ end.Y = to.Y;
}
expanded._position = begin;
@@ -151,20 +161,11 @@ namespace Godot
}
/// <summary>
- /// Returns the area of the <see cref="Rect2"/>.
- /// </summary>
- /// <returns>The area.</returns>
- public real_t GetArea()
- {
- return _size.x * _size.y;
- }
-
- /// <summary>
/// Returns the center of the <see cref="Rect2"/>, which is equal
/// to <see cref="Position"/> + (<see cref="Size"/> / 2).
/// </summary>
/// <returns>The center.</returns>
- public Vector2 GetCenter()
+ public readonly Vector2 GetCenter()
{
return _position + (_size * 0.5f);
}
@@ -177,14 +178,14 @@ namespace Godot
/// <seealso cref="GrowSide(Side, real_t)"/>
/// <param name="by">The amount to grow by.</param>
/// <returns>The grown <see cref="Rect2"/>.</returns>
- public Rect2 Grow(real_t by)
+ public readonly Rect2 Grow(real_t by)
{
Rect2 g = this;
- g._position.x -= by;
- g._position.y -= by;
- g._size.x += by * 2;
- g._size.y += by * 2;
+ g._position.X -= by;
+ g._position.Y -= by;
+ g._size.X += by * 2;
+ g._size.Y += by * 2;
return g;
}
@@ -200,14 +201,14 @@ namespace Godot
/// <param name="right">The amount to grow by on the right side.</param>
/// <param name="bottom">The amount to grow by on the bottom side.</param>
/// <returns>The grown <see cref="Rect2"/>.</returns>
- public Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom)
+ public readonly Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom)
{
Rect2 g = this;
- g._position.x -= left;
- g._position.y -= top;
- g._size.x += left + right;
- g._size.y += top + bottom;
+ g._position.X -= left;
+ g._position.Y -= top;
+ g._size.X += left + right;
+ g._size.Y += top + bottom;
return g;
}
@@ -221,7 +222,7 @@ namespace Godot
/// <param name="side">The side to grow.</param>
/// <param name="by">The amount to grow by.</param>
/// <returns>The grown <see cref="Rect2"/>.</returns>
- public Rect2 GrowSide(Side side, real_t by)
+ public readonly Rect2 GrowSide(Side side, real_t by)
{
Rect2 g = this;
@@ -237,14 +238,14 @@ namespace Godot
/// Returns <see langword="true"/> if the <see cref="Rect2"/> has
/// area, and <see langword="false"/> if the <see cref="Rect2"/>
/// is linear, empty, or has a negative <see cref="Size"/>.
- /// See also <see cref="GetArea"/>.
+ /// See also <see cref="Area"/>.
/// </summary>
/// <returns>
/// A <see langword="bool"/> for whether or not the <see cref="Rect2"/> has area.
/// </returns>
- public bool HasArea()
+ public readonly bool HasArea()
{
- return _size.x > 0.0f && _size.y > 0.0f;
+ return _size.X > 0.0f && _size.Y > 0.0f;
}
/// <summary>
@@ -255,16 +256,16 @@ namespace Godot
/// <returns>
/// A <see langword="bool"/> for whether or not the <see cref="Rect2"/> contains <paramref name="point"/>.
/// </returns>
- public bool HasPoint(Vector2 point)
+ public readonly bool HasPoint(Vector2 point)
{
- if (point.x < _position.x)
+ if (point.X < _position.X)
return false;
- if (point.y < _position.y)
+ if (point.Y < _position.Y)
return false;
- if (point.x >= _position.x + _size.x)
+ if (point.X >= _position.X + _size.X)
return false;
- if (point.y >= _position.y + _size.y)
+ if (point.Y >= _position.Y + _size.Y)
return false;
return true;
@@ -281,42 +282,42 @@ namespace Godot
/// <param name="b">The other <see cref="Rect2"/> to check for intersections with.</param>
/// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns>
- public bool Intersects(Rect2 b, bool includeBorders = false)
+ public readonly bool Intersects(Rect2 b, bool includeBorders = false)
{
if (includeBorders)
{
- if (_position.x > b._position.x + b._size.x)
+ if (_position.X > b._position.X + b._size.X)
{
return false;
}
- if (_position.x + _size.x < b._position.x)
+ if (_position.X + _size.X < b._position.X)
{
return false;
}
- if (_position.y > b._position.y + b._size.y)
+ if (_position.Y > b._position.Y + b._size.Y)
{
return false;
}
- if (_position.y + _size.y < b._position.y)
+ if (_position.Y + _size.Y < b._position.Y)
{
return false;
}
}
else
{
- if (_position.x >= b._position.x + b._size.x)
+ if (_position.X >= b._position.X + b._size.X)
{
return false;
}
- if (_position.x + _size.x <= b._position.x)
+ if (_position.X + _size.X <= b._position.X)
{
return false;
}
- if (_position.y >= b._position.y + b._size.y)
+ if (_position.Y >= b._position.Y + b._size.Y)
{
return false;
}
- if (_position.y + _size.y <= b._position.y)
+ if (_position.Y + _size.Y <= b._position.Y)
{
return false;
}
@@ -330,15 +331,15 @@ namespace Godot
/// </summary>
/// <param name="b">The other <see cref="Rect2"/>.</param>
/// <returns>The merged <see cref="Rect2"/>.</returns>
- public Rect2 Merge(Rect2 b)
+ public readonly Rect2 Merge(Rect2 b)
{
Rect2 newRect;
- newRect._position.x = Mathf.Min(b._position.x, _position.x);
- newRect._position.y = Mathf.Min(b._position.y, _position.y);
+ newRect._position.X = Mathf.Min(b._position.X, _position.X);
+ newRect._position.Y = Mathf.Min(b._position.Y, _position.Y);
- newRect._size.x = Mathf.Max(b._position.x + b._size.x, _position.x + _size.x);
- newRect._size.y = Mathf.Max(b._position.y + b._size.y, _position.y + _size.y);
+ newRect._size.X = Mathf.Max(b._position.X + b._size.X, _position.X + _size.X);
+ newRect._size.Y = Mathf.Max(b._position.Y + b._size.Y, _position.Y + _size.Y);
newRect._size -= newRect._position; // Make relative again
@@ -426,7 +427,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The other object to compare.</param>
/// <returns>Whether or not the rect and the other object are exactly equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Rect2 other && Equals(other);
}
@@ -436,7 +437,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other rect to compare.</param>
/// <returns>Whether or not the rects are exactly equal.</returns>
- public bool Equals(Rect2 other)
+ public readonly bool Equals(Rect2 other)
{
return _position.Equals(other._position) && _size.Equals(other._size);
}
@@ -447,7 +448,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other rect to compare.</param>
/// <returns>Whether or not the rects are approximately equal.</returns>
- public bool IsEqualApprox(Rect2 other)
+ public readonly bool IsEqualApprox(Rect2 other)
{
return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other.Size);
}
@@ -456,7 +457,7 @@ namespace Godot
/// Serves as the hash function for <see cref="Rect2"/>.
/// </summary>
/// <returns>A hash code for this rect.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
return _position.GetHashCode() ^ _size.GetHashCode();
}
@@ -465,7 +466,7 @@ namespace Godot
/// Converts this <see cref="Rect2"/> to a string.
/// </summary>
/// <returns>A string representation of this rect.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
return $"{_position}, {_size}";
}
@@ -474,7 +475,7 @@ namespace Godot
/// Converts this <see cref="Rect2"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this rect.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
return $"{_position.ToString(format)}, {_size.ToString(format)}";
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs
index b2768476cc..2099d0abca 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs
@@ -4,23 +4,23 @@ using System.Runtime.InteropServices;
namespace Godot
{
/// <summary>
- /// 2D axis-aligned bounding box using integers. Rect2i consists of a position, a size, and
+ /// 2D axis-aligned bounding box using integers. Rect2I consists of a position, a size, and
/// several utility functions. It is typically used for fast overlap tests.
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
- public struct Rect2i : IEquatable<Rect2i>
+ public struct Rect2I : IEquatable<Rect2I>
{
- private Vector2i _position;
- private Vector2i _size;
+ private Vector2I _position;
+ private Vector2I _size;
/// <summary>
/// Beginning corner. Typically has values lower than <see cref="End"/>.
/// </summary>
/// <value>Directly uses a private field.</value>
- public Vector2i Position
+ public Vector2I Position
{
- get { return _position; }
+ readonly get { return _position; }
set { _position = value; }
}
@@ -29,9 +29,9 @@ namespace Godot
/// If the size is negative, you can use <see cref="Abs"/> to fix it.
/// </summary>
/// <value>Directly uses a private field.</value>
- public Vector2i Size
+ public Vector2I Size
{
- get { return _size; }
+ readonly get { return _size; }
set { _size = value; }
}
@@ -43,105 +43,105 @@ namespace Godot
/// Getting is equivalent to <paramref name="value"/> = <see cref="Position"/> + <see cref="Size"/>,
/// setting is equivalent to <see cref="Size"/> = <paramref name="value"/> - <see cref="Position"/>
/// </value>
- public Vector2i End
+ public Vector2I End
{
- get { return _position + _size; }
+ readonly get { return _position + _size; }
set { _size = value - _position; }
}
/// <summary>
- /// The area of this <see cref="Rect2i"/>.
+ /// The area of this <see cref="Rect2I"/>.
+ /// See also <see cref="HasArea"/>.
/// </summary>
- /// <value>Equivalent to <see cref="GetArea()"/>.</value>
- public int Area
+ public readonly int Area
{
- get { return GetArea(); }
+ get { return _size.X * _size.Y; }
}
/// <summary>
- /// Returns a <see cref="Rect2i"/> with equivalent position and size, modified so that
+ /// Returns a <see cref="Rect2I"/> with equivalent position and size, modified so that
/// the top-left corner is the origin and width and height are positive.
/// </summary>
- /// <returns>The modified <see cref="Rect2i"/>.</returns>
- public Rect2i Abs()
+ /// <returns>The modified <see cref="Rect2I"/>.</returns>
+ public readonly Rect2I Abs()
{
- Vector2i end = End;
- Vector2i topLeft = new Vector2i(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y));
- return new Rect2i(topLeft, _size.Abs());
+ Vector2I end = End;
+ Vector2I topLeft = new Vector2I(Mathf.Min(_position.X, end.X), Mathf.Min(_position.Y, end.Y));
+ return new Rect2I(topLeft, _size.Abs());
}
/// <summary>
- /// Returns the intersection of this <see cref="Rect2i"/> and <paramref name="b"/>.
- /// If the rectangles do not intersect, an empty <see cref="Rect2i"/> is returned.
+ /// Returns the intersection of this <see cref="Rect2I"/> and <paramref name="b"/>.
+ /// If the rectangles do not intersect, an empty <see cref="Rect2I"/> is returned.
/// </summary>
- /// <param name="b">The other <see cref="Rect2i"/>.</param>
+ /// <param name="b">The other <see cref="Rect2I"/>.</param>
/// <returns>
- /// The intersection of this <see cref="Rect2i"/> and <paramref name="b"/>,
- /// or an empty <see cref="Rect2i"/> if they do not intersect.
+ /// The intersection of this <see cref="Rect2I"/> and <paramref name="b"/>,
+ /// or an empty <see cref="Rect2I"/> if they do not intersect.
/// </returns>
- public Rect2i Intersection(Rect2i b)
+ public readonly Rect2I Intersection(Rect2I b)
{
- Rect2i newRect = b;
+ Rect2I newRect = b;
if (!Intersects(newRect))
{
- return new Rect2i();
+ return new Rect2I();
}
- newRect._position.x = Mathf.Max(b._position.x, _position.x);
- newRect._position.y = Mathf.Max(b._position.y, _position.y);
+ newRect._position.X = Mathf.Max(b._position.X, _position.X);
+ newRect._position.Y = Mathf.Max(b._position.Y, _position.Y);
- Vector2i bEnd = b._position + b._size;
- Vector2i end = _position + _size;
+ Vector2I bEnd = b._position + b._size;
+ Vector2I end = _position + _size;
- newRect._size.x = Mathf.Min(bEnd.x, end.x) - newRect._position.x;
- newRect._size.y = Mathf.Min(bEnd.y, end.y) - newRect._position.y;
+ newRect._size.X = Mathf.Min(bEnd.X, end.X) - newRect._position.X;
+ newRect._size.Y = Mathf.Min(bEnd.Y, end.Y) - newRect._position.Y;
return newRect;
}
/// <summary>
- /// Returns <see langword="true"/> if this <see cref="Rect2i"/> completely encloses another one.
+ /// Returns <see langword="true"/> if this <see cref="Rect2I"/> completely encloses another one.
/// </summary>
- /// <param name="b">The other <see cref="Rect2i"/> that may be enclosed.</param>
+ /// <param name="b">The other <see cref="Rect2I"/> that may be enclosed.</param>
/// <returns>
- /// A <see langword="bool"/> for whether or not this <see cref="Rect2i"/> encloses <paramref name="b"/>.
+ /// A <see langword="bool"/> for whether or not this <see cref="Rect2I"/> encloses <paramref name="b"/>.
/// </returns>
- public bool Encloses(Rect2i b)
+ public readonly bool Encloses(Rect2I b)
{
- return b._position.x >= _position.x && b._position.y >= _position.y &&
- b._position.x + b._size.x < _position.x + _size.x &&
- b._position.y + b._size.y < _position.y + _size.y;
+ return b._position.X >= _position.X && b._position.Y >= _position.Y &&
+ b._position.X + b._size.X < _position.X + _size.X &&
+ b._position.Y + b._size.Y < _position.Y + _size.Y;
}
/// <summary>
- /// Returns this <see cref="Rect2i"/> expanded to include a given point.
+ /// Returns this <see cref="Rect2I"/> expanded to include a given point.
/// </summary>
/// <param name="to">The point to include.</param>
- /// <returns>The expanded <see cref="Rect2i"/>.</returns>
- public Rect2i Expand(Vector2i to)
+ /// <returns>The expanded <see cref="Rect2I"/>.</returns>
+ public readonly Rect2I Expand(Vector2I to)
{
- Rect2i expanded = this;
+ Rect2I expanded = this;
- Vector2i begin = expanded._position;
- Vector2i end = expanded._position + expanded._size;
+ Vector2I begin = expanded._position;
+ Vector2I end = expanded._position + expanded._size;
- if (to.x < begin.x)
+ if (to.X < begin.X)
{
- begin.x = to.x;
+ begin.X = to.X;
}
- if (to.y < begin.y)
+ if (to.Y < begin.Y)
{
- begin.y = to.y;
+ begin.Y = to.Y;
}
- if (to.x > end.x)
+ if (to.X > end.X)
{
- end.x = to.x;
+ end.X = to.X;
}
- if (to.y > end.y)
+ if (to.Y > end.Y)
{
- end.y = to.y;
+ end.Y = to.Y;
}
expanded._position = begin;
@@ -151,48 +151,39 @@ namespace Godot
}
/// <summary>
- /// Returns the area of the <see cref="Rect2i"/>.
- /// </summary>
- /// <returns>The area.</returns>
- public int GetArea()
- {
- return _size.x * _size.y;
- }
-
- /// <summary>
- /// Returns the center of the <see cref="Rect2i"/>, which is equal
+ /// Returns the center of the <see cref="Rect2I"/>, which is equal
/// to <see cref="Position"/> + (<see cref="Size"/> / 2).
/// If <see cref="Size"/> is an odd number, the returned center
/// value will be rounded towards <see cref="Position"/>.
/// </summary>
/// <returns>The center.</returns>
- public Vector2i GetCenter()
+ public readonly Vector2I GetCenter()
{
return _position + (_size / 2);
}
/// <summary>
- /// Returns a copy of the <see cref="Rect2i"/> grown by the specified amount
+ /// Returns a copy of the <see cref="Rect2I"/> grown by the specified amount
/// on all sides.
/// </summary>
/// <seealso cref="GrowIndividual(int, int, int, int)"/>
/// <seealso cref="GrowSide(Side, int)"/>
/// <param name="by">The amount to grow by.</param>
- /// <returns>The grown <see cref="Rect2i"/>.</returns>
- public Rect2i Grow(int by)
+ /// <returns>The grown <see cref="Rect2I"/>.</returns>
+ public readonly Rect2I Grow(int by)
{
- Rect2i g = this;
+ Rect2I g = this;
- g._position.x -= by;
- g._position.y -= by;
- g._size.x += by * 2;
- g._size.y += by * 2;
+ g._position.X -= by;
+ g._position.Y -= by;
+ g._size.X += by * 2;
+ g._size.Y += by * 2;
return g;
}
/// <summary>
- /// Returns a copy of the <see cref="Rect2i"/> grown by the specified amount
+ /// Returns a copy of the <see cref="Rect2I"/> grown by the specified amount
/// on each side individually.
/// </summary>
/// <seealso cref="Grow(int)"/>
@@ -201,31 +192,31 @@ namespace Godot
/// <param name="top">The amount to grow by on the top side.</param>
/// <param name="right">The amount to grow by on the right side.</param>
/// <param name="bottom">The amount to grow by on the bottom side.</param>
- /// <returns>The grown <see cref="Rect2i"/>.</returns>
- public Rect2i GrowIndividual(int left, int top, int right, int bottom)
+ /// <returns>The grown <see cref="Rect2I"/>.</returns>
+ public readonly Rect2I GrowIndividual(int left, int top, int right, int bottom)
{
- Rect2i g = this;
+ Rect2I g = this;
- g._position.x -= left;
- g._position.y -= top;
- g._size.x += left + right;
- g._size.y += top + bottom;
+ g._position.X -= left;
+ g._position.Y -= top;
+ g._size.X += left + right;
+ g._size.Y += top + bottom;
return g;
}
/// <summary>
- /// Returns a copy of the <see cref="Rect2i"/> grown by the specified amount
+ /// Returns a copy of the <see cref="Rect2I"/> grown by the specified amount
/// on the specified <see cref="Side"/>.
/// </summary>
/// <seealso cref="Grow(int)"/>
/// <seealso cref="GrowIndividual(int, int, int, int)"/>
/// <param name="side">The side to grow.</param>
/// <param name="by">The amount to grow by.</param>
- /// <returns>The grown <see cref="Rect2i"/>.</returns>
- public Rect2i GrowSide(Side side, int by)
+ /// <returns>The grown <see cref="Rect2I"/>.</returns>
+ public readonly Rect2I GrowSide(Side side, int by)
{
- Rect2i g = this;
+ Rect2I g = this;
g = g.GrowIndividual(Side.Left == side ? by : 0,
Side.Top == side ? by : 0,
@@ -236,95 +227,76 @@ namespace Godot
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="Rect2i"/> has
- /// area, and <see langword="false"/> if the <see cref="Rect2i"/>
+ /// Returns <see langword="true"/> if the <see cref="Rect2I"/> has
+ /// area, and <see langword="false"/> if the <see cref="Rect2I"/>
/// is linear, empty, or has a negative <see cref="Size"/>.
- /// See also <see cref="GetArea"/>.
+ /// See also <see cref="Area"/>.
/// </summary>
/// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="Rect2i"/> has area.
+ /// A <see langword="bool"/> for whether or not the <see cref="Rect2I"/> has area.
/// </returns>
- public bool HasArea()
+ public readonly bool HasArea()
{
- return _size.x > 0 && _size.y > 0;
+ return _size.X > 0 && _size.Y > 0;
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="Rect2i"/> contains a point,
+ /// Returns <see langword="true"/> if the <see cref="Rect2I"/> contains a point,
/// or <see langword="false"/> otherwise.
/// </summary>
/// <param name="point">The point to check.</param>
/// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="Rect2i"/> contains <paramref name="point"/>.
+ /// A <see langword="bool"/> for whether or not the <see cref="Rect2I"/> contains <paramref name="point"/>.
/// </returns>
- public bool HasPoint(Vector2i point)
+ public readonly bool HasPoint(Vector2I point)
{
- if (point.x < _position.x)
+ if (point.X < _position.X)
return false;
- if (point.y < _position.y)
+ if (point.Y < _position.Y)
return false;
- if (point.x >= _position.x + _size.x)
+ if (point.X >= _position.X + _size.X)
return false;
- if (point.y >= _position.y + _size.y)
+ if (point.Y >= _position.Y + _size.Y)
return false;
return true;
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="Rect2i"/> overlaps with <paramref name="b"/>
+ /// Returns <see langword="true"/> if the <see cref="Rect2I"/> overlaps with <paramref name="b"/>
/// (i.e. they have at least one point in common).
- ///
- /// If <paramref name="includeBorders"/> is <see langword="true"/>,
- /// they will also be considered overlapping if their borders touch,
- /// even without intersection.
/// </summary>
- /// <param name="b">The other <see cref="Rect2i"/> to check for intersections with.</param>
- /// <param name="includeBorders">Whether or not to consider borders.</param>
+ /// <param name="b">The other <see cref="Rect2I"/> to check for intersections with.</param>
/// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns>
- public bool Intersects(Rect2i b, bool includeBorders = false)
+ public readonly bool Intersects(Rect2I b)
{
- if (includeBorders)
- {
- if (_position.x > b._position.x + b._size.x)
- return false;
- if (_position.x + _size.x < b._position.x)
- return false;
- if (_position.y > b._position.y + b._size.y)
- return false;
- if (_position.y + _size.y < b._position.y)
- return false;
- }
- else
- {
- if (_position.x >= b._position.x + b._size.x)
- return false;
- if (_position.x + _size.x <= b._position.x)
- return false;
- if (_position.y >= b._position.y + b._size.y)
- return false;
- if (_position.y + _size.y <= b._position.y)
- return false;
- }
+ if (_position.X >= b._position.X + b._size.X)
+ return false;
+ if (_position.X + _size.X <= b._position.X)
+ return false;
+ if (_position.Y >= b._position.Y + b._size.Y)
+ return false;
+ if (_position.Y + _size.Y <= b._position.Y)
+ return false;
return true;
}
/// <summary>
- /// Returns a larger <see cref="Rect2i"/> that contains this <see cref="Rect2i"/> and <paramref name="b"/>.
+ /// Returns a larger <see cref="Rect2I"/> that contains this <see cref="Rect2I"/> and <paramref name="b"/>.
/// </summary>
- /// <param name="b">The other <see cref="Rect2i"/>.</param>
- /// <returns>The merged <see cref="Rect2i"/>.</returns>
- public Rect2i Merge(Rect2i b)
+ /// <param name="b">The other <see cref="Rect2I"/>.</param>
+ /// <returns>The merged <see cref="Rect2I"/>.</returns>
+ public readonly Rect2I Merge(Rect2I b)
{
- Rect2i newRect;
+ Rect2I newRect;
- newRect._position.x = Mathf.Min(b._position.x, _position.x);
- newRect._position.y = Mathf.Min(b._position.y, _position.y);
+ newRect._position.X = Mathf.Min(b._position.X, _position.X);
+ newRect._position.Y = Mathf.Min(b._position.Y, _position.Y);
- newRect._size.x = Mathf.Max(b._position.x + b._size.x, _position.x + _size.x);
- newRect._size.y = Mathf.Max(b._position.y + b._size.y, _position.y + _size.y);
+ newRect._size.X = Mathf.Max(b._position.X + b._size.X, _position.X + _size.X);
+ newRect._size.Y = Mathf.Max(b._position.Y + b._size.Y, _position.Y + _size.Y);
newRect._size -= newRect._position; // Make relative again
@@ -332,93 +304,93 @@ namespace Godot
}
/// <summary>
- /// Constructs a <see cref="Rect2i"/> from a position and size.
+ /// Constructs a <see cref="Rect2I"/> from a position and size.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="size">The size.</param>
- public Rect2i(Vector2i position, Vector2i size)
+ public Rect2I(Vector2I position, Vector2I size)
{
_position = position;
_size = size;
}
/// <summary>
- /// Constructs a <see cref="Rect2i"/> from a position, width, and height.
+ /// Constructs a <see cref="Rect2I"/> from a position, width, and height.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
- public Rect2i(Vector2i position, int width, int height)
+ public Rect2I(Vector2I position, int width, int height)
{
_position = position;
- _size = new Vector2i(width, height);
+ _size = new Vector2I(width, height);
}
/// <summary>
- /// Constructs a <see cref="Rect2i"/> from x, y, and size.
+ /// Constructs a <see cref="Rect2I"/> from x, y, and size.
/// </summary>
/// <param name="x">The position's X coordinate.</param>
/// <param name="y">The position's Y coordinate.</param>
/// <param name="size">The size.</param>
- public Rect2i(int x, int y, Vector2i size)
+ public Rect2I(int x, int y, Vector2I size)
{
- _position = new Vector2i(x, y);
+ _position = new Vector2I(x, y);
_size = size;
}
/// <summary>
- /// Constructs a <see cref="Rect2i"/> from x, y, width, and height.
+ /// Constructs a <see cref="Rect2I"/> from x, y, width, and height.
/// </summary>
/// <param name="x">The position's X coordinate.</param>
/// <param name="y">The position's Y coordinate.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
- public Rect2i(int x, int y, int width, int height)
+ public Rect2I(int x, int y, int width, int height)
{
- _position = new Vector2i(x, y);
- _size = new Vector2i(width, height);
+ _position = new Vector2I(x, y);
+ _size = new Vector2I(width, height);
}
/// <summary>
/// Returns <see langword="true"/> if the
- /// <see cref="Rect2i"/>s are exactly equal.
+ /// <see cref="Rect2I"/>s are exactly equal.
/// </summary>
/// <param name="left">The left rect.</param>
/// <param name="right">The right rect.</param>
/// <returns>Whether or not the rects are equal.</returns>
- public static bool operator ==(Rect2i left, Rect2i right)
+ public static bool operator ==(Rect2I left, Rect2I right)
{
return left.Equals(right);
}
/// <summary>
/// Returns <see langword="true"/> if the
- /// <see cref="Rect2i"/>s are not equal.
+ /// <see cref="Rect2I"/>s are not equal.
/// </summary>
/// <param name="left">The left rect.</param>
/// <param name="right">The right rect.</param>
/// <returns>Whether or not the rects are not equal.</returns>
- public static bool operator !=(Rect2i left, Rect2i right)
+ public static bool operator !=(Rect2I left, Rect2I right)
{
return !left.Equals(right);
}
/// <summary>
- /// Converts this <see cref="Rect2i"/> to a <see cref="Rect2"/>.
+ /// Converts this <see cref="Rect2I"/> to a <see cref="Rect2"/>.
/// </summary>
/// <param name="value">The rect to convert.</param>
- public static implicit operator Rect2(Rect2i value)
+ public static implicit operator Rect2(Rect2I value)
{
return new Rect2(value._position, value._size);
}
/// <summary>
- /// Converts a <see cref="Rect2"/> to a <see cref="Rect2i"/>.
+ /// Converts a <see cref="Rect2"/> to a <see cref="Rect2I"/>.
/// </summary>
/// <param name="value">The rect to convert.</param>
- public static explicit operator Rect2i(Rect2 value)
+ public static explicit operator Rect2I(Rect2 value)
{
- return new Rect2i((Vector2i)value.Position, (Vector2i)value.Size);
+ return new Rect2I((Vector2I)value.Position, (Vector2I)value.Size);
}
/// <summary>
@@ -426,9 +398,9 @@ namespace Godot
/// </summary>
/// <param name="obj">The other object to compare.</param>
/// <returns>Whether or not the rect and the other object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
- return obj is Rect2i other && Equals(other);
+ return obj is Rect2I other && Equals(other);
}
/// <summary>
@@ -436,34 +408,34 @@ namespace Godot
/// </summary>
/// <param name="other">The other rect to compare.</param>
/// <returns>Whether or not the rects are equal.</returns>
- public bool Equals(Rect2i other)
+ public readonly bool Equals(Rect2I other)
{
return _position.Equals(other._position) && _size.Equals(other._size);
}
/// <summary>
- /// Serves as the hash function for <see cref="Rect2i"/>.
+ /// Serves as the hash function for <see cref="Rect2I"/>.
/// </summary>
/// <returns>A hash code for this rect.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
return _position.GetHashCode() ^ _size.GetHashCode();
}
/// <summary>
- /// Converts this <see cref="Rect2i"/> to a string.
+ /// Converts this <see cref="Rect2I"/> to a string.
/// </summary>
/// <returns>A string representation of this rect.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
return $"{_position}, {_size}";
}
/// <summary>
- /// Converts this <see cref="Rect2i"/> to a string with the given <paramref name="format"/>.
+ /// Converts this <see cref="Rect2I"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this rect.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
return $"{_position.ToString(format)}, {_size.ToString(format)}";
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs
new file mode 100644
index 0000000000..350626389b
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
+namespace Godot
+{
+ /// <summary>
+ /// The RID type is used to access a low-level resource by its unique ID.
+ /// RIDs are opaque, which means they do not grant access to the resource
+ /// by themselves. They are used by the low-level server classes, such as
+ /// <see cref="DisplayServer"/>, <see cref="RenderingServer"/>,
+ /// <see cref="TextServer"/>, etc.
+ ///
+ /// A low-level resource may correspond to a high-level <see cref="Resource"/>,
+ /// such as <see cref="Texture"/> or <see cref="Mesh"/>
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public readonly struct Rid : IEquatable<Rid>
+ {
+ private readonly ulong _id; // Default is 0
+
+ internal Rid(ulong id)
+ {
+ _id = id;
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Rid"/> for the given <see cref="GodotObject"/> <paramref name="from"/>.
+ /// </summary>
+ public Rid(GodotObject from)
+ => _id = from is Resource res ? res.GetRid()._id : default;
+
+ /// <summary>
+ /// Returns the ID of the referenced low-level resource.
+ /// </summary>
+ /// <returns>The ID of the referenced resource.</returns>
+ public ulong Id => _id;
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the <see cref="Rid"/> is not <c>0</c>.
+ /// </summary>
+ /// <returns>Whether or not the ID is valid.</returns>
+ public bool IsValid => _id != 0;
+
+ /// <summary>
+ /// Returns <see langword="true"/> if both <see cref="Rid"/>s are equal,
+ /// which means they both refer to the same low-level resource.
+ /// </summary>
+ /// <param name="left">The left RID.</param>
+ /// <param name="right">The right RID.</param>
+ /// <returns>Whether or not the RIDs are equal.</returns>
+ public static bool operator ==(Rid left, Rid right)
+ {
+ return left.Equals(right);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the <see cref="Rid"/>s are not equal.
+ /// </summary>
+ /// <param name="left">The left RID.</param>
+ /// <param name="right">The right RID.</param>
+ /// <returns>Whether or not the RIDs are equal.</returns>
+ public static bool operator !=(Rid left, Rid right)
+ {
+ return !left.Equals(right);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this RID and <paramref name="obj"/> are equal.
+ /// </summary>
+ /// <param name="obj">The other object to compare.</param>
+ /// <returns>Whether or not the color and the other object are equal.</returns>
+ public override readonly bool Equals(object obj)
+ {
+ return obj is Rid other && Equals(other);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the RIDs are equal.
+ /// </summary>
+ /// <param name="other">The other RID.</param>
+ /// <returns>Whether or not the RIDs are equal.</returns>
+ public readonly bool Equals(Rid other)
+ {
+ return _id == other.Id;
+ }
+
+ /// <summary>
+ /// Serves as the hash function for <see cref="Rid"/>.
+ /// </summary>
+ /// <returns>A hash code for this RID.</returns>
+ public override readonly int GetHashCode()
+ {
+ return HashCode.Combine(_id);
+ }
+
+ /// <summary>
+ /// Converts this <see cref="Rid"/> to a string.
+ /// </summary>
+ /// <returns>A string representation of this Rid.</returns>
+ public override string ToString() => $"RID({Id})";
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Signal.cs
index 3f50df0a0d..9ac8abd37b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Signal.cs
@@ -3,30 +3,36 @@ namespace Godot
/// <summary>
/// Represents a signal defined in an object.
/// </summary>
- public readonly struct SignalInfo
+ public readonly struct Signal : IAwaitable<Variant[]>
{
- private readonly Object _owner;
+ private readonly GodotObject _owner;
private readonly StringName _signalName;
/// <summary>
/// Object that contains the signal.
/// </summary>
- public Object Owner => _owner;
+ public GodotObject Owner => _owner;
+
/// <summary>
/// Name of the signal.
/// </summary>
public StringName Name => _signalName;
/// <summary>
- /// Creates a new <see cref="SignalInfo"/> with the name <paramref name="name"/>
+ /// Creates a new <see cref="Signal"/> with the name <paramref name="name"/>
/// in the specified <paramref name="owner"/>.
/// </summary>
/// <param name="owner">Object that contains the signal.</param>
/// <param name="name">Name of the signal.</param>
- public SignalInfo(Object owner, StringName name)
+ public Signal(GodotObject owner, StringName name)
{
_owner = owner;
_signalName = name;
}
+
+ public IAwaiter<Variant[]> GetAwaiter()
+ {
+ return new SignalAwaiter(_owner, _signalName, _owner);
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
index 96fb891086..a67f626d35 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
@@ -10,13 +10,13 @@ namespace Godot
private Variant[] _result;
private Action _continuation;
- public SignalAwaiter(Object source, StringName signal, Object target)
+ public SignalAwaiter(GodotObject source, StringName signal, GodotObject target)
{
var awaiterGcHandle = CustomGCHandle.AllocStrong(this);
using godot_string_name signalSrc = NativeFuncs.godotsharp_string_name_new_copy(
(godot_string_name)(signal?.NativeValue ?? default));
- NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), in signalSrc,
- Object.GetPtr(target), GCHandle.ToIntPtr(awaiterGcHandle));
+ NativeFuncs.godotsharp_internal_signal_awaiter_connect(GodotObject.GetPtr(source), in signalSrc,
+ GodotObject.GetPtr(target), GCHandle.ToIntPtr(awaiterGcHandle));
}
public bool IsCompleted => _completed;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index d77baab24b..df67e075ac 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Security;
+using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using Godot.NativeInterop;
@@ -67,36 +69,6 @@ namespace Godot
}
/// <summary>
- /// If the string is a path to a file, return the path to the file without the extension.
- /// </summary>
- /// <seealso cref="GetExtension(string)"/>
- /// <seealso cref="GetBaseDir(string)"/>
- /// <seealso cref="GetFile(string)"/>
- /// <param name="instance">The path to a file.</param>
- /// <returns>The path to the file without the extension.</returns>
- public static string GetBaseName(this string instance)
- {
- int index = instance.LastIndexOf('.');
-
- if (index > 0)
- return instance.Substring(0, index);
-
- return instance;
- }
-
- /// <summary>
- /// Returns <see langword="true"/> if the strings begins
- /// with the given string <paramref name="text"/>.
- /// </summary>
- /// <param name="instance">The string to check.</param>
- /// <param name="text">The beginning string.</param>
- /// <returns>If the string begins with the given string.</returns>
- public static bool BeginsWith(this string instance, string text)
- {
- return instance.StartsWith(text);
- }
-
- /// <summary>
/// Returns the bigrams (pairs of consecutive letters) of this string.
/// </summary>
/// <param name="instance">The string that will be used.</param>
@@ -144,15 +116,15 @@ namespace Godot
}
/// <summary>
- /// Returns the amount of substrings <paramref name="what"/> in the string.
+ /// Returns the number of occurrences of substring <paramref name="what"/> in the string.
/// </summary>
/// <param name="instance">The string where the substring will be searched.</param>
/// <param name="what">The substring that will be counted.</param>
- /// <param name="caseSensitive">If the search is case sensitive.</param>
/// <param name="from">Index to start searching from.</param>
/// <param name="to">Index to stop searching at.</param>
- /// <returns>Amount of substrings in the string.</returns>
- public static int Count(this string instance, string what, bool caseSensitive = true, int from = 0, int to = 0)
+ /// <param name="caseSensitive">If the search is case sensitive.</param>
+ /// <returns>Number of occurrences of the substring in the string.</returns>
+ public static int Count(this string instance, string what, int from = 0, int to = 0, bool caseSensitive = true)
{
if (what.Length == 0)
{
@@ -211,6 +183,82 @@ namespace Godot
}
/// <summary>
+ /// Returns the number of occurrences of substring <paramref name="what"/> (ignoring case)
+ /// between <paramref name="from"/> and <paramref name="to"/> positions. If <paramref name="from"/>
+ /// and <paramref name="to"/> equals 0 the whole string will be used. If only <paramref name="to"/>
+ /// equals 0 the remained substring will be used.
+ /// </summary>
+ /// <param name="instance">The string where the substring will be searched.</param>
+ /// <param name="what">The substring that will be counted.</param>
+ /// <param name="from">Index to start searching from.</param>
+ /// <param name="to">Index to stop searching at.</param>
+ /// <returns>Number of occurrences of the substring in the string.</returns>
+ public static int CountN(this string instance, string what, int from = 0, int to = 0)
+ {
+ return instance.Count(what, from, to, caseSensitive: false);
+ }
+
+ /// <summary>
+ /// Returns a copy of the string with indentation (leading tabs and spaces) removed.
+ /// See also <see cref="Indent"/> to add indentation.
+ /// </summary>
+ /// <param name="instance">The string to remove the indentation from.</param>
+ /// <returns>The string with the indentation removed.</returns>
+ public static string Dedent(this string instance)
+ {
+ var sb = new StringBuilder();
+ string indent = "";
+ bool hasIndent = false;
+ bool hasText = false;
+ int lineStart = 0;
+ int indentStop = -1;
+
+ for (int i = 0; i < instance.Length; i++)
+ {
+ char c = instance[i];
+ if (c == '\n')
+ {
+ if (hasText)
+ {
+ sb.Append(instance.Substring(indentStop, i - indentStop));
+ }
+ sb.Append('\n');
+ hasText = false;
+ lineStart = i + 1;
+ indentStop = -1;
+ }
+ else if (!hasText)
+ {
+ if (c > 32)
+ {
+ hasText = true;
+ if (!hasIndent)
+ {
+ hasIndent = true;
+ indent = instance.Substring(lineStart, i - lineStart);
+ indentStop = i;
+ }
+ }
+ if (hasIndent && indentStop < 0)
+ {
+ int j = i - lineStart;
+ if (j >= indent.Length || c != indent[j])
+ {
+ indentStop = i;
+ }
+ }
+ }
+ }
+
+ if (hasText)
+ {
+ sb.Append(instance.Substring(indentStop, instance.Length - indentStop));
+ }
+
+ return sb.ToString();
+ }
+
+ /// <summary>
/// Returns a copy of the string with special characters escaped using the C language standard.
/// </summary>
/// <param name="instance">The string to escape.</param>
@@ -229,7 +277,6 @@ namespace Godot
sb.Replace("\v", "\\v");
sb.Replace("\'", "\\'");
sb.Replace("\"", "\\\"");
- sb.Replace("?", "\\?");
return sb.ToString();
}
@@ -253,7 +300,6 @@ namespace Godot
sb.Replace("\\v", "\v");
sb.Replace("\\'", "\'");
sb.Replace("\\\"", "\"");
- sb.Replace("\\?", "?");
sb.Replace("\\\\", "\\");
return sb.ToString();
@@ -445,29 +491,6 @@ namespace Godot
}
/// <summary>
- /// Returns <see langword="true"/> if the strings ends
- /// with the given string <paramref name="text"/>.
- /// </summary>
- /// <param name="instance">The string to check.</param>
- /// <param name="text">The ending string.</param>
- /// <returns>If the string ends with the given string.</returns>
- public static bool EndsWith(this string instance, string text)
- {
- return instance.EndsWith(text);
- }
-
- /// <summary>
- /// Erase <paramref name="chars"/> characters from the string starting from <paramref name="pos"/>.
- /// </summary>
- /// <param name="instance">The string to modify.</param>
- /// <param name="pos">Starting position from which to erase.</param>
- /// <param name="chars">Amount of characters to erase.</param>
- public static void Erase(this StringBuilder instance, int pos, int chars)
- {
- instance.Remove(pos, chars);
- }
-
- /// <summary>
/// Returns the extension without the leading period character (<c>.</c>)
/// if the string is a valid file name or path. If the string does not contain
/// an extension, returns an empty string instead.
@@ -491,7 +514,7 @@ namespace Godot
/// <returns>The extension of the file or an empty string.</returns>
public static string GetExtension(this string instance)
{
- int pos = instance.FindLast(".");
+ int pos = instance.RFind(".");
if (pos < 0)
return instance;
@@ -500,12 +523,16 @@ namespace Godot
}
/// <summary>
- /// Find the first occurrence of a substring. Optionally, the search starting position can be passed.
+ /// Returns the index of the first occurrence of the specified string in this instance,
+ /// or <c>-1</c>. Optionally, the starting search index can be specified, continuing
+ /// to the end of the string.
+ /// Note: If you just want to know whether a string contains a substring, use the
+ /// <see cref="string.Contains(string)"/> method.
/// </summary>
/// <seealso cref="Find(string, char, int, bool)"/>
- /// <seealso cref="FindLast(string, string, bool)"/>
- /// <seealso cref="FindLast(string, string, int, bool)"/>
/// <seealso cref="FindN(string, string, int)"/>
+ /// <seealso cref="RFind(string, string, int, bool)"/>
+ /// <seealso cref="RFindN(string, string, int)"/>
/// <param name="instance">The string that will be searched.</param>
/// <param name="what">The substring to find.</param>
/// <param name="from">The search starting position.</param>
@@ -521,9 +548,9 @@ namespace Godot
/// Find the first occurrence of a char. Optionally, the search starting position can be passed.
/// </summary>
/// <seealso cref="Find(string, string, int, bool)"/>
- /// <seealso cref="FindLast(string, string, bool)"/>
- /// <seealso cref="FindLast(string, string, int, bool)"/>
/// <seealso cref="FindN(string, string, int)"/>
+ /// <seealso cref="RFind(string, string, int, bool)"/>
+ /// <seealso cref="RFindN(string, string, int)"/>
/// <param name="instance">The string that will be searched.</param>
/// <param name="what">The substring to find.</param>
/// <param name="from">The search starting position.</param>
@@ -531,50 +558,21 @@ namespace Godot
/// <returns>The first instance of the char, or -1 if not found.</returns>
public static int Find(this string instance, char what, int from = 0, bool caseSensitive = true)
{
- // TODO: Could be more efficient if we get a char version of `IndexOf`.
- // See https://github.com/dotnet/runtime/issues/44116
- return instance.IndexOf(what.ToString(), from,
- caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
- }
+ if (caseSensitive)
+ return instance.IndexOf(what, from);
- /// <summary>Find the last occurrence of a substring.</summary>
- /// <seealso cref="Find(string, string, int, bool)"/>
- /// <seealso cref="Find(string, char, int, bool)"/>
- /// <seealso cref="FindLast(string, string, int, bool)"/>
- /// <seealso cref="FindN(string, string, int)"/>
- /// <param name="instance">The string that will be searched.</param>
- /// <param name="what">The substring to find.</param>
- /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param>
- /// <returns>The starting position of the substring, or -1 if not found.</returns>
- public static int FindLast(this string instance, string what, bool caseSensitive = true)
- {
- return instance.FindLast(what, instance.Length - 1, caseSensitive);
- }
-
- /// <summary>Find the last occurrence of a substring specifying the search starting position.</summary>
- /// <seealso cref="Find(string, string, int, bool)"/>
- /// <seealso cref="Find(string, char, int, bool)"/>
- /// <seealso cref="FindLast(string, string, bool)"/>
- /// <seealso cref="FindN(string, string, int)"/>
- /// <param name="instance">The string that will be searched.</param>
- /// <param name="what">The substring to find.</param>
- /// <param name="from">The search starting position.</param>
- /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param>
- /// <returns>The starting position of the substring, or -1 if not found.</returns>
- public static int FindLast(this string instance, string what, int from, bool caseSensitive = true)
- {
- return instance.LastIndexOf(what, from,
- caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+ return CultureInfo.InvariantCulture.CompareInfo.IndexOf(instance, what, from, CompareOptions.OrdinalIgnoreCase);
}
/// <summary>
- /// Find the first occurrence of a substring but search as case-insensitive.
- /// Optionally, the search starting position can be passed.
+ /// Returns the index of the first case-insensitive occurrence of the specified string in this instance,
+ /// or <c>-1</c>. Optionally, the starting search index can be specified, continuing
+ /// to the end of the string.
/// </summary>
/// <seealso cref="Find(string, string, int, bool)"/>
/// <seealso cref="Find(string, char, int, bool)"/>
- /// <seealso cref="FindLast(string, string, bool)"/>
- /// <seealso cref="FindLast(string, string, int, bool)"/>
+ /// <seealso cref="RFind(string, string, int, bool)"/>
+ /// <seealso cref="RFindN(string, string, int)"/>
/// <param name="instance">The string that will be searched.</param>
/// <param name="what">The substring to find.</param>
/// <param name="from">The search starting position.</param>
@@ -607,7 +605,7 @@ namespace Godot
}
else
{
- if (instance.BeginsWith("/"))
+ if (instance.StartsWith('/'))
{
rs = instance.Substring(1);
directory = "/";
@@ -618,7 +616,7 @@ namespace Godot
}
}
- int sep = Mathf.Max(rs.FindLast("/"), rs.FindLast("\\"));
+ int sep = Mathf.Max(rs.RFind("/"), rs.RFind("\\"));
if (sep == -1)
return directory;
@@ -627,6 +625,24 @@ namespace Godot
}
/// <summary>
+ /// If the string is a path to a file, return the path to the file without the extension.
+ /// </summary>
+ /// <seealso cref="GetExtension(string)"/>
+ /// <seealso cref="GetBaseDir(string)"/>
+ /// <seealso cref="GetFile(string)"/>
+ /// <param name="instance">The path to a file.</param>
+ /// <returns>The path to the file without the extension.</returns>
+ public static string GetBaseName(this string instance)
+ {
+ int index = instance.RFind(".");
+
+ if (index > 0)
+ return instance.Substring(0, index);
+
+ return instance;
+ }
+
+ /// <summary>
/// If the string is a path to a file, return the file and ignore the base directory.
/// </summary>
/// <seealso cref="GetBaseName(string)"/>
@@ -636,7 +652,7 @@ namespace Godot
/// <returns>The file name.</returns>
public static string GetFile(this string instance)
{
- int sep = Mathf.Max(instance.FindLast("/"), instance.FindLast("\\"));
+ int sep = Mathf.Max(instance.RFind("/"), instance.RFind("\\"));
if (sep == -1)
return instance;
@@ -645,30 +661,52 @@ namespace Godot
}
/// <summary>
- /// Converts the given byte array of ASCII encoded text to a string.
- /// Faster alternative to <see cref="GetStringFromUTF8"/> if the
+ /// Converts ASCII encoded array to string.
+ /// Fast alternative to <see cref="GetStringFromUtf8"/> if the
/// content is ASCII-only. Unlike the UTF-8 function this function
/// maps every byte to a character in the array. Multibyte sequences
/// will not be interpreted correctly. For parsing user input always
- /// use <see cref="GetStringFromUTF8"/>.
+ /// use <see cref="GetStringFromUtf8"/>.
/// </summary>
/// <param name="bytes">A byte array of ASCII characters (on the range of 0-127).</param>
/// <returns>A string created from the bytes.</returns>
- public static string GetStringFromASCII(this byte[] bytes)
+ public static string GetStringFromAscii(this byte[] bytes)
{
return Encoding.ASCII.GetString(bytes);
}
/// <summary>
- /// Converts the given byte array of UTF-8 encoded text to a string.
- /// Slower than <see cref="GetStringFromASCII"/> but supports UTF-8
+ /// Converts UTF-16 encoded array to string using the little endian byte order.
+ /// </summary>
+ /// <param name="bytes">A byte array of UTF-16 characters.</param>
+ /// <returns>A string created from the bytes.</returns>
+ public static string GetStringFromUtf16(this byte[] bytes)
+ {
+ return Encoding.Unicode.GetString(bytes);
+ }
+
+ /// <summary>
+ /// Converts UTF-32 encoded array to string using the little endian byte order.
+ /// </summary>
+ /// <param name="bytes">A byte array of UTF-32 characters.</param>
+ /// <returns>A string created from the bytes.</returns>
+ public static string GetStringFromUtf32(this byte[] bytes)
+ {
+ return Encoding.UTF32.GetString(bytes);
+ }
+
+ /// <summary>
+ /// Converts UTF-8 encoded array to string.
+ /// Slower than <see cref="GetStringFromAscii"/> but supports UTF-8
/// encoded data. Use this function if you are unsure about the
/// source of the data. For user input this function
/// should always be preferred.
/// </summary>
- /// <param name="bytes">A byte array of UTF-8 characters (a character may take up multiple bytes).</param>
+ /// <param name="bytes">
+ /// A byte array of UTF-8 characters (a character may take up multiple bytes).
+ /// </param>
/// <returns>A string created from the bytes.</returns>
- public static string GetStringFromUTF8(this byte[] bytes)
+ public static string GetStringFromUtf8(this byte[] bytes)
{
return Encoding.UTF8.GetString(bytes);
}
@@ -768,18 +806,44 @@ namespace Godot
}
/// <summary>
- /// Inserts a substring at a given position.
+ /// Returns a copy of the string with lines indented with <paramref name="prefix"/>.
+ /// For example, the string can be indented with two tabs using <c>"\t\t"</c>,
+ /// or four spaces using <c>" "</c>. The prefix can be any string so it can
+ /// also be used to comment out strings with e.g. <c>"// </c>.
+ /// See also <see cref="Dedent"/> to remove indentation.
+ /// Note: Empty lines are kept empty.
/// </summary>
- /// <param name="instance">The string to modify.</param>
- /// <param name="pos">Position at which to insert the substring.</param>
- /// <param name="what">Substring to insert.</param>
- /// <returns>
- /// The string with <paramref name="what"/> inserted at the given
- /// position <paramref name="pos"/>.
- /// </returns>
- public static string Insert(this string instance, int pos, string what)
+ /// <param name="instance">The string to add indentation to.</param>
+ /// <param name="prefix">The string to use as indentation.</param>
+ /// <returns>The string with indentation added.</returns>
+ public static string Indent(this string instance, string prefix)
{
- return instance.Insert(pos, what);
+ var sb = new StringBuilder();
+ int lineStart = 0;
+
+ for (int i = 0; i < instance.Length; i++)
+ {
+ char c = instance[i];
+ if (c == '\n')
+ {
+ if (i == lineStart)
+ {
+ sb.Append(c); // Leave empty lines empty.
+ }
+ else
+ {
+ sb.Append(prefix);
+ sb.Append(instance.Substring(lineStart, i - lineStart + 1));
+ }
+ lineStart = i + 1;
+ }
+ }
+ if (lineStart != instance.Length)
+ {
+ sb.Append(prefix);
+ sb.Append(instance.Substring(lineStart));
+ }
+ return sb.ToString();
}
/// <summary>
@@ -875,19 +939,94 @@ namespace Godot
return instance.IsSubsequenceOf(text, caseSensitive: false);
}
+ private static readonly char[] _invalidFileNameCharacters = { ':', '/', '\\', '?', '*', '"', '|', '%', '<', '>' };
+
/// <summary>
- /// Check whether the string contains a valid <see langword="float"/>.
+ /// Returns <see langword="true"/> if this string is free from characters that
+ /// aren't allowed in file names.
/// </summary>
/// <param name="instance">The string to check.</param>
+ /// <returns>If the string contains a valid file name.</returns>
+ public static bool IsValidFileName(this string instance)
+ {
+ var stripped = instance.Trim();
+ if (instance != stripped)
+ return false;
+
+ if (string.IsNullOrEmpty(stripped))
+ return false;
+
+ return instance.IndexOfAny(_invalidFileNameCharacters) == -1;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this string contains a valid <see langword="float"/>.
+ /// This is inclusive of integers, and also supports exponents.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print("1.7".IsValidFloat()) // Prints "True"
+ /// GD.Print("24".IsValidFloat()) // Prints "True"
+ /// GD.Print("7e3".IsValidFloat()) // Prints "True"
+ /// GD.Print("Hello".IsValidFloat()) // Prints "False"
+ /// </code>
+ /// </example>
+ /// <param name="instance">The string to check.</param>
/// <returns>If the string contains a valid floating point number.</returns>
public static bool IsValidFloat(this string instance)
{
- float f;
- return float.TryParse(instance, out f);
+ return float.TryParse(instance, out _);
}
/// <summary>
- /// Check whether the string contains a valid color in HTML notation.
+ /// Returns <see langword="true"/> if this string contains a valid hexadecimal number.
+ /// If <paramref name="withPrefix"/> is <see langword="true"/>, then a validity of the
+ /// hexadecimal number is determined by <c>0x</c> prefix, for instance: <c>0xDEADC0DE</c>.
+ /// </summary>
+ /// <param name="instance">The string to check.</param>
+ /// <param name="withPrefix">If the string must contain the <c>0x</c> prefix to be valid.</param>
+ /// <returns>If the string contains a valid hexadecimal number.</returns>
+ public static bool IsValidHexNumber(this string instance, bool withPrefix = false)
+ {
+ if (string.IsNullOrEmpty(instance))
+ return false;
+
+ int from = 0;
+ if (instance.Length != 1 && instance[0] == '+' || instance[0] == '-')
+ {
+ from++;
+ }
+
+ if (withPrefix)
+ {
+ if (instance.Length < 3)
+ return false;
+ if (instance[from] != '0' || instance[from + 1] != 'x')
+ return false;
+ from += 2;
+ }
+
+ for (int i = from; i < instance.Length; i++)
+ {
+ char c = instance[i];
+ if (IsHexDigit(c))
+ continue;
+
+ return false;
+ }
+
+ return true;
+
+ static bool IsHexDigit(char c)
+ {
+ return char.IsDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+ }
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this string contains a valid color in hexadecimal
+ /// HTML notation. Other HTML notations such as named colors or <c>hsl()</c> aren't
+ /// considered valid by this method and will return <see langword="false"/>.
/// </summary>
/// <param name="instance">The string to check.</param>
/// <returns>If the string contains a valid HTML color.</returns>
@@ -897,10 +1036,17 @@ namespace Godot
}
/// <summary>
- /// Check whether the string is a valid identifier. As is common in
- /// programming languages, a valid identifier may contain only letters,
- /// digits and underscores (_) and the first character may not be a digit.
+ /// Returns <see langword="true"/> if this string is a valid identifier.
+ /// A valid identifier may contain only letters, digits and underscores (<c>_</c>)
+ /// and the first character may not be a digit.
/// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print("good_ident_1".IsValidIdentifier()) // Prints "True"
+ /// GD.Print("1st_bad_ident".IsValidIdentifier()) // Prints "False"
+ /// GD.Print("bad_ident_#2".IsValidIdentifier()) // Prints "False"
+ /// </code>
+ /// </example>
/// <param name="instance">The string to check.</param>
/// <returns>If the string contains a valid identifier.</returns>
public static bool IsValidIdentifier(this string instance)
@@ -928,38 +1074,73 @@ namespace Godot
}
/// <summary>
- /// Check whether the string contains a valid integer.
+ /// Returns <see langword="true"/> if this string contains a valid <see langword="int"/>.
/// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print("7".IsValidInt()) // Prints "True"
+ /// GD.Print("14.6".IsValidInt()) // Prints "False"
+ /// GD.Print("L".IsValidInt()) // Prints "False"
+ /// GD.Print("+3".IsValidInt()) // Prints "True"
+ /// GD.Print("-12".IsValidInt()) // Prints "True"
+ /// </code>
+ /// </example>
/// <param name="instance">The string to check.</param>
/// <returns>If the string contains a valid integer.</returns>
- public static bool IsValidInteger(this string instance)
+ public static bool IsValidInt(this string instance)
{
- int f;
- return int.TryParse(instance, out f);
+ return int.TryParse(instance, out _);
}
/// <summary>
- /// Check whether the string contains a valid IP address.
+ /// Returns <see langword="true"/> if this string contains only a well-formatted
+ /// IPv4 or IPv6 address. This method considers reserved IP addresses such as
+ /// <c>0.0.0.0</c> as valid.
/// </summary>
/// <param name="instance">The string to check.</param>
/// <returns>If the string contains a valid IP address.</returns>
public static bool IsValidIPAddress(this string instance)
{
- // TODO: Support IPv6 addresses
- string[] ip = instance.Split(".");
+ if (instance.Contains(':'))
+ {
+ string[] ip = instance.Split(':');
- if (ip.Length != 4)
- return false;
+ for (int i = 0; i < ip.Length; i++)
+ {
+ string n = ip[i];
+ if (n.Length == 0)
+ continue;
+
+ if (n.IsValidHexNumber(withPrefix: false))
+ {
+ long nint = n.HexToInt();
+ if (nint < 0 || nint > 0xffff)
+ return false;
- for (int i = 0; i < ip.Length; i++)
+ continue;
+ }
+
+ if (!n.IsValidIPAddress())
+ return false;
+ }
+ }
+ else
{
- string n = ip[i];
- if (!n.IsValidInteger())
- return false;
+ string[] ip = instance.Split('.');
- int val = n.ToInt();
- if (val < 0 || val > 255)
+ if (ip.Length != 4)
return false;
+
+ for (int i = 0; i < ip.Length; i++)
+ {
+ string n = ip[i];
+ if (!n.IsValidInt())
+ return false;
+
+ int val = n.ToInt();
+ if (val < 0 || val > 255)
+ return false;
+ }
}
return true;
@@ -1005,44 +1186,6 @@ namespace Godot
}
/// <summary>
- /// Returns the length of the string in characters.
- /// </summary>
- /// <param name="instance">The string to check.</param>
- /// <returns>The length of the string.</returns>
- public static int Length(this string instance)
- {
- return instance.Length;
- }
-
- /// <summary>
- /// Returns a copy of the string with characters removed from the left.
- /// </summary>
- /// <seealso cref="RStrip(string, string)"/>
- /// <param name="instance">The string to remove characters from.</param>
- /// <param name="chars">The characters to be removed.</param>
- /// <returns>A copy of the string with characters removed from the left.</returns>
- public static string LStrip(this string instance, string chars)
- {
- int len = instance.Length;
- int beg;
-
- for (beg = 0; beg < len; beg++)
- {
- if (chars.Find(instance[beg]) == -1)
- {
- break;
- }
- }
-
- if (beg == 0)
- {
- return instance;
- }
-
- return instance.Substr(beg, len - beg);
- }
-
- /// <summary>
/// Do a simple expression match, where '*' matches zero or more
/// arbitrary characters and '?' matches any single character except '.'.
/// </summary>
@@ -1114,29 +1257,25 @@ namespace Godot
/// <summary>
/// Returns the MD5 hash of the string as an array of bytes.
/// </summary>
- /// <seealso cref="MD5Text(string)"/>
+ /// <seealso cref="Md5Text(string)"/>
/// <param name="instance">The string to hash.</param>
/// <returns>The MD5 hash of the string.</returns>
- public static byte[] MD5Buffer(this string instance)
+ public static byte[] Md5Buffer(this string instance)
{
- using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
- NativeFuncs.godotsharp_string_md5_buffer(instanceStr, out var md5Buffer);
- using (md5Buffer)
- return Marshaling.ConvertNativePackedByteArrayToSystemArray(md5Buffer);
+#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms
+ return MD5.HashData(Encoding.UTF8.GetBytes(instance));
+#pragma warning restore CA5351
}
/// <summary>
/// Returns the MD5 hash of the string as a string.
/// </summary>
- /// <seealso cref="MD5Buffer(string)"/>
+ /// <seealso cref="Md5Buffer(string)"/>
/// <param name="instance">The string to hash.</param>
/// <returns>The MD5 hash of the string.</returns>
- public static string MD5Text(this string instance)
+ public static string Md5Text(this string instance)
{
- using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
- NativeFuncs.godotsharp_string_md5_text(instanceStr, out var md5Text);
- using (md5Text)
- return Marshaling.ConvertStringToManaged(md5Text);
+ return instance.Md5Buffer().HexEncode();
}
/// <summary>
@@ -1153,17 +1292,6 @@ namespace Godot
}
/// <summary>
- /// Returns the character code at position <paramref name="at"/>.
- /// </summary>
- /// <param name="instance">The string to check.</param>
- /// <param name="at">The position int the string for the character to check.</param>
- /// <returns>The character code.</returns>
- public static int OrdAt(this string instance, int at)
- {
- return instance[at];
- }
-
- /// <summary>
/// Format a number to have an exact number of <paramref name="digits"/>
/// after the decimal point.
/// </summary>
@@ -1284,34 +1412,47 @@ namespace Godot
}
/// <summary>
- /// Perform a search for a substring, but start from the end of the string instead of the beginning.
+ /// Returns the index of the last occurrence of the specified string in this instance,
+ /// or <c>-1</c>. Optionally, the starting search index can be specified, continuing to
+ /// the beginning of the string.
/// </summary>
+ /// <seealso cref="Find(string, string, int, bool)"/>
+ /// <seealso cref="Find(string, char, int, bool)"/>
+ /// <seealso cref="FindN(string, string, int)"/>
/// <seealso cref="RFindN(string, string, int)"/>
/// <param name="instance">The string that will be searched.</param>
/// <param name="what">The substring to search in the string.</param>
/// <param name="from">The position at which to start searching.</param>
+ /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param>
/// <returns>The position at which the substring was found, or -1 if not found.</returns>
- public static int RFind(this string instance, string what, int from = -1)
+ public static int RFind(this string instance, string what, int from = -1, bool caseSensitive = true)
{
- using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
- using godot_string whatStr = Marshaling.ConvertStringToNative(instance);
- return NativeFuncs.godotsharp_string_rfind(instanceStr, whatStr, from);
+ if (from == -1)
+ from = instance.Length - 1;
+
+ return instance.LastIndexOf(what, from,
+ caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
}
/// <summary>
- /// Perform a search for a substring, but start from the end of the string instead of the beginning.
- /// Also search case-insensitive.
+ /// Returns the index of the last case-insensitive occurrence of the specified string in this instance,
+ /// or <c>-1</c>. Optionally, the starting search index can be specified, continuing to
+ /// the beginning of the string.
/// </summary>
- /// <seealso cref="RFind(string, string, int)"/>
+ /// <seealso cref="Find(string, string, int, bool)"/>
+ /// <seealso cref="Find(string, char, int, bool)"/>
+ /// <seealso cref="FindN(string, string, int)"/>
+ /// <seealso cref="RFind(string, string, int, bool)"/>
/// <param name="instance">The string that will be searched.</param>
/// <param name="what">The substring to search in the string.</param>
/// <param name="from">The position at which to start searching.</param>
/// <returns>The position at which the substring was found, or -1 if not found.</returns>
public static int RFindN(this string instance, string what, int from = -1)
{
- using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
- using godot_string whatStr = Marshaling.ConvertStringToNative(instance);
- return NativeFuncs.godotsharp_string_rfindn(instanceStr, whatStr, from);
+ if (from == -1)
+ from = instance.Length - 1;
+
+ return instance.LastIndexOf(what, from, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
@@ -1333,59 +1474,49 @@ namespace Godot
}
/// <summary>
- /// Returns a copy of the string with characters removed from the right.
+ /// Returns the SHA-1 hash of the string as an array of bytes.
/// </summary>
- /// <seealso cref="LStrip(string, string)"/>
- /// <param name="instance">The string to remove characters from.</param>
- /// <param name="chars">The characters to be removed.</param>
- /// <returns>A copy of the string with characters removed from the right.</returns>
- public static string RStrip(this string instance, string chars)
+ /// <seealso cref="Sha1Text(string)"/>
+ /// <param name="instance">The string to hash.</param>
+ /// <returns>The SHA-1 hash of the string.</returns>
+ public static byte[] Sha1Buffer(this string instance)
{
- int len = instance.Length;
- int end;
-
- for (end = len - 1; end >= 0; end--)
- {
- if (chars.Find(instance[end]) == -1)
- {
- break;
- }
- }
-
- if (end == len - 1)
- {
- return instance;
- }
+#pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms
+ return SHA1.HashData(Encoding.UTF8.GetBytes(instance));
+#pragma warning restore CA5350
+ }
- return instance.Substr(0, end + 1);
+ /// <summary>
+ /// Returns the SHA-1 hash of the string as a string.
+ /// </summary>
+ /// <seealso cref="Sha1Buffer(string)"/>
+ /// <param name="instance">The string to hash.</param>
+ /// <returns>The SHA-1 hash of the string.</returns>
+ public static string Sha1Text(this string instance)
+ {
+ return instance.Sha1Buffer().HexEncode();
}
/// <summary>
/// Returns the SHA-256 hash of the string as an array of bytes.
/// </summary>
- /// <seealso cref="SHA256Text(string)"/>
+ /// <seealso cref="Sha256Text(string)"/>
/// <param name="instance">The string to hash.</param>
/// <returns>The SHA-256 hash of the string.</returns>
- public static byte[] SHA256Buffer(this string instance)
+ public static byte[] Sha256Buffer(this string instance)
{
- using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
- NativeFuncs.godotsharp_string_sha256_buffer(instanceStr, out var sha256Buffer);
- using (sha256Buffer)
- return Marshaling.ConvertNativePackedByteArrayToSystemArray(sha256Buffer);
+ return SHA256.HashData(Encoding.UTF8.GetBytes(instance));
}
/// <summary>
/// Returns the SHA-256 hash of the string as a string.
/// </summary>
- /// <seealso cref="SHA256Buffer(string)"/>
+ /// <seealso cref="Sha256Buffer(string)"/>
/// <param name="instance">The string to hash.</param>
/// <returns>The SHA-256 hash of the string.</returns>
- public static string SHA256Text(this string instance)
+ public static string Sha256Text(this string instance)
{
- using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
- NativeFuncs.godotsharp_string_sha256_text(instanceStr, out var sha256Text);
- using (sha256Text)
- return Marshaling.ConvertStringToManaged(sha256Text);
+ return instance.Sha256Buffer().HexEncode();
}
/// <summary>
@@ -1457,7 +1588,7 @@ namespace Godot
/// <returns>The array of strings split from the string.</returns>
public static string[] Split(this string instance, string divisor, bool allowEmpty = true)
{
- return instance.Split(new[] { divisor },
+ return instance.Split(divisor,
allowEmpty ? StringSplitOptions.None : StringSplitOptions.RemoveEmptyEntries);
}
@@ -1505,8 +1636,10 @@ namespace Godot
};
/// <summary>
- /// Returns a copy of the string stripped of any non-printable character at the beginning and the end.
- /// The optional arguments are used to toggle stripping on the left and right edges respectively.
+ /// Returns a copy of the string stripped of any non-printable character
+ /// (including tabulations, spaces and line breaks) at the beginning and the end.
+ /// The optional arguments are used to toggle stripping on the left and right
+ /// edges respectively.
/// </summary>
/// <param name="instance">The string to strip.</param>
/// <param name="left">If the left side should be stripped.</param>
@@ -1524,6 +1657,30 @@ namespace Godot
return instance.TrimEnd(_nonPrintable);
}
+
+ /// <summary>
+ /// Returns a copy of the string stripped of any escape character.
+ /// These include all non-printable control characters of the first page
+ /// of the ASCII table (&lt; 32), such as tabulation (<c>\t</c>) and
+ /// newline (<c>\n</c> and <c>\r</c>) characters, but not spaces.
+ /// </summary>
+ /// <param name="instance">The string to strip.</param>
+ /// <returns>The string stripped of any escape characters.</returns>
+ public static string StripEscapes(this string instance)
+ {
+ var sb = new StringBuilder();
+ for (int i = 0; i < instance.Length; i++)
+ {
+ // Escape characters on first page of the ASCII table, before 32 (Space).
+ if (instance[i] < 32)
+ continue;
+
+ sb.Append(instance[i]);
+ }
+
+ return sb.ToString();
+ }
+
/// <summary>
/// Returns part of the string from the position <paramref name="from"/>, with length <paramref name="len"/>.
/// </summary>
@@ -1541,13 +1698,15 @@ namespace Godot
/// <summary>
/// Converts the String (which is a character array) to PackedByteArray (which is an array of bytes).
- /// The conversion is speeded up in comparison to <see cref="ToUTF8(string)"/> with the assumption
- /// that all the characters the String contains are only ASCII characters.
+ /// The conversion is faster compared to <see cref="ToUtf8Buffer(string)"/>,
+ /// as this method assumes that all the characters in the String are ASCII characters.
/// </summary>
- /// <seealso cref="ToUTF8(string)"/>
+ /// <seealso cref="ToUtf8Buffer(string)"/>
+ /// <seealso cref="ToUtf16Buffer(string)"/>
+ /// <seealso cref="ToUtf32Buffer(string)"/>
/// <param name="instance">The string to convert.</param>
/// <returns>The string as ASCII encoded bytes.</returns>
- public static byte[] ToAscii(this string instance)
+ public static byte[] ToAsciiBuffer(this string instance)
{
return Encoding.ASCII.GetBytes(instance);
}
@@ -1575,41 +1734,76 @@ namespace Godot
}
/// <summary>
- /// Returns the string converted to lowercase.
+ /// Converts the string (which is an array of characters) to an UTF-16 encoded array of bytes.
/// </summary>
- /// <seealso cref="ToUpper(string)"/>
+ /// <seealso cref="ToAsciiBuffer(string)"/>
+ /// <seealso cref="ToUtf32Buffer(string)"/>
+ /// <seealso cref="ToUtf8Buffer(string)"/>
/// <param name="instance">The string to convert.</param>
- /// <returns>The string converted to lowercase.</returns>
- public static string ToLower(this string instance)
+ /// <returns>The string as UTF-16 encoded bytes.</returns>
+ public static byte[] ToUtf16Buffer(this string instance)
{
- return instance.ToLower();
+ return Encoding.Unicode.GetBytes(instance);
}
/// <summary>
- /// Returns the string converted to uppercase.
+ /// Converts the string (which is an array of characters) to an UTF-32 encoded array of bytes.
/// </summary>
- /// <seealso cref="ToLower(string)"/>
+ /// <seealso cref="ToAsciiBuffer(string)"/>
+ /// <seealso cref="ToUtf16Buffer(string)"/>
+ /// <seealso cref="ToUtf8Buffer(string)"/>
/// <param name="instance">The string to convert.</param>
- /// <returns>The string converted to uppercase.</returns>
- public static string ToUpper(this string instance)
+ /// <returns>The string as UTF-32 encoded bytes.</returns>
+ public static byte[] ToUtf32Buffer(this string instance)
{
- return instance.ToUpper();
+ return Encoding.UTF32.GetBytes(instance);
}
/// <summary>
- /// Converts the String (which is an array of characters) to PackedByteArray (which is an array of bytes).
- /// The conversion is a bit slower than <see cref="ToAscii(string)"/>, but supports all UTF-8 characters.
- /// Therefore, you should prefer this function over <see cref="ToAscii(string)"/>.
+ /// Converts the string (which is an array of characters) to an UTF-8 encoded array of bytes.
+ /// The conversion is a bit slower than <see cref="ToAsciiBuffer(string)"/>,
+ /// but supports all UTF-8 characters. Therefore, you should prefer this function
+ /// over <see cref="ToAsciiBuffer(string)"/>.
/// </summary>
- /// <seealso cref="ToAscii(string)"/>
+ /// <seealso cref="ToAsciiBuffer(string)"/>
+ /// <seealso cref="ToUtf16Buffer(string)"/>
+ /// <seealso cref="ToUtf32Buffer(string)"/>
/// <param name="instance">The string to convert.</param>
/// <returns>The string as UTF-8 encoded bytes.</returns>
- public static byte[] ToUTF8(this string instance)
+ public static byte[] ToUtf8Buffer(this string instance)
{
return Encoding.UTF8.GetBytes(instance);
}
/// <summary>
+ /// Removes a given string from the start if it starts with it or leaves the string unchanged.
+ /// </summary>
+ /// <param name="instance">The string to remove the prefix from.</param>
+ /// <param name="prefix">The string to remove from the start.</param>
+ /// <returns>A copy of the string with the prefix string removed from the start.</returns>
+ public static string TrimPrefix(this string instance, string prefix)
+ {
+ if (instance.StartsWith(prefix))
+ return instance.Substring(prefix.Length);
+
+ return instance;
+ }
+
+ /// <summary>
+ /// Removes a given string from the end if it ends with it or leaves the string unchanged.
+ /// </summary>
+ /// <param name="instance">The string to remove the suffix from.</param>
+ /// <param name="suffix">The string to remove from the end.</param>
+ /// <returns>A copy of the string with the suffix string removed from the end.</returns>
+ public static string TrimSuffix(this string instance, string suffix)
+ {
+ if (instance.EndsWith(suffix))
+ return instance.Substring(0, instance.Length - suffix.Length);
+
+ return instance;
+ }
+
+ /// <summary>
/// Decodes a string in URL encoded format. This is meant to
/// decode parameters in a URL when receiving an HTTP request.
/// This mostly wraps around <see cref="Uri.UnescapeDataString"/>,
@@ -1636,6 +1830,25 @@ namespace Godot
return Uri.EscapeDataString(instance);
}
+ private const string _uniqueNodePrefix = "%";
+ private static readonly string[] _invalidNodeNameCharacters = { ".", ":", "@", "/", "\"", _uniqueNodePrefix };
+
+ /// <summary>
+ /// Removes any characters from the string that are prohibited in
+ /// <see cref="Node"/> names (<c>.</c> <c>:</c> <c>@</c> <c>/</c> <c>"</c>).
+ /// </summary>
+ /// <param name="instance">The string to sanitize.</param>
+ /// <returns>The string sanitized as a valid node name.</returns>
+ public static string ValidateNodeName(this string instance)
+ {
+ string name = instance.Replace(_invalidNodeNameCharacters[0], "");
+ for (int i = 1; i < _invalidNodeNameCharacters.Length; i++)
+ {
+ name = name.Replace(_invalidNodeNameCharacters[i], "");
+ }
+ return name;
+ }
+
/// <summary>
/// Returns a copy of the string with special characters escaped using the XML standard.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
index b9ee0bc278..97d28f9ee9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
@@ -10,7 +10,7 @@ namespace Godot
/// Comparing them is much faster than with regular strings, because only the pointers are compared,
/// not the whole strings.
/// </summary>
- public sealed class StringName : IDisposable
+ public sealed class StringName : IDisposable, IEquatable<StringName>
{
internal godot_string_name.movable NativeValue;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index 894667db76..d7392dbda8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Godot
@@ -18,61 +19,51 @@ namespace Godot
/// <summary>
/// The basis matrix's X vector (column 0). Equivalent to array index <c>[0]</c>.
/// </summary>
- public Vector2 x;
+ public Vector2 X;
/// <summary>
/// The basis matrix's Y vector (column 1). Equivalent to array index <c>[1]</c>.
/// </summary>
- public Vector2 y;
+ public Vector2 Y;
/// <summary>
/// The origin vector (column 2, the third column). Equivalent to array index <c>[2]</c>.
/// The origin vector represents translation.
/// </summary>
- public Vector2 origin;
+ public Vector2 Origin;
/// <summary>
- /// The rotation of this transformation matrix.
+ /// Returns the transform's rotation (in radians).
/// </summary>
- /// <value>Getting is equivalent to calling <see cref="Mathf.Atan2(real_t, real_t)"/> with the values of <see cref="x"/>.</value>
- public real_t Rotation
+ public readonly real_t Rotation => Mathf.Atan2(X.Y, X.X);
+
+ /// <summary>
+ /// Returns the scale.
+ /// </summary>
+ public readonly Vector2 Scale
{
get
{
- return Mathf.Atan2(x.y, x.x);
- }
- set
- {
- Vector2 scale = Scale;
- x.x = y.y = Mathf.Cos(value);
- x.y = y.x = Mathf.Sin(value);
- y.x *= -1;
- Scale = scale;
+ real_t detSign = Mathf.Sign(BasisDeterminant());
+ return new Vector2(X.Length(), detSign * Y.Length());
}
}
/// <summary>
- /// The scale of this transformation matrix.
+ /// Returns the transform's skew (in radians).
/// </summary>
- /// <value>Equivalent to the lengths of each column vector, but Y is negative if the determinant is negative.</value>
- public Vector2 Scale
+ public readonly real_t Skew
{
get
{
real_t detSign = Mathf.Sign(BasisDeterminant());
- return new Vector2(x.Length(), detSign * y.Length());
- }
- set
- {
- value /= Scale; // Value becomes what's called "delta_scale" in core.
- x *= value.x;
- y *= value.y;
+ return Mathf.Acos(X.Normalized().Dot(detSign * Y.Normalized())) - Mathf.Pi * 0.5f;
}
}
/// <summary>
/// Access whole columns in the form of <see cref="Vector2"/>.
- /// The third column is the <see cref="origin"/> vector.
+ /// The third column is the <see cref="Origin"/> vector.
/// </summary>
/// <param name="column">Which column vector.</param>
/// <exception cref="ArgumentOutOfRangeException">
@@ -80,16 +71,16 @@ namespace Godot
/// </exception>
public Vector2 this[int column]
{
- get
+ readonly get
{
switch (column)
{
case 0:
- return x;
+ return X;
case 1:
- return y;
+ return Y;
case 2:
- return origin;
+ return Origin;
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
@@ -99,13 +90,13 @@ namespace Godot
switch (column)
{
case 0:
- x = value;
+ X = value;
return;
case 1:
- y = value;
+ Y = value;
return;
case 2:
- origin = value;
+ Origin = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(column));
@@ -115,13 +106,13 @@ namespace Godot
/// <summary>
/// Access matrix elements in column-major order.
- /// The third column is the <see cref="origin"/> vector.
+ /// The third column is the <see cref="Origin"/> vector.
/// </summary>
/// <param name="column">Which column, the matrix horizontal position.</param>
/// <param name="row">Which row, the matrix vertical position.</param>
public real_t this[int column, int row]
{
- get
+ readonly get
{
return this[column][row];
}
@@ -139,7 +130,7 @@ namespace Godot
/// </summary>
/// <seealso cref="Inverse"/>
/// <returns>The inverse transformation matrix.</returns>
- public Transform2D AffineInverse()
+ public readonly Transform2D AffineInverse()
{
real_t det = BasisDeterminant();
@@ -148,9 +139,8 @@ namespace Godot
Transform2D inv = this;
- real_t temp = inv[0, 0];
- inv[0, 0] = inv[1, 1];
- inv[1, 1] = temp;
+ inv[0, 0] = this[1, 1];
+ inv[1, 1] = this[0, 0];
real_t detInv = 1.0f / det;
@@ -171,26 +161,27 @@ namespace Godot
/// and is usually considered invalid.
/// </summary>
/// <returns>The determinant of the basis matrix.</returns>
- private real_t BasisDeterminant()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private readonly real_t BasisDeterminant()
{
- return (x.x * y.y) - (x.y * y.x);
+ return (X.X * Y.Y) - (X.Y * Y.X);
}
/// <summary>
/// Returns a vector transformed (multiplied) by the basis matrix.
- /// This method does not account for translation (the <see cref="origin"/> vector).
+ /// This method does not account for translation (the <see cref="Origin"/> vector).
/// </summary>
/// <seealso cref="BasisXformInv(Vector2)"/>
/// <param name="v">A vector to transform.</param>
/// <returns>The transformed vector.</returns>
- public Vector2 BasisXform(Vector2 v)
+ public readonly Vector2 BasisXform(Vector2 v)
{
return new Vector2(Tdotx(v), Tdoty(v));
}
/// <summary>
/// Returns a vector transformed (multiplied) by the inverse basis matrix.
- /// This method does not account for translation (the <see cref="origin"/> vector).
+ /// This method does not account for translation (the <see cref="Origin"/> vector).
///
/// Note: This results in a multiplication by the inverse of the
/// basis matrix only if it represents a rotation-reflection.
@@ -198,9 +189,9 @@ namespace Godot
/// <seealso cref="BasisXform(Vector2)"/>
/// <param name="v">A vector to inversely transform.</param>
/// <returns>The inversely transformed vector.</returns>
- public Vector2 BasisXformInv(Vector2 v)
+ public readonly Vector2 BasisXformInv(Vector2 v)
{
- return new Vector2(x.Dot(v), y.Dot(v));
+ return new Vector2(X.Dot(v), Y.Dot(v));
}
/// <summary>
@@ -209,47 +200,15 @@ namespace Godot
/// <param name="transform">The other transform.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated transform.</returns>
- public Transform2D InterpolateWith(Transform2D transform, real_t weight)
+ public readonly Transform2D InterpolateWith(Transform2D transform, real_t weight)
{
- real_t r1 = Rotation;
- real_t r2 = transform.Rotation;
-
- Vector2 s1 = Scale;
- Vector2 s2 = transform.Scale;
-
- // Slerp rotation
- var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1));
- var v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2));
-
- real_t dot = v1.Dot(v2);
-
- dot = Mathf.Clamp(dot, -1.0f, 1.0f);
-
- Vector2 v;
-
- if (dot > 0.9995f)
- {
- // Linearly interpolate to avoid numerical precision issues
- v = v1.Lerp(v2, weight).Normalized();
- }
- else
- {
- real_t angle = weight * Mathf.Acos(dot);
- Vector2 v3 = (v2 - (v1 * dot)).Normalized();
- v = (v1 * Mathf.Cos(angle)) + (v3 * Mathf.Sin(angle));
- }
-
- // Extract parameters
- Vector2 p1 = origin;
- Vector2 p2 = transform.origin;
-
- // Construct matrix
- var res = new Transform2D(Mathf.Atan2(v.y, v.x), p1.Lerp(p2, weight));
- Vector2 scale = s1.Lerp(s2, weight);
- res.x *= scale;
- res.y *= scale;
-
- return res;
+ return new Transform2D
+ (
+ Mathf.LerpAngle(Rotation, transform.Rotation, weight),
+ Scale.Lerp(transform.Scale, weight),
+ Mathf.LerpAngle(Skew, transform.Skew, weight),
+ Origin.Lerp(transform.Origin, weight)
+ );
}
/// <summary>
@@ -258,40 +217,49 @@ namespace Godot
/// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling).
/// </summary>
/// <returns>The inverse matrix.</returns>
- public Transform2D Inverse()
+ public readonly Transform2D Inverse()
{
Transform2D inv = this;
// Swap
- real_t temp = inv.x.y;
- inv.x.y = inv.y.x;
- inv.y.x = temp;
+ inv.X.Y = Y.X;
+ inv.Y.X = X.Y;
- inv.origin = inv.BasisXform(-inv.origin);
+ inv.Origin = inv.BasisXform(-inv.Origin);
return inv;
}
/// <summary>
+ /// Returns <see langword="true"/> if this transform is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return X.IsFinite() && Y.IsFinite() && Origin.IsFinite();
+ }
+
+ /// <summary>
/// Returns the transform with the basis orthogonal (90 degrees),
/// and normalized axis vectors (scale of 1 or -1).
/// </summary>
/// <returns>The orthonormalized transform.</returns>
- public Transform2D Orthonormalized()
+ public readonly Transform2D Orthonormalized()
{
- Transform2D on = this;
+ Transform2D ortho = this;
- Vector2 onX = on.x;
- Vector2 onY = on.y;
+ Vector2 orthoX = ortho.X;
+ Vector2 orthoY = ortho.Y;
- onX.Normalize();
- onY = onY - (onX * onX.Dot(onY));
- onY.Normalize();
+ orthoX.Normalize();
+ orthoY = orthoY - orthoX * orthoX.Dot(orthoY);
+ orthoY.Normalize();
- on.x = onX;
- on.y = onY;
+ ortho.X = orthoX;
+ ortho.Y = orthoY;
- return on;
+ return ortho;
}
/// <summary>
@@ -301,9 +269,9 @@ namespace Godot
/// </summary>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
- public Transform2D Rotated(real_t angle)
+ public readonly Transform2D Rotated(real_t angle)
{
- return this * new Transform2D(angle, new Vector2());
+ return new Transform2D(angle, new Vector2()) * this;
}
/// <summary>
@@ -313,9 +281,9 @@ namespace Godot
/// </summary>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
- public Transform2D RotatedLocal(real_t angle)
+ public readonly Transform2D RotatedLocal(real_t angle)
{
- return new Transform2D(angle, new Vector2()) * this;
+ return this * new Transform2D(angle, new Vector2());
}
/// <summary>
@@ -325,12 +293,12 @@ namespace Godot
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
- public Transform2D Scaled(Vector2 scale)
+ public readonly Transform2D Scaled(Vector2 scale)
{
Transform2D copy = this;
- copy.x *= scale;
- copy.y *= scale;
- copy.origin *= scale;
+ copy.X *= scale;
+ copy.Y *= scale;
+ copy.Origin *= scale;
return copy;
}
@@ -341,20 +309,20 @@ namespace Godot
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
- public Transform2D ScaledLocal(Vector2 scale)
+ public readonly Transform2D ScaledLocal(Vector2 scale)
{
Transform2D copy = this;
- copy.x *= scale;
- copy.y *= scale;
+ copy.X *= scale;
+ copy.Y *= scale;
return copy;
}
- private real_t Tdotx(Vector2 with)
+ private readonly real_t Tdotx(Vector2 with)
{
return (this[0, 0] * with[0]) + (this[1, 0] * with[1]);
}
- private real_t Tdoty(Vector2 with)
+ private readonly real_t Tdoty(Vector2 with)
{
return (this[0, 1] * with[0]) + (this[1, 1] * with[1]);
}
@@ -366,10 +334,10 @@ namespace Godot
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
- public Transform2D Translated(Vector2 offset)
+ public readonly Transform2D Translated(Vector2 offset)
{
Transform2D copy = this;
- copy.origin += offset;
+ copy.Origin += offset;
return copy;
}
@@ -380,10 +348,10 @@ namespace Godot
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
- public Transform2D TranslatedLocal(Vector2 offset)
+ public readonly Transform2D TranslatedLocal(Vector2 offset)
{
Transform2D copy = this;
- copy.origin += copy.BasisXform(offset);
+ copy.Origin += copy.BasisXform(offset);
return copy;
}
@@ -418,26 +386,26 @@ namespace Godot
/// <param name="originPos">The origin vector, or column index 2.</param>
public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 originPos)
{
- x = xAxis;
- y = yAxis;
- origin = originPos;
+ X = xAxis;
+ Y = yAxis;
+ Origin = originPos;
}
/// <summary>
/// Constructs a transformation matrix from the given components.
- /// Arguments are named such that xy is equal to calling x.y
- /// </summary>
- /// <param name="xx">The X component of the X column vector, accessed via <c>t.x.x</c> or <c>[0][0]</c>.</param>
- /// <param name="xy">The Y component of the X column vector, accessed via <c>t.x.y</c> or <c>[0][1]</c>.</param>
- /// <param name="yx">The X component of the Y column vector, accessed via <c>t.y.x</c> or <c>[1][0]</c>.</param>
- /// <param name="yy">The Y component of the Y column vector, accessed via <c>t.y.y</c> or <c>[1][1]</c>.</param>
- /// <param name="ox">The X component of the origin vector, accessed via <c>t.origin.x</c> or <c>[2][0]</c>.</param>
- /// <param name="oy">The Y component of the origin vector, accessed via <c>t.origin.y</c> or <c>[2][1]</c>.</param>
+ /// Arguments are named such that xy is equal to calling <c>X.Y</c>.
+ /// </summary>
+ /// <param name="xx">The X component of the X column vector, accessed via <c>t.X.X</c> or <c>[0][0]</c>.</param>
+ /// <param name="xy">The Y component of the X column vector, accessed via <c>t.X.Y</c> or <c>[0][1]</c>.</param>
+ /// <param name="yx">The X component of the Y column vector, accessed via <c>t.Y.X</c> or <c>[1][0]</c>.</param>
+ /// <param name="yy">The Y component of the Y column vector, accessed via <c>t.Y.Y</c> or <c>[1][1]</c>.</param>
+ /// <param name="ox">The X component of the origin vector, accessed via <c>t.Origin.X</c> or <c>[2][0]</c>.</param>
+ /// <param name="oy">The Y component of the origin vector, accessed via <c>t.Origin.Y</c> or <c>[2][1]</c>.</param>
public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy)
{
- x = new Vector2(xx, xy);
- y = new Vector2(yx, yy);
- origin = new Vector2(ox, oy);
+ X = new Vector2(xx, xy);
+ Y = new Vector2(yx, yy);
+ Origin = new Vector2(ox, oy);
}
/// <summary>
@@ -448,10 +416,31 @@ namespace Godot
/// <param name="origin">The origin vector, or column index 2.</param>
public Transform2D(real_t rotation, Vector2 origin)
{
- x.x = y.y = Mathf.Cos(rotation);
- x.y = y.x = Mathf.Sin(rotation);
- y.x *= -1;
- this.origin = origin;
+ (real_t sin, real_t cos) = Mathf.SinCos(rotation);
+ X.X = Y.Y = cos;
+ X.Y = Y.X = sin;
+ Y.X *= -1;
+ Origin = origin;
+ }
+
+ /// <summary>
+ /// Constructs a transformation matrix from a <paramref name="rotation"/> value,
+ /// <paramref name="scale"/> vector, <paramref name="skew"/> value, and
+ /// <paramref name="origin"/> vector.
+ /// </summary>
+ /// <param name="rotation">The rotation of the new transform, in radians.</param>
+ /// <param name="scale">The scale of the new transform.</param>
+ /// <param name="skew">The skew of the new transform, in radians.</param>
+ /// <param name="origin">The origin vector, or column index 2.</param>
+ public Transform2D(real_t rotation, Vector2 scale, real_t skew, Vector2 origin)
+ {
+ (real_t rotationSin, real_t rotationCos) = Mathf.SinCos(rotation);
+ (real_t rotationSkewSin, real_t rotationSkewCos) = Mathf.SinCos(rotation + skew);
+ X.X = rotationCos * scale.X;
+ Y.Y = rotationSkewCos * scale.Y;
+ Y.X = -rotationSkewSin * scale.Y;
+ X.Y = rotationSin * scale.X;
+ Origin = origin;
}
/// <summary>
@@ -464,17 +453,17 @@ namespace Godot
/// <returns>The composed transform.</returns>
public static Transform2D operator *(Transform2D left, Transform2D right)
{
- left.origin = left * right.origin;
+ left.Origin = left * right.Origin;
- real_t x0 = left.Tdotx(right.x);
- real_t x1 = left.Tdoty(right.x);
- real_t y0 = left.Tdotx(right.y);
- real_t y1 = left.Tdoty(right.y);
+ real_t x0 = left.Tdotx(right.X);
+ real_t x1 = left.Tdoty(right.X);
+ real_t y0 = left.Tdotx(right.Y);
+ real_t y1 = left.Tdoty(right.Y);
- left.x.x = x0;
- left.x.y = x1;
- left.y.x = y0;
- left.y.y = y1;
+ left.X.X = x0;
+ left.X.Y = x1;
+ left.Y.X = y0;
+ left.Y.Y = y1;
return left;
}
@@ -487,7 +476,7 @@ namespace Godot
/// <returns>The transformed Vector2.</returns>
public static Vector2 operator *(Transform2D transform, Vector2 vector)
{
- return new Vector2(transform.Tdotx(vector), transform.Tdoty(vector)) + transform.origin;
+ return new Vector2(transform.Tdotx(vector), transform.Tdoty(vector)) + transform.Origin;
}
/// <summary>
@@ -498,8 +487,8 @@ namespace Godot
/// <returns>The inversely transformed Vector2.</returns>
public static Vector2 operator *(Vector2 vector, Transform2D transform)
{
- Vector2 vInv = vector - transform.origin;
- return new Vector2(transform.x.Dot(vInv), transform.y.Dot(vInv));
+ Vector2 vInv = vector - transform.Origin;
+ return new Vector2(transform.X.Dot(vInv), transform.Y.Dot(vInv));
}
/// <summary>
@@ -511,8 +500,8 @@ namespace Godot
public static Rect2 operator *(Transform2D transform, Rect2 rect)
{
Vector2 pos = transform * rect.Position;
- Vector2 toX = transform.x * rect.Size.x;
- Vector2 toY = transform.y * rect.Size.y;
+ Vector2 toX = transform.X * rect.Size.X;
+ Vector2 toY = transform.Y * rect.Size.Y;
return new Rect2(pos, new Vector2()).Expand(pos + toX).Expand(pos + toY).Expand(pos + toX + toY);
}
@@ -526,9 +515,9 @@ namespace Godot
public static Rect2 operator *(Rect2 rect, Transform2D transform)
{
Vector2 pos = rect.Position * transform;
- Vector2 to1 = new Vector2(rect.Position.x, rect.Position.y + rect.Size.y) * transform;
- Vector2 to2 = new Vector2(rect.Position.x + rect.Size.x, rect.Position.y + rect.Size.y) * transform;
- Vector2 to3 = new Vector2(rect.Position.x + rect.Size.x, rect.Position.y) * transform;
+ Vector2 to1 = new Vector2(rect.Position.X, rect.Position.Y + rect.Size.Y) * transform;
+ Vector2 to2 = new Vector2(rect.Position.X + rect.Size.X, rect.Position.Y + rect.Size.Y) * transform;
+ Vector2 to3 = new Vector2(rect.Position.X + rect.Size.X, rect.Position.Y) * transform;
return new Rect2(pos, new Vector2()).Expand(to1).Expand(to2).Expand(to3);
}
@@ -603,7 +592,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the transform and the object are exactly equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Transform2D other && Equals(other);
}
@@ -615,9 +604,9 @@ namespace Godot
/// </summary>
/// <param name="other">The other transform to compare.</param>
/// <returns>Whether or not the matrices are exactly equal.</returns>
- public bool Equals(Transform2D other)
+ public readonly bool Equals(Transform2D other)
{
- return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin);
+ return X.Equals(other.X) && Y.Equals(other.Y) && Origin.Equals(other.Origin);
}
/// <summary>
@@ -626,36 +615,36 @@ namespace Godot
/// </summary>
/// <param name="other">The other transform to compare.</param>
/// <returns>Whether or not the matrices are approximately equal.</returns>
- public bool IsEqualApprox(Transform2D other)
+ public readonly bool IsEqualApprox(Transform2D other)
{
- return x.IsEqualApprox(other.x) && y.IsEqualApprox(other.y) && origin.IsEqualApprox(other.origin);
+ return X.IsEqualApprox(other.X) && Y.IsEqualApprox(other.Y) && Origin.IsEqualApprox(other.Origin);
}
/// <summary>
/// Serves as the hash function for <see cref="Transform2D"/>.
/// </summary>
/// <returns>A hash code for this transform.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return x.GetHashCode() ^ y.GetHashCode() ^ origin.GetHashCode();
+ return X.GetHashCode() ^ Y.GetHashCode() ^ Origin.GetHashCode();
}
/// <summary>
/// Converts this <see cref="Transform2D"/> to a string.
/// </summary>
/// <returns>A string representation of this transform.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"[X: {x}, Y: {y}, O: {origin}]";
+ return $"[X: {X}, Y: {Y}, O: {Origin}]";
}
/// <summary>
/// Converts this <see cref="Transform2D"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this transform.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"[X: {x.ToString(format)}, Y: {y.ToString(format)}, O: {origin.ToString(format)}]";
+ return $"[X: {X.ToString(format)}, Y: {Y.ToString(format)}, O: {Origin.ToString(format)}]";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 2f7891e7ef..b34e95c04d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -6,7 +6,7 @@ namespace Godot
/// <summary>
/// 3×4 matrix (3 rows, 4 columns) used for 3D linear transformations.
/// It can represent transformations such as translation, rotation, or scaling.
- /// It consists of a <see cref="Basis"/> (first 3 columns) and a
+ /// It consists of a <see cref="Godot.Basis"/> (first 3 columns) and a
/// <see cref="Vector3"/> for the origin (last column).
///
/// For more information, read this documentation article:
@@ -17,19 +17,19 @@ namespace Godot
public struct Transform3D : IEquatable<Transform3D>
{
/// <summary>
- /// The <see cref="Basis"/> of this transform. Contains the X, Y, and Z basis
+ /// The <see cref="Godot.Basis"/> of this transform. Contains the X, Y, and Z basis
/// vectors (columns 0 to 2) and is responsible for rotation and scale.
/// </summary>
- public Basis basis;
+ public Basis Basis;
/// <summary>
/// The origin vector (column 3, the fourth column). Equivalent to array index <c>[3]</c>.
/// </summary>
- public Vector3 origin;
+ public Vector3 Origin;
/// <summary>
/// Access whole columns in the form of <see cref="Vector3"/>.
- /// The fourth column is the <see cref="origin"/> vector.
+ /// The fourth column is the <see cref="Origin"/> vector.
/// </summary>
/// <param name="column">Which column vector.</param>
/// <exception cref="ArgumentOutOfRangeException">
@@ -37,18 +37,18 @@ namespace Godot
/// </exception>
public Vector3 this[int column]
{
- get
+ readonly get
{
switch (column)
{
case 0:
- return basis.Column0;
+ return Basis.Column0;
case 1:
- return basis.Column1;
+ return Basis.Column1;
case 2:
- return basis.Column2;
+ return Basis.Column2;
case 3:
- return origin;
+ return Origin;
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
@@ -58,16 +58,16 @@ namespace Godot
switch (column)
{
case 0:
- basis.Column0 = value;
+ Basis.Column0 = value;
return;
case 1:
- basis.Column1 = value;
+ Basis.Column1 = value;
return;
case 2:
- basis.Column2 = value;
+ Basis.Column2 = value;
return;
case 3:
- origin = value;
+ Origin = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(column));
@@ -77,28 +77,28 @@ namespace Godot
/// <summary>
/// Access matrix elements in column-major order.
- /// The fourth column is the <see cref="origin"/> vector.
+ /// The fourth column is the <see cref="Origin"/> vector.
/// </summary>
/// <param name="column">Which column, the matrix horizontal position.</param>
/// <param name="row">Which row, the matrix vertical position.</param>
public real_t this[int column, int row]
{
- get
+ readonly get
{
if (column == 3)
{
- return origin[row];
+ return Origin[row];
}
- return basis[column, row];
+ return Basis[column, row];
}
set
{
if (column == 3)
{
- origin[row] = value;
+ Origin[row] = value;
return;
}
- basis[column, row] = value;
+ Basis[column, row] = value;
}
}
@@ -108,23 +108,37 @@ namespace Godot
/// </summary>
/// <seealso cref="Inverse"/>
/// <returns>The inverse transformation matrix.</returns>
- public Transform3D AffineInverse()
+ public readonly Transform3D AffineInverse()
{
- Basis basisInv = basis.Inverse();
- return new Transform3D(basisInv, basisInv * -origin);
+ Basis basisInv = Basis.Inverse();
+ return new Transform3D(basisInv, basisInv * -Origin);
}
/// <summary>
- /// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>.
+ /// Returns a transform interpolated between this transform and another
+ /// <paramref name="transform"/> by a given <paramref name="weight"/>
+ /// (on the range of 0.0 to 1.0).
/// </summary>
/// <param name="transform">The other transform.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated transform.</returns>
- public Transform3D InterpolateWith(Transform3D transform, real_t weight)
+ public readonly Transform3D InterpolateWith(Transform3D transform, real_t weight)
{
- Basis retBasis = basis.Lerp(transform.basis, weight);
- Vector3 retOrigin = origin.Lerp(transform.origin, weight);
- return new Transform3D(retBasis, retOrigin);
+ Vector3 sourceScale = Basis.Scale;
+ Quaternion sourceRotation = Basis.GetRotationQuaternion();
+ Vector3 sourceLocation = Origin;
+
+ Vector3 destinationScale = transform.Basis.Scale;
+ Quaternion destinationRotation = transform.Basis.GetRotationQuaternion();
+ Vector3 destinationLocation = transform.Origin;
+
+ var interpolated = new Transform3D();
+ Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized();
+ Vector3 scale = sourceScale.Lerp(destinationScale, weight);
+ interpolated.Basis.SetQuaternionScale(quaternion, scale);
+ interpolated.Origin = sourceLocation.Lerp(destinationLocation, weight);
+
+ return interpolated;
}
/// <summary>
@@ -133,10 +147,20 @@ namespace Godot
/// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling).
/// </summary>
/// <returns>The inverse matrix.</returns>
- public Transform3D Inverse()
+ public readonly Transform3D Inverse()
{
- Basis basisTr = basis.Transposed();
- return new Transform3D(basisTr, basisTr * -origin);
+ Basis basisTr = Basis.Transposed();
+ return new Transform3D(basisTr, basisTr * -Origin);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this transform is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Basis.IsFinite() && Origin.IsFinite();
}
/// <summary>
@@ -155,7 +179,7 @@ namespace Godot
public readonly Transform3D LookingAt(Vector3 target, Vector3 up)
{
Transform3D t = this;
- t.SetLookAt(origin, target, up);
+ t.SetLookAt(Origin, target, up);
return t;
}
@@ -164,9 +188,9 @@ namespace Godot
/// and normalized axis vectors (scale of 1 or -1).
/// </summary>
/// <returns>The orthonormalized transform.</returns>
- public Transform3D Orthonormalized()
+ public readonly Transform3D Orthonormalized()
{
- return new Transform3D(basis.Orthonormalized(), origin);
+ return new Transform3D(Basis.Orthonormalized(), Origin);
}
/// <summary>
@@ -192,10 +216,10 @@ namespace Godot
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
- public Transform3D RotatedLocal(Vector3 axis, real_t angle)
+ public readonly Transform3D RotatedLocal(Vector3 axis, real_t angle)
{
Basis tmpBasis = new Basis(axis, angle);
- return new Transform3D(basis * tmpBasis, origin);
+ return new Transform3D(Basis * tmpBasis, Origin);
}
/// <summary>
@@ -205,9 +229,9 @@ namespace Godot
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
- public Transform3D Scaled(Vector3 scale)
+ public readonly Transform3D Scaled(Vector3 scale)
{
- return new Transform3D(basis.Scaled(scale), origin * scale);
+ return new Transform3D(Basis.Scaled(scale), Origin * scale);
}
/// <summary>
@@ -217,38 +241,10 @@ namespace Godot
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
- public Transform3D ScaledLocal(Vector3 scale)
+ public readonly Transform3D ScaledLocal(Vector3 scale)
{
Basis tmpBasis = Basis.FromScale(scale);
- return new Transform3D(basis * tmpBasis, origin);
- }
-
- /// <summary>
- /// Returns a transform spherically interpolated between this transform and
- /// another <paramref name="transform"/> by <paramref name="weight"/>.
- /// </summary>
- /// <param name="transform">The other transform.</param>
- /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The interpolated transform.</returns>
- public Transform3D SphericalInterpolateWith(Transform3D transform, real_t weight)
- {
- /* not sure if very "efficient" but good enough? */
-
- Vector3 sourceScale = basis.Scale;
- Quaternion sourceRotation = basis.GetRotationQuaternion();
- Vector3 sourceLocation = origin;
-
- Vector3 destinationScale = transform.basis.Scale;
- Quaternion destinationRotation = transform.basis.GetRotationQuaternion();
- Vector3 destinationLocation = transform.origin;
-
- var interpolated = new Transform3D();
- Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized();
- Vector3 scale = sourceScale.Lerp(destinationScale, weight);
- interpolated.basis.SetQuaternionScale(quaternion, scale);
- interpolated.origin = sourceLocation.Lerp(destinationLocation, weight);
-
- return interpolated;
+ return new Transform3D(Basis * tmpBasis, Origin);
}
private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up)
@@ -269,9 +265,9 @@ namespace Godot
column0.Normalize();
column1.Normalize();
- basis = new Basis(column0, column1, column2);
+ Basis = new Basis(column0, column1, column2);
- origin = eye;
+ Origin = eye;
}
/// <summary>
@@ -281,9 +277,9 @@ namespace Godot
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
- public Transform3D Translated(Vector3 offset)
+ public readonly Transform3D Translated(Vector3 offset)
{
- return new Transform3D(basis, origin + offset);
+ return new Transform3D(Basis, Origin + offset);
}
/// <summary>
@@ -293,13 +289,13 @@ namespace Godot
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
- public Transform3D TranslatedLocal(Vector3 offset)
+ public readonly Transform3D TranslatedLocal(Vector3 offset)
{
- return new Transform3D(basis, new Vector3
+ return new Transform3D(Basis, new Vector3
(
- origin[0] + basis.Row0.Dot(offset),
- origin[1] + basis.Row1.Dot(offset),
- origin[2] + basis.Row2.Dot(offset)
+ Origin[0] + Basis.Row0.Dot(offset),
+ Origin[1] + Basis.Row1.Dot(offset),
+ Origin[2] + Basis.Row2.Dot(offset)
));
}
@@ -341,32 +337,65 @@ namespace Godot
/// <param name="origin">The origin vector, or column index 3.</param>
public Transform3D(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin)
{
- basis = new Basis(column0, column1, column2);
- this.origin = origin;
+ Basis = new Basis(column0, column1, column2);
+ Origin = origin;
}
/// <summary>
- /// Constructs a transformation matrix from the given <paramref name="quaternion"/>
- /// and <paramref name="origin"/> vector.
+ /// Constructs a transformation matrix from the given components.
+ /// Arguments are named such that xy is equal to calling <c>Basis.X.Y</c>.
/// </summary>
- /// <param name="quaternion">The <see cref="Quaternion"/> to create the basis from.</param>
- /// <param name="origin">The origin vector, or column index 3.</param>
- public Transform3D(Quaternion quaternion, Vector3 origin)
+ /// <param name="xx">The X component of the X column vector, accessed via <c>t.Basis.X.X</c> or <c>[0][0]</c>.</param>
+ /// <param name="yx">The X component of the Y column vector, accessed via <c>t.Basis.Y.X</c> or <c>[1][0]</c>.</param>
+ /// <param name="zx">The X component of the Z column vector, accessed via <c>t.Basis.Z.X</c> or <c>[2][0]</c>.</param>
+ /// <param name="xy">The Y component of the X column vector, accessed via <c>t.Basis.X.Y</c> or <c>[0][1]</c>.</param>
+ /// <param name="yy">The Y component of the Y column vector, accessed via <c>t.Basis.Y.Y</c> or <c>[1][1]</c>.</param>
+ /// <param name="zy">The Y component of the Z column vector, accessed via <c>t.Basis.Y.Y</c> or <c>[2][1]</c>.</param>
+ /// <param name="xz">The Z component of the X column vector, accessed via <c>t.Basis.X.Y</c> or <c>[0][2]</c>.</param>
+ /// <param name="yz">The Z component of the Y column vector, accessed via <c>t.Basis.Y.Y</c> or <c>[1][2]</c>.</param>
+ /// <param name="zz">The Z component of the Z column vector, accessed via <c>t.Basis.Y.Y</c> or <c>[2][2]</c>.</param>
+ /// <param name="ox">The X component of the origin vector, accessed via <c>t.Origin.X</c> or <c>[2][0]</c>.</param>
+ /// <param name="oy">The Y component of the origin vector, accessed via <c>t.Origin.Y</c> or <c>[2][1]</c>.</param>
+ /// <param name="oz">The Z component of the origin vector, accessed via <c>t.Origin.Z</c> or <c>[2][2]</c>.</param>
+ public Transform3D(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz, real_t ox, real_t oy, real_t oz)
{
- basis = new Basis(quaternion);
- this.origin = origin;
+ Basis = new Basis(xx, yx, zx, xy, yy, zy, xz, yz, zz);
+ Origin = new Vector3(ox, oy, oz);
}
/// <summary>
/// Constructs a transformation matrix from the given <paramref name="basis"/> and
/// <paramref name="origin"/> vector.
/// </summary>
- /// <param name="basis">The <see cref="Basis"/> to create the basis from.</param>
+ /// <param name="basis">The <see cref="Godot.Basis"/> to create the basis from.</param>
/// <param name="origin">The origin vector, or column index 3.</param>
public Transform3D(Basis basis, Vector3 origin)
{
- this.basis = basis;
- this.origin = origin;
+ Basis = basis;
+ Origin = origin;
+ }
+
+ /// <summary>
+ /// Constructs a transformation matrix from the given <paramref name="projection"/>
+ /// by trimming the last row of the projection matrix (<c>projection.X.W</c>,
+ /// <c>projection.Y.W</c>, <c>projection.Z.W</c>, and <c>projection.W.W</c>
+ /// are not copied over).
+ /// </summary>
+ /// <param name="projection">The <see cref="Projection"/> to create the transform from.</param>
+ public Transform3D(Projection projection)
+ {
+ Basis = new Basis
+ (
+ projection.X.X, projection.Y.X, projection.Z.X,
+ projection.X.Y, projection.Y.Y, projection.Z.Y,
+ projection.X.Z, projection.Y.Z, projection.Z.Z
+ );
+ Origin = new Vector3
+ (
+ projection.W.X,
+ projection.W.Y,
+ projection.W.Z
+ );
}
/// <summary>
@@ -379,8 +408,8 @@ namespace Godot
/// <returns>The composed transform.</returns>
public static Transform3D operator *(Transform3D left, Transform3D right)
{
- left.origin = left * right.origin;
- left.basis *= right.basis;
+ left.Origin = left * right.Origin;
+ left.Basis *= right.Basis;
return left;
}
@@ -394,9 +423,9 @@ namespace Godot
{
return new Vector3
(
- transform.basis.Row0.Dot(vector) + transform.origin.x,
- transform.basis.Row1.Dot(vector) + transform.origin.y,
- transform.basis.Row2.Dot(vector) + transform.origin.z
+ transform.Basis.Row0.Dot(vector) + transform.Origin.X,
+ transform.Basis.Row1.Dot(vector) + transform.Origin.Y,
+ transform.Basis.Row2.Dot(vector) + transform.Origin.Z
);
}
@@ -411,13 +440,13 @@ namespace Godot
/// <returns>The inversely transformed Vector3.</returns>
public static Vector3 operator *(Vector3 vector, Transform3D transform)
{
- Vector3 vInv = vector - transform.origin;
+ Vector3 vInv = vector - transform.Origin;
return new Vector3
(
- (transform.basis.Row0[0] * vInv.x) + (transform.basis.Row1[0] * vInv.y) + (transform.basis.Row2[0] * vInv.z),
- (transform.basis.Row0[1] * vInv.x) + (transform.basis.Row1[1] * vInv.y) + (transform.basis.Row2[1] * vInv.z),
- (transform.basis.Row0[2] * vInv.x) + (transform.basis.Row1[2] * vInv.y) + (transform.basis.Row2[2] * vInv.z)
+ (transform.Basis.Row0[0] * vInv.X) + (transform.Basis.Row1[0] * vInv.Y) + (transform.Basis.Row2[0] * vInv.Z),
+ (transform.Basis.Row0[1] * vInv.X) + (transform.Basis.Row1[1] * vInv.Y) + (transform.Basis.Row2[1] * vInv.Z),
+ (transform.Basis.Row0[2] * vInv.X) + (transform.Basis.Row1[2] * vInv.Y) + (transform.Basis.Row2[2] * vInv.Z)
);
}
@@ -427,19 +456,19 @@ namespace Godot
/// <param name="transform">The transformation to apply.</param>
/// <param name="aabb">An AABB to transform.</param>
/// <returns>The transformed AABB.</returns>
- public static AABB operator *(Transform3D transform, AABB aabb)
+ public static Aabb operator *(Transform3D transform, Aabb aabb)
{
Vector3 min = aabb.Position;
Vector3 max = aabb.Position + aabb.Size;
- Vector3 tmin = transform.origin;
- Vector3 tmax = transform.origin;
+ Vector3 tmin = transform.Origin;
+ Vector3 tmax = transform.Origin;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
- real_t e = transform.basis[i][j] * min[j];
- real_t f = transform.basis[i][j] * max[j];
+ real_t e = transform.Basis[i][j] * min[j];
+ real_t f = transform.Basis[i][j] * max[j];
if (e < f)
{
tmin[i] += e;
@@ -453,7 +482,7 @@ namespace Godot
}
}
- return new AABB(tmin, tmax - tmin);
+ return new Aabb(tmin, tmax - tmin);
}
/// <summary>
@@ -462,18 +491,18 @@ namespace Godot
/// <param name="aabb">An AABB to inversely transform.</param>
/// <param name="transform">The transformation to apply.</param>
/// <returns>The inversely transformed AABB.</returns>
- public static AABB operator *(AABB aabb, Transform3D transform)
+ public static Aabb operator *(Aabb aabb, Transform3D transform)
{
- Vector3 pos = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y + aabb.Size.y, aabb.Position.z + aabb.Size.z) * transform;
- Vector3 to1 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y + aabb.Size.y, aabb.Position.z) * transform;
- Vector3 to2 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y, aabb.Position.z + aabb.Size.z) * transform;
- Vector3 to3 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y, aabb.Position.z) * transform;
- Vector3 to4 = new Vector3(aabb.Position.x, aabb.Position.y + aabb.Size.y, aabb.Position.z + aabb.Size.z) * transform;
- Vector3 to5 = new Vector3(aabb.Position.x, aabb.Position.y + aabb.Size.y, aabb.Position.z) * transform;
- Vector3 to6 = new Vector3(aabb.Position.x, aabb.Position.y, aabb.Position.z + aabb.Size.z) * transform;
- Vector3 to7 = new Vector3(aabb.Position.x, aabb.Position.y, aabb.Position.z) * transform;
+ Vector3 pos = new Vector3(aabb.Position.X + aabb.Size.X, aabb.Position.Y + aabb.Size.Y, aabb.Position.Z + aabb.Size.Z) * transform;
+ Vector3 to1 = new Vector3(aabb.Position.X + aabb.Size.X, aabb.Position.Y + aabb.Size.Y, aabb.Position.Z) * transform;
+ Vector3 to2 = new Vector3(aabb.Position.X + aabb.Size.X, aabb.Position.Y, aabb.Position.Z + aabb.Size.Z) * transform;
+ Vector3 to3 = new Vector3(aabb.Position.X + aabb.Size.X, aabb.Position.Y, aabb.Position.Z) * transform;
+ Vector3 to4 = new Vector3(aabb.Position.X, aabb.Position.Y + aabb.Size.Y, aabb.Position.Z + aabb.Size.Z) * transform;
+ Vector3 to5 = new Vector3(aabb.Position.X, aabb.Position.Y + aabb.Size.Y, aabb.Position.Z) * transform;
+ Vector3 to6 = new Vector3(aabb.Position.X, aabb.Position.Y, aabb.Position.Z + aabb.Size.Z) * transform;
+ Vector3 to7 = new Vector3(aabb.Position.X, aabb.Position.Y, aabb.Position.Z) * transform;
- return new AABB(pos, new Vector3()).Expand(to1).Expand(to2).Expand(to3).Expand(to4).Expand(to5).Expand(to6).Expand(to7);
+ return new Aabb(pos, new Vector3()).Expand(to1).Expand(to2).Expand(to3).Expand(to4).Expand(to5).Expand(to6).Expand(to7);
}
/// <summary>
@@ -484,7 +513,7 @@ namespace Godot
/// <returns>The transformed Plane.</returns>
public static Plane operator *(Transform3D transform, Plane plane)
{
- Basis bInvTrans = transform.basis.Inverse().Transposed();
+ Basis bInvTrans = transform.Basis.Inverse().Transposed();
// Transform a single point on the plane.
Vector3 point = transform * (plane.Normal * plane.D);
@@ -505,7 +534,7 @@ namespace Godot
public static Plane operator *(Plane plane, Transform3D transform)
{
Transform3D tInv = transform.AffineInverse();
- Basis bTrans = transform.basis.Transposed();
+ Basis bTrans = transform.Basis.Transposed();
// Transform a single point on the plane.
Vector3 point = tInv * (plane.Normal * plane.D);
@@ -608,7 +637,7 @@ namespace Godot
/// <returns>Whether or not the matrices are exactly equal.</returns>
public readonly bool Equals(Transform3D other)
{
- return basis.Equals(other.basis) && origin.Equals(other.origin);
+ return Basis.Equals(other.Basis) && Origin.Equals(other.Origin);
}
/// <summary>
@@ -617,36 +646,36 @@ namespace Godot
/// </summary>
/// <param name="other">The other transform to compare.</param>
/// <returns>Whether or not the matrices are approximately equal.</returns>
- public bool IsEqualApprox(Transform3D other)
+ public readonly bool IsEqualApprox(Transform3D other)
{
- return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin);
+ return Basis.IsEqualApprox(other.Basis) && Origin.IsEqualApprox(other.Origin);
}
/// <summary>
/// Serves as the hash function for <see cref="Transform3D"/>.
/// </summary>
/// <returns>A hash code for this transform.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return basis.GetHashCode() ^ origin.GetHashCode();
+ return Basis.GetHashCode() ^ Origin.GetHashCode();
}
/// <summary>
/// Converts this <see cref="Transform3D"/> to a string.
/// </summary>
/// <returns>A string representation of this transform.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"[X: {basis.x}, Y: {basis.y}, Z: {basis.z}, O: {origin}]";
+ return $"[X: {Basis.X}, Y: {Basis.Y}, Z: {Basis.Z}, O: {Origin}]";
}
/// <summary>
/// Converts this <see cref="Transform3D"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this transform.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"[X: {basis.x.ToString(format)}, Y: {basis.y.ToString(format)}, Z: {basis.z.ToString(format)}, O: {origin.ToString(format)}]";
+ return $"[X: {Basis.X.ToString(format)}, Y: {Basis.Y.ToString(format)}, Z: {Basis.Z.ToString(format)}, O: {Origin.ToString(format)}]";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs
index d354509dbf..9aad965ad0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs
@@ -60,13 +60,13 @@ public partial struct Variant : IDisposable
case Type.Int:
case Type.Float:
case Type.Vector2:
- case Type.Vector2i:
+ case Type.Vector2I:
case Type.Rect2:
- case Type.Rect2i:
+ case Type.Rect2I:
case Type.Vector3:
- case Type.Vector3i:
+ case Type.Vector3I:
case Type.Vector4:
- case Type.Vector4i:
+ case Type.Vector4I:
case Type.Plane:
case Type.Quaternion:
case Type.Color:
@@ -109,16 +109,58 @@ public partial struct Variant : IDisposable
public override string ToString() => AsString();
- public object? Obj
- {
- get
+ public object? Obj =>
+ _obj ??= NativeVar.DangerousSelfRef.Type switch
{
- if (_obj == null)
- _obj = Marshaling.ConvertVariantToManagedObject((godot_variant)NativeVar);
-
- return _obj;
- }
- }
+ Type.Bool => AsBool(),
+ Type.Int => AsInt64(),
+ Type.Float => AsDouble(),
+ Type.String => AsString(),
+ Type.Vector2 => AsVector2(),
+ Type.Vector2I => AsVector2I(),
+ Type.Rect2 => AsRect2(),
+ Type.Rect2I => AsRect2I(),
+ Type.Vector3 => AsVector3(),
+ Type.Vector3I => AsVector3I(),
+ Type.Transform2D => AsTransform2D(),
+ Type.Vector4 => AsVector4(),
+ Type.Vector4I => AsVector4I(),
+ Type.Plane => AsPlane(),
+ Type.Quaternion => AsQuaternion(),
+ Type.Aabb => AsAabb(),
+ Type.Basis => AsBasis(),
+ Type.Transform3D => AsTransform3D(),
+ Type.Projection => AsProjection(),
+ Type.Color => AsColor(),
+ Type.StringName => AsStringName(),
+ Type.NodePath => AsNodePath(),
+ Type.Rid => AsRid(),
+ Type.Object => AsGodotObject(),
+ Type.Callable => AsCallable(),
+ Type.Signal => AsSignal(),
+ Type.Dictionary => AsGodotDictionary(),
+ Type.Array => AsGodotArray(),
+ Type.PackedByteArray => AsByteArray(),
+ Type.PackedInt32Array => AsInt32Array(),
+ Type.PackedInt64Array => AsInt64Array(),
+ Type.PackedFloat32Array => AsFloat32Array(),
+ Type.PackedFloat64Array => AsFloat64Array(),
+ Type.PackedStringArray => AsStringArray(),
+ Type.PackedVector2Array => AsVector2Array(),
+ Type.PackedVector3Array => AsVector3Array(),
+ Type.PackedColorArray => AsColorArray(),
+ Type.Nil => null,
+ Type.Max or _ =>
+ throw new InvalidOperationException($"Invalid Variant type: {NativeVar.DangerousSelfRef.Type}"),
+ };
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant From<[MustBeVariant] T>(in T from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFrom(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T As<[MustBeVariant] T>() =>
+ VariantUtils.ConvertTo<T>(NativeVar.DangerousSelfRef);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool AsBool() =>
@@ -170,23 +212,23 @@ public partial struct Variant : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string AsString() =>
- VariantUtils.ConvertToStringObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToString((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 AsVector2() =>
VariantUtils.ConvertToVector2((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vector2i AsVector2i() =>
- VariantUtils.ConvertToVector2i((godot_variant)NativeVar);
+ public Vector2I AsVector2I() =>
+ VariantUtils.ConvertToVector2I((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rect2 AsRect2() =>
VariantUtils.ConvertToRect2((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Rect2i AsRect2i() =>
- VariantUtils.ConvertToRect2i((godot_variant)NativeVar);
+ public Rect2I AsRect2I() =>
+ VariantUtils.ConvertToRect2I((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Transform2D AsTransform2D() =>
@@ -197,8 +239,8 @@ public partial struct Variant : IDisposable
VariantUtils.ConvertToVector3((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vector3i AsVector3i() =>
- VariantUtils.ConvertToVector3i((godot_variant)NativeVar);
+ public Vector3I AsVector3I() =>
+ VariantUtils.ConvertToVector3I((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Basis AsBasis() =>
@@ -217,16 +259,16 @@ public partial struct Variant : IDisposable
VariantUtils.ConvertToVector4((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vector4i AsVector4i() =>
- VariantUtils.ConvertToVector4i((godot_variant)NativeVar);
+ public Vector4I AsVector4I() =>
+ VariantUtils.ConvertToVector4I((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Projection AsProjection() =>
VariantUtils.ConvertToProjection((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public AABB AsAABB() =>
- VariantUtils.ConvertToAABB((godot_variant)NativeVar);
+ public Aabb AsAabb() =>
+ VariantUtils.ConvertToAabb((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color AsColor() =>
@@ -238,11 +280,11 @@ public partial struct Variant : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Callable AsCallable() =>
- VariantUtils.ConvertToCallableManaged((godot_variant)NativeVar);
+ VariantUtils.ConvertToCallable((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public SignalInfo AsSignalInfo() =>
- VariantUtils.ConvertToSignalInfo((godot_variant)NativeVar);
+ public Signal AsSignal() =>
+ VariantUtils.ConvertToSignal((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte[] AsByteArray() =>
@@ -282,16 +324,16 @@ public partial struct Variant : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T[] AsGodotObjectArray<T>()
- where T : Godot.Object =>
+ where T : GodotObject =>
VariantUtils.ConvertToSystemArrayOfGodotObject<T>((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Collections.Dictionary<TKey, TValue> AsGodotDictionary<TKey, TValue>() =>
- VariantUtils.ConvertToDictionaryObject<TKey, TValue>((godot_variant)NativeVar);
+ public Collections.Dictionary<TKey, TValue> AsGodotDictionary<[MustBeVariant] TKey, [MustBeVariant] TValue>() =>
+ VariantUtils.ConvertToDictionary<TKey, TValue>((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Collections.Array<T> AsGodotArray<T>() =>
- VariantUtils.ConvertToArrayObject<T>((godot_variant)NativeVar);
+ public Collections.Array<T> AsGodotArray<[MustBeVariant] T>() =>
+ VariantUtils.ConvertToArray<T>((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public StringName[] AsSystemArrayOfStringName() =>
@@ -302,32 +344,32 @@ public partial struct Variant : IDisposable
VariantUtils.ConvertToSystemArrayOfNodePath((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public RID[] AsSystemArrayOfRID() =>
- VariantUtils.ConvertToSystemArrayOfRID((godot_variant)NativeVar);
+ public Rid[] AsSystemArrayOfRid() =>
+ VariantUtils.ConvertToSystemArrayOfRid((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Godot.Object AsGodotObject() =>
+ public GodotObject AsGodotObject() =>
VariantUtils.ConvertToGodotObject((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public StringName AsStringName() =>
- VariantUtils.ConvertToStringNameObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToStringName((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NodePath AsNodePath() =>
- VariantUtils.ConvertToNodePathObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToNodePath((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public RID AsRID() =>
- VariantUtils.ConvertToRID((godot_variant)NativeVar);
+ public Rid AsRid() =>
+ VariantUtils.ConvertToRid((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Collections.Dictionary AsGodotDictionary() =>
- VariantUtils.ConvertToDictionaryObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToDictionary((godot_variant)NativeVar);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Collections.Array AsGodotArray() =>
- VariantUtils.ConvertToArrayObject((godot_variant)NativeVar);
+ VariantUtils.ConvertToArray((godot_variant)NativeVar);
// Explicit conversion operators to supported types
@@ -374,13 +416,13 @@ public partial struct Variant : IDisposable
public static explicit operator Vector2(Variant from) => from.AsVector2();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator Vector2i(Variant from) => from.AsVector2i();
+ public static explicit operator Vector2I(Variant from) => from.AsVector2I();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Rect2(Variant from) => from.AsRect2();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator Rect2i(Variant from) => from.AsRect2i();
+ public static explicit operator Rect2I(Variant from) => from.AsRect2I();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Transform2D(Variant from) => from.AsTransform2D();
@@ -389,7 +431,7 @@ public partial struct Variant : IDisposable
public static explicit operator Vector3(Variant from) => from.AsVector3();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator Vector3i(Variant from) => from.AsVector3i();
+ public static explicit operator Vector3I(Variant from) => from.AsVector3I();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Basis(Variant from) => from.AsBasis();
@@ -404,13 +446,13 @@ public partial struct Variant : IDisposable
public static explicit operator Vector4(Variant from) => from.AsVector4();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator Vector4i(Variant from) => from.AsVector4i();
+ public static explicit operator Vector4I(Variant from) => from.AsVector4I();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Projection(Variant from) => from.AsProjection();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator AABB(Variant from) => from.AsAABB();
+ public static explicit operator Aabb(Variant from) => from.AsAabb();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Color(Variant from) => from.AsColor();
@@ -422,7 +464,7 @@ public partial struct Variant : IDisposable
public static explicit operator Callable(Variant from) => from.AsCallable();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator SignalInfo(Variant from) => from.AsSignalInfo();
+ public static explicit operator Signal(Variant from) => from.AsSignal();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator byte[](Variant from) => from.AsByteArray();
@@ -458,10 +500,10 @@ public partial struct Variant : IDisposable
public static explicit operator NodePath[](Variant from) => from.AsSystemArrayOfNodePath();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator RID[](Variant from) => from.AsSystemArrayOfRID();
+ public static explicit operator Rid[](Variant from) => from.AsSystemArrayOfRid();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator Godot.Object(Variant from) => from.AsGodotObject();
+ public static explicit operator GodotObject(Variant from) => from.AsGodotObject();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator StringName(Variant from) => from.AsStringName();
@@ -470,7 +512,7 @@ public partial struct Variant : IDisposable
public static explicit operator NodePath(Variant from) => from.AsNodePath();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator RID(Variant from) => from.AsRID();
+ public static explicit operator Rid(Variant from) => from.AsRid();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Collections.Dictionary(Variant from) => from.AsGodotDictionary();
@@ -524,13 +566,13 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(Vector2 from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(Vector2i from) => from;
+ public static Variant CreateFrom(Vector2I from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Rect2 from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(Rect2i from) => from;
+ public static Variant CreateFrom(Rect2I from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Transform2D from) => from;
@@ -539,7 +581,7 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(Vector3 from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(Vector3i from) => from;
+ public static Variant CreateFrom(Vector3I from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Basis from) => from;
@@ -554,13 +596,13 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(Vector4 from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(Vector4i from) => from;
+ public static Variant CreateFrom(Vector4I from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Projection from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(AABB from) => from;
+ public static Variant CreateFrom(Aabb from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Color from) => from;
@@ -572,7 +614,7 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(Callable from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(SignalInfo from) => from;
+ public static Variant CreateFrom(Signal from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Span<byte> from) => from;
@@ -602,14 +644,14 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(Span<Color> from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(Godot.Object[] from) => from;
+ public static Variant CreateFrom(GodotObject[] from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom<TKey, TValue>(Collections.Dictionary<TKey, TValue> from) =>
+ public static Variant CreateFrom<[MustBeVariant] TKey, [MustBeVariant] TValue>(Collections.Dictionary<TKey, TValue> from) =>
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromDictionary(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom<T>(Collections.Array<T> from) =>
+ public static Variant CreateFrom<[MustBeVariant] T>(Collections.Array<T> from) =>
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromArray(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -619,10 +661,10 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(Span<NodePath> from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(Span<RID> from) => from;
+ public static Variant CreateFrom(Span<Rid> from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(Godot.Object from) => from;
+ public static Variant CreateFrom(GodotObject from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(StringName from) => from;
@@ -631,7 +673,7 @@ public partial struct Variant : IDisposable
public static Variant CreateFrom(NodePath from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Variant CreateFrom(RID from) => from;
+ public static Variant CreateFrom(Rid from) => from;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant CreateFrom(Collections.Dictionary from) => from;
@@ -698,16 +740,16 @@ public partial struct Variant : IDisposable
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector2(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(Vector2i from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector2i(from));
+ public static implicit operator Variant(Vector2I from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector2I(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Variant(Rect2 from) =>
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromRect2(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(Rect2i from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromRect2i(from));
+ public static implicit operator Variant(Rect2I from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromRect2I(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Variant(Transform2D from) =>
@@ -718,8 +760,8 @@ public partial struct Variant : IDisposable
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector3(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(Vector3i from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector3i(from));
+ public static implicit operator Variant(Vector3I from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector3I(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Variant(Basis from) =>
@@ -738,16 +780,16 @@ public partial struct Variant : IDisposable
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector4(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(Vector4i from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector4i(from));
+ public static implicit operator Variant(Vector4I from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector4I(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Variant(Projection from) =>
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromProjection(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(AABB from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromAABB(from));
+ public static implicit operator Variant(Aabb from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromAabb(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Variant(Color from) =>
@@ -762,8 +804,8 @@ public partial struct Variant : IDisposable
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromCallable(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(SignalInfo from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSignalInfo(from));
+ public static implicit operator Variant(Signal from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSignal(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Variant(byte[] from) =>
@@ -802,7 +844,7 @@ public partial struct Variant : IDisposable
(Variant)from.AsSpan();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(Godot.Object[] from) =>
+ public static implicit operator Variant(GodotObject[] from) =>
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfGodotObject(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -814,7 +856,7 @@ public partial struct Variant : IDisposable
(Variant)from.AsSpan();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(RID[] from) =>
+ public static implicit operator Variant(Rid[] from) =>
(Variant)from.AsSpan();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -862,11 +904,11 @@ public partial struct Variant : IDisposable
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfNodePath(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(Span<RID> from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfRID(from));
+ public static implicit operator Variant(Span<Rid> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfRid(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(Godot.Object from) =>
+ public static implicit operator Variant(GodotObject from) =>
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromGodotObject(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -878,8 +920,8 @@ public partial struct Variant : IDisposable
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromNodePath(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator Variant(RID from) =>
- CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromRID(from));
+ public static implicit operator Variant(Rid from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromRid(from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Variant(Collections.Dictionary from) =>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index 87f397891e..0bf8f25f06 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -29,12 +29,12 @@ namespace Godot
/// <summary>
/// The vector's X component. Also accessible by using the index position <c>[0]</c>.
/// </summary>
- public real_t x;
+ public real_t X;
/// <summary>
/// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
/// </summary>
- public real_t y;
+ public real_t Y;
/// <summary>
/// Access vector components using their index.
@@ -43,19 +43,19 @@ namespace Godot
/// <paramref name="index"/> is not 0 or 1.
/// </exception>
/// <value>
- /// <c>[0]</c> is equivalent to <see cref="x"/>,
- /// <c>[1]</c> is equivalent to <see cref="y"/>.
+ /// <c>[0]</c> is equivalent to <see cref="X"/>,
+ /// <c>[1]</c> is equivalent to <see cref="Y"/>.
/// </value>
public real_t this[int index]
{
- get
+ readonly get
{
switch (index)
{
case 0:
- return x;
+ return X;
case 1:
- return y;
+ return Y;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
@@ -65,10 +65,10 @@ namespace Godot
switch (index)
{
case 0:
- x = value;
+ X = value;
return;
case 1:
- y = value;
+ Y = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(index));
@@ -79,10 +79,10 @@ namespace Godot
/// <summary>
/// Helper method for deconstruction into a tuple.
/// </summary>
- public void Deconstruct(out real_t x, out real_t y)
+ public readonly void Deconstruct(out real_t x, out real_t y)
{
- x = this.x;
- y = this.y;
+ x = X;
+ y = Y;
}
internal void Normalize()
@@ -91,13 +91,13 @@ namespace Godot
if (lengthsq == 0)
{
- x = y = 0f;
+ X = Y = 0f;
}
else
{
real_t length = Mathf.Sqrt(lengthsq);
- x /= length;
- y /= length;
+ X /= length;
+ Y /= length;
}
}
@@ -105,21 +105,21 @@ namespace Godot
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns>
- public Vector2 Abs()
+ public readonly Vector2 Abs()
{
- return new Vector2(Mathf.Abs(x), Mathf.Abs(y));
+ return new Vector2(Mathf.Abs(X), Mathf.Abs(Y));
}
/// <summary>
/// Returns this vector's angle with respect to the X axis, or (1, 0) vector, in radians.
///
/// Equivalent to the result of <see cref="Mathf.Atan2(real_t, real_t)"/> when
- /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>.
+ /// called with the vector's <see cref="Y"/> and <see cref="X"/> as parameters: <c>Mathf.Atan2(v.Y, v.X)</c>.
/// </summary>
/// <returns>The angle of this vector, in radians.</returns>
- public real_t Angle()
+ public readonly real_t Angle()
{
- return Mathf.Atan2(y, x);
+ return Mathf.Atan2(Y, X);
}
/// <summary>
@@ -127,7 +127,7 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
/// <returns>The angle between the two vectors, in radians.</returns>
- public real_t AngleTo(Vector2 to)
+ public readonly real_t AngleTo(Vector2 to)
{
return Mathf.Atan2(Cross(to), Dot(to));
}
@@ -137,18 +137,18 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
/// <returns>The angle between the two vectors, in radians.</returns>
- public real_t AngleToPoint(Vector2 to)
+ public readonly real_t AngleToPoint(Vector2 to)
{
- return Mathf.Atan2(y - to.y, x - to.x);
+ return Mathf.Atan2(to.Y - Y, to.X - X);
}
/// <summary>
- /// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>.
+ /// Returns the aspect ratio of this vector, the ratio of <see cref="X"/> to <see cref="Y"/>.
/// </summary>
- /// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns>
- public real_t Aspect()
+ /// <returns>The <see cref="X"/> component divided by the <see cref="Y"/> component.</returns>
+ public readonly real_t Aspect()
{
- return x / y;
+ return X / Y;
}
/// <summary>
@@ -156,7 +156,7 @@ namespace Godot
/// </summary>
/// <param name="normal">The normal vector defining the plane to bounce off. Must be normalized.</param>
/// <returns>The bounced vector.</returns>
- public Vector2 Bounce(Vector2 normal)
+ public readonly Vector2 Bounce(Vector2 normal)
{
return -Reflect(normal);
}
@@ -165,9 +165,9 @@ namespace Godot
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
- public Vector2 Ceil()
+ public readonly Vector2 Ceil()
{
- return new Vector2(Mathf.Ceil(x), Mathf.Ceil(y));
+ return new Vector2(Mathf.Ceil(X), Mathf.Ceil(Y));
}
/// <summary>
@@ -178,12 +178,12 @@ namespace Godot
/// <param name="min">The vector with minimum allowed values.</param>
/// <param name="max">The vector with maximum allowed values.</param>
/// <returns>The vector with all components clamped.</returns>
- public Vector2 Clamp(Vector2 min, Vector2 max)
+ public readonly Vector2 Clamp(Vector2 min, Vector2 max)
{
return new Vector2
(
- Mathf.Clamp(x, min.x, max.x),
- Mathf.Clamp(y, min.y, max.y)
+ Mathf.Clamp(X, min.X, max.X),
+ Mathf.Clamp(Y, min.Y, max.Y)
);
}
@@ -192,9 +192,9 @@ namespace Godot
/// </summary>
/// <param name="with">The other vector.</param>
/// <returns>The cross product value.</returns>
- public real_t Cross(Vector2 with)
+ public readonly real_t Cross(Vector2 with)
{
- return (x * with.y) - (y * with.x);
+ return (X * with.Y) - (Y * with.X);
}
/// <summary>
@@ -206,12 +206,12 @@ namespace Godot
/// <param name="postB">A vector after <paramref name="b"/>.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight)
+ public readonly Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight)
{
return new Vector2
(
- Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
- Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight)
+ Mathf.CubicInterpolate(X, b.X, preA.X, postB.X, weight),
+ Mathf.CubicInterpolate(Y, b.Y, preA.Y, postB.Y, weight)
);
}
@@ -229,34 +229,48 @@ namespace Godot
/// <param name="preAT"></param>
/// <param name="postBT"></param>
/// <returns>The interpolated vector.</returns>
- public Vector2 CubicInterpolateInTime(Vector2 b, Vector2 preA, Vector2 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
+ public readonly Vector2 CubicInterpolateInTime(Vector2 b, Vector2 preA, Vector2 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
{
return new Vector2
(
- Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT),
- Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT)
+ Mathf.CubicInterpolateInTime(X, b.X, preA.X, postB.X, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(Y, b.Y, preA.Y, postB.Y, weight, t, preAT, postBT)
);
}
/// <summary>
/// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector
- /// and the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
+ /// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
/// </summary>
/// <param name="control1">Control point that defines the bezier curve.</param>
/// <param name="control2">Control point that defines the bezier curve.</param>
/// <param name="end">The destination vector.</param>
/// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector2 BezierInterpolate(Vector2 control1, Vector2 control2, Vector2 end, real_t t)
+ public readonly Vector2 BezierInterpolate(Vector2 control1, Vector2 control2, Vector2 end, real_t t)
{
- // Formula from Wikipedia article on Bezier curves
- real_t omt = 1 - t;
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- real_t t3 = t2 * t;
+ return new Vector2
+ (
+ Mathf.BezierInterpolate(X, control1.X, control2.X, end.X, t),
+ Mathf.BezierInterpolate(Y, control1.Y, control2.Y, end.Y, t)
+ );
+ }
- return this * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3;
+ /// <summary>
+ /// Returns the derivative at the given <paramref name="t"/> on the Bezier curve defined by this vector
+ /// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
+ /// </summary>
+ /// <param name="control1">Control point that defines the bezier curve.</param>
+ /// <param name="control2">Control point that defines the bezier curve.</param>
+ /// <param name="end">The destination value for the interpolation.</param>
+ /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public readonly Vector2 BezierDerivative(Vector2 control1, Vector2 control2, Vector2 end, real_t t)
+ {
+ return new Vector2(
+ Mathf.BezierDerivative(X, control1.X, control2.X, end.X, t),
+ Mathf.BezierDerivative(Y, control1.Y, control2.Y, end.Y, t)
+ );
}
/// <summary>
@@ -264,9 +278,9 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to point towards.</param>
/// <returns>The direction from this vector to <paramref name="to"/>.</returns>
- public Vector2 DirectionTo(Vector2 to)
+ public readonly Vector2 DirectionTo(Vector2 to)
{
- return new Vector2(to.x - x, to.y - y).Normalized();
+ return new Vector2(to.X - X, to.Y - Y).Normalized();
}
/// <summary>
@@ -276,9 +290,9 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to use.</param>
/// <returns>The squared distance between the two vectors.</returns>
- public real_t DistanceSquaredTo(Vector2 to)
+ public readonly real_t DistanceSquaredTo(Vector2 to)
{
- return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y);
+ return (X - to.X) * (X - to.X) + (Y - to.Y) * (Y - to.Y);
}
/// <summary>
@@ -286,9 +300,9 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to use.</param>
/// <returns>The distance between the two vectors.</returns>
- public real_t DistanceTo(Vector2 to)
+ public readonly real_t DistanceTo(Vector2 to)
{
- return Mathf.Sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y));
+ return Mathf.Sqrt((X - to.X) * (X - to.X) + (Y - to.Y) * (Y - to.Y));
}
/// <summary>
@@ -296,34 +310,44 @@ namespace Godot
/// </summary>
/// <param name="with">The other vector to use.</param>
/// <returns>The dot product of the two vectors.</returns>
- public real_t Dot(Vector2 with)
+ public readonly real_t Dot(Vector2 with)
{
- return (x * with.x) + (y * with.y);
+ return (X * with.X) + (Y * with.Y);
}
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
- public Vector2 Floor()
+ public readonly Vector2 Floor()
{
- return new Vector2(Mathf.Floor(x), Mathf.Floor(y));
+ return new Vector2(Mathf.Floor(X), Mathf.Floor(Y));
}
/// <summary>
- /// Returns the inverse of this vector. This is the same as <c>new Vector2(1 / v.x, 1 / v.y)</c>.
+ /// Returns the inverse of this vector. This is the same as <c>new Vector2(1 / v.X, 1 / v.Y)</c>.
/// </summary>
/// <returns>The inverse of this vector.</returns>
- public Vector2 Inverse()
+ public readonly Vector2 Inverse()
{
- return new Vector2(1 / x, 1 / y);
+ return new Vector2(1 / X, 1 / Y);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(X) && Mathf.IsFinite(Y);
}
/// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
- public bool IsNormalized()
+ public readonly bool IsNormalized()
{
return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
}
@@ -333,9 +357,9 @@ namespace Godot
/// </summary>
/// <seealso cref="LengthSquared"/>
/// <returns>The length of this vector.</returns>
- public real_t Length()
+ public readonly real_t Length()
{
- return Mathf.Sqrt((x * x) + (y * y));
+ return Mathf.Sqrt((X * X) + (Y * Y));
}
/// <summary>
@@ -344,9 +368,9 @@ namespace Godot
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
- public real_t LengthSquared()
+ public readonly real_t LengthSquared()
{
- return (x * x) + (y * y);
+ return (X * X) + (Y * Y);
}
/// <summary>
@@ -356,30 +380,12 @@ namespace Godot
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
- public Vector2 Lerp(Vector2 to, real_t weight)
+ public readonly Vector2 Lerp(Vector2 to, real_t weight)
{
return new Vector2
(
- Mathf.Lerp(x, to.x, weight),
- Mathf.Lerp(y, to.y, weight)
- );
- }
-
- /// <summary>
- /// Returns the result of the linear interpolation between
- /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>.
- /// </summary>
- /// <param name="to">The destination vector for interpolation.</param>
- /// <param name="weight">
- /// A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.
- /// </param>
- /// <returns>The resulting vector of the interpolation.</returns>
- public Vector2 Lerp(Vector2 to, Vector2 weight)
- {
- return new Vector2
- (
- Mathf.Lerp(x, to.x, weight.x),
- Mathf.Lerp(y, to.y, weight.y)
+ Mathf.Lerp(X, to.X, weight),
+ Mathf.Lerp(Y, to.Y, weight)
);
}
@@ -388,7 +394,7 @@ namespace Godot
/// </summary>
/// <param name="length">The length to limit to.</param>
/// <returns>The vector with its length limited.</returns>
- public Vector2 LimitLength(real_t length = 1.0f)
+ public readonly Vector2 LimitLength(real_t length = 1.0f)
{
Vector2 v = this;
real_t l = Length();
@@ -407,9 +413,9 @@ namespace Godot
/// If both components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the highest axis.</returns>
- public Axis MaxAxisIndex()
+ public readonly Axis MaxAxisIndex()
{
- return x < y ? Axis.Y : Axis.X;
+ return X < Y ? Axis.Y : Axis.X;
}
/// <summary>
@@ -417,9 +423,9 @@ namespace Godot
/// If both components are equal, this method returns <see cref="Axis.Y"/>.
/// </summary>
/// <returns>The index of the lowest axis.</returns>
- public Axis MinAxisIndex()
+ public readonly Axis MinAxisIndex()
{
- return x < y ? Axis.X : Axis.Y;
+ return X < Y ? Axis.X : Axis.Y;
}
/// <summary>
@@ -428,7 +434,7 @@ namespace Godot
/// <param name="to">The vector to move towards.</param>
/// <param name="delta">The amount to move towards by.</param>
/// <returns>The resulting vector.</returns>
- public Vector2 MoveToward(Vector2 to, real_t delta)
+ public readonly Vector2 MoveToward(Vector2 to, real_t delta)
{
Vector2 v = this;
Vector2 vd = to - v;
@@ -443,7 +449,7 @@ namespace Godot
/// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>.
/// </summary>
/// <returns>A normalized version of the vector.</returns>
- public Vector2 Normalized()
+ public readonly Vector2 Normalized()
{
Vector2 v = this;
v.Normalize();
@@ -458,11 +464,11 @@ namespace Godot
/// <returns>
/// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>.
/// </returns>
- public Vector2 PosMod(real_t mod)
+ public readonly Vector2 PosMod(real_t mod)
{
Vector2 v;
- v.x = Mathf.PosMod(x, mod);
- v.y = Mathf.PosMod(y, mod);
+ v.X = Mathf.PosMod(X, mod);
+ v.Y = Mathf.PosMod(Y, mod);
return v;
}
@@ -474,11 +480,11 @@ namespace Godot
/// <returns>
/// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components.
/// </returns>
- public Vector2 PosMod(Vector2 modv)
+ public readonly Vector2 PosMod(Vector2 modv)
{
Vector2 v;
- v.x = Mathf.PosMod(x, modv.x);
- v.y = Mathf.PosMod(y, modv.y);
+ v.X = Mathf.PosMod(X, modv.X);
+ v.Y = Mathf.PosMod(Y, modv.Y);
return v;
}
@@ -487,7 +493,7 @@ namespace Godot
/// </summary>
/// <param name="onNormal">The vector to project onto.</param>
/// <returns>The projected vector.</returns>
- public Vector2 Project(Vector2 onNormal)
+ public readonly Vector2 Project(Vector2 onNormal)
{
return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
}
@@ -497,7 +503,7 @@ namespace Godot
/// </summary>
/// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param>
/// <returns>The reflected vector.</returns>
- public Vector2 Reflect(Vector2 normal)
+ public readonly Vector2 Reflect(Vector2 normal)
{
#if DEBUG
if (!normal.IsNormalized())
@@ -513,13 +519,14 @@ namespace Godot
/// </summary>
/// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
- public Vector2 Rotated(real_t angle)
+ public readonly Vector2 Rotated(real_t angle)
{
- real_t sine = Mathf.Sin(angle);
- real_t cosi = Mathf.Cos(angle);
- return new Vector2(
- x * cosi - y * sine,
- x * sine + y * cosi);
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+ return new Vector2
+ (
+ X * cos - Y * sin,
+ X * sin + Y * cos
+ );
}
/// <summary>
@@ -527,9 +534,9 @@ namespace Godot
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
/// <returns>The rounded vector.</returns>
- public Vector2 Round()
+ public readonly Vector2 Round()
{
- return new Vector2(Mathf.Round(x), Mathf.Round(y));
+ return new Vector2(Mathf.Round(X), Mathf.Round(Y));
}
/// <summary>
@@ -538,11 +545,11 @@ namespace Godot
/// by calling <see cref="Mathf.Sign(real_t)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
- public Vector2 Sign()
+ public readonly Vector2 Sign()
{
Vector2 v;
- v.x = Mathf.Sign(x);
- v.y = Mathf.Sign(y);
+ v.X = Mathf.Sign(X);
+ v.Y = Mathf.Sign(Y);
return v;
}
@@ -557,7 +564,7 @@ namespace Godot
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
- public Vector2 Slerp(Vector2 to, real_t weight)
+ public readonly Vector2 Slerp(Vector2 to, real_t weight)
{
real_t startLengthSquared = LengthSquared();
real_t endLengthSquared = to.LengthSquared();
@@ -577,7 +584,7 @@ namespace Godot
/// </summary>
/// <param name="normal">The normal vector defining the plane to slide on.</param>
/// <returns>The slid vector.</returns>
- public Vector2 Slide(Vector2 normal)
+ public readonly Vector2 Slide(Vector2 normal)
{
return this - (normal * Dot(normal));
}
@@ -588,9 +595,9 @@ namespace Godot
/// </summary>
/// <param name="step">A vector value representing the step size to snap to.</param>
/// <returns>The snapped vector.</returns>
- public Vector2 Snapped(Vector2 step)
+ public readonly Vector2 Snapped(Vector2 step)
{
- return new Vector2(Mathf.Snapped(x, step.x), Mathf.Snapped(y, step.y));
+ return new Vector2(Mathf.Snapped(X, step.X), Mathf.Snapped(Y, step.Y));
}
/// <summary>
@@ -598,9 +605,9 @@ namespace Godot
/// compared to the original, with the same length.
/// </summary>
/// <returns>The perpendicular vector.</returns>
- public Vector2 Orthogonal()
+ public readonly Vector2 Orthogonal()
{
- return new Vector2(y, -x);
+ return new Vector2(Y, -X);
}
// Constants
@@ -657,8 +664,8 @@ namespace Godot
/// <param name="y">The vector's Y component.</param>
public Vector2(real_t x, real_t y)
{
- this.x = x;
- this.y = y;
+ X = x;
+ Y = y;
}
/// <summary>
@@ -669,7 +676,8 @@ namespace Godot
/// <returns>The resulting vector.</returns>
public static Vector2 FromAngle(real_t angle)
{
- return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+ return new Vector2(cos, sin);
}
/// <summary>
@@ -681,8 +689,8 @@ namespace Godot
/// <returns>The added vector.</returns>
public static Vector2 operator +(Vector2 left, Vector2 right)
{
- left.x += right.x;
- left.y += right.y;
+ left.X += right.X;
+ left.Y += right.Y;
return left;
}
@@ -695,14 +703,14 @@ namespace Godot
/// <returns>The subtracted vector.</returns>
public static Vector2 operator -(Vector2 left, Vector2 right)
{
- left.x -= right.x;
- left.y -= right.y;
+ left.X -= right.X;
+ left.Y -= right.Y;
return left;
}
/// <summary>
/// Returns the negative value of the <see cref="Vector2"/>.
- /// This is the same as writing <c>new Vector2(-v.x, -v.y)</c>.
+ /// This is the same as writing <c>new Vector2(-v.X, -v.Y)</c>.
/// This operation flips the direction of the vector while
/// keeping the same magnitude.
/// With floats, the number zero can be either positive or negative.
@@ -711,8 +719,8 @@ namespace Godot
/// <returns>The negated/flipped vector.</returns>
public static Vector2 operator -(Vector2 vec)
{
- vec.x = -vec.x;
- vec.y = -vec.y;
+ vec.X = -vec.X;
+ vec.Y = -vec.Y;
return vec;
}
@@ -725,8 +733,8 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector2 operator *(Vector2 vec, real_t scale)
{
- vec.x *= scale;
- vec.y *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
return vec;
}
@@ -739,8 +747,8 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector2 operator *(real_t scale, Vector2 vec)
{
- vec.x *= scale;
- vec.y *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
return vec;
}
@@ -753,8 +761,8 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector2 operator *(Vector2 left, Vector2 right)
{
- left.x *= right.x;
- left.y *= right.y;
+ left.X *= right.X;
+ left.Y *= right.Y;
return left;
}
@@ -767,8 +775,8 @@ namespace Godot
/// <returns>The divided vector.</returns>
public static Vector2 operator /(Vector2 vec, real_t divisor)
{
- vec.x /= divisor;
- vec.y /= divisor;
+ vec.X /= divisor;
+ vec.Y /= divisor;
return vec;
}
@@ -781,8 +789,8 @@ namespace Godot
/// <returns>The divided vector.</returns>
public static Vector2 operator /(Vector2 vec, Vector2 divisorv)
{
- vec.x /= divisorv.x;
- vec.y /= divisorv.y;
+ vec.X /= divisorv.X;
+ vec.Y /= divisorv.Y;
return vec;
}
@@ -804,8 +812,8 @@ namespace Godot
/// <returns>The remainder vector.</returns>
public static Vector2 operator %(Vector2 vec, real_t divisor)
{
- vec.x %= divisor;
- vec.y %= divisor;
+ vec.X %= divisor;
+ vec.Y %= divisor;
return vec;
}
@@ -827,8 +835,8 @@ namespace Godot
/// <returns>The remainder vector.</returns>
public static Vector2 operator %(Vector2 vec, Vector2 divisorv)
{
- vec.x %= divisorv.x;
- vec.y %= divisorv.y;
+ vec.X %= divisorv.X;
+ vec.Y %= divisorv.Y;
return vec;
}
@@ -871,11 +879,11 @@ namespace Godot
/// <returns>Whether or not the left is less than the right.</returns>
public static bool operator <(Vector2 left, Vector2 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
@@ -891,11 +899,11 @@ namespace Godot
/// <returns>Whether or not the left is greater than the right.</returns>
public static bool operator >(Vector2 left, Vector2 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
@@ -911,11 +919,11 @@ namespace Godot
/// <returns>Whether or not the left is less than or equal to the right.</returns>
public static bool operator <=(Vector2 left, Vector2 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- return left.y <= right.y;
+ return left.Y <= right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
@@ -931,11 +939,11 @@ namespace Godot
/// <returns>Whether or not the left is greater than or equal to the right.</returns>
public static bool operator >=(Vector2 left, Vector2 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- return left.y >= right.y;
+ return left.Y >= right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
@@ -946,7 +954,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Vector2 other && Equals(other);
}
@@ -958,9 +966,9 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>Whether or not the vectors are exactly equal.</returns>
- public bool Equals(Vector2 other)
+ public readonly bool Equals(Vector2 other)
{
- return x == other.x && y == other.y;
+ return X == other.X && Y == other.Y;
}
/// <summary>
@@ -969,36 +977,48 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector to compare.</param>
/// <returns>Whether or not the vectors are approximately equal.</returns>
- public bool IsEqualApprox(Vector2 other)
+ public readonly bool IsEqualApprox(Vector2 other)
+ {
+ return Mathf.IsEqualApprox(X, other.X) && Mathf.IsEqualApprox(Y, other.Y);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
{
- return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y);
+ return Mathf.IsZeroApprox(X) && Mathf.IsZeroApprox(Y);
}
/// <summary>
/// Serves as the hash function for <see cref="Vector2"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return y.GetHashCode() ^ x.GetHashCode();
+ return Y.GetHashCode() ^ X.GetHashCode();
}
/// <summary>
/// Converts this <see cref="Vector2"/> to a string.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"({x}, {y})";
+ return $"({X}, {Y})";
}
/// <summary>
/// Converts this <see cref="Vector2"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"({x.ToString(format)}, {y.ToString(format)})";
+ return $"({X.ToString(format)}, {Y.ToString(format)})";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
index bdadf696e3..e849939ebb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
@@ -8,7 +8,7 @@ namespace Godot
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
- public struct Vector2i : IEquatable<Vector2i>
+ public struct Vector2I : IEquatable<Vector2I>
{
/// <summary>
/// Enumerated index values for the axes.
@@ -29,12 +29,12 @@ namespace Godot
/// <summary>
/// The vector's X component. Also accessible by using the index position <c>[0]</c>.
/// </summary>
- public int x;
+ public int X;
/// <summary>
/// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
/// </summary>
- public int y;
+ public int Y;
/// <summary>
/// Access vector components using their index.
@@ -43,19 +43,19 @@ namespace Godot
/// <paramref name="index"/> is not 0 or 1.
/// </exception>
/// <value>
- /// <c>[0]</c> is equivalent to <see cref="x"/>,
- /// <c>[1]</c> is equivalent to <see cref="y"/>.
+ /// <c>[0]</c> is equivalent to <see cref="X"/>,
+ /// <c>[1]</c> is equivalent to <see cref="Y"/>.
/// </value>
public int this[int index]
{
- get
+ readonly get
{
switch (index)
{
case 0:
- return x;
+ return X;
case 1:
- return y;
+ return Y;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
@@ -65,10 +65,10 @@ namespace Godot
switch (index)
{
case 0:
- x = value;
+ X = value;
return;
case 1:
- y = value;
+ Y = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(index));
@@ -79,60 +79,28 @@ namespace Godot
/// <summary>
/// Helper method for deconstruction into a tuple.
/// </summary>
- public void Deconstruct(out int x, out int y)
+ public readonly void Deconstruct(out int x, out int y)
{
- x = this.x;
- y = this.y;
+ x = X;
+ y = Y;
}
/// <summary>
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns>
- public Vector2i Abs()
+ public readonly Vector2I Abs()
{
- return new Vector2i(Mathf.Abs(x), Mathf.Abs(y));
+ return new Vector2I(Mathf.Abs(X), Mathf.Abs(Y));
}
/// <summary>
- /// Returns this vector's angle with respect to the X axis, or (1, 0) vector, in radians.
- ///
- /// Equivalent to the result of <see cref="Mathf.Atan2(real_t, real_t)"/> when
- /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>.
+ /// Returns the aspect ratio of this vector, the ratio of <see cref="X"/> to <see cref="Y"/>.
/// </summary>
- /// <returns>The angle of this vector, in radians.</returns>
- public real_t Angle()
+ /// <returns>The <see cref="X"/> component divided by the <see cref="Y"/> component.</returns>
+ public readonly real_t Aspect()
{
- return Mathf.Atan2(y, x);
- }
-
- /// <summary>
- /// Returns the angle to the given vector, in radians.
- /// </summary>
- /// <param name="to">The other vector to compare this vector to.</param>
- /// <returns>The angle between the two vectors, in radians.</returns>
- public real_t AngleTo(Vector2i to)
- {
- return Mathf.Atan2(Cross(to), Dot(to));
- }
-
- /// <summary>
- /// Returns the angle between the line connecting the two points and the X axis, in radians.
- /// </summary>
- /// <param name="to">The other vector to compare this vector to.</param>
- /// <returns>The angle between the two vectors, in radians.</returns>
- public real_t AngleToPoint(Vector2i to)
- {
- return Mathf.Atan2(y - to.y, x - to.x);
- }
-
- /// <summary>
- /// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>.
- /// </summary>
- /// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns>
- public real_t Aspect()
- {
- return x / (real_t)y;
+ return X / (real_t)Y;
}
/// <summary>
@@ -143,66 +111,24 @@ namespace Godot
/// <param name="min">The vector with minimum allowed values.</param>
/// <param name="max">The vector with maximum allowed values.</param>
/// <returns>The vector with all components clamped.</returns>
- public Vector2i Clamp(Vector2i min, Vector2i max)
+ public readonly Vector2I Clamp(Vector2I min, Vector2I max)
{
- return new Vector2i
+ return new Vector2I
(
- Mathf.Clamp(x, min.x, max.x),
- Mathf.Clamp(y, min.y, max.y)
+ Mathf.Clamp(X, min.X, max.X),
+ Mathf.Clamp(Y, min.Y, max.Y)
);
}
/// <summary>
- /// Returns the cross product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector.</param>
- /// <returns>The cross product vector.</returns>
- public int Cross(Vector2i with)
- {
- return x * with.y - y * with.x;
- }
-
- /// <summary>
- /// Returns the squared distance between this vector and <paramref name="to"/>.
- /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
- /// you need to compare vectors or need the squared distance for some formula.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The squared distance between the two vectors.</returns>
- public int DistanceSquaredTo(Vector2i to)
- {
- return (to - this).LengthSquared();
- }
-
- /// <summary>
- /// Returns the distance between this vector and <paramref name="to"/>.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The distance between the two vectors.</returns>
- public real_t DistanceTo(Vector2i to)
- {
- return (to - this).Length();
- }
-
- /// <summary>
- /// Returns the dot product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector to use.</param>
- /// <returns>The dot product of the two vectors.</returns>
- public int Dot(Vector2i with)
- {
- return x * with.x + y * with.y;
- }
-
- /// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <seealso cref="LengthSquared"/>
/// <returns>The length of this vector.</returns>
- public real_t Length()
+ public readonly real_t Length()
{
- int x2 = x * x;
- int y2 = y * y;
+ int x2 = X * X;
+ int y2 = Y * Y;
return Mathf.Sqrt(x2 + y2);
}
@@ -213,10 +139,10 @@ namespace Godot
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
- public int LengthSquared()
+ public readonly int LengthSquared()
{
- int x2 = x * x;
- int y2 = y * y;
+ int x2 = X * X;
+ int y2 = Y * Y;
return x2 + y2;
}
@@ -226,9 +152,9 @@ namespace Godot
/// If both components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the highest axis.</returns>
- public Axis MaxAxisIndex()
+ public readonly Axis MaxAxisIndex()
{
- return x < y ? Axis.Y : Axis.X;
+ return X < Y ? Axis.Y : Axis.X;
}
/// <summary>
@@ -236,41 +162,9 @@ namespace Godot
/// If both components are equal, this method returns <see cref="Axis.Y"/>.
/// </summary>
/// <returns>The index of the lowest axis.</returns>
- public Axis MinAxisIndex()
- {
- return x < y ? Axis.X : Axis.Y;
- }
-
- /// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="mod"/>.
- /// </summary>
- /// <param name="mod">A value representing the divisor of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>.
- /// </returns>
- public Vector2i PosMod(int mod)
+ public readonly Axis MinAxisIndex()
{
- Vector2i v = this;
- v.x = Mathf.PosMod(v.x, mod);
- v.y = Mathf.PosMod(v.y, mod);
- return v;
- }
-
- /// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="modv"/>'s components.
- /// </summary>
- /// <param name="modv">A vector representing the divisors of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components.
- /// </returns>
- public Vector2i PosMod(Vector2i modv)
- {
- Vector2i v = this;
- v.x = Mathf.PosMod(v.x, modv.x);
- v.y = Mathf.PosMod(v.y, modv.y);
- return v;
+ return X < Y ? Axis.X : Axis.Y;
}
/// <summary>
@@ -279,260 +173,222 @@ namespace Godot
/// by calling <see cref="Mathf.Sign(int)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
- public Vector2i Sign()
+ public readonly Vector2I Sign()
{
- Vector2i v = this;
- v.x = Mathf.Sign(v.x);
- v.y = Mathf.Sign(v.y);
+ Vector2I v = this;
+ v.X = Mathf.Sign(v.X);
+ v.Y = Mathf.Sign(v.Y);
return v;
}
- /// <summary>
- /// Returns a perpendicular vector rotated 90 degrees counter-clockwise
- /// compared to the original, with the same length.
- /// </summary>
- /// <returns>The perpendicular vector.</returns>
- public Vector2i Orthogonal()
- {
- return new Vector2i(y, -x);
- }
-
// Constants
- private static readonly Vector2i _zero = new Vector2i(0, 0);
- private static readonly Vector2i _one = new Vector2i(1, 1);
+ private static readonly Vector2I _zero = new Vector2I(0, 0);
+ private static readonly Vector2I _one = new Vector2I(1, 1);
- private static readonly Vector2i _up = new Vector2i(0, -1);
- private static readonly Vector2i _down = new Vector2i(0, 1);
- private static readonly Vector2i _right = new Vector2i(1, 0);
- private static readonly Vector2i _left = new Vector2i(-1, 0);
+ private static readonly Vector2I _up = new Vector2I(0, -1);
+ private static readonly Vector2I _down = new Vector2I(0, 1);
+ private static readonly Vector2I _right = new Vector2I(1, 0);
+ private static readonly Vector2I _left = new Vector2I(-1, 0);
/// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
/// </summary>
- /// <value>Equivalent to <c>new Vector2i(0, 0)</c>.</value>
- public static Vector2i Zero { get { return _zero; } }
+ /// <value>Equivalent to <c>new Vector2I(0, 0)</c>.</value>
+ public static Vector2I Zero { get { return _zero; } }
/// <summary>
/// One vector, a vector with all components set to <c>1</c>.
/// </summary>
- /// <value>Equivalent to <c>new Vector2i(1, 1)</c>.</value>
- public static Vector2i One { get { return _one; } }
+ /// <value>Equivalent to <c>new Vector2I(1, 1)</c>.</value>
+ public static Vector2I One { get { return _one; } }
/// <summary>
/// Up unit vector. Y is down in 2D, so this vector points -Y.
/// </summary>
- /// <value>Equivalent to <c>new Vector2i(0, -1)</c>.</value>
- public static Vector2i Up { get { return _up; } }
+ /// <value>Equivalent to <c>new Vector2I(0, -1)</c>.</value>
+ public static Vector2I Up { get { return _up; } }
/// <summary>
/// Down unit vector. Y is down in 2D, so this vector points +Y.
/// </summary>
- /// <value>Equivalent to <c>new Vector2i(0, 1)</c>.</value>
- public static Vector2i Down { get { return _down; } }
+ /// <value>Equivalent to <c>new Vector2I(0, 1)</c>.</value>
+ public static Vector2I Down { get { return _down; } }
/// <summary>
/// Right unit vector. Represents the direction of right.
/// </summary>
- /// <value>Equivalent to <c>new Vector2i(1, 0)</c>.</value>
- public static Vector2i Right { get { return _right; } }
+ /// <value>Equivalent to <c>new Vector2I(1, 0)</c>.</value>
+ public static Vector2I Right { get { return _right; } }
/// <summary>
/// Left unit vector. Represents the direction of left.
/// </summary>
- /// <value>Equivalent to <c>new Vector2i(-1, 0)</c>.</value>
- public static Vector2i Left { get { return _left; } }
+ /// <value>Equivalent to <c>new Vector2I(-1, 0)</c>.</value>
+ public static Vector2I Left { get { return _left; } }
/// <summary>
- /// Constructs a new <see cref="Vector2i"/> with the given components.
+ /// Constructs a new <see cref="Vector2I"/> with the given components.
/// </summary>
/// <param name="x">The vector's X component.</param>
/// <param name="y">The vector's Y component.</param>
- public Vector2i(int x, int y)
+ public Vector2I(int x, int y)
{
- this.x = x;
- this.y = y;
+ X = x;
+ Y = y;
}
/// <summary>
- /// Adds each component of the <see cref="Vector2i"/>
- /// with the components of the given <see cref="Vector2i"/>.
+ /// Adds each component of the <see cref="Vector2I"/>
+ /// with the components of the given <see cref="Vector2I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The added vector.</returns>
- public static Vector2i operator +(Vector2i left, Vector2i right)
+ public static Vector2I operator +(Vector2I left, Vector2I right)
{
- left.x += right.x;
- left.y += right.y;
+ left.X += right.X;
+ left.Y += right.Y;
return left;
}
/// <summary>
- /// Subtracts each component of the <see cref="Vector2i"/>
- /// by the components of the given <see cref="Vector2i"/>.
+ /// Subtracts each component of the <see cref="Vector2I"/>
+ /// by the components of the given <see cref="Vector2I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The subtracted vector.</returns>
- public static Vector2i operator -(Vector2i left, Vector2i right)
+ public static Vector2I operator -(Vector2I left, Vector2I right)
{
- left.x -= right.x;
- left.y -= right.y;
+ left.X -= right.X;
+ left.Y -= right.Y;
return left;
}
/// <summary>
- /// Returns the negative value of the <see cref="Vector2i"/>.
- /// This is the same as writing <c>new Vector2i(-v.x, -v.y)</c>.
+ /// Returns the negative value of the <see cref="Vector2I"/>.
+ /// This is the same as writing <c>new Vector2I(-v.X, -v.Y)</c>.
/// This operation flips the direction of the vector while
/// keeping the same magnitude.
/// </summary>
/// <param name="vec">The vector to negate/flip.</param>
/// <returns>The negated/flipped vector.</returns>
- public static Vector2i operator -(Vector2i vec)
+ public static Vector2I operator -(Vector2I vec)
{
- vec.x = -vec.x;
- vec.y = -vec.y;
+ vec.X = -vec.X;
+ vec.Y = -vec.Y;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector2i"/>
+ /// Multiplies each component of the <see cref="Vector2I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="vec">The vector to multiply.</param>
/// <param name="scale">The scale to multiply by.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector2i operator *(Vector2i vec, int scale)
+ public static Vector2I operator *(Vector2I vec, int scale)
{
- vec.x *= scale;
- vec.y *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector2i"/>
+ /// Multiplies each component of the <see cref="Vector2I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="scale">The scale to multiply by.</param>
/// <param name="vec">The vector to multiply.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector2i operator *(int scale, Vector2i vec)
+ public static Vector2I operator *(int scale, Vector2I vec)
{
- vec.x *= scale;
- vec.y *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector2i"/>
- /// by the components of the given <see cref="Vector2i"/>.
+ /// Multiplies each component of the <see cref="Vector2I"/>
+ /// by the components of the given <see cref="Vector2I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector2i operator *(Vector2i left, Vector2i right)
+ public static Vector2I operator *(Vector2I left, Vector2I right)
{
- left.x *= right.x;
- left.y *= right.y;
+ left.X *= right.X;
+ left.Y *= right.Y;
return left;
}
/// <summary>
- /// Divides each component of the <see cref="Vector2i"/>
+ /// Divides each component of the <see cref="Vector2I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisor">The divisor value.</param>
/// <returns>The divided vector.</returns>
- public static Vector2i operator /(Vector2i vec, int divisor)
+ public static Vector2I operator /(Vector2I vec, int divisor)
{
- vec.x /= divisor;
- vec.y /= divisor;
+ vec.X /= divisor;
+ vec.Y /= divisor;
return vec;
}
/// <summary>
- /// Divides each component of the <see cref="Vector2i"/>
- /// by the components of the given <see cref="Vector2i"/>.
+ /// Divides each component of the <see cref="Vector2I"/>
+ /// by the components of the given <see cref="Vector2I"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisorv">The divisor vector.</param>
/// <returns>The divided vector.</returns>
- public static Vector2i operator /(Vector2i vec, Vector2i divisorv)
+ public static Vector2I operator /(Vector2I vec, Vector2I divisorv)
{
- vec.x /= divisorv.x;
- vec.y /= divisorv.y;
+ vec.X /= divisorv.X;
+ vec.Y /= divisorv.Y;
return vec;
}
/// <summary>
- /// Gets the remainder of each component of the <see cref="Vector2i"/>
+ /// Gets the remainder of each component of the <see cref="Vector2I"/>
/// with the components of the given <see langword="int"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(int)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
/// <code>
- /// GD.Print(new Vector2i(10, -20) % 7); // Prints "(3, -6)"
+ /// GD.Print(new Vector2I(10, -20) % 7); // Prints "(3, -6)"
/// </code>
/// </example>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisor">The divisor value.</param>
/// <returns>The remainder vector.</returns>
- public static Vector2i operator %(Vector2i vec, int divisor)
+ public static Vector2I operator %(Vector2I vec, int divisor)
{
- vec.x %= divisor;
- vec.y %= divisor;
+ vec.X %= divisor;
+ vec.Y %= divisor;
return vec;
}
/// <summary>
- /// Gets the remainder of each component of the <see cref="Vector2i"/>
- /// with the components of the given <see cref="Vector2i"/>.
+ /// Gets the remainder of each component of the <see cref="Vector2I"/>
+ /// with the components of the given <see cref="Vector2I"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(Vector2i)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
/// <code>
- /// GD.Print(new Vector2i(10, -20) % new Vector2i(7, 8)); // Prints "(3, -4)"
+ /// GD.Print(new Vector2I(10, -20) % new Vector2I(7, 8)); // Prints "(3, -4)"
/// </code>
/// </example>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisorv">The divisor vector.</param>
/// <returns>The remainder vector.</returns>
- public static Vector2i operator %(Vector2i vec, Vector2i divisorv)
- {
- vec.x %= divisorv.x;
- vec.y %= divisorv.y;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector2i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector2i operator &(Vector2i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector2i"/>
- /// and the given <see cref="Vector2i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector2i operator &(Vector2i vec, Vector2i andv)
+ public static Vector2I operator %(Vector2I vec, Vector2I divisorv)
{
- vec.x &= andv.x;
- vec.y &= andv.y;
+ vec.X %= divisorv.X;
+ vec.Y %= divisorv.Y;
return vec;
}
@@ -542,7 +398,7 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the vectors are equal.</returns>
- public static bool operator ==(Vector2i left, Vector2i right)
+ public static bool operator ==(Vector2I left, Vector2I right)
{
return left.Equals(right);
}
@@ -553,13 +409,13 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the vectors are not equal.</returns>
- public static bool operator !=(Vector2i left, Vector2i right)
+ public static bool operator !=(Vector2I left, Vector2I right)
{
return !left.Equals(right);
}
/// <summary>
- /// Compares two <see cref="Vector2i"/> vectors by first checking if
+ /// Compares two <see cref="Vector2I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is less than
/// the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -569,17 +425,17 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is less than the right.</returns>
- public static bool operator <(Vector2i left, Vector2i right)
+ public static bool operator <(Vector2I left, Vector2I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
- /// Compares two <see cref="Vector2i"/> vectors by first checking if
+ /// Compares two <see cref="Vector2I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is greater than
/// the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -589,17 +445,17 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is greater than the right.</returns>
- public static bool operator >(Vector2i left, Vector2i right)
+ public static bool operator >(Vector2I left, Vector2I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
- /// Compares two <see cref="Vector2i"/> vectors by first checking if
+ /// Compares two <see cref="Vector2I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is less than
/// or equal to the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -609,17 +465,17 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is less than or equal to the right.</returns>
- public static bool operator <=(Vector2i left, Vector2i right)
+ public static bool operator <=(Vector2I left, Vector2I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- return left.y <= right.y;
+ return left.Y <= right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
- /// Compares two <see cref="Vector2i"/> vectors by first checking if
+ /// Compares two <see cref="Vector2I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is greater than
/// or equal to the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -629,33 +485,33 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is greater than or equal to the right.</returns>
- public static bool operator >=(Vector2i left, Vector2i right)
+ public static bool operator >=(Vector2I left, Vector2I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- return left.y >= right.y;
+ return left.Y >= right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
- /// Converts this <see cref="Vector2i"/> to a <see cref="Vector2"/>.
+ /// Converts this <see cref="Vector2I"/> to a <see cref="Vector2"/>.
/// </summary>
/// <param name="value">The vector to convert.</param>
- public static implicit operator Vector2(Vector2i value)
+ public static implicit operator Vector2(Vector2I value)
{
- return new Vector2(value.x, value.y);
+ return new Vector2(value.X, value.Y);
}
/// <summary>
- /// Converts a <see cref="Vector2"/> to a <see cref="Vector2i"/>.
+ /// Converts a <see cref="Vector2"/> to a <see cref="Vector2I"/>.
/// </summary>
/// <param name="value">The vector to convert.</param>
- public static explicit operator Vector2i(Vector2 value)
+ public static explicit operator Vector2I(Vector2 value)
{
- return new Vector2i(
- Mathf.RoundToInt(value.x),
- Mathf.RoundToInt(value.y)
+ return new Vector2I(
+ Mathf.RoundToInt(value.X),
+ Mathf.RoundToInt(value.Y)
);
}
@@ -665,9 +521,9 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
- return obj is Vector2i other && Equals(other);
+ return obj is Vector2I other && Equals(other);
}
/// <summary>
@@ -675,36 +531,36 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>Whether or not the vectors are equal.</returns>
- public bool Equals(Vector2i other)
+ public readonly bool Equals(Vector2I other)
{
- return x == other.x && y == other.y;
+ return X == other.X && Y == other.Y;
}
/// <summary>
- /// Serves as the hash function for <see cref="Vector2i"/>.
+ /// Serves as the hash function for <see cref="Vector2I"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return y.GetHashCode() ^ x.GetHashCode();
+ return Y.GetHashCode() ^ X.GetHashCode();
}
/// <summary>
- /// Converts this <see cref="Vector2i"/> to a string.
+ /// Converts this <see cref="Vector2I"/> to a string.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"({x}, {y})";
+ return $"({X}, {Y})";
}
/// <summary>
- /// Converts this <see cref="Vector2i"/> to a string with the given <paramref name="format"/>.
+ /// Converts this <see cref="Vector2I"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"({x.ToString(format)}, {y.ToString(format)})";
+ return $"({X.ToString(format)}, {Y.ToString(format)})";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 6649f3b784..c773c0fda6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -33,17 +33,17 @@ namespace Godot
/// <summary>
/// The vector's X component. Also accessible by using the index position <c>[0]</c>.
/// </summary>
- public real_t x;
+ public real_t X;
/// <summary>
/// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
/// </summary>
- public real_t y;
+ public real_t Y;
/// <summary>
/// The vector's Z component. Also accessible by using the index position <c>[2]</c>.
/// </summary>
- public real_t z;
+ public real_t Z;
/// <summary>
/// Access vector components using their index.
@@ -52,22 +52,22 @@ namespace Godot
/// <paramref name="index"/> is not 0, 1 or 2.
/// </exception>
/// <value>
- /// <c>[0]</c> is equivalent to <see cref="x"/>,
- /// <c>[1]</c> is equivalent to <see cref="y"/>,
- /// <c>[2]</c> is equivalent to <see cref="z"/>.
+ /// <c>[0]</c> is equivalent to <see cref="X"/>,
+ /// <c>[1]</c> is equivalent to <see cref="Y"/>,
+ /// <c>[2]</c> is equivalent to <see cref="Z"/>.
/// </value>
public real_t this[int index]
{
- get
+ readonly get
{
switch (index)
{
case 0:
- return x;
+ return X;
case 1:
- return y;
+ return Y;
case 2:
- return z;
+ return Z;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
@@ -77,13 +77,13 @@ namespace Godot
switch (index)
{
case 0:
- x = value;
+ X = value;
return;
case 1:
- y = value;
+ Y = value;
return;
case 2:
- z = value;
+ Z = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(index));
@@ -94,11 +94,11 @@ namespace Godot
/// <summary>
/// Helper method for deconstruction into a tuple.
/// </summary>
- public void Deconstruct(out real_t x, out real_t y, out real_t z)
+ public readonly void Deconstruct(out real_t x, out real_t y, out real_t z)
{
- x = this.x;
- y = this.y;
- z = this.z;
+ x = X;
+ y = Y;
+ z = Z;
}
internal void Normalize()
@@ -107,14 +107,14 @@ namespace Godot
if (lengthsq == 0)
{
- x = y = z = 0f;
+ X = Y = Z = 0f;
}
else
{
real_t length = Mathf.Sqrt(lengthsq);
- x /= length;
- y /= length;
- z /= length;
+ X /= length;
+ Y /= length;
+ Z /= length;
}
}
@@ -122,9 +122,9 @@ namespace Godot
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns>
- public Vector3 Abs()
+ public readonly Vector3 Abs()
{
- return new Vector3(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z));
+ return new Vector3(Mathf.Abs(X), Mathf.Abs(Y), Mathf.Abs(Z));
}
/// <summary>
@@ -132,7 +132,7 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
/// <returns>The unsigned angle between the two vectors, in radians.</returns>
- public real_t AngleTo(Vector3 to)
+ public readonly real_t AngleTo(Vector3 to)
{
return Mathf.Atan2(Cross(to).Length(), Dot(to));
}
@@ -142,7 +142,7 @@ namespace Godot
/// </summary>
/// <param name="normal">The normal vector defining the plane to bounce off. Must be normalized.</param>
/// <returns>The bounced vector.</returns>
- public Vector3 Bounce(Vector3 normal)
+ public readonly Vector3 Bounce(Vector3 normal)
{
return -Reflect(normal);
}
@@ -151,9 +151,9 @@ namespace Godot
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
- public Vector3 Ceil()
+ public readonly Vector3 Ceil()
{
- return new Vector3(Mathf.Ceil(x), Mathf.Ceil(y), Mathf.Ceil(z));
+ return new Vector3(Mathf.Ceil(X), Mathf.Ceil(Y), Mathf.Ceil(Z));
}
/// <summary>
@@ -164,13 +164,13 @@ namespace Godot
/// <param name="min">The vector with minimum allowed values.</param>
/// <param name="max">The vector with maximum allowed values.</param>
/// <returns>The vector with all components clamped.</returns>
- public Vector3 Clamp(Vector3 min, Vector3 max)
+ public readonly Vector3 Clamp(Vector3 min, Vector3 max)
{
return new Vector3
(
- Mathf.Clamp(x, min.x, max.x),
- Mathf.Clamp(y, min.y, max.y),
- Mathf.Clamp(z, min.z, max.z)
+ Mathf.Clamp(X, min.X, max.X),
+ Mathf.Clamp(Y, min.Y, max.Y),
+ Mathf.Clamp(Z, min.Z, max.Z)
);
}
@@ -179,13 +179,13 @@ namespace Godot
/// </summary>
/// <param name="with">The other vector.</param>
/// <returns>The cross product vector.</returns>
- public Vector3 Cross(Vector3 with)
+ public readonly Vector3 Cross(Vector3 with)
{
return new Vector3
(
- (y * with.z) - (z * with.y),
- (z * with.x) - (x * with.z),
- (x * with.y) - (y * with.x)
+ (Y * with.Z) - (Z * with.Y),
+ (Z * with.X) - (X * with.Z),
+ (X * with.Y) - (Y * with.X)
);
}
@@ -198,13 +198,13 @@ namespace Godot
/// <param name="postB">A vector after <paramref name="b"/>.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight)
+ public readonly Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight)
{
return new Vector3
(
- Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
- Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight),
- Mathf.CubicInterpolate(z, b.z, preA.z, postB.z, weight)
+ Mathf.CubicInterpolate(X, b.X, preA.X, postB.X, weight),
+ Mathf.CubicInterpolate(Y, b.Y, preA.Y, postB.Y, weight),
+ Mathf.CubicInterpolate(Z, b.Z, preA.Z, postB.Z, weight)
);
}
@@ -222,35 +222,51 @@ namespace Godot
/// <param name="preAT"></param>
/// <param name="postBT"></param>
/// <returns>The interpolated vector.</returns>
- public Vector3 CubicInterpolateInTime(Vector3 b, Vector3 preA, Vector3 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
+ public readonly Vector3 CubicInterpolateInTime(Vector3 b, Vector3 preA, Vector3 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
{
return new Vector3
(
- Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT),
- Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT),
- Mathf.CubicInterpolateInTime(z, b.z, preA.z, postB.z, weight, t, preAT, postBT)
+ Mathf.CubicInterpolateInTime(X, b.X, preA.X, postB.X, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(Y, b.Y, preA.Y, postB.Y, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(Z, b.Z, preA.Z, postB.Z, weight, t, preAT, postBT)
);
}
/// <summary>
/// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector
- /// and the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
+ /// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
/// </summary>
/// <param name="control1">Control point that defines the bezier curve.</param>
/// <param name="control2">Control point that defines the bezier curve.</param>
/// <param name="end">The destination vector.</param>
/// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector3 BezierInterpolate(Vector3 control1, Vector3 control2, Vector3 end, real_t t)
+ public readonly Vector3 BezierInterpolate(Vector3 control1, Vector3 control2, Vector3 end, real_t t)
{
- // Formula from Wikipedia article on Bezier curves
- real_t omt = 1 - t;
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- real_t t3 = t2 * t;
+ return new Vector3
+ (
+ Mathf.BezierInterpolate(X, control1.X, control2.X, end.X, t),
+ Mathf.BezierInterpolate(Y, control1.Y, control2.Y, end.Y, t),
+ Mathf.BezierInterpolate(Z, control1.Z, control2.Z, end.Z, t)
+ );
+ }
- return this * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3;
+ /// <summary>
+ /// Returns the derivative at the given <paramref name="t"/> on the Bezier curve defined by this vector
+ /// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
+ /// </summary>
+ /// <param name="control1">Control point that defines the bezier curve.</param>
+ /// <param name="control2">Control point that defines the bezier curve.</param>
+ /// <param name="end">The destination value for the interpolation.</param>
+ /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public readonly Vector3 BezierDerivative(Vector3 control1, Vector3 control2, Vector3 end, real_t t)
+ {
+ return new Vector3(
+ Mathf.BezierDerivative(X, control1.X, control2.X, end.X, t),
+ Mathf.BezierDerivative(Y, control1.Y, control2.Y, end.Y, t),
+ Mathf.BezierDerivative(Z, control1.Z, control2.Z, end.Y, t)
+ );
}
/// <summary>
@@ -258,9 +274,9 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to point towards.</param>
/// <returns>The direction from this vector to <paramref name="to"/>.</returns>
- public Vector3 DirectionTo(Vector3 to)
+ public readonly Vector3 DirectionTo(Vector3 to)
{
- return new Vector3(to.x - x, to.y - y, to.z - z).Normalized();
+ return new Vector3(to.X - X, to.Y - Y, to.Z - Z).Normalized();
}
/// <summary>
@@ -270,7 +286,7 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to use.</param>
/// <returns>The squared distance between the two vectors.</returns>
- public real_t DistanceSquaredTo(Vector3 to)
+ public readonly real_t DistanceSquaredTo(Vector3 to)
{
return (to - this).LengthSquared();
}
@@ -281,7 +297,7 @@ namespace Godot
/// <seealso cref="DistanceSquaredTo(Vector3)"/>
/// <param name="to">The other vector to use.</param>
/// <returns>The distance between the two vectors.</returns>
- public real_t DistanceTo(Vector3 to)
+ public readonly real_t DistanceTo(Vector3 to)
{
return (to - this).Length();
}
@@ -291,34 +307,44 @@ namespace Godot
/// </summary>
/// <param name="with">The other vector to use.</param>
/// <returns>The dot product of the two vectors.</returns>
- public real_t Dot(Vector3 with)
+ public readonly real_t Dot(Vector3 with)
{
- return (x * with.x) + (y * with.y) + (z * with.z);
+ return (X * with.X) + (Y * with.Y) + (Z * with.Z);
}
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
- public Vector3 Floor()
+ public readonly Vector3 Floor()
{
- return new Vector3(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z));
+ return new Vector3(Mathf.Floor(X), Mathf.Floor(Y), Mathf.Floor(Z));
}
/// <summary>
- /// Returns the inverse of this vector. This is the same as <c>new Vector3(1 / v.x, 1 / v.y, 1 / v.z)</c>.
+ /// Returns the inverse of this vector. This is the same as <c>new Vector3(1 / v.X, 1 / v.Y, 1 / v.Z)</c>.
/// </summary>
/// <returns>The inverse of this vector.</returns>
- public Vector3 Inverse()
+ public readonly Vector3 Inverse()
+ {
+ return new Vector3(1 / X, 1 / Y, 1 / Z);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
{
- return new Vector3(1 / x, 1 / y, 1 / z);
+ return Mathf.IsFinite(X) && Mathf.IsFinite(Y) && Mathf.IsFinite(Z);
}
/// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
- public bool IsNormalized()
+ public readonly bool IsNormalized()
{
return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
}
@@ -328,11 +354,11 @@ namespace Godot
/// </summary>
/// <seealso cref="LengthSquared"/>
/// <returns>The length of this vector.</returns>
- public real_t Length()
+ public readonly real_t Length()
{
- real_t x2 = x * x;
- real_t y2 = y * y;
- real_t z2 = z * z;
+ real_t x2 = X * X;
+ real_t y2 = Y * Y;
+ real_t z2 = Z * Z;
return Mathf.Sqrt(x2 + y2 + z2);
}
@@ -343,11 +369,11 @@ namespace Godot
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
- public real_t LengthSquared()
+ public readonly real_t LengthSquared()
{
- real_t x2 = x * x;
- real_t y2 = y * y;
- real_t z2 = z * z;
+ real_t x2 = X * X;
+ real_t y2 = Y * Y;
+ real_t z2 = Z * Z;
return x2 + y2 + z2;
}
@@ -359,30 +385,13 @@ namespace Godot
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
- public Vector3 Lerp(Vector3 to, real_t weight)
+ public readonly Vector3 Lerp(Vector3 to, real_t weight)
{
return new Vector3
(
- Mathf.Lerp(x, to.x, weight),
- Mathf.Lerp(y, to.y, weight),
- Mathf.Lerp(z, to.z, weight)
- );
- }
-
- /// <summary>
- /// Returns the result of the linear interpolation between
- /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>.
- /// </summary>
- /// <param name="to">The destination vector for interpolation.</param>
- /// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The resulting vector of the interpolation.</returns>
- public Vector3 Lerp(Vector3 to, Vector3 weight)
- {
- return new Vector3
- (
- Mathf.Lerp(x, to.x, weight.x),
- Mathf.Lerp(y, to.y, weight.y),
- Mathf.Lerp(z, to.z, weight.z)
+ Mathf.Lerp(X, to.X, weight),
+ Mathf.Lerp(Y, to.Y, weight),
+ Mathf.Lerp(Z, to.Z, weight)
);
}
@@ -391,7 +400,7 @@ namespace Godot
/// </summary>
/// <param name="length">The length to limit to.</param>
/// <returns>The vector with its length limited.</returns>
- public Vector3 LimitLength(real_t length = 1.0f)
+ public readonly Vector3 LimitLength(real_t length = 1.0f)
{
Vector3 v = this;
real_t l = Length();
@@ -410,9 +419,9 @@ namespace Godot
/// If all components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the highest axis.</returns>
- public Axis MaxAxisIndex()
+ public readonly Axis MaxAxisIndex()
{
- return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X);
+ return X < Y ? (Y < Z ? Axis.Z : Axis.Y) : (X < Z ? Axis.Z : Axis.X);
}
/// <summary>
@@ -420,9 +429,9 @@ namespace Godot
/// If all components are equal, this method returns <see cref="Axis.Z"/>.
/// </summary>
/// <returns>The index of the lowest axis.</returns>
- public Axis MinAxisIndex()
+ public readonly Axis MinAxisIndex()
{
- return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
+ return X < Y ? (X < Z ? Axis.X : Axis.Z) : (Y < Z ? Axis.Y : Axis.Z);
}
/// <summary>
@@ -431,7 +440,7 @@ namespace Godot
/// <param name="to">The vector to move towards.</param>
/// <param name="delta">The amount to move towards by.</param>
/// <returns>The resulting vector.</returns>
- public Vector3 MoveToward(Vector3 to, real_t delta)
+ public readonly Vector3 MoveToward(Vector3 to, real_t delta)
{
Vector3 v = this;
Vector3 vd = to - v;
@@ -446,7 +455,7 @@ namespace Godot
/// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>.
/// </summary>
/// <returns>A normalized version of the vector.</returns>
- public Vector3 Normalized()
+ public readonly Vector3 Normalized()
{
Vector3 v = this;
v.Normalize();
@@ -458,12 +467,12 @@ namespace Godot
/// </summary>
/// <param name="with">The other vector.</param>
/// <returns>A <see cref="Basis"/> representing the outer product matrix.</returns>
- public Basis Outer(Vector3 with)
+ public readonly Basis Outer(Vector3 with)
{
return new Basis(
- x * with.x, x * with.y, x * with.z,
- y * with.x, y * with.y, y * with.z,
- z * with.x, z * with.y, z * with.z
+ X * with.X, X * with.Y, X * with.Z,
+ Y * with.X, Y * with.Y, Y * with.Z,
+ Z * with.X, Z * with.Y, Z * with.Z
);
}
@@ -475,12 +484,12 @@ namespace Godot
/// <returns>
/// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>.
/// </returns>
- public Vector3 PosMod(real_t mod)
+ public readonly Vector3 PosMod(real_t mod)
{
Vector3 v;
- v.x = Mathf.PosMod(x, mod);
- v.y = Mathf.PosMod(y, mod);
- v.z = Mathf.PosMod(z, mod);
+ v.X = Mathf.PosMod(X, mod);
+ v.Y = Mathf.PosMod(Y, mod);
+ v.Z = Mathf.PosMod(Z, mod);
return v;
}
@@ -492,12 +501,12 @@ namespace Godot
/// <returns>
/// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components.
/// </returns>
- public Vector3 PosMod(Vector3 modv)
+ public readonly Vector3 PosMod(Vector3 modv)
{
Vector3 v;
- v.x = Mathf.PosMod(x, modv.x);
- v.y = Mathf.PosMod(y, modv.y);
- v.z = Mathf.PosMod(z, modv.z);
+ v.X = Mathf.PosMod(X, modv.X);
+ v.Y = Mathf.PosMod(Y, modv.Y);
+ v.Z = Mathf.PosMod(Z, modv.Z);
return v;
}
@@ -506,7 +515,7 @@ namespace Godot
/// </summary>
/// <param name="onNormal">The vector to project onto.</param>
/// <returns>The projected vector.</returns>
- public Vector3 Project(Vector3 onNormal)
+ public readonly Vector3 Project(Vector3 onNormal)
{
return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
}
@@ -516,7 +525,7 @@ namespace Godot
/// </summary>
/// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param>
/// <returns>The reflected vector.</returns>
- public Vector3 Reflect(Vector3 normal)
+ public readonly Vector3 Reflect(Vector3 normal)
{
#if DEBUG
if (!normal.IsNormalized())
@@ -534,7 +543,7 @@ namespace Godot
/// <param name="axis">The vector to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
- public Vector3 Rotated(Vector3 axis, real_t angle)
+ public readonly Vector3 Rotated(Vector3 axis, real_t angle)
{
#if DEBUG
if (!axis.IsNormalized())
@@ -550,9 +559,9 @@ namespace Godot
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
/// <returns>The rounded vector.</returns>
- public Vector3 Round()
+ public readonly Vector3 Round()
{
- return new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z));
+ return new Vector3(Mathf.Round(X), Mathf.Round(Y), Mathf.Round(Z));
}
/// <summary>
@@ -561,12 +570,12 @@ namespace Godot
/// by calling <see cref="Mathf.Sign(real_t)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
- public Vector3 Sign()
+ public readonly Vector3 Sign()
{
Vector3 v;
- v.x = Mathf.Sign(x);
- v.y = Mathf.Sign(y);
- v.z = Mathf.Sign(z);
+ v.X = Mathf.Sign(X);
+ v.Y = Mathf.Sign(Y);
+ v.Z = Mathf.Sign(Z);
return v;
}
@@ -579,7 +588,7 @@ namespace Godot
/// <param name="to">The other vector to compare this vector to.</param>
/// <param name="axis">The reference axis to use for the angle sign.</param>
/// <returns>The signed angle between the two vectors, in radians.</returns>
- public real_t SignedAngleTo(Vector3 to, Vector3 axis)
+ public readonly real_t SignedAngleTo(Vector3 to, Vector3 axis)
{
Vector3 crossTo = Cross(to);
real_t unsignedAngle = Mathf.Atan2(crossTo.Length(), Dot(to));
@@ -598,7 +607,7 @@ namespace Godot
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
- public Vector3 Slerp(Vector3 to, real_t weight)
+ public readonly Vector3 Slerp(Vector3 to, real_t weight)
{
real_t startLengthSquared = LengthSquared();
real_t endLengthSquared = to.LengthSquared();
@@ -618,7 +627,7 @@ namespace Godot
/// </summary>
/// <param name="normal">The normal vector defining the plane to slide on.</param>
/// <returns>The slid vector.</returns>
- public Vector3 Slide(Vector3 normal)
+ public readonly Vector3 Slide(Vector3 normal)
{
return this - (normal * Dot(normal));
}
@@ -629,13 +638,13 @@ namespace Godot
/// </summary>
/// <param name="step">A vector value representing the step size to snap to.</param>
/// <returns>The snapped vector.</returns>
- public Vector3 Snapped(Vector3 step)
+ public readonly Vector3 Snapped(Vector3 step)
{
return new Vector3
(
- Mathf.Snapped(x, step.x),
- Mathf.Snapped(y, step.y),
- Mathf.Snapped(z, step.z)
+ Mathf.Snapped(X, step.X),
+ Mathf.Snapped(Y, step.Y),
+ Mathf.Snapped(Z, step.Z)
);
}
@@ -710,9 +719,9 @@ namespace Godot
/// <param name="z">The vector's Z component.</param>
public Vector3(real_t x, real_t y, real_t z)
{
- this.x = x;
- this.y = y;
- this.z = z;
+ X = x;
+ Y = y;
+ Z = z;
}
/// <summary>
@@ -724,9 +733,9 @@ namespace Godot
/// <returns>The added vector.</returns>
public static Vector3 operator +(Vector3 left, Vector3 right)
{
- left.x += right.x;
- left.y += right.y;
- left.z += right.z;
+ left.X += right.X;
+ left.Y += right.Y;
+ left.Z += right.Z;
return left;
}
@@ -739,15 +748,15 @@ namespace Godot
/// <returns>The subtracted vector.</returns>
public static Vector3 operator -(Vector3 left, Vector3 right)
{
- left.x -= right.x;
- left.y -= right.y;
- left.z -= right.z;
+ left.X -= right.X;
+ left.Y -= right.Y;
+ left.Z -= right.Z;
return left;
}
/// <summary>
/// Returns the negative value of the <see cref="Vector3"/>.
- /// This is the same as writing <c>new Vector3(-v.x, -v.y, -v.z)</c>.
+ /// This is the same as writing <c>new Vector3(-v.X, -v.Y, -v.Z)</c>.
/// This operation flips the direction of the vector while
/// keeping the same magnitude.
/// With floats, the number zero can be either positive or negative.
@@ -756,9 +765,9 @@ namespace Godot
/// <returns>The negated/flipped vector.</returns>
public static Vector3 operator -(Vector3 vec)
{
- vec.x = -vec.x;
- vec.y = -vec.y;
- vec.z = -vec.z;
+ vec.X = -vec.X;
+ vec.Y = -vec.Y;
+ vec.Z = -vec.Z;
return vec;
}
@@ -771,9 +780,9 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector3 operator *(Vector3 vec, real_t scale)
{
- vec.x *= scale;
- vec.y *= scale;
- vec.z *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
+ vec.Z *= scale;
return vec;
}
@@ -786,9 +795,9 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector3 operator *(real_t scale, Vector3 vec)
{
- vec.x *= scale;
- vec.y *= scale;
- vec.z *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
+ vec.Z *= scale;
return vec;
}
@@ -801,9 +810,9 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector3 operator *(Vector3 left, Vector3 right)
{
- left.x *= right.x;
- left.y *= right.y;
- left.z *= right.z;
+ left.X *= right.X;
+ left.Y *= right.Y;
+ left.Z *= right.Z;
return left;
}
@@ -816,9 +825,9 @@ namespace Godot
/// <returns>The divided vector.</returns>
public static Vector3 operator /(Vector3 vec, real_t divisor)
{
- vec.x /= divisor;
- vec.y /= divisor;
- vec.z /= divisor;
+ vec.X /= divisor;
+ vec.Y /= divisor;
+ vec.Z /= divisor;
return vec;
}
@@ -831,9 +840,9 @@ namespace Godot
/// <returns>The divided vector.</returns>
public static Vector3 operator /(Vector3 vec, Vector3 divisorv)
{
- vec.x /= divisorv.x;
- vec.y /= divisorv.y;
- vec.z /= divisorv.z;
+ vec.X /= divisorv.X;
+ vec.Y /= divisorv.Y;
+ vec.Z /= divisorv.Z;
return vec;
}
@@ -855,9 +864,9 @@ namespace Godot
/// <returns>The remainder vector.</returns>
public static Vector3 operator %(Vector3 vec, real_t divisor)
{
- vec.x %= divisor;
- vec.y %= divisor;
- vec.z %= divisor;
+ vec.X %= divisor;
+ vec.Y %= divisor;
+ vec.Z %= divisor;
return vec;
}
@@ -879,9 +888,9 @@ namespace Godot
/// <returns>The remainder vector.</returns>
public static Vector3 operator %(Vector3 vec, Vector3 divisorv)
{
- vec.x %= divisorv.x;
- vec.y %= divisorv.y;
- vec.z %= divisorv.z;
+ vec.X %= divisorv.X;
+ vec.Y %= divisorv.Y;
+ vec.Z %= divisorv.Z;
return vec;
}
@@ -924,15 +933,15 @@ namespace Godot
/// <returns>Whether or not the left is less than the right.</returns>
public static bool operator <(Vector3 left, Vector3 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- return left.z < right.z;
+ return left.Z < right.Z;
}
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
@@ -948,15 +957,15 @@ namespace Godot
/// <returns>Whether or not the left is greater than the right.</returns>
public static bool operator >(Vector3 left, Vector3 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- return left.z > right.z;
+ return left.Z > right.Z;
}
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
@@ -972,15 +981,15 @@ namespace Godot
/// <returns>Whether or not the left is less than or equal to the right.</returns>
public static bool operator <=(Vector3 left, Vector3 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- return left.z <= right.z;
+ return left.Z <= right.Z;
}
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
@@ -996,15 +1005,15 @@ namespace Godot
/// <returns>Whether or not the left is greater than or equal to the right.</returns>
public static bool operator >=(Vector3 left, Vector3 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- return left.z >= right.z;
+ return left.Z >= right.Z;
}
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
@@ -1015,7 +1024,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Vector3 other && Equals(other);
}
@@ -1027,9 +1036,9 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>Whether or not the vectors are exactly equal.</returns>
- public bool Equals(Vector3 other)
+ public readonly bool Equals(Vector3 other)
{
- return x == other.x && y == other.y && z == other.z;
+ return X == other.X && Y == other.Y && Z == other.Z;
}
/// <summary>
@@ -1038,36 +1047,48 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector to compare.</param>
/// <returns>Whether or not the vectors are approximately equal.</returns>
- public bool IsEqualApprox(Vector3 other)
+ public readonly bool IsEqualApprox(Vector3 other)
+ {
+ return Mathf.IsEqualApprox(X, other.X) && Mathf.IsEqualApprox(Y, other.Y) && Mathf.IsEqualApprox(Z, other.Z);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
{
- return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z);
+ return Mathf.IsZeroApprox(X) && Mathf.IsZeroApprox(Y) && Mathf.IsZeroApprox(Z);
}
/// <summary>
/// Serves as the hash function for <see cref="Vector3"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode();
+ return Y.GetHashCode() ^ X.GetHashCode() ^ Z.GetHashCode();
}
/// <summary>
/// Converts this <see cref="Vector3"/> to a string.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"({x}, {y}, {z})";
+ return $"({X}, {Y}, {Z})";
}
/// <summary>
/// Converts this <see cref="Vector3"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)})";
+ return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
index e88a043cb3..fe899527ef 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
@@ -8,7 +8,7 @@ namespace Godot
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
- public struct Vector3i : IEquatable<Vector3i>
+ public struct Vector3I : IEquatable<Vector3I>
{
/// <summary>
/// Enumerated index values for the axes.
@@ -33,17 +33,17 @@ namespace Godot
/// <summary>
/// The vector's X component. Also accessible by using the index position <c>[0]</c>.
/// </summary>
- public int x;
+ public int X;
/// <summary>
/// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
/// </summary>
- public int y;
+ public int Y;
/// <summary>
/// The vector's Z component. Also accessible by using the index position <c>[2]</c>.
/// </summary>
- public int z;
+ public int Z;
/// <summary>
/// Access vector components using their <paramref name="index"/>.
@@ -52,22 +52,22 @@ namespace Godot
/// <paramref name="index"/> is not 0, 1 or 2.
/// </exception>
/// <value>
- /// <c>[0]</c> is equivalent to <see cref="x"/>,
- /// <c>[1]</c> is equivalent to <see cref="y"/>,
- /// <c>[2]</c> is equivalent to <see cref="z"/>.
+ /// <c>[0]</c> is equivalent to <see cref="X"/>,
+ /// <c>[1]</c> is equivalent to <see cref="Y"/>,
+ /// <c>[2]</c> is equivalent to <see cref="Z"/>.
/// </value>
public int this[int index]
{
- get
+ readonly get
{
switch (index)
{
case 0:
- return x;
+ return X;
case 1:
- return y;
+ return Y;
case 2:
- return z;
+ return Z;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
@@ -77,13 +77,13 @@ namespace Godot
switch (index)
{
case 0:
- x = value;
+ X = value;
return;
case 1:
- y = value;
+ Y = value;
return;
case 2:
- z = value;
+ Z = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(index));
@@ -94,20 +94,20 @@ namespace Godot
/// <summary>
/// Helper method for deconstruction into a tuple.
/// </summary>
- public void Deconstruct(out int x, out int y, out int z)
+ public readonly void Deconstruct(out int x, out int y, out int z)
{
- x = this.x;
- y = this.y;
- z = this.z;
+ x = X;
+ y = Y;
+ z = Z;
}
/// <summary>
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns>
- public Vector3i Abs()
+ public readonly Vector3I Abs()
{
- return new Vector3i(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z));
+ return new Vector3I(Mathf.Abs(X), Mathf.Abs(Y), Mathf.Abs(Z));
}
/// <summary>
@@ -118,59 +118,26 @@ namespace Godot
/// <param name="min">The vector with minimum allowed values.</param>
/// <param name="max">The vector with maximum allowed values.</param>
/// <returns>The vector with all components clamped.</returns>
- public Vector3i Clamp(Vector3i min, Vector3i max)
+ public readonly Vector3I Clamp(Vector3I min, Vector3I max)
{
- return new Vector3i
+ return new Vector3I
(
- Mathf.Clamp(x, min.x, max.x),
- Mathf.Clamp(y, min.y, max.y),
- Mathf.Clamp(z, min.z, max.z)
+ Mathf.Clamp(X, min.X, max.X),
+ Mathf.Clamp(Y, min.Y, max.Y),
+ Mathf.Clamp(Z, min.Z, max.Z)
);
}
/// <summary>
- /// Returns the squared distance between this vector and <paramref name="to"/>.
- /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
- /// you need to compare vectors or need the squared distance for some formula.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The squared distance between the two vectors.</returns>
- public int DistanceSquaredTo(Vector3i to)
- {
- return (to - this).LengthSquared();
- }
-
- /// <summary>
- /// Returns the distance between this vector and <paramref name="to"/>.
- /// </summary>
- /// <seealso cref="DistanceSquaredTo(Vector3i)"/>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The distance between the two vectors.</returns>
- public real_t DistanceTo(Vector3i to)
- {
- return (to - this).Length();
- }
-
- /// <summary>
- /// Returns the dot product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector to use.</param>
- /// <returns>The dot product of the two vectors.</returns>
- public int Dot(Vector3i with)
- {
- return x * with.x + y * with.y + z * with.z;
- }
-
- /// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <seealso cref="LengthSquared"/>
/// <returns>The length of this vector.</returns>
- public real_t Length()
+ public readonly real_t Length()
{
- int x2 = x * x;
- int y2 = y * y;
- int z2 = z * z;
+ int x2 = X * X;
+ int y2 = Y * Y;
+ int z2 = Z * Z;
return Mathf.Sqrt(x2 + y2 + z2);
}
@@ -181,11 +148,11 @@ namespace Godot
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
- public int LengthSquared()
+ public readonly int LengthSquared()
{
- int x2 = x * x;
- int y2 = y * y;
- int z2 = z * z;
+ int x2 = X * X;
+ int y2 = Y * Y;
+ int z2 = Z * Z;
return x2 + y2 + z2;
}
@@ -195,9 +162,9 @@ namespace Godot
/// If all components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the highest axis.</returns>
- public Axis MaxAxisIndex()
+ public readonly Axis MaxAxisIndex()
{
- return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X);
+ return X < Y ? (Y < Z ? Axis.Z : Axis.Y) : (X < Z ? Axis.Z : Axis.X);
}
/// <summary>
@@ -205,43 +172,9 @@ namespace Godot
/// If all components are equal, this method returns <see cref="Axis.Z"/>.
/// </summary>
/// <returns>The index of the lowest axis.</returns>
- public Axis MinAxisIndex()
+ public readonly Axis MinAxisIndex()
{
- return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
- }
-
- /// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="mod"/>.
- /// </summary>
- /// <param name="mod">A value representing the divisor of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>.
- /// </returns>
- public Vector3i PosMod(int mod)
- {
- Vector3i v = this;
- v.x = Mathf.PosMod(v.x, mod);
- v.y = Mathf.PosMod(v.y, mod);
- v.z = Mathf.PosMod(v.z, mod);
- return v;
- }
-
- /// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="modv"/>'s components.
- /// </summary>
- /// <param name="modv">A vector representing the divisors of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components.
- /// </returns>
- public Vector3i PosMod(Vector3i modv)
- {
- Vector3i v = this;
- v.x = Mathf.PosMod(v.x, modv.x);
- v.y = Mathf.PosMod(v.y, modv.y);
- v.z = Mathf.PosMod(v.z, modv.z);
- return v;
+ return X < Y ? (X < Z ? Axis.X : Axis.Z) : (Y < Z ? Axis.Y : Axis.Z);
}
/// <summary>
@@ -250,281 +183,251 @@ namespace Godot
/// by calling <see cref="Mathf.Sign(int)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
- public Vector3i Sign()
+ public readonly Vector3I Sign()
{
- Vector3i v = this;
- v.x = Mathf.Sign(v.x);
- v.y = Mathf.Sign(v.y);
- v.z = Mathf.Sign(v.z);
+ Vector3I v = this;
+ v.X = Mathf.Sign(v.X);
+ v.Y = Mathf.Sign(v.Y);
+ v.Z = Mathf.Sign(v.Z);
return v;
}
// Constants
- private static readonly Vector3i _zero = new Vector3i(0, 0, 0);
- private static readonly Vector3i _one = new Vector3i(1, 1, 1);
+ private static readonly Vector3I _zero = new Vector3I(0, 0, 0);
+ private static readonly Vector3I _one = new Vector3I(1, 1, 1);
- private static readonly Vector3i _up = new Vector3i(0, 1, 0);
- private static readonly Vector3i _down = new Vector3i(0, -1, 0);
- private static readonly Vector3i _right = new Vector3i(1, 0, 0);
- private static readonly Vector3i _left = new Vector3i(-1, 0, 0);
- private static readonly Vector3i _forward = new Vector3i(0, 0, -1);
- private static readonly Vector3i _back = new Vector3i(0, 0, 1);
+ private static readonly Vector3I _up = new Vector3I(0, 1, 0);
+ private static readonly Vector3I _down = new Vector3I(0, -1, 0);
+ private static readonly Vector3I _right = new Vector3I(1, 0, 0);
+ private static readonly Vector3I _left = new Vector3I(-1, 0, 0);
+ private static readonly Vector3I _forward = new Vector3I(0, 0, -1);
+ private static readonly Vector3I _back = new Vector3I(0, 0, 1);
/// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
/// </summary>
- /// <value>Equivalent to <c>new Vector3i(0, 0, 0)</c>.</value>
- public static Vector3i Zero { get { return _zero; } }
+ /// <value>Equivalent to <c>new Vector3I(0, 0, 0)</c>.</value>
+ public static Vector3I Zero { get { return _zero; } }
/// <summary>
/// One vector, a vector with all components set to <c>1</c>.
/// </summary>
- /// <value>Equivalent to <c>new Vector3i(1, 1, 1)</c>.</value>
- public static Vector3i One { get { return _one; } }
+ /// <value>Equivalent to <c>new Vector3I(1, 1, 1)</c>.</value>
+ public static Vector3I One { get { return _one; } }
/// <summary>
/// Up unit vector.
/// </summary>
- /// <value>Equivalent to <c>new Vector3i(0, 1, 0)</c>.</value>
- public static Vector3i Up { get { return _up; } }
+ /// <value>Equivalent to <c>new Vector3I(0, 1, 0)</c>.</value>
+ public static Vector3I Up { get { return _up; } }
/// <summary>
/// Down unit vector.
/// </summary>
- /// <value>Equivalent to <c>new Vector3i(0, -1, 0)</c>.</value>
- public static Vector3i Down { get { return _down; } }
+ /// <value>Equivalent to <c>new Vector3I(0, -1, 0)</c>.</value>
+ public static Vector3I Down { get { return _down; } }
/// <summary>
/// Right unit vector. Represents the local direction of right,
/// and the global direction of east.
/// </summary>
- /// <value>Equivalent to <c>new Vector3i(1, 0, 0)</c>.</value>
- public static Vector3i Right { get { return _right; } }
+ /// <value>Equivalent to <c>new Vector3I(1, 0, 0)</c>.</value>
+ public static Vector3I Right { get { return _right; } }
/// <summary>
/// Left unit vector. Represents the local direction of left,
/// and the global direction of west.
/// </summary>
- /// <value>Equivalent to <c>new Vector3i(-1, 0, 0)</c>.</value>
- public static Vector3i Left { get { return _left; } }
+ /// <value>Equivalent to <c>new Vector3I(-1, 0, 0)</c>.</value>
+ public static Vector3I Left { get { return _left; } }
/// <summary>
/// Forward unit vector. Represents the local direction of forward,
/// and the global direction of north.
/// </summary>
- /// <value>Equivalent to <c>new Vector3i(0, 0, -1)</c>.</value>
- public static Vector3i Forward { get { return _forward; } }
+ /// <value>Equivalent to <c>new Vector3I(0, 0, -1)</c>.</value>
+ public static Vector3I Forward { get { return _forward; } }
/// <summary>
/// Back unit vector. Represents the local direction of back,
/// and the global direction of south.
/// </summary>
- /// <value>Equivalent to <c>new Vector3i(0, 0, 1)</c>.</value>
- public static Vector3i Back { get { return _back; } }
+ /// <value>Equivalent to <c>new Vector3I(0, 0, 1)</c>.</value>
+ public static Vector3I Back { get { return _back; } }
/// <summary>
- /// Constructs a new <see cref="Vector3i"/> with the given components.
+ /// Constructs a new <see cref="Vector3I"/> with the given components.
/// </summary>
/// <param name="x">The vector's X component.</param>
/// <param name="y">The vector's Y component.</param>
/// <param name="z">The vector's Z component.</param>
- public Vector3i(int x, int y, int z)
+ public Vector3I(int x, int y, int z)
{
- this.x = x;
- this.y = y;
- this.z = z;
+ X = x;
+ Y = y;
+ Z = z;
}
/// <summary>
- /// Adds each component of the <see cref="Vector3i"/>
- /// with the components of the given <see cref="Vector3i"/>.
+ /// Adds each component of the <see cref="Vector3I"/>
+ /// with the components of the given <see cref="Vector3I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The added vector.</returns>
- public static Vector3i operator +(Vector3i left, Vector3i right)
+ public static Vector3I operator +(Vector3I left, Vector3I right)
{
- left.x += right.x;
- left.y += right.y;
- left.z += right.z;
+ left.X += right.X;
+ left.Y += right.Y;
+ left.Z += right.Z;
return left;
}
/// <summary>
- /// Subtracts each component of the <see cref="Vector3i"/>
- /// by the components of the given <see cref="Vector3i"/>.
+ /// Subtracts each component of the <see cref="Vector3I"/>
+ /// by the components of the given <see cref="Vector3I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The subtracted vector.</returns>
- public static Vector3i operator -(Vector3i left, Vector3i right)
+ public static Vector3I operator -(Vector3I left, Vector3I right)
{
- left.x -= right.x;
- left.y -= right.y;
- left.z -= right.z;
+ left.X -= right.X;
+ left.Y -= right.Y;
+ left.Z -= right.Z;
return left;
}
/// <summary>
- /// Returns the negative value of the <see cref="Vector3i"/>.
- /// This is the same as writing <c>new Vector3i(-v.x, -v.y, -v.z)</c>.
+ /// Returns the negative value of the <see cref="Vector3I"/>.
+ /// This is the same as writing <c>new Vector3I(-v.X, -v.Y, -v.Z)</c>.
/// This operation flips the direction of the vector while
/// keeping the same magnitude.
/// </summary>
/// <param name="vec">The vector to negate/flip.</param>
/// <returns>The negated/flipped vector.</returns>
- public static Vector3i operator -(Vector3i vec)
+ public static Vector3I operator -(Vector3I vec)
{
- vec.x = -vec.x;
- vec.y = -vec.y;
- vec.z = -vec.z;
+ vec.X = -vec.X;
+ vec.Y = -vec.Y;
+ vec.Z = -vec.Z;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector3i"/>
+ /// Multiplies each component of the <see cref="Vector3I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="vec">The vector to multiply.</param>
/// <param name="scale">The scale to multiply by.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector3i operator *(Vector3i vec, int scale)
+ public static Vector3I operator *(Vector3I vec, int scale)
{
- vec.x *= scale;
- vec.y *= scale;
- vec.z *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
+ vec.Z *= scale;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector3i"/>
+ /// Multiplies each component of the <see cref="Vector3I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="scale">The scale to multiply by.</param>
/// <param name="vec">The vector to multiply.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector3i operator *(int scale, Vector3i vec)
+ public static Vector3I operator *(int scale, Vector3I vec)
{
- vec.x *= scale;
- vec.y *= scale;
- vec.z *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
+ vec.Z *= scale;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector3i"/>
- /// by the components of the given <see cref="Vector3i"/>.
+ /// Multiplies each component of the <see cref="Vector3I"/>
+ /// by the components of the given <see cref="Vector3I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector3i operator *(Vector3i left, Vector3i right)
+ public static Vector3I operator *(Vector3I left, Vector3I right)
{
- left.x *= right.x;
- left.y *= right.y;
- left.z *= right.z;
+ left.X *= right.X;
+ left.Y *= right.Y;
+ left.Z *= right.Z;
return left;
}
/// <summary>
- /// Divides each component of the <see cref="Vector3i"/>
+ /// Divides each component of the <see cref="Vector3I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisor">The divisor value.</param>
/// <returns>The divided vector.</returns>
- public static Vector3i operator /(Vector3i vec, int divisor)
+ public static Vector3I operator /(Vector3I vec, int divisor)
{
- vec.x /= divisor;
- vec.y /= divisor;
- vec.z /= divisor;
+ vec.X /= divisor;
+ vec.Y /= divisor;
+ vec.Z /= divisor;
return vec;
}
/// <summary>
- /// Divides each component of the <see cref="Vector3i"/>
- /// by the components of the given <see cref="Vector3i"/>.
+ /// Divides each component of the <see cref="Vector3I"/>
+ /// by the components of the given <see cref="Vector3I"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisorv">The divisor vector.</param>
/// <returns>The divided vector.</returns>
- public static Vector3i operator /(Vector3i vec, Vector3i divisorv)
+ public static Vector3I operator /(Vector3I vec, Vector3I divisorv)
{
- vec.x /= divisorv.x;
- vec.y /= divisorv.y;
- vec.z /= divisorv.z;
+ vec.X /= divisorv.X;
+ vec.Y /= divisorv.Y;
+ vec.Z /= divisorv.Z;
return vec;
}
/// <summary>
- /// Gets the remainder of each component of the <see cref="Vector3i"/>
+ /// Gets the remainder of each component of the <see cref="Vector3I"/>
/// with the components of the given <see langword="int"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(int)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
/// <code>
- /// GD.Print(new Vector3i(10, -20, 30) % 7); // Prints "(3, -6, 2)"
+ /// GD.Print(new Vector3I(10, -20, 30) % 7); // Prints "(3, -6, 2)"
/// </code>
/// </example>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisor">The divisor value.</param>
/// <returns>The remainder vector.</returns>
- public static Vector3i operator %(Vector3i vec, int divisor)
+ public static Vector3I operator %(Vector3I vec, int divisor)
{
- vec.x %= divisor;
- vec.y %= divisor;
- vec.z %= divisor;
+ vec.X %= divisor;
+ vec.Y %= divisor;
+ vec.Z %= divisor;
return vec;
}
/// <summary>
- /// Gets the remainder of each component of the <see cref="Vector3i"/>
- /// with the components of the given <see cref="Vector3i"/>.
+ /// Gets the remainder of each component of the <see cref="Vector3I"/>
+ /// with the components of the given <see cref="Vector3I"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(Vector3i)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
/// <code>
- /// GD.Print(new Vector3i(10, -20, 30) % new Vector3i(7, 8, 9)); // Prints "(3, -4, 3)"
+ /// GD.Print(new Vector3I(10, -20, 30) % new Vector3I(7, 8, 9)); // Prints "(3, -4, 3)"
/// </code>
/// </example>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisorv">The divisor vector.</param>
/// <returns>The remainder vector.</returns>
- public static Vector3i operator %(Vector3i vec, Vector3i divisorv)
- {
- vec.x %= divisorv.x;
- vec.y %= divisorv.y;
- vec.z %= divisorv.z;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector3i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector3i operator &(Vector3i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- vec.z &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector3i"/>
- /// and the given <see cref="Vector3i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector3i operator &(Vector3i vec, Vector3i andv)
+ public static Vector3I operator %(Vector3I vec, Vector3I divisorv)
{
- vec.x &= andv.x;
- vec.y &= andv.y;
- vec.z &= andv.z;
+ vec.X %= divisorv.X;
+ vec.Y %= divisorv.Y;
+ vec.Z %= divisorv.Z;
return vec;
}
@@ -534,7 +437,7 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the vectors are equal.</returns>
- public static bool operator ==(Vector3i left, Vector3i right)
+ public static bool operator ==(Vector3I left, Vector3I right)
{
return left.Equals(right);
}
@@ -545,13 +448,13 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the vectors are not equal.</returns>
- public static bool operator !=(Vector3i left, Vector3i right)
+ public static bool operator !=(Vector3I left, Vector3I right)
{
return !left.Equals(right);
}
/// <summary>
- /// Compares two <see cref="Vector3i"/> vectors by first checking if
+ /// Compares two <see cref="Vector3I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is less than
/// the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -561,21 +464,21 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is less than the right.</returns>
- public static bool operator <(Vector3i left, Vector3i right)
+ public static bool operator <(Vector3I left, Vector3I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- return left.z < right.z;
+ return left.Z < right.Z;
}
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
- /// Compares two <see cref="Vector3i"/> vectors by first checking if
+ /// Compares two <see cref="Vector3I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is greater than
/// the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -585,21 +488,21 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is greater than the right.</returns>
- public static bool operator >(Vector3i left, Vector3i right)
+ public static bool operator >(Vector3I left, Vector3I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- return left.z > right.z;
+ return left.Z > right.Z;
}
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
- /// Compares two <see cref="Vector3i"/> vectors by first checking if
+ /// Compares two <see cref="Vector3I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is less than
/// or equal to the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -609,21 +512,21 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is less than or equal to the right.</returns>
- public static bool operator <=(Vector3i left, Vector3i right)
+ public static bool operator <=(Vector3I left, Vector3I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- return left.z <= right.z;
+ return left.Z <= right.Z;
}
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
- /// Compares two <see cref="Vector3i"/> vectors by first checking if
+ /// Compares two <see cref="Vector3I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is greater than
/// or equal to the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -633,38 +536,38 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is greater than or equal to the right.</returns>
- public static bool operator >=(Vector3i left, Vector3i right)
+ public static bool operator >=(Vector3I left, Vector3I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- return left.z >= right.z;
+ return left.Z >= right.Z;
}
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
- /// Converts this <see cref="Vector3i"/> to a <see cref="Vector3"/>.
+ /// Converts this <see cref="Vector3I"/> to a <see cref="Vector3"/>.
/// </summary>
/// <param name="value">The vector to convert.</param>
- public static implicit operator Vector3(Vector3i value)
+ public static implicit operator Vector3(Vector3I value)
{
- return new Vector3(value.x, value.y, value.z);
+ return new Vector3(value.X, value.Y, value.Z);
}
/// <summary>
- /// Converts a <see cref="Vector3"/> to a <see cref="Vector3i"/>.
+ /// Converts a <see cref="Vector3"/> to a <see cref="Vector3I"/>.
/// </summary>
/// <param name="value">The vector to convert.</param>
- public static explicit operator Vector3i(Vector3 value)
+ public static explicit operator Vector3I(Vector3 value)
{
- return new Vector3i(
- Mathf.RoundToInt(value.x),
- Mathf.RoundToInt(value.y),
- Mathf.RoundToInt(value.z)
+ return new Vector3I(
+ Mathf.RoundToInt(value.X),
+ Mathf.RoundToInt(value.Y),
+ Mathf.RoundToInt(value.Z)
);
}
@@ -674,9 +577,9 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
- return obj is Vector3i other && Equals(other);
+ return obj is Vector3I other && Equals(other);
}
/// <summary>
@@ -684,36 +587,36 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>Whether or not the vectors are equal.</returns>
- public bool Equals(Vector3i other)
+ public readonly bool Equals(Vector3I other)
{
- return x == other.x && y == other.y && z == other.z;
+ return X == other.X && Y == other.Y && Z == other.Z;
}
/// <summary>
- /// Serves as the hash function for <see cref="Vector3i"/>.
+ /// Serves as the hash function for <see cref="Vector3I"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode();
+ return Y.GetHashCode() ^ X.GetHashCode() ^ Z.GetHashCode();
}
/// <summary>
- /// Converts this <see cref="Vector3i"/> to a string.
+ /// Converts this <see cref="Vector3I"/> to a string.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"({x}, {y}, {z})";
+ return $"({X}, {Y}, {Z})";
}
/// <summary>
- /// Converts this <see cref="Vector3i"/> to a string with the given <paramref name="format"/>.
+ /// Converts this <see cref="Vector3I"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)})";
+ return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
index e2da41ff47..1fd39632b0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -37,22 +37,22 @@ namespace Godot
/// <summary>
/// The vector's X component. Also accessible by using the index position <c>[0]</c>.
/// </summary>
- public real_t x;
+ public real_t X;
/// <summary>
/// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
/// </summary>
- public real_t y;
+ public real_t Y;
/// <summary>
/// The vector's Z component. Also accessible by using the index position <c>[2]</c>.
/// </summary>
- public real_t z;
+ public real_t Z;
/// <summary>
/// The vector's W component. Also accessible by using the index position <c>[3]</c>.
/// </summary>
- public real_t w;
+ public real_t W;
/// <summary>
/// Access vector components using their index.
@@ -61,25 +61,25 @@ namespace Godot
/// <paramref name="index"/> is not 0, 1, 2 or 3.
/// </exception>
/// <value>
- /// <c>[0]</c> is equivalent to <see cref="x"/>,
- /// <c>[1]</c> is equivalent to <see cref="y"/>,
- /// <c>[2]</c> is equivalent to <see cref="z"/>.
- /// <c>[3]</c> is equivalent to <see cref="w"/>.
+ /// <c>[0]</c> is equivalent to <see cref="X"/>,
+ /// <c>[1]</c> is equivalent to <see cref="Y"/>,
+ /// <c>[2]</c> is equivalent to <see cref="Z"/>.
+ /// <c>[3]</c> is equivalent to <see cref="W"/>.
/// </value>
public real_t this[int index]
{
- get
+ readonly get
{
switch (index)
{
case 0:
- return x;
+ return X;
case 1:
- return y;
+ return Y;
case 2:
- return z;
+ return Z;
case 3:
- return w;
+ return W;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
@@ -89,16 +89,16 @@ namespace Godot
switch (index)
{
case 0:
- x = value;
+ X = value;
return;
case 1:
- y = value;
+ Y = value;
return;
case 2:
- z = value;
+ Z = value;
return;
case 3:
- w = value;
+ W = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(index));
@@ -109,12 +109,12 @@ namespace Godot
/// <summary>
/// Helper method for deconstruction into a tuple.
/// </summary>
- public void Deconstruct(out real_t x, out real_t y, out real_t z, out real_t w)
+ public readonly void Deconstruct(out real_t x, out real_t y, out real_t z, out real_t w)
{
- x = this.x;
- y = this.y;
- z = this.z;
- w = this.w;
+ x = X;
+ y = Y;
+ z = Z;
+ w = W;
}
internal void Normalize()
@@ -123,15 +123,15 @@ namespace Godot
if (lengthsq == 0)
{
- x = y = z = w = 0f;
+ X = Y = Z = W = 0f;
}
else
{
real_t length = Mathf.Sqrt(lengthsq);
- x /= length;
- y /= length;
- z /= length;
- w /= length;
+ X /= length;
+ Y /= length;
+ Z /= length;
+ W /= length;
}
}
@@ -139,18 +139,18 @@ namespace Godot
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns>
- public Vector4 Abs()
+ public readonly Vector4 Abs()
{
- return new Vector4(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z), Mathf.Abs(w));
+ return new Vector4(Mathf.Abs(X), Mathf.Abs(Y), Mathf.Abs(Z), Mathf.Abs(W));
}
/// <summary>
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
- public Vector4 Ceil()
+ public readonly Vector4 Ceil()
{
- return new Vector4(Mathf.Ceil(x), Mathf.Ceil(y), Mathf.Ceil(z), Mathf.Ceil(w));
+ return new Vector4(Mathf.Ceil(X), Mathf.Ceil(Y), Mathf.Ceil(Z), Mathf.Ceil(W));
}
/// <summary>
@@ -161,14 +161,14 @@ namespace Godot
/// <param name="min">The vector with minimum allowed values.</param>
/// <param name="max">The vector with maximum allowed values.</param>
/// <returns>The vector with all components clamped.</returns>
- public Vector4 Clamp(Vector4 min, Vector4 max)
+ public readonly Vector4 Clamp(Vector4 min, Vector4 max)
{
return new Vector4
(
- Mathf.Clamp(x, min.x, max.x),
- Mathf.Clamp(y, min.y, max.y),
- Mathf.Clamp(z, min.z, max.z),
- Mathf.Clamp(w, min.w, max.w)
+ Mathf.Clamp(X, min.X, max.X),
+ Mathf.Clamp(Y, min.Y, max.Y),
+ Mathf.Clamp(Z, min.Z, max.Z),
+ Mathf.Clamp(W, min.W, max.W)
);
}
@@ -181,14 +181,14 @@ namespace Godot
/// <param name="postB">A vector after <paramref name="b"/>.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
- public Vector4 CubicInterpolate(Vector4 b, Vector4 preA, Vector4 postB, real_t weight)
+ public readonly Vector4 CubicInterpolate(Vector4 b, Vector4 preA, Vector4 postB, real_t weight)
{
return new Vector4
(
- Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
- Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight),
- Mathf.CubicInterpolate(z, b.z, preA.z, postB.z, weight),
- Mathf.CubicInterpolate(w, b.w, preA.w, postB.w, weight)
+ Mathf.CubicInterpolate(X, b.X, preA.X, postB.X, weight),
+ Mathf.CubicInterpolate(Y, b.Y, preA.Y, postB.Y, weight),
+ Mathf.CubicInterpolate(Z, b.Z, preA.Z, postB.Z, weight),
+ Mathf.CubicInterpolate(W, b.W, preA.W, postB.W, weight)
);
}
@@ -206,14 +206,14 @@ namespace Godot
/// <param name="preAT"></param>
/// <param name="postBT"></param>
/// <returns>The interpolated vector.</returns>
- public Vector4 CubicInterpolateInTime(Vector4 b, Vector4 preA, Vector4 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
+ public readonly Vector4 CubicInterpolateInTime(Vector4 b, Vector4 preA, Vector4 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
{
return new Vector4
(
- Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT),
- Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT),
- Mathf.CubicInterpolateInTime(z, b.z, preA.z, postB.z, weight, t, preAT, postBT),
- Mathf.CubicInterpolateInTime(w, b.w, preA.w, postB.w, weight, t, preAT, postBT)
+ Mathf.CubicInterpolateInTime(X, b.X, preA.X, postB.X, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(Y, b.Y, preA.Y, postB.Y, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(Z, b.Z, preA.Z, postB.Z, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(W, b.W, preA.W, postB.W, weight, t, preAT, postBT)
);
}
@@ -222,9 +222,9 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to point towards.</param>
/// <returns>The direction from this vector to <paramref name="to"/>.</returns>
- public Vector4 DirectionTo(Vector4 to)
+ public readonly Vector4 DirectionTo(Vector4 to)
{
- Vector4 ret = new Vector4(to.x - x, to.y - y, to.z - z, to.w - w);
+ Vector4 ret = new Vector4(to.X - X, to.Y - Y, to.Z - Z, to.W - W);
ret.Normalize();
return ret;
}
@@ -236,7 +236,7 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to use.</param>
/// <returns>The squared distance between the two vectors.</returns>
- public real_t DistanceSquaredTo(Vector4 to)
+ public readonly real_t DistanceSquaredTo(Vector4 to)
{
return (to - this).LengthSquared();
}
@@ -246,7 +246,7 @@ namespace Godot
/// </summary>
/// <param name="to">The other vector to use.</param>
/// <returns>The distance between the two vectors.</returns>
- public real_t DistanceTo(Vector4 to)
+ public readonly real_t DistanceTo(Vector4 to)
{
return (to - this).Length();
}
@@ -256,34 +256,44 @@ namespace Godot
/// </summary>
/// <param name="with">The other vector to use.</param>
/// <returns>The dot product of the two vectors.</returns>
- public real_t Dot(Vector4 with)
+ public readonly real_t Dot(Vector4 with)
{
- return (x * with.x) + (y * with.y) + (z * with.z) + (w * with.w);
+ return (X * with.X) + (Y * with.Y) + (Z * with.Z) + (W * with.W);
}
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
- public Vector4 Floor()
+ public readonly Vector4 Floor()
{
- return new Vector4(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z), Mathf.Floor(w));
+ return new Vector4(Mathf.Floor(X), Mathf.Floor(Y), Mathf.Floor(Z), Mathf.Floor(W));
}
/// <summary>
- /// Returns the inverse of this vector. This is the same as <c>new Vector4(1 / v.x, 1 / v.y, 1 / v.z, 1 / v.w)</c>.
+ /// Returns the inverse of this vector. This is the same as <c>new Vector4(1 / v.X, 1 / v.Y, 1 / v.Z, 1 / v.W)</c>.
/// </summary>
/// <returns>The inverse of this vector.</returns>
- public Vector4 Inverse()
+ public readonly Vector4 Inverse()
{
- return new Vector4(1 / x, 1 / y, 1 / z, 1 / w);
+ return new Vector4(1 / X, 1 / Y, 1 / Z, 1 / W);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(X) && Mathf.IsFinite(Y) && Mathf.IsFinite(Z) && Mathf.IsFinite(W);
}
/// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
- public bool IsNormalized()
+ public readonly bool IsNormalized()
{
return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
}
@@ -293,12 +303,12 @@ namespace Godot
/// </summary>
/// <seealso cref="LengthSquared"/>
/// <returns>The length of this vector.</returns>
- public real_t Length()
+ public readonly real_t Length()
{
- real_t x2 = x * x;
- real_t y2 = y * y;
- real_t z2 = z * z;
- real_t w2 = w * w;
+ real_t x2 = X * X;
+ real_t y2 = Y * Y;
+ real_t z2 = Z * Z;
+ real_t w2 = W * W;
return Mathf.Sqrt(x2 + y2 + z2 + w2);
}
@@ -309,12 +319,12 @@ namespace Godot
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
- public real_t LengthSquared()
+ public readonly real_t LengthSquared()
{
- real_t x2 = x * x;
- real_t y2 = y * y;
- real_t z2 = z * z;
- real_t w2 = w * w;
+ real_t x2 = X * X;
+ real_t y2 = Y * Y;
+ real_t z2 = Z * Z;
+ real_t w2 = W * W;
return x2 + y2 + z2 + w2;
}
@@ -326,14 +336,14 @@ namespace Godot
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
- public Vector4 Lerp(Vector4 to, real_t weight)
+ public readonly Vector4 Lerp(Vector4 to, real_t weight)
{
return new Vector4
(
- Mathf.Lerp(x, to.x, weight),
- Mathf.Lerp(y, to.y, weight),
- Mathf.Lerp(z, to.z, weight),
- Mathf.Lerp(w, to.w, weight)
+ Mathf.Lerp(X, to.X, weight),
+ Mathf.Lerp(Y, to.Y, weight),
+ Mathf.Lerp(Z, to.Z, weight),
+ Mathf.Lerp(W, to.W, weight)
);
}
@@ -342,10 +352,10 @@ namespace Godot
/// If all components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the highest axis.</returns>
- public Axis MaxAxisIndex()
+ public readonly Axis MaxAxisIndex()
{
int max_index = 0;
- real_t max_value = x;
+ real_t max_value = X;
for (int i = 1; i < 4; i++)
{
if (this[i] > max_value)
@@ -362,10 +372,10 @@ namespace Godot
/// If all components are equal, this method returns <see cref="Axis.W"/>.
/// </summary>
/// <returns>The index of the lowest axis.</returns>
- public Axis MinAxisIndex()
+ public readonly Axis MinAxisIndex()
{
int min_index = 0;
- real_t min_value = x;
+ real_t min_value = X;
for (int i = 1; i < 4; i++)
{
if (this[i] <= min_value)
@@ -381,7 +391,7 @@ namespace Godot
/// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>.
/// </summary>
/// <returns>A normalized version of the vector.</returns>
- public Vector4 Normalized()
+ public readonly Vector4 Normalized()
{
Vector4 v = this;
v.Normalize();
@@ -396,13 +406,13 @@ namespace Godot
/// <returns>
/// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>.
/// </returns>
- public Vector4 PosMod(real_t mod)
+ public readonly Vector4 PosMod(real_t mod)
{
return new Vector4(
- Mathf.PosMod(x, mod),
- Mathf.PosMod(y, mod),
- Mathf.PosMod(z, mod),
- Mathf.PosMod(w, mod)
+ Mathf.PosMod(X, mod),
+ Mathf.PosMod(Y, mod),
+ Mathf.PosMod(Z, mod),
+ Mathf.PosMod(W, mod)
);
}
@@ -414,13 +424,13 @@ namespace Godot
/// <returns>
/// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components.
/// </returns>
- public Vector4 PosMod(Vector4 modv)
+ public readonly Vector4 PosMod(Vector4 modv)
{
return new Vector4(
- Mathf.PosMod(x, modv.x),
- Mathf.PosMod(y, modv.y),
- Mathf.PosMod(z, modv.z),
- Mathf.PosMod(w, modv.w)
+ Mathf.PosMod(X, modv.X),
+ Mathf.PosMod(Y, modv.Y),
+ Mathf.PosMod(Z, modv.Z),
+ Mathf.PosMod(W, modv.W)
);
}
@@ -429,9 +439,9 @@ namespace Godot
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
/// <returns>The rounded vector.</returns>
- public Vector4 Round()
+ public readonly Vector4 Round()
{
- return new Vector4(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z), Mathf.Round(w));
+ return new Vector4(Mathf.Round(X), Mathf.Round(Y), Mathf.Round(Z), Mathf.Round(W));
}
/// <summary>
@@ -440,13 +450,13 @@ namespace Godot
/// by calling <see cref="Mathf.Sign(real_t)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
- public Vector4 Sign()
+ public readonly Vector4 Sign()
{
Vector4 v;
- v.x = Mathf.Sign(x);
- v.y = Mathf.Sign(y);
- v.z = Mathf.Sign(z);
- v.w = Mathf.Sign(w);
+ v.X = Mathf.Sign(X);
+ v.Y = Mathf.Sign(Y);
+ v.Z = Mathf.Sign(Z);
+ v.W = Mathf.Sign(W);
return v;
}
@@ -456,13 +466,13 @@ namespace Godot
/// </summary>
/// <param name="step">A vector value representing the step size to snap to.</param>
/// <returns>The snapped vector.</returns>
- public Vector4 Snapped(Vector4 step)
+ public readonly Vector4 Snapped(Vector4 step)
{
return new Vector4(
- Mathf.Snapped(x, step.x),
- Mathf.Snapped(y, step.y),
- Mathf.Snapped(z, step.z),
- Mathf.Snapped(w, step.w)
+ Mathf.Snapped(X, step.X),
+ Mathf.Snapped(Y, step.Y),
+ Mathf.Snapped(Z, step.Z),
+ Mathf.Snapped(W, step.W)
);
}
@@ -496,10 +506,10 @@ namespace Godot
/// <param name="w">The vector's W component.</param>
public Vector4(real_t x, real_t y, real_t z, real_t w)
{
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
+ X = x;
+ Y = y;
+ Z = z;
+ W = w;
}
/// <summary>
@@ -511,10 +521,10 @@ namespace Godot
/// <returns>The added vector.</returns>
public static Vector4 operator +(Vector4 left, Vector4 right)
{
- left.x += right.x;
- left.y += right.y;
- left.z += right.z;
- left.w += right.w;
+ left.X += right.X;
+ left.Y += right.Y;
+ left.Z += right.Z;
+ left.W += right.W;
return left;
}
@@ -527,16 +537,16 @@ namespace Godot
/// <returns>The subtracted vector.</returns>
public static Vector4 operator -(Vector4 left, Vector4 right)
{
- left.x -= right.x;
- left.y -= right.y;
- left.z -= right.z;
- left.w -= right.w;
+ left.X -= right.X;
+ left.Y -= right.Y;
+ left.Z -= right.Z;
+ left.W -= right.W;
return left;
}
/// <summary>
/// Returns the negative value of the <see cref="Vector4"/>.
- /// This is the same as writing <c>new Vector4(-v.x, -v.y, -v.z, -v.w)</c>.
+ /// This is the same as writing <c>new Vector4(-v.X, -v.Y, -v.Z, -v.W)</c>.
/// This operation flips the direction of the vector while
/// keeping the same magnitude.
/// With floats, the number zero can be either positive or negative.
@@ -545,10 +555,10 @@ namespace Godot
/// <returns>The negated/flipped vector.</returns>
public static Vector4 operator -(Vector4 vec)
{
- vec.x = -vec.x;
- vec.y = -vec.y;
- vec.z = -vec.z;
- vec.w = -vec.w;
+ vec.X = -vec.X;
+ vec.Y = -vec.Y;
+ vec.Z = -vec.Z;
+ vec.W = -vec.W;
return vec;
}
@@ -561,10 +571,10 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector4 operator *(Vector4 vec, real_t scale)
{
- vec.x *= scale;
- vec.y *= scale;
- vec.z *= scale;
- vec.w *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
+ vec.Z *= scale;
+ vec.W *= scale;
return vec;
}
@@ -577,10 +587,10 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector4 operator *(real_t scale, Vector4 vec)
{
- vec.x *= scale;
- vec.y *= scale;
- vec.z *= scale;
- vec.w *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
+ vec.Z *= scale;
+ vec.W *= scale;
return vec;
}
@@ -593,10 +603,10 @@ namespace Godot
/// <returns>The multiplied vector.</returns>
public static Vector4 operator *(Vector4 left, Vector4 right)
{
- left.x *= right.x;
- left.y *= right.y;
- left.z *= right.z;
- left.w *= right.w;
+ left.X *= right.X;
+ left.Y *= right.Y;
+ left.Z *= right.Z;
+ left.W *= right.W;
return left;
}
@@ -609,10 +619,10 @@ namespace Godot
/// <returns>The divided vector.</returns>
public static Vector4 operator /(Vector4 vec, real_t divisor)
{
- vec.x /= divisor;
- vec.y /= divisor;
- vec.z /= divisor;
- vec.w /= divisor;
+ vec.X /= divisor;
+ vec.Y /= divisor;
+ vec.Z /= divisor;
+ vec.W /= divisor;
return vec;
}
@@ -625,10 +635,10 @@ namespace Godot
/// <returns>The divided vector.</returns>
public static Vector4 operator /(Vector4 vec, Vector4 divisorv)
{
- vec.x /= divisorv.x;
- vec.y /= divisorv.y;
- vec.z /= divisorv.z;
- vec.w /= divisorv.w;
+ vec.X /= divisorv.X;
+ vec.Y /= divisorv.Y;
+ vec.Z /= divisorv.Z;
+ vec.W /= divisorv.W;
return vec;
}
@@ -650,10 +660,10 @@ namespace Godot
/// <returns>The remainder vector.</returns>
public static Vector4 operator %(Vector4 vec, real_t divisor)
{
- vec.x %= divisor;
- vec.y %= divisor;
- vec.z %= divisor;
- vec.w %= divisor;
+ vec.X %= divisor;
+ vec.Y %= divisor;
+ vec.Z %= divisor;
+ vec.W %= divisor;
return vec;
}
@@ -675,10 +685,10 @@ namespace Godot
/// <returns>The remainder vector.</returns>
public static Vector4 operator %(Vector4 vec, Vector4 divisorv)
{
- vec.x %= divisorv.x;
- vec.y %= divisorv.y;
- vec.z %= divisorv.z;
- vec.w %= divisorv.w;
+ vec.X %= divisorv.X;
+ vec.Y %= divisorv.Y;
+ vec.Z %= divisorv.Z;
+ vec.W %= divisorv.W;
return vec;
}
@@ -721,19 +731,19 @@ namespace Godot
/// <returns>Whether or not the left is less than the right.</returns>
public static bool operator <(Vector4 left, Vector4 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- if (left.z == right.z)
+ if (left.Z == right.Z)
{
- return left.w < right.w;
+ return left.W < right.W;
}
- return left.z < right.z;
+ return left.Z < right.Z;
}
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
@@ -749,19 +759,19 @@ namespace Godot
/// <returns>Whether or not the left is greater than the right.</returns>
public static bool operator >(Vector4 left, Vector4 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- if (left.z == right.z)
+ if (left.Z == right.Z)
{
- return left.w > right.w;
+ return left.W > right.W;
}
- return left.z > right.z;
+ return left.Z > right.Z;
}
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
@@ -777,19 +787,19 @@ namespace Godot
/// <returns>Whether or not the left is less than or equal to the right.</returns>
public static bool operator <=(Vector4 left, Vector4 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- if (left.z == right.z)
+ if (left.Z == right.Z)
{
- return left.w <= right.w;
+ return left.W <= right.W;
}
- return left.z < right.z;
+ return left.Z < right.Z;
}
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
@@ -805,19 +815,19 @@ namespace Godot
/// <returns>Whether or not the left is greater than or equal to the right.</returns>
public static bool operator >=(Vector4 left, Vector4 right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- if (left.z == right.z)
+ if (left.Z == right.Z)
{
- return left.w >= right.w;
+ return left.W >= right.W;
}
- return left.z > right.z;
+ return left.Z > right.Z;
}
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
@@ -828,7 +838,7 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
return obj is Vector4 other && Equals(other);
}
@@ -840,9 +850,9 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>Whether or not the vectors are exactly equal.</returns>
- public bool Equals(Vector4 other)
+ public readonly bool Equals(Vector4 other)
{
- return x == other.x && y == other.y && z == other.z && w == other.w;
+ return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
}
/// <summary>
@@ -851,18 +861,30 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector to compare.</param>
/// <returns>Whether or not the vectors are approximately equal.</returns>
- public bool IsEqualApprox(Vector4 other)
+ public readonly bool IsEqualApprox(Vector4 other)
+ {
+ return Mathf.IsEqualApprox(X, other.X) && Mathf.IsEqualApprox(Y, other.Y) && Mathf.IsEqualApprox(Z, other.Z) && Mathf.IsEqualApprox(W, other.W);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
{
- return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);
+ return Mathf.IsZeroApprox(X) && Mathf.IsZeroApprox(Y) && Mathf.IsZeroApprox(Z) && Mathf.IsZeroApprox(W);
}
/// <summary>
/// Serves as the hash function for <see cref="Vector4"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ return Y.GetHashCode() ^ X.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode();
}
/// <summary>
@@ -871,16 +893,16 @@ namespace Godot
/// <returns>A string representation of this vector.</returns>
public override string ToString()
{
- return $"({x}, {y}, {z}, {w})";
+ return $"({X}, {Y}, {Z}, {W})";
}
/// <summary>
/// Converts this <see cref="Vector4"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}, {w.ToString(format)})";
+ return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
index 4b1bb3ba19..f065327066 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
@@ -8,7 +8,7 @@ namespace Godot
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
- public struct Vector4i : IEquatable<Vector4i>
+ public struct Vector4I : IEquatable<Vector4I>
{
/// <summary>
/// Enumerated index values for the axes.
@@ -37,22 +37,22 @@ namespace Godot
/// <summary>
/// The vector's X component. Also accessible by using the index position <c>[0]</c>.
/// </summary>
- public int x;
+ public int X;
/// <summary>
/// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
/// </summary>
- public int y;
+ public int Y;
/// <summary>
/// The vector's Z component. Also accessible by using the index position <c>[2]</c>.
/// </summary>
- public int z;
+ public int Z;
/// <summary>
/// The vector's W component. Also accessible by using the index position <c>[3]</c>.
/// </summary>
- public int w;
+ public int W;
/// <summary>
/// Access vector components using their <paramref name="index"/>.
@@ -61,25 +61,25 @@ namespace Godot
/// <paramref name="index"/> is not 0, 1, 2 or 3.
/// </exception>
/// <value>
- /// <c>[0]</c> is equivalent to <see cref="x"/>,
- /// <c>[1]</c> is equivalent to <see cref="y"/>,
- /// <c>[2]</c> is equivalent to <see cref="z"/>.
- /// <c>[3]</c> is equivalent to <see cref="w"/>.
+ /// <c>[0]</c> is equivalent to <see cref="X"/>,
+ /// <c>[1]</c> is equivalent to <see cref="Y"/>,
+ /// <c>[2]</c> is equivalent to <see cref="Z"/>.
+ /// <c>[3]</c> is equivalent to <see cref="W"/>.
/// </value>
public int this[int index]
{
- get
+ readonly get
{
switch (index)
{
case 0:
- return x;
+ return X;
case 1:
- return y;
+ return Y;
case 2:
- return z;
+ return Z;
case 3:
- return w;
+ return W;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
@@ -89,16 +89,16 @@ namespace Godot
switch (index)
{
case 0:
- x = value;
+ X = value;
return;
case 1:
- y = value;
+ Y = value;
return;
case 2:
- z = value;
+ Z = value;
return;
case 3:
- w = value;
+ W = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(index));
@@ -109,21 +109,21 @@ namespace Godot
/// <summary>
/// Helper method for deconstruction into a tuple.
/// </summary>
- public void Deconstruct(out int x, out int y, out int z, out int w)
+ public readonly void Deconstruct(out int x, out int y, out int z, out int w)
{
- x = this.x;
- y = this.y;
- z = this.z;
- w = this.w;
+ x = X;
+ y = Y;
+ z = Z;
+ w = W;
}
/// <summary>
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns>
- public Vector4i Abs()
+ public readonly Vector4I Abs()
{
- return new Vector4i(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z), Mathf.Abs(w));
+ return new Vector4I(Mathf.Abs(X), Mathf.Abs(Y), Mathf.Abs(Z), Mathf.Abs(W));
}
/// <summary>
@@ -134,14 +134,14 @@ namespace Godot
/// <param name="min">The vector with minimum allowed values.</param>
/// <param name="max">The vector with maximum allowed values.</param>
/// <returns>The vector with all components clamped.</returns>
- public Vector4i Clamp(Vector4i min, Vector4i max)
+ public readonly Vector4I Clamp(Vector4I min, Vector4I max)
{
- return new Vector4i
+ return new Vector4I
(
- Mathf.Clamp(x, min.x, max.x),
- Mathf.Clamp(y, min.y, max.y),
- Mathf.Clamp(z, min.z, max.z),
- Mathf.Clamp(w, min.w, max.w)
+ Mathf.Clamp(X, min.X, max.X),
+ Mathf.Clamp(Y, min.Y, max.Y),
+ Mathf.Clamp(Z, min.Z, max.Z),
+ Mathf.Clamp(W, min.W, max.W)
);
}
@@ -150,12 +150,12 @@ namespace Godot
/// </summary>
/// <seealso cref="LengthSquared"/>
/// <returns>The length of this vector.</returns>
- public real_t Length()
+ public readonly real_t Length()
{
- int x2 = x * x;
- int y2 = y * y;
- int z2 = z * z;
- int w2 = w * w;
+ int x2 = X * X;
+ int y2 = Y * Y;
+ int z2 = Z * Z;
+ int w2 = W * W;
return Mathf.Sqrt(x2 + y2 + z2 + w2);
}
@@ -166,12 +166,12 @@ namespace Godot
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
- public int LengthSquared()
+ public readonly int LengthSquared()
{
- int x2 = x * x;
- int y2 = y * y;
- int z2 = z * z;
- int w2 = w * w;
+ int x2 = X * X;
+ int y2 = Y * Y;
+ int z2 = Z * Z;
+ int w2 = W * W;
return x2 + y2 + z2 + w2;
}
@@ -181,10 +181,10 @@ namespace Godot
/// If all components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the highest axis.</returns>
- public Axis MaxAxisIndex()
+ public readonly Axis MaxAxisIndex()
{
int max_index = 0;
- int max_value = x;
+ int max_value = X;
for (int i = 1; i < 4; i++)
{
if (this[i] > max_value)
@@ -201,10 +201,10 @@ namespace Godot
/// If all components are equal, this method returns <see cref="Axis.W"/>.
/// </summary>
/// <returns>The index of the lowest axis.</returns>
- public Axis MinAxisIndex()
+ public readonly Axis MinAxisIndex()
{
int min_index = 0;
- int min_value = x;
+ int min_value = X;
for (int i = 1; i < 4; i++)
{
if (this[i] <= min_value)
@@ -222,245 +222,217 @@ namespace Godot
/// by calling <see cref="Mathf.Sign(int)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
- public Vector4i Sign()
+ public readonly Vector4I Sign()
{
- return new Vector4i(Mathf.Sign(x), Mathf.Sign(y), Mathf.Sign(z), Mathf.Sign(w));
+ return new Vector4I(Mathf.Sign(X), Mathf.Sign(Y), Mathf.Sign(Z), Mathf.Sign(W));
}
// Constants
- private static readonly Vector4i _zero = new Vector4i(0, 0, 0, 0);
- private static readonly Vector4i _one = new Vector4i(1, 1, 1, 1);
+ private static readonly Vector4I _zero = new Vector4I(0, 0, 0, 0);
+ private static readonly Vector4I _one = new Vector4I(1, 1, 1, 1);
/// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
/// </summary>
- /// <value>Equivalent to <c>new Vector4i(0, 0, 0, 0)</c>.</value>
- public static Vector4i Zero { get { return _zero; } }
+ /// <value>Equivalent to <c>new Vector4I(0, 0, 0, 0)</c>.</value>
+ public static Vector4I Zero { get { return _zero; } }
/// <summary>
/// One vector, a vector with all components set to <c>1</c>.
/// </summary>
- /// <value>Equivalent to <c>new Vector4i(1, 1, 1, 1)</c>.</value>
- public static Vector4i One { get { return _one; } }
+ /// <value>Equivalent to <c>new Vector4I(1, 1, 1, 1)</c>.</value>
+ public static Vector4I One { get { return _one; } }
/// <summary>
- /// Constructs a new <see cref="Vector4i"/> with the given components.
+ /// Constructs a new <see cref="Vector4I"/> with the given components.
/// </summary>
/// <param name="x">The vector's X component.</param>
/// <param name="y">The vector's Y component.</param>
/// <param name="z">The vector's Z component.</param>
/// <param name="w">The vector's W component.</param>
- public Vector4i(int x, int y, int z, int w)
+ public Vector4I(int x, int y, int z, int w)
{
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
+ X = x;
+ Y = y;
+ Z = z;
+ W = w;
}
/// <summary>
- /// Adds each component of the <see cref="Vector4i"/>
- /// with the components of the given <see cref="Vector4i"/>.
+ /// Adds each component of the <see cref="Vector4I"/>
+ /// with the components of the given <see cref="Vector4I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The added vector.</returns>
- public static Vector4i operator +(Vector4i left, Vector4i right)
+ public static Vector4I operator +(Vector4I left, Vector4I right)
{
- left.x += right.x;
- left.y += right.y;
- left.z += right.z;
- left.w += right.w;
+ left.X += right.X;
+ left.Y += right.Y;
+ left.Z += right.Z;
+ left.W += right.W;
return left;
}
/// <summary>
- /// Subtracts each component of the <see cref="Vector4i"/>
- /// by the components of the given <see cref="Vector4i"/>.
+ /// Subtracts each component of the <see cref="Vector4I"/>
+ /// by the components of the given <see cref="Vector4I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The subtracted vector.</returns>
- public static Vector4i operator -(Vector4i left, Vector4i right)
+ public static Vector4I operator -(Vector4I left, Vector4I right)
{
- left.x -= right.x;
- left.y -= right.y;
- left.z -= right.z;
- left.w -= right.w;
+ left.X -= right.X;
+ left.Y -= right.Y;
+ left.Z -= right.Z;
+ left.W -= right.W;
return left;
}
/// <summary>
- /// Returns the negative value of the <see cref="Vector4i"/>.
- /// This is the same as writing <c>new Vector4i(-v.x, -v.y, -v.z, -v.w)</c>.
+ /// Returns the negative value of the <see cref="Vector4I"/>.
+ /// This is the same as writing <c>new Vector4I(-v.X, -v.Y, -v.Z, -v.W)</c>.
/// This operation flips the direction of the vector while
/// keeping the same magnitude.
/// </summary>
/// <param name="vec">The vector to negate/flip.</param>
/// <returns>The negated/flipped vector.</returns>
- public static Vector4i operator -(Vector4i vec)
+ public static Vector4I operator -(Vector4I vec)
{
- vec.x = -vec.x;
- vec.y = -vec.y;
- vec.z = -vec.z;
- vec.w = -vec.w;
+ vec.X = -vec.X;
+ vec.Y = -vec.Y;
+ vec.Z = -vec.Z;
+ vec.W = -vec.W;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector4i"/>
+ /// Multiplies each component of the <see cref="Vector4I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="vec">The vector to multiply.</param>
/// <param name="scale">The scale to multiply by.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector4i operator *(Vector4i vec, int scale)
+ public static Vector4I operator *(Vector4I vec, int scale)
{
- vec.x *= scale;
- vec.y *= scale;
- vec.z *= scale;
- vec.w *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
+ vec.Z *= scale;
+ vec.W *= scale;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector4i"/>
+ /// Multiplies each component of the <see cref="Vector4I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="scale">The scale to multiply by.</param>
/// <param name="vec">The vector to multiply.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector4i operator *(int scale, Vector4i vec)
+ public static Vector4I operator *(int scale, Vector4I vec)
{
- vec.x *= scale;
- vec.y *= scale;
- vec.z *= scale;
- vec.w *= scale;
+ vec.X *= scale;
+ vec.Y *= scale;
+ vec.Z *= scale;
+ vec.W *= scale;
return vec;
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector4i"/>
- /// by the components of the given <see cref="Vector4i"/>.
+ /// Multiplies each component of the <see cref="Vector4I"/>
+ /// by the components of the given <see cref="Vector4I"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The multiplied vector.</returns>
- public static Vector4i operator *(Vector4i left, Vector4i right)
+ public static Vector4I operator *(Vector4I left, Vector4I right)
{
- left.x *= right.x;
- left.y *= right.y;
- left.z *= right.z;
- left.w *= right.w;
+ left.X *= right.X;
+ left.Y *= right.Y;
+ left.Z *= right.Z;
+ left.W *= right.W;
return left;
}
/// <summary>
- /// Divides each component of the <see cref="Vector4i"/>
+ /// Divides each component of the <see cref="Vector4I"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisor">The divisor value.</param>
/// <returns>The divided vector.</returns>
- public static Vector4i operator /(Vector4i vec, int divisor)
+ public static Vector4I operator /(Vector4I vec, int divisor)
{
- vec.x /= divisor;
- vec.y /= divisor;
- vec.z /= divisor;
- vec.w /= divisor;
+ vec.X /= divisor;
+ vec.Y /= divisor;
+ vec.Z /= divisor;
+ vec.W /= divisor;
return vec;
}
/// <summary>
- /// Divides each component of the <see cref="Vector4i"/>
- /// by the components of the given <see cref="Vector4i"/>.
+ /// Divides each component of the <see cref="Vector4I"/>
+ /// by the components of the given <see cref="Vector4I"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisorv">The divisor vector.</param>
/// <returns>The divided vector.</returns>
- public static Vector4i operator /(Vector4i vec, Vector4i divisorv)
+ public static Vector4I operator /(Vector4I vec, Vector4I divisorv)
{
- vec.x /= divisorv.x;
- vec.y /= divisorv.y;
- vec.z /= divisorv.z;
- vec.w /= divisorv.w;
+ vec.X /= divisorv.X;
+ vec.Y /= divisorv.Y;
+ vec.Z /= divisorv.Z;
+ vec.W /= divisorv.W;
return vec;
}
/// <summary>
- /// Gets the remainder of each component of the <see cref="Vector4i"/>
+ /// Gets the remainder of each component of the <see cref="Vector4I"/>
/// with the components of the given <see langword="int"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
+ /// if you want to handle negative numbers.
/// </summary>
/// <example>
/// <code>
- /// GD.Print(new Vecto43i(10, -20, 30, -40) % 7); // Prints "(3, -6, 2, -5)"
+ /// GD.Print(new Vector4I(10, -20, 30, -40) % 7); // Prints "(3, -6, 2, -5)"
/// </code>
/// </example>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisor">The divisor value.</param>
/// <returns>The remainder vector.</returns>
- public static Vector4i operator %(Vector4i vec, int divisor)
+ public static Vector4I operator %(Vector4I vec, int divisor)
{
- vec.x %= divisor;
- vec.y %= divisor;
- vec.z %= divisor;
- vec.w %= divisor;
+ vec.X %= divisor;
+ vec.Y %= divisor;
+ vec.Z %= divisor;
+ vec.W %= divisor;
return vec;
}
/// <summary>
- /// Gets the remainder of each component of the <see cref="Vector4i"/>
- /// with the components of the given <see cref="Vector4i"/>.
+ /// Gets the remainder of each component of the <see cref="Vector4I"/>
+ /// with the components of the given <see cref="Vector4I"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
+ /// if you want to handle negative numbers.
/// </summary>
/// <example>
/// <code>
- /// GD.Print(new Vector4i(10, -20, 30, -40) % new Vector4i(6, 7, 8, 9)); // Prints "(4, -6, 6, -4)"
+ /// GD.Print(new Vector4I(10, -20, 30, -40) % new Vector4I(6, 7, 8, 9)); // Prints "(4, -6, 6, -4)"
/// </code>
/// </example>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisorv">The divisor vector.</param>
/// <returns>The remainder vector.</returns>
- public static Vector4i operator %(Vector4i vec, Vector4i divisorv)
+ public static Vector4I operator %(Vector4I vec, Vector4I divisorv)
{
- vec.x %= divisorv.x;
- vec.y %= divisorv.y;
- vec.z %= divisorv.z;
- vec.w %= divisorv.w;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector4i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector4i operator &(Vector4i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- vec.z &= and;
- vec.w &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector4i"/>
- /// and the given <see cref="Vector4i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector4i operator &(Vector4i vec, Vector4i andv)
- {
- vec.x &= andv.x;
- vec.y &= andv.y;
- vec.z &= andv.z;
- vec.w &= andv.w;
+ vec.X %= divisorv.X;
+ vec.Y %= divisorv.Y;
+ vec.Z %= divisorv.Z;
+ vec.W %= divisorv.W;
return vec;
}
@@ -470,7 +442,7 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the vectors are equal.</returns>
- public static bool operator ==(Vector4i left, Vector4i right)
+ public static bool operator ==(Vector4I left, Vector4I right)
{
return left.Equals(right);
}
@@ -481,13 +453,13 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the vectors are not equal.</returns>
- public static bool operator !=(Vector4i left, Vector4i right)
+ public static bool operator !=(Vector4I left, Vector4I right)
{
return !left.Equals(right);
}
/// <summary>
- /// Compares two <see cref="Vector4i"/> vectors by first checking if
+ /// Compares two <see cref="Vector4I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is less than
/// the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -497,25 +469,25 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is less than the right.</returns>
- public static bool operator <(Vector4i left, Vector4i right)
+ public static bool operator <(Vector4I left, Vector4I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- if (left.z == right.z)
+ if (left.Z == right.Z)
{
- return left.w < right.w;
+ return left.W < right.W;
}
- return left.z < right.z;
+ return left.Z < right.Z;
}
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
- /// Compares two <see cref="Vector4i"/> vectors by first checking if
+ /// Compares two <see cref="Vector4I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is greater than
/// the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -525,25 +497,25 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is greater than the right.</returns>
- public static bool operator >(Vector4i left, Vector4i right)
+ public static bool operator >(Vector4I left, Vector4I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- if (left.z == right.z)
+ if (left.Z == right.Z)
{
- return left.w > right.w;
+ return left.W > right.W;
}
- return left.z > right.z;
+ return left.Z > right.Z;
}
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
- /// Compares two <see cref="Vector4i"/> vectors by first checking if
+ /// Compares two <see cref="Vector4I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is less than
/// or equal to the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -553,25 +525,25 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is less than or equal to the right.</returns>
- public static bool operator <=(Vector4i left, Vector4i right)
+ public static bool operator <=(Vector4I left, Vector4I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- if (left.z == right.z)
+ if (left.Z == right.Z)
{
- return left.w <= right.w;
+ return left.W <= right.W;
}
- return left.z < right.z;
+ return left.Z < right.Z;
}
- return left.y < right.y;
+ return left.Y < right.Y;
}
- return left.x < right.x;
+ return left.X < right.X;
}
/// <summary>
- /// Compares two <see cref="Vector4i"/> vectors by first checking if
+ /// Compares two <see cref="Vector4I"/> vectors by first checking if
/// the X value of the <paramref name="left"/> vector is greater than
/// or equal to the X value of the <paramref name="right"/> vector.
/// If the X values are exactly equal, then it repeats this check
@@ -581,43 +553,43 @@ namespace Godot
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>Whether or not the left is greater than or equal to the right.</returns>
- public static bool operator >=(Vector4i left, Vector4i right)
+ public static bool operator >=(Vector4I left, Vector4I right)
{
- if (left.x == right.x)
+ if (left.X == right.X)
{
- if (left.y == right.y)
+ if (left.Y == right.Y)
{
- if (left.z == right.z)
+ if (left.Z == right.Z)
{
- return left.w >= right.w;
+ return left.W >= right.W;
}
- return left.z > right.z;
+ return left.Z > right.Z;
}
- return left.y > right.y;
+ return left.Y > right.Y;
}
- return left.x > right.x;
+ return left.X > right.X;
}
/// <summary>
- /// Converts this <see cref="Vector4i"/> to a <see cref="Vector4"/>.
+ /// Converts this <see cref="Vector4I"/> to a <see cref="Vector4"/>.
/// </summary>
/// <param name="value">The vector to convert.</param>
- public static implicit operator Vector4(Vector4i value)
+ public static implicit operator Vector4(Vector4I value)
{
- return new Vector4(value.x, value.y, value.z, value.w);
+ return new Vector4(value.X, value.Y, value.Z, value.W);
}
/// <summary>
- /// Converts a <see cref="Vector4"/> to a <see cref="Vector4i"/>.
+ /// Converts a <see cref="Vector4"/> to a <see cref="Vector4I"/>.
/// </summary>
/// <param name="value">The vector to convert.</param>
- public static explicit operator Vector4i(Vector4 value)
+ public static explicit operator Vector4I(Vector4 value)
{
- return new Vector4i(
- Mathf.RoundToInt(value.x),
- Mathf.RoundToInt(value.y),
- Mathf.RoundToInt(value.z),
- Mathf.RoundToInt(value.w)
+ return new Vector4I(
+ Mathf.RoundToInt(value.X),
+ Mathf.RoundToInt(value.Y),
+ Mathf.RoundToInt(value.Z),
+ Mathf.RoundToInt(value.W)
);
}
@@ -627,9 +599,9 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
- return obj is Vector4i other && Equals(other);
+ return obj is Vector4I other && Equals(other);
}
/// <summary>
@@ -637,36 +609,36 @@ namespace Godot
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>Whether or not the vectors are equal.</returns>
- public bool Equals(Vector4i other)
+ public readonly bool Equals(Vector4I other)
{
- return x == other.x && y == other.y && z == other.z && w == other.w;
+ return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
}
/// <summary>
- /// Serves as the hash function for <see cref="Vector4i"/>.
+ /// Serves as the hash function for <see cref="Vector4I"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
- public override int GetHashCode()
+ public override readonly int GetHashCode()
{
- return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ return Y.GetHashCode() ^ X.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode();
}
/// <summary>
- /// Converts this <see cref="Vector4i"/> to a string.
+ /// Converts this <see cref="Vector4I"/> to a string.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public override string ToString()
+ public override readonly string ToString()
{
- return $"({x}, {y}, {z}, {w})";
+ return $"({X}, {Y}, {Z}, {W})";
}
/// <summary>
- /// Converts this <see cref="Vector4i"/> to a string with the given <paramref name="format"/>.
+ /// Converts this <see cref="Vector4I"/> to a string with the given <paramref name="format"/>.
/// </summary>
/// <returns>A string representation of this vector.</returns>
- public string ToString(string format)
+ public readonly string ToString(string format)
{
- return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}), {w.ToString(format)})";
+ return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}), {W.ToString(format)})";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index e3fb254f49..7aa2f7e959 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -49,7 +49,7 @@
</ItemGroup>
<!-- Sources -->
<ItemGroup>
- <Compile Include="Core\AABB.cs" />
+ <Compile Include="Core\Aabb.cs" />
<Compile Include="Core\Bridge\GodotSerializationInfo.cs" />
<Compile Include="Core\Bridge\MethodInfo.cs" />
<Compile Include="Core\Callable.generics.cs" />
@@ -60,8 +60,9 @@
<Compile Include="Core\Attributes\ExportCategoryAttribute.cs" />
<Compile Include="Core\Attributes\ExportGroupAttribute.cs" />
<Compile Include="Core\Attributes\ExportSubgroupAttribute.cs" />
+ <Compile Include="Core\Attributes\GodotClassNameAttribute.cs" />
<Compile Include="Core\Attributes\MustBeVariantAttribute.cs" />
- <Compile Include="Core\Attributes\RPCAttribute.cs" />
+ <Compile Include="Core\Attributes\RpcAttribute.cs" />
<Compile Include="Core\Attributes\ScriptPathAttribute.cs" />
<Compile Include="Core\Attributes\SignalAttribute.cs" />
<Compile Include="Core\Attributes\ToolAttribute.cs" />
@@ -80,11 +81,13 @@
<Compile Include="Core\DelegateUtils.cs" />
<Compile Include="Core\Dictionary.cs" />
<Compile Include="Core\Dispatcher.cs" />
+ <Compile Include="Core\Extensions\GodotObjectExtensions.cs" />
<Compile Include="Core\Extensions\NodeExtensions.cs" />
- <Compile Include="Core\Extensions\ObjectExtensions.cs" />
<Compile Include="Core\Extensions\PackedSceneExtensions.cs" />
<Compile Include="Core\Extensions\ResourceLoaderExtensions.cs" />
<Compile Include="Core\GD.cs" />
+ <Compile Include="Core\GodotObject.base.cs" />
+ <Compile Include="Core\GodotObject.exceptions.cs" />
<Compile Include="Core\GodotSynchronizationContext.cs" />
<Compile Include="Core\GodotTaskScheduler.cs" />
<Compile Include="Core\GodotTraceListener.cs" />
@@ -101,37 +104,34 @@
<Compile Include="Core\NativeInterop\InteropUtils.cs" />
<Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" />
<Compile Include="Core\NativeInterop\NativeVariantPtrArgs.cs" />
- <Compile Include="Core\NativeInterop\VariantConversionCallbacks.cs" />
- <Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" />
<Compile Include="Core\NativeInterop\VariantUtils.cs" />
+ <Compile Include="Core\NativeInterop\VariantUtils.generic.cs" />
<Compile Include="Core\NodePath.cs" />
- <Compile Include="Core\Object.base.cs" />
- <Compile Include="Core\Object.exceptions.cs" />
<Compile Include="Core\Plane.cs" />
<Compile Include="Core\Projection.cs" />
<Compile Include="Core\Quaternion.cs" />
<Compile Include="Core\Rect2.cs" />
- <Compile Include="Core\Rect2i.cs" />
+ <Compile Include="Core\Rect2I.cs" />
<Compile Include="Core\ReflectionUtils.cs" />
- <Compile Include="Core\RID.cs" />
+ <Compile Include="Core\Rid.cs" />
<Compile Include="Core\NativeInterop\NativeFuncs.cs" />
<Compile Include="Core\NativeInterop\InteropStructs.cs" />
<Compile Include="Core\NativeInterop\Marshaling.cs" />
- <Compile Include="Core\SignalInfo.cs" />
+ <Compile Include="Core\Signal.cs" />
<Compile Include="Core\SignalAwaiter.cs" />
<Compile Include="Core\StringExtensions.cs" />
<Compile Include="Core\StringName.cs" />
<Compile Include="Core\Transform2D.cs" />
<Compile Include="Core\Transform3D.cs" />
+ <Compile Include="Core\Variant.cs" />
<Compile Include="Core\Vector2.cs" />
- <Compile Include="Core\Vector2i.cs" />
+ <Compile Include="Core\Vector2I.cs" />
<Compile Include="Core\Vector3.cs" />
- <Compile Include="Core\Vector3i.cs" />
+ <Compile Include="Core\Vector3I.cs" />
<Compile Include="Core\Vector4.cs" />
- <Compile Include="Core\Vector4i.cs" />
+ <Compile Include="Core\Vector4I.cs" />
<Compile Include="GlobalUsings.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Variant.cs" />
</ItemGroup>
<!--
We import a props file with auto-generated includes. This works well with Rider.