diff --git a/src/GameCult.Caching.MessagePack/CultMathJson.cs b/src/GameCult.Caching.MessagePack/CultMathJson.cs index 438c6150..0e65bf22 100644 --- a/src/GameCult.Caching.MessagePack/CultMathJson.cs +++ b/src/GameCult.Caching.MessagePack/CultMathJson.cs @@ -14,7 +14,7 @@ namespace GameCult.Caching.MessagePack; /// The canonical System.Text.Json shape of every public CultMath value type, the JSON twin of /// . Vectors, quaternions and colors are objects keyed by their /// field names ({"x":1,"y":2}), matrices are arrays of row objects, rect is -/// {"min":..,"max":..}, and CultCellular is {"nearest":..,"edge":..,"id":..}. +/// {"min":..,"max":..}, CultCellular is {"nearest":..,"edge":..,"id":..}, and CultPhasor is {"cos":..,"sin":..}. /// Property names are fixed: PropertyNamingPolicy does not rename them, and /// PropertyNameCaseInsensitive makes reading case-insensitive. /// @@ -481,7 +481,7 @@ public static class CultMathJson Add(UIntScalar.Instance, new Fields(("state", Val())), a => new Random { state = a[0] }, (v, a) => a[0] = v.state), - // Compositions: matrices are arrays of row objects, rect is {min, max}, CultCellular is {nearest, edge, id}. + // Compositions: matrices are arrays of row objects, rect is {min, max}, CultCellular is {nearest, edge, id}, CultPhasor is {cos, sin}. Add(f, new Rows(2, Xy()), a => new float2x2(a[0], a[1], a[2], a[3]), (v, a) => { a[0] = v[0].x; a[1] = v[0].y; a[2] = v[1].x; a[3] = v[1].y; }), @@ -507,6 +507,13 @@ public static class CultMathJson a[4] = v.edge.x; a[5] = v.edge.y; a[6] = v.edge.z; a[7] = v.edge.w; a[8] = v.id; }), + Add(f, new Fields(("cos", Xyzw()), ("sin", Xyzw())), + a => new CultPhasor(new float4(a[0], a[1], a[2], a[3]), new float4(a[4], a[5], a[6], a[7])), + (v, a) => + { + a[0] = v.cos.x; a[1] = v.cos.y; a[2] = v.cos.z; a[3] = v.cos.w; + a[4] = v.sin.x; a[5] = v.sin.y; a[6] = v.sin.z; a[7] = v.sin.w; + }), }; var map = new Dictionary(); diff --git a/src/GameCult.Caching.MessagePack/CultMathResolver.cs b/src/GameCult.Caching.MessagePack/CultMathResolver.cs index 803b3873..8383a464 100644 --- a/src/GameCult.Caching.MessagePack/CultMathResolver.cs +++ b/src/GameCult.Caching.MessagePack/CultMathResolver.cs @@ -180,7 +180,7 @@ public sealed class CultMathResolver : IFormatterResolver return value; }), - // Compositions: matrices are rows, rect is [min, max], CultCellular is [nearest, edge, id]. + // Compositions: matrices are rows, rect is [min, max], CultCellular is [nearest, edge, id], CultPhasor is [cos, sin]. Shape((ref MessagePackWriter w, float2x2 v) => { w.WriteArrayHeader(2); PutFloat2(ref w, v[0]); PutFloat2(ref w, v[1]); }, (ref MessagePackReader r) => { @@ -221,6 +221,21 @@ public sealed class CultMathResolver : IFormatterResolver } return value; }), + Shape((ref MessagePackWriter w, CultPhasor v) => { w.WriteArrayHeader(2); PutFloat4(ref w, v.cos); PutFloat4(ref w, v.sin); }, + (ref MessagePackReader r) => + { + var value = default(CultPhasor); + for (int i = 0, n = r.ReadArrayHeader(); i < n; i++) + { + switch (i) + { + case 0: value.cos = GetFloat4(ref r); break; + case 1: value.sin = GetFloat4(ref r); break; + default: r.Skip(); break; + } + } + return value; + }), }; var map = new Dictionary(); diff --git a/src/GameCult.Caching.MessagePack/README.md b/src/GameCult.Caching.MessagePack/README.md index fdf91ab2..ccd8f568 100644 --- a/src/GameCult.Caching.MessagePack/README.md +++ b/src/GameCult.Caching.MessagePack/README.md @@ -93,6 +93,7 @@ registered ahead of these wins. | `float2x2`, `float3x3` | array of row vectors (row-major) | array of row objects | | `rect` | `[min, max]` of `float2` | `{"min":{..},"max":{..}}` | | `CultCellular` | `[nearest, edge, id]` | `{"nearest":{..},"edge":{..},"id":..}` | +| `CultPhasor` | `[cos, sin]` of `float4` | `{"cos":{..},"sin":{..}}` | Floats are MessagePack float32 (`0xCA`), doubles float64 (`0xCB`), integers the shortest MessagePack integer. diff --git a/tests/GameCult.Caching.Tests/CultMathJsonTests.cs b/tests/GameCult.Caching.Tests/CultMathJsonTests.cs index 87e5b742..90d739be 100644 --- a/tests/GameCult.Caching.Tests/CultMathJsonTests.cs +++ b/tests/GameCult.Caching.Tests/CultMathJsonTests.cs @@ -43,6 +43,8 @@ namespace GameCult.Caching.Tests Json(new rect(5f, 7f, -1f, -2f)).Should().Be("""{"min":{"x":-1,"y":-2},"max":{"x":5,"y":7}}"""); Json(new CultCellular(new float4(1f, 2f, 3f, 4f), new float4(5f, 6f, 7f, 8f), 0.25f)).Should().Be( """{"nearest":{"x":1,"y":2,"z":3,"w":4},"edge":{"x":5,"y":6,"z":7,"w":8},"id":0.25}"""); + Json(new CultPhasor(new float4(1f, 2f, 3f, 4f), new float4(5f, 6f, 7f, 8f))).Should().Be( + """{"cos":{"x":1,"y":2,"z":3,"w":4},"sin":{"x":5,"y":6,"z":7,"w":8}}"""); } [Test] @@ -66,6 +68,7 @@ namespace GameCult.Caching.Tests RoundTrip(new float3x3(1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f)); RoundTrip(new rect(-1f, -2f, 5f, 7f)); RoundTrip(new CultCellular(new float4(1, 2, 3, 4), new float4(5, 6, 7, 8), 0.25f)); + RoundTrip(new CultPhasor(new float4(1, 2, 3, 4), new float4(5, 6, 7, 8))); } [Test] diff --git a/tests/GameCult.Caching.Tests/CultMathSerializationTests.cs b/tests/GameCult.Caching.Tests/CultMathSerializationTests.cs index 32531679..98f126af 100644 --- a/tests/GameCult.Caching.Tests/CultMathSerializationTests.cs +++ b/tests/GameCult.Caching.Tests/CultMathSerializationTests.cs @@ -101,6 +101,7 @@ namespace GameCult.Caching.Tests RoundTrip(new float3x3(1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f)); RoundTrip(new rect(-1f, -2f, 5f, 7f)); RoundTrip(new CultCellular(new float4(1, 2, 3, 4), new float4(5, 6, 7, 8), 0.25f)); + RoundTrip(new CultPhasor(new float4(1, 2, 3, 4), new float4(5, 6, 7, 8))); } [Test] @@ -132,6 +133,10 @@ namespace GameCult.Caching.Tests "94CA3F800000CA40000000CA40400000CA40800000" + "94CA40A00000CA40C00000CA40E00000CA41000000" + "CA3E800000"); + Hex(new CultPhasor(new float4(1f, 2f, 3f, 4f), new float4(5f, 6f, 7f, 8f))).Should().Be( + "92" + + "94CA3F800000CA40000000CA40400000CA40800000" + + "94CA40A00000CA40C00000CA40E00000CA41000000"); } [Test]