diff --git a/OverlapWFC.cs b/OverlapWFC.cs index c5360ef..70df2d3 100644 --- a/OverlapWFC.cs +++ b/OverlapWFC.cs @@ -28,9 +28,10 @@ class OverlapWFC : MonoBehaviour{ public static bool IsPrefabRef(UnityEngine.Object o){ #if UNITY_EDITOR - return PrefabUtility.GetPrefabParent(o) == null && PrefabUtility.GetPrefabObject(o) != null; - #endif + return PrefabUtility.GetOutermostPrefabInstanceRoot(o) != null; + #else return true; + #endif } static GameObject CreatePrefab(UnityEngine.Object fab, Vector3 pos, Quaternion rot) { @@ -39,11 +40,12 @@ static GameObject CreatePrefab(UnityEngine.Object fab, Vector3 pos, Quaternion r e.transform.position = pos; e.transform.rotation = rot; return e; - #endif + #else GameObject o = GameObject.Instantiate(fab as GameObject) as GameObject; o.transform.position = pos; o.transform.rotation = rot; return o; + #endif } public void Clear(){ @@ -146,7 +148,7 @@ public void Draw(){ } } } - } catch (IndexOutOfRangeException e) { + } catch (IndexOutOfRangeException) { model = null; return; } diff --git a/SimpleTiledWFC.cs b/SimpleTiledWFC.cs index ea97497..3d71e89 100644 --- a/SimpleTiledWFC.cs +++ b/SimpleTiledWFC.cs @@ -9,7 +9,7 @@ [ExecuteInEditMode] public class SimpleTiledWFC : MonoBehaviour{ - public string xmlpath = null; + public TextAsset xml = null; private string subset = ""; public int gridsize = 1; @@ -76,13 +76,13 @@ public void Generate(){ GameObject go = output.transform.GetChild(i).gameObject; if (Application.isPlaying){Destroy(go);} else {DestroyImmediate(go);} } - group = new GameObject(xmlpath).transform; + group = new GameObject(xml.name).transform; group.parent = output.transform; group.position = output.transform.position; group.rotation = output.transform.rotation; group.localScale = new Vector3(1f, 1f, 1f); rendering = new GameObject[width, depth]; - this.model = new SimpleTiledModel(Application.dataPath+"/"+xmlpath, subset, width, depth, periodic); + this.model = new SimpleTiledModel(xml.text, subset, width, depth, periodic); undrawn = true; } @@ -130,7 +130,7 @@ public void Draw(){ public class TileSetEditor : Editor { public override void OnInspectorGUI () { SimpleTiledWFC me = (SimpleTiledWFC)target; - if (me.xmlpath != null){ + if (me.xml != null){ if(GUILayout.Button("generate")){ me.Generate(); } diff --git a/TilePainter.cs b/TilePainter.cs index 82dc0e5..6e4e6b9 100644 --- a/TilePainter.cs +++ b/TilePainter.cs @@ -184,12 +184,30 @@ public Vector3 Local(Vector3 p){ return this.transform.TransformPoint(p); } + public UnityEngine.Object PrefabSource(GameObject o){ + if (o == null) + { + return null; + } + UnityEngine.Object fab = PrefabUtility.GetCorrespondingObjectFromSource(o); + if (fab == null) + { + fab = Resources.Load(o.name); + } + if (fab == null) + { + fab = palette[0]; + } + return fab; + } + public void Drag(Vector3 mouse, TileLayerEditor.TileOperation op){ Resize(); if (tileobs == null){Restore();} if (this.ValidCoords((int)cursor.x, (int)cursor.y)){ if (op == TileLayerEditor.TileOperation.Sampling){ - UnityEngine.Object s = PrefabUtility.GetPrefabParent(tileobs[(int)cursor.x, (int)cursor.y]); + UnityEngine.Object s = PrefabSource(tileobs[(int)cursor.x, (int)cursor.y]); + Debug.Log(s); if (s != null){ color = s; color_rotation = tileobs[(int)cursor.x, (int)cursor.y].transform.localRotation; @@ -270,7 +288,7 @@ private bool AmHovering(Event e){ me.focused = true; Renderer rend = me.gameObject.GetComponentInChildren( ); - if( rend ) EditorUtility.SetSelectedWireframeHidden( rend, false ); + if( rend ) EditorUtility.SetSelectedRenderState( rend, EditorSelectedRenderState.Wireframe ); return true; } me.focused = false; @@ -285,19 +303,19 @@ public void ProcessEvents(){ Event current = Event.current; bool leftbutton = (current.button == 0); switch(current.type){ - case EventType.keyDown: + case EventType.KeyDown: if (current.keyCode == KeyCode.S) operation = TileOperation.Sampling; if (current.keyCode == KeyCode.X) operation = TileOperation.Erasing; current.Use(); return; - case EventType.keyUp: + case EventType.KeyUp: operation = TileOperation.None; if (current.keyCode == KeyCode.Space) me.Turn(); if (current.keyCode == KeyCode.B) me.CycleColor(); current.Use(); return; - case EventType.mouseDown: + case EventType.MouseDown: if (leftbutton) { if (operation == TileOperation.None){ @@ -309,7 +327,7 @@ public void ProcessEvents(){ return; } break; - case EventType.mouseDrag: + case EventType.MouseDrag: if (leftbutton) { if (operation != TileOperation.None){ @@ -320,7 +338,7 @@ public void ProcessEvents(){ return; } break; - case EventType.mouseUp: + case EventType.MouseUp: if (leftbutton) { operation = TileOperation.None; @@ -328,13 +346,13 @@ public void ProcessEvents(){ return; } break; - case EventType.mouseMove: + case EventType.MouseMove: me.Resize(); current.Use(); break; - case EventType.repaint: + case EventType.Repaint: break; - case EventType.layout: + case EventType.Layout: HandleUtility.AddDefaultControl(controlID); break; } diff --git a/Training.cs b/Training.cs index b6083ff..dc39f8f 100644 --- a/Training.cs +++ b/Training.cs @@ -1,6 +1,7 @@ using System; using System.IO; using UnityEngine; +using System.Globalization; #if UNITY_EDITOR using UnityEditor; #endif @@ -25,6 +26,7 @@ public int Card(int n){ } public void RecordNeighbors() { + Compile(); neighbors = new Dictionary(); for (int y = 0; y < depth; y++){ for (int x = 0; x < width; x++){ @@ -73,7 +75,7 @@ public string NeighborXML(){ if (last == "X" || last == "I" || last == "L" || last == "T" || last == "D"){ sym = last; } - res += "\n"; + res += "\n"; } } res += " \n"; @@ -113,17 +115,16 @@ public void Compile() { (tilepos.y > -0.55f) && (tilepos.y <= depth*gridsize-0.55f)){ UnityEngine.Object fab = tile; #if UNITY_EDITOR - fab = PrefabUtility.GetPrefabParent(tile); - if (fab == null){ - PrefabUtility.ReconnectToLastPrefab(tile); - fab = PrefabUtility.GetPrefabParent(tile); - } + fab = PrefabUtility.GetCorrespondingObjectFromSource(tile); + // if (fab == null){ + // PrefabUtility.RevertPrefabInstance(tile); + // fab = PrefabUtility.GetCorrespondingObjectFromSource(tile); + // } if (fab == null){ fab = (GameObject)Resources.Load(tile.name); - if (fab){ - tile = PrefabUtility.ConnectGameObjectToPrefab(tile, (GameObject)fab); - }else{ - fab = tile;} + if (!fab){ + fab = tile; + } } tile.name = fab.name; diff --git a/impl/Model.cs b/impl/Model.cs index fe1513c..a2ff16b 100644 --- a/impl/Model.cs +++ b/impl/Model.cs @@ -10,116 +10,160 @@ The above copyright notice and this permission notice shall be included in all c public abstract class Model { - public bool[][][] wave; - public bool[][] changes; - public double[] stationary; - protected int[][] observed; + protected bool[][] wave; + + protected int[][][] propagator; + int[][][] compatible; + protected int[] observed; protected bool init = false; + Tuple[] stack; + int stacksize; + protected System.Random random; - protected int FMX, FMY, T, limit; + protected int FMX, FMY, T; protected bool periodic; - double[] logProb; - double logT; - - protected Model(int width, int height) - { - FMX = width; - FMY = height; - - wave = new bool[FMX][][]; - changes = new bool[FMX][]; - for (int x = 0; x[wave.Length * T]; + stacksize = 0; + } - if (amount == 1) entropy = 0; - else if (amount == T) entropy = logT; - else - { - mainSum = 0; - logSum = Math.Log(sum); - for (int t = 0; t < T; t++) if (w[t]) mainSum += stationary[t] * logProb[t]; - entropy = logSum - mainSum / sum; - } + + + bool? Observe() + { + double min = 1E+3; + int argmin = -1; + + for (int i = 0; i < wave.Length; i++) + { + if (OnBoundary(i % FMX, i / FMX)) continue; + + int amount = sumsOfOnes[i]; + if (amount == 0) return false; - if (entropy > 0 && entropy + noise < min) + double entropy = entropies[i]; + if (amount > 1 && entropy <= min) + { + double noise = 1E-6 * random.NextDouble(); + if (entropy + noise < min) { min = entropy + noise; - argminx = x; - argminy = y; + argmin = i; } } + } + + if (argmin == -1) + { + observed = new int[FMX * FMY]; + for (int i = 0; i < wave.Length; i++) for (int t = 0; t < T; t++) if (wave[i][t]) { observed[i] = t; break; } + return true; + } - if (argminx == -1 && argminy == -1) - { - observed = new int[FMX][]; - for (int x = 0; x < FMX; x++) - { - observed[x] = new int[FMY]; - for (int y = 0; y < FMY; y++) for (int t = 0; t < T; t++) if (wave[x][y][t]) - { - observed[x][y] = t; - break; - } - } - return true; - } - - double[] distribution = new double[T]; - for (int t = 0; t < T; t++) distribution[t] = wave[argminx][argminy][t] ? stationary[t] : 0; - int r = Stuff.Random(distribution, random.NextDouble()); - for (int t = 0; t < T; t++) wave[argminx][argminy][t] = t == r; - changes[argminx][argminy] = true; + double[] distribution = new double[T]; + for (int t = 0; t < T; t++) distribution[t] = wave[argmin][t] ? weights[t] : 0; + int r = distribution.Random(random.NextDouble()); + + bool[] w = wave[argmin]; + for (int t = 0; t < T; t++) if (w[t] != (t == r)) Ban(argmin, t); return null; } + protected void Propagate() + { + while (stacksize > 0) + { + var e1 = stack[stacksize - 1]; + stacksize--; + + int i1 = e1.Item1; + int x1 = i1 % FMX, y1 = i1 / FMX; + bool[] w1 = wave[i1]; + + for (int d = 0; d < 4; d++) + { + int dx = DX[d], dy = DY[d]; + int x2 = x1 + dx, y2 = y1 + dy; + if (OnBoundary(x2, y2)) continue; + + if (x2 < 0) x2 += FMX; + else if (x2 >= FMX) x2 -= FMX; + if (y2 < 0) y2 += FMY; + else if (y2 >= FMY) y2 -= FMY; + + int i2 = x2 + y2 * FMX; + int[] p = propagator[d][e1.Item2]; + int[][] compat = compatible[i2]; + + for (int l = 0; l < p.Length; l++) + { + int t2 = p[l]; + int[] comp = compat[t2]; + + comp[d]--; + if (comp[d] == 0) Ban(i2, t2); + } + } + } + } + public bool Run(int seed, int limit) { - logT = Math.Log(T); - logProb = new double[T]; - for (int t = 0; t < T; t++) logProb[t] = Math.Log(stationary[t]); + if (wave == null) Init(); - if (!this.init){ + if (!this.init) { this.init = true; this.Clear(); } - if (seed==0){ + if (seed==0) { random = new System.Random(); - }else{ + } else { random = new System.Random(seed); } @@ -127,20 +171,52 @@ public bool Run(int seed, int limit) { bool? result = Observe(); if (result != null) return (bool)result; - while (Propagate()); + Propagate(); } return true; } - public virtual void Clear() + protected void Ban(int i, int t) + { + wave[i][t] = false; + + int[] comp = compatible[i][t]; + for (int d = 0; d < 4; d++) comp[d] = 0; + stack[stacksize] = new Tuple(i, t); + stacksize++; + + double sum = sumsOfWeights[i]; + entropies[i] += sumsOfWeightLogWeights[i] / sum - Math.Log(sum); + + sumsOfOnes[i] -= 1; + sumsOfWeights[i] -= weights[t]; + sumsOfWeightLogWeights[i] -= weightLogWeights[t]; + + sum = sumsOfWeights[i]; + entropies[i] -= sumsOfWeightLogWeights[i] / sum - Math.Log(sum); + } + + protected virtual void Clear() { - for (int x = 0; x < FMX; x++) for (int y = 0; y < FMY; y++) + for (int i = 0; i < wave.Length; i++) + { + for (int t = 0; t < T; t++) { - for (int t = 0; t < T; t++) wave[x][y][t] = true; - changes[x][y] = false; + wave[i][t] = true; + for (int d = 0; d < 4; d++) compatible[i][t][d] = propagator[opposite[d]][t].Length; } + + sumsOfOnes[i] = weights.Length; + sumsOfWeights[i] = sumOfWeights; + sumsOfWeightLogWeights[i] = sumOfWeightLogWeights; + entropies[i] = startingEntropy; + } } protected abstract bool OnBoundary(int x, int y); -} + + protected static int[] DX = { -1, 0, 1, 0 }; + protected static int[] DY = { 0, 1, 0, -1 }; + static int[] opposite = { 2, 3, 0, 1 }; +} \ No newline at end of file diff --git a/impl/OverlappingModel.cs b/impl/OverlappingModel.cs index 22571c5..f175d28 100644 --- a/impl/OverlappingModel.cs +++ b/impl/OverlappingModel.cs @@ -8,17 +8,18 @@ The above copyright notice and this permission notice shall be included in all c using System; using System.Collections.Generic; +using UnityEngine; class OverlappingModel : Model { - int[][][][] propagator; + int N; public byte[][] patterns; - int foundation; + int ground; public List colors; - public OverlappingModel(byte[,] sample, int N, int width, int height, bool periodicInput, bool periodicOutput, int symmetry, int foundation) + public OverlappingModel(byte[,] sample, int N, int width, int height, bool periodicInput, bool periodicOutput, int symmetry, int ground) :base(width, height) { this.N = N; @@ -48,11 +49,7 @@ public OverlappingModel(byte[,] sample, int N, int width, int height, bool perio Func, byte[]> pattern = (f) => { byte[] result = new byte[N * N]; - for (int y = 0; y < N; y++){ - for (int x = 0; x < N; x++){ - result[x + y * N] = f(x, y); - } - } + for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) result[x + y * N] = f(x, y); return result; }; @@ -94,7 +91,9 @@ public OverlappingModel(byte[,] sample, int N, int width, int height, bool perio }; Dictionary weights = new Dictionary(); - for (int y = 0; y < (periodicInput ? SMY : SMY - N + 1); y++) for (int x = 0; x < (periodicInput ? SMX : SMX - N + 1); x++) + List ordering = new List(); + + for (int y = 0; y < (periodicInput ? SMY : SMY - N + 1); y++) for (int x = 0; x < (periodicInput ? SMX : SMX - N + 1); x++) { byte[][] ps = new byte[8][]; @@ -111,26 +110,28 @@ public OverlappingModel(byte[,] sample, int N, int width, int height, bool perio { long ind = index(ps[k]); if (weights.ContainsKey(ind)) weights[ind]++; - else weights.Add(ind, 1); + else { + weights.Add(ind, 1); + ordering.Add(ind); + } } } T = weights.Count; - this.foundation = (foundation + T) % T; + this.ground = (ground + T) % T; patterns = new byte[T][]; - stationary = new double[T]; - propagator = new int[2 * N - 1][][][]; + base.weights = new double[T]; int counter = 0; - foreach (int w in weights.Keys) + foreach (long w in ordering) { patterns[counter] = patternFromIndex(w); - stationary[counter] = weights[w]; - counter++; + base.weights[counter] = weights[w]; + counter++; } - for (int x = 0; x < FMX; x++) for (int y = 0; y < FMY; y++) wave[x][y] = new bool[T]; + Func agrees = (p1, p2, dx, dy) => { @@ -139,74 +140,31 @@ public OverlappingModel(byte[,] sample, int N, int width, int height, bool perio return true; }; - for (int x = 0; x < 2 * N - 1; x++) + propagator = new int[4][][]; + for (int d = 0; d < 4; d++) { - propagator[x] = new int[2 * N - 1][][]; - for (int y = 0; y < 2 * N - 1; y++) + propagator[d] = new int[T][]; + for (int t = 0; t < T; t++) { - propagator[x][y] = new int[T][]; - for (int t = 0; t < T; t++) - { - List list = new List(); - for (int t2 = 0; t2 < T; t2++) if (agrees(patterns[t], patterns[t2], x - N + 1, y - N + 1)) list.Add(t2); - propagator[x][y][t] = new int[list.Count]; - for (int c = 0; c < list.Count; c++) propagator[x][y][t][c] = list[c]; - } + List list = new List(); + for (int t2 = 0; t2 < T; t2++) if (agrees(patterns[t], patterns[t2], DX[d], DY[d])) list.Add(t2); + propagator[d][t] = new int[list.Count]; + for (int c = 0; c < list.Count; c++) propagator[d][t][c] = list[c]; } } } - protected override bool OnBoundary(int x, int y){ - return !periodic && (x + N > FMX || y + N > FMY);} - - override protected bool Propagate() + protected override bool OnBoundary(int x, int y) { - bool change = false, b; - int x2, y2; + return !periodic && (x + N > FMX || y + N > FMY || x < 0 || y < 0); + } - for (int x1 = 0; x1 < FMX; x1++) for (int y1 = 0; y1 < FMY; y1++) if (changes[x1][y1]) - { - changes[x1][y1] = false; - for (int dx = -N + 1; dx < N; dx++) for (int dy = -N + 1; dy < N; dy++) - { - x2 = x1 + dx; - if (x2 < 0) x2 += FMX; - else if (x2 >= FMX) x2 -= FMX; - - y2 = y1 + dy; - if (y2 < 0) y2 += FMY; - else if (y2 >= FMY) y2 -= FMY; - - if (!periodic && (x2 + N > FMX || y2 + N > FMY)) continue; - - bool[] w1 = wave[x1][y1]; - bool[] w2 = wave[x2][y2]; - int[][] p = propagator[N - 1 - dx][N - 1 - dy]; - - for (int t2 = 0; t2 < T; t2++) - { - if (!w2[t2]) continue; - b = false; - int[] prop = p[t2]; - for (int i1 = 0; i1 < prop.Length && !b; i1++) b = w1[prop[i1]]; - - if (!b) - { - changes[x2][y2] = true; - change = true; - w2[t2] = false; - } - } - } - } - return change; - } public byte Sample(int x, int y){ bool found = false; byte res = (byte)99; - for (int t = 0; t < T; t++) if (wave[x][y][t]){ + for (int t = 0; t < T; t++) if (wave[x + y * FMX][t]){ if (found) {return (byte)99;} found = true; res = patterns[t][0]; @@ -214,25 +172,32 @@ public byte Sample(int x, int y){ return res; } - public override void Clear() + protected override void Clear() { base.Clear(); - - if (foundation != 0) + //here we could actually set ground as all 4 sides possibly, think i need to query which ngram is made from the ground tile index, instead of just using that index into the ngrams + if (ground != 0) { for (int x = 0; x < FMX; x++) { - for (int t = 0; t < T; t++) if (t != foundation) wave[x][0][t] = false; - changes[x][0] = true; - - for (int y = 2; y < FMY; y++) - { - wave[x][y][foundation] = false; - changes[x][y] = true; - } - - while (Propagate()); - } + //top + //for (int t = 0; t < T; t++) if (t != ground) Ban(x + (FMY - 1) * FMX, t); + + //bottom + for (int t = 0; t < T; t++) if (t != ground) Ban(x, t); + + } + + /* for (int y = 0; y < FMY; y++) + { + //right + for (int t = 0; t < T; t++) if (t != ground) Ban((y * FMX) + (FMX - 1), t); + + //left + for (int t = 0; t < T; t++) if (t != ground) Ban(y * FMX, t); + }*/ + + Propagate(); } } } \ No newline at end of file diff --git a/impl/SimpleTiledModel.cs b/impl/SimpleTiledModel.cs index 5612ab6..b0a340a 100644 --- a/impl/SimpleTiledModel.cs +++ b/impl/SimpleTiledModel.cs @@ -13,7 +13,6 @@ The above copyright notice and this permission notice shall be included in all c public class SimpleTiledModel : Model { - public int[][][] propagator; public List tiles; public SimpleTiledModel(string name, string subsetName, int width, int height, bool periodic) @@ -22,7 +21,7 @@ public SimpleTiledModel(string name, string subsetName, int width, int height, b this.periodic = periodic; var xdoc = new XmlDocument(); - xdoc.Load(name); + xdoc.LoadXml(name); XmlNode xnode = xdoc.FirstChild; bool unique = xnode.Get("unique", false); xnode = xnode.FirstChild; @@ -127,10 +126,10 @@ public SimpleTiledModel(string name, string subsetName, int width, int height, b } T = action.Count; - stationary = tempStationary.ToArray(); + weights = tempStationary.ToArray(); - var tempPropagator = new bool[4][][]; propagator = new int[4][][]; + var tempPropagator = new bool[4][][]; for (int d = 0; d < 4; d++) { tempPropagator[d] = new bool[T][]; @@ -138,8 +137,6 @@ public SimpleTiledModel(string name, string subsetName, int width, int height, b for (int t = 0; t < T; t++) tempPropagator[d][t] = new bool[T]; } - for (int x = 0; x < FMX; x++) for (int y = 0; y < FMY; y++) wave[x][y] = new bool[T]; - foreach (XmlNode xneighbor in xnode.NextSibling.ChildNodes) { string[] left = xneighbor.Get("left").Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); @@ -187,75 +184,12 @@ public SimpleTiledModel(string name, string subsetName, int width, int height, b } } - protected override bool Propagate() - { - bool change = false, b; - for (int x2 = 0; x2 < FMX; x2++) for (int y2 = 0; y2 < FMY; y2++) for (int d = 0; d < 4; d++) - { - int x1 = x2, y1 = y2; - if (d == 0) - { - if (x2 == 0) - { - if (!periodic) continue; - else x1 = FMX - 1; - } - else x1 = x2 - 1; - } - else if (d == 1) - { - if (y2 == FMY - 1) - { - if (!periodic) continue; - else y1 = 0; - } - else y1 = y2 + 1; - } - else if (d == 2) - { - if (x2 == FMX - 1) - { - if (!periodic) continue; - else x1 = 0; - } - else x1 = x2 + 1; - } - else - { - if (y2 == 0) - { - if (!periodic) continue; - else y1 = FMY - 1; - } - else y1 = y2 - 1; - } - - if (!changes[x1][y1]) continue; - bool[] w1 = wave[x1][y1]; - bool[] w2 = wave[x2][y2]; - - for (int t2 = 0; t2 < T; t2++) - { - if (!w2[t2]) continue; - b = false; - int[] prop = propagator[d][t2]; - for (int i1 = 0; i1 < prop.Length && !b; i1++) b = w1[prop[i1]]; - if (!b) - { - changes[x2][y2] = true; - change = true; - w2[t2] = false; - } - } - } - - return change; - } + public string Sample(int x, int y){ bool found = false; string res = "?"; - for (int t = 0; t < T; t++) if (wave[x][y][t]){ + for (int t = 0; t < T; t++) if (wave[x + y * FMX][t]){ if (found) {return "?";} found = true; res = tiles[t]; @@ -264,7 +198,7 @@ public string Sample(int x, int y){ } protected override bool OnBoundary(int x, int y){ - return false; + return !periodic && (x < 0 || y < 0 || x >= FMX || y >= FMY); } } \ No newline at end of file