Source: extras/PerlinTexture.js

/**
 *  @class PerlinTexture
 *  @memberof SQR
 *
 *  @description Utility to generate procedural textures based on Perlin noise.
 */
SQR.PerlinTexture = function(canvas, options) {

	var BADCTX = "> SQR.PerlinTexture - Invalid canvas reference.";

	if(!canvas) canvas = document.createElement('canvas');
	if(!(canvas instanceof HTMLElement)) canvas = document.querySelector(canvas);
	if(!canvas.getContext) throw BADCTX;

	var tt = {
		offset: new SQR.V3(0, 0, 0),
		canvas: canvas
	};

	var ctx, width, height, data;

	var interpolate = function(v, s, e) {
		if(v <= s) return 0;
		if(v >= e) return 1;
		return (v - s) / (e - s);
	}

	tt.create = function(w, h, noCanvas) {
		width = w | 0;
		height = h | 0 || w;

		if(!noCanvas) {
			ctx = canvas.getContext('2d');
			canvas.width = width;
			canvas.height = height;
			data = ctx.getImageData(0, 0, width, height);
		}

		return tt;
	}

	tt.configure = function(c) {
		// low, high, octaves, factors, seed, offset
		c.low = c.low || 0;
		c.high = c.high || 0;
		c.octaves = c.octaves || [1];
		c.factors = c.factors || [1];
		c.seed = c.seed || 0;
		tt.config = c;

		SQR.PerlinNoise.seed(c.seed);

		return tt;
	}	

	tt.setOffset = function(x, y, z) {
		tt.offset.set(x, y, z);
		return tt;
	}

	tt.getValue = function(x, y) {
		var col = 0;
		var cf = tt.config;
		var ol = cf.octaves.length;

		for(var k = 0; k < ol; k++) {

			var c = SQR.PerlinNoise.simplex3(
				(x + tt.offset.x * cf.factors[k]) / height * cf.octaves[k],
				(y + tt.offset.y * cf.factors[k]) / width * cf.octaves[k],
				tt.offset.z
			);

			c = (c + 1) * 0.5; // Get it to [0-1]
			c = c * cf.factors[k];

			col += c;
		}

		col = col / ol;
		col = interpolate(col, cf.low, cf.high);
		return col;
	}

	tt.getPixel = function(x, y) {
		var i = (y * width + x) * 4;
		return data.data[i+0] / 255; // Just return red
	}

	tt.draw = function() {

		var l = width * height * 4;
		for(var i = 0; i < l; i += 4) {

			var px = (i/4) % width;
			var py = (i/4) / height;
			var col = tt.getValue(px, py);

			col = (col * 255) | 0;

			data.data[i+0] = col;
			data.data[i+1] = col;
			data.data[i+2] = col;

			data.data[i+3] = 255;
			
		}
		
		ctx.putImageData(data, 0, 0);

		return tt;
	}

	return tt;
}