summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Editor/stack_2d_noise_to_3d.cs120
-rw-r--r--Editor/tooner.cs28
-rw-r--r--Textures/SSFD_2x2/README.md4
-rw-r--r--Textures/SSFD_2x2/Texture3DFromSequence.asset40
-rw-r--r--Textures/SSFD_2x2/Texture3DFromSequence.asset.meta8
-rw-r--r--Textures/SSFD_2x2/dots_L1-sdf.pngbin0 -> 372 bytes
-rw-r--r--Textures/SSFD_2x2/dots_L1-sdf.png.meta127
-rw-r--r--Textures/SSFD_2x2/dots_L1.pngbin0 -> 156 bytes
-rw-r--r--Textures/SSFD_2x2/dots_L1.png.meta127
-rw-r--r--Textures/SSFD_2x2/dots_L2-sdf.pngbin0 -> 376 bytes
-rw-r--r--Textures/SSFD_2x2/dots_L2-sdf.png.meta127
-rw-r--r--Textures/SSFD_2x2/dots_L2.pngbin0 -> 181 bytes
-rw-r--r--Textures/SSFD_2x2/dots_L2.png.meta127
-rw-r--r--Textures/SSFD_2x2/dots_L3-sdf.pngbin0 -> 379 bytes
-rw-r--r--Textures/SSFD_2x2/dots_L3-sdf.png.meta127
-rw-r--r--Textures/SSFD_2x2/dots_L3.pngbin0 -> 161 bytes
-rw-r--r--Textures/SSFD_2x2/dots_L3.png.meta127
-rw-r--r--Textures/SSFD_2x2/dots_L4-sdf.pngbin0 -> 387 bytes
-rw-r--r--Textures/SSFD_2x2/dots_L4-sdf.png.meta127
-rw-r--r--Textures/SSFD_2x2/dots_L4.pngbin0 -> 140 bytes
-rw-r--r--Textures/SSFD_2x2/dots_L4.png.meta127
-rw-r--r--Third_Party/generate_recursive_dithering.py88
-rw-r--r--Third_Party/shift_image_to_corner.py97
-rw-r--r--feature_macros.cginc1
-rw-r--r--globals.cginc6
-rw-r--r--tooner.shader5
-rw-r--r--tooner_lighting.cginc59
27 files changed, 1471 insertions, 1 deletions
diff --git a/Editor/stack_2d_noise_to_3d.cs b/Editor/stack_2d_noise_to_3d.cs
new file mode 100644
index 0000000..adc2773
--- /dev/null
+++ b/Editor/stack_2d_noise_to_3d.cs
@@ -0,0 +1,120 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+
+public class ImageSequenceToTexture3D : EditorWindow
+{
+ private List<Texture2D> sourceImages = new List<Texture2D>();
+ private string textureName = "Texture3DFromSequence";
+ private FilterMode filterMode = FilterMode.Bilinear;
+ private TextureWrapMode wrapMode = TextureWrapMode.Repeat;
+
+ [MenuItem("Tools/yum_food/Image Sequence to Texture3D")]
+ public static void ShowWindow()
+ {
+ GetWindow<ImageSequenceToTexture3D>("Image Sequence to Texture3D");
+ }
+
+ private void OnGUI()
+ {
+ GUILayout.Label("Image Sequence to Texture3D Converter", EditorStyles.boldLabel);
+ EditorGUILayout.HelpBox("Add images in the order they should appear in the Z-axis", MessageType.Info);
+
+ // Image sequence management
+ EditorGUILayout.LabelField("Source Images", EditorStyles.boldLabel);
+ for (int i = 0; i < sourceImages.Count; i++)
+ {
+ EditorGUILayout.BeginHorizontal();
+ sourceImages[i] = (Texture2D)EditorGUILayout.ObjectField($"Slice {i}", sourceImages[i], typeof(Texture2D), false);
+ if (GUILayout.Button("Remove", GUILayout.Width(60)))
+ {
+ sourceImages.RemoveAt(i);
+ GUILayout.EndHorizontal();
+ break;
+ }
+ EditorGUILayout.EndHorizontal();
+ }
+
+ if (GUILayout.Button("Add Image Slot"))
+ {
+ sourceImages.Add(null);
+ }
+
+ textureName = EditorGUILayout.TextField("Texture Name", textureName);
+ filterMode = (FilterMode)EditorGUILayout.EnumPopup("Filter Mode", filterMode);
+ wrapMode = (TextureWrapMode)EditorGUILayout.EnumPopup("Wrap Mode", wrapMode);
+
+ if (GUILayout.Button("Generate 3D Texture"))
+ {
+ if (ValidateInputs())
+ {
+ Generate3DTexture();
+ }
+ }
+ }
+
+ private bool ValidateInputs()
+ {
+ if (sourceImages.Count == 0)
+ {
+ EditorUtility.DisplayDialog("Error", "Please add at least one image.", "OK");
+ return false;
+ }
+
+ if (sourceImages.Contains(null))
+ {
+ EditorUtility.DisplayDialog("Error", "Please assign all image slots.", "OK");
+ return false;
+ }
+
+ // Verify all images have the same dimensions
+ int width = sourceImages[0].width;
+ int height = sourceImages[0].height;
+
+ for (int i = 1; i < sourceImages.Count; i++)
+ {
+ if (sourceImages[i].width != width || sourceImages[i].height != height)
+ {
+ EditorUtility.DisplayDialog("Error",
+ $"All images must have the same dimensions. Expected {width}x{height}, but image {i} is {sourceImages[i].width}x{sourceImages[i].height}",
+ "OK");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void Generate3DTexture()
+ {
+ int width = sourceImages[0].width;
+ int height = sourceImages[0].height;
+ int depth = sourceImages.Count;
+
+ // Create the 3D texture
+ Texture3D texture3D = new Texture3D(width, height, depth, TextureFormat.RGBA32, false);
+ texture3D.filterMode = filterMode;
+ texture3D.wrapMode = wrapMode;
+
+ // Prepare the color array
+ Color[] colors = new Color[width * height * depth];
+
+ // Copy the pixel data from each source image
+ for (int z = 0; z < depth; z++)
+ {
+ Color[] imageColors = sourceImages[z].GetPixels();
+ System.Array.Copy(imageColors, 0, colors, z * width * height, width * height);
+ }
+
+ texture3D.SetPixels(colors);
+ texture3D.Apply();
+
+ // Save the texture asset
+ string path = $"Assets/{textureName}.asset";
+ AssetDatabase.CreateAsset(texture3D, path);
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+
+ EditorUtility.DisplayDialog("Success", $"3D texture generated and saved at {path}", "OK");
+ }
+}
diff --git a/Editor/tooner.cs b/Editor/tooner.cs
index fab06e0..c7d89d4 100644
--- a/Editor/tooner.cs
+++ b/Editor/tooner.cs
@@ -3236,6 +3236,33 @@ public class ToonerGUI : ShaderGUI {
EditorGUI.indentLevel -= 1;
}
+ void DoSurfaceStableFractalDithering() {
+ MaterialProperty bc;
+
+ bc = FindProperty("_Surface_Stable_Fractal_Dithering_Enable_Static");
+ bool enabled = (bc.floatValue != 0.0);
+ EditorGUI.BeginChangeCheck();
+ enabled = Toggle("Stable fractal dithering", enabled);
+ EditorGUI.EndChangeCheck();
+ bc.floatValue = enabled ? 1.0f : 0.0f;
+ SetKeyword("_SURFACE_STABLE_FRACTAL_DITHERING", enabled);
+
+ if (!enabled) {
+ return;
+ }
+
+ EditorGUI.indentLevel += 1;
+
+ bc = FindProperty("_Surface_Stable_Fractal_Dithering_Noise");
+ TexturePropertySingleLine(MakeLabel(bc, "Noise"), bc);
+ bc = FindProperty("_Surface_Stable_Fractal_Dithering_Scale");
+ FloatProperty(bc, "Scale");
+ bc = FindProperty("_Surface_Stable_Fractal_Dithering_Max_Fwidth");
+ FloatProperty(bc, "Max fwidth");
+
+ EditorGUI.indentLevel -= 1;
+ }
+
void DoGimmicks() {
show_ui.Add(AddCollapsibleMenu("Gimmicks", "_Gimmicks"));
EditorGUI.indentLevel += 1;
@@ -3269,6 +3296,7 @@ public class ToonerGUI : ShaderGUI {
DoGeoScroll();
DoGimmickEpilepsyMode();
DoLens00();
+ DoSurfaceStableFractalDithering();
EditorGUI.indentLevel -= 1;
show_ui.RemoveAt(show_ui.Count - 1);
diff --git a/Textures/SSFD_2x2/README.md b/Textures/SSFD_2x2/README.md
new file mode 100644
index 0000000..2c17d37
--- /dev/null
+++ b/Textures/SSFD_2x2/README.md
@@ -0,0 +1,4 @@
+Images for surface stable fractal dithering.
+
+https://www.youtube.com/watch?v=HPqGaIMVuLs
+
diff --git a/Textures/SSFD_2x2/Texture3DFromSequence.asset b/Textures/SSFD_2x2/Texture3DFromSequence.asset
new file mode 100644
index 0000000..d037f79
--- /dev/null
+++ b/Textures/SSFD_2x2/Texture3DFromSequence.asset
@@ -0,0 +1,40 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!117 &11700000
+Texture3D:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: Texture3DFromSequence
+ m_ImageContentsHash:
+ serializedVersion: 2
+ Hash: 00000000000000000000000000000000
+ m_ForcedFallbackFormat: 4
+ m_DownscaleFallback: 0
+ m_IsAlphaChannelOptional: 0
+ serializedVersion: 3
+ m_ColorSpace: 0
+ m_Format: 8
+ m_Width: 32
+ m_Height: 32
+ m_Depth: 4
+ m_MipCount: 1
+ m_DataSize: 16384
+ m_TextureSettings:
+ serializedVersion: 2
+ m_FilterMode: 1
+ m_Aniso: 1
+ m_MipBias: 0
+ m_WrapU: 0
+ m_WrapV: 0
+ m_WrapW: 0
+ m_UsageMode: 0
+ m_IsReadable: 1
+ image data: 16384
+ _typelessdata: 89ffffff89ffffff88ffffff87ffffff86ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff87ffffff88ffffff89ffffff88ffffff88ffffff87ffffff87ffffff86ffffff85ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff86ffffff87ffffff87ffffff88ffffff87ffffff87ffffff87ffffff86ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff87ffffff87ffffff87ffffff86ffffff86ffffff85ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff86ffffff86ffffff85ffffff85ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff85ffffff85ffffff85ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff84ffffff84ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff84ffffff83ffffff83ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff78ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff83ffffff82ffffff82ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff78ffffff78ffffff78ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff82ffffff82ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff79ffffff78ffffff77ffffff78ffffff79ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff81ffffff7fffffff7fffffff7fffffff7fffffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff79ffffff78ffffff77ffffff76ffffff77ffffff78ffffff79ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7fffffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff79ffffff78ffffff77ffffff76ffffff76ffffff76ffffff77ffffff78ffffff79ffffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7dffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7bffffff7affffff79ffffff79ffffff78ffffff77ffffff76ffffff76ffffff75ffffff76ffffff76ffffff77ffffff78ffffff79ffffff79ffffff7affffff7bffffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7cffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7affffff7affffff79ffffff79ffffff78ffffff77ffffff76ffffff76ffffff75ffffff74ffffff75ffffff76ffffff76ffffff77ffffff78ffffff79ffffff79ffffff7affffff7affffff7bffffff7bffffff7bffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7bffffff7affffff7affffff7affffff79ffffff79ffffff78ffffff78ffffff77ffffff76ffffff76ffffff75ffffff74ffffff74ffffff74ffffff75ffffff76ffffff76ffffff77ffffff78ffffff78ffffff79ffffff79ffffff7affffff7affffff7affffff7bffffff7bffffff7bffffff7affffff7affffff7affffff7affffff79ffffff79ffffff79ffffff78ffffff78ffffff78ffffff77ffffff76ffffff76ffffff75ffffff74ffffff74ffffff73ffffff74ffffff74ffffff75ffffff76ffffff76ffffff77ffffff78ffffff78ffffff78ffffff79ffffff79ffffff79ffffff7affffff7affffff7affffff7bffffff7bffffff7bffffff7bffffff7affffff7affffff7affffff79ffffff79ffffff78ffffff78ffffff77ffffff76ffffff76ffffff75ffffff74ffffff74ffffff74ffffff75ffffff76ffffff76ffffff77ffffff78ffffff78ffffff79ffffff79ffffff7affffff7affffff7affffff7bffffff7bffffff7bffffff7cffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7affffff7affffff79ffffff79ffffff78ffffff77ffffff76ffffff76ffffff75ffffff74ffffff75ffffff76ffffff76ffffff77ffffff78ffffff79ffffff79ffffff7affffff7affffff7bffffff7bffffff7bffffff7cffffff7cffffff7cffffff7dffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7bffffff7affffff79ffffff79ffffff78ffffff77ffffff76ffffff76ffffff75ffffff76ffffff76ffffff77ffffff78ffffff79ffffff79ffffff7affffff7bffffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff79ffffff78ffffff77ffffff76ffffff76ffffff76ffffff77ffffff78ffffff79ffffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7fffffff7fffffff7fffffff7fffffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff79ffffff78ffffff77ffffff76ffffff77ffffff78ffffff79ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7fffffff81ffffff81ffffff81ffffff81ffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff79ffffff78ffffff77ffffff78ffffff79ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff78ffffff78ffffff78ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff78ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff83ffffff84ffffff84ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff84ffffff85ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff86ffffff85ffffff85ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff85ffffff85ffffff87ffffff86ffffff86ffffff85ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff86ffffff87ffffff87ffffff87ffffff86ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff87ffffff87ffffff88ffffff88ffffff87ffffff87ffffff86ffffff85ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff86ffffff87ffffff87ffffff88ffffff89ffffff89ffffff88ffffff87ffffff86ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff87ffffff88ffffff89ffffff8affffff89ffffff88ffffff87ffffff87ffffff86ffffff85ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff85ffffff86ffffff87ffffff87ffffff88ffffff89ffffff86ffffff86ffffff85ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff78ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff86ffffff85ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff79ffffff79ffffff79ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff7affffff7affffff7affffff7affffff7affffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7affffff7bffffff7bffffff7bffffff7bffffff7bffffff7affffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff83ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7bffffff7bffffff7bffffff7cffffff7cffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff82ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff7fffffff7fffffff7fffffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff83ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7bffffff7bffffff7bffffff7cffffff7cffffff7bffffff7bffffff7bffffff7affffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff84ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7affffff7bffffff7bffffff7affffff7affffff7affffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff7affffff7affffff79ffffff79ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff85ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff79ffffff78ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff86ffffff86ffffff86ffffff85ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff87ffffff86ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff78ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff86ffffff86ffffff86ffffff85ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff79ffffff79ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff85ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff79ffffff7affffff7affffff7affffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff7affffff7affffff7bffffff7bffffff7bffffff7affffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff84ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7affffff7bffffff7bffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff83ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7bffffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7fffffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff81ffffff81ffffff81ffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff82ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff82ffffff83ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7bffffff7bffffff7bffffff7cffffff7cffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff84ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff7affffff7bffffff7bffffff7bffffff7bffffff7bffffff7affffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff7affffff7affffff7affffff7affffff7affffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff85ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff79ffffff79ffffff79ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff86ffffff85ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff78ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff86ffffff87ffffff86ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff86ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7bffffff7cffffff7cffffff7bffffff7bffffff7bffffff7affffff7affffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7affffff7affffff7bffffff7bffffff7affffff7affffff7affffff79ffffff79ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff79ffffff79ffffff7affffff7affffff79ffffff79ffffff79ffffff78ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff78ffffff79ffffff79ffffff78ffffff78ffffff78ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff78ffffff78ffffff77ffffff77ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff77ffffff76ffffff76ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff76ffffff75ffffff76ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff76ffffff76ffffff76ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff76ffffff77ffffff77ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff77ffffff78ffffff78ffffff78ffffff77ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff77ffffff78ffffff78ffffff79ffffff79ffffff79ffffff78ffffff78ffffff79ffffff7affffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7affffff79ffffff78ffffff78ffffff79ffffff79ffffff7affffff7affffff7affffff79ffffff79ffffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff79ffffff79ffffff7affffff7affffff7bffffff7bffffff7bffffff7affffff7affffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7affffff7affffff7bffffff7bffffff7cffffff7cffffff7cffffff7bffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7dffffff7dffffff7dffffff7cffffff7cffffff7bffffff7bffffff7affffff79ffffff7affffff7bffffff7bffffff7cffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7effffff7effffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7affffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7effffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff7fffffff7fffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7bffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff7fffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff81ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7bffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7dffffff7cffffff7dffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7cffffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff83ffffff82ffffff82ffffff81ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff84ffffff84ffffff83ffffff82ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff82ffffff83ffffff84ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff85ffffff84ffffff84ffffff83ffffff82ffffff81ffffff7fffffff7effffff7dffffff7effffff7fffffff81ffffff82ffffff83ffffff84ffffff84ffffff
+ m_StreamData:
+ serializedVersion: 2
+ offset: 0
+ size: 0
+ path:
diff --git a/Textures/SSFD_2x2/Texture3DFromSequence.asset.meta b/Textures/SSFD_2x2/Texture3DFromSequence.asset.meta
new file mode 100644
index 0000000..91f92fa
--- /dev/null
+++ b/Textures/SSFD_2x2/Texture3DFromSequence.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 88d49b37d73085a4a9fba2a31aca23a8
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11700000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Textures/SSFD_2x2/dots_L1-sdf.png b/Textures/SSFD_2x2/dots_L1-sdf.png
new file mode 100644
index 0000000..b13a467
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L1-sdf.png
Binary files differ
diff --git a/Textures/SSFD_2x2/dots_L1-sdf.png.meta b/Textures/SSFD_2x2/dots_L1-sdf.png.meta
new file mode 100644
index 0000000..82a34ca
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L1-sdf.png.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: e250e710129eb0246b4edba42ad04709
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 1
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 128
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 128
+ resizeAlgorithm: 0
+ textureFormat: 63
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Textures/SSFD_2x2/dots_L1.png b/Textures/SSFD_2x2/dots_L1.png
new file mode 100644
index 0000000..b038984
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L1.png
Binary files differ
diff --git a/Textures/SSFD_2x2/dots_L1.png.meta b/Textures/SSFD_2x2/dots_L1.png.meta
new file mode 100644
index 0000000..3bb9af5
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L1.png.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 16dbeda9f06ea2e40b9d57bb1f2dac18
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 1
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Textures/SSFD_2x2/dots_L2-sdf.png b/Textures/SSFD_2x2/dots_L2-sdf.png
new file mode 100644
index 0000000..30fa038
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L2-sdf.png
Binary files differ
diff --git a/Textures/SSFD_2x2/dots_L2-sdf.png.meta b/Textures/SSFD_2x2/dots_L2-sdf.png.meta
new file mode 100644
index 0000000..a16a5da
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L2-sdf.png.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 4080328d94716ac49a1b63ab33301779
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 1
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 128
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 128
+ resizeAlgorithm: 0
+ textureFormat: 63
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Textures/SSFD_2x2/dots_L2.png b/Textures/SSFD_2x2/dots_L2.png
new file mode 100644
index 0000000..b994fbf
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L2.png
Binary files differ
diff --git a/Textures/SSFD_2x2/dots_L2.png.meta b/Textures/SSFD_2x2/dots_L2.png.meta
new file mode 100644
index 0000000..878ae5c
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L2.png.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: f07d4cf96598fe441a03e12746205bdb
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 1
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Textures/SSFD_2x2/dots_L3-sdf.png b/Textures/SSFD_2x2/dots_L3-sdf.png
new file mode 100644
index 0000000..f895230
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L3-sdf.png
Binary files differ
diff --git a/Textures/SSFD_2x2/dots_L3-sdf.png.meta b/Textures/SSFD_2x2/dots_L3-sdf.png.meta
new file mode 100644
index 0000000..5b3d66a
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L3-sdf.png.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 4a6a92f4dedeb2240ac75d4f2e5d73dd
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 1
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 128
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 128
+ resizeAlgorithm: 0
+ textureFormat: 63
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Textures/SSFD_2x2/dots_L3.png b/Textures/SSFD_2x2/dots_L3.png
new file mode 100644
index 0000000..c6209d6
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L3.png
Binary files differ
diff --git a/Textures/SSFD_2x2/dots_L3.png.meta b/Textures/SSFD_2x2/dots_L3.png.meta
new file mode 100644
index 0000000..7bc9920
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L3.png.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 050570fab8254644792b440fc832ccf5
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 1
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Textures/SSFD_2x2/dots_L4-sdf.png b/Textures/SSFD_2x2/dots_L4-sdf.png
new file mode 100644
index 0000000..117bb48
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L4-sdf.png
Binary files differ
diff --git a/Textures/SSFD_2x2/dots_L4-sdf.png.meta b/Textures/SSFD_2x2/dots_L4-sdf.png.meta
new file mode 100644
index 0000000..72992b0
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L4-sdf.png.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 28d40e9889ec9e44da1eed65dd9e51ed
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 1
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 128
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 128
+ resizeAlgorithm: 0
+ textureFormat: 63
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 1
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Textures/SSFD_2x2/dots_L4.png b/Textures/SSFD_2x2/dots_L4.png
new file mode 100644
index 0000000..92c8d25
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L4.png
Binary files differ
diff --git a/Textures/SSFD_2x2/dots_L4.png.meta b/Textures/SSFD_2x2/dots_L4.png.meta
new file mode 100644
index 0000000..e4104c5
--- /dev/null
+++ b/Textures/SSFD_2x2/dots_L4.png.meta
@@ -0,0 +1,127 @@
+fileFormatVersion: 2
+guid: 0fe8f5ad256f8ac4987a8e0caa3dea84
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 12
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 1
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Third_Party/generate_recursive_dithering.py b/Third_Party/generate_recursive_dithering.py
new file mode 100644
index 0000000..417647e
--- /dev/null
+++ b/Third_Party/generate_recursive_dithering.py
@@ -0,0 +1,88 @@
+import numpy as np
+from PIL import Image, ImageDraw
+import argparse
+import math
+
+from shift_image_to_corner import shift_to_corner
+
+def create_circle_image(res, radius, center=None):
+ """Create a binary image with a white circle on black background."""
+ if center is None:
+ center = (res/2, res/2)
+
+ img = Image.new('L', (res, res), 0)
+ draw = ImageDraw.Draw(img)
+
+ # Convert radius and center to pixels
+ r_px = int(radius * res)
+ cx, cy = int(center[0]), int(center[1])
+
+ # Draw white circle (255)
+ draw.ellipse([cx-r_px, cy-r_px, cx+r_px, cy+r_px], fill=255)
+ return img
+
+def main():
+ parser = argparse.ArgumentParser(description="Generate dot and circle images.")
+ parser.add_argument("--res", type=int, default=128, help="Resolution of the images.")
+ args = parser.parse_args()
+
+ res = args.res
+ goal_area = 0.1
+ # a = pi * r^2
+ # r = sqrt(a / pi)
+ initial_r = math.sqrt(goal_area / math.pi) * res # Start with a circle that fills 1/4 of the image
+
+ # Calculate areas and radii for each layer
+ initial_area = math.pi * (initial_r/res)**2
+
+ # Layer 1: Single circle in corner
+ r1 = math.sqrt(initial_area/1) * res # Calculate radius consistently with other layers
+ base_img = create_circle_image(res, r1/res)
+ corner_img = shift_to_corner(base_img)
+ corner_img.save("dots_L1.png")
+
+ # Layer 2: Two circles, split area
+ r2 = math.sqrt(initial_area/2) * res # New radius for each circle
+ # Create corner circle
+ corner_img = shift_to_corner(create_circle_image(res, r2/res))
+ # Create center circle
+ center_img = create_circle_image(res, r2/res)
+ # Combine images
+ layer2 = Image.fromarray(np.maximum(np.array(corner_img), np.array(center_img)))
+ layer2.save("dots_L2.png")
+
+ # Layer 3: Three circles
+ r3 = math.sqrt(initial_area/3) * res
+ # Create corner and center circles as before
+ corner_img = shift_to_corner(create_circle_image(res, r3/res))
+ center_img = create_circle_image(res, r3/res)
+ # Create top circle
+ top_img = shift_to_corner(create_circle_image(res, r3/res), shift_side=False)
+ # Combine images
+ layer3 = Image.fromarray(np.maximum.reduce([
+ np.array(corner_img),
+ np.array(center_img),
+ np.array(top_img)
+ ]))
+ layer3.save("dots_L3.png")
+
+ # Layer 4: Four circles
+ r4 = math.sqrt(initial_area/4) * res
+ # Create corner and center circles
+ corner_img = shift_to_corner(create_circle_image(res, r4/res))
+ center_img = create_circle_image(res, r4/res)
+ # Create top and right circles
+ top_img = shift_to_corner(create_circle_image(res, r4/res), shift_side=False)
+ right_img = shift_to_corner(create_circle_image(res, r4/res), shift_up=False)
+ # Combine images
+
+ layer4 = Image.fromarray(np.maximum.reduce([
+ np.array(corner_img),
+ np.array(center_img),
+ np.array(top_img),
+ np.array(right_img)
+ ]))
+ layer4.save("dots_L4.png")
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/Third_Party/shift_image_to_corner.py b/Third_Party/shift_image_to_corner.py
new file mode 100644
index 0000000..8f365a7
--- /dev/null
+++ b/Third_Party/shift_image_to_corner.py
@@ -0,0 +1,97 @@
+"""
+Shift image to corner, wrapping it toroidally.
+"""
+
+from PIL import Image
+import numpy as np
+import argparse
+import os
+
+def shift_to_corner(img, shift_side=True, shift_up=True):
+ """
+ Shifts an image to edges with toroidal wrapping based on specified directions.
+
+ Args:
+ img (PIL.Image): Input Pillow image
+ shift_side (bool): Whether to shift horizontally to the right edge
+ shift_up (bool): Whether to shift vertically to the top edge
+
+ Returns:
+ PIL.Image: Shifted image
+ """
+ # Convert image to numpy array
+ img_array = np.array(img)
+
+ # Get dimensions
+ height, width = img_array.shape[:2]
+ half_height = height // 2
+ half_width = width // 2
+
+ # Create new array for the shifted image
+ shifted = np.zeros_like(img_array)
+
+ if shift_side and shift_up:
+ # Original behavior - shift to upper right corner
+ shifted[half_height:, half_width:] = img_array[:half_height, :half_width] # Q1 -> BR
+ shifted[half_height:, :half_width] = img_array[:half_height, half_width:] # Q2 -> BL
+ shifted[:half_height, half_width:] = img_array[half_height:, :half_width] # Q3 -> TR
+ shifted[:half_height, :half_width] = img_array[half_height:, half_width:] # Q4 -> TL
+ elif shift_side:
+ # Only shift horizontally to right
+ shifted[:, half_width:] = img_array[:, :half_width] # Left half -> Right
+ shifted[:, :half_width] = img_array[:, half_width:] # Right half -> Left
+ elif shift_up:
+ # Only shift vertically to top
+ shifted[half_height:, :] = img_array[:half_height, :] # Top half -> Bottom
+ shifted[:half_height, :] = img_array[half_height:, :] # Bottom half -> Top
+ else:
+ # No shift, return original image
+ shifted = img_array.copy()
+
+ # Convert back to PIL Image and return
+ return Image.fromarray(shifted)
+
+def shift_to_corner_from_file(image_path, output_path, shift_side=True, shift_up=True):
+ """
+ Wrapper function that shifts an image file to edges with toroidal wrapping.
+
+ Args:
+ image_path (str): Path to the input image
+ output_path (str): Path where the shifted image will be saved
+ shift_side (bool): Whether to shift horizontally to the right edge
+ shift_up (bool): Whether to shift vertically to the top edge
+
+ Returns:
+ PIL.Image: Shifted image
+ """
+ img = Image.open(image_path)
+ result = shift_to_corner(img, shift_side=shift_side, shift_up=shift_up)
+ result.save(output_path)
+ return result
+
+def get_output_path(input_path):
+ """
+ Generate output path by adding '_shifted' before the file extension.
+
+ Args:
+ input_path (str): Path to the input image
+ Returns:
+ str: Path for the output image
+ """
+ base, ext = os.path.splitext(input_path)
+ return f"{base}_shifted{ext}"
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Shift an image to the corner with toroidal wrapping.')
+ parser.add_argument('input_image', help='Path to the input image file')
+ parser.add_argument('--no-side', action='store_false', dest='shift_side',
+ help='Disable horizontal shifting (default: enabled)')
+ parser.add_argument('--no-up', action='store_false', dest='shift_up',
+ help='Disable vertical shifting (default: enabled)')
+
+ args = parser.parse_args()
+ output_path = get_output_path(args.input_image)
+
+ shift_to_corner_from_file(args.input_image, output_path,
+ shift_side=args.shift_side,
+ shift_up=args.shift_up)
diff --git a/feature_macros.cginc b/feature_macros.cginc
index ecbc709..3f5d177 100644
--- a/feature_macros.cginc
+++ b/feature_macros.cginc
@@ -291,6 +291,7 @@
#pragma shader_feature_local _ _GIMMICK_LENS_00_GRABPASS
#pragma shader_feature_local _ _GIMMICK_LENS_00_BAYER
#pragma shader_feature_local _ _GIMMICK_LENS_00_INTERLEAVED_GRADIENT_NOISE
+#pragma shader_feature_local _ _SURFACE_STABLE_FRACTAL_DITHERING
#endif // __FEATURE_MACROS_INC
diff --git a/globals.cginc b/globals.cginc
index a1eca79..88abb0f 100644
--- a/globals.cginc
+++ b/globals.cginc
@@ -1139,5 +1139,11 @@ float _Gimmick_Lens_00_Frame_Counter_Speed;
#endif
#endif
+#if defined(_SURFACE_STABLE_FRACTAL_DITHERING)
+texture3D _Surface_Stable_Fractal_Dithering_Noise;
+float _Surface_Stable_Fractal_Dithering_Scale;
+float _Surface_Stable_Fractal_Dithering_Max_Fwidth;
+#endif
+
#endif
diff --git a/tooner.shader b/tooner.shader
index a816e67..5632ce2 100644
--- a/tooner.shader
+++ b/tooner.shader
@@ -1175,7 +1175,10 @@ Shader "yum_food/tooner"
_Gimmick_Lens_00_Mode("Mode", Float) = 0 // 0 = Bayer, 1 = InterleavedGradientNoise
_Gimmick_Lens_00_Scale("Scale", Float) = 1
-
+ _Surface_Stable_Fractal_Dithering_Enable_Static("Enable stable fractal dithering", Float) = 0
+ _Surface_Stable_Fractal_Dithering_Noise("Noise", 3D) = "white" {}
+ _Surface_Stable_Fractal_Dithering_Scale("Scale", Float) = 1
+ _Surface_Stable_Fractal_Dithering_Max_Fwidth("Max fwidth", Float) = 0.001
}
SubShader
{
diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc
index 3241394..ab885e6 100644
--- a/tooner_lighting.cginc
+++ b/tooner_lighting.cginc
@@ -1069,6 +1069,65 @@ float4 effect(inout v2f i, out float depth)
const float frame = 0;
#endif // _FRAME_COUNTER
+#if defined(_SURFACE_STABLE_FRACTAL_DITHERING)
+ {
+ float2 duv = i.uv0;
+
+ //float duv_fw = fwidth(duv.x) + fwidth(duv.y);
+ // Original paper uses SVD instead of fwidth.
+ float2x2 M = float2x2(ddx(duv), ddy(duv));
+ float2x2 MtM = mul(transpose(M), M);
+ float trace = MtM[0][0] + MtM[1][1];
+ float det = determinant(MtM);
+ // Calculate eigenvalues using quadratic formula.
+ float tmp = sqrt(trace * trace - 4 * det);
+ float e1 = (trace + tmp) * 0.5;
+ float e2 = (trace - tmp) * 0.5;
+ float2 singular_values = sqrt(float2(e1, e2));
+ // Logic from original paper: the smaller eigenvalue corresponds to the
+ // largest amount of stretching, so we use it to determine when to
+ // subdivide.
+ float duv_fw = singular_values.y;
+
+ // Suppose Max_Fwidth is 1.
+ // duv_fw is 16. That means UV is changing a lot per pixel. That means we want to shrink the scale of the UV.
+ // Factor is 16.
+ // log_2(factor) is 4.
+ // Divide original by 16.
+ float fw_factor = duv_fw / _Surface_Stable_Fractal_Dithering_Max_Fwidth;
+ float fractal_level = log2(fw_factor);
+ float fractal_level_floor = floor(fractal_level);
+ float fractal_remainder = fractal_level - fractal_level_floor;
+ duv /= pow(2, fractal_level_floor);
+ duv *= _Surface_Stable_Fractal_Dithering_Scale;
+
+ //float subdivisions = 4;
+ //float fractal_remainder_subd = fractal_remainder * subdivisions;
+
+#if 1
+ // Four layers -> coarsest at 0.125, finest at 0.875.
+ uint width, height, depth;
+ _Surface_Stable_Fractal_Dithering_Noise.GetDimensions(width, height, depth);
+ float n_layers = depth;
+ float not_used_lo = 1/(n_layers*2);
+ float not_used_hi = 1 - not_used_lo;
+ float uvw = (not_used_hi - not_used_lo) * (1 - fractal_remainder) + not_used_lo;
+
+ float3 duv_3d = float3(duv, uvw);
+#else
+ float3 duv_3d = float3(duv, 0);
+#endif
+ float noise = _Surface_Stable_Fractal_Dithering_Noise.SampleLevel(bilinear_repeat_s, duv_3d, 0);
+ noise = (noise > 0.5) ? 1 : 0;
+
+ albedo.rgb = noise;
+#if 0
+ float hue = 0;
+ hue += glsl_mod(fractal_level_floor*.1, 1);
+ albedo.rgb *= HSVtoRGB(float3(hue, 1, 1));
+#endif
+ }
+#endif
#if defined(_GIMMICK_GERSTNER_WATER)
#if defined(_EXPLODE)