displacement-map
Version:
Mid-point displacement map
83 lines (60 loc) • 4.89 kB
JavaScript
/**
* WorkerString magic - regex replaces this empty string with built worker code string
* @TODO this is fragile and will need some love
*/
;
exports.__esModule = true;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var displacementLineWorkerString = '"use strict";var buf8,roughness;function clamp(num){return Math.min(Math.max(num,0),255)}function variance(){return-128+Math.random()*255}function generateMidpoint(start,end){var length=end-start;var avg=(buf8[end]+buf8[start])/2;var displacement=.5*variance()*roughness*(length/buf8.length-1);buf8[start+length/2]=clamp(avg*1+displacement)}function generate(step){if(!step){step=1}var size=(buf8.length-1)*step;for(var i=0;i<buf8.length-1;i+=size){generateMidpoint(i,i+size)}if(size>2){generate(step*.5);return}done()}self.addEventListener("message",function(event){buf8=event.data.buf8;roughness=event.data.roughness||1;generate()});function done(){self.postMessage({buf8:buf8})}';
var displacementMapWorkerString = '"use strict";var map,height,width,roughness;function clamp(num){return Math.min(Math.max(num,0),255)}function to1d(x,y){return y*width+x}function wrapX(num){var min=0;var max=width-1;if(num>max){return num%max}if(num<min){return max-(min-num)%(max-min)}return num}function wrapY(num){var min=0;var max=height-1;if(num>max){return num%max}if(num<min){return max-(min-num)%(max-min)}return num}function get(x,y){return map[to1d(wrapX(x),wrapY(y))]}function set(x,y,value){map[to1d(wrapX(x),wrapY(y))]=value&255}function variance(){return-128+Math.random()*255}function getMidpointDisplacement(size){return clamp(variance()*roughness*(size/(width-1)))}function getAvg(){return Array.prototype.reduce.call(arguments,function(prev,num){return prev+num})/arguments.length}function getAvgEdge(x1,y1,x2,y2){var size=~~(x2-x1)/2;return getAvg(get(x1+size,y1),get(x1,y1+size),get(x2,y1+size),get(x1+size,y2))}function getAvgCorner(x1,y1,x2,y2){return getAvg(get(x1,y1),get(x2,y1),get(x1,y2),get(x2,y2))}function getAvgPoint(x,y,size){return getAvg(get(x,y-size),get(x+size,y),get(x-size,y),get(x,y+size))}function iterate(cb,step){var size=(width-1)*step;for(var x=0;x<width-1;x+=size){for(var y=0;y<height-1;y+=size){cb(x,y,size)}}}function performSquareStep(x,y,size){var mid=size/2;var avg=getAvgCorner(x,y,x+size,y+size);set(x+mid,y+mid,avg+getMidpointDisplacement(size))}function performDiamondStep(x,y,size){var mid=size/2;var setCell=function setCell(xx,yy){var avg=getAvgPoint(xx,yy,mid);set(xx,yy,avg+getMidpointDisplacement(size))};setCell(x+mid,y);setCell(x+mid,y+size);setCell(x,y+mid);setCell(x+size,y+mid)}function generate(step){if(!step){step=1}var size=(width-1)*step;iterate(performSquareStep,step);iterate(performDiamondStep,step);if(size>2){generate(step/2);return}done()}self.addEventListener("message",function(event){map=event.data.map;height=event.data.height;width=event.data.width;roughness=event.data.roughness||1;generate(1)});function done(){self.postMessage({map:map})}';
var mapBlob = new Blob([displacementMapWorkerString]);
var mapURI = window.URL.createObjectURL(mapBlob);
var lineBlob = new Blob([displacementLineWorkerString]);
var lineURI = window.URL.createObjectURL(lineBlob);
var Generator = (function () {
function Generator(opts) {
_classCallCheck(this, Generator);
this.opts = opts || {};
}
Generator.prototype.debug = function debug() {
if (!this.opts.debug) {
return;
}
console.log.apply(console, arguments);
};
Generator.prototype.generate = function generate(opts) {
var _this = this;
return new Promise(function (resolve, reject) {
var worker = new window.Worker(mapURI);
worker.onmessage = function (event) {
_this.debug('worker status:', event.data);
worker.terminate();
resolve(event.data.map);
};
worker.postMessage({
map: opts.map,
width: opts.width,
height: opts.height,
roughness: opts.roughness
});
});
};
Generator.prototype.generateLine = function generateLine(opts) {
var _this2 = this;
return new Promise(function (resolve, reject) {
var worker = new window.Worker(lineURI);
worker.onmessage = function (event) {
_this2.debug('line worker status', event.data);
worker.terminate();
resolve(event.data.buf8);
};
worker.postMessage({
buf8: opts.buf8,
roughness: opts.roughness
});
});
};
return Generator;
})();
exports['default'] = Generator;
module.exports = exports['default'];