com.wallstop-studios.unity-helpers 2.0.0-rc12 → 2.0.0-rc14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Editor/EnsureTextureSizeWizard.cs +110 -0
- package/Editor/EnsureTextureSizeWizard.cs.meta +3 -0
- package/Runtime/Core/Attributes/ChildComponentAttribute.cs +124 -31
- package/Runtime/Core/Attributes/ParentComponent.cs +119 -29
- package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +31 -12
- package/Runtime/Core/Extension/ColorExtensions.cs +260 -1
- package/Runtime/Core/Extension/UnityExtensions.cs +10 -0
- package/Runtime/Core/Helper/Geometry.cs +17 -0
- package/Runtime/Core/Helper/SpriteHelpers.cs +36 -3
- package/Runtime/Core/Random/PcgRandom.cs +2 -2
- package/Runtime/Core/Random/RomuDuo.cs +116 -0
- package/Runtime/Core/Random/RomuDuo.cs.meta +3 -0
- package/Runtime/Core/Random/SplitMix64.cs +94 -0
- package/Runtime/Core/Random/SplitMix64.cs.meta +3 -0
- package/Runtime/Core/Random/XorShiroRandom.cs +117 -0
- package/Runtime/Core/Random/XorShiroRandom.cs.meta +3 -0
- package/Runtime/UI/LayeredImage.cs +364 -0
- package/Runtime/UI/LayeredImage.cs.meta +3 -0
- package/Runtime/UI.meta +3 -0
- package/Tests/Runtime/Attributes/ChildComponentTests.cs +81 -0
- package/Tests/Runtime/Attributes/ChildComponentTests.cs.meta +3 -0
- package/Tests/Runtime/Attributes/Components/ExpectChildSpriteRenderers.cs +28 -0
- package/Tests/Runtime/Attributes/Components/ExpectChildSpriteRenderers.cs.meta +3 -0
- package/Tests/Runtime/Attributes/Components/ExpectParentSpriteRenderers.cs +28 -0
- package/Tests/Runtime/Attributes/Components/ExpectParentSpriteRenderers.cs.meta +3 -0
- package/Tests/Runtime/Attributes/Components.meta +3 -0
- package/Tests/Runtime/Attributes/ParentComponentTests.cs +68 -0
- package/Tests/Runtime/Attributes/ParentComponentTests.cs.meta +3 -0
- package/Tests/Runtime/Attributes.meta +3 -0
- package/Tests/Runtime/Performance/RandomPerformanceTests.cs +3 -0
- package/Tests/Runtime/Random/RomuDuoRandomTests.cs +9 -0
- package/Tests/Runtime/Random/RomuDuoRandomTests.cs.meta +3 -0
- package/Tests/Runtime/Random/SplitMix64RandomTests.cs +9 -0
- package/Tests/Runtime/Random/SplitMix64RandomTests.cs.meta +3 -0
- package/Tests/Runtime/Random/XorShiroRandomTests.cs +9 -0
- package/Tests/Runtime/Random/XorShiroRandomTests.cs.meta +3 -0
- package/package.json +1 -1
|
@@ -1,13 +1,272 @@
|
|
|
1
1
|
namespace UnityHelpers.Core.Extension
|
|
2
2
|
{
|
|
3
3
|
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.ComponentModel;
|
|
6
|
+
using System.Linq;
|
|
7
|
+
using Helper;
|
|
4
8
|
using Random;
|
|
5
9
|
using UnityEngine;
|
|
6
10
|
|
|
11
|
+
public enum ColorAveragingMethod
|
|
12
|
+
{
|
|
13
|
+
LAB = 0, // CIE L*a*b* space averaging
|
|
14
|
+
HSV = 1, // HSV space averaging
|
|
15
|
+
Weighted = 2, // Weighted RGB averaging using perceived luminance
|
|
16
|
+
Dominant = 3, // Find most dominant color cluster
|
|
17
|
+
}
|
|
18
|
+
|
|
7
19
|
// https://sharpsnippets.wordpress.com/2014/03/11/c-extension-complementary-color/
|
|
8
20
|
public static class ColorExtensions
|
|
9
21
|
{
|
|
10
|
-
public static Color
|
|
22
|
+
public static Color GetAverageColor(
|
|
23
|
+
this Sprite sprite,
|
|
24
|
+
ColorAveragingMethod method = ColorAveragingMethod.LAB
|
|
25
|
+
)
|
|
26
|
+
{
|
|
27
|
+
return GetAverageColor(Enumerables.Of(sprite), method);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static Color GetAverageColor(
|
|
31
|
+
this IEnumerable<Sprite> sprites,
|
|
32
|
+
ColorAveragingMethod method = ColorAveragingMethod.LAB
|
|
33
|
+
)
|
|
34
|
+
{
|
|
35
|
+
return GetAverageColor(
|
|
36
|
+
sprites
|
|
37
|
+
.Where(Objects.NotNull)
|
|
38
|
+
.Select(sprite => sprite.texture)
|
|
39
|
+
.Where(Objects.NotNull)
|
|
40
|
+
.SelectMany(texture =>
|
|
41
|
+
{
|
|
42
|
+
texture.MakeReadable();
|
|
43
|
+
Color[] pixels = texture.GetPixels();
|
|
44
|
+
return pixels.Where(pixel => pixel.a > 0.01f);
|
|
45
|
+
}),
|
|
46
|
+
method
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public static Color GetAverageColor(
|
|
51
|
+
this IEnumerable<Color> pixels,
|
|
52
|
+
ColorAveragingMethod method = ColorAveragingMethod.LAB
|
|
53
|
+
)
|
|
54
|
+
{
|
|
55
|
+
switch (method)
|
|
56
|
+
{
|
|
57
|
+
case ColorAveragingMethod.LAB:
|
|
58
|
+
{
|
|
59
|
+
return AverageInLABSpace(pixels);
|
|
60
|
+
}
|
|
61
|
+
case ColorAveragingMethod.HSV:
|
|
62
|
+
{
|
|
63
|
+
return AverageInHSVSpace(pixels);
|
|
64
|
+
}
|
|
65
|
+
case ColorAveragingMethod.Weighted:
|
|
66
|
+
{
|
|
67
|
+
return WeightedRGBAverage(pixels);
|
|
68
|
+
}
|
|
69
|
+
case ColorAveragingMethod.Dominant:
|
|
70
|
+
{
|
|
71
|
+
return GetDominantColor(pixels);
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
{
|
|
75
|
+
throw new InvalidEnumArgumentException(
|
|
76
|
+
nameof(method),
|
|
77
|
+
(int)method,
|
|
78
|
+
typeof(ColorAveragingMethod)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// CIE L*a*b* space averaging - most perceptually accurate
|
|
85
|
+
private static Color AverageInLABSpace(IEnumerable<Color> pixels)
|
|
86
|
+
{
|
|
87
|
+
List<LABColor> labValues = pixels.Select(RGBToLAB).ToList();
|
|
88
|
+
|
|
89
|
+
double avgL = labValues.Average(lab => lab.l);
|
|
90
|
+
double avgA = labValues.Average(lab => lab.a);
|
|
91
|
+
double avgB = labValues.Average(lab => lab.b);
|
|
92
|
+
|
|
93
|
+
return LABToRGB(avgL, avgA, avgB);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// HSV space averaging - good for preserving vibrant colors
|
|
97
|
+
private static Color AverageInHSVSpace(IEnumerable<Color> pixels)
|
|
98
|
+
{
|
|
99
|
+
float avgH = 0f;
|
|
100
|
+
float avgS = 0f;
|
|
101
|
+
float avgV = 0f;
|
|
102
|
+
int count = 0;
|
|
103
|
+
|
|
104
|
+
foreach (Color pixel in pixels)
|
|
105
|
+
{
|
|
106
|
+
Color.RGBToHSV(pixel, out float h, out float s, out float v);
|
|
107
|
+
|
|
108
|
+
// Handle hue wrapping around 360 degrees
|
|
109
|
+
float hRad = h * 2f * Mathf.PI;
|
|
110
|
+
avgH += Mathf.Cos(hRad);
|
|
111
|
+
avgH += Mathf.Sin(hRad);
|
|
112
|
+
|
|
113
|
+
avgS += s;
|
|
114
|
+
avgV += v;
|
|
115
|
+
count++;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
avgH = Mathf.Atan2(avgH / count, avgH / count) / (2f * Mathf.PI);
|
|
119
|
+
if (avgH < 0)
|
|
120
|
+
{
|
|
121
|
+
avgH += 1f;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (count <= 0)
|
|
125
|
+
{
|
|
126
|
+
count = 1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
avgS /= count;
|
|
130
|
+
avgV /= count;
|
|
131
|
+
|
|
132
|
+
return Color.HSVToRGB(avgH, avgS, avgV);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Weighted RGB averaging using perceived luminance
|
|
136
|
+
private static Color WeightedRGBAverage(IEnumerable<Color> pixels)
|
|
137
|
+
{
|
|
138
|
+
// Use perceived luminance weights
|
|
139
|
+
const float rWeight = 0.299f;
|
|
140
|
+
const float gWeight = 0.587f;
|
|
141
|
+
const float bWeight = 0.114f;
|
|
142
|
+
|
|
143
|
+
float totalWeight = 0f;
|
|
144
|
+
float r = 0f,
|
|
145
|
+
g = 0f,
|
|
146
|
+
b = 0f,
|
|
147
|
+
a = 0f;
|
|
148
|
+
|
|
149
|
+
foreach (Color pixel in pixels)
|
|
150
|
+
{
|
|
151
|
+
float weight = pixel.r * rWeight + pixel.g * gWeight + pixel.b * bWeight;
|
|
152
|
+
r += pixel.r * weight;
|
|
153
|
+
g += pixel.g * weight;
|
|
154
|
+
b += pixel.b * weight;
|
|
155
|
+
a += pixel.a * weight;
|
|
156
|
+
totalWeight += weight;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (totalWeight > 0f)
|
|
160
|
+
{
|
|
161
|
+
r /= totalWeight;
|
|
162
|
+
g /= totalWeight;
|
|
163
|
+
b /= totalWeight;
|
|
164
|
+
a /= totalWeight;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return new Color(r, g, b, a);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Find dominant color using simple clustering
|
|
171
|
+
private static Color GetDominantColor(IEnumerable<Color> pixels)
|
|
172
|
+
{
|
|
173
|
+
Dictionary<Vector3Int, int> colorBuckets = new();
|
|
174
|
+
const int bucketSize = 32; // Adjust for different precision
|
|
175
|
+
|
|
176
|
+
foreach (Color pixel in pixels)
|
|
177
|
+
{
|
|
178
|
+
Vector3Int bucket = new(
|
|
179
|
+
Mathf.RoundToInt(pixel.r * 255 / bucketSize),
|
|
180
|
+
Mathf.RoundToInt(pixel.g * 255 / bucketSize),
|
|
181
|
+
Mathf.RoundToInt(pixel.b * 255 / bucketSize)
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
colorBuckets.TryAdd(bucket, 0);
|
|
185
|
+
colorBuckets[bucket]++;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
Vector3Int dominantBucket = colorBuckets
|
|
189
|
+
.OrderByDescending(kvp => kvp.Value)
|
|
190
|
+
.First()
|
|
191
|
+
.Key;
|
|
192
|
+
return new Color(
|
|
193
|
+
dominantBucket.x * bucketSize / 255f,
|
|
194
|
+
dominantBucket.y * bucketSize / 255f,
|
|
195
|
+
dominantBucket.z * bucketSize / 255f
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Helper struct for LAB color space
|
|
200
|
+
private readonly struct LABColor
|
|
201
|
+
{
|
|
202
|
+
public readonly double l;
|
|
203
|
+
public readonly double a;
|
|
204
|
+
public readonly double b;
|
|
205
|
+
|
|
206
|
+
public LABColor(double l, double a, double b)
|
|
207
|
+
{
|
|
208
|
+
this.l = l;
|
|
209
|
+
this.a = a;
|
|
210
|
+
this.b = b;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private static LABColor RGBToLAB(Color rgb)
|
|
215
|
+
{
|
|
216
|
+
// First convert to XYZ
|
|
217
|
+
double r =
|
|
218
|
+
rgb.r > 0.04045 ? Mathf.Pow((rgb.r + 0.055f) / 1.055f, 2.4f) : rgb.r / 12.92f;
|
|
219
|
+
double g =
|
|
220
|
+
rgb.g > 0.04045 ? Mathf.Pow((rgb.g + 0.055f) / 1.055f, 2.4f) : rgb.g / 12.92f;
|
|
221
|
+
double b =
|
|
222
|
+
rgb.b > 0.04045 ? Mathf.Pow((rgb.b + 0.055f) / 1.055f, 2.4f) : rgb.b / 12.92f;
|
|
223
|
+
|
|
224
|
+
double x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
|
|
225
|
+
double y = (r * 0.2126 + g * 0.7152 + b * 0.0722);
|
|
226
|
+
double z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
|
|
227
|
+
|
|
228
|
+
x = x > 0.008856 ? Mathf.Pow((float)x, 1f / 3f) : (7.787 * x) + 16f / 116f;
|
|
229
|
+
y = y > 0.008856 ? Mathf.Pow((float)y, 1f / 3f) : (7.787 * y) + 16f / 116f;
|
|
230
|
+
z = z > 0.008856 ? Mathf.Pow((float)z, 1f / 3f) : (7.787 * z) + 16f / 116f;
|
|
231
|
+
|
|
232
|
+
return new LABColor((116 * y) - 16, 500 * (x - y), 200 * (y - z));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private static Color LABToRGB(double l, double a, double b)
|
|
236
|
+
{
|
|
237
|
+
double y = (l + 16) / 116;
|
|
238
|
+
double x = a / 500 + y;
|
|
239
|
+
double z = y - b / 200;
|
|
240
|
+
|
|
241
|
+
double x3 = x * x * x;
|
|
242
|
+
double y3 = y * y * y;
|
|
243
|
+
double z3 = z * z * z;
|
|
244
|
+
|
|
245
|
+
x = 0.95047 * (x3 > 0.008856 ? x3 : (x - 16.0 / 116.0) / 7.787);
|
|
246
|
+
y = y3 > 0.008856 ? y3 : (y - 16.0 / 116.0) / 7.787;
|
|
247
|
+
z = 1.08883 * (z3 > 0.008856 ? z3 : (z - 16.0 / 116.0) / 7.787);
|
|
248
|
+
|
|
249
|
+
double r = x * 3.2406 + y * -1.5372 + z * -0.4986;
|
|
250
|
+
double g = x * -0.9689 + y * 1.8758 + z * 0.0415;
|
|
251
|
+
double b2 = x * 0.0557 + y * -0.2040 + z * 1.0570;
|
|
252
|
+
|
|
253
|
+
r = r > 0.0031308 ? 1.055 * Mathf.Pow((float)r, 1 / 2.4f) - 0.055 : 12.92 * r;
|
|
254
|
+
g = g > 0.0031308 ? 1.055 * Mathf.Pow((float)g, 1 / 2.4f) - 0.055 : 12.92 * g;
|
|
255
|
+
b2 = b2 > 0.0031308 ? 1.055 * Mathf.Pow((float)b2, 1 / 2.4f) - 0.055 : 12.92 * b2;
|
|
256
|
+
|
|
257
|
+
return new Color(
|
|
258
|
+
Mathf.Clamp01((float)r),
|
|
259
|
+
Mathf.Clamp01((float)g),
|
|
260
|
+
Mathf.Clamp01((float)b2),
|
|
261
|
+
1f
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public static Color GetComplement(
|
|
266
|
+
this Color source,
|
|
267
|
+
IRandom random = null,
|
|
268
|
+
float variance = 0f
|
|
269
|
+
)
|
|
11
270
|
{
|
|
12
271
|
Color inputColor = source;
|
|
13
272
|
//if RGB values are close to each other by a diff less than 10%, then if RGB values are lighter side, decrease the blue by 50% (eventually it will increase in conversion below), if RBB values are on darker side, decrease yellow by about 50% (it will increase in conversion)
|
|
@@ -14,6 +14,16 @@
|
|
|
14
14
|
|
|
15
15
|
public static class UnityExtensions
|
|
16
16
|
{
|
|
17
|
+
public static Vector2 GetCenter(this GameObject gameObject)
|
|
18
|
+
{
|
|
19
|
+
if (gameObject.TryGetComponent(out CenterPointOffset centerPointOffset))
|
|
20
|
+
{
|
|
21
|
+
return centerPointOffset.CenterPoint;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return gameObject.transform.position;
|
|
25
|
+
}
|
|
26
|
+
|
|
17
27
|
public static Bounds Bounds(this Rect rect)
|
|
18
28
|
{
|
|
19
29
|
return new Bounds(rect.center, rect.size);
|
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
namespace UnityHelpers.Core.Helper
|
|
2
2
|
{
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Linq;
|
|
3
5
|
using UnityEngine;
|
|
4
6
|
|
|
5
7
|
public static class Geometry
|
|
6
8
|
{
|
|
9
|
+
public static Rect Accumulate(this IEnumerable<Rect> rects)
|
|
10
|
+
{
|
|
11
|
+
return rects.Aggregate(
|
|
12
|
+
(accumulated, next) =>
|
|
13
|
+
new Rect(
|
|
14
|
+
Mathf.Min(accumulated.xMin, next.xMin),
|
|
15
|
+
Mathf.Min(accumulated.yMin, next.yMin),
|
|
16
|
+
Mathf.Max(accumulated.xMax, next.xMax)
|
|
17
|
+
- Mathf.Min(accumulated.xMin, next.xMin),
|
|
18
|
+
Mathf.Max(accumulated.yMax, next.yMax)
|
|
19
|
+
- Mathf.Min(accumulated.yMin, next.yMin)
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
7
24
|
//Where is p in relation to a-b
|
|
8
25
|
// < 0 -> to the right
|
|
9
26
|
// = 0 -> on the line
|
|
@@ -1,11 +1,41 @@
|
|
|
1
1
|
namespace UnityHelpers.Core.Helper
|
|
2
2
|
{
|
|
3
|
+
using Extension;
|
|
3
4
|
using UnityEditor;
|
|
4
5
|
using UnityEngine;
|
|
5
6
|
using Utils;
|
|
6
7
|
|
|
7
8
|
public static class SpriteHelpers
|
|
8
9
|
{
|
|
10
|
+
public static void MakeReadable(this Texture2D texture)
|
|
11
|
+
{
|
|
12
|
+
if (texture.isReadable)
|
|
13
|
+
{
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#if UNITY_EDITOR
|
|
18
|
+
string assetPath = AssetDatabase.GetAssetPath(texture);
|
|
19
|
+
if (string.IsNullOrEmpty(assetPath))
|
|
20
|
+
{
|
|
21
|
+
texture.LogError("Failed to get asset path.");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
TextureImporter tImporter = AssetImporter.GetAtPath(assetPath) as TextureImporter;
|
|
26
|
+
if (tImporter == null)
|
|
27
|
+
{
|
|
28
|
+
texture.LogError("Failed to get texture importer.");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
tImporter.isReadable = true;
|
|
33
|
+
EditorUtility.SetDirty(tImporter);
|
|
34
|
+
tImporter.SaveAndReimport();
|
|
35
|
+
EditorUtility.SetDirty(texture);
|
|
36
|
+
#endif
|
|
37
|
+
}
|
|
38
|
+
|
|
9
39
|
public static void SetSpritePivot(string fullSpritePath, Vector2 pivot)
|
|
10
40
|
{
|
|
11
41
|
#if UNITY_EDITOR
|
|
@@ -16,7 +46,10 @@
|
|
|
16
46
|
public static void SetSpritePivot(Sprite sprite, Vector2 pivot)
|
|
17
47
|
{
|
|
18
48
|
#if UNITY_EDITOR
|
|
19
|
-
SetSpritePivot(
|
|
49
|
+
SetSpritePivot(
|
|
50
|
+
AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(sprite)) as TextureImporter,
|
|
51
|
+
pivot
|
|
52
|
+
);
|
|
20
53
|
#endif
|
|
21
54
|
}
|
|
22
55
|
|
|
@@ -30,7 +63,7 @@
|
|
|
30
63
|
|
|
31
64
|
TextureImporterSettings textureImportSettings = new TextureImporterSettings();
|
|
32
65
|
textureImporter.ReadTextureSettings(textureImportSettings);
|
|
33
|
-
textureImportSettings.spriteAlignment = (int)
|
|
66
|
+
textureImportSettings.spriteAlignment = (int)SpriteAlignment.Custom;
|
|
34
67
|
textureImportSettings.wrapMode = TextureWrapMode.Clamp;
|
|
35
68
|
textureImportSettings.filterMode = FilterMode.Trilinear;
|
|
36
69
|
textureImporter.SetTextureSettings(textureImportSettings);
|
|
@@ -40,7 +73,7 @@
|
|
|
40
73
|
resizeAlgorithm = TextureResizeAlgorithm.Bilinear,
|
|
41
74
|
maxTextureSize = SetTextureImportData.RegularTextureSize,
|
|
42
75
|
textureCompression = TextureImporterCompression.Compressed,
|
|
43
|
-
format = TextureImporterFormat.Automatic
|
|
76
|
+
format = TextureImporterFormat.Automatic,
|
|
44
77
|
};
|
|
45
78
|
|
|
46
79
|
textureImporter.SetPlatformTextureSettings(importerSettings);
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
{
|
|
18
18
|
public static IRandom Instance => ThreadLocalRandom<PcgRandom>.Instance;
|
|
19
19
|
|
|
20
|
+
public override RandomState InternalState => new(_state, _increment, _cachedGaussian);
|
|
21
|
+
|
|
20
22
|
internal readonly ulong _increment;
|
|
21
23
|
|
|
22
24
|
internal ulong _state;
|
|
@@ -53,8 +55,6 @@
|
|
|
53
55
|
_increment = NextUlong();
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
public override RandomState InternalState => new(_state, _increment, _cachedGaussian);
|
|
57
|
-
|
|
58
58
|
public override uint NextUint()
|
|
59
59
|
{
|
|
60
60
|
unchecked
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
namespace UnityHelpers.Core.Random
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Runtime.CompilerServices;
|
|
5
|
+
using System.Runtime.Serialization;
|
|
6
|
+
using System.Text.Json.Serialization;
|
|
7
|
+
using Extension;
|
|
8
|
+
using Helper;
|
|
9
|
+
|
|
10
|
+
[Serializable]
|
|
11
|
+
[DataContract]
|
|
12
|
+
public sealed class RomuDuo
|
|
13
|
+
: AbstractRandom,
|
|
14
|
+
IEquatable<RomuDuo>,
|
|
15
|
+
IComparable,
|
|
16
|
+
IComparable<RomuDuo>
|
|
17
|
+
{
|
|
18
|
+
public static IRandom Instance => ThreadLocalRandom<RomuDuo>.Instance;
|
|
19
|
+
public override RandomState InternalState => new(_x, _y, _cachedGaussian);
|
|
20
|
+
|
|
21
|
+
internal ulong _x;
|
|
22
|
+
internal ulong _y;
|
|
23
|
+
|
|
24
|
+
public RomuDuo()
|
|
25
|
+
: this(Guid.NewGuid()) { }
|
|
26
|
+
|
|
27
|
+
public RomuDuo(Guid guid)
|
|
28
|
+
{
|
|
29
|
+
byte[] bytes = guid.ToByteArray();
|
|
30
|
+
_x = BitConverter.ToUInt64(bytes, 0);
|
|
31
|
+
_y = BitConverter.ToUInt64(bytes, sizeof(ulong));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public RomuDuo(ulong seedX, ulong seedY)
|
|
35
|
+
{
|
|
36
|
+
_x = seedX;
|
|
37
|
+
_y = seedY;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
[JsonConstructor]
|
|
41
|
+
public RomuDuo(RandomState internalState)
|
|
42
|
+
{
|
|
43
|
+
_x = internalState.State1;
|
|
44
|
+
_y = internalState.State2;
|
|
45
|
+
_cachedGaussian = internalState.Gaussian;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public override uint NextUint()
|
|
49
|
+
{
|
|
50
|
+
unchecked
|
|
51
|
+
{
|
|
52
|
+
ulong xp = _x;
|
|
53
|
+
_x = 15241094284759029579UL * _y;
|
|
54
|
+
_y = Rol64(_y, 27) + xp;
|
|
55
|
+
return (uint)xp;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public override IRandom Copy()
|
|
60
|
+
{
|
|
61
|
+
return new RomuDuo(InternalState);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
65
|
+
private static ulong Rol64(ulong x, int k)
|
|
66
|
+
{
|
|
67
|
+
return (x << k) | (x >> (64 - k));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public override bool Equals(object obj)
|
|
71
|
+
{
|
|
72
|
+
return Equals(obj as RomuDuo);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public bool Equals(RomuDuo other)
|
|
76
|
+
{
|
|
77
|
+
if (other == null)
|
|
78
|
+
{
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return _x == other._x && _y == other._y;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public override int GetHashCode()
|
|
86
|
+
{
|
|
87
|
+
return Objects.ValueTypeHashCode(_x, _y);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public override string ToString()
|
|
91
|
+
{
|
|
92
|
+
return this.ToJson();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public int CompareTo(object obj)
|
|
96
|
+
{
|
|
97
|
+
return CompareTo(obj as RomuDuo);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public int CompareTo(RomuDuo other)
|
|
101
|
+
{
|
|
102
|
+
if (other == null)
|
|
103
|
+
{
|
|
104
|
+
return -1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
int comparison = _x.CompareTo(other._x);
|
|
108
|
+
if (comparison != 0)
|
|
109
|
+
{
|
|
110
|
+
return comparison;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return _y.CompareTo(other._y);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
namespace UnityHelpers.Core.Random
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Runtime.Serialization;
|
|
5
|
+
using System.Text.Json.Serialization;
|
|
6
|
+
|
|
7
|
+
[Serializable]
|
|
8
|
+
[DataContract]
|
|
9
|
+
public sealed class SplitMix64
|
|
10
|
+
: AbstractRandom,
|
|
11
|
+
IEquatable<SplitMix64>,
|
|
12
|
+
IComparable,
|
|
13
|
+
IComparable<SplitMix64>
|
|
14
|
+
{
|
|
15
|
+
public static IRandom Instance => ThreadLocalRandom<SplitMix64>.Instance;
|
|
16
|
+
|
|
17
|
+
public override RandomState InternalState => new(_state, 0, _cachedGaussian);
|
|
18
|
+
|
|
19
|
+
internal ulong _state;
|
|
20
|
+
|
|
21
|
+
public SplitMix64()
|
|
22
|
+
: this(Guid.NewGuid()) { }
|
|
23
|
+
|
|
24
|
+
public SplitMix64(Guid guid)
|
|
25
|
+
: this(BitConverter.ToUInt64(guid.ToByteArray(), 0)) { }
|
|
26
|
+
|
|
27
|
+
public SplitMix64(ulong seed)
|
|
28
|
+
{
|
|
29
|
+
_state = seed;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[JsonConstructor]
|
|
33
|
+
public SplitMix64(RandomState internalState)
|
|
34
|
+
{
|
|
35
|
+
_state = internalState.State1;
|
|
36
|
+
_cachedGaussian = internalState.Gaussian;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public override uint NextUint()
|
|
40
|
+
{
|
|
41
|
+
unchecked
|
|
42
|
+
{
|
|
43
|
+
_state += 0x9E3779B97F4A7C15UL;
|
|
44
|
+
|
|
45
|
+
ulong z = _state;
|
|
46
|
+
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9UL;
|
|
47
|
+
z = (z ^ (z >> 27)) * 0x94D049BB133111EBUL;
|
|
48
|
+
z ^= (z >> 31);
|
|
49
|
+
|
|
50
|
+
return (uint)z;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public override IRandom Copy()
|
|
55
|
+
{
|
|
56
|
+
return new SplitMix64(InternalState);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public bool Equals(SplitMix64 other)
|
|
60
|
+
{
|
|
61
|
+
if (other == null)
|
|
62
|
+
{
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return _state == other._state;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public int CompareTo(object obj)
|
|
70
|
+
{
|
|
71
|
+
return CompareTo(obj as SplitMix64);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public int CompareTo(SplitMix64 other)
|
|
75
|
+
{
|
|
76
|
+
if (other == null)
|
|
77
|
+
{
|
|
78
|
+
return -1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return _state.CompareTo(other._state);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public override int GetHashCode()
|
|
85
|
+
{
|
|
86
|
+
return _state.GetHashCode();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public override string ToString()
|
|
90
|
+
{
|
|
91
|
+
return $"{{\"State\": {_state}}}";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|