diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/README.md diff --git a/js/jsPerlinNoise.js b/js/jsPerlinNoise.js new file mode 100644 index 0000000..c98ba14 --- /dev/null +++ b/js/jsPerlinNoise.js @@ -0,0 +1,235 @@ +/* +* +* A Perlin Noise generator to dynamically generate a terrian-like effect. +* +* References: +* http://freespace.virgin.net/hugo.elias/models/m_perlin.htm +* +* Start date: 28 April 2015 +* +*/ +var perlin = (function() { + 'use strict'; + + // number of points to generate + var _NUMPTS = 101; + + // number of prime numbers in each array + var _NUMPRIMES = 5; + + // holds the 5, 6 and 10 digit prime numbers + let _p5d; + let _p6d; + let _p10d; + + // 5 digit prime numbers + var _prime5 = [ 15731, 16069, 17579, 31963, 22453]; + var _prime6 = [ 789221, 790289, 811081, 211777, 566173]; + var _prime10 = [1376312589, 1480028201, 1500450271, 1000075057, 1023465798]; + + // holds the 100 points + var _perlin = []; + + // initialize the array + for (var i = 0; i < _NUMPTS; i++) { + _perlin[i] = 0.0; + } + + // get a random number from each of the prime number arrays + _p5d = _prime5[Math.floor(Math.random() * 5)]; + _p6d = _prime6[Math.floor(Math.random() * 5)]; + _p10d = _prime10[Math.floor(Math.random() * 5)]; + + + + var _perlin1D = function(persist, octave, x) { + + var total = 0; + var freq = 0; + var amp = 0; + + for (var i = 0; i < octave; i++) { + freq = Math.pow(2, i); + amp = Math.pow(persist, i); + total += _interpolateNoise(x * freq) * amp; + } + + return total; + }; + + /* + * interpolatedNoise - performs a successive smoothing functions on the + * input value. + * + * ARGUMENT: + * x: float value to be smoothed. + */ + var _interpolateNoise = function(x) { + + var intX = Math.floor(x); + var fractionX = x - intX; + + var v1 = _smoothedNoise(intX); + var v2 = _smoothedNoise(intX + 1); + + return _cosineInterpolation(v1, v2, fractionX); + }; + + /* + * cosineInterpolation - + * + * Interpolates between two numbers using a cosine function + */ + var _cosineInterpolation = function (a, b, x) { + + var ft = (x * Math.PI); + var f = (1 - Math.cos(ft)) * 0.5; + + return a * (1 - f) + (b * f); + + }; + + /* + * findNoise - Random number generator. Unlike other RNG this method + * will return the same number for the same input. + * + * ARGUMENTS: + * x: an integer value + * + * RETURNS: + * returns a floating point number between -1.0 and 1.0. + */ + var _findNoise = function(x) { + x = (x << 13) ^ x; + + return (1.0 - ( ( x * (x * x * _p5d + _p6d) + _p10d) + & 0x7fffffff ) / 1073741824.0); + + // original return value as published on + // http://freespace.virgin.net/hugo.elias/models/m_perlin.htm + + }; + + /* + * smoothedNoise - smooths the output to make it look less random + * + * ARGUMENTS: + * x: integer value to be smoothed. It is done by averaging between + * the points before and after the given point. + * + * RETURNS: + * a float value that has been "smoothed". + */ + var _smoothedNoise = function(x) { + return (_findNoise(x) /2) + (_findNoise(x - 1) / 4) + _findNoise(x+1)/4; + }; + + var perlinNoise1D = function(persist, octave) { + + for (var i = 0; i < _NUMPTS; i++) { + _perlin[i] = _perlin1D(persist, octave, 0.1 * i); + } + + return _perlin; + + }; + + /* + * draw the "terrain" on the given context + */ + var draw = function(context, width, height, color, fill) { + + if (context === undefined) + return null; + + if (color === undefined) + color = '#000000'; // black + + if (width === undefined) + width = 400; + + if (height === undefined) + height = 400; + + if (fill === undefined) + fill = true; + + var step = width / _NUMPTS; + + context.lineWidth = 1; + context.strokeStyle = color; + + // start drawing at the bottom left corner + context.beginPath(); + context.moveTo(0, height); + + for (var i = 0; i < _NUMPTS; i++) { + context.lineTo(step * i, height / 2 + _perlin[i] * height / 2); + } + + context.lineTo(width, height / 2 + _perlin[_NUMPTS - 1] * height / 2); + context.lineTo(width, height); + context.closePath(); + context.stroke(); + + if (fill) { + context.fillStyle = color; + context.fill(); + } + + }; + + // public functions + return { + + perlinNoise1D: perlinNoise1D, + draw: draw + + }; + +})(); + +var canvas = document.getElementById('canvas'); +var context = canvas.getContext('2d'); +canvas.width = 800; +canvas.height = 400; + +function drawTerrain() { + + var octave = document.getElementById('octave'); + octave.addEventListener("change", generate, false); + + var persist = document.getElementById('persist'); + persist.addEventListener("change", generate, false); + + function generate() { + context.clearRect(0, 0, canvas.width, canvas.height); + perlin.perlinNoise1D(persist.value, octave.value); + perlin.draw(context, canvas.width, canvas.height); + } + +} + +function eventWindowLoaded() { + perlin.perlinNoise1D(0.3, 4); + perlin.draw(context, canvas.width, canvas.height); + drawTerrain(); + + let perlin1 = new (perlin.perlinNoise1D(0.3, 4))(); + + console.log("perlin1:"); + console.log(perlin1); + + let perlin2 = new (perlin.perlinNoise1D(0.3, 4))(); + console.log("perlin2"); + console.log(perlin2); + +} + +window.addEventListener("load", eventWindowLoaded, false); + + +//var pts = perlin.perlinNoise1D(0.3, 1); +//perlin.draw(context, canvas.width, canvas.height); + + diff --git a/jsPerlinNoise.html b/jsPerlinNoise.html new file mode 100644 index 0000000..61580ec --- /dev/null +++ b/jsPerlinNoise.html @@ -0,0 +1,29 @@ + + + + + HTML5 Template + + + +
+ + + + + + + +

+ +
+ + + + + + \ No newline at end of file