# HG changeset patch # User Steve Losh # Date 1456660310 0 # Node ID e2b8f5dc9ae4613fe444c6c8c40edfc4097edd69 # Parent 37c769f2a211b7a628e4519e5757462b637484f5 Just Use Make™ diff -r 37c769f2a211 -r e2b8f5dc9ae4 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sun Feb 28 11:51:50 2016 +0000 @@ -0,0 +1,26 @@ +.PHONY: all clean generate regen serve deploy + +wisps := $(shell ffind --literal '.wisp') +javascripts := $(subst .wisp,.js,$(wisps)) + +all: media/js/terrain1.js + +media/js/wisp/%.js: media/js/wisp/%.wisp + cat $< | wisp > $@ + +media/js/terrain1.js: $(javascripts) + browserify media/js/wisp/terrain1.js -o $@ + +clean: + rm -rf ./deploy + +generate: all + hyde -g -s . + +serve: + hyde -w -s . -k + +regen: clean generate + +deploy: generate + rsync -avz ./deploy/ sl:/var/www/stevelosh.com diff -r 37c769f2a211 -r e2b8f5dc9ae4 content/blog/2016/02/midpoint-displacement.html --- a/content/blog/2016/02/midpoint-displacement.html Fri Feb 19 19:48:12 2016 +0000 +++ b/content/blog/2016/02/midpoint-displacement.html Sun Feb 28 11:51:50 2016 +0000 @@ -13,10 +13,6 @@ - - {% endblock extra_js %} {% block article %} diff -r 37c769f2a211 -r e2b8f5dc9ae4 fabfile.py --- a/fabfile.py Fri Feb 19 19:48:12 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -from fabric.api import * -import os -import fabric.contrib.project as project - -PROD = 'sl' -DEST_PATH = '/var/www/stevelosh.com/' -ROOT_PATH = os.path.abspath(os.path.dirname(__file__)) -DEPLOY_PATH = os.path.join(ROOT_PATH, 'deploy') - -def clean(): - local('rm -rf ./deploy') - -def generate(): - local('hyde -g -s .') - -def regen(): - clean() - generate() - -def serve(): - local('hyde -w -s . -k') - -def reserve(): - regen() - serve() - -def smush(): - local('smusher ./media/images') - -@hosts(PROD) -def publish(): - regen() - project.rsync_project( - remote_dir=DEST_PATH, - local_dir=DEPLOY_PATH.rstrip('/') + '/', - delete=True - ) diff -r 37c769f2a211 -r e2b8f5dc9ae4 media/js/terrain1.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/media/js/terrain1.js Sun Feb 28 11:51:50 2016 +0000 @@ -0,0 +1,523 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o elø1 ? (function () { + return minø1 = elø1; + })() : void 0; + }.call(this)); + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + return function () { + var spanø1 = maxø1 - minø1; + return function () { + var G__2ø1 = hm.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__2ø1 ? (function () { + hm[iø1] = (hm[iø1] - minø1) / spanø1; + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this); + }.call(this); + }.call(this); +}; +var zeroHeightmap = exports.zeroHeightmap = function zeroHeightmap(heightmap) { + (function () { + var G__3ø1 = heightmap.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__3ø1 ? (function () { + heightmap[iø1] = 0; + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + return heightmap; +}; +var makeHeightmap = exports.makeHeightmap = function makeHeightmap(exponent) { + return function () { + var resolutionø1 = 1 + Math.pow(2, exponent); + l('Creating ' + resolutionø1 + ' by ' + resolutionø1 + ' heightmap...'); + var heightmap = new Array(resolutionø1 * resolutionø1); + heightmap.resolution = resolutionø1; + heightmap.exponent = exponent; + heightmap.last = resolutionø1 - 1; + return zeroHeightmap(heightmap); + }.call(this); +}; +var randomNoise = exports.randomNoise = function randomNoise(heightmap) { + return function () { + var G__4ø1 = heightmap.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__4ø1 ? (function () { + heightmap[iø1] = rand(); + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this); +}; +var mpdInitCorners = exports.mpdInitCorners = function mpdInitCorners(heightmap) { + heightmap[0 * heightmap.resolution + 0] = rand(); + heightmap[heightmap.last * heightmap.resolution + 0] = rand(); + heightmap[0 * heightmap.resolution + heightmap.last] = rand(); + return heightmap[heightmap.last * heightmap.resolution + heightmap.last] = rand(); +}; +var mpdDisplace = exports.mpdDisplace = function mpdDisplace(heightmap, lx, rx, by, ty, spread) { + return function () { + var cxø1 = midpoint(lx, rx); + var cyø1 = midpoint(by, ty); + var bottomLeftø1 = heightmap[by * heightmap.resolution + lx]; + var bottomRightø1 = heightmap[by * heightmap.resolution + rx]; + var topLeftø1 = heightmap[ty * heightmap.resolution + lx]; + var topRightø1 = heightmap[ty * heightmap.resolution + rx]; + var topø1 = average2(topLeftø1, topRightø1); + var leftø1 = average2(bottomLeftø1, topLeftø1); + var bottomø1 = average2(bottomLeftø1, bottomRightø1); + var rightø1 = average2(bottomRightø1, topRightø1); + var centerø1 = average4(topø1, leftø1, bottomø1, rightø1); + heightmap[by * heightmap.resolution + cxø1] = jitter(bottomø1, spread); + heightmap[ty * heightmap.resolution + cxø1] = jitter(topø1, spread); + heightmap[cyø1 * heightmap.resolution + lx] = jitter(leftø1, spread); + heightmap[cyø1 * heightmap.resolution + rx] = jitter(rightø1, spread); + return heightmap[cyø1 * heightmap.resolution + cxø1] = jitter(centerø1, spread); + }.call(this); +}; +var midpointDisplacement = exports.midpointDisplacement = function midpointDisplacement(heightmap) { + mpdInitCorners(heightmap); + (function loop() { + var recur = loop; + var iterø1 = 0; + var spreadø1 = 0.3; + do { + recur = iterø1 < heightmap.exponent ? (function () { + (function () { + var chunksø1 = Math.pow(2, iterø1); + var chunkWidthø1 = (heightmap.resolution - 1) / chunksø1; + return function () { + var G__5ø1 = chunksø1; + return function () { + var G__6ø1 = G__5ø1; + return function loop() { + var recur = loop; + var xchunkø1 = 0; + do { + recur = xchunkø1 < G__6ø1 ? (function () { + (function () { + var G__7ø1 = G__5ø1; + return function loop() { + var recur = loop; + var ychunkø1 = 0; + do { + recur = ychunkø1 < G__7ø1 ? (function () { + (function () { + var leftXø1 = chunkWidthø1 * xchunkø1; + var rightXø1 = leftXø1 + chunkWidthø1; + var bottomYø1 = chunkWidthø1 * ychunkø1; + var topYø1 = bottomYø1 + chunkWidthø1; + return mpdDisplace(heightmap, leftXø1, rightXø1, bottomYø1, topYø1, spreadø1); + }.call(this)); + return loop[0] = 1 + ychunkø1, loop; + })() : void 0; + } while (ychunkø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + return loop[0] = 1 + xchunkø1, loop; + })() : void 0; + } while (xchunkø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this); + }.call(this); + }.call(this)); + return loop[0] = 1 + iterø1, loop[1] = spreadø1 * 0.5, loop; + })() : void 0; + } while (iterø1 = loop[0], spreadø1 = loop[1], recur === loop); + return recur; + }.call(this)); + return normalize(heightmap); +}; +var midpointDisplacementFinal = exports.midpointDisplacementFinal = function midpointDisplacementFinal(heightmap) { + mpdInitCorners(heightmap); + (function loop() { + var recur = loop; + var iterø1 = 0; + var spreadø1 = 0 + $('#input-starting-spread').val(); + do { + recur = iterø1 < heightmap.exponent ? (function () { + (function () { + var chunksø1 = Math.pow(2, iterø1); + var chunkWidthø1 = (heightmap.resolution - 1) / chunksø1; + return function () { + var G__8ø1 = chunksø1; + return function () { + var G__9ø1 = G__8ø1; + return function loop() { + var recur = loop; + var xchunkø1 = 0; + do { + recur = xchunkø1 < G__9ø1 ? (function () { + (function () { + var G__10ø1 = G__8ø1; + return function loop() { + var recur = loop; + var ychunkø1 = 0; + do { + recur = ychunkø1 < G__10ø1 ? (function () { + (function () { + var leftXø1 = chunkWidthø1 * xchunkø1; + var rightXø1 = leftXø1 + chunkWidthø1; + var bottomYø1 = chunkWidthø1 * ychunkø1; + var topYø1 = bottomYø1 + chunkWidthø1; + return mpdDisplace(heightmap, leftXø1, rightXø1, bottomYø1, topYø1, spreadø1); + }.call(this)); + return loop[0] = 1 + ychunkø1, loop; + })() : void 0; + } while (ychunkø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + return loop[0] = 1 + xchunkø1, loop; + })() : void 0; + } while (xchunkø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this); + }.call(this); + }.call(this)); + return loop[0] = 1 + iterø1, loop[1] = spreadø1 * (0 + $('#input-spread-reduction').val()), loop; + })() : void 0; + } while (iterø1 = loop[0], spreadø1 = loop[1], recur === loop); + return recur; + }.call(this)); + return normalize(heightmap); +}; +var mpdDisplaceD2 = exports.mpdDisplaceD2 = function mpdDisplaceD2(heightmap, lx, rx, by, ty, spread) { + return function () { + var cxø1 = midpoint(lx, rx); + var cyø1 = midpoint(by, ty); + var bottomLeftø1 = heightmap[by * heightmap.resolution + lx]; + var bottomRightø1 = heightmap[by * heightmap.resolution + rx]; + var topLeftø1 = heightmap[ty * heightmap.resolution + lx]; + var topRightø1 = heightmap[ty * heightmap.resolution + rx]; + var topø1 = average2(topLeftø1, topRightø1); + var leftø1 = average2(bottomLeftø1, topLeftø1); + var bottomø1 = average2(bottomLeftø1, bottomRightø1); + var rightø1 = average2(bottomRightø1, topRightø1); + heightmap[by * heightmap.resolution + cxø1] = jitter(bottomø1, spread); + heightmap[ty * heightmap.resolution + cxø1] = jitter(topø1, spread); + heightmap[cyø1 * heightmap.resolution + lx] = jitter(leftø1, spread); + return heightmap[cyø1 * heightmap.resolution + rx] = jitter(rightø1, spread); + }.call(this); +}; +var midpointDisplacementD1 = exports.midpointDisplacementD1 = function midpointDisplacementD1(heightmap) { + return mpdInitCorners(heightmap); +}; +var midpointDisplacementD2 = exports.midpointDisplacementD2 = function midpointDisplacementD2(heightmap) { + mpdInitCorners(heightmap); + return mpdDisplaceD2(heightmap, 0, heightmap.last, 0, heightmap.last, 0.1); +}; +var midpointDisplacementD3 = exports.midpointDisplacementD3 = function midpointDisplacementD3(heightmap) { + mpdInitCorners(heightmap); + return mpdDisplace(heightmap, 0, heightmap.last, 0, heightmap.last, 0.1); +}; +var makeDirectionalLight = exports.makeDirectionalLight = function makeDirectionalLight() { + return function () { + var lightø1 = new THREE.DirectionalLight(16777215, 1); + lightø1.position.set(100, 0, 150); + return lightø1; + }.call(this); +}; +var makeCamera = exports.makeCamera = function makeCamera() { + return function () { + var cameraø1 = new THREE.PerspectiveCamera(55, width / height, 0.1, 1000); + cameraø1.position.set(0, -100, 150); + return cameraø1; + }.call(this); +}; +var makeRenderer = exports.makeRenderer = function makeRenderer() { + return function () { + var rendererø1 = new THREE.WebGLRenderer({ 'antialias': false }); + rendererø1.setClearColor(16777215); + rendererø1.setSize(width, height); + rendererø1.setPixelRatio(2); + return rendererø1; + }.call(this); +}; +var makeGeometry = exports.makeGeometry = function makeGeometry(heightmap) { + return function () { + var geometryø1 = new THREE.PlaneGeometry(terrainSize, terrainSize, heightmap.resolution - 1, heightmap.resolution - 1); + geometryø1.dynamic = true; + return geometryø1; + }.call(this); +}; +var makeControls = exports.makeControls = function makeControls(camera, renderer) { + return function () { + var controlsø1 = new THREE.TrackballControls(camera, renderer.domElement); + controlsø1.rotateSpeed = 1.4; + controlsø1.zoomSpeed = 0.5; + controlsø1.staticMoving = true; + controlsø1.dynamicDampingFactor = 0.3; + return controlsø1; + }.call(this); +}; +var makePlane = exports.makePlane = function makePlane(geometry) { + return function () { + var materialø1 = new THREE.MeshLambertMaterial({ + 'wireframe': wireframe, + 'wireframeLinewidth': wireframeWidth, + 'color': 47872 + }); + return new THREE.Mesh(geometry, materialø1); + }.call(this); +}; +var attachToDom = exports.attachToDom = function attachToDom(renderer, elName, refreshFn) { + return function () { + var containerø1 = document.getElementById(elName); + var settingsø1 = document.createElement('div'); + var refreshButtonø1 = document.createElement('button'); + var buttonTextø1 = document.createTextNode('Refresh'); + var cancelScrollø1 = function (e) { + return e.preventDefault(); + }; + refreshButtonø1.onclick = refreshFn; + renderer.domElement.onmousewheel = cancelScrollø1; + renderer.domElement.addEventListener('MozMousePixelScroll', cancelScrollø1, false); + refreshButtonø1.appendChild(buttonTextø1); + containerø1.appendChild(renderer.domElement); + containerø1.appendChild(settingsø1); + return settingsø1.appendChild(refreshButtonø1); + }.call(this); +}; +var updateGeometry = exports.updateGeometry = function updateGeometry(geometry, heightmap) { + (function () { + var G__11ø1 = geometry.vertices.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__11ø1 ? (function () { + geometry.vertices[iø1].z = terrainHeight * heightmap[iø1]; + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + geometry.verticesNeedUpdate = true; + geometry.computeFaceNormals(); + geometry.computeVertexNormals(); + geometry.computeMorphNormals(); + return geometry; +}; +var makeDemo = exports.makeDemo = function makeDemo(elementId, algorithm, size) { + var scene = new THREE.Scene(); + scene.add(new THREE.AxisHelper(100)); + var clock = new THREE.Clock(); + var camera = makeCamera(); + var renderer = makeRenderer(); + var geometry = makeGeometry(makeHeightmap(size)); + scene.add(makeDirectionalLight()); + scene.add(new THREE.AmbientLight(16777215, 0.05)); + scene.add(makePlane(geometry)); + var refresh = function refresh() { + l('Refreshing ========================================'); + return function () { + var heightmapø1 = makeHeightmap(size); + l('Generating terrain...'); + (function () { + var G__12ø1 = new Date().getTime(); + var G__14ø1 = (function () { + return algorithm(heightmapø1); + })(); + var G__13ø1 = new Date().getTime(); + l('Elapsed time: ' + (G__13ø1 - G__12ø1) + 'ms.'); + return G__14ø1; + }.call(this)); + l('Refreshing geometry...'); + (function () { + var G__15ø1 = new Date().getTime(); + var G__17ø1 = (function () { + return updateGeometry(geometry, heightmapø1); + })(); + var G__16ø1 = new Date().getTime(); + l('Elapsed time: ' + (G__16ø1 - G__15ø1) + 'ms.'); + return G__17ø1; + }.call(this)); + return l('Done!'); + }.call(this); + }; + attachToDom(renderer, elementId, refresh); + var controls = makeControls(camera, renderer); + var render = function render() { + return function () { + var deltaø1 = clock.getDelta(); + requestAnimationFrame(render); + controls.update(deltaø1); + return renderer.render(scene, camera); + }.call(this); + }; + render(); + return void 0; +}; +var makeFinal = exports.makeFinal = function makeFinal(elementId) { + var scene = new THREE.Scene(); + scene.add(new THREE.AxisHelper(100)); + var clock = new THREE.Clock(); + var camera = makeCamera(); + var renderer = makeRenderer(); + var heightmap = makeHeightmap($('#input-exponent').val()); + var geometry = makeGeometry(heightmap); + var plane = makePlane(geometry); + scene.add(makeDirectionalLight()); + scene.add(new THREE.AmbientLight(16777215, 0.05)); + scene.add(plane); + var refresh = function refresh() { + l('Refreshing ========================================'); + scene.remove(plane); + heightmap = makeHeightmap($('#input-exponent').val()); + geometry = makeGeometry(heightmap); + plane = makePlane(geometry); + scene.add(plane); + l('Generating terrain...'); + (function () { + var G__18ø1 = new Date().getTime(); + var G__20ø1 = (function () { + return midpointDisplacementFinal(heightmap); + })(); + var G__19ø1 = new Date().getTime(); + l('Elapsed time: ' + (G__19ø1 - G__18ø1) + 'ms.'); + return G__20ø1; + }.call(this)); + l('Refreshing geometry...'); + (function () { + var G__21ø1 = new Date().getTime(); + var G__23ø1 = (function () { + return updateGeometry(geometry, heightmap); + })(); + var G__22ø1 = new Date().getTime(); + l('Elapsed time: ' + (G__22ø1 - G__21ø1) + 'ms.'); + return G__23ø1; + }.call(this)); + return l('Done!'); + }; + attachToDom(renderer, elementId, refresh); + var controls = makeControls(camera, renderer); + var render = function render() { + return function () { + var deltaø1 = clock.getDelta(); + requestAnimationFrame(render); + controls.update(deltaø1); + return renderer.render(scene, camera); + }.call(this); + }; + render(); + return void 0; +}; +var run = exports.run = function run() { + makeDemo('demo-random', randomNoise, 7); + makeDemo('demo-mpd-1', midpointDisplacementD1, 2); + makeDemo('demo-mpd-2', midpointDisplacementD2, 2); + makeDemo('demo-mpd-3', midpointDisplacementD3, 2); + makeDemo('demo-mpd-4', midpointDisplacement, 3); + return makeFinal('demo-final'); +}; +$(run); + + +},{}]},{},[1]); diff -r 37c769f2a211 -r e2b8f5dc9ae4 media/js/terrain1.wisp --- a/media/js/terrain1.wisp Fri Feb 19 19:48:12 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,391 +0,0 @@ -; Constants ------------------------------------------------------------------- -(set! exports {}) ; fuck off wisp -(def width 610) -(def height 400) -(def wireframe true) -(def wireframe-width 1.2) -(def terrain-height 50) -(def terrain-size 100) - -; General Utilities ----------------------------------------------------------- -(defmacro when [condition & body] - `(if ~condition - (do ~@body))) - -(defmacro do-times [varname limit & body] - (let [end (gensym)] - `(let [~end ~limit] - (loop [~varname 0] - (when (< ~varname ~end) - ~@body - (recur (+ 1 ~varname))))))) - -(defmacro do-nested [xname yname width & body] - (let [iterations (gensym)] - `(let [~iterations ~width] - (do-times ~xname ~iterations - (do-times ~yname ~iterations - ~@body))))) - -(defmacro inc! [place] - `(set! ~place (+ ~place 1))) - -(defmacro add! [place amount] - `(set! ~place (+ ~place ~amount))) - -(defmacro time [& body] - (let [start (gensym) - end (gensym) - result (gensym)] - `(let [~start (.getTime (new Date)) - ~result (do ~@body) - ~end (.getTime (new Date))] - (l (+ "Elapsed time: " (- ~end ~start) "ms.")) - ~result))) - -(defn l [v] - (console.log v)) - - -(defn midpoint [a b] - (/ (+ a b) 2)) - -(defn average2 [a b] - (/ (+ a b) 2)) - -(defn average4 [a b c d] - (/ (+ a b c d) 4)) - -(defn safe-average [a b c d] - (let [total 0 count 0] - (when a (add! total a) (inc! count)) - (when b (add! total b) (inc! count)) - (when c (add! total c) (inc! count)) - (when d (add! total d) (inc! count)) - (/ total count))) - - -(defn rand [] - (Math.random)) - -(defn rand-around-zero [spread] - (- (* spread (rand) 2) spread)) - - -(defn jitter [value spread] - (+ value (rand-around-zero spread))) - - -; Heightmap Helpers ----------------------------------------------------------- -(defmacro heightmap-get [hm x y] - `(aget ~hm (+ (* ~y (.-resolution ~hm)) ~x))) - -(defn heightmap-get-safe [hm x y] - (when (and (<= 0 x hm.last) - (<= 0 y hm.last)) - (heightmap-get hm x y))) - -(defmacro heightmap-set! [hm x y val] - `(set! (heightmap-get ~hm ~x ~y) ~val)) - - -(defn normalize [hm] - (let [max (- Infinity) - min Infinity] - (do-times i hm.length - (let [el (aget hm i)] - (when (< max el) (set! max el)) - (when (> min el) (set! min el)))) - (let [span (- max min)] - (do-times i hm.length - (set! (aget hm i) - (/ (- (aget hm i) min) - span)))))) - -(defn zero-heightmap [heightmap] - (do-times i heightmap.length - (set! (aget heightmap i) 0.0)) - heightmap) - -(defn make-heightmap [exponent] - (let [resolution (+ 1 (Math.pow 2 exponent))] - (l (+ "Creating " resolution " by " resolution " heightmap...")) - (def heightmap - (new Array (* resolution resolution))) - (set! heightmap.resolution resolution) - (set! heightmap.exponent exponent) - (set! heightmap.last (- resolution 1)) - (zero-heightmap heightmap))) - - -; Random Noise ---------------------------------------------------------------- -(defn random-noise [heightmap] - (do-times i heightmap.length - (set! (aget heightmap i) (rand)))) - - -; Midpoint Displacement ------------------------------------------------------- -(defn mpd-init-corners [heightmap] - (heightmap-set! heightmap 0 0 (rand)) - (heightmap-set! heightmap 0 heightmap.last (rand)) - (heightmap-set! heightmap heightmap.last 0 (rand)) - (heightmap-set! heightmap heightmap.last heightmap.last (rand))) - -(defn mpd-displace [heightmap lx rx by ty spread] - (let [cx (midpoint lx rx) - cy (midpoint by ty) - - bottom-left (heightmap-get heightmap lx by) - bottom-right (heightmap-get heightmap rx by) - top-left (heightmap-get heightmap lx ty) - top-right (heightmap-get heightmap rx ty) - - top (average2 top-left top-right) - left (average2 bottom-left top-left) - bottom (average2 bottom-left bottom-right) - right (average2 bottom-right top-right) - center (average4 top left bottom right)] - (heightmap-set! heightmap cx by (jitter bottom spread)) - (heightmap-set! heightmap cx ty (jitter top spread)) - (heightmap-set! heightmap lx cy (jitter left spread)) - (heightmap-set! heightmap rx cy (jitter right spread)) - (heightmap-set! heightmap cx cy (jitter center spread)))) - -(defn midpoint-displacement [heightmap] - (mpd-init-corners heightmap) - ; (mpd-displace heightmap 0 heightmap.last 0 heightmap.last 0.1) - (loop [iter 0 - spread 0.3] - (when (< iter heightmap.exponent) - (let [chunks (Math.pow 2 iter) - chunk-width (/ (- heightmap.resolution 1) chunks)] - (do-nested xchunk ychunk chunks - (let [left-x (* chunk-width xchunk) - right-x (+ left-x chunk-width) - bottom-y (* chunk-width ychunk) - top-y (+ bottom-y chunk-width)] - (mpd-displace heightmap left-x right-x bottom-y top-y spread)))) - (recur (+ 1 iter) (* spread 0.5)))) - (normalize heightmap)) - - -(defn midpoint-displacement-final [heightmap] - (mpd-init-corners heightmap) - ; (let [spread ]) - (loop [iter 0 - spread (+ 0 (.val ($ "#input-starting-spread")))] - (when (< iter heightmap.exponent) - (let [chunks (Math.pow 2 iter) - chunk-width (/ (- heightmap.resolution 1) chunks)] - (do-nested xchunk ychunk chunks - (let [left-x (* chunk-width xchunk) - right-x (+ left-x chunk-width) - bottom-y (* chunk-width ychunk) - top-y (+ bottom-y chunk-width)] - (mpd-displace heightmap left-x right-x bottom-y top-y spread)))) - (recur (+ 1 iter) (* spread - (+ 0 (.val ($ "#input-spread-reduction"))))))) - (normalize heightmap)) - - -(defn mpd-displace-d2 [heightmap lx rx by ty spread] - (let [cx (midpoint lx rx) - cy (midpoint by ty) - - bottom-left (heightmap-get heightmap lx by) - bottom-right (heightmap-get heightmap rx by) - top-left (heightmap-get heightmap lx ty) - top-right (heightmap-get heightmap rx ty) - - top (average2 top-left top-right) - left (average2 bottom-left top-left) - bottom (average2 bottom-left bottom-right) - right (average2 bottom-right top-right)] - (heightmap-set! heightmap cx by (jitter bottom spread)) - (heightmap-set! heightmap cx ty (jitter top spread)) - (heightmap-set! heightmap lx cy (jitter left spread)) - (heightmap-set! heightmap rx cy (jitter right spread)))) - -(defn midpoint-displacement-d1 [heightmap] - (mpd-init-corners heightmap)) - -(defn midpoint-displacement-d2 [heightmap] - (mpd-init-corners heightmap) - (mpd-displace-d2 heightmap - 0 heightmap.last - 0 heightmap.last - 0.1)) - -(defn midpoint-displacement-d3 [heightmap] - (mpd-init-corners heightmap) - (mpd-displace heightmap - 0 heightmap.last - 0 heightmap.last - 0.1)) - - - -; Three.js Helpers ------------------------------------------------------------ -(defn make-directional-light [] - (let [light (new THREE.DirectionalLight 0xffffff 1)] - (light.position.set 100 0 150) - light)) - -(defn make-camera [] - (let [camera (new THREE.PerspectiveCamera - 55, - (/ width height) - 0.1, - 1000)] - (camera.position.set 0 -100 150) - camera)) - -(defn make-renderer [] - (let [renderer (new THREE.WebGLRenderer {:antialias false})] - (renderer.setClearColor 0xffffff) - (renderer.setSize width height) - (renderer.setPixelRatio 2) - renderer)) - -(defn make-geometry [heightmap] - (let [geometry (new THREE.PlaneGeometry - terrain-size - terrain-size - (- heightmap.resolution 1) - (- heightmap.resolution 1))] - (set! geometry.dynamic true) - geometry)) - -(defn make-controls [camera renderer] - (let [controls (new THREE.TrackballControls camera renderer.domElement)] - (set! controls.rotateSpeed 1.4) - (set! controls.zoomSpeed 0.5) - (set! controls.staticMoving true) - (set! controls.dynamicDampingFactor 0.3) - controls)) - -(defn make-plane [geometry] - (let [material (new THREE.MeshLambertMaterial - {:wireframe wireframe - :wireframeLinewidth wireframe-width - :color 0x00bb00})] - (new THREE.Mesh geometry material))) - - -(defn attach-to-dom [renderer el-name refresh-fn] - (let [container (document.getElementById el-name) - settings (document.createElement "div") - refresh-button (document.createElement "button") - button-text (document.createTextNode "Refresh") - cancel-scroll (fn [e] (.preventDefault e))] - (set! refresh-button.onclick refresh-fn) - (set! renderer.domElement.onmousewheel cancel-scroll) - (renderer.domElement.addEventListener "MozMousePixelScroll" cancel-scroll false) - (.appendChild refresh-button button-text) - (.appendChild container renderer.domElement) - (.appendChild container settings) - (.appendChild settings refresh-button))) - -(defn update-geometry [geometry heightmap] - (do-times i geometry.vertices.length - (set! (.-z (aget geometry.vertices i)) - (* terrain-height (aget heightmap i)))) - (set! geometry.verticesNeedUpdate true) - (geometry.computeFaceNormals) - (geometry.computeVertexNormals) - (geometry.computeMorphNormals) - geometry) - - -; Main ------------------------------------------------------------------------ -(defn make-demo [element-id algorithm size] - (def scene (new THREE.Scene)) - (scene.add (new THREE.AxisHelper 100)) - - (def clock (new THREE.Clock)) - (def camera (make-camera)) - (def renderer (make-renderer)) - (def geometry (make-geometry (make-heightmap size))) - - (scene.add (make-directional-light)) - (scene.add (new THREE.AmbientLight 0xffffff 0.05)) - (scene.add (make-plane geometry)) - - (defn refresh [] - (l "Refreshing ========================================") - (let [heightmap (make-heightmap size)] - (l "Generating terrain...") - (time (algorithm heightmap)) - (l "Refreshing geometry...") - (time (update-geometry geometry heightmap)) - (l "Done!"))) - - (attach-to-dom renderer element-id refresh) - (def controls (make-controls camera renderer)) - - (defn render [] - (let [delta (clock.getDelta)] - (requestAnimationFrame render) - (.update controls delta) - (renderer.render scene camera))) - - (render) - - nil) - -(defn make-final [element-id] - (def scene (new THREE.Scene)) - (scene.add (new THREE.AxisHelper 100)) - - (def clock (new THREE.Clock)) - (def camera (make-camera)) - (def renderer (make-renderer)) - (def heightmap (make-heightmap (.val ($ "#input-exponent")))) - (def geometry (make-geometry heightmap)) - (def plane (make-plane geometry)) - - (scene.add (make-directional-light)) - (scene.add (new THREE.AmbientLight 0xffffff 0.05)) - (scene.add plane) - - (defn refresh [] - (l "Refreshing ========================================") - (scene.remove plane) - (set! heightmap (make-heightmap (.val ($ "#input-exponent")))) - (set! geometry (make-geometry heightmap)) - (set! plane (make-plane geometry)) - (scene.add plane) - (l "Generating terrain...") - (time (midpoint-displacement-final heightmap)) - (l "Refreshing geometry...") - (time (update-geometry geometry heightmap)) - (l "Done!")) - - (attach-to-dom renderer element-id refresh) - (def controls (make-controls camera renderer)) - - (defn render [] - (let [delta (clock.getDelta)] - (requestAnimationFrame render) - (.update controls delta) - (renderer.render scene camera))) - - (render) - - nil) - - -(defn run [] - (make-demo "demo-random" random-noise 7) - (make-demo "demo-mpd-1" midpoint-displacement-d1 2) - (make-demo "demo-mpd-2" midpoint-displacement-d2 2) - (make-demo "demo-mpd-3" midpoint-displacement-d3 2) - (make-demo "demo-mpd-4" midpoint-displacement 3) - (make-final "demo-final") - ; (make-demo "demo-midpoint" midpoint-displacement) - ; (make-demo "demo-diamond" diamond-square) - - ) - - -; vim: lw+=do-times lw+=do-nested : diff -r 37c769f2a211 -r e2b8f5dc9ae4 media/js/wisp/terrain1.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/media/js/wisp/terrain1.js Sun Feb 28 11:51:50 2016 +0000 @@ -0,0 +1,520 @@ +var width = exports.width = 610; +var height = exports.height = 400; +var wireframe = exports.wireframe = true; +var wireframeWidth = exports.wireframeWidth = 1.2; +var terrainHeight = exports.terrainHeight = 50; +var terrainSize = exports.terrainSize = 100; +void 0; +void 0; +void 0; +void 0; +void 0; +void 0; +var l = exports.l = function l(v) { + return console.log(v); +}; +var midpoint = exports.midpoint = function midpoint(a, b) { + return (a + b) / 2; +}; +var average2 = exports.average2 = function average2(a, b) { + return (a + b) / 2; +}; +var average4 = exports.average4 = function average4(a, b, c, d) { + return (a + b + c + d) / 4; +}; +var safeAverage = exports.safeAverage = function safeAverage(a, b, c, d) { + return function () { + var totalø1 = 0; + var countø1 = 0; + a ? (function () { + totalø1 = totalø1 + a; + return countø1 = countø1 + 1; + })() : void 0; + b ? (function () { + totalø1 = totalø1 + b; + return countø1 = countø1 + 1; + })() : void 0; + c ? (function () { + totalø1 = totalø1 + c; + return countø1 = countø1 + 1; + })() : void 0; + d ? (function () { + totalø1 = totalø1 + d; + return countø1 = countø1 + 1; + })() : void 0; + return totalø1 / countø1; + }.call(this); +}; +var rand = exports.rand = function rand() { + return Math.random(); +}; +var randAroundZero = exports.randAroundZero = function randAroundZero(spread) { + return spread * rand() * 2 - spread; +}; +var jitter = exports.jitter = function jitter(value, spread) { + return value + randAroundZero(spread); +}; +void 0; +var heightmapGetSafe = exports.heightmapGetSafe = function heightmapGetSafe(hm, x, y) { + return 0 <= x && x <= hm.last && (0 <= y && y <= hm.last) ? (function () { + return hm[y * hm.resolution + x]; + })() : void 0; +}; +void 0; +var normalize = exports.normalize = function normalize(hm) { + return function () { + var maxø1 = 0 - Infinity; + var minø1 = Infinity; + (function () { + var G__1ø1 = hm.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__1ø1 ? (function () { + (function () { + var elø1 = hm[iø1]; + maxø1 < elø1 ? (function () { + return maxø1 = elø1; + })() : void 0; + return minø1 > elø1 ? (function () { + return minø1 = elø1; + })() : void 0; + }.call(this)); + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + return function () { + var spanø1 = maxø1 - minø1; + return function () { + var G__2ø1 = hm.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__2ø1 ? (function () { + hm[iø1] = (hm[iø1] - minø1) / spanø1; + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this); + }.call(this); + }.call(this); +}; +var zeroHeightmap = exports.zeroHeightmap = function zeroHeightmap(heightmap) { + (function () { + var G__3ø1 = heightmap.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__3ø1 ? (function () { + heightmap[iø1] = 0; + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + return heightmap; +}; +var makeHeightmap = exports.makeHeightmap = function makeHeightmap(exponent) { + return function () { + var resolutionø1 = 1 + Math.pow(2, exponent); + l('Creating ' + resolutionø1 + ' by ' + resolutionø1 + ' heightmap...'); + var heightmap = new Array(resolutionø1 * resolutionø1); + heightmap.resolution = resolutionø1; + heightmap.exponent = exponent; + heightmap.last = resolutionø1 - 1; + return zeroHeightmap(heightmap); + }.call(this); +}; +var randomNoise = exports.randomNoise = function randomNoise(heightmap) { + return function () { + var G__4ø1 = heightmap.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__4ø1 ? (function () { + heightmap[iø1] = rand(); + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this); +}; +var mpdInitCorners = exports.mpdInitCorners = function mpdInitCorners(heightmap) { + heightmap[0 * heightmap.resolution + 0] = rand(); + heightmap[heightmap.last * heightmap.resolution + 0] = rand(); + heightmap[0 * heightmap.resolution + heightmap.last] = rand(); + return heightmap[heightmap.last * heightmap.resolution + heightmap.last] = rand(); +}; +var mpdDisplace = exports.mpdDisplace = function mpdDisplace(heightmap, lx, rx, by, ty, spread) { + return function () { + var cxø1 = midpoint(lx, rx); + var cyø1 = midpoint(by, ty); + var bottomLeftø1 = heightmap[by * heightmap.resolution + lx]; + var bottomRightø1 = heightmap[by * heightmap.resolution + rx]; + var topLeftø1 = heightmap[ty * heightmap.resolution + lx]; + var topRightø1 = heightmap[ty * heightmap.resolution + rx]; + var topø1 = average2(topLeftø1, topRightø1); + var leftø1 = average2(bottomLeftø1, topLeftø1); + var bottomø1 = average2(bottomLeftø1, bottomRightø1); + var rightø1 = average2(bottomRightø1, topRightø1); + var centerø1 = average4(topø1, leftø1, bottomø1, rightø1); + heightmap[by * heightmap.resolution + cxø1] = jitter(bottomø1, spread); + heightmap[ty * heightmap.resolution + cxø1] = jitter(topø1, spread); + heightmap[cyø1 * heightmap.resolution + lx] = jitter(leftø1, spread); + heightmap[cyø1 * heightmap.resolution + rx] = jitter(rightø1, spread); + return heightmap[cyø1 * heightmap.resolution + cxø1] = jitter(centerø1, spread); + }.call(this); +}; +var midpointDisplacement = exports.midpointDisplacement = function midpointDisplacement(heightmap) { + mpdInitCorners(heightmap); + (function loop() { + var recur = loop; + var iterø1 = 0; + var spreadø1 = 0.3; + do { + recur = iterø1 < heightmap.exponent ? (function () { + (function () { + var chunksø1 = Math.pow(2, iterø1); + var chunkWidthø1 = (heightmap.resolution - 1) / chunksø1; + return function () { + var G__5ø1 = chunksø1; + return function () { + var G__6ø1 = G__5ø1; + return function loop() { + var recur = loop; + var xchunkø1 = 0; + do { + recur = xchunkø1 < G__6ø1 ? (function () { + (function () { + var G__7ø1 = G__5ø1; + return function loop() { + var recur = loop; + var ychunkø1 = 0; + do { + recur = ychunkø1 < G__7ø1 ? (function () { + (function () { + var leftXø1 = chunkWidthø1 * xchunkø1; + var rightXø1 = leftXø1 + chunkWidthø1; + var bottomYø1 = chunkWidthø1 * ychunkø1; + var topYø1 = bottomYø1 + chunkWidthø1; + return mpdDisplace(heightmap, leftXø1, rightXø1, bottomYø1, topYø1, spreadø1); + }.call(this)); + return loop[0] = 1 + ychunkø1, loop; + })() : void 0; + } while (ychunkø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + return loop[0] = 1 + xchunkø1, loop; + })() : void 0; + } while (xchunkø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this); + }.call(this); + }.call(this)); + return loop[0] = 1 + iterø1, loop[1] = spreadø1 * 0.5, loop; + })() : void 0; + } while (iterø1 = loop[0], spreadø1 = loop[1], recur === loop); + return recur; + }.call(this)); + return normalize(heightmap); +}; +var midpointDisplacementFinal = exports.midpointDisplacementFinal = function midpointDisplacementFinal(heightmap) { + mpdInitCorners(heightmap); + (function loop() { + var recur = loop; + var iterø1 = 0; + var spreadø1 = 0 + $('#input-starting-spread').val(); + do { + recur = iterø1 < heightmap.exponent ? (function () { + (function () { + var chunksø1 = Math.pow(2, iterø1); + var chunkWidthø1 = (heightmap.resolution - 1) / chunksø1; + return function () { + var G__8ø1 = chunksø1; + return function () { + var G__9ø1 = G__8ø1; + return function loop() { + var recur = loop; + var xchunkø1 = 0; + do { + recur = xchunkø1 < G__9ø1 ? (function () { + (function () { + var G__10ø1 = G__8ø1; + return function loop() { + var recur = loop; + var ychunkø1 = 0; + do { + recur = ychunkø1 < G__10ø1 ? (function () { + (function () { + var leftXø1 = chunkWidthø1 * xchunkø1; + var rightXø1 = leftXø1 + chunkWidthø1; + var bottomYø1 = chunkWidthø1 * ychunkø1; + var topYø1 = bottomYø1 + chunkWidthø1; + return mpdDisplace(heightmap, leftXø1, rightXø1, bottomYø1, topYø1, spreadø1); + }.call(this)); + return loop[0] = 1 + ychunkø1, loop; + })() : void 0; + } while (ychunkø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + return loop[0] = 1 + xchunkø1, loop; + })() : void 0; + } while (xchunkø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this); + }.call(this); + }.call(this)); + return loop[0] = 1 + iterø1, loop[1] = spreadø1 * (0 + $('#input-spread-reduction').val()), loop; + })() : void 0; + } while (iterø1 = loop[0], spreadø1 = loop[1], recur === loop); + return recur; + }.call(this)); + return normalize(heightmap); +}; +var mpdDisplaceD2 = exports.mpdDisplaceD2 = function mpdDisplaceD2(heightmap, lx, rx, by, ty, spread) { + return function () { + var cxø1 = midpoint(lx, rx); + var cyø1 = midpoint(by, ty); + var bottomLeftø1 = heightmap[by * heightmap.resolution + lx]; + var bottomRightø1 = heightmap[by * heightmap.resolution + rx]; + var topLeftø1 = heightmap[ty * heightmap.resolution + lx]; + var topRightø1 = heightmap[ty * heightmap.resolution + rx]; + var topø1 = average2(topLeftø1, topRightø1); + var leftø1 = average2(bottomLeftø1, topLeftø1); + var bottomø1 = average2(bottomLeftø1, bottomRightø1); + var rightø1 = average2(bottomRightø1, topRightø1); + heightmap[by * heightmap.resolution + cxø1] = jitter(bottomø1, spread); + heightmap[ty * heightmap.resolution + cxø1] = jitter(topø1, spread); + heightmap[cyø1 * heightmap.resolution + lx] = jitter(leftø1, spread); + return heightmap[cyø1 * heightmap.resolution + rx] = jitter(rightø1, spread); + }.call(this); +}; +var midpointDisplacementD1 = exports.midpointDisplacementD1 = function midpointDisplacementD1(heightmap) { + return mpdInitCorners(heightmap); +}; +var midpointDisplacementD2 = exports.midpointDisplacementD2 = function midpointDisplacementD2(heightmap) { + mpdInitCorners(heightmap); + return mpdDisplaceD2(heightmap, 0, heightmap.last, 0, heightmap.last, 0.1); +}; +var midpointDisplacementD3 = exports.midpointDisplacementD3 = function midpointDisplacementD3(heightmap) { + mpdInitCorners(heightmap); + return mpdDisplace(heightmap, 0, heightmap.last, 0, heightmap.last, 0.1); +}; +var makeDirectionalLight = exports.makeDirectionalLight = function makeDirectionalLight() { + return function () { + var lightø1 = new THREE.DirectionalLight(16777215, 1); + lightø1.position.set(100, 0, 150); + return lightø1; + }.call(this); +}; +var makeCamera = exports.makeCamera = function makeCamera() { + return function () { + var cameraø1 = new THREE.PerspectiveCamera(55, width / height, 0.1, 1000); + cameraø1.position.set(0, -100, 150); + return cameraø1; + }.call(this); +}; +var makeRenderer = exports.makeRenderer = function makeRenderer() { + return function () { + var rendererø1 = new THREE.WebGLRenderer({ 'antialias': false }); + rendererø1.setClearColor(16777215); + rendererø1.setSize(width, height); + rendererø1.setPixelRatio(2); + return rendererø1; + }.call(this); +}; +var makeGeometry = exports.makeGeometry = function makeGeometry(heightmap) { + return function () { + var geometryø1 = new THREE.PlaneGeometry(terrainSize, terrainSize, heightmap.resolution - 1, heightmap.resolution - 1); + geometryø1.dynamic = true; + return geometryø1; + }.call(this); +}; +var makeControls = exports.makeControls = function makeControls(camera, renderer) { + return function () { + var controlsø1 = new THREE.TrackballControls(camera, renderer.domElement); + controlsø1.rotateSpeed = 1.4; + controlsø1.zoomSpeed = 0.5; + controlsø1.staticMoving = true; + controlsø1.dynamicDampingFactor = 0.3; + return controlsø1; + }.call(this); +}; +var makePlane = exports.makePlane = function makePlane(geometry) { + return function () { + var materialø1 = new THREE.MeshLambertMaterial({ + 'wireframe': wireframe, + 'wireframeLinewidth': wireframeWidth, + 'color': 47872 + }); + return new THREE.Mesh(geometry, materialø1); + }.call(this); +}; +var attachToDom = exports.attachToDom = function attachToDom(renderer, elName, refreshFn) { + return function () { + var containerø1 = document.getElementById(elName); + var settingsø1 = document.createElement('div'); + var refreshButtonø1 = document.createElement('button'); + var buttonTextø1 = document.createTextNode('Refresh'); + var cancelScrollø1 = function (e) { + return e.preventDefault(); + }; + refreshButtonø1.onclick = refreshFn; + renderer.domElement.onmousewheel = cancelScrollø1; + renderer.domElement.addEventListener('MozMousePixelScroll', cancelScrollø1, false); + refreshButtonø1.appendChild(buttonTextø1); + containerø1.appendChild(renderer.domElement); + containerø1.appendChild(settingsø1); + return settingsø1.appendChild(refreshButtonø1); + }.call(this); +}; +var updateGeometry = exports.updateGeometry = function updateGeometry(geometry, heightmap) { + (function () { + var G__11ø1 = geometry.vertices.length; + return function loop() { + var recur = loop; + var iø1 = 0; + do { + recur = iø1 < G__11ø1 ? (function () { + geometry.vertices[iø1].z = terrainHeight * heightmap[iø1]; + return loop[0] = 1 + iø1, loop; + })() : void 0; + } while (iø1 = loop[0], recur === loop); + return recur; + }.call(this); + }.call(this)); + geometry.verticesNeedUpdate = true; + geometry.computeFaceNormals(); + geometry.computeVertexNormals(); + geometry.computeMorphNormals(); + return geometry; +}; +var makeDemo = exports.makeDemo = function makeDemo(elementId, algorithm, size) { + var scene = new THREE.Scene(); + scene.add(new THREE.AxisHelper(100)); + var clock = new THREE.Clock(); + var camera = makeCamera(); + var renderer = makeRenderer(); + var geometry = makeGeometry(makeHeightmap(size)); + scene.add(makeDirectionalLight()); + scene.add(new THREE.AmbientLight(16777215, 0.05)); + scene.add(makePlane(geometry)); + var refresh = function refresh() { + l('Refreshing ========================================'); + return function () { + var heightmapø1 = makeHeightmap(size); + l('Generating terrain...'); + (function () { + var G__12ø1 = new Date().getTime(); + var G__14ø1 = (function () { + return algorithm(heightmapø1); + })(); + var G__13ø1 = new Date().getTime(); + l('Elapsed time: ' + (G__13ø1 - G__12ø1) + 'ms.'); + return G__14ø1; + }.call(this)); + l('Refreshing geometry...'); + (function () { + var G__15ø1 = new Date().getTime(); + var G__17ø1 = (function () { + return updateGeometry(geometry, heightmapø1); + })(); + var G__16ø1 = new Date().getTime(); + l('Elapsed time: ' + (G__16ø1 - G__15ø1) + 'ms.'); + return G__17ø1; + }.call(this)); + return l('Done!'); + }.call(this); + }; + attachToDom(renderer, elementId, refresh); + var controls = makeControls(camera, renderer); + var render = function render() { + return function () { + var deltaø1 = clock.getDelta(); + requestAnimationFrame(render); + controls.update(deltaø1); + return renderer.render(scene, camera); + }.call(this); + }; + render(); + return void 0; +}; +var makeFinal = exports.makeFinal = function makeFinal(elementId) { + var scene = new THREE.Scene(); + scene.add(new THREE.AxisHelper(100)); + var clock = new THREE.Clock(); + var camera = makeCamera(); + var renderer = makeRenderer(); + var heightmap = makeHeightmap($('#input-exponent').val()); + var geometry = makeGeometry(heightmap); + var plane = makePlane(geometry); + scene.add(makeDirectionalLight()); + scene.add(new THREE.AmbientLight(16777215, 0.05)); + scene.add(plane); + var refresh = function refresh() { + l('Refreshing ========================================'); + scene.remove(plane); + heightmap = makeHeightmap($('#input-exponent').val()); + geometry = makeGeometry(heightmap); + plane = makePlane(geometry); + scene.add(plane); + l('Generating terrain...'); + (function () { + var G__18ø1 = new Date().getTime(); + var G__20ø1 = (function () { + return midpointDisplacementFinal(heightmap); + })(); + var G__19ø1 = new Date().getTime(); + l('Elapsed time: ' + (G__19ø1 - G__18ø1) + 'ms.'); + return G__20ø1; + }.call(this)); + l('Refreshing geometry...'); + (function () { + var G__21ø1 = new Date().getTime(); + var G__23ø1 = (function () { + return updateGeometry(geometry, heightmap); + })(); + var G__22ø1 = new Date().getTime(); + l('Elapsed time: ' + (G__22ø1 - G__21ø1) + 'ms.'); + return G__23ø1; + }.call(this)); + return l('Done!'); + }; + attachToDom(renderer, elementId, refresh); + var controls = makeControls(camera, renderer); + var render = function render() { + return function () { + var deltaø1 = clock.getDelta(); + requestAnimationFrame(render); + controls.update(deltaø1); + return renderer.render(scene, camera); + }.call(this); + }; + render(); + return void 0; +}; +var run = exports.run = function run() { + makeDemo('demo-random', randomNoise, 7); + makeDemo('demo-mpd-1', midpointDisplacementD1, 2); + makeDemo('demo-mpd-2', midpointDisplacementD2, 2); + makeDemo('demo-mpd-3', midpointDisplacementD3, 2); + makeDemo('demo-mpd-4', midpointDisplacement, 3); + return makeFinal('demo-final'); +}; +$(run); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFub255bW91cy53aXNwIl0sIm5hbWVzIjpbIndpZHRoIiwiZXhwb3J0cyIsImhlaWdodCIsIndpcmVmcmFtZSIsIndpcmVmcmFtZVdpZHRoIiwidGVycmFpbkhlaWdodCIsInRlcnJhaW5TaXplIiwibCIsInYiLCJjb25zb2xlIiwibG9nIiwibWlkcG9pbnQiLCJhIiwiYiIsImF2ZXJhZ2UyIiwiYXZlcmFnZTQiLCJjIiwiZCIsInNhZmVBdmVyYWdlIiwidG90YWzDuDEiLCJjb3VudMO4MSIsInJhbmQiLCJNYXRoIiwicmFuZG9tIiwicmFuZEFyb3VuZFplcm8iLCJzcHJlYWQiLCJqaXR0ZXIiLCJ2YWx1ZSIsImhlaWdodG1hcEdldFNhZmUiLCJobSIsIngiLCJ5IiwibGFzdCIsIm5vcm1hbGl6ZSIsIm1heMO4MSIsIkluZmluaXR5IiwibWluw7gxIiwibGVuZ3RoIiwiacO4MSIsImVsw7gxIiwic3BhbsO4MSIsInplcm9IZWlnaHRtYXAiLCJoZWlnaHRtYXAiLCJtYWtlSGVpZ2h0bWFwIiwiZXhwb25lbnQiLCJyZXNvbHV0aW9uw7gxIiwicG93IiwiQXJyYXkiLCJyZXNvbHV0aW9uIiwicmFuZG9tTm9pc2UiLCJtcGRJbml0Q29ybmVycyIsIm1wZERpc3BsYWNlIiwibHgiLCJyeCIsImJ5IiwidHkiLCJjeMO4MSIsImN5w7gxIiwiYm90dG9tTGVmdMO4MSIsImJvdHRvbVJpZ2h0w7gxIiwidG9wTGVmdMO4MSIsInRvcFJpZ2h0w7gxIiwidG9ww7gxIiwibGVmdMO4MSIsImJvdHRvbcO4MSIsInJpZ2h0w7gxIiwiY2VudGVyw7gxIiwibWlkcG9pbnREaXNwbGFjZW1lbnQiLCJpdGVyw7gxIiwic3ByZWFkw7gxIiwiY2h1bmtzw7gxIiwiY2h1bmtXaWR0aMO4MSIsInhjaHVua8O4MSIsInljaHVua8O4MSIsImxlZnRYw7gxIiwicmlnaHRYw7gxIiwiYm90dG9tWcO4MSIsInRvcFnDuDEiLCJtaWRwb2ludERpc3BsYWNlbWVudEZpbmFsIiwiJCIsInZhbCIsIm1wZERpc3BsYWNlRDIiLCJtaWRwb2ludERpc3BsYWNlbWVudEQxIiwibWlkcG9pbnREaXNwbGFjZW1lbnREMiIsIm1pZHBvaW50RGlzcGxhY2VtZW50RDMiLCJtYWtlRGlyZWN0aW9uYWxMaWdodCIsImxpZ2h0w7gxIiwiVEhSRUUiLCJEaXJlY3Rpb25hbExpZ2h0IiwicG9zaXRpb24uc2V0IiwibWFrZUNhbWVyYSIsImNhbWVyYcO4MSIsIlBlcnNwZWN0aXZlQ2FtZXJhIiwibWFrZVJlbmRlcmVyIiwicmVuZGVyZXLDuDEiLCJXZWJHTFJlbmRlcmVyIiwic2V0Q2xlYXJDb2xvciIsInNldFNpemUiLCJzZXRQaXhlbFJhdGlvIiwibWFrZUdlb21ldHJ5IiwiZ2VvbWV0cnnDuDEiLCJQbGFuZUdlb21ldHJ5IiwiZHluYW1pYyIsIm1ha2VDb250cm9scyIsImNhbWVyYSIsInJlbmRlcmVyIiwiY29udHJvbHPDuDEiLCJUcmFja2JhbGxDb250cm9scyIsImRvbUVsZW1lbnQiLCJyb3RhdGVTcGVlZCIsInpvb21TcGVlZCIsInN0YXRpY01vdmluZyIsImR5bmFtaWNEYW1waW5nRmFjdG9yIiwibWFrZVBsYW5lIiwiZ2VvbWV0cnkiLCJtYXRlcmlhbMO4MSIsIk1lc2hMYW1iZXJ0TWF0ZXJpYWwiLCJNZXNoIiwiYXR0YWNoVG9Eb20iLCJlbE5hbWUiLCJyZWZyZXNoRm4iLCJjb250YWluZXLDuDEiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwic2V0dGluZ3PDuDEiLCJjcmVhdGVFbGVtZW50IiwicmVmcmVzaEJ1dHRvbsO4MSIsImJ1dHRvblRleHTDuDEiLCJjcmVhdGVUZXh0Tm9kZSIsImNhbmNlbFNjcm9sbMO4MSIsImUiLCJwcmV2ZW50RGVmYXVsdCIsIm9uY2xpY2siLCJkb21FbGVtZW50Lm9ubW91c2V3aGVlbCIsImRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciIsImFwcGVuZENoaWxkIiwidXBkYXRlR2VvbWV0cnkiLCJ2ZXJ0aWNlcy5sZW5ndGgiLCJ2ZXJ0aWNlcyIsInoiLCJ2ZXJ0aWNlc05lZWRVcGRhdGUiLCJjb21wdXRlRmFjZU5vcm1hbHMiLCJjb21wdXRlVmVydGV4Tm9ybWFscyIsImNvbXB1dGVNb3JwaE5vcm1hbHMiLCJtYWtlRGVtbyIsImVsZW1lbnRJZCIsImFsZ29yaXRobSIsInNpemUiLCJzY2VuZSIsIlNjZW5lIiwiYWRkIiwiQXhpc0hlbHBlciIsImNsb2NrIiwiQ2xvY2siLCJBbWJpZW50TGlnaHQiLCJyZWZyZXNoIiwiaGVpZ2h0bWFww7gxIiwiY29udHJvbHMiLCJyZW5kZXIiLCJkZWx0YcO4MSIsImdldERlbHRhIiwicmVxdWVzdEFuaW1hdGlvbkZyYW1lIiwidXBkYXRlIiwibWFrZUZpbmFsIiwicGxhbmUiLCJyZW1vdmUiLCJydW4iXSwibWFwcGluZ3MiOiJBQUNBLElBQUtBLEtBQUEsR0FBQUMsT0FBQSxDQUFBRCxLQUFBLEdBQU0sR0FBWDtBQUNBLElBQUtFLE1BQUEsR0FBQUQsT0FBQSxDQUFBQyxNQUFBLEdBQU8sR0FBWixDQURBO0FBRUEsSUFBS0MsU0FBQSxHQUFBRixPQUFBLENBQUFFLFNBQUEsRyxJQUFMLENBRkE7QUFHQSxJQUFLQyxjQUFBLEdBQUFILE9BQUEsQ0FBQUcsY0FBQSxHQUFnQixHQUFyQixDQUhBO0FBSUEsSUFBS0MsYUFBQSxHQUFBSixPQUFBLENBQUFJLGFBQUEsR0FBZSxFQUFwQixDQUpBO0FBS0EsSUFBS0MsV0FBQSxHQUFBTCxPQUFBLENBQUFLLFdBQUEsR0FBYSxHQUFsQixDQUxBO09BQUE7T0FBQTtPQUFBO09BQUE7T0FBQTtPQUFBO0FBMkNBLElBQU1DLENBQUEsR0FBQU4sT0FBQSxDQUFBTSxDQUFBLEdBQU4sU0FBTUEsQ0FBTixDQUFTQyxDQUFULEVBQ0U7QUFBQSxXQUFDQyxPQUFBLENBQVFDLEdBQVQsQ0FBYUYsQ0FBYjtBQUFBLENBREYsQ0EzQ0E7QUErQ0EsSUFBTUcsUUFBQSxHQUFBVixPQUFBLENBQUFVLFFBQUEsR0FBTixTQUFNQSxRQUFOLENBQWdCQyxDQUFoQixFQUFrQkMsQ0FBbEIsRUFDRTtBQUFBLFdB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QVcsWUFBWCxFQUF3QjdFLG9CQUF4QixFQUE4QyxDQUE5QyxFQUpBO0FBQUEsSUFLQSxPQUFDZ0csU0FBRCxDQUFZLFlBQVosRUFMQTtBQUFBLENBREYsQ0F2WEE7QUFtWUNwRixDQUFELENBQUd1RixHQUFIIiwic291cmNlc0NvbnRlbnQiOlsiOyBDb25zdGFudHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZiB3aWR0aCA2MTApXG4oZGVmIGhlaWdodCA0MDApXG4oZGVmIHdpcmVmcmFtZSB0cnVlKVxuKGRlZiB3aXJlZnJhbWUtd2lkdGggMS4yKVxuKGRlZiB0ZXJyYWluLWhlaWdodCA1MClcbihkZWYgdGVycmFpbi1zaXplIDEwMClcblxuOyBHZW5lcmFsIFV0aWxpdGllcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZm1hY3JvIHdoZW4gW2NvbmRpdGlvbiAmIGJvZHldXG4gIGAoaWYgfmNvbmRpdGlvblxuICAgICAoZG8gfkBib2R5KSkpXG5cbihkZWZtYWNybyBkby10aW1lcyBbdmFybmFtZSBsaW1pdCAmIGJvZHldXG4gIChsZXQgW2VuZCAoZ2Vuc3ltKV1cbiAgICBgKGxldCBbfmVuZCB+bGltaXRdXG4gICAgICAgKGxvb3AgW352YXJuYW1lIDBdXG4gICAgICAgICAod2hlbiAoPCB+dmFybmFtZSB+ZW5kKVxuICAgICAgICAgICB+QGJvZHlcbiAgICAgICAgICAgKHJlY3VyICgrIDEgfnZhcm5hbWUpKSkpKSkpXG5cbihkZWZtYWNybyBkby1uZXN0ZWQgW3huYW1lIHluYW1lIHdpZHRoICYgYm9keV1cbiAgKGxldCBbaXRlcmF0aW9ucyAoZ2Vuc3ltKV1cbiAgICBgKGxldCBbfml0ZXJhdGlvbnMgfndpZHRoXVxuICAgICAgIChkby10aW1lcyB+eG5hbWUgfml0ZXJhdGlvbnNcbiAgICAgICAgIChkby10aW1lcyB+eW5hbWUgfml0ZXJhdGlvbnNcbiAgICAgICAgICAgfkBib2R5KSkpKSlcblxuKGRlZm1hY3JvIGluYyEgW3BsYWNlXVxuICBgKHNldCEgfnBsYWNlICgrIH5wbGFjZSAxKSkpXG5cbihkZWZtYWNybyBhZGQhIFtwbGFjZSBhbW91bnRdXG4gIGAoc2V0ISB+cGxhY2UgKCsgfnBsYWNlIH5hbW91bnQpKSlcblxuKGRlZm1hY3JvIHRpbWUgWyYgYm9keV1cbiAgKGxldCBbc3RhcnQgKGdlbnN5bSlcbiAgICAgICAgZW5kIChnZW5zeW0pXG4gICAgICAgIHJlc3VsdCAoZ2Vuc3ltKV1cbiAgICBgKGxldCBbfnN0YXJ0ICguZ2V0VGltZSAobmV3IERhdGUpKVxuICAgICAgICAgICB+cmVzdWx0IChkbyB+QGJvZHkpXG4gICAgICAgICAgIH5lbmQgKC5nZXRUaW1lIChuZXcgRGF0ZSkpXVxuICAgICAgIChsICgrIFwiRWxhcHNlZCB0aW1lOiBcIiAoLSB+ZW5kIH5zdGFydCkgXCJtcy5cIikpXG4gICAgICAgfnJlc3VsdCkpKVxuXG4oZGVmbiBsIFt2XVxuICAoY29uc29sZS5sb2cgdikpXG5cblxuKGRlZm4gbWlkcG9pbnQgW2EgYl1cbiAgKC8gKCsgYSBiKSAyKSlcblxuKGRlZm4gYXZlcmFnZTIgW2EgYl1cbiAgKC8gKCsgYSBiKSAyKSlcblxuKGRlZm4gYXZlcmFnZTQgW2EgYiBjIGRdXG4gICgvICgrIGEgYiBjIGQpIDQpKVxuXG4oZGVmbiBzYWZlLWF2ZXJhZ2UgW2EgYiBjIGRdXG4gIChsZXQgW3RvdGFsIDAgY291bnQgMF1cbiAgICAod2hlbiBhIChhZGQhIHRvdGFsIGEpIChpbmMhIGNvdW50KSlcbiAgICAod2hlbiBiIChhZGQhIHRvdGFsIGIpIChpbmMhIGNvdW50KSlcbiAgICAod2hlbiBjIChhZGQhIHRvdGFsIGMpIChpbmMhIGNvdW50KSlcbiAgICAod2hlbiBkIChhZGQhIHRvdGFsIGQpIChpbmMhIGNvdW50KSlcbiAgICAoLyB0b3RhbCBjb3VudCkpKVxuXG5cbihkZWZuIHJhbmQgW11cbiAgKE1hdGgucmFuZG9tKSlcblxuKGRlZm4gcmFuZC1hcm91bmQtemVybyBbc3ByZWFkXVxuICAoLSAoKiBzcHJlYWQgKHJhbmQpIDIpIHNwcmVhZCkpXG5cblxuKGRlZm4gaml0dGVyIFt2YWx1ZSBzcHJlYWRdXG4gICgrIHZhbHVlIChyYW5kLWFyb3VuZC16ZXJvIHNwcmVhZCkpKVxuXG5cbjsgSGVpZ2h0bWFwIEhlbHBlcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbihkZWZtYWNybyBoZWlnaHRtYXAtZ2V0IFtobSB4IHldXG4gIGAoYWdldCB+aG0gKCsgKCogfnkgKC4tcmVzb2x1dGlvbiB+aG0pKSB+eCkpKVxuXG4oZGVmbiBoZWlnaHRtYXAtZ2V0LXNhZmUgW2htIHggeV1cbiAgKHdoZW4gKGFuZCAoPD0gMCB4IGhtLmxhc3QpXG4gICAgICAgICAgICAgKDw9IDAgeSBobS5sYXN0KSlcbiAgICAoaGVpZ2h0bWFwLWdldCBobSB4IHkpKSlcblxuKGRlZm1hY3JvIGhlaWdodG1hcC1zZXQhIFtobSB4IHkgdmFsXVxuICBgKHNldCEgKGhlaWdodG1hcC1nZXQgfmhtIH54IH55KSB+dmFsKSlcblxuXG4oZGVmbiBub3JtYWxpemUgW2htXVxuICAobGV0IFttYXggKC0gSW5maW5pdHkpXG4gICAgICAgIG1pbiBJbmZpbml0eV1cbiAgICAoZG8tdGltZXMgaSBobS5sZW5ndGhcbiAgICAgIChsZXQgW2VsIChhZ2V0IGhtIGkpXVxuICAgICAgICAod2hlbiAoPCBtYXggZWwpIChzZXQhIG1heCBlbCkpXG4gICAgICAgICh3aGVuICg+IG1pbiBlbCkgKHNldCEgbWluIGVsKSkpKVxuICAgIChsZXQgW3NwYW4gKC0gbWF4IG1pbildXG4gICAgICAoZG8tdGltZXMgaSBobS5sZW5ndGhcbiAgICAgICAgKHNldCEgKGFnZXQgaG0gaSlcbiAgICAgICAgICAoLyAoLSAoYWdldCBobSBpKSBtaW4pXG4gICAgICAgICAgICAgc3BhbikpKSkpKVxuXG4oZGVmbiB6ZXJvLWhlaWdodG1hcCBbaGVpZ2h0bWFwXVxuICAoZG8tdGltZXMgaSBoZWlnaHRtYXAubGVuZ3RoXG4gICAgKHNldCEgKGFnZXQgaGVpZ2h0bWFwIGkpIDAuMCkpXG4gIGhlaWdodG1hcClcblxuKGRlZm4gbWFrZS1oZWlnaHRtYXAgW2V4cG9uZW50XVxuICAobGV0IFtyZXNvbHV0aW9uICgrIDEgKE1hdGgucG93IDIgZXhwb25lbnQpKV1cbiAgICAobCAoKyBcIkNyZWF0aW5nIFwiIHJlc29sdXRpb24gXCIgYnkgXCIgcmVzb2x1dGlvbiBcIiBoZWlnaHRtYXAuLi5cIikpXG4gICAgKGRlZiBoZWlnaHRtYXBcbiAgICAgIChuZXcgQXJyYXkgKCogcmVzb2x1dGlvbiByZXNvbHV0aW9uKSkpXG4gICAgKHNldCEgaGVpZ2h0bWFwLnJlc29sdXRpb24gcmVzb2x1dGlvbilcbiAgICAoc2V0ISBoZWlnaHRtYXAuZXhwb25lbnQgZXhwb25lbnQpXG4gICAgKHNldCEgaGVpZ2h0bWFwLmxhc3QgKC0gcmVzb2x1dGlvbiAxKSlcbiAgICAoemVyby1oZWlnaHRtYXAgaGVpZ2h0bWFwKSkpXG5cblxuOyBSYW5kb20gTm9pc2UgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZm4gcmFuZG9tLW5vaXNlIFtoZWlnaHRtYXBdXG4gIChkby10aW1lcyBpIGhlaWdodG1hcC5sZW5ndGhcbiAgICAoc2V0ISAoYWdldCBoZWlnaHRtYXAgaSkgKHJhbmQpKSkpXG5cblxuOyBNaWRwb2ludCBEaXNwbGFjZW1lbnQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZm4gbXBkLWluaXQtY29ybmVycyBbaGVpZ2h0bWFwXVxuICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIDAgMCAocmFuZCkpXG4gIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgMCBoZWlnaHRtYXAubGFzdCAocmFuZCkpXG4gIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgaGVpZ2h0bWFwLmxhc3QgMCAocmFuZCkpXG4gIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgaGVpZ2h0bWFwLmxhc3QgaGVpZ2h0bWFwLmxhc3QgKHJhbmQpKSlcblxuKGRlZm4gbXBkLWRpc3BsYWNlIFtoZWlnaHRtYXAgbHggcnggYnkgdHkgc3ByZWFkXVxuICAobGV0IFtjeCAobWlkcG9pbnQgbHggcngpXG4gICAgICAgIGN5IChtaWRwb2ludCBieSB0eSlcblxuICAgICAgICBib3R0b20tbGVmdCAoaGVpZ2h0bWFwLWdldCBoZWlnaHRtYXAgbHggYnkpXG4gICAgICAgIGJvdHRvbS1yaWdodCAoaGVpZ2h0bWFwLWdldCBoZWlnaHRtYXAgcnggYnkpXG4gICAgICAgIHRvcC1sZWZ0IChoZWlnaHRtYXAtZ2V0IGhlaWdodG1hcCBseCB0eSlcbiAgICAgICAgdG9wLXJpZ2h0IChoZWlnaHRtYXAtZ2V0IGhlaWdodG1hcCByeCB0eSlcblxuICAgICAgICB0b3AgKGF2ZXJhZ2UyIHRvcC1sZWZ0IHRvcC1yaWdodClcbiAgICAgICAgbGVmdCAoYXZlcmFnZTIgYm90dG9tLWxlZnQgdG9wLWxlZnQpXG4gICAgICAgIGJvdHRvbSAoYXZlcmFnZTIgYm90dG9tLWxlZnQgYm90dG9tLXJpZ2h0KVxuICAgICAgICByaWdodCAoYXZlcmFnZTIgYm90dG9tLXJpZ2h0IHRvcC1yaWdodClcbiAgICAgICAgY2VudGVyIChhdmVyYWdlNCB0b3AgbGVmdCBib3R0b20gcmlnaHQpXVxuICAgIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgY3ggYnkgKGppdHRlciBib3R0b20gc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIGN4IHR5IChqaXR0ZXIgdG9wIHNwcmVhZCkpXG4gICAgKGhlaWdodG1hcC1zZXQhIGhlaWdodG1hcCBseCBjeSAoaml0dGVyIGxlZnQgc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIHJ4IGN5IChqaXR0ZXIgcmlnaHQgc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIGN4IGN5IChqaXR0ZXIgY2VudGVyIHNwcmVhZCkpKSlcblxuKGRlZm4gbWlkcG9pbnQtZGlzcGxhY2VtZW50IFtoZWlnaHRtYXBdXG4gIChtcGQtaW5pdC1jb3JuZXJzIGhlaWdodG1hcClcbiAgOyAobXBkLWRpc3BsYWNlIGhlaWdodG1hcCAwIGhlaWdodG1hcC5sYXN0IDAgaGVpZ2h0bWFwLmxhc3QgMC4xKVxuICAobG9vcCBbaXRlciAwXG4gICAgICAgICBzcHJlYWQgMC4zXVxuICAgICh3aGVuICg8IGl0ZXIgaGVpZ2h0bWFwLmV4cG9uZW50KVxuICAgICAgKGxldCBbY2h1bmtzIChNYXRoLnBvdyAyIGl0ZXIpXG4gICAgICAgICAgICBjaHVuay13aWR0aCAoLyAoLSBoZWlnaHRtYXAucmVzb2x1dGlvbiAxKSBjaHVua3MpXVxuICAgICAgICAoZG8tbmVzdGVkIHhjaHVuayB5Y2h1bmsgY2h1bmtzXG4gICAgICAgICAgKGxldCBbbGVmdC14ICgqIGNodW5rLXdpZHRoIHhjaHVuaylcbiAgICAgICAgICAgICAgICByaWdodC14ICgrIGxlZnQteCBjaHVuay13aWR0aClcbiAgICAgICAgICAgICAgICBib3R0b20teSAoKiBjaHVuay13aWR0aCB5Y2h1bmspXG4gICAgICAgICAgICAgICAgdG9wLXkgKCsgYm90dG9tLXkgY2h1bmstd2lkdGgpXVxuICAgICAgICAgICAgKG1wZC1kaXNwbGFjZSBoZWlnaHRtYXAgbGVmdC14IHJpZ2h0LXggYm90dG9tLXkgdG9wLXkgc3ByZWFkKSkpKVxuICAgICAgKHJlY3VyICgrIDEgaXRlcikgKCogc3ByZWFkIDAuNSkpKSlcbiAgKG5vcm1hbGl6ZSBoZWlnaHRtYXApKVxuXG5cbihkZWZuIG1pZHBvaW50LWRpc3BsYWNlbWVudC1maW5hbCBbaGVpZ2h0bWFwXVxuICAobXBkLWluaXQtY29ybmVycyBoZWlnaHRtYXApXG4gIDsgKGxldCBbc3ByZWFkIF0pXG4gIChsb29wIFtpdGVyIDBcbiAgICAgICAgIHNwcmVhZCAoKyAwICgudmFsICgkIFwiI2lucHV0LXN0YXJ0aW5nLXNwcmVhZFwiKSkpXVxuICAgICh3aGVuICg8IGl0ZXIgaGVpZ2h0bWFwLmV4cG9uZW50KVxuICAgICAgKGxldCBbY2h1bmtzIChNYXRoLnBvdyAyIGl0ZXIpXG4gICAgICAgICAgICBjaHVuay13aWR0aCAoLyAoLSBoZWlnaHRtYXAucmVzb2x1dGlvbiAxKSBjaHVua3MpXVxuICAgICAgICAoZG8tbmVzdGVkIHhjaHVuayB5Y2h1bmsgY2h1bmtzXG4gICAgICAgICAgKGxldCBbbGVmdC14ICgqIGNodW5rLXdpZHRoIHhjaHVuaylcbiAgICAgICAgICAgICAgICByaWdodC14ICgrIGxlZnQteCBjaHVuay13aWR0aClcbiAgICAgICAgICAgICAgICBib3R0b20teSAoKiBjaHVuay13aWR0aCB5Y2h1bmspXG4gICAgICAgICAgICAgICAgdG9wLXkgKCsgYm90dG9tLXkgY2h1bmstd2lkdGgpXVxuICAgICAgICAgICAgKG1wZC1kaXNwbGFjZSBoZWlnaHRtYXAgbGVmdC14IHJpZ2h0LXggYm90dG9tLXkgdG9wLXkgc3ByZWFkKSkpKVxuICAgICAgKHJlY3VyICgrIDEgaXRlcikgKCogc3ByZWFkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAoKyAwICgudmFsICgkIFwiI2lucHV0LXNwcmVhZC1yZWR1Y3Rpb25cIikpKSkpKSlcbiAgKG5vcm1hbGl6ZSBoZWlnaHRtYXApKVxuXG5cbihkZWZuIG1wZC1kaXNwbGFjZS1kMiBbaGVpZ2h0bWFwIGx4IHJ4IGJ5IHR5IHNwcmVhZF1cbiAgKGxldCBbY3ggKG1pZHBvaW50IGx4IHJ4KVxuICAgICAgICBjeSAobWlkcG9pbnQgYnkgdHkpXG5cbiAgICAgICAgYm90dG9tLWxlZnQgKGhlaWdodG1hcC1nZXQgaGVpZ2h0bWFwIGx4IGJ5KVxuICAgICAgICBib3R0b20tcmlnaHQgKGhlaWdodG1hcC1nZXQgaGVpZ2h0bWFwIHJ4IGJ5KVxuICAgICAgICB0b3AtbGVmdCAoaGVpZ2h0bWFwLWdldCBoZWlnaHRtYXAgbHggdHkpXG4gICAgICAgIHRvcC1yaWdodCAoaGVpZ2h0bWFwLWdldCBoZWlnaHRtYXAgcnggdHkpXG5cbiAgICAgICAgdG9wIChhdmVyYWdlMiB0b3AtbGVmdCB0b3AtcmlnaHQpXG4gICAgICAgIGxlZnQgKGF2ZXJhZ2UyIGJvdHRvbS1sZWZ0IHRvcC1sZWZ0KVxuICAgICAgICBib3R0b20gKGF2ZXJhZ2UyIGJvdHRvbS1sZWZ0IGJvdHRvbS1yaWdodClcbiAgICAgICAgcmlnaHQgKGF2ZXJhZ2UyIGJvdHRvbS1yaWdodCB0b3AtcmlnaHQpXVxuICAgIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgY3ggYnkgKGppdHRlciBib3R0b20gc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIGN4IHR5IChqaXR0ZXIgdG9wIHNwcmVhZCkpXG4gICAgKGhlaWdodG1hcC1zZXQhIGhlaWdodG1hcCBseCBjeSAoaml0dGVyIGxlZnQgc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIHJ4IGN5IChqaXR0ZXIgcmlnaHQgc3ByZWFkKSkpKVxuXG4oZGVmbiBtaWRwb2ludC1kaXNwbGFjZW1lbnQtZDEgW2hlaWdodG1hcF1cbiAgKG1wZC1pbml0LWNvcm5lcnMgaGVpZ2h0bWFwKSlcblxuKGRlZm4gbWlkcG9pbnQtZGlzcGxhY2VtZW50LWQyIFtoZWlnaHRtYXBdXG4gIChtcGQtaW5pdC1jb3JuZXJzIGhlaWdodG1hcClcbiAgKG1wZC1kaXNwbGFjZS1kMiBoZWlnaHRtYXBcbiAgICAgICAgICAgICAgICAgICAwIGhlaWdodG1hcC5sYXN0XG4gICAgICAgICAgICAgICAgICAgMCBoZWlnaHRtYXAubGFzdFxuICAgICAgICAgICAgICAgICAgIDAuMSkpXG5cbihkZWZuIG1pZHBvaW50LWRpc3BsYWNlbWVudC1kMyBbaGVpZ2h0bWFwXVxuICAobXBkLWluaXQtY29ybmVycyBoZWlnaHRtYXApXG4gIChtcGQtZGlzcGxhY2UgaGVpZ2h0bWFwXG4gICAgICAgICAgICAgICAgMCBoZWlnaHRtYXAubGFzdFxuICAgICAgICAgICAgICAgIDAgaGVpZ2h0bWFwLmxhc3RcbiAgICAgICAgICAgICAgICAwLjEpKVxuXG5cblxuOyBUaHJlZS5qcyBIZWxwZXJzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZm4gbWFrZS1kaXJlY3Rpb25hbC1saWdodCBbXVxuICAobGV0IFtsaWdodCAobmV3IFRIUkVFLkRpcmVjdGlvbmFsTGlnaHQgMHhmZmZmZmYgMSldXG4gICAgKGxpZ2h0LnBvc2l0aW9uLnNldCAxMDAgMCAxNTApXG4gICAgbGlnaHQpKVxuXG4oZGVmbiBtYWtlLWNhbWVyYSBbXVxuICAobGV0IFtjYW1lcmEgKG5ldyBUSFJFRS5QZXJzcGVjdGl2ZUNhbWVyYVxuICAgICAgICAgICAgICAgICAgICA1NSxcbiAgICAgICAgICAgICAgICAgICAgKC8gd2lkdGggaGVpZ2h0KVxuICAgICAgICAgICAgICAgICAgICAwLjEsXG4gICAgICAgICAgICAgICAgICAgIDEwMDApXVxuICAgIChjYW1lcmEucG9zaXRpb24uc2V0IDAgLTEwMCAxNTApXG4gICAgY2FtZXJhKSlcblxuKGRlZm4gbWFrZS1yZW5kZXJlciBbXVxuICAobGV0IFtyZW5kZXJlciAobmV3IFRIUkVFLldlYkdMUmVuZGVyZXIgezphbnRpYWxpYXMgZmFsc2V9KV1cbiAgICAocmVuZGVyZXIuc2V0Q2xlYXJDb2xvciAweGZmZmZmZilcbiAgICAocmVuZGVyZXIuc2V0U2l6ZSB3aWR0aCBoZWlnaHQpXG4gICAgKHJlbmRlcmVyLnNldFBpeGVsUmF0aW8gMilcbiAgICByZW5kZXJlcikpXG5cbihkZWZuIG1ha2UtZ2VvbWV0cnkgW2hlaWdodG1hcF1cbiAgKGxldCBbZ2VvbWV0cnkgKG5ldyBUSFJFRS5QbGFuZUdlb21ldHJ5XG4gICAgICAgICAgICAgICAgICAgICAgdGVycmFpbi1zaXplXG4gICAgICAgICAgICAgICAgICAgICAgdGVycmFpbi1zaXplXG4gICAgICAgICAgICAgICAgICAgICAgKC0gaGVpZ2h0bWFwLnJlc29sdXRpb24gMSlcbiAgICAgICAgICAgICAgICAgICAgICAoLSBoZWlnaHRtYXAucmVzb2x1dGlvbiAxKSldXG4gICAgKHNldCEgZ2VvbWV0cnkuZHluYW1pYyB0cnVlKVxuICAgIGdlb21ldHJ5KSlcblxuKGRlZm4gbWFrZS1jb250cm9scyBbY2FtZXJhIHJlbmRlcmVyXVxuICAobGV0IFtjb250cm9scyAobmV3IFRIUkVFLlRyYWNrYmFsbENvbnRyb2xzIGNhbWVyYSByZW5kZXJlci5kb21FbGVtZW50KV1cbiAgICAoc2V0ISBjb250cm9scy5yb3RhdGVTcGVlZCAxLjQpXG4gICAgKHNldCEgY29udHJvbHMuem9vbVNwZWVkIDAuNSlcbiAgICAoc2V0ISBjb250cm9scy5zdGF0aWNNb3ZpbmcgdHJ1ZSlcbiAgICAoc2V0ISBjb250cm9scy5keW5hbWljRGFtcGluZ0ZhY3RvciAwLjMpXG4gICAgY29udHJvbHMpKVxuXG4oZGVmbiBtYWtlLXBsYW5lIFtnZW9tZXRyeV1cbiAgKGxldCBbbWF0ZXJpYWwgKG5ldyBUSFJFRS5NZXNoTGFtYmVydE1hdGVyaWFsXG4gICAgICAgICAgICAgICAgICAgICAgezp3aXJlZnJhbWUgd2lyZWZyYW1lXG4gICAgICAgICAgICAgICAgICAgICAgIDp3aXJlZnJhbWVMaW5ld2lkdGggd2lyZWZyYW1lLXdpZHRoXG4gICAgICAgICAgICAgICAgICAgICAgIDpjb2xvciAweDAwYmIwMH0pXVxuICAgIChuZXcgVEhSRUUuTWVzaCBnZW9tZXRyeSBtYXRlcmlhbCkpKVxuXG5cbihkZWZuIGF0dGFjaC10by1kb20gW3JlbmRlcmVyIGVsLW5hbWUgcmVmcmVzaC1mbl1cbiAgKGxldCBbY29udGFpbmVyIChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCBlbC1uYW1lKVxuICAgICAgICBzZXR0aW5ncyAoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCBcImRpdlwiKVxuICAgICAgICByZWZyZXNoLWJ1dHRvbiAoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCBcImJ1dHRvblwiKVxuICAgICAgICBidXR0b24tdGV4dCAoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUgXCJSZWZyZXNoXCIpXG4gICAgICAgIGNhbmNlbC1zY3JvbGwgKGZuIFtlXSAoLnByZXZlbnREZWZhdWx0IGUpKV1cbiAgICAoc2V0ISByZWZyZXNoLWJ1dHRvbi5vbmNsaWNrIHJlZnJlc2gtZm4pXG4gICAgKHNldCEgcmVuZGVyZXIuZG9tRWxlbWVudC5vbm1vdXNld2hlZWwgY2FuY2VsLXNjcm9sbClcbiAgICAocmVuZGVyZXIuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyIFwiTW96TW91c2VQaXhlbFNjcm9sbFwiIGNhbmNlbC1zY3JvbGwgZmFsc2UpXG4gICAgKC5hcHBlbmRDaGlsZCByZWZyZXNoLWJ1dHRvbiBidXR0b24tdGV4dClcbiAgICAoLmFwcGVuZENoaWxkIGNvbnRhaW5lciByZW5kZXJlci5kb21FbGVtZW50KVxuICAgICguYXBwZW5kQ2hpbGQgY29udGFpbmVyIHNldHRpbmdzKVxuICAgICguYXBwZW5kQ2hpbGQgc2V0dGluZ3MgcmVmcmVzaC1idXR0b24pKSlcblxuKGRlZm4gdXBkYXRlLWdlb21ldHJ5IFtnZW9tZXRyeSBoZWlnaHRtYXBdXG4gIChkby10aW1lcyBpIGdlb21ldHJ5LnZlcnRpY2VzLmxlbmd0aFxuICAgIChzZXQhICguLXogKGFnZXQgZ2VvbWV0cnkudmVydGljZXMgaSkpXG4gICAgICAoKiB0ZXJyYWluLWhlaWdodCAoYWdldCBoZWlnaHRtYXAgaSkpKSlcbiAgKHNldCEgZ2VvbWV0cnkudmVydGljZXNOZWVkVXBkYXRlIHRydWUpXG4gIChnZW9tZXRyeS5jb21wdXRlRmFjZU5vcm1hbHMpXG4gIChnZW9tZXRyeS5jb21wdXRlVmVydGV4Tm9ybWFscylcbiAgKGdlb21ldHJ5LmNvbXB1dGVNb3JwaE5vcm1hbHMpXG4gIGdlb21ldHJ5KVxuXG5cbjsgTWFpbiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbihkZWZuIG1ha2UtZGVtbyBbZWxlbWVudC1pZCBhbGdvcml0aG0gc2l6ZV1cbiAgKGRlZiBzY2VuZSAobmV3IFRIUkVFLlNjZW5lKSlcbiAgKHNjZW5lLmFkZCAobmV3IFRIUkVFLkF4aXNIZWxwZXIgMTAwKSlcblxuICAoZGVmIGNsb2NrIChuZXcgVEhSRUUuQ2xvY2spKVxuICAoZGVmIGNhbWVyYSAobWFrZS1jYW1lcmEpKVxuICAoZGVmIHJlbmRlcmVyIChtYWtlLXJlbmRlcmVyKSlcbiAgKGRlZiBnZW9tZXRyeSAobWFrZS1nZW9tZXRyeSAobWFrZS1oZWlnaHRtYXAgc2l6ZSkpKVxuXG4gIChzY2VuZS5hZGQgKG1ha2UtZGlyZWN0aW9uYWwtbGlnaHQpKVxuICAoc2NlbmUuYWRkIChuZXcgVEhSRUUuQW1iaWVudExpZ2h0IDB4ZmZmZmZmIDAuMDUpKVxuICAoc2NlbmUuYWRkIChtYWtlLXBsYW5lIGdlb21ldHJ5KSlcblxuICAoZGVmbiByZWZyZXNoIFtdXG4gICAgKGwgXCJSZWZyZXNoaW5nID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cIilcbiAgICAobGV0IFtoZWlnaHRtYXAgKG1ha2UtaGVpZ2h0bWFwIHNpemUpXVxuICAgICAgKGwgXCJHZW5lcmF0aW5nIHRlcnJhaW4uLi5cIilcbiAgICAgICh0aW1lIChhbGdvcml0aG0gaGVpZ2h0bWFwKSlcbiAgICAgIChsIFwiUmVmcmVzaGluZyBnZW9tZXRyeS4uLlwiKVxuICAgICAgKHRpbWUgKHVwZGF0ZS1nZW9tZXRyeSBnZW9tZXRyeSBoZWlnaHRtYXApKVxuICAgICAgKGwgXCJEb25lIVwiKSkpXG5cbiAgKGF0dGFjaC10by1kb20gcmVuZGVyZXIgZWxlbWVudC1pZCByZWZyZXNoKVxuICAoZGVmIGNvbnRyb2xzIChtYWtlLWNvbnRyb2xzIGNhbWVyYSByZW5kZXJlcikpXG5cbiAgKGRlZm4gcmVuZGVyIFtdXG4gICAgKGxldCBbZGVsdGEgKGNsb2NrLmdldERlbHRhKV1cbiAgICAgIChyZXF1ZXN0QW5pbWF0aW9uRnJhbWUgcmVuZGVyKVxuICAgICAgKC51cGRhdGUgY29udHJvbHMgZGVsdGEpXG4gICAgICAocmVuZGVyZXIucmVuZGVyIHNjZW5lIGNhbWVyYSkpKVxuXG4gIChyZW5kZXIpXG5cbiAgbmlsKVxuXG4oZGVmbiBtYWtlLWZpbmFsIFtlbGVtZW50LWlkXVxuICAoZGVmIHNjZW5lIChuZXcgVEhSRUUuU2NlbmUpKVxuICAoc2NlbmUuYWRkIChuZXcgVEhSRUUuQXhpc0hlbHBlciAxMDApKVxuXG4gIChkZWYgY2xvY2sgKG5ldyBUSFJFRS5DbG9jaykpXG4gIChkZWYgY2FtZXJhIChtYWtlLWNhbWVyYSkpXG4gIChkZWYgcmVuZGVyZXIgKG1ha2UtcmVuZGVyZXIpKVxuICAoZGVmIGhlaWdodG1hcCAobWFrZS1oZWlnaHRtYXAgKC52YWwgKCQgXCIjaW5wdXQtZXhwb25lbnRcIikpKSlcbiAgKGRlZiBnZW9tZXRyeSAobWFrZS1nZW9tZXRyeSBoZWlnaHRtYXApKVxuICAoZGVmIHBsYW5lIChtYWtlLXBsYW5lIGdlb21ldHJ5KSlcblxuICAoc2NlbmUuYWRkIChtYWtlLWRpcmVjdGlvbmFsLWxpZ2h0KSlcbiAgKHNjZW5lLmFkZCAobmV3IFRIUkVFLkFtYmllbnRMaWdodCAweGZmZmZmZiAwLjA1KSlcbiAgKHNjZW5lLmFkZCBwbGFuZSlcblxuICAoZGVmbiByZWZyZXNoIFtdXG4gICAgKGwgXCJSZWZyZXNoaW5nID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cIilcbiAgICAoc2NlbmUucmVtb3ZlIHBsYW5lKVxuICAgIChzZXQhIGhlaWdodG1hcCAobWFrZS1oZWlnaHRtYXAgKC52YWwgKCQgXCIjaW5wdXQtZXhwb25lbnRcIikpKSlcbiAgICAoc2V0ISBnZW9tZXRyeSAobWFrZS1nZW9tZXRyeSBoZWlnaHRtYXApKVxuICAgIChzZXQhIHBsYW5lIChtYWtlLXBsYW5lIGdlb21ldHJ5KSlcbiAgICAoc2NlbmUuYWRkIHBsYW5lKVxuICAgIChsIFwiR2VuZXJhdGluZyB0ZXJyYWluLi4uXCIpXG4gICAgKHRpbWUgKG1pZHBvaW50LWRpc3BsYWNlbWVudC1maW5hbCBoZWlnaHRtYXApKVxuICAgIChsIFwiUmVmcmVzaGluZyBnZW9tZXRyeS4uLlwiKVxuICAgICh0aW1lICh1cGRhdGUtZ2VvbWV0cnkgZ2VvbWV0cnkgaGVpZ2h0bWFwKSlcbiAgICAobCBcIkRvbmUhXCIpKVxuXG4gIChhdHRhY2gtdG8tZG9tIHJlbmRlcmVyIGVsZW1lbnQtaWQgcmVmcmVzaClcbiAgKGRlZiBjb250cm9scyAobWFrZS1jb250cm9scyBjYW1lcmEgcmVuZGVyZXIpKVxuXG4gIChkZWZuIHJlbmRlciBbXVxuICAgIChsZXQgW2RlbHRhIChjbG9jay5nZXREZWx0YSldXG4gICAgICAocmVxdWVzdEFuaW1hdGlvbkZyYW1lIHJlbmRlcilcbiAgICAgICgudXBkYXRlIGNvbnRyb2xzIGRlbHRhKVxuICAgICAgKHJlbmRlcmVyLnJlbmRlciBzY2VuZSBjYW1lcmEpKSlcblxuICAocmVuZGVyKVxuXG4gIG5pbClcblxuXG4oZGVmbiBydW4gW11cbiAgKG1ha2UtZGVtbyBcImRlbW8tcmFuZG9tXCIgcmFuZG9tLW5vaXNlIDcpXG4gIChtYWtlLWRlbW8gXCJkZW1vLW1wZC0xXCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50LWQxIDIpXG4gIChtYWtlLWRlbW8gXCJkZW1vLW1wZC0yXCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50LWQyIDIpXG4gIChtYWtlLWRlbW8gXCJkZW1vLW1wZC0zXCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50LWQzIDIpXG4gIChtYWtlLWRlbW8gXCJkZW1vLW1wZC00XCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50IDMpXG4gIChtYWtlLWZpbmFsIFwiZGVtby1maW5hbFwiKVxuICA7IChtYWtlLWRlbW8gXCJkZW1vLW1pZHBvaW50XCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50KVxuICA7IChtYWtlLWRlbW8gXCJkZW1vLWRpYW1vbmRcIiBkaWFtb25kLXNxdWFyZSlcblxuICApXG5cbigkIHJ1bilcblxuXG47IHZpbTogbHcrPWRvLXRpbWVzIGx3Kz1kby1uZXN0ZWQgOlxuIl19 diff -r 37c769f2a211 -r e2b8f5dc9ae4 media/js/wisp/terrain1.wisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/media/js/wisp/terrain1.wisp Sun Feb 28 11:51:50 2016 +0000 @@ -0,0 +1,392 @@ +; Constants ------------------------------------------------------------------- +(def width 610) +(def height 400) +(def wireframe true) +(def wireframe-width 1.2) +(def terrain-height 50) +(def terrain-size 100) + +; General Utilities ----------------------------------------------------------- +(defmacro when [condition & body] + `(if ~condition + (do ~@body))) + +(defmacro do-times [varname limit & body] + (let [end (gensym)] + `(let [~end ~limit] + (loop [~varname 0] + (when (< ~varname ~end) + ~@body + (recur (+ 1 ~varname))))))) + +(defmacro do-nested [xname yname width & body] + (let [iterations (gensym)] + `(let [~iterations ~width] + (do-times ~xname ~iterations + (do-times ~yname ~iterations + ~@body))))) + +(defmacro inc! [place] + `(set! ~place (+ ~place 1))) + +(defmacro add! [place amount] + `(set! ~place (+ ~place ~amount))) + +(defmacro time [& body] + (let [start (gensym) + end (gensym) + result (gensym)] + `(let [~start (.getTime (new Date)) + ~result (do ~@body) + ~end (.getTime (new Date))] + (l (+ "Elapsed time: " (- ~end ~start) "ms.")) + ~result))) + +(defn l [v] + (console.log v)) + + +(defn midpoint [a b] + (/ (+ a b) 2)) + +(defn average2 [a b] + (/ (+ a b) 2)) + +(defn average4 [a b c d] + (/ (+ a b c d) 4)) + +(defn safe-average [a b c d] + (let [total 0 count 0] + (when a (add! total a) (inc! count)) + (when b (add! total b) (inc! count)) + (when c (add! total c) (inc! count)) + (when d (add! total d) (inc! count)) + (/ total count))) + + +(defn rand [] + (Math.random)) + +(defn rand-around-zero [spread] + (- (* spread (rand) 2) spread)) + + +(defn jitter [value spread] + (+ value (rand-around-zero spread))) + + +; Heightmap Helpers ----------------------------------------------------------- +(defmacro heightmap-get [hm x y] + `(aget ~hm (+ (* ~y (.-resolution ~hm)) ~x))) + +(defn heightmap-get-safe [hm x y] + (when (and (<= 0 x hm.last) + (<= 0 y hm.last)) + (heightmap-get hm x y))) + +(defmacro heightmap-set! [hm x y val] + `(set! (heightmap-get ~hm ~x ~y) ~val)) + + +(defn normalize [hm] + (let [max (- Infinity) + min Infinity] + (do-times i hm.length + (let [el (aget hm i)] + (when (< max el) (set! max el)) + (when (> min el) (set! min el)))) + (let [span (- max min)] + (do-times i hm.length + (set! (aget hm i) + (/ (- (aget hm i) min) + span)))))) + +(defn zero-heightmap [heightmap] + (do-times i heightmap.length + (set! (aget heightmap i) 0.0)) + heightmap) + +(defn make-heightmap [exponent] + (let [resolution (+ 1 (Math.pow 2 exponent))] + (l (+ "Creating " resolution " by " resolution " heightmap...")) + (def heightmap + (new Array (* resolution resolution))) + (set! heightmap.resolution resolution) + (set! heightmap.exponent exponent) + (set! heightmap.last (- resolution 1)) + (zero-heightmap heightmap))) + + +; Random Noise ---------------------------------------------------------------- +(defn random-noise [heightmap] + (do-times i heightmap.length + (set! (aget heightmap i) (rand)))) + + +; Midpoint Displacement ------------------------------------------------------- +(defn mpd-init-corners [heightmap] + (heightmap-set! heightmap 0 0 (rand)) + (heightmap-set! heightmap 0 heightmap.last (rand)) + (heightmap-set! heightmap heightmap.last 0 (rand)) + (heightmap-set! heightmap heightmap.last heightmap.last (rand))) + +(defn mpd-displace [heightmap lx rx by ty spread] + (let [cx (midpoint lx rx) + cy (midpoint by ty) + + bottom-left (heightmap-get heightmap lx by) + bottom-right (heightmap-get heightmap rx by) + top-left (heightmap-get heightmap lx ty) + top-right (heightmap-get heightmap rx ty) + + top (average2 top-left top-right) + left (average2 bottom-left top-left) + bottom (average2 bottom-left bottom-right) + right (average2 bottom-right top-right) + center (average4 top left bottom right)] + (heightmap-set! heightmap cx by (jitter bottom spread)) + (heightmap-set! heightmap cx ty (jitter top spread)) + (heightmap-set! heightmap lx cy (jitter left spread)) + (heightmap-set! heightmap rx cy (jitter right spread)) + (heightmap-set! heightmap cx cy (jitter center spread)))) + +(defn midpoint-displacement [heightmap] + (mpd-init-corners heightmap) + ; (mpd-displace heightmap 0 heightmap.last 0 heightmap.last 0.1) + (loop [iter 0 + spread 0.3] + (when (< iter heightmap.exponent) + (let [chunks (Math.pow 2 iter) + chunk-width (/ (- heightmap.resolution 1) chunks)] + (do-nested xchunk ychunk chunks + (let [left-x (* chunk-width xchunk) + right-x (+ left-x chunk-width) + bottom-y (* chunk-width ychunk) + top-y (+ bottom-y chunk-width)] + (mpd-displace heightmap left-x right-x bottom-y top-y spread)))) + (recur (+ 1 iter) (* spread 0.5)))) + (normalize heightmap)) + + +(defn midpoint-displacement-final [heightmap] + (mpd-init-corners heightmap) + ; (let [spread ]) + (loop [iter 0 + spread (+ 0 (.val ($ "#input-starting-spread")))] + (when (< iter heightmap.exponent) + (let [chunks (Math.pow 2 iter) + chunk-width (/ (- heightmap.resolution 1) chunks)] + (do-nested xchunk ychunk chunks + (let [left-x (* chunk-width xchunk) + right-x (+ left-x chunk-width) + bottom-y (* chunk-width ychunk) + top-y (+ bottom-y chunk-width)] + (mpd-displace heightmap left-x right-x bottom-y top-y spread)))) + (recur (+ 1 iter) (* spread + (+ 0 (.val ($ "#input-spread-reduction"))))))) + (normalize heightmap)) + + +(defn mpd-displace-d2 [heightmap lx rx by ty spread] + (let [cx (midpoint lx rx) + cy (midpoint by ty) + + bottom-left (heightmap-get heightmap lx by) + bottom-right (heightmap-get heightmap rx by) + top-left (heightmap-get heightmap lx ty) + top-right (heightmap-get heightmap rx ty) + + top (average2 top-left top-right) + left (average2 bottom-left top-left) + bottom (average2 bottom-left bottom-right) + right (average2 bottom-right top-right)] + (heightmap-set! heightmap cx by (jitter bottom spread)) + (heightmap-set! heightmap cx ty (jitter top spread)) + (heightmap-set! heightmap lx cy (jitter left spread)) + (heightmap-set! heightmap rx cy (jitter right spread)))) + +(defn midpoint-displacement-d1 [heightmap] + (mpd-init-corners heightmap)) + +(defn midpoint-displacement-d2 [heightmap] + (mpd-init-corners heightmap) + (mpd-displace-d2 heightmap + 0 heightmap.last + 0 heightmap.last + 0.1)) + +(defn midpoint-displacement-d3 [heightmap] + (mpd-init-corners heightmap) + (mpd-displace heightmap + 0 heightmap.last + 0 heightmap.last + 0.1)) + + + +; Three.js Helpers ------------------------------------------------------------ +(defn make-directional-light [] + (let [light (new THREE.DirectionalLight 0xffffff 1)] + (light.position.set 100 0 150) + light)) + +(defn make-camera [] + (let [camera (new THREE.PerspectiveCamera + 55, + (/ width height) + 0.1, + 1000)] + (camera.position.set 0 -100 150) + camera)) + +(defn make-renderer [] + (let [renderer (new THREE.WebGLRenderer {:antialias false})] + (renderer.setClearColor 0xffffff) + (renderer.setSize width height) + (renderer.setPixelRatio 2) + renderer)) + +(defn make-geometry [heightmap] + (let [geometry (new THREE.PlaneGeometry + terrain-size + terrain-size + (- heightmap.resolution 1) + (- heightmap.resolution 1))] + (set! geometry.dynamic true) + geometry)) + +(defn make-controls [camera renderer] + (let [controls (new THREE.TrackballControls camera renderer.domElement)] + (set! controls.rotateSpeed 1.4) + (set! controls.zoomSpeed 0.5) + (set! controls.staticMoving true) + (set! controls.dynamicDampingFactor 0.3) + controls)) + +(defn make-plane [geometry] + (let [material (new THREE.MeshLambertMaterial + {:wireframe wireframe + :wireframeLinewidth wireframe-width + :color 0x00bb00})] + (new THREE.Mesh geometry material))) + + +(defn attach-to-dom [renderer el-name refresh-fn] + (let [container (document.getElementById el-name) + settings (document.createElement "div") + refresh-button (document.createElement "button") + button-text (document.createTextNode "Refresh") + cancel-scroll (fn [e] (.preventDefault e))] + (set! refresh-button.onclick refresh-fn) + (set! renderer.domElement.onmousewheel cancel-scroll) + (renderer.domElement.addEventListener "MozMousePixelScroll" cancel-scroll false) + (.appendChild refresh-button button-text) + (.appendChild container renderer.domElement) + (.appendChild container settings) + (.appendChild settings refresh-button))) + +(defn update-geometry [geometry heightmap] + (do-times i geometry.vertices.length + (set! (.-z (aget geometry.vertices i)) + (* terrain-height (aget heightmap i)))) + (set! geometry.verticesNeedUpdate true) + (geometry.computeFaceNormals) + (geometry.computeVertexNormals) + (geometry.computeMorphNormals) + geometry) + + +; Main ------------------------------------------------------------------------ +(defn make-demo [element-id algorithm size] + (def scene (new THREE.Scene)) + (scene.add (new THREE.AxisHelper 100)) + + (def clock (new THREE.Clock)) + (def camera (make-camera)) + (def renderer (make-renderer)) + (def geometry (make-geometry (make-heightmap size))) + + (scene.add (make-directional-light)) + (scene.add (new THREE.AmbientLight 0xffffff 0.05)) + (scene.add (make-plane geometry)) + + (defn refresh [] + (l "Refreshing ========================================") + (let [heightmap (make-heightmap size)] + (l "Generating terrain...") + (time (algorithm heightmap)) + (l "Refreshing geometry...") + (time (update-geometry geometry heightmap)) + (l "Done!"))) + + (attach-to-dom renderer element-id refresh) + (def controls (make-controls camera renderer)) + + (defn render [] + (let [delta (clock.getDelta)] + (requestAnimationFrame render) + (.update controls delta) + (renderer.render scene camera))) + + (render) + + nil) + +(defn make-final [element-id] + (def scene (new THREE.Scene)) + (scene.add (new THREE.AxisHelper 100)) + + (def clock (new THREE.Clock)) + (def camera (make-camera)) + (def renderer (make-renderer)) + (def heightmap (make-heightmap (.val ($ "#input-exponent")))) + (def geometry (make-geometry heightmap)) + (def plane (make-plane geometry)) + + (scene.add (make-directional-light)) + (scene.add (new THREE.AmbientLight 0xffffff 0.05)) + (scene.add plane) + + (defn refresh [] + (l "Refreshing ========================================") + (scene.remove plane) + (set! heightmap (make-heightmap (.val ($ "#input-exponent")))) + (set! geometry (make-geometry heightmap)) + (set! plane (make-plane geometry)) + (scene.add plane) + (l "Generating terrain...") + (time (midpoint-displacement-final heightmap)) + (l "Refreshing geometry...") + (time (update-geometry geometry heightmap)) + (l "Done!")) + + (attach-to-dom renderer element-id refresh) + (def controls (make-controls camera renderer)) + + (defn render [] + (let [delta (clock.getDelta)] + (requestAnimationFrame render) + (.update controls delta) + (renderer.render scene camera))) + + (render) + + nil) + + +(defn run [] + (make-demo "demo-random" random-noise 7) + (make-demo "demo-mpd-1" midpoint-displacement-d1 2) + (make-demo "demo-mpd-2" midpoint-displacement-d2 2) + (make-demo "demo-mpd-3" midpoint-displacement-d3 2) + (make-demo "demo-mpd-4" midpoint-displacement 3) + (make-final "demo-final") + ; (make-demo "demo-midpoint" midpoint-displacement) + ; (make-demo "demo-diamond" diamond-square) + + ) + +($ run) + + +; vim: lw+=do-times lw+=do-nested : diff -r 37c769f2a211 -r e2b8f5dc9ae4 requirements.txt --- a/requirements.txt Fri Feb 19 19:48:12 2016 +0000 +++ b/requirements.txt Sun Feb 28 11:51:50 2016 +0000 @@ -1,5 +1,4 @@ -e git://github.com/django/django.git@stable/1.1.x#egg=django --e git://github.com/fabric/fabric.git@0.9rc2#egg=fabric -e svn+http://typogrify.googlecode.com/svn/trunk/#egg=typogrify -e hg+http://bitbucket.org/cherrypy/cherrypy@cherrypy-3.2.0rc1#egg=cherrypy -e git://github.com/waylan/python-markdown.git#egg=markdown diff -r 37c769f2a211 -r e2b8f5dc9ae4 settings.py --- a/settings.py Fri Feb 19 19:48:12 2016 +0000 +++ b/settings.py Sun Feb 28 11:51:50 2016 +0000 @@ -46,9 +46,6 @@ '.png': ('hydeengine.media_processors.Thumbnail',), '.jpg': ('hydeengine.media_processors.Thumbnail',), }, - 'js/': { - '.wisp': ('custom.processors.Wisp',), - }, } CONTENT_PROCESSORS = {}