From ee04c311779426bb5fff611e1358b855483ed726 Mon Sep 17 00:00:00 2001 From: Ortiz Date: Wed, 4 Sep 2024 01:18:25 +0000 Subject: [PATCH 1/8] Moved items to "/src" folder --- .glitch-assets | 6 - index.js | 857 ------------------------------------------------- ndwfc-tools.js | 418 ------------------------ ndwfc.js | 229 ------------- 4 files changed, 1510 deletions(-) delete mode 100644 .glitch-assets delete mode 100644 index.js delete mode 100644 ndwfc-tools.js delete mode 100644 ndwfc.js diff --git a/.glitch-assets b/.glitch-assets deleted file mode 100644 index 954626f..0000000 --- a/.glitch-assets +++ /dev/null @@ -1,6 +0,0 @@ -{"name":"drag-in-files.svg","date":"2016-10-22T16:17:49.954Z","url":"https://cdn.hyperdev.com/drag-in-files.svg","type":"image/svg","size":7646,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/drag-in-files.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(102, 153, 205)","uuid":"adSBq97hhhpFNUna"} -{"name":"click-me.svg","date":"2016-10-23T16:17:49.954Z","url":"https://cdn.hyperdev.com/click-me.svg","type":"image/svg","size":7116,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/click-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(243, 185, 186)","uuid":"adSBq97hhhpFNUnb"} -{"name":"paste-me.svg","date":"2016-10-24T16:17:49.954Z","url":"https://cdn.hyperdev.com/paste-me.svg","type":"image/svg","size":7242,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/paste-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(42, 179, 185)","uuid":"adSBq97hhhpFNUnc"} -{"uuid":"adSBq97hhhpFNUna","deleted":true} -{"uuid":"adSBq97hhhpFNUnb","deleted":true} -{"uuid":"adSBq97hhhpFNUnc","deleted":true} diff --git a/index.js b/index.js deleted file mode 100644 index 0e66102..0000000 --- a/index.js +++ /dev/null @@ -1,857 +0,0 @@ -/* global describe WFC WFCTool2D WFCTool3D THREE*/ - -var tilesets = { -circuit_simple: function(tool){ - -tool.addTile(`\ -@@@ -@@@ -@@@`,{weight:5}) - -tool.addTile(`\ -... -... -...`) - -tool.addTile(`\ -@.. -@-= -@..`) - -tool.addTile(`\ -@.. -... -...`) - -tool.addTile(`\ -... -=== -...`) - -tool.addTile(`\ -.-. -=== -.-.`) - - -tool.addTile(`\ -... -=-- -...`) - -tool.addTile(`\ -.=. -.== -.=.`) - -tool.addTile(`\ -.=. -.== -...`) - -tool.addColor("@", [55,45,45]) -tool.addColor(".", [30,100,20]) -tool.addColor("-", [180,170,170]) -tool.addColor("=", [125,145,25]) - -}, - -circuit: function(tool){ - -tool.addTile(`\ -@@@@@@@@ -@@@@@@@@ -@@@@@@@@ -@@@@@@@@ -@@@@@@@@ -@@@@@@@@ -@@@@@@@@ -@@@@@@@@`,{weight:10}) - -tool.addTile(`\ -........ -........ -........ -........ -........ -........ -........ -........`) - -tool.addTile(`\ -........ -..####.. -.#----## -.#----#= -.#----#= -.#----## -..####.. -........`) - -tool.addTile(`\ -@#...... -@###.... -@#-##### -@#-#-#== -@#-#-#== -@#-##### -@###.... -@#......`) - -tool.addTile(`\ -@#...... -##...... -........ -........ -........ -........ -........ -........`) - -tool.addTile(`\ -........ -........ -######## -======== -======== -######## -........ -........`) - -tool.addTile(`\ -..#--#.. -..#--#.. -###--### -==#--#== -==#--#== -###--### -..#--#.. -..#--#..`) - - -tool.addTile(`\ -........ -..####.. -##---### -=#------ -=#------ -##---### -..####.. -........`) - -tool.addTile(`\ -..#==#.. -..#==#.. -..#==### -..#===== -..#===== -..#==### -..#==#.. -..#==#..`) - -tool.addTile(`\ -..#==#.. -...#==#. -#...#==# -=#...#== -==#...#= -#==#...# -.#==#... -..#==#..`) - -tool.addTile(`\ -..#==#.. -...#==#. -....#==# -.....#== -......#= -.......# -........ -........`) - -tool.addColor("@", [55,45,45]) -tool.addColor(".", [30,100,20]) -tool.addColor("-", [180,170,170]) -tool.addColor("=", [125,145,25]) -tool.addColor("#", [10,10,30]) - -}, - -floor_plan: function(tool){ - - -tool.addTile(`\ -......... -......... -......... -......... -......... -......... -......... -......... -.........`,{weight:2}) - -tool.addTile(`\ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@`,) - -tool.addTile(`\ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -######### -######### -######### -......... -......... -.........`) - -tool.addTile(`\ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -@@@###### -@@@###### -@@@###### -@@@###... -@@@###... -@@@###...`) - -tool.addTile(`\ -......... -......... -......... -...###### -...###### -...###### -...###@@@ -...###@@@ -...###@@@`) - -tool.addTile(`\ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -######### -######### -######### -....#.... -....#.... -....#....`) - - -tool.addTile(`\ -....#.... -....#.... -....#.... -....#.... -....#.... -....#.... -....#.... -....#.... -....#....`) - -tool.addTile(`\ -......... -......... -......... -......... -....##### -....#.... -....#.... -....#.... -....#....`) - -tool.addTile(`\ -....#.... -....#.... -....#.... -....#.... -....##### -....#.... -....#.... -....#.... -....#....`) - -tool.addTile(`\ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -####===== -######### -####===== -......... -......... -.........`) - - -tool.addTile(`\ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -=====#### -######### -=====#### -......... -......... -.........`) - -tool.addTile(`\ -@@@@@@@@@ -@@@@@@@@@ -@@@@@@@@@ -========= -######### -========= -......... -......... -.........`) - - -tool.addTile(`\ -@@@@@@@@@ -@#==@@@@@ -@#..=@@@@ -##...=### -##....### -##....### -......... -......... -.........`) - -tool.addTile(`\ -@@@@@@@@@ -@#==@==#@ -@#..=..#@ -##..=..## -##.....## -##.....## -......... -......... -.........`) - -tool.addTile(`\ -....#.... -....#.... -....===.. -.......=. -.......=. -....####. -....#.... -....#.... -....#....`) - - -tool.addTile(`\ -......... -.#######. -.##...##. -.#.#.#.#. -.#..#..#. -.#.#.#.#. -.##...##. -.#######. -.........`) - - -tool.addTile(`\ -......... -......... -...###... -..#...#.. -..#...#.. -..#...#.. -...###... -......... -.........`,{weight:0.2}) - - -tool.addTile(`\ -....#.... -....##### -....#.... -....##### -....#.... -....##### -....#.... -....##### -....#....`) - - -tool.addColor(".", [210,210,190]) -tool.addColor("#", [20,20,30]) -tool.addColor("=", [140,140,140]) -tool.addColor("@", [240,240,235]) - -}, - - -noodle: function(tool){ - -tool.addTile(`\ -....... -####### -======= -------- -======= -####### -.......`) - -tool.addTile(`\ -....... -####### -+++++++ -~~~~~~~ -+++++++ -####### -.......`) - -tool.addTile(`\ -....... -####### -@@@@@@@ -;;;;;;; -@@@@@@@ -####### -.......`) - -tool.addTile(`\ -.#=-=#. -.#=-=## -.#=-=== -.#=---- -.#===== -.###### -.......`) - -tool.addTile(`\ -.#+~+#. -.#+~+## -.#+~+++ -.#+~~~~ -.#+++++ -.###### -.......`) - -tool.addTile(`\ -.#@;@#. -.#@;@## -.#@;@@@ -.#@;;;; -.#@@@@@ -.###### -.......`) - - -tool.addTile(`\ -.#+~+#. -####### -======= -------- -======= -####### -.#+~+#.`) - - -tool.addTile(`\ -.#=-=#. -####### -+++++++ -~~~~~~~ -+++++++ -####### -.#=-=#.`) - -tool.addTile(`\ -.#=-=#. -####### -@@@@@@@ -;;;;;;; -@@@@@@@ -####### -.#=-=#.`) - -tool.addTile(`\ -.#@;@#. -####### -======= -------- -======= -####### -.#@;@#.`) - -tool.addTile(`\ -.#+~+#. -####### -@@@@@@@ -;;;;;;; -@@@@@@@ -####### -.#+~+#.`) - -tool.addTile(`\ -.#@;@#. -####### -+++++++ -~~~~~~~ -+++++++ -####### -.#@;@#.`) - - -tool.addColor(".", [255,255,0]) -tool.addColor("#", [50,50,50]) - -tool.addColor("-", [250,230,230]) -tool.addColor("=", [250,200,200]) - -tool.addColor("~", [230,250,230]) -tool.addColor("+", [200,250,200]) - -tool.addColor(";", [230,230,250]) -tool.addColor("@", [200,200,250]) - - -}, - -noodle3d: function(tool){ - -tool.addTile([`\ -___ -_@_ -___` -,`\ -___ -_@_ -___` -,`\ -___ -_@_ -___` -],{transforms:['rx','rz']}) - -tool.addTile([`\ -___ -_#_ -___` -,`\ -___ -_#_ -___` -,`\ -___ -_#_ -___` -],{transforms:['rx','rz']}) - -tool.addTile([`\ -___ -_@_ -___` -,`\ -___ -_@@ -___` -,`\ -___ -___ -___` -]) - -tool.addTile([`\ -___ -_#_ -___` -,`\ -___ -_## -___` -,`\ -___ -___ -___` -]) - -tool.addMaterial("@", new THREE.MeshLambertMaterial( { color: 0xffffff } )); -tool.addMaterial("#", new THREE.MeshLambertMaterial( { color: 0xff4444 } )); - -}, - -} - -var worker; -var canvas; -var scene; -var camera; -var renderer; -var root; - -function wfcDemo2D(tilesetName){ - - if (worker){ - worker.terminate(); - } - - var tool = new WFCTool2D(); - - tilesets[tilesetName](tool); - - var viewport; - var wave; - - var workerCode = function(){ - var viewport; - var wfc; - var aspectRatio; - var size; - var increment; - var multiply; - - console.log("connect") - - onmessage = function(e) { - console.log(e) - if (e.data.op == "init"){ - wfc = new WFC(e.data.wfcInput); - aspectRatio = e.data.aspectRatio; - size = e.data.initialSize; - increment = e.data.increment; - multiply = e.data.multiply - main(); - } - } - - function main(){ - setTimeout(main,1); - if (!wfc){ - return - } - if (wfc.step()){ - viewport = {x:-size,y:-Math.round(size*aspectRatio),w:size*2,h:Math.round(size*2*aspectRatio)} - wfc.expand([viewport.y,viewport.x],[viewport.y+viewport.h,viewport.x+viewport.w]); - size=Math.ceil((size+increment)*multiply); - } - postMessage({viewport,wave:wfc.readout(/*false*/)}) - } - } - - console.log(tool.getTileFormulae()) - - worker =new Worker(URL.createObjectURL(new Blob(["var WFC="+WFC.toString()+';('+workerCode.toString()+')()'])));// new Worker('worker.js'); - - worker.postMessage({ - op:'init', - wfcInput:tool.generateWFCInput(), - aspectRatio:window.innerHeight/window.innerWidth, - initialSize:8, - increment:0, - multiply:1.5, - }) - - worker.onmessage = function(e){ - viewport = e.data.viewport; - wave = e.data.wave; - } - - if (renderer){ - renderer.domElement.style.display="none"; - } - - if (!canvas){ - canvas = document.createElement("canvas"); - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; - canvas.style.position = "absolute"; - canvas.style.left = "0px"; - canvas.style.top = "0px"; - document.body.appendChild(canvas); - }else{ - var ctx = canvas.getContext('2d'); - ctx.clearRect(0,0,canvas.width,canvas.height); - } - - canvas.style.display="block"; - - function main(){ - requestAnimationFrame(main) - // tool.clearPlotCache(); - if (viewport && wave){ - tool.plotWFCOutput(canvas,viewport,wave) - } - } - main(); -} - - -function wfcDemo3D(tilesetName){ - if (worker){ - worker.terminate(); - } - - var tool = new WFCTool3D(); - tilesets[tilesetName](tool); - - var wave; - - if (canvas){ - canvas.style.display="none"; - } - - if (!scene){ - scene = new THREE.Scene(); - camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); - camera.position.set(10,8,10); - camera.lookAt(0,0,0); - renderer = new THREE.WebGLRenderer(); - - renderer.setSize( window.innerWidth, window.innerHeight ); - renderer.shadowMap.enabled = true; - renderer.domElement.style.position = "absolute"; - renderer.domElement.style.left = "0px"; - renderer.domElement.style.top = "0px"; - - document.body.appendChild( renderer.domElement ); - - var light = new THREE.DirectionalLight( 0xffffff, 1 ); - light.position.set(10,15,5); - light.castShadow = true; - - scene.add( light ); - scene.add( new THREE.AmbientLight( 0xffffff, 0.3 ) ); - - root = new THREE.Object3D(); - - scene.add(root); - - }else{ - while (root.children.length){ - root.children.pop(); - } - } - renderer.domElement.style.display="block"; - - - var workerCode = function(){ - var wfc; - var size; - var increment; - var multiply; - - console.log("connect") - - onmessage = function(e) { - console.log(e) - if (e.data.op == "init"){ - wfc = new WFC(e.data.wfcInput); - size = e.data.initialSize; - increment = e.data.increment; - multiply = e.data.multiply - main(); - } - } - - function main(){ - setTimeout(main,1); - if (!wfc){ - return - } - if (wfc.step()){ - wfc.expand([-size,-size,-size],[size,size,size]); - size=Math.ceil((size+increment)*multiply); - } - postMessage({wave:wfc.readout()}) - } - } - - console.log(tool.getTileFormulae()) - - worker =new Worker(URL.createObjectURL(new Blob(["var WFC="+WFC.toString()+';('+workerCode.toString()+')()'])));// new Worker('worker.js'); - - worker.postMessage({ - op:'init', - wfcInput:tool.generateWFCInput(), - initialSize:5, - increment:0, - multiply:1.5, - }) - - worker.onmessage = function(e){ - wave = e.data.wave; - } - - var frame = 0; - var done = false; - - function main(){ - requestAnimationFrame(main) - if (wave){ - tool.plotWFCOutput(root,wave); - root.rotation.setFromVector3(new THREE.Vector3(0,frame*0.01,0)) - } - renderer.render( scene, camera ); - frame++; - } - main(); - -} - -var menubar = document.createElement("div"); -var title = document.createElement("span"); menubar.appendChild(title); -title.innerHTML = "NDWFC: N-dimensional Wave Function Collapse with infinite canvas" -// title.style.border="1px solid white" -title.style.display="inline-block"; -title.style.marginTop="4px"; -menubar.style.zIndex="1000" -menubar.style.position="absolute"; -menubar.style.left="0px"; -menubar.style.top="0px"; -menubar.style.background="rgba(0,0,0,0.6)" -menubar.style.color="white"; -menubar.style.padding="10px" -menubar.style.fontFamily="sans-serif"; -menubar.style.width=window.innerWidth+"px"; -menubar.style.fontSize="20px" - -var selbox = document.createElement("span"); menubar.appendChild(selbox); -selbox.innerHTML = "Tileset = " -selbox.style.marginRight="30px"; -selbox.style.float="right"; -// selbox.style.border="1px solid rgba(255,255,255,0.8)"; -selbox.style.padding="5px"; -selbox.style.fontSize="16px" - -var select = document.createElement("select"); -for (var k in tilesets){ - var option = document.createElement("option"); - option.value = k; - option.innerHTML = k; - select.appendChild(option); -} -// select.style.position="absolute"; -// select.style.left="20px"; -// select.style.top="20px"; -select.style.background="rgba(0,0,0,0)"; -select.style.color="white" -select.style.fontSize="16px" -select.onchange = function(){ - if (select.value.includes("3d")){ - wfcDemo3D(select.value); - }else{ - wfcDemo2D(select.value); - } -} - -selbox.appendChild(select); - - -document.body.appendChild(menubar) - -select.value="noodle" -wfcDemo2D('noodle'); \ No newline at end of file diff --git a/ndwfc-tools.js b/ndwfc-tools.js deleted file mode 100644 index 4939c28..0000000 --- a/ndwfc-tools.js +++ /dev/null @@ -1,418 +0,0 @@ -var WFCTool2D = function(){ - var tiles = [] - var colors = {} - var weights = [] - var n_prototypes = 0 - var formulae = [] - - - var transformBank = { - cw:function(m){ - var r = []; - for (var i = 0; i < m.length; i++){ - r.push([]) - for (var j = m.length-1; j >= 0; j--){ - r[r.length-1].push(m[j][i]); - } - } - return r; - }, - - fx:function(m){ - var r = []; - for (var i = 0; i < m.length; i++){ - r.push([]) - for (var j = m[0].length-1; j >= 0; j--){ - r[r.length-1].push(m[i][j]); - } - } - return r; - }, - fy:function(m){ - var r = []; - for (var i = m.length-1; i >= 0; i--){ - r.push([]) - for (var j = 0; j < m[i].length; j++){ - r[r.length-1].push(m[i][j]); - } - } - return r; - } - } - - - function equal(m,r){ - for (var i = 0; i < m.length; i++){ - for (var j = 0; j < m[0].length; j++){ - if (m[i][j] != r[i][j]){ - return false; - } - } - } - return true; - } - - function fit(d,a,b){ - if (d == "x"){ - for (var i = 0; i < a.length; i++){ - if (a[i][a[i].length-1] != b[i][0]){ - return false; - } - } - }else if (d == "y"){ - for (var i = 0; i < a[0].length; i++){ - if (a[a.length-1][i] != b[0][i]){ - return false; - } - } - } - return true; - } - - this.addTile = function(s,{transforms="auto",weight=1}={}){ - var t = s.split("\n").map(x=>x.split("")) - tiles.push(t); - formulae.push([ n_prototypes, '', t ]) - weights.push(weight) - - var tests = [] - - if (transforms == "auto"){ - transforms = ['cw','cw+cw','cw+cw+cw'] - } - - for (var i = 0; i < transforms.length; i++){ - var tl = transforms[i].split("+") - var tt = t - for (var j = 0; j < tl.length; j++){ - tt = transformBank[tl[j]](tt); - } - tests.push(tt); - } - for (var i = 0; i < tests.length; i++){ - var ok = true; - for (var j = 0; j < tiles.length; j++){ - if (equal(tests[i],tiles[j])){ - ok = false; - break; - } - } - if (ok){ - tiles.push(tests[i]) - weights.push(weight) - formulae.push([ n_prototypes, transforms[i], tests[i] ]) - } - } - n_prototypes++; - } - - this.addColor = function(symbol, color){ - colors[symbol] = color - } - - this.getTileFormulae = function(){ - return formulae; - } - - this.generateWFCInput = function(){ - var rules = [] - for (var i = 0; i < tiles.length; i++){ - for (var j = 0; j < tiles.length; j++){ - - if (fit("x",tiles[i],tiles[j])){ - rules.push(['x',i,j]) - } - if (fit("y",tiles[i],tiles[j])){ - rules.push(['y',i,j]) - } - } - } - return {weights,rules,nd:2} - } - - var viewportCached = {x:0,y:0,w:-1,h:-1}; - var waveCached = {}; - - this.clearPlotCache = function(){ - waveCached = {}; - } - - this.plotWFCOutput = function(canvas,viewport,wave){ - var ctx = canvas.getContext('2d'); - var w = tiles[0][0].length - var h = tiles[0].length; - - var cw = canvas.width/viewport.w - var ch = canvas.height/viewport.h - - if (viewportCached.x != viewport.x || viewportCached.y != viewport.y || viewportCached.w != viewport.w || viewportCached.h != viewport.h){ - console.log("no cache") - waveCached = {}; - ctx.fillStyle = "black" - ctx.fillRect(0,0,canvas.width,canvas.height) - } - viewportCached = {x:viewport.x,y:viewport.y,w:viewport.w,h:viewport.h}; - - for (var k in wave){ - if (k in waveCached){ - continue - } - waveCached[k] = wave[k] - var [y,x] = k.split(",").map(x=>parseInt(x)); - x = (x-viewport.x)/viewport.w*canvas.width - y = (y-viewport.y)/viewport.h*canvas.height - - var v = wave[k]; - - for (var i = 0; i < h; i++){ - for (var j = 0; j < w; j++){ - - var rgb = [0,0,0]; - if (typeof v === 'number'){ - rgb = colors[tiles[v][i][j]]; - }else{ - for (var ii = 0; ii < tiles.length; ii++){ - rgb[0] += colors[tiles[ii][i][j]][0]*v[ii]; - rgb[1] += colors[tiles[ii][i][j]][1]*v[ii]; - rgb[2] += colors[tiles[ii][i][j]][2]*v[ii]; - } - rgb = rgb.map(Math.round) - } - ctx.fillStyle = `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`; - ctx.fillRect(x+cw*j/w,y+ch*i/h,cw/w+1,ch/h+1); - } - } - } - } - -} - - - -var WFCTool3D = function(){ - var tiles = [] - var materials = {} - var weights = [] - var n_prototypes = 0 - var formulae = [] - - - var transformBank = { - ry:function(m){ - var r = JSON.parse(JSON.stringify(m)); - for (var i = 0; i < m.length; i++){ - for (var j = 0; j < m.length; j++){ - for (var k = 0; k < m.length; k++){ - r[i][j][k] = m[i][m.length-1-k][j]; - } - } - } - return r; - }, - - rx:function(m){ - var r = JSON.parse(JSON.stringify(m)); - for (var i = 0; i < m.length; i++){ - for (var j = 0; j < m.length; j++){ - for (var k = 0; k < m.length; k++){ - r[i][j][k] = m[k][j][m.length-1-i]; - } - } - } - return r; - }, - - rz:function(m){ - var r = JSON.parse(JSON.stringify(m)); - for (var i = 0; i < m.length; i++){ - for (var j = 0; j < m.length; j++){ - for (var k = 0; k < m.length; k++){ - r[i][j][k] = m[m.length-1-j][i][k]; - } - } - } - return r; - }, - - fz:function(m){ - var r = JSON.parse(JSON.stringify(m)); - for (var i = 0; i < m.length; i++){ - for (var j = 0; j < m[0].length; j++){ - for (var k = 0; k < m[0][0].length; k++){ - r[i][j][k] = m[i][j][m.length-1-k]; - } - } - } - return r; - }, - - fx:function(m){ - var r = JSON.parse(JSON.stringify(m)); - for (var i = 0; i < m.length; i++){ - for (var j = 0; j < m[0].length; j++){ - for (var k = 0; k < m[0][0].length; k++){ - r[i][j][k] = m[i][m.length-1-j][k]; - } - } - } - return r; - }, - - fy:function(m){ - - var r = JSON.parse(JSON.stringify(m)); - - for (var i = 0; i < m.length; i++){ - for (var j = 0; j < m[0].length; j++){ - for (var k = 0; k < m[0][0].length; k++){ - r[i][j][k] = m[m.length-1-i][j][k]; - } - } - } - return r; - }, - } - - function equal(m,r){ - for (var i = 0; i < m.length; i++){ - for (var j = 0; j < m[0].length; j++){ - for (var k = 0; k < m[0][0].length; k++){ - if (m[i][j][k] != r[i][j][k]){ - return false; - } - } - } - } - return true; - } - - function fit(d,a,b){ - if (d == "x"){ - for (var i = 0; i < a.length; i++){ - for (var j = 0; j < a[i][0].length; j++){ - if (a[i][a[i].length-1][j] != b[i][0][j]){ - return false; - } - } - } - }else if (d == "y"){ - for (var i = 0; i < a[0].length; i++){ - for (var j = 0; j < a[i][0].length; j++){ - if (a[a.length-1][i][j] != b[0][i][j]){ - return false; - } - } - } - }else if (d == "z"){ - for (var i = 0; i < a.length; i++){ - for (var j = 0; j < a[0].length; j++){ - if (a[i][j][a[i][0].length-1] != b[i][j][0]){ - return false; - } - } - } - } - return true; - } - - this.addTile = function(s,{transforms="auto",weight=1}={}){ - var t = s.map(y=>y.split("\n").map(x=>x.split(""))); - tiles.push(t); - formulae.push([ n_prototypes, '', t ]) - weights.push(weight) - - var tests = [] - - if (transforms == "auto"){ - transforms = ['ry','ry+ry','ry+ry+ry','fy','fy+ry','fy+ry+ry','fy+ry+ry+ry'] - } - - for (var i = 0; i < transforms.length; i++){ - var tl = transforms[i].split("+") - var tt = t - for (var j = 0; j < tl.length; j++){ - tt = transformBank[tl[j]](tt); - } - tests.push(tt); - } - for (var i = 0; i < tests.length; i++){ - var ok = true; - for (var j = 0; j < tiles.length; j++){ - if (equal(tests[i],tiles[j])){ - ok = false; - break; - } - } - if (ok){ - tiles.push(tests[i]) - weights.push(weight) - formulae.push([ n_prototypes, transforms[i], tests[i] ]) - } - } - n_prototypes++; - } - - this.addMaterial = function(symbol, material){ - materials[symbol] = material; - } - - this.getTileFormulae = function(){ - return formulae; - } - - this.generateWFCInput = function(){ - var rules = [] - for (var i = 0; i < tiles.length; i++){ - for (var j = 0; j < tiles.length; j++){ - - if (fit("x",tiles[i],tiles[j])){ - rules.push(['x',i,j]) - } - if (fit("y",tiles[i],tiles[j])){ - rules.push(['y',i,j]) - } - if (fit("z",tiles[i],tiles[j])){ - rules.push(['z',i,j]) - } - } - } - return {weights,rules,nd:3} - } - - /*global describe THREE */ - this.plotWFCOutput = function(root,wave){ - - while (root.children.length){ - root.children.pop(); - } - - var wz = tiles[0][0][0].length - var wx = tiles[0][0].length - var wy = tiles[0].length; - - var geometry = new THREE.BoxGeometry( 1/wx, 1/wy, 1/wz ); - - for (var K in wave){ - var [y,x,z] = K.split(",").map(x=>parseInt(x)); - for (var i = 0; i < wy; i++){ - for (var j = 0; j < wx; j++){ - for (var k = 0; k < wz; k++){ - var material = materials[tiles[wave[K]][i][j][k]] - if (material){ - var cube = new THREE.Mesh(geometry,material); - cube.position.set(x+j/wx,y+i/wy,z+k/wz) - cube.castShadow = true; - cube.receiveShadow = true; - root.add(cube); - } - } - } - } - } - } - -} - -if (typeof module === "object"){ - module.exports = {WFCTool2D,WFCTool3D}; -} \ No newline at end of file diff --git a/ndwfc.js b/ndwfc.js deleted file mode 100644 index fdd1fd4..0000000 --- a/ndwfc.js +++ /dev/null @@ -1,229 +0,0 @@ -var WFC = function({nd,weights,rules,wave}){ - wave = wave || {}; - var wavefront = {} - var n_patterns = weights.length - var wavefront = {} - - function coord(k){ - return k.split(",").map(x=>parseInt(x)) - } - - function entropy(x){ - var one = 0 - for (var i = 0; i < x.length; i++){ - one += x[i]*weights[i] - } - var S = 0 - for (var i = 0; i < x.length; i++){ - var pi = x[i]*weights[i]/one - if (pi != 0){ - S -= pi*Math.log(pi) - } - } - return S - } - - function collapse(x){ - var one = 0 - for (var i = 0; i < x.length; i++){ - one += x[i]*weights[i] - } - var r = Math.random()*one - for (var i = 0; i < x.length; i++){ - r -= x[i]*weights[i] - if (r < 0){ - var y = new Array(x.length).fill(0) - y[i] = 1 - return y - } - } - } - - function neighborable(d,a,b){ - var didx = d.indexOf(1) - if (didx < 0){ - didx = d.indexOf(-1) - ;[a,b] = [b,a] - } - for (var i = 0; i < rules.length; i++){ - if (didx == rules[i][0] || "yxz"[didx] == rules[i][0]){ - if (a == rules[i][1] && b == rules[i][2]){ - return true - } - } - } - return false - } - - function propagate(p){ - var stack = [p] - - while (stack.length){ - p = stack.pop() - - var dirs = [] - for (var i = 0; i < nd; i++){ - var d0 = new Array(nd).fill(0) - d0[i] = -1 - dirs.push(d0) - - var d1 = new Array(nd).fill(0) - d1[i] = 1 - dirs.push(d1) - } - for (var i = 0; i < dirs.length; i++){ - var q = [] - for (var j = 0; j < p.length; j++){ - q.push(p[j]+dirs[i][j]) - } - var x = wavefront[p]; if (x == undefined) {x = wave[p]} - var y = wavefront[q]; if (x == undefined) {x = wave[q]} - - if (typeof y == 'number' || typeof y == 'undefined'){ - continue - - }else if (typeof x == 'number' && typeof y == 'object'){ - - var mod = false - for (var j = 0; j < y.length; j++){ - if (y[j] == 0){ - continue - } - if (y[j] > 0 && !neighborable(dirs[i],x,j)){ - y[j] = 0 - mod = true - } - } - if (mod){ - stack.push(q); - } - - }else if (typeof x == 'object' && typeof y == 'object'){ - var mod = false - for (var j = 0; j < y.length; j++){ - if (y[j] == 0){ - continue - } - var ok = false - for (var k = 0; k < x.length; k++){ - if (x[k] > 0 && y[j] > 0 && neighborable(dirs[i],k,j)){ - ok = true - break - } - } - if (!ok){ - y[j] = 0 - mod = true - } - } - if (mod){ - stack.push(q) - } - - }else{ - throw Error("Invalid propagation parameter",x,y); - } - - } - } - } - - function argmax(vals){ - var mi = -1; - var mv = -Infinity; - for (var i = 0; i < vals.length; i++){ - if (vals[i] > mv){ - mv = vals[i] - mi = i - } - } - return mi - } - - this.readout = function(collapse=true){ - if (!collapse){ - var result = {} - for (var k in wave){ - var oh = Array(n_patterns).fill(0); - oh[wave[k]] = 1; - result[k] = oh; - } - for (var k in wavefront){ - var s = wavefront[k].reduce((a,b) => a + b, 0) - var oh = wavefront[k].map(x=>(s==0?0:x/s)); - result[k] = oh; - } - return result; - } - - var result = {} - for (var k in wavefront){ - if (wavefront[k].reduce((a,b) => a + b, 0) == 1){ - result[k] = argmax(wavefront[k]) - } - } - return Object.assign({},wave,result) - } - - - this.expand = function(xmin, xmax){ - var coords = [[0]] - for (var i = 0; i < xmin.length; i++){ - var cc = [] - for (var x = xmin[i]; x < xmax[i]; x++){ - var c = [] - for (var j = 0; j < coords.length; j++){ - c.push(coords[j].concat(x)) - } - cc = cc.concat(c) - } - coords = cc; - } - coords = coords.map(x=>x.slice(1)).filter(x=>!(x in wave || x in wavefront)) - - coords.map(x=>wavefront[x]=new Array(n_patterns).fill(1)) - for (var k in wave){ - propagate(coord(k)) - } - } - - this.step = function(){ - var min_ent = Infinity - var min_arg = undefined - - for (var k in wavefront){ - var ent = entropy(wavefront[k]) - if (isNaN(ent)){ - for (var k in wavefront){ - wavefront[k]=new Array(n_patterns).fill(1) - } - for (var k in wave){ - propagate(coord(k)) - } - console.log(":(") - return false - } - if (ent == 0){ - continue; - } - ent += (Math.random()-0.5) - if (ent < min_ent){ - min_ent = ent - min_arg = coord(k) - } - } - - if (min_ent == Infinity){ - wave = this.readout(); - wavefront = {}; - return true; - } - wavefront[min_arg] = collapse(wavefront[min_arg]); - propagate(min_arg); - return false; - } -} - -if (typeof module === "object"){ - module.exports = WFC; -} \ No newline at end of file From 0e9ff317d7ad3e8e11bb9b0b078ac403a364c215 Mon Sep 17 00:00:00 2001 From: Ortiz Date: Wed, 4 Sep 2024 01:21:22 +0000 Subject: [PATCH 2/8] Added images for closing and opening --- src/res/images/SideBar-Closed.svg | 1 + src/res/images/SideBar-Open.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 src/res/images/SideBar-Closed.svg create mode 100644 src/res/images/SideBar-Open.svg diff --git a/src/res/images/SideBar-Closed.svg b/src/res/images/SideBar-Closed.svg new file mode 100644 index 0000000..f72848c --- /dev/null +++ b/src/res/images/SideBar-Closed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/res/images/SideBar-Open.svg b/src/res/images/SideBar-Open.svg new file mode 100644 index 0000000..2403d27 --- /dev/null +++ b/src/res/images/SideBar-Open.svg @@ -0,0 +1 @@ + \ No newline at end of file From 2aad96e06a011301412a1d621aa98e25f83737ec Mon Sep 17 00:00:00 2001 From: Ortiz Date: Wed, 4 Sep 2024 01:23:45 +0000 Subject: [PATCH 3/8] Changed code so it adds classes to the elements --- src/js/index.js | 847 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 847 insertions(+) create mode 100644 src/js/index.js diff --git a/src/js/index.js b/src/js/index.js new file mode 100644 index 0000000..cf5bef8 --- /dev/null +++ b/src/js/index.js @@ -0,0 +1,847 @@ +/* global describe WFC WFCTool2D WFCTool3D THREE*/ + +var tilesets = { +circuit_simple: function(tool){ + +tool.addTile(`\ +@@@ +@@@ +@@@`,{weight:5}) + +tool.addTile(`\ +... +... +...`) + +tool.addTile(`\ +@.. +@-= +@..`) + +tool.addTile(`\ +@.. +... +...`) + +tool.addTile(`\ +... +=== +...`) + +tool.addTile(`\ +.-. +=== +.-.`) + + +tool.addTile(`\ +... +=-- +...`) + +tool.addTile(`\ +.=. +.== +.=.`) + +tool.addTile(`\ +.=. +.== +...`) + +tool.addColor("@", [55,45,45]) +tool.addColor(".", [30,100,20]) +tool.addColor("-", [180,170,170]) +tool.addColor("=", [125,145,25]) + +}, + +circuit: function(tool){ + +tool.addTile(`\ +@@@@@@@@ +@@@@@@@@ +@@@@@@@@ +@@@@@@@@ +@@@@@@@@ +@@@@@@@@ +@@@@@@@@ +@@@@@@@@`,{weight:10}) + +tool.addTile(`\ +........ +........ +........ +........ +........ +........ +........ +........`) + +tool.addTile(`\ +........ +..####.. +.#----## +.#----#= +.#----#= +.#----## +..####.. +........`) + +tool.addTile(`\ +@#...... +@###.... +@#-##### +@#-#-#== +@#-#-#== +@#-##### +@###.... +@#......`) + +tool.addTile(`\ +@#...... +##...... +........ +........ +........ +........ +........ +........`) + +tool.addTile(`\ +........ +........ +######## +======== +======== +######## +........ +........`) + +tool.addTile(`\ +..#--#.. +..#--#.. +###--### +==#--#== +==#--#== +###--### +..#--#.. +..#--#..`) + + +tool.addTile(`\ +........ +..####.. +##---### +=#------ +=#------ +##---### +..####.. +........`) + +tool.addTile(`\ +..#==#.. +..#==#.. +..#==### +..#===== +..#===== +..#==### +..#==#.. +..#==#..`) + +tool.addTile(`\ +..#==#.. +...#==#. +#...#==# +=#...#== +==#...#= +#==#...# +.#==#... +..#==#..`) + +tool.addTile(`\ +..#==#.. +...#==#. +....#==# +.....#== +......#= +.......# +........ +........`) + +tool.addColor("@", [55,45,45]) +tool.addColor(".", [30,100,20]) +tool.addColor("-", [180,170,170]) +tool.addColor("=", [125,145,25]) +tool.addColor("#", [10,10,30]) + +}, + +floor_plan: function(tool){ + + +tool.addTile(`\ +......... +......... +......... +......... +......... +......... +......... +......... +.........`,{weight:2}) + +tool.addTile(`\ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@`,) + +tool.addTile(`\ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +######### +######### +######### +......... +......... +.........`) + +tool.addTile(`\ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +@@@###### +@@@###### +@@@###### +@@@###... +@@@###... +@@@###...`) + +tool.addTile(`\ +......... +......... +......... +...###### +...###### +...###### +...###@@@ +...###@@@ +...###@@@`) + +tool.addTile(`\ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +######### +######### +######### +....#.... +....#.... +....#....`) + + +tool.addTile(`\ +....#.... +....#.... +....#.... +....#.... +....#.... +....#.... +....#.... +....#.... +....#....`) + +tool.addTile(`\ +......... +......... +......... +......... +....##### +....#.... +....#.... +....#.... +....#....`) + +tool.addTile(`\ +....#.... +....#.... +....#.... +....#.... +....##### +....#.... +....#.... +....#.... +....#....`) + +tool.addTile(`\ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +####===== +######### +####===== +......... +......... +.........`) + + +tool.addTile(`\ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +=====#### +######### +=====#### +......... +......... +.........`) + +tool.addTile(`\ +@@@@@@@@@ +@@@@@@@@@ +@@@@@@@@@ +========= +######### +========= +......... +......... +.........`) + + +tool.addTile(`\ +@@@@@@@@@ +@#==@@@@@ +@#..=@@@@ +##...=### +##....### +##....### +......... +......... +.........`) + +tool.addTile(`\ +@@@@@@@@@ +@#==@==#@ +@#..=..#@ +##..=..## +##.....## +##.....## +......... +......... +.........`) + +tool.addTile(`\ +....#.... +....#.... +....===.. +.......=. +.......=. +....####. +....#.... +....#.... +....#....`) + + +tool.addTile(`\ +......... +.#######. +.##...##. +.#.#.#.#. +.#..#..#. +.#.#.#.#. +.##...##. +.#######. +.........`) + + +tool.addTile(`\ +......... +......... +...###... +..#...#.. +..#...#.. +..#...#.. +...###... +......... +.........`,{weight:0.2}) + + +tool.addTile(`\ +....#.... +....##### +....#.... +....##### +....#.... +....##### +....#.... +....##### +....#....`) + + +tool.addColor(".", [210,210,190]) +tool.addColor("#", [20,20,30]) +tool.addColor("=", [140,140,140]) +tool.addColor("@", [240,240,235]) + +}, + + +noodle: function(tool){ + +tool.addTile(`\ +....... +####### +======= +------- +======= +####### +.......`) + +tool.addTile(`\ +....... +####### ++++++++ +~~~~~~~ ++++++++ +####### +.......`) + +tool.addTile(`\ +....... +####### +@@@@@@@ +;;;;;;; +@@@@@@@ +####### +.......`) + +tool.addTile(`\ +.#=-=#. +.#=-=## +.#=-=== +.#=---- +.#===== +.###### +.......`) + +tool.addTile(`\ +.#+~+#. +.#+~+## +.#+~+++ +.#+~~~~ +.#+++++ +.###### +.......`) + +tool.addTile(`\ +.#@;@#. +.#@;@## +.#@;@@@ +.#@;;;; +.#@@@@@ +.###### +.......`) + + +tool.addTile(`\ +.#+~+#. +####### +======= +------- +======= +####### +.#+~+#.`) + + +tool.addTile(`\ +.#=-=#. +####### ++++++++ +~~~~~~~ ++++++++ +####### +.#=-=#.`) + +tool.addTile(`\ +.#=-=#. +####### +@@@@@@@ +;;;;;;; +@@@@@@@ +####### +.#=-=#.`) + +tool.addTile(`\ +.#@;@#. +####### +======= +------- +======= +####### +.#@;@#.`) + +tool.addTile(`\ +.#+~+#. +####### +@@@@@@@ +;;;;;;; +@@@@@@@ +####### +.#+~+#.`) + +tool.addTile(`\ +.#@;@#. +####### ++++++++ +~~~~~~~ ++++++++ +####### +.#@;@#.`) + + +tool.addColor(".", [255,255,0]) +tool.addColor("#", [50,50,50]) + +tool.addColor("-", [250,230,230]) +tool.addColor("=", [250,200,200]) + +tool.addColor("~", [230,250,230]) +tool.addColor("+", [200,250,200]) + +tool.addColor(";", [230,230,250]) +tool.addColor("@", [200,200,250]) + + +}, + +noodle3d: function(tool){ + +tool.addTile([`\ +___ +_@_ +___` +,`\ +___ +_@_ +___` +,`\ +___ +_@_ +___` +],{transforms:['rx','rz']}) + +tool.addTile([`\ +___ +_#_ +___` +,`\ +___ +_#_ +___` +,`\ +___ +_#_ +___` +],{transforms:['rx','rz']}) + +tool.addTile([`\ +___ +_@_ +___` +,`\ +___ +_@@ +___` +,`\ +___ +___ +___` +]) + +tool.addTile([`\ +___ +_#_ +___` +,`\ +___ +_## +___` +,`\ +___ +___ +___` +]) + +tool.addMaterial("@", new THREE.MeshLambertMaterial( { color: 0xffffff } )); +tool.addMaterial("#", new THREE.MeshLambertMaterial( { color: 0xff4444 } )); + +}, + +} + +var worker; +var canvas; +var scene; +var camera; +var renderer; +var root; + +function wfcDemo2D(tilesetName){ + + if (worker){ + worker.terminate(); + } + + var tool = new WFCTool2D(); + + tilesets[tilesetName](tool); + + var viewport; + var wave; + + var workerCode = function(){ + var viewport; + var wfc; + var aspectRatio; + var size; + var increment; + var multiply; + + console.log("connect") + + onmessage = function(e) { + console.log(e) + if (e.data.op == "init"){ + wfc = new WFC(e.data.wfcInput); + aspectRatio = e.data.aspectRatio; + size = e.data.initialSize; + increment = e.data.increment; + multiply = e.data.multiply + main(); + } + } + + function main(){ + setTimeout(main,1); + if (!wfc){ + return + } + if (wfc.step()){ + viewport = {x:-size,y:-Math.round(size*aspectRatio),w:size*2,h:Math.round(size*2*aspectRatio)} + wfc.expand([viewport.y,viewport.x],[viewport.y+viewport.h,viewport.x+viewport.w]); + size=Math.ceil((size+increment)*multiply); + } + postMessage({viewport,wave:wfc.readout(/*false*/)}) + } + } + + console.log(tool.getTileFormulae()) + + worker =new Worker(URL.createObjectURL(new Blob(["var WFC="+WFC.toString()+';('+workerCode.toString()+')()'])));// new Worker('worker.js'); + + worker.postMessage({ + op:'init', + wfcInput:tool.generateWFCInput(), + aspectRatio:window.innerHeight/window.innerWidth, + initialSize:8, + increment:0, + multiply:1.5, + }) + + worker.onmessage = function(e){ + viewport = e.data.viewport; + wave = e.data.wave; + } + + if (renderer){ + renderer.domElement.style.display="none"; + } + + if (!canvas){ + canvas = document.createElement("canvas"); + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + canvas.style.position = "absolute"; + canvas.style.left = "0px"; + canvas.style.top = "0px"; + document.body.appendChild(canvas); + }else{ + var ctx = canvas.getContext('2d'); + ctx.clearRect(0,0,canvas.width,canvas.height); + } + + canvas.style.display="block"; + + function main(){ + requestAnimationFrame(main) + // tool.clearPlotCache(); + if (viewport && wave){ + tool.plotWFCOutput(canvas,viewport,wave) + } + } + main(); +} + + +function wfcDemo3D(tilesetName){ + if (worker){ + worker.terminate(); + } + + var tool = new WFCTool3D(); + tilesets[tilesetName](tool); + + var wave; + + if (canvas){ + canvas.style.display="none"; + } + + if (!scene){ + scene = new THREE.Scene(); + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); + camera.position.set(10,8,10); + camera.lookAt(0,0,0); + renderer = new THREE.WebGLRenderer(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.shadowMap.enabled = true; + renderer.domElement.style.position = "absolute"; + renderer.domElement.style.left = "0px"; + renderer.domElement.style.top = "0px"; + + document.body.appendChild( renderer.domElement ); + + var light = new THREE.DirectionalLight( 0xffffff, 1 ); + light.position.set(10,15,5); + light.castShadow = true; + + scene.add( light ); + scene.add( new THREE.AmbientLight( 0xffffff, 0.3 ) ); + + root = new THREE.Object3D(); + + scene.add(root); + + }else{ + while (root.children.length){ + root.children.pop(); + } + } + renderer.domElement.style.display="block"; + + + var workerCode = function(){ + var wfc; + var size; + var increment; + var multiply; + + console.log("connect") + + onmessage = function(e) { + console.log(e) + if (e.data.op == "init"){ + wfc = new WFC(e.data.wfcInput); + size = e.data.initialSize; + increment = e.data.increment; + multiply = e.data.multiply + main(); + } + } + + function main(){ + setTimeout(main,1); + if (!wfc){ + return + } + if (wfc.step()){ + wfc.expand([-size,-size,-size],[size,size,size]); + size=Math.ceil((size+increment)*multiply); + } + postMessage({wave:wfc.readout()}) + } + } + + console.log(tool.getTileFormulae()) + + worker =new Worker(URL.createObjectURL(new Blob(["var WFC="+WFC.toString()+';('+workerCode.toString()+')()'])));// new Worker('worker.js'); + + worker.postMessage({ + op:'init', + wfcInput:tool.generateWFCInput(), + initialSize:5, + increment:0, + multiply:1.5, + }) + + worker.onmessage = function(e){ + wave = e.data.wave; + } + + var frame = 0; + var done = false; + + function main(){ + requestAnimationFrame(main) + if (wave){ + tool.plotWFCOutput(root,wave); + root.rotation.setFromVector3(new THREE.Vector3(0,frame*0.01,0)) + } + renderer.render( scene, camera ); + frame++; + } + main(); + +} + + + +var menubar = document.createElement("div"); +var title = document.createElement("span"); menubar.appendChild(title); + +title.innerHTML = "WFCT: Wave Function Collapses Testing" + +title.classList.add("span-title") +menubar.classList.add("div-menu") + + +var selbox = document.createElement("span"); menubar.appendChild(selbox); +selbox.innerHTML = "Tileset = " +selbox.classList.add("span-select") + +var select = document.createElement("select"); +select.classList.add("type-select"); + +for (var k in tilesets){ + var option = document.createElement("option"); + option.classList.add("select-option"); + + option.value = k; + option.innerHTML = k; + select.appendChild(option); +} + + +select.onchange = function(){ + if (select.value.includes("3d")){ + wfcDemo3D(select.value); + }else{ + wfcDemo2D(select.value); + } +} + +selbox.appendChild(select); + + +document.body.appendChild(menubar) + +select.value="noodle" +wfcDemo2D('noodle'); \ No newline at end of file From 5c9bd948bc63e739136c9234ff247ef92d93dca1 Mon Sep 17 00:00:00 2001 From: Ortiz Date: Wed, 4 Sep 2024 01:24:24 +0000 Subject: [PATCH 4/8] Moved to "./src/js" --- src/js/ndwfc-tools.js | 418 ++++++++++++++++++++++++++++++++++++++++++ src/js/ndwfc.js | 229 +++++++++++++++++++++++ 2 files changed, 647 insertions(+) create mode 100644 src/js/ndwfc-tools.js create mode 100644 src/js/ndwfc.js diff --git a/src/js/ndwfc-tools.js b/src/js/ndwfc-tools.js new file mode 100644 index 0000000..4939c28 --- /dev/null +++ b/src/js/ndwfc-tools.js @@ -0,0 +1,418 @@ +var WFCTool2D = function(){ + var tiles = [] + var colors = {} + var weights = [] + var n_prototypes = 0 + var formulae = [] + + + var transformBank = { + cw:function(m){ + var r = []; + for (var i = 0; i < m.length; i++){ + r.push([]) + for (var j = m.length-1; j >= 0; j--){ + r[r.length-1].push(m[j][i]); + } + } + return r; + }, + + fx:function(m){ + var r = []; + for (var i = 0; i < m.length; i++){ + r.push([]) + for (var j = m[0].length-1; j >= 0; j--){ + r[r.length-1].push(m[i][j]); + } + } + return r; + }, + fy:function(m){ + var r = []; + for (var i = m.length-1; i >= 0; i--){ + r.push([]) + for (var j = 0; j < m[i].length; j++){ + r[r.length-1].push(m[i][j]); + } + } + return r; + } + } + + + function equal(m,r){ + for (var i = 0; i < m.length; i++){ + for (var j = 0; j < m[0].length; j++){ + if (m[i][j] != r[i][j]){ + return false; + } + } + } + return true; + } + + function fit(d,a,b){ + if (d == "x"){ + for (var i = 0; i < a.length; i++){ + if (a[i][a[i].length-1] != b[i][0]){ + return false; + } + } + }else if (d == "y"){ + for (var i = 0; i < a[0].length; i++){ + if (a[a.length-1][i] != b[0][i]){ + return false; + } + } + } + return true; + } + + this.addTile = function(s,{transforms="auto",weight=1}={}){ + var t = s.split("\n").map(x=>x.split("")) + tiles.push(t); + formulae.push([ n_prototypes, '', t ]) + weights.push(weight) + + var tests = [] + + if (transforms == "auto"){ + transforms = ['cw','cw+cw','cw+cw+cw'] + } + + for (var i = 0; i < transforms.length; i++){ + var tl = transforms[i].split("+") + var tt = t + for (var j = 0; j < tl.length; j++){ + tt = transformBank[tl[j]](tt); + } + tests.push(tt); + } + for (var i = 0; i < tests.length; i++){ + var ok = true; + for (var j = 0; j < tiles.length; j++){ + if (equal(tests[i],tiles[j])){ + ok = false; + break; + } + } + if (ok){ + tiles.push(tests[i]) + weights.push(weight) + formulae.push([ n_prototypes, transforms[i], tests[i] ]) + } + } + n_prototypes++; + } + + this.addColor = function(symbol, color){ + colors[symbol] = color + } + + this.getTileFormulae = function(){ + return formulae; + } + + this.generateWFCInput = function(){ + var rules = [] + for (var i = 0; i < tiles.length; i++){ + for (var j = 0; j < tiles.length; j++){ + + if (fit("x",tiles[i],tiles[j])){ + rules.push(['x',i,j]) + } + if (fit("y",tiles[i],tiles[j])){ + rules.push(['y',i,j]) + } + } + } + return {weights,rules,nd:2} + } + + var viewportCached = {x:0,y:0,w:-1,h:-1}; + var waveCached = {}; + + this.clearPlotCache = function(){ + waveCached = {}; + } + + this.plotWFCOutput = function(canvas,viewport,wave){ + var ctx = canvas.getContext('2d'); + var w = tiles[0][0].length + var h = tiles[0].length; + + var cw = canvas.width/viewport.w + var ch = canvas.height/viewport.h + + if (viewportCached.x != viewport.x || viewportCached.y != viewport.y || viewportCached.w != viewport.w || viewportCached.h != viewport.h){ + console.log("no cache") + waveCached = {}; + ctx.fillStyle = "black" + ctx.fillRect(0,0,canvas.width,canvas.height) + } + viewportCached = {x:viewport.x,y:viewport.y,w:viewport.w,h:viewport.h}; + + for (var k in wave){ + if (k in waveCached){ + continue + } + waveCached[k] = wave[k] + var [y,x] = k.split(",").map(x=>parseInt(x)); + x = (x-viewport.x)/viewport.w*canvas.width + y = (y-viewport.y)/viewport.h*canvas.height + + var v = wave[k]; + + for (var i = 0; i < h; i++){ + for (var j = 0; j < w; j++){ + + var rgb = [0,0,0]; + if (typeof v === 'number'){ + rgb = colors[tiles[v][i][j]]; + }else{ + for (var ii = 0; ii < tiles.length; ii++){ + rgb[0] += colors[tiles[ii][i][j]][0]*v[ii]; + rgb[1] += colors[tiles[ii][i][j]][1]*v[ii]; + rgb[2] += colors[tiles[ii][i][j]][2]*v[ii]; + } + rgb = rgb.map(Math.round) + } + ctx.fillStyle = `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`; + ctx.fillRect(x+cw*j/w,y+ch*i/h,cw/w+1,ch/h+1); + } + } + } + } + +} + + + +var WFCTool3D = function(){ + var tiles = [] + var materials = {} + var weights = [] + var n_prototypes = 0 + var formulae = [] + + + var transformBank = { + ry:function(m){ + var r = JSON.parse(JSON.stringify(m)); + for (var i = 0; i < m.length; i++){ + for (var j = 0; j < m.length; j++){ + for (var k = 0; k < m.length; k++){ + r[i][j][k] = m[i][m.length-1-k][j]; + } + } + } + return r; + }, + + rx:function(m){ + var r = JSON.parse(JSON.stringify(m)); + for (var i = 0; i < m.length; i++){ + for (var j = 0; j < m.length; j++){ + for (var k = 0; k < m.length; k++){ + r[i][j][k] = m[k][j][m.length-1-i]; + } + } + } + return r; + }, + + rz:function(m){ + var r = JSON.parse(JSON.stringify(m)); + for (var i = 0; i < m.length; i++){ + for (var j = 0; j < m.length; j++){ + for (var k = 0; k < m.length; k++){ + r[i][j][k] = m[m.length-1-j][i][k]; + } + } + } + return r; + }, + + fz:function(m){ + var r = JSON.parse(JSON.stringify(m)); + for (var i = 0; i < m.length; i++){ + for (var j = 0; j < m[0].length; j++){ + for (var k = 0; k < m[0][0].length; k++){ + r[i][j][k] = m[i][j][m.length-1-k]; + } + } + } + return r; + }, + + fx:function(m){ + var r = JSON.parse(JSON.stringify(m)); + for (var i = 0; i < m.length; i++){ + for (var j = 0; j < m[0].length; j++){ + for (var k = 0; k < m[0][0].length; k++){ + r[i][j][k] = m[i][m.length-1-j][k]; + } + } + } + return r; + }, + + fy:function(m){ + + var r = JSON.parse(JSON.stringify(m)); + + for (var i = 0; i < m.length; i++){ + for (var j = 0; j < m[0].length; j++){ + for (var k = 0; k < m[0][0].length; k++){ + r[i][j][k] = m[m.length-1-i][j][k]; + } + } + } + return r; + }, + } + + function equal(m,r){ + for (var i = 0; i < m.length; i++){ + for (var j = 0; j < m[0].length; j++){ + for (var k = 0; k < m[0][0].length; k++){ + if (m[i][j][k] != r[i][j][k]){ + return false; + } + } + } + } + return true; + } + + function fit(d,a,b){ + if (d == "x"){ + for (var i = 0; i < a.length; i++){ + for (var j = 0; j < a[i][0].length; j++){ + if (a[i][a[i].length-1][j] != b[i][0][j]){ + return false; + } + } + } + }else if (d == "y"){ + for (var i = 0; i < a[0].length; i++){ + for (var j = 0; j < a[i][0].length; j++){ + if (a[a.length-1][i][j] != b[0][i][j]){ + return false; + } + } + } + }else if (d == "z"){ + for (var i = 0; i < a.length; i++){ + for (var j = 0; j < a[0].length; j++){ + if (a[i][j][a[i][0].length-1] != b[i][j][0]){ + return false; + } + } + } + } + return true; + } + + this.addTile = function(s,{transforms="auto",weight=1}={}){ + var t = s.map(y=>y.split("\n").map(x=>x.split(""))); + tiles.push(t); + formulae.push([ n_prototypes, '', t ]) + weights.push(weight) + + var tests = [] + + if (transforms == "auto"){ + transforms = ['ry','ry+ry','ry+ry+ry','fy','fy+ry','fy+ry+ry','fy+ry+ry+ry'] + } + + for (var i = 0; i < transforms.length; i++){ + var tl = transforms[i].split("+") + var tt = t + for (var j = 0; j < tl.length; j++){ + tt = transformBank[tl[j]](tt); + } + tests.push(tt); + } + for (var i = 0; i < tests.length; i++){ + var ok = true; + for (var j = 0; j < tiles.length; j++){ + if (equal(tests[i],tiles[j])){ + ok = false; + break; + } + } + if (ok){ + tiles.push(tests[i]) + weights.push(weight) + formulae.push([ n_prototypes, transforms[i], tests[i] ]) + } + } + n_prototypes++; + } + + this.addMaterial = function(symbol, material){ + materials[symbol] = material; + } + + this.getTileFormulae = function(){ + return formulae; + } + + this.generateWFCInput = function(){ + var rules = [] + for (var i = 0; i < tiles.length; i++){ + for (var j = 0; j < tiles.length; j++){ + + if (fit("x",tiles[i],tiles[j])){ + rules.push(['x',i,j]) + } + if (fit("y",tiles[i],tiles[j])){ + rules.push(['y',i,j]) + } + if (fit("z",tiles[i],tiles[j])){ + rules.push(['z',i,j]) + } + } + } + return {weights,rules,nd:3} + } + + /*global describe THREE */ + this.plotWFCOutput = function(root,wave){ + + while (root.children.length){ + root.children.pop(); + } + + var wz = tiles[0][0][0].length + var wx = tiles[0][0].length + var wy = tiles[0].length; + + var geometry = new THREE.BoxGeometry( 1/wx, 1/wy, 1/wz ); + + for (var K in wave){ + var [y,x,z] = K.split(",").map(x=>parseInt(x)); + for (var i = 0; i < wy; i++){ + for (var j = 0; j < wx; j++){ + for (var k = 0; k < wz; k++){ + var material = materials[tiles[wave[K]][i][j][k]] + if (material){ + var cube = new THREE.Mesh(geometry,material); + cube.position.set(x+j/wx,y+i/wy,z+k/wz) + cube.castShadow = true; + cube.receiveShadow = true; + root.add(cube); + } + } + } + } + } + } + +} + +if (typeof module === "object"){ + module.exports = {WFCTool2D,WFCTool3D}; +} \ No newline at end of file diff --git a/src/js/ndwfc.js b/src/js/ndwfc.js new file mode 100644 index 0000000..fdd1fd4 --- /dev/null +++ b/src/js/ndwfc.js @@ -0,0 +1,229 @@ +var WFC = function({nd,weights,rules,wave}){ + wave = wave || {}; + var wavefront = {} + var n_patterns = weights.length + var wavefront = {} + + function coord(k){ + return k.split(",").map(x=>parseInt(x)) + } + + function entropy(x){ + var one = 0 + for (var i = 0; i < x.length; i++){ + one += x[i]*weights[i] + } + var S = 0 + for (var i = 0; i < x.length; i++){ + var pi = x[i]*weights[i]/one + if (pi != 0){ + S -= pi*Math.log(pi) + } + } + return S + } + + function collapse(x){ + var one = 0 + for (var i = 0; i < x.length; i++){ + one += x[i]*weights[i] + } + var r = Math.random()*one + for (var i = 0; i < x.length; i++){ + r -= x[i]*weights[i] + if (r < 0){ + var y = new Array(x.length).fill(0) + y[i] = 1 + return y + } + } + } + + function neighborable(d,a,b){ + var didx = d.indexOf(1) + if (didx < 0){ + didx = d.indexOf(-1) + ;[a,b] = [b,a] + } + for (var i = 0; i < rules.length; i++){ + if (didx == rules[i][0] || "yxz"[didx] == rules[i][0]){ + if (a == rules[i][1] && b == rules[i][2]){ + return true + } + } + } + return false + } + + function propagate(p){ + var stack = [p] + + while (stack.length){ + p = stack.pop() + + var dirs = [] + for (var i = 0; i < nd; i++){ + var d0 = new Array(nd).fill(0) + d0[i] = -1 + dirs.push(d0) + + var d1 = new Array(nd).fill(0) + d1[i] = 1 + dirs.push(d1) + } + for (var i = 0; i < dirs.length; i++){ + var q = [] + for (var j = 0; j < p.length; j++){ + q.push(p[j]+dirs[i][j]) + } + var x = wavefront[p]; if (x == undefined) {x = wave[p]} + var y = wavefront[q]; if (x == undefined) {x = wave[q]} + + if (typeof y == 'number' || typeof y == 'undefined'){ + continue + + }else if (typeof x == 'number' && typeof y == 'object'){ + + var mod = false + for (var j = 0; j < y.length; j++){ + if (y[j] == 0){ + continue + } + if (y[j] > 0 && !neighborable(dirs[i],x,j)){ + y[j] = 0 + mod = true + } + } + if (mod){ + stack.push(q); + } + + }else if (typeof x == 'object' && typeof y == 'object'){ + var mod = false + for (var j = 0; j < y.length; j++){ + if (y[j] == 0){ + continue + } + var ok = false + for (var k = 0; k < x.length; k++){ + if (x[k] > 0 && y[j] > 0 && neighborable(dirs[i],k,j)){ + ok = true + break + } + } + if (!ok){ + y[j] = 0 + mod = true + } + } + if (mod){ + stack.push(q) + } + + }else{ + throw Error("Invalid propagation parameter",x,y); + } + + } + } + } + + function argmax(vals){ + var mi = -1; + var mv = -Infinity; + for (var i = 0; i < vals.length; i++){ + if (vals[i] > mv){ + mv = vals[i] + mi = i + } + } + return mi + } + + this.readout = function(collapse=true){ + if (!collapse){ + var result = {} + for (var k in wave){ + var oh = Array(n_patterns).fill(0); + oh[wave[k]] = 1; + result[k] = oh; + } + for (var k in wavefront){ + var s = wavefront[k].reduce((a,b) => a + b, 0) + var oh = wavefront[k].map(x=>(s==0?0:x/s)); + result[k] = oh; + } + return result; + } + + var result = {} + for (var k in wavefront){ + if (wavefront[k].reduce((a,b) => a + b, 0) == 1){ + result[k] = argmax(wavefront[k]) + } + } + return Object.assign({},wave,result) + } + + + this.expand = function(xmin, xmax){ + var coords = [[0]] + for (var i = 0; i < xmin.length; i++){ + var cc = [] + for (var x = xmin[i]; x < xmax[i]; x++){ + var c = [] + for (var j = 0; j < coords.length; j++){ + c.push(coords[j].concat(x)) + } + cc = cc.concat(c) + } + coords = cc; + } + coords = coords.map(x=>x.slice(1)).filter(x=>!(x in wave || x in wavefront)) + + coords.map(x=>wavefront[x]=new Array(n_patterns).fill(1)) + for (var k in wave){ + propagate(coord(k)) + } + } + + this.step = function(){ + var min_ent = Infinity + var min_arg = undefined + + for (var k in wavefront){ + var ent = entropy(wavefront[k]) + if (isNaN(ent)){ + for (var k in wavefront){ + wavefront[k]=new Array(n_patterns).fill(1) + } + for (var k in wave){ + propagate(coord(k)) + } + console.log(":(") + return false + } + if (ent == 0){ + continue; + } + ent += (Math.random()-0.5) + if (ent < min_ent){ + min_ent = ent + min_arg = coord(k) + } + } + + if (min_ent == Infinity){ + wave = this.readout(); + wavefront = {}; + return true; + } + wavefront[min_arg] = collapse(wavefront[min_arg]); + propagate(min_arg); + return false; + } +} + +if (typeof module === "object"){ + module.exports = WFC; +} \ No newline at end of file From 9febbaab8d414f5b40afb6a21bb966aab84d6ccd Mon Sep 17 00:00:00 2001 From: Ortiz Date: Wed, 4 Sep 2024 01:25:04 +0000 Subject: [PATCH 5/8] Created to handle Button onClick --- src/js/button.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/js/button.js diff --git a/src/js/button.js b/src/js/button.js new file mode 100644 index 0000000..c3c9746 --- /dev/null +++ b/src/js/button.js @@ -0,0 +1,15 @@ +var currentState = false + +function toggleFunc(){ + var imagetoggle = document.getElementsByClassName("image-toggle")[0] + var menudiv = document.getElementsByClassName("div-menu")[0] + if (currentState == false){ + imagetoggle.src = "./src/res/images/SideBar-Closed.svg"; + menudiv.style.display = "none" + currentState = true + }else{ + imagetoggle.src = "./src/res/images/SideBar-Open.svg"; + menudiv.style.display = null + currentState = false + }; +} \ No newline at end of file From 3324b0649f358b941464d3bc49904982c6a5e9f5 Mon Sep 17 00:00:00 2001 From: Ortiz Date: Wed, 4 Sep 2024 01:25:48 +0000 Subject: [PATCH 6/8] Created and Updated style.css --- src/css/style.css | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/css/style.css diff --git a/src/css/style.css b/src/css/style.css new file mode 100644 index 0000000..36dd651 --- /dev/null +++ b/src/css/style.css @@ -0,0 +1,67 @@ +body{ + overflow: hidden; +} + +.button-toggle{ + z-Index: 3; + + position: absolute; + left: 10px; + top: 15px; + + background: rgb(0 0 0); + color: white; + + width: 10px; + height: 10px; + padding: 10px; + aspect-ratio: 1; + + border-radius: 100%; + border: 2px solid white; +} + +.image-toggle{ + width: 100%; + height: 100%; + aspect-ratio: 1; +} + +.span-title{ + display: inline-block; + margin-top:4px; + margin-left: 30px; +} + +.div-menu{ + z-Index: 2; + + position: absolute; + left: 0; + top: 0; + + background: rgba(0,0,0,0.6); + color: white; + + width: 100%; + padding:10px; + font-family: Verdana, Geneva, Tahoma, sans-serif; + font-size: 20px; +} + +.span-select{ + margin-right: 30px; + float: right; + padding: 5px; + font-size: 16px; +} + +.type-select{ + background-color: rgba(0,0,0,0); + color: white; + font-size: 16px; +} + +.select-option{ + color: black; +} \ No newline at end of file From c4cb6b6c1b6ad51e2078257894d9d270f2cc98df Mon Sep 17 00:00:00 2001 From: Ortiz Date: Wed, 4 Sep 2024 01:26:38 +0000 Subject: [PATCH 7/8] Added stylesheet and button.js to the code --- index.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/index.html b/index.html index 9dbb076..d4af8a7 100644 --- a/index.html +++ b/index.html @@ -5,21 +5,21 @@ + - + - - - - + + + + - + From 410bedeab10eb285b3888ace94f1d00f7ccfb564 Mon Sep 17 00:00:00 2001 From: Ortiz Date: Wed, 4 Sep 2024 01:33:03 +0000 Subject: [PATCH 8/8] Changed README.md to better explain Fork objectives. --- README.md | 197 ++++-------------------------------------------------- 1 file changed, 12 insertions(+), 185 deletions(-) diff --git a/README.md b/README.md index 4bee004..ffdb874 100644 --- a/README.md +++ b/README.md @@ -1,189 +1,16 @@ -# NDWFC +# WFCT -A Wave Function Collapse implementation with infinite canvas in arbitrary number of dimensions. +Wave Function Collapse Testing is a fork of [NDWFC](https://github.com/LingDong-/ndwfc). +At the moment, it only implements some small quality-of-life improvements to the code, but there are plans to add new types of tilesets. -### [Online Demo](https://ndwfc.glitch.me/) +### [Original Project Demo](https://ndwfc.glitch.me/) - Based on the algorithm of [the original Wave Function Collapse](https://github.com/mxgmn/WaveFunctionCollapse). -- For the browser and node.js -- Works with web worker multithreading -- Infinitely expandable canvas -- 2D/3D/ND - - - - - - - - -## Installation - -Browser - -```html - - - - - -``` - -Node.js - -```JavaScript -// the main library -const WFC = require('./ndwfc'); - -// optional helpful tools -const {WFCTool2D,WFCTool3D} = require('./ndwfc-tools'); - -``` - -## Usage - -The main library, `ndwfc.js`, doesn't make any assumption about what you're trying to generate. It is an abstracted implementation of the WFC algorithm, while `ndwfc-tools.js` provide helpful functions for practical usage such as generating tiled textures or models. - -Below are some sample code, but be sure to check out `index.js` for detailed usage and examples. - -### Basics - -```JavaScript -var nd = 2; // number of dimensions (2, 3, etc.) -var weights = [1, 1, 1] // weight for each type of tile - // this also implies the total number of tiles - // here all weights are equal, so the tiles will - // generate at equal probability - -// the rules is an array of 3-tuples. -// for each rule, the first element specifies the axis, and the 2nd and 3rd -// specifies what tiles can go next to each other on that axis - -var rules = [ - ['x',0,1], // 0th tile can be placed to the left of 1st tile - ['x',1,0], // 1st tile can also be placed to the left of 0th tile - ['y',1,2], - // if you have more than 3 dimensions, the axis can be specified - // using integers instead of 'x', 'y' and 'z'. - // in fact 'y' is an alias of 0th axis, 'x' the 1st, and 'z' the 2nd - ... - ... -] - -var wfc = new WFC({nd, weights, rules}); // initialize the wfc! - - -// define a region of interest inside which you want tiles to be generated -// by passing two corners of the bounding box/cube/hypercube -var size = 5; -wfc.expand([-size,-size],[size,size]); - -// the main loop -// subsitute with setTimeout/requestAnimationFrame/WebWorker depending on usage - -while (true){ - var done = wfc.step(); // advance 1 step, filling at least 1 new coordinate. - // step() returns true if the region of interest has - // been entirely filled - - if (done){ - size += 5 // all space filled, time to expand more - wfc.expand([-size,-size],[size,size]); // newly marked area will begin to - // be generated in the next step() - } - - console.log(wfc.readout()); - // ^ get the current result, an object mapping coordinate to tile index - // something like {'1,2':0, '2,2':2, '3,1':1, ...} - - // use wfc.readout(false) to read the result as probability distribution, - // something like {'1,2',[1,0,0], '2,2':[0.3,0.2,0.5], ...} - -} -``` - -### Using the 2D/3D tile helpers - -`ndwfc-tools.js` provides helpers for generating 2D and 3D content. You can use strings of characters to describe the semantics of your tiles, and the tool can figure out what can go next to what and generate the rules for you. Though the tool is also capable of simple visualization using canvas (2D) or three.js (3D), you can just grab the result from `wfc.readout()` and plug in your own assets such as image files and 3D models to produce the visuals you want. - -```JavaScript - -// initialize the 2d tool -var tool = new WFCTool2D(); - -// add an 3x3 "L" shaped tile -tool.addTile(`\ -.@. -.@@ -...`) -// ^ all rotated versions of the tile will also be added, -// unless you specify otherwise (see below) - -// add an 3x3 "I" shaped tile -tool.addTile(`\ -.@. -.@. -.@.`, -{transformations:['cw']}) -// ^ for this tile, we only need itself and a clockwise 90 deg rotated version -// for 2D tiles, transformations can include 'cw', 'fx' (flip x) and 'fy' (flip y). -// you can also combine them using '+' -// e.g. for anti-clockwise 90 deg rotation you can do 'cw+cw+cw' -// duplicates will be detected and will not be added multiple times. - -// add a plain tile -tool.addTile(`\ -... -... -...`, -{transformations:[],weight:0.1}) -// you can specify the weight of the tile. higher the weight, -// more often it will appear. default is 1. - - -// rules are automatically generated based on this logic: -// only tiles with an identical edge can go next to each other, like so: -// .@. ... -// .@@ + @@@ -// ... ... -// the tiles below can NOT go next to each other: -// .@. ... -// .@@ + ... -// ... ... -// because the right edge of 1st tile does not match left edge of the 2nd -// same for vertical axis. - - -// define the color of the symbols. -// this is used only to quickly visualize the results -// you won't need this if you're using your own assets -tool.addColor("@", [255,0,0]) -tool.addColor(".", [0,255,255]) - - -// print a summary of automatically generated version of the tiles -// you'll need this if you're using your own assets -// each formula is a 3-tuple: -// the first element is the original index (the order you called `addTile`) -// the second element is the transformations applied (e.g. 'fx+cw') -// the third element is the transformed version -console.log(tool.getTileFormulae()); - -// this generates all the input which you can directly pass to WFC -var wfcInput = tool.generateWFCInput(); -var wfc = new WFC(wfcInput); - -... -... // see previous section on how to use wfc -... - -// visualize the output on a HTML canvas -var canvas = document.createElement("canvas"); - -var viewport = {x:0,y:0,w:10,h:10}; // the region you want to visualize -tool.plotWFCOoutput(canvas, viewport, wfc.readout()); // plot it! - - -``` - -`WFCTool3D` is similar to `WFCTool2D`, see `index.js` for usage example. \ No newline at end of file +- Infinitely expandable canvas. +- 2D/3D/ND support. + +#### Gifs Showing the site: + + + +