From fb26b02a20ef751cdd1832abc925b5e57bb2234b Mon Sep 17 00:00:00 2001 From: yum Date: Sat, 1 Feb 2025 19:15:58 -0800 Subject: Implement surface stable fractal dithering --- Editor/stack_2d_noise_to_3d.cs | 120 +++++++++++++++++++ Editor/tooner.cs | 28 +++++ Textures/SSFD_2x2/README.md | 4 + Textures/SSFD_2x2/Texture3DFromSequence.asset | 40 +++++++ Textures/SSFD_2x2/Texture3DFromSequence.asset.meta | 8 ++ Textures/SSFD_2x2/dots_L1-sdf.png | Bin 0 -> 372 bytes Textures/SSFD_2x2/dots_L1-sdf.png.meta | 127 +++++++++++++++++++++ Textures/SSFD_2x2/dots_L1.png | Bin 0 -> 156 bytes Textures/SSFD_2x2/dots_L1.png.meta | 127 +++++++++++++++++++++ Textures/SSFD_2x2/dots_L2-sdf.png | Bin 0 -> 376 bytes Textures/SSFD_2x2/dots_L2-sdf.png.meta | 127 +++++++++++++++++++++ Textures/SSFD_2x2/dots_L2.png | Bin 0 -> 181 bytes Textures/SSFD_2x2/dots_L2.png.meta | 127 +++++++++++++++++++++ Textures/SSFD_2x2/dots_L3-sdf.png | Bin 0 -> 379 bytes Textures/SSFD_2x2/dots_L3-sdf.png.meta | 127 +++++++++++++++++++++ Textures/SSFD_2x2/dots_L3.png | Bin 0 -> 161 bytes Textures/SSFD_2x2/dots_L3.png.meta | 127 +++++++++++++++++++++ Textures/SSFD_2x2/dots_L4-sdf.png | Bin 0 -> 387 bytes Textures/SSFD_2x2/dots_L4-sdf.png.meta | 127 +++++++++++++++++++++ Textures/SSFD_2x2/dots_L4.png | Bin 0 -> 140 bytes Textures/SSFD_2x2/dots_L4.png.meta | 127 +++++++++++++++++++++ Third_Party/generate_recursive_dithering.py | 88 ++++++++++++++ Third_Party/shift_image_to_corner.py | 97 ++++++++++++++++ feature_macros.cginc | 1 + globals.cginc | 6 + tooner.shader | 5 +- tooner_lighting.cginc | 59 ++++++++++ 27 files changed, 1471 insertions(+), 1 deletion(-) create mode 100644 Editor/stack_2d_noise_to_3d.cs create mode 100644 Textures/SSFD_2x2/README.md create mode 100644 Textures/SSFD_2x2/Texture3DFromSequence.asset create mode 100644 Textures/SSFD_2x2/Texture3DFromSequence.asset.meta create mode 100644 Textures/SSFD_2x2/dots_L1-sdf.png create mode 100644 Textures/SSFD_2x2/dots_L1-sdf.png.meta create mode 100644 Textures/SSFD_2x2/dots_L1.png create mode 100644 Textures/SSFD_2x2/dots_L1.png.meta create mode 100644 Textures/SSFD_2x2/dots_L2-sdf.png create mode 100644 Textures/SSFD_2x2/dots_L2-sdf.png.meta create mode 100644 Textures/SSFD_2x2/dots_L2.png create mode 100644 Textures/SSFD_2x2/dots_L2.png.meta create mode 100644 Textures/SSFD_2x2/dots_L3-sdf.png create mode 100644 Textures/SSFD_2x2/dots_L3-sdf.png.meta create mode 100644 Textures/SSFD_2x2/dots_L3.png create mode 100644 Textures/SSFD_2x2/dots_L3.png.meta create mode 100644 Textures/SSFD_2x2/dots_L4-sdf.png create mode 100644 Textures/SSFD_2x2/dots_L4-sdf.png.meta create mode 100644 Textures/SSFD_2x2/dots_L4.png create mode 100644 Textures/SSFD_2x2/dots_L4.png.meta create mode 100644 Third_Party/generate_recursive_dithering.py create mode 100644 Third_Party/shift_image_to_corner.py 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 sourceImages = new List(); + 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("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 Binary files /dev/null and b/Textures/SSFD_2x2/dots_L1-sdf.png 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 Binary files /dev/null and b/Textures/SSFD_2x2/dots_L1.png 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 Binary files /dev/null and b/Textures/SSFD_2x2/dots_L2-sdf.png 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 Binary files /dev/null and b/Textures/SSFD_2x2/dots_L2.png 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 Binary files /dev/null and b/Textures/SSFD_2x2/dots_L3-sdf.png 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 Binary files /dev/null and b/Textures/SSFD_2x2/dots_L3.png 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 Binary files /dev/null and b/Textures/SSFD_2x2/dots_L4-sdf.png 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 Binary files /dev/null and b/Textures/SSFD_2x2/dots_L4.png 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) -- cgit v1.2.3