From 9cf5ccd0524273e2374531ae7c2ff0335eb319c8 Mon Sep 17 00:00:00 2001 From: Phill Date: Thu, 1 May 2025 19:39:38 -0400 Subject: [PATCH 1/5] get rid of the euler angles component #1 --- source/Components/Anchor.cs | 66 +++++++++++++++++-------------- source/Components/EulerAngles.cs | 67 -------------------------------- source/Transform.cs | 21 +++------- tests/AnchorTypeTests.cs | 58 +++++++++++++-------------- tests/LocalToWorldTests.cs | 12 ------ 5 files changed, 72 insertions(+), 152 deletions(-) delete mode 100644 source/Components/EulerAngles.cs diff --git a/source/Components/Anchor.cs b/source/Components/Anchor.cs index da16ce0..2495d7c 100644 --- a/source/Components/Anchor.cs +++ b/source/Components/Anchor.cs @@ -21,12 +21,12 @@ public struct Anchor : IEquatable public static readonly Anchor Right = new(new(1f, false), new(0.5f, false), new(0f, false), new(1f, false), new(0.5f, false), new(0f, false)); public static readonly Anchor Default = default; - public value minX; - public value minY; - public value minZ; - public value maxX; - public value maxY; - public value maxZ; + public Number minX; + public Number minY; + public Number minZ; + public Number maxX; + public Number maxY; + public Number maxZ; #if NET /// @@ -43,7 +43,7 @@ public Anchor() } #endif - public Anchor(value minX, value minY, value minZ, value maxX, value maxY, value maxZ) + public Anchor(Number minX, Number minY, Number minZ, Number maxX, Number maxY, Number maxZ) { this.minX = minX; this.minY = minY; @@ -78,7 +78,7 @@ public readonly override int GetHashCode() return !(left == right); } - public struct value : IEquatable + public struct Number : IEquatable { public const int NumberRange = 65536; public const int MaxNumberValue = 32768; @@ -86,7 +86,7 @@ public struct value : IEquatable private int data; - public bool Absolute + public bool IsAbsolute { readonly get { @@ -106,7 +106,7 @@ readonly get } } - public float Number + public float Value { readonly get { @@ -116,7 +116,7 @@ readonly get } set { - bool absolute = Absolute; + bool absolute = IsAbsolute; int valueInt = (int)(value * NumberRange) >> 1; data = valueInt; if (absolute) @@ -130,12 +130,12 @@ readonly get } } - public value(float number, bool fromEdge) + public Number(float value, bool absolute) { - ThrowIfOutOfRange(number); + ThrowIfOutOfRange(value); - data = (int)(number * NumberRange) >> 1; - if (fromEdge) + data = (int)(value * NumberRange) >> 1; + if (absolute) { data &= ~1; } @@ -145,7 +145,7 @@ public value(float number, bool fromEdge) } } - public value(ReadOnlySpan text) + public Number(ReadOnlySpan text) { bool negative = false; int index = 0; @@ -199,14 +199,22 @@ public value(ReadOnlySpan text) number = -number; } - Absolute = absolute; if (absolute) { - Number = number; + data &= ~1; + } + else + { + data |= 1; + } + + if (absolute) + { + Value = number; } else { - Number = number / 100f; + Value = number / 100f; } } @@ -219,8 +227,8 @@ public readonly override string ToString() public readonly int ToString(Span destination) { - bool isRelative = Absolute; - float number = Number; + bool isRelative = IsAbsolute; + float number = Value; int length = 0; if (isRelative) { @@ -241,10 +249,10 @@ public readonly int ToString(Span destination) public readonly override bool Equals(object? obj) { - return obj is value value && Equals(value); + return obj is Number value && Equals(value); } - public readonly bool Equals(value other) + public readonly bool Equals(Number other) { return data == other.data; } @@ -254,27 +262,27 @@ public readonly override int GetHashCode() return data.GetHashCode(); } - public static bool operator ==(value left, value right) + public static bool operator ==(Number left, Number right) { return left.Equals(right); } - public static bool operator !=(value left, value right) + public static bool operator !=(Number left, Number right) { return !(left == right); } - public static implicit operator float(value value) + public static implicit operator float(Number value) { - return value.Number; + return value.Value; } - public static implicit operator value(ReadOnlySpan text) + public static implicit operator Number(ReadOnlySpan text) { return new(text); } - public static implicit operator value(string text) + public static implicit operator Number(string text) { return new(text.AsSpan()); } diff --git a/source/Components/EulerAngles.cs b/source/Components/EulerAngles.cs deleted file mode 100644 index c74124c..0000000 --- a/source/Components/EulerAngles.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Numerics; - -namespace Transforms.Components -{ - public struct EulerAngles - { - public static readonly EulerAngles Default = new(0, 0, 0); - - public Vector3 value; - - public EulerAngles(Vector3 value) - { - this.value = value; - } - - public EulerAngles(float x, float y, float z) - { - value = new Vector3(x, y, z); - } - - public EulerAngles(Quaternion rotation) - { - Quaternion normalized = Quaternion.Normalize(rotation); - float sinPitch = 2f * (normalized.Y * normalized.Z + normalized.W * normalized.X); - float cosPitch = 1f - 2f * (normalized.X * normalized.X + normalized.Y * normalized.Y); - float pitch = MathF.Atan2(sinPitch, cosPitch); - - float sinYaw = 2f * (normalized.W * normalized.Y - normalized.X * normalized.Z); - float yaw; - if (MathF.Abs(sinYaw) >= 1f) - { - yaw = MathF.CopySign(MathF.PI * 0.5f, sinYaw); - } - else - { - yaw = MathF.Asin(sinYaw); - } - - float sinRoll = 2f * (normalized.X * normalized.Y + normalized.W * normalized.Z); - float cosRoll = 1f - 2f * (normalized.Y * normalized.Y + normalized.Z * normalized.Z); - float roll = MathF.Atan2(sinRoll, cosRoll); - value = new Vector3(pitch, yaw, roll); - } - - public readonly Quaternion AsQuaternion() - { - Vector3 value = this.value * 0.5f; - (float s, float c) x = MathF.SinCos(value.X); - (float s, float c) y = MathF.SinCos(value.Y); - (float s, float c) z = MathF.SinCos(value.Z); - return new Quaternion - { - W = x.c * y.c * z.c + x.s * y.s * z.s, - X = x.s * y.c * z.c - x.c * y.s * z.s, - Y = x.c * y.s * z.c + x.s * y.c * z.s, - Z = x.c * y.c * z.s - x.s * y.s * z.c - }; - } - - public static EulerAngles CreateFromDegrees(float x, float y, float z) - { - float ratio = MathF.PI / 180f; - return new EulerAngles(x * ratio, y * ratio, z * ratio); - } - } -} diff --git a/source/Transform.cs b/source/Transform.cs index 48315b5..9b0f284 100644 --- a/source/Transform.cs +++ b/source/Transform.cs @@ -43,21 +43,9 @@ public readonly ref Quaternion LocalRotation } } - public readonly ref Vector3 EulerAngles - { - get - { - ref EulerAngles component = ref TryGetComponent(out bool contains); - if (!contains) - { - component = ref AddComponent(); - component = Components.EulerAngles.Default; - } - - return ref component.value; - } - } - + /// + /// The anchor of this entity relative to the parent entity. + /// public readonly ref Anchor Anchor { get @@ -73,6 +61,9 @@ public readonly ref Anchor Anchor } } + /// + /// The pivot of this entity relative to the parent entity. + /// public readonly ref Pivot Pivot { get diff --git a/tests/AnchorTypeTests.cs b/tests/AnchorTypeTests.cs index e3a6822..9c1a77d 100644 --- a/tests/AnchorTypeTests.cs +++ b/tests/AnchorTypeTests.cs @@ -8,56 +8,56 @@ public class AnchorTypeTests [Test] public void CheckAnchorDataType() { - Anchor.value left = new(0.92123f, true); - Assert.That(left.Absolute, Is.True); - Assert.That(left.Number, Is.EqualTo(0.92123f).Within(0.1f)); + Anchor.Number left = new(0.92123f, true); + Assert.That(left.IsAbsolute, Is.True); + Assert.That(left.Value, Is.EqualTo(0.92123f).Within(0.1f)); - Anchor.value right = new(456f, false); - Assert.That(right.Absolute, Is.False); - Assert.That(right.Number, Is.EqualTo(456f).Within(0.1f)); + Anchor.Number right = new(456f, false); + Assert.That(right.IsAbsolute, Is.False); + Assert.That(right.Value, Is.EqualTo(456f).Within(0.1f)); Assert.That(left, Is.Not.EqualTo(right)); - Anchor.value up = new(0.5f, true); + Anchor.Number up = new(0.5f, true); Assert.That(up, Is.Not.EqualTo(left)); - Assert.That(up.Absolute, Is.True); - Assert.That(up.Number, Is.EqualTo(0.5f).Within(0.1f)); + Assert.That(up.IsAbsolute, Is.True); + Assert.That(up.Value, Is.EqualTo(0.5f).Within(0.1f)); - Anchor.value down = new(-3.1412f, false); + Anchor.Number down = new(-3.1412f, false); Assert.That(down, Is.Not.EqualTo(right)); - Assert.That(down.Absolute, Is.False); - Assert.That(down.Number, Is.EqualTo(-3.1412f).Within(0.1f)); + Assert.That(down.IsAbsolute, Is.False); + Assert.That(down.Value, Is.EqualTo(-3.1412f).Within(0.1f)); using RandomGenerator rng = new(); for (uint i = 0; i < 1024; i++) { float number = rng.NextFloat(-1000f, 1000f); bool isNormalized = rng.NextBool(); - Anchor.value value = new(number, isNormalized); - value.Number *= 2; - value.Absolute = !value.Absolute; - Assert.That(value.Number, Is.EqualTo(number * 2).Within(0.1f)); - Assert.That(value.Absolute, Is.EqualTo(!isNormalized)); + Anchor.Number value = new(number, isNormalized); + value.Value *= 2; + value.IsAbsolute = !value.IsAbsolute; + Assert.That(value.Value, Is.EqualTo(number * 2).Within(0.1f)); + Assert.That(value.IsAbsolute, Is.EqualTo(!isNormalized)); } } [Test] public void BuildAnchorValuesFromText() { - Anchor.value a = "0.5f"; - Assert.That(a.Number, Is.EqualTo(0.5f).Within(0.001f)); - Assert.That(a.Absolute, Is.True); + Anchor.Number a = "0.5f"; + Assert.That(a.Value, Is.EqualTo(0.5f).Within(0.001f)); + Assert.That(a.IsAbsolute, Is.True); - Anchor.value b = "50%"; - Assert.That(b.Number, Is.EqualTo(0.5f).Within(0.001f)); - Assert.That(b.Absolute, Is.False); + Anchor.Number b = "50%"; + Assert.That(b.Value, Is.EqualTo(0.5f).Within(0.001f)); + Assert.That(b.IsAbsolute, Is.False); - Anchor.value c = "-25%"; - Assert.That(c.Number, Is.EqualTo(-0.25f).Within(0.001f)); - Assert.That(c.Absolute, Is.False); + Anchor.Number c = "-25%"; + Assert.That(c.Value, Is.EqualTo(-0.25f).Within(0.001f)); + Assert.That(c.IsAbsolute, Is.False); - Anchor.value d = "0"; - Assert.That(d.Number, Is.EqualTo(0f).Within(0.001f)); - Assert.That(d.Absolute, Is.True); + Anchor.Number d = "0"; + Assert.That(d.Value, Is.EqualTo(0f).Within(0.001f)); + Assert.That(d.IsAbsolute, Is.True); } } } diff --git a/tests/LocalToWorldTests.cs b/tests/LocalToWorldTests.cs index d86ba79..357cbce 100644 --- a/tests/LocalToWorldTests.cs +++ b/tests/LocalToWorldTests.cs @@ -158,17 +158,5 @@ public void LocalPositionFromWorld() Assert.That(desiredLocalPosition.Y, Is.EqualTo(-0.6666f).Within(0.1f)); Assert.That(desiredLocalPosition.Z, Is.EqualTo(-1f).Within(0.1f)); } - - [Test] - public void ConvertEulerToRotation() - { - EulerAngles euler = EulerAngles.CreateFromDegrees(0f, 90f, 0f); - Quaternion a = Quaternion.CreateFromYawPitchRoll(euler.value.Y, euler.value.X, euler.value.Z); - Quaternion b = euler.AsQuaternion(); - Assert.That(a.X, Is.EqualTo(b.X).Within(0.001f)); - Assert.That(a.Y, Is.EqualTo(b.Y).Within(0.001f)); - Assert.That(a.Z, Is.EqualTo(b.Z).Within(0.001f)); - Assert.That(a.W, Is.EqualTo(b.W).Within(0.001f)); - } } } \ No newline at end of file From 6a66ee7d61a277ee61522cf66396cac5a1ddd08c Mon Sep 17 00:00:00 2001 From: Phill Date: Thu, 1 May 2025 21:16:22 -0400 Subject: [PATCH 2/5] replace complicated anchor values with simpler ones --- source/Components/Anchor.cs | 333 ++++++++++-------------------------- source/Transform.cs | 31 ++-- source/Transforms.csproj | 4 +- tests/AnchorTypeTests.cs | 61 +------ 4 files changed, 108 insertions(+), 321 deletions(-) diff --git a/source/Components/Anchor.cs b/source/Components/Anchor.cs index 2495d7c..eefdf6e 100644 --- a/source/Components/Anchor.cs +++ b/source/Components/Anchor.cs @@ -1,6 +1,4 @@ -#pragma warning disable CS8981 -using System; -using System.Diagnostics; +using System; namespace Transforms.Components { @@ -10,40 +8,26 @@ namespace Transforms.Components /// public struct Anchor : IEquatable { - public static readonly Anchor Centered = new(new(0.5f, false), new(0.5f, false), new(0f, false), new(0.5f, false), new(0.5f, false), new(0f, false)); - public static readonly Anchor BottomLeft = new(new(0f, false), new(0f, false), new(0f, false), new(0f, false), new(0f, false), new(0f, false)); - public static readonly Anchor TopRight = new(new(1f, false), new(1f, false), new(0f, false), new(1f, false), new(1f, false), new(0f, false)); - public static readonly Anchor BottomRight = new(new(1f, false), new(0f, false), new(0f, false), new(1f, false), new(0f, false), new(0f, false)); - public static readonly Anchor TopLeft = new(new(0f, false), new(1f, false), new(0f, false), new(0f, false), new(1f, false), new(0f, false)); - public static readonly Anchor Bottom = new(new(0.5f, false), new(0f, false), new(0f, false), new(0.5f, false), new(0f, false), new(0f, false)); - public static readonly Anchor Top = new(new(0.5f, false), new(1f, false), new(0f, false), new(0.5f, false), new(1f, false), new(0f, false)); - public static readonly Anchor Left = new(new(0f, false), new(0.5f, false), new(0f, false), new(0f, false), new(0.5f, false), new(0f, false)); - public static readonly Anchor Right = new(new(1f, false), new(0.5f, false), new(0f, false), new(1f, false), new(0.5f, false), new(0f, false)); + public static readonly Anchor Centered = new(0.5f, 0.5f, 0f, 0.5f, 0.5f, 0f); + public static readonly Anchor BottomLeft = new(0f, 0f, 0f, 0f, 0f, 0f); + public static readonly Anchor TopRight = new(1f, 1f, 0f, 1f, 1f, 0f); + public static readonly Anchor BottomRight = new(1f, 0f, 0f, 1f, 0f, 0f); + public static readonly Anchor TopLeft = new(0f, 1f, 0f, 0f, 1f, 0f); + public static readonly Anchor Bottom = new(0.5f, 0f, 0f, 0.5f, 0f, 0f); + public static readonly Anchor Top = new(0.5f, 1f, 0f, 0.5f, 1f, 0f); + public static readonly Anchor Left = new(0f, 0.5f, 0f, 0f, 0.5f, 0f); + public static readonly Anchor Right = new(1f, 0.5f, 0f, 1f, 0.5f, 0f); public static readonly Anchor Default = default; - public Number minX; - public Number minY; - public Number minZ; - public Number maxX; - public Number maxY; - public Number maxZ; + public float minX; + public float minY; + public float minZ; + public float maxX; + public float maxY; + public float maxZ; + public Relativeness flags; -#if NET - /// - /// Creates a default anchor pointing towards bottom left. - /// - public Anchor() - { - minX = new(0f, false); - minY = new(0f, false); - minZ = new(0f, false); - maxX = new(0f, false); - maxY = new(0f, false); - maxZ = new(0f, false); - } -#endif - - public Anchor(Number minX, Number minY, Number minZ, Number maxX, Number maxY, Number maxZ) + public Anchor(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, Relativeness flags = default) { this.minX = minX; this.minY = minY; @@ -51,250 +35,105 @@ public Anchor(Number minX, Number minY, Number minZ, Number maxX, Number maxY, N this.maxX = maxX; this.maxY = maxY; this.maxZ = maxZ; + this.flags = flags; } - public readonly override bool Equals(object? obj) + public Anchor(ReadOnlySpan minX, ReadOnlySpan minY, ReadOnlySpan minZ, ReadOnlySpan maxX, ReadOnlySpan maxY, ReadOnlySpan maxZ) { - return obj is Anchor anchor && Equals(anchor); - } - - public readonly bool Equals(Anchor other) - { - return minX.Equals(other.minX) && minY.Equals(other.minY) && minZ.Equals(other.minZ) && maxX.Equals(other.maxX) && maxY.Equals(other.maxY) && maxZ.Equals(other.maxZ); - } - - public readonly override int GetHashCode() - { - return HashCode.Combine(minX, minY, minZ, maxX, maxY, maxZ); - } - - public static bool operator ==(Anchor left, Anchor right) - { - return left.Equals(right); - } - - public static bool operator !=(Anchor left, Anchor right) - { - return !(left == right); - } - - public struct Number : IEquatable - { - public const int NumberRange = 65536; - public const int MaxNumberValue = 32768; - public const float Precision = 0.00003051757f; - - private int data; - - public bool IsAbsolute + if (TryParse(minX, out this.minX, out bool relative) && relative) { - readonly get - { - int bitPos = 0; - return (data & (1 << bitPos)) == 0; - } - set - { - if (value) - { - data &= ~1; - } - else - { - data |= 1; - } - } + flags |= Relativeness.MinX; } - public float Value + if (TryParse(minY, out this.minY, out relative) && relative) { - readonly get - { - int bitPos = 0; - int numberInt = data & ~(1 << bitPos); - return (numberInt << 1) / (float)NumberRange; - } - set - { - bool absolute = IsAbsolute; - int valueInt = (int)(value * NumberRange) >> 1; - data = valueInt; - if (absolute) - { - data &= ~1; - } - else - { - data |= 1; - } - } + flags |= Relativeness.MinY; } - public Number(float value, bool absolute) + if (TryParse(minZ, out this.minZ, out relative) && relative) { - ThrowIfOutOfRange(value); - - data = (int)(value * NumberRange) >> 1; - if (absolute) - { - data &= ~1; - } - else - { - data |= 1; - } + flags |= Relativeness.MinZ; } - public Number(ReadOnlySpan text) + if (TryParse(maxX, out this.maxX, out relative) && relative) { - bool negative = false; - int index = 0; - int startIndex = 0; - bool foundNumber = false; - bool absolute = true; - int endIndex = 0; - while (index < text.Length) - { - char c = text[index]; - if (c == '-') - { - negative = true; - } - else if (c == '.' || char.IsDigit(c)) - { - if (!foundNumber) - { - startIndex = index; - } - - foundNumber = true; - if (index == text.Length - 1) - { - endIndex = index + 1; - break; - } - } - else - { - endIndex = index; - - if (c == '%') - { - absolute = false; - break; - } - } - - index++; - } - - if (!foundNumber) - { - throw new FormatException($"No number found in text input `{text.ToString()}`"); - } - - float number = float.Parse(text.Slice(startIndex, endIndex - startIndex)); - if (negative) - { - number = -number; - } - - if (absolute) - { - data &= ~1; - } - else - { - data |= 1; - } - - if (absolute) - { - Value = number; - } - else - { - Value = number / 100f; - } + flags |= Relativeness.MaxX; } - public readonly override string ToString() + if (TryParse(maxY, out this.maxY, out relative) && relative) { - Span buffer = stackalloc char[32]; - int length = ToString(buffer); - return buffer.Slice(0, length).ToString(); + flags |= Relativeness.MaxY; } - public readonly int ToString(Span destination) + if (TryParse(maxZ, out this.maxZ, out relative) && relative) { - bool isRelative = IsAbsolute; - float number = Value; - int length = 0; - if (isRelative) - { - destination[0] = 'r'; - destination[1] = ':'; - length = 2; - } - else - { - destination[0] = 'a'; - destination[1] = ':'; - length = 2; - } - - length += number.ToString(destination.Slice(length)); - return length; + flags |= Relativeness.MaxZ; } + } - public readonly override bool Equals(object? obj) - { - return obj is Number value && Equals(value); - } + public readonly override bool Equals(object? obj) + { + return obj is Anchor anchor && Equals(anchor); + } - public readonly bool Equals(Number other) - { - return data == other.data; - } + public readonly bool Equals(Anchor other) + { + return minX.Equals(other.minX) && minY.Equals(other.minY) && minZ.Equals(other.minZ) && maxX.Equals(other.maxX) && maxY.Equals(other.maxY) && maxZ.Equals(other.maxZ) && flags == other.flags; + } - public readonly override int GetHashCode() - { - return data.GetHashCode(); - } + public readonly override int GetHashCode() + { + return HashCode.Combine(minX, minY, minZ, maxX, maxY, maxZ, flags); + } - public static bool operator ==(Number left, Number right) + public static bool TryParse(ReadOnlySpan text, out float number, out bool relative) + { + if (text.Length > 0) { - return left.Equals(right); - } + if (text[text.Length - 1] == '%') + { + relative = true; + text = text.Slice(0, text.Length - 1); + } + else + { + relative = false; + } - public static bool operator !=(Number left, Number right) - { - return !(left == right); + return float.TryParse(text, out number); } - - public static implicit operator float(Number value) + else { - return value.Value; + number = default; + relative = false; + return false; } + } - public static implicit operator Number(ReadOnlySpan text) - { - return new(text); - } + public static bool operator ==(Anchor left, Anchor right) + { + return left.Equals(right); + } - public static implicit operator Number(string text) - { - return new(text.AsSpan()); - } + public static bool operator !=(Anchor left, Anchor right) + { + return !(left == right); + } - [Conditional("DEBUG")] - private static void ThrowIfOutOfRange(float input) - { - if (input < -MaxNumberValue || input >= MaxNumberValue) - { - throw new ArgumentOutOfRangeException(nameof(input), $"Anchor value must be greater than {-MaxNumberValue} and below {MaxNumberValue}."); - } - } + [Flags] + public enum Relativeness : byte + { + None = 0, + MinX = 1, + MinY = 2, + MinZ = 4, + MaxX = 8, + MaxY = 16, + MaxZ = 32, + X = MinX | MaxX, + Y = MinY | MaxY, + Z = MinZ | MaxZ, + All = MinX | MinY | MinZ | MaxX | MaxY | MaxZ } } -} +} \ No newline at end of file diff --git a/source/Transform.cs b/source/Transform.cs index 9b0f284..b25b79d 100644 --- a/source/Transform.cs +++ b/source/Transform.cs @@ -14,10 +14,11 @@ public readonly ref Vector3 LocalPosition { get { - ref Position component = ref TryGetComponent(out bool contains); + int type = world.Schema.GetComponentType(); + ref Position component = ref TryGetComponent(type, out bool contains); if (!contains) { - component = ref AddComponent(); + component = ref AddComponent(type); component = Position.Default; } @@ -32,10 +33,11 @@ public readonly ref Quaternion LocalRotation { get { - ref Rotation component = ref TryGetComponent(out bool contains); + int type = world.Schema.GetComponentType(); + ref Rotation component = ref TryGetComponent(type, out bool contains); if (!contains) { - component = ref AddComponent(); + component = ref AddComponent(type); component = Rotation.Default; } @@ -50,10 +52,11 @@ public readonly ref Anchor Anchor { get { - ref Anchor component = ref TryGetComponent(out bool contains); + int type = world.Schema.GetComponentType(); + ref Anchor component = ref TryGetComponent(type, out bool contains); if (!contains) { - component = ref AddComponent(); + component = ref AddComponent(type); component = Anchor.Default; } @@ -64,18 +67,19 @@ public readonly ref Anchor Anchor /// /// The pivot of this entity relative to the parent entity. /// - public readonly ref Pivot Pivot + public readonly ref Vector3 Pivot { get { - ref Pivot component = ref TryGetComponent(out bool contains); + int type = world.Schema.GetComponentType(); + ref Pivot component = ref TryGetComponent(type, out bool contains); if (!contains) { - component = ref AddComponent(); - component = Pivot.Default; + component = ref AddComponent(type); + component = Components.Pivot.Default; } - return ref component; + return ref component.value; } } @@ -86,10 +90,11 @@ public readonly ref Vector3 LocalScale { get { - ref Scale component = ref TryGetComponent(out bool contains); + int type = world.Schema.GetComponentType(); + ref Scale component = ref TryGetComponent(type, out bool contains); if (!contains) { - component = ref AddComponent(); + component = ref AddComponent(type); component = Scale.Default; } diff --git a/source/Transforms.csproj b/source/Transforms.csproj index d3a4b03..44477b0 100644 --- a/source/Transforms.csproj +++ b/source/Transforms.csproj @@ -11,11 +11,11 @@ popcron simulation-tree https://github.com/simulation-tree/transforms - + - + Analyzer false diff --git a/tests/AnchorTypeTests.cs b/tests/AnchorTypeTests.cs index 9c1a77d..c54f7ef 100644 --- a/tests/AnchorTypeTests.cs +++ b/tests/AnchorTypeTests.cs @@ -1,63 +1,6 @@ -using Transforms.Components; -using Unmanaged; - -namespace Transforms.Tests +namespace Transforms.Tests { public class AnchorTypeTests { - [Test] - public void CheckAnchorDataType() - { - Anchor.Number left = new(0.92123f, true); - Assert.That(left.IsAbsolute, Is.True); - Assert.That(left.Value, Is.EqualTo(0.92123f).Within(0.1f)); - - Anchor.Number right = new(456f, false); - Assert.That(right.IsAbsolute, Is.False); - Assert.That(right.Value, Is.EqualTo(456f).Within(0.1f)); - - Assert.That(left, Is.Not.EqualTo(right)); - Anchor.Number up = new(0.5f, true); - Assert.That(up, Is.Not.EqualTo(left)); - Assert.That(up.IsAbsolute, Is.True); - Assert.That(up.Value, Is.EqualTo(0.5f).Within(0.1f)); - - Anchor.Number down = new(-3.1412f, false); - Assert.That(down, Is.Not.EqualTo(right)); - Assert.That(down.IsAbsolute, Is.False); - Assert.That(down.Value, Is.EqualTo(-3.1412f).Within(0.1f)); - - using RandomGenerator rng = new(); - for (uint i = 0; i < 1024; i++) - { - float number = rng.NextFloat(-1000f, 1000f); - bool isNormalized = rng.NextBool(); - Anchor.Number value = new(number, isNormalized); - value.Value *= 2; - value.IsAbsolute = !value.IsAbsolute; - Assert.That(value.Value, Is.EqualTo(number * 2).Within(0.1f)); - Assert.That(value.IsAbsolute, Is.EqualTo(!isNormalized)); - } - } - - [Test] - public void BuildAnchorValuesFromText() - { - Anchor.Number a = "0.5f"; - Assert.That(a.Value, Is.EqualTo(0.5f).Within(0.001f)); - Assert.That(a.IsAbsolute, Is.True); - - Anchor.Number b = "50%"; - Assert.That(b.Value, Is.EqualTo(0.5f).Within(0.001f)); - Assert.That(b.IsAbsolute, Is.False); - - Anchor.Number c = "-25%"; - Assert.That(c.Value, Is.EqualTo(-0.25f).Within(0.001f)); - Assert.That(c.IsAbsolute, Is.False); - - Anchor.Number d = "0"; - Assert.That(d.Value, Is.EqualTo(0f).Within(0.001f)); - Assert.That(d.IsAbsolute, Is.True); - } } -} +} \ No newline at end of file From d7d62e435cef752c5343b96edadc1dae7d5eecff Mon Sep 17 00:00:00 2001 From: Phill Date: Thu, 1 May 2025 21:34:19 -0400 Subject: [PATCH 3/5] update readme --- README.md | 55 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index b88ec9b..0203fa0 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,50 @@ # Transforms -Calculates 3D transformations for objects within a hierarchy. -### Dependencies -* [Simulation](https://github.com/simulation-tree/simulation) +For representing a hierarchy of objects in 3D space. ### Behaviour -Entities with an `IsTransform` component will have a `LocalToWorld` component built -using data from these components (relative to the parent entity), whenever the `TransformUpdate` event -is polled: + +Entities with the `IsTransform` tag will have a `LocalToWorld` component calculated +using data from these components, relative to the parent: * `Position` * `Rotation` * `Scale` +* `Anchor` +* `Pivot` + +### Anchoring to corners -### Example +The `Anchor` component is able to describe both relative and absolute values. The example +below makes the child transform have a 10 pixel border inside the parent: ```cs -eint parentObj = world.CreateEntity(); -world.AddComponent(parentObj, new IsTransform()); -world.AddComponent(parentObj, new Scale(2, 2, 2)); +Transform parent = new(world); +parent.LocalScale = new(100, 100, 0); +parent.LocalPosition = new(50, 50, 0); -eint obj = world.CreateEntity(parentObj); -world.AddComponent(obj, new IsTransform()); -world.AddComponent(obj, new Position(0, 5, 0)); +Transform child = new(world); +child.Anchor = new(10, 10, 0, 10, 10, 0, Anchor.Relativeness.X | Anchor.Relativeness.Y); + +//after simulating, child will be at position (60, 60) with size (80, 80) +``` -world.Submit(new TransformUpdate()); -world.Poll(); +### Reading world state -LocalToWorld ltw = world.GetComponent(obj)); -Vector3 worldPosition = ltw.Position; -Matrix4x4 matrix = ltw.value; +Accessing world position, rotation or scale is can be done through properties of a transform +entity: +```cs +Transform a = ... +Vector3 position = a.WorldPosition; +Quaternion rotation = a.WorldRotation; +Vector3 scale = a.WorldScale; ``` + +And optionally, can be accessed directly through components. However, accessing +the world rotation is not possible through the `LocalToWorld` component and must +be done through `WorldRotation`: +```cs +uint a = ... +LocalToWorld ltw = world.GetComponent(a); +Vector3 position = ltw.Position; +Vector3 scale = ltw.Scale; +Quaternion rotation = world.GetComponent(a).value; +``` \ No newline at end of file From 6096ad35cfcf80f95e3332e1b69cc5872713c960 Mon Sep 17 00:00:00 2001 From: Phill Date: Fri, 2 May 2025 00:44:33 -0400 Subject: [PATCH 4/5] add missing xml docs --- README.md | 7 ++ source/Components/Anchor.cs | 126 +++++++++++++++++++++++++++++ source/Components/IsTransform.cs | 4 +- source/Components/LocalToWorld.cs | 74 +++++++++++++++-- source/Components/Pivot.cs | 35 ++++++++ source/Components/Position.cs | 25 +++++- source/Components/Rotation.cs | 23 ++++++ source/Components/Scale.cs | 30 ++++++- source/Components/WorldRotation.cs | 15 ++++ source/Transform.cs | 47 +++++++++++ source/Transforms.csproj | 10 ++- 11 files changed, 383 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0203fa0..c1ff717 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,13 @@ using data from these components, relative to the parent: * `Anchor` * `Pivot` +### Axis convention + +This is only relevant for rotations when working with them manually: +* X axis is right (pitch) +* Y axis is up (yaw) +* Z axis is forward (roll) + ### Anchoring to corners The `Anchor` component is able to describe both relative and absolute values. The example diff --git a/source/Components/Anchor.cs b/source/Components/Anchor.cs index eefdf6e..d6a71c4 100644 --- a/source/Components/Anchor.cs +++ b/source/Components/Anchor.cs @@ -8,25 +8,94 @@ namespace Transforms.Components /// public struct Anchor : IEquatable { + /// + /// Centers the transform on the X and Y axes. + /// public static readonly Anchor Centered = new(0.5f, 0.5f, 0f, 0.5f, 0.5f, 0f); + + /// + /// Anchors the transform to the bottom left (also the ). + /// public static readonly Anchor BottomLeft = new(0f, 0f, 0f, 0f, 0f, 0f); + + /// + /// Anchors the transform to the top right. + /// public static readonly Anchor TopRight = new(1f, 1f, 0f, 1f, 1f, 0f); + + /// + /// Anchors the transform to the bottom right. + /// public static readonly Anchor BottomRight = new(1f, 0f, 0f, 1f, 0f, 0f); + + /// + /// Anchors the transform to the top left. + /// public static readonly Anchor TopLeft = new(0f, 1f, 0f, 0f, 1f, 0f); + + /// + /// Anchors the transform to the center bottom. + /// public static readonly Anchor Bottom = new(0.5f, 0f, 0f, 0.5f, 0f, 0f); + + /// + /// Anchors the transform to the center top. + /// public static readonly Anchor Top = new(0.5f, 1f, 0f, 0.5f, 1f, 0f); + + /// + /// Anchors the transform to the left middle. + /// public static readonly Anchor Left = new(0f, 0.5f, 0f, 0f, 0.5f, 0f); + + /// + /// Anchors the transform to the right middle. + /// public static readonly Anchor Right = new(1f, 0.5f, 0f, 1f, 0.5f, 0f); + + /// + /// Default value. + /// public static readonly Anchor Default = default; + /// + /// Minimum X anchor value. + /// public float minX; + + /// + /// Minimum Y anchor value. + /// public float minY; + + /// + /// Minimum Z anchor value. + /// public float minZ; + + /// + /// Maximum X anchor value. + /// public float maxX; + + /// + /// Maximum Y anchor value. + /// public float maxY; + + /// + /// Maximum Z anchor value. + /// public float maxZ; + + /// + /// Flags defining which anchor values are relative. + /// public Relativeness flags; + /// + /// Creates an instance of the anchor component. + /// public Anchor(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, Relativeness flags = default) { this.minX = minX; @@ -38,6 +107,9 @@ public Anchor(float minX, float minY, float minZ, float maxX, float maxY, float this.flags = flags; } + /// + /// Creates an instance of the anchor component from the parsed values. + /// public Anchor(ReadOnlySpan minX, ReadOnlySpan minY, ReadOnlySpan minZ, ReadOnlySpan maxX, ReadOnlySpan maxY, ReadOnlySpan maxZ) { if (TryParse(minX, out this.minX, out bool relative) && relative) @@ -71,21 +143,27 @@ public Anchor(ReadOnlySpan minX, ReadOnlySpan minY, ReadOnlySpan public readonly override bool Equals(object? obj) { return obj is Anchor anchor && Equals(anchor); } + /// public readonly bool Equals(Anchor other) { return minX.Equals(other.minX) && minY.Equals(other.minY) && minZ.Equals(other.minZ) && maxX.Equals(other.maxX) && maxY.Equals(other.maxY) && maxZ.Equals(other.maxZ) && flags == other.flags; } + /// public readonly override int GetHashCode() { return HashCode.Combine(minX, minY, minZ, maxX, maxY, maxZ, flags); } + /// + /// Tries to parse the given as a single anchor number. + /// public static bool TryParse(ReadOnlySpan text, out float number, out bool relative) { if (text.Length > 0) @@ -110,29 +188,77 @@ public static bool TryParse(ReadOnlySpan text, out float number, out bool } } + /// public static bool operator ==(Anchor left, Anchor right) { return left.Equals(right); } + /// public static bool operator !=(Anchor left, Anchor right) { return !(left == right); } + /// + /// Settings for describing which anchor numbers are relative to the parent bounds. + /// [Flags] public enum Relativeness : byte { + /// + /// No values are relative to the parent. + /// None = 0, + + /// + /// The minimum X number is relative to the parent's left edge. + /// MinX = 1, + + /// + /// The minimum Y number is relative to the parent's bottom edge. + /// MinY = 2, + + /// + /// The minimum Z number is relative to the parent's back edge. + /// MinZ = 4, + + /// + /// The maximum X number is relative to the parent's right edge. + /// MaxX = 8, + + /// + /// The maximum Y number is relative to the parent's top edge. + /// MaxY = 16, + + /// + /// The maximum Z number is relative to the parent's front edge. + /// MaxZ = 32, + + /// + /// Both minimum and maximum X numbers are relative to the parent's left and right edges. + /// X = MinX | MaxX, + + /// + /// Both minimum and maximum Y numbers are relative to the parent's bottom and top edges. + /// Y = MinY | MaxY, + + /// + /// Both minimum and maximum Z numbers are relative to the parent's back and front edges. + /// Z = MinZ | MaxZ, + + /// + /// All minimum and maximum numbers are relative to the parent's edges. + /// All = MinX | MinY | MinZ | MaxX | MaxY | MaxZ } } diff --git a/source/Components/IsTransform.cs b/source/Components/IsTransform.cs index 21bdc09..de9de36 100644 --- a/source/Components/IsTransform.cs +++ b/source/Components/IsTransform.cs @@ -1,7 +1,9 @@ namespace Transforms.Components { + /// + /// Tag type to identify entities that are transforms. + /// public struct IsTransform { - } } \ No newline at end of file diff --git a/source/Components/LocalToWorld.cs b/source/Components/LocalToWorld.cs index 113afea..a1ccc8a 100644 --- a/source/Components/LocalToWorld.cs +++ b/source/Components/LocalToWorld.cs @@ -3,22 +3,48 @@ namespace Transforms.Components { + /// + /// Calculated for transforming local space to world space. + /// public struct LocalToWorld : IEquatable { + /// + /// Default state of this component. + /// public static readonly LocalToWorld Default = new(Components.Position.Default.value, Components.Rotation.Default.value, Components.Scale.Default.value); + /// + /// The matrix value. + /// public Matrix4x4 value; + /// + /// Decomposed position of the matrix value. + /// public Vector3 Position { readonly get => value.Translation; set => this.value.Translation = value; } + /// + /// Vector referring to the right direction of the matrix value. + /// public readonly Vector3 Right => Vector3.Normalize(new(value.M11, value.M12, value.M13)); + + /// + /// Vector referring to the up direction of the matrix value. + /// public readonly Vector3 Up => Vector3.Normalize(new(value.M21, value.M22, value.M23)); + + /// + /// Vector referring to the forward direction of the matrix value. + /// public readonly Vector3 Forward => Vector3.Normalize(new(value.M31, value.M32, value.M33)); + /// + /// Decomposed rotation of the matrix value. + /// public readonly Quaternion Rotation { get @@ -28,6 +54,9 @@ public readonly Quaternion Rotation } } + /// + /// Decomposed scale of the matrix value. + /// public readonly Vector3 Scale { get @@ -37,6 +66,9 @@ public readonly Vector3 Scale } } + /// + /// Decomposed state of this component. + /// public readonly (Vector3 position, Quaternion rotation, Vector3 scale) Decomposed { get @@ -47,64 +79,90 @@ public readonly (Vector3 position, Quaternion rotation, Vector3 scale) Decompose } #if NET + /// + /// Creates a default component. + /// public LocalToWorld() { value = Default.value; } #endif + /// + /// Initializes a new component from the given . + /// public LocalToWorld(Matrix4x4 value) { this.value = value; } + /// + /// Creates a new component from the given , , and . + /// public LocalToWorld(Vector3 position, Quaternion rotation, Vector3 scale) { value = Matrix4x4.CreateScale(scale) * Matrix4x4.CreateFromQuaternion(rotation) * Matrix4x4.CreateTranslation(position); } + /// public readonly override bool Equals(object? obj) { return obj is LocalToWorld world && Equals(world); } + /// public readonly bool Equals(LocalToWorld other) { return value.Equals(other.value); } + /// public readonly override int GetHashCode() { return HashCode.Combine(value); } - public readonly Vector3 TransformInverse(Vector3 position) + /// + /// Transforms the given to local space. + /// + public readonly Vector3 TransformInverse(Vector3 worldPosition) { Matrix4x4.Invert(value, out Matrix4x4 invValue); - return Vector3.Transform(position, invValue); + return Vector3.Transform(worldPosition, invValue); } - public readonly Vector3 Transform(Vector3 position) + /// + /// Transforms the given to world space. + /// + public readonly Vector3 Transform(Vector3 localPosition) { - return Vector3.Transform(position, value); + return Vector3.Transform(localPosition, value); } - public readonly Quaternion TransformInverse(Quaternion rotation) + /// + /// Transforms the given into local space. + /// + public readonly Quaternion TransformInverse(Quaternion worldRotation) { Matrix4x4.Invert(value, out Matrix4x4 invValue); - return Quaternion.Normalize(Quaternion.CreateFromRotationMatrix(invValue) * rotation); + return Quaternion.Normalize(Quaternion.CreateFromRotationMatrix(invValue) * worldRotation); } - public readonly Quaternion Transform(Quaternion rotation) + /// + /// Transforms the given into world space. + /// + public readonly Quaternion Transform(Quaternion localRotation) { - return Quaternion.Normalize(Quaternion.CreateFromRotationMatrix(value) * rotation); + return Quaternion.Normalize(Quaternion.CreateFromRotationMatrix(value) * localRotation); } + /// public static bool operator ==(LocalToWorld left, LocalToWorld right) { return left.Equals(right); } + /// public static bool operator !=(LocalToWorld left, LocalToWorld right) { return !(left == right); diff --git a/source/Components/Pivot.cs b/source/Components/Pivot.cs index 19904b1..b6babe1 100644 --- a/source/Components/Pivot.cs +++ b/source/Components/Pivot.cs @@ -2,22 +2,57 @@ namespace Transforms.Components { + /// + /// Implies that the final position of this entity is affected by its scale. + /// public struct Pivot { + /// + /// Offsets the entity by half of its scale. + /// public static readonly Pivot Centered = new(0.5f, 0.5f, 0.5f); + + /// + /// Offsets the entity to the right by its width. + /// public static readonly Pivot BottomRight = new(1f, 0f, 0f); + + /// + /// Applies no offset to the entity (same as ). + /// public static readonly Pivot BottomLeft = new(0f, 0f, 0f); + + /// + /// Offsets the entity to the right by its width, and up by its height. + /// public static readonly Pivot TopRight = new(1f, 1f, 0f); + + /// + /// Offsets the entity up by its height. + /// public static readonly Pivot TopLeft = new(0f, 1f, 0f); + + /// + /// The default state. + /// public static readonly Pivot Default = default; + /// + /// The pivot value. + /// public Vector3 value; + /// + /// Creates a new component. + /// public Pivot(float x, float y, float z = default) { value = new Vector3(x, y, z); } + /// + /// Initializes the component with the given . + /// public Pivot(Vector3 value) { this.value = value; diff --git a/source/Components/Position.cs b/source/Components/Position.cs index b899c64..854dbff 100644 --- a/source/Components/Position.cs +++ b/source/Components/Position.cs @@ -3,39 +3,62 @@ namespace Transforms.Components { + /// + /// Describes the position of the entity relative to its parent. + /// public struct Position { + /// + /// The value. + /// public static readonly Position Default = new(Vector3.Zero); + /// + /// The value. + /// public Vector3 value; + /// + /// Initializes the component with the given . + /// public Position(Vector2 value, float z = 0f) { this.value = new Vector3(value, z); } + /// + /// Initializes the component with the given . + /// public Position(Vector3 value) { this.value = value; } + /// + /// Initializes the component with the given and . + /// public Position(float x, float y) { value = new Vector3(x, y, Default.value.Z); } + /// + /// Initializes the component with the given , , and . + /// public Position(float x, float y, float z) { value = new Vector3(x, y, z); } - public unsafe readonly override string ToString() + /// + public readonly override string ToString() { Span buffer = stackalloc char[32]; int length = ToString(buffer); return buffer.Slice(0, length).ToString(); } + /// public readonly int ToString(Span destination) { return value.ToString(destination); diff --git a/source/Components/Rotation.cs b/source/Components/Rotation.cs index 5716080..ddbeca5 100644 --- a/source/Components/Rotation.cs +++ b/source/Components/Rotation.cs @@ -3,29 +3,48 @@ namespace Transforms.Components { + /// + /// Describes the rotation of the entity relative to its parent. + /// public struct Rotation { + /// + /// The intended state of this component. + /// public static readonly Rotation Default = new(Quaternion.Identity); + /// + /// The value. + /// public Quaternion value; #if NET + /// + /// Creates a default state of this component. + /// public Rotation() { value = Quaternion.Identity; } #endif + /// + /// Initializes the component with the given . + /// public Rotation(Quaternion value) { this.value = value; } + /// + /// Initializes the component with the given , , , and . + /// public Rotation(float x, float y, float z, float w) { value = new Quaternion(x, y, z, w); } + /// public readonly override string ToString() { Span buffer = stackalloc char[32]; @@ -33,11 +52,15 @@ public readonly override string ToString() return buffer.Slice(0, length).ToString(); } + /// public readonly int ToString(Span destination) { return value.ToString(destination); } + /// + /// Builds a new component from the given . + /// public static Rotation FromDirection(Vector3 forwardDirection) { Vector3 identity = Vector3.UnitZ; diff --git a/source/Components/Scale.cs b/source/Components/Scale.cs index 41a70c2..f762aa0 100644 --- a/source/Components/Scale.cs +++ b/source/Components/Scale.cs @@ -3,46 +3,72 @@ namespace Transforms.Components { + /// + /// Describes the scale of the entity relative to its parent. + /// public struct Scale { + /// + /// The intended state of the component. + /// public static readonly Scale Default = new(Vector3.One); + /// + /// The value. + /// public Vector3 value; #if NET + /// + /// Creates a new default component. + /// public Scale() { - value = Vector3.One; + value = Default.value; } #endif + /// + /// Creates a new scale component from the given . + /// public Scale(Vector2 value, float z = 1f) { this.value = new(value, z); } + /// + /// Creates a new scale component from the given . + /// public Scale(Vector3 value) { this.value = value; } + /// + /// Creates a new scale component from the given and . + /// public Scale(float x, float y) { value = new Vector3(x, y, Default.value.Z); } + /// + /// Creates a new scale component from the given , , and . + /// public Scale(float x, float y, float z) { value = new Vector3(x, y, z); } - public unsafe readonly override string ToString() + /// + public readonly override string ToString() { Span buffer = stackalloc char[32]; int length = ToString(buffer); return buffer.Slice(0, length).ToString(); } + /// public readonly int ToString(Span destination) { return value.ToString(destination); diff --git a/source/Components/WorldRotation.cs b/source/Components/WorldRotation.cs index 3af8804..ece767d 100644 --- a/source/Components/WorldRotation.cs +++ b/source/Components/WorldRotation.cs @@ -2,19 +2,34 @@ namespace Transforms.Components { + /// + /// Describes the calculated and final rotation of the entity. + /// public struct WorldRotation { + /// + /// The intended state of this component. + /// public static readonly WorldRotation Default = new(Quaternion.Identity); + /// + /// The value. + /// public Quaternion value; #if NET + /// + /// Creates a default state of this component. + /// public WorldRotation() { value = Default.value; } #endif + /// + /// Creates a new component from the given . + /// public WorldRotation(Quaternion value) { this.value = value; diff --git a/source/Transform.cs b/source/Transform.cs index b25b79d..77d592f 100644 --- a/source/Transform.cs +++ b/source/Transform.cs @@ -102,17 +102,59 @@ public readonly ref Vector3 LocalScale } } + /// + /// Vector pointing to the right of this entity relative to the parent entity. + /// public readonly Vector3 LocalRight => Vector3.Transform(Vector3.UnitX, LocalRotation); + + /// + /// Vector pointing up of this entity relative to the parent entity. + /// public readonly Vector3 LocalUp => Vector3.Transform(Vector3.UnitY, LocalRotation); + + /// + /// Vector pointing forward of this entity relative to the parent entity. + /// public readonly Vector3 LocalForward => Vector3.Transform(Vector3.UnitZ, LocalRotation); + + /// + /// Position of this entity in world space. + /// public readonly Vector3 WorldPosition => GetComponent().Position; + + /// + /// Rotation of this entity in world space. + /// public readonly Quaternion WorldRotation => GetComponent().value; + + /// + /// Scale of this entity in world space. + /// public readonly Vector3 WorldScale => GetComponent().Scale; + + /// + /// Vector pointing to the right of this entity in world space. + /// public readonly Vector3 WorldRight => Vector3.Transform(Vector3.UnitX, WorldRotation); + + /// + /// Vector pointing up of this entity in world space. + /// public readonly Vector3 WorldUp => Vector3.Transform(Vector3.UnitY, WorldRotation); + + /// + /// Vector pointing forward of this entity in world space. + /// public readonly Vector3 WorldForward => Vector3.Transform(Vector3.UnitZ, WorldRotation); + + /// + /// The final calculated matrix for transforming the local components of this entity to world space. + /// public readonly LocalToWorld LocalToWorld => GetComponent(); + /// + /// Creates a new transform entity. + /// public Transform(World world) { this.world = world; @@ -120,6 +162,9 @@ public Transform(World world) AddTag(); } + /// + /// Creates a new transform entity with the given , , and . + /// public Transform(World world, Vector3 position, Quaternion rotation, Vector3 scale) { this.world = world; @@ -133,6 +178,7 @@ readonly void IEntity.Describe(ref Archetype archetype) archetype.AddTagType(); } + /// public readonly override string ToString() { Span buffer = stackalloc char[64]; @@ -140,6 +186,7 @@ public readonly override string ToString() return buffer.Slice(0, length).ToString(); } + /// public readonly int ToString(Span buffer) { return value.ToString(buffer); diff --git a/source/Transforms.csproj b/source/Transforms.csproj index 44477b0..d0b1a18 100644 --- a/source/Transforms.csproj +++ b/source/Transforms.csproj @@ -4,7 +4,6 @@ net9.0 disable enable - true True True Transforms @@ -12,8 +11,17 @@ simulation-tree https://github.com/simulation-tree/transforms + True + README.md + + + True + \ + + + From 724a255b0b8a78d2a54535a14fd4fad6a8c5b6c3 Mon Sep 17 00:00:00 2001 From: Phill Date: Sat, 3 May 2025 12:29:37 -0400 Subject: [PATCH 5/5] Update Transform.cs --- source/Transform.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/Transform.cs b/source/Transform.cs index 77d592f..57505a1 100644 --- a/source/Transform.cs +++ b/source/Transform.cs @@ -5,6 +5,9 @@ namespace Transforms { + /// + /// Represents an entity that can be transformed in 3D space. + /// public readonly partial struct Transform : IEntity { ///