Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

HTML

            
              <div id="screen">
    <div id="scene">
      <div id="container"></div>
      <div id="start">Generate</div>
      <div id="stats"></div>
    </div>
</div>

<script type="text/js-worker">
  //This is required to be here so that the program can use web-workers within the context of Codepen.
  
function RefValue(value){
    this.val = value;
}

function Geometry(){
    this.x = 0;
    this.y = 0;
    this.z = 0;
    this.vertices = new Array();
    this.faces = new Array();
    this.colors = new Array();
    this.faceColors = new Array();
}

Geometry.prototype.GetVertexBuffer = function(){
    var buffer = new ArrayBuffer(this.vertices.length * 3 * 4);
    var floatArray = new Float32Array(buffer);
    
    for(var i = 0; i < this.vertices.length; i++){
        floatArray[i * 3] = this.vertices[i].x;
        floatArray[(i * 3) + 1] = this.vertices[i].y;
        floatArray[(i * 3) + 2] = this.vertices[i].z;
    }
    
    return buffer;
};

Geometry.prototype.GetFaceBuffer = function(){
    var buffer = new ArrayBuffer(this.faces.length * 3 * 4);
    var intArray = new Int32Array(buffer);
    
    for(var i = 0; i < this.faces.length; i++){
        intArray[i * 3] = this.faces[i].a;
        intArray[(i * 3) + 1] = this.faces[i].b;
        intArray[(i * 3) + 2] = this.faces[i].c;
    }
    
    return buffer;
};

Geometry.prototype.GetLightBuffer = function(){
    var buffer = new ArrayBuffer(this.faceColors.length * 2);
    var byteArray = new Int8Array(buffer);
    
    for(var i = 0; i < this.faceColors.length; i++){
        byteArray[(i * 2)] = this.faceColors[i];
        byteArray[(i * 2) + 1] = this.faceColors[i];
    }
    
    return buffer;
};

Geometry.prototype.GetColorBuffer = function(){
    var buffer = new ArrayBuffer(this.colors.length);
    var byteArray = new Int8Array(buffer);
    
    for(var i = 0; i < this.colors.length; i++){
        byteArray[i] = this.colors[i];
    };
    
    return buffer;
};

function Vector3(x,y,z){
    this.x = x;
    this.y = y;
    this.z = z;
}

function Face3(a,b,c){
    this.a = a;
    this.b = b;
    this.c = c;
}

// Needed a seedable random function
// ==================================
function Rand(seed){
    this.m_w = seed;
    this.m_z = 987654321;
    this.mask = 0xffffffff;
    
    this.Next = function (){
        this.m_z = (36969 * (this.m_z & 65535) + (this.m_z >> 16)) & this.mask;
        this.m_w = (18000 * (this.m_w & 65535) + (this.m_w >> 16)) & this.mask;
        var result = ((this.m_z << 16) + this.m_w) & this.mask;
        result /= 4294967296;
        return result + 0.5;
    };
}

// Implementation of Ken Perlin's improved noise algorithm
//  Just perlin noise, not simplex noise.
// ========================================================
function ImprovedPerlin(seed){
    this.p = new Array(512);
    this.rand = new Rand(seed);
    
    for(var i = 0; i < 256; i++)
        this.p[i] = i;
    
    for(var i = 255; i > 0; i--){
        var j = Math.floor(this.rand.Next() * (i + 1));
        var tmp = this.p[j];
        this.p[j] = this.p[i];
        this.p[i] = tmp;
        this.p[i + 256] = this.p[i];
        this.p[j + 256] = this.p[j];
    }
    
    this.Fade = function(t){
        return t * t * t * (t * (t * 6 - 15) + 10);
    };
    
    this.Lerp = function(t, a, b){
        return a + t * (b - a);
    };
    
    this.Grad = function(hash, x, y, z){
        var h = hash & 15;
        var u = h < 8 ? x : y;
        var v = h < 4 ? y : h == 12 || h == 14 ? x : z;
        
        return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
    };
    
    this.Noise = function (x, y, z){
        var X = (x & 255);
        var Y = (y & 255);
        var Z = (z & 255);
        
        x = x - Math.floor(x);
        y = y - Math.floor(y);
        z = z - Math.floor(z);
        
        var u = this.Fade(x);
        var v = this.Fade(y);
        var w = this.Fade(z);
        
        var A = this.p[X] + Y;
        var AA = this.p[A] + Z;
        var AB = this.p[A + 1] + Z;
        var B = this.p[X + 1] + Y;
        var BA = this.p[B] + Z;
        var BB = this.p[B + 1] + Z;
        
        var value = this.Lerp(w, this.Lerp(v, this.Lerp(u, this.Grad(this.p[AA],     x,   y,   z),
                                                           this.Grad(this.p[BA],     x-1, y,   z)),
                                              this.Lerp(u, this.Grad(this.p[AB],     x,   y-1, z),
                                                           this.Grad(this.p[BB],     x-1, y-1, z))),
                                 this.Lerp(v, this.Lerp(u, this.Grad(this.p[AA + 1], x,   y,   z-1),
                                                           this.Grad(this.p[BA + 1], x-1, y,   z-1)),
                                              this.Lerp(u, this.Grad(this.p[AB + 1], x,   y-1, z-1),
                                                           this.Grad(this.p[BB + 1], x-1, y-1, z-1))));
        
        return value;
    };
    
    this.OctaveNoise = function(_x, _y, _z, octaves){
        var value = 0;
        
        for(var i = 0; i < octaves.length; i++){
            var x, y, z;
            x = octaves[i].xFreq * _x;
            y = octaves[i].yFreq * _y;
            z = octaves[i].zFreq * _z;
            
            var xF = Math.floor(x);
            var yF = Math.floor(y);
            var zF = Math.floor(z);
            
            var X = xF & 255;
            var Y = yF & 255;
            var Z = zF & 255;
        
            x = x - xF;
            y = y - yF;
            z = z - zF;
            
            var u = this.Fade(x);
            var v = this.Fade(y);
            var w = this.Fade(z);
            
            var A = this.p[X] + Y;
            var AA = this.p[A] + Z;
            var AB = this.p[A + 1] + Z;
            var B = this.p[X + 1] + Y;
            var BA = this.p[B] + Z;
            var BB = this.p[B + 1] + Z;
            
            var v = this.Lerp(w, this.Lerp(v, this.Lerp(u, this.Grad(this.p[AA],     x,   y,   z),
                                                           this.Grad(this.p[BA],     x-1, y,   z)),
                                              this.Lerp(u, this.Grad(this.p[AB],     x,   y-1, z),
                                                           this.Grad(this.p[BB],     x-1, y-1, z))),
                                 this.Lerp(v, this.Lerp(u, this.Grad(this.p[AA + 1], x,   y,   z-1),
                                                           this.Grad(this.p[BA + 1], x-1, y,   z-1)),
                                              this.Lerp(u, this.Grad(this.p[AB + 1], x,   y-1, z-1),
                                                           this.Grad(this.p[BB + 1], x-1, y-1, z-1))));
            value += v * octaves[i].amplitude;
        }
    
        return value;
    };
    
    this.WarpPoint = function(_x, _y, _z, wDiv, hDiv, dDiv, times, amplitude, frequency){
        var x, y, z, u, v, w;
        var xF, yF, zF, X, Y, Z, A, AA, AB, B, BA, BB;
        var hash;
        var hu, hv;
        var value;
        var g000, g001, g010, g011, g100, g101, g110, g111;
        var l000, l001, l010, l011, l100, l101, l110;
        var value;
        var i;
        
        var point = []; point[0] = _x; point[1] = _y; point[2] = _z;
        
        for(i = 0; i < 3 && i < times; i++){
            x = point[0] * wDiv * frequency;
            y = point[1] * hDiv * frequency;
            z = point[2] * dDiv * frequency;
            
            xF = Math.floor(x);
            yF = Math.floor(y);
            zF = Math.floor(z);

            // Find Unit Cube that Contains Point
            X = xF & 255;
            Y = yF & 255;
            Z = zF & 255;

            // Find Relative (X,Y,Z) of point in Cube
            x -= xF;
            y -= yF;
            z -= zF;

            // Compute fade curves for (x,y,z)
            u = x * x * x * (x * (x * 6 - 15) + 10);
            v = y * y * y * (y * (y * 6 - 15) + 10);
            w = z * z * z * (z * (z * 6 - 15) + 10);

            // Hash coordinates of the 8 cube corners
            A = this.p[X] + Y;
            AA = this.p[A] + Z;
            AB = this.p[A + 1] + Z;
            B = this.p[X + 1] + Y;
            BA = this.p[B] + Z;
            BB = this.p[B + 1] + Z;

            // Add blended results from 8 corners of cube

            // GRADIENTS
            // ================

            hash = this.p[BB + 1] & 15;
            hu = hash < 8 ? x - 1 : y - 1;
            hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x - 1 : z - 1;
            g000 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[AB + 1] & 15;
            hu = hash < 8 ? x : y - 1;
            hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x : z - 1;
            g001 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[BA + 1] & 15;
            hu = hash < 8 ? x - 1 : y;
            hv = hash < 4 ? y : hash == 12 || hash == 14 ? x - 1 : z - 1;
            g010 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[AA + 1] & 15;
            hu = hash < 8 ? x : y;
            hv = hash < 4 ? y : hash == 12 || hash == 14 ? x : z - 1;
            g011 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[BB] & 15;
            hu = hash < 8 ? x - 1 : y - 1;
            hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x - 1 : z;
            g100 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[AB] & 15;
            hu = hash < 8 ? x : y - 1;
            hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x : z;
            g101 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[BA] & 15;
            hu = hash < 8 ? x - 1 : y;
            hv = hash < 4 ? y : hash == 12 || hash == 14 ? x - 1 : z;
            g110 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[AA] & 15;
            hu = hash < 8 ? x : y;
            hv = hash < 4 ? y : hash == 12 || hash == 14 ? x : z;
            g111 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            // ===================

            // Final LERP
            // ============

            l000 = g001 + u * (g000 - g001);
            l001 = g011 + u * (g010 - g011);
            l010 = g101 + u * (g100 - g101);
            l011 = g111 + u * (g110 - g111);

            l100 = l001 + v * (l000 - l001);
            l101 = l011 + v * (l010 - l011);

            l110 = l101 + w * (l100 - l101);

            // ==============
            
            value = l110 * amplitude;
            point[i] = value + point[i];
        };
        
        for(var j = i; j < 3; j++){
            point[j] = point[j] + value;
        }
        
        return point;
    };
    
    this.NoiseOptimized = function(x, y, z){
        var u, v, w;
        var xF, yF, zF, X, Y, Z, A, AA, AB, B, BA, BB;
        var hash;
        var hu, hv;
        var g000, g001, g010, g011, g100, g101, g110, g111;
        var l000, l001, l010, l011, l100, l101, l110;
        
        xF = Math.floor(x);
        yF = Math.floor(y);
        zF = Math.floor(z);

        // Find Unit Cube that Contains Point
        X = xF & 255;
        Y = yF & 255;
        Z = zF & 255;

        // Find Relative (X,Y,Z) of point in Cube
        x -= xF;
        y -= yF;
        z -= zF;

        // Compute fade curves for (x,y,z)
        u = x * x * x * (x * (x * 6 - 15) + 10);
        v = y * y * y * (y * (y * 6 - 15) + 10);
        w = z * z * z * (z * (z * 6 - 15) + 10);

        // Hash coordinates of the 8 cube corners
        A = this.p[X] + Y;
        AA = this.p[A] + Z;
        AB = this.p[A + 1] + Z;
        B = this.p[X + 1] + Y;
        BA = this.p[B] + Z;
        BB = this.p[B + 1] + Z;

        // Add blended results from 8 corners of cube

        // GRADIENTS
        // ================

        hash = this.p[BB + 1] & 15;
        hu = hash < 8 ? x - 1 : y - 1;
        hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x - 1 : z - 1;
        g000 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
        
        hash = this.p[AB + 1] & 15;
        hu = hash < 8 ? x : y - 1;
        hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x : z - 1;
        g001 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
        
        hash = this.p[BA + 1] & 15;
        hu = hash < 8 ? x - 1 : y;
        hv = hash < 4 ? y : hash == 12 || hash == 14 ? x - 1 : z - 1;
        g010 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
        
        hash = this.p[AA + 1] & 15;
        hu = hash < 8 ? x : y;
        hv = hash < 4 ? y : hash == 12 || hash == 14 ? x : z - 1;
        g011 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
        
        hash = this.p[BB] & 15;
        hu = hash < 8 ? x - 1 : y - 1;
        hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x - 1 : z;
        g100 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
        
        hash = this.p[AB] & 15;
        hu = hash < 8 ? x : y - 1;
        hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x : z;
        g101 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
        
        hash = this.p[BA] & 15;
        hu = hash < 8 ? x - 1 : y;
        hv = hash < 4 ? y : hash == 12 || hash == 14 ? x - 1 : z;
        g110 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
        
        hash = this.p[AA] & 15;
        hu = hash < 8 ? x : y;
        hv = hash < 4 ? y : hash == 12 || hash == 14 ? x : z;
        g111 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
        
        // ===================

        // Final LERP
        // ============

        l000 = g001 + u * (g000 - g001);
        l001 = g011 + u * (g010 - g011);
        l010 = g101 + u * (g100 - g101);
        l011 = g111 + u * (g110 - g111);

        l100 = l001 + v * (l000 - l001);
        l101 = l011 + v * (l010 - l011);

        l110 = l101 + w * (l100 - l101);

        // ==============

        return l110;
    };
    
    this.OctaveNoiseOptimized = function(_x, _y, _z, octaves){
        var value = 0;
        var x, y, z, u, v, w;
        var xF, yF, zF, X, Y, Z, A, AA, AB, B, BA, BB;
        var hash;
        var hu, hv;
        var g000, g001, g010, g011, g100, g101, g110, g111;
        var l000, l001, l010, l011, l100, l101, l110;
        
        for(var i = 0; i < octaves.length; i++){
            x, y, z;
            x = octaves[i].xFreq * _x;
            y = octaves[i].yFreq * _y;
            z = octaves[i].zFreq * _z;
            
            xF = Math.floor(x);
            yF = Math.floor(y);
            zF = Math.floor(z);

            // Find Unit Cube that Contains Point
            X = xF & 255;
            Y = yF & 255;
            Z = zF & 255;

            // Find Relative (X,Y,Z) of point in Cube
            x -= xF;
            y -= yF;
            z -= zF;

            // Compute fade curves for (x,y,z)
            u = x * x * x * (x * (x * 6 - 15) + 10);
            v = y * y * y * (y * (y * 6 - 15) + 10);
            w = z * z * z * (z * (z * 6 - 15) + 10);

            // Hash coordinates of the 8 cube corners
            A = this.p[X] + Y;
            AA = this.p[A] + Z;
            AB = this.p[A + 1] + Z;
            B = this.p[X + 1] + Y;
            BA = this.p[B] + Z;
            BB = this.p[B + 1] + Z;

            // Add blended results from 8 corners of cube

            // GRADIENTS
            // ================

            hash = this.p[BB + 1] & 15;
            hu = hash < 8 ? x - 1 : y - 1;
            hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x - 1 : z - 1;
            g000 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[AB + 1] & 15;
            hu = hash < 8 ? x : y - 1;
            hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x : z - 1;
            g001 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[BA + 1] & 15;
            hu = hash < 8 ? x - 1 : y;
            hv = hash < 4 ? y : hash == 12 || hash == 14 ? x - 1 : z - 1;
            g010 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[AA + 1] & 15;
            hu = hash < 8 ? x : y;
            hv = hash < 4 ? y : hash == 12 || hash == 14 ? x : z - 1;
            g011 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[BB] & 15;
            hu = hash < 8 ? x - 1 : y - 1;
            hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x - 1 : z;
            g100 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[AB] & 15;
            hu = hash < 8 ? x : y - 1;
            hv = hash < 4 ? y - 1 : hash == 12 || hash == 14 ? x : z;
            g101 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[BA] & 15;
            hu = hash < 8 ? x - 1 : y;
            hv = hash < 4 ? y : hash == 12 || hash == 14 ? x - 1 : z;
            g110 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            hash = this.p[AA] & 15;
            hu = hash < 8 ? x : y;
            hv = hash < 4 ? y : hash == 12 || hash == 14 ? x : z;
            g111 = ((hash & 1) == 0 ? hu : -hu) + ((hash & 2) == 0 ? hv : -hv);
            
            // ===================

            // Final LERP
            // ============

            l000 = g001 + u * (g000 - g001);
            l001 = g011 + u * (g010 - g011);
            l010 = g101 + u * (g100 - g101);
            l011 = g111 + u * (g110 - g111);

            l100 = l001 + v * (l000 - l001);
            l101 = l011 + v * (l010 - l011);

            l110 = l101 + w * (l100 - l101);

            // ==============

            value += l110 * octaves[i].amplitude;
        }

        return value;
    };
}
  
function VoxelChunk(noise, x, y, z, width, height, depth){
    this.noise = noise;
    
    if(width % 32 != 0)
        width = (Math.floor(width / 32) + 1) * 32;
    if(height % 32 != 0)
        height = (Math.floor(height / 32) + 1) * 32;
    if(depth % 32 != 0)
        depth = (Math.floor(depth / 32) + 1) * 32;
        
    this.xBlocks = width / 32;
    this.zBlocks = depth / 32;
    this.yBlocks = height / 32;
    
    this.xOffset = x;
    this.yOffset = y;
    this.zOffset = z;
    
    this.width = width + 2;
    this.height = height + 2;
    this.depth = depth + 2;
    
    this.lightRadius = 16;
    
    this.voxels = new Int8Array(this.width * this.height * this.depth);
    this.lightVoxels = new Int8Array((this.width + (this.lightRadius * 2)) * (this.height) * (this.depth + (this.lightRadius * 2)));
}

VoxelChunk.prototype.GetLightValue = function(x, y, z){
    var _x = x + this.lightRadius - 1;
    var _y = y;
    var _z = z + this.lightRadius - 1;
    
    return this.lightVoxels[_x + (_y * (this.width + (this.lightRadius * 2) - 2)) + (_z * (this.width + (this.lightRadius * 2) - 2) * (this.height))];
};

VoxelChunk.prototype.Octaves = [
    { amplitude : 32, xFreq : 2, yFreq : 2, zFreq : 1 },
    { amplitude : 64, xFreq : 4, yFreq : 4, zFreq : 1 },
    { amplitude : 8, xFreq : 8, yFreq : 8, zFreq : 1 },
    { amplitude : 4, xFreq : 16, yFreq : 16, zFreq : 1 },
    { amplitude : 2, xFreq : 32, yFreq : 32, zFreq : 1 },
    { amplitude : 1, xFreq : 64, yFreq : 64, zFreq : 1 }
];

VoxelChunk.prototype.CreateChunk = function(){
    var wDiv = 1 / 256;
    var hDiv = 1 / 32;
    var dDiv = 1 / 128;
    var start = new Date();
    // Use the offsets to generate the correct terrain for the chunk
    for(var z = this.zOffset - this.lightRadius; z < (this.depth + (this.lightRadius * 2) - 2) + this.zOffset - this.lightRadius; z++){
        for(var y = this.yOffset - 1; y < this.height + this.yOffset - 1; y++){
            for(var x = this.xOffset - this.lightRadius; x < (this.width + (this.lightRadius * 2) - 2) + this.xOffset - this.lightRadius; x++){
                /*var warp = 8 * this.noise.NoiseOptimized(2 * x * wDiv, 2 * z * dDiv, 2 * y * hDiv);
                var newX = x + warp;
                warp = 8 * this.noise.NoiseOptimized(2 * newX * wDiv, 2 * z * dDiv, 2 * y * hDiv); //this.noise.Noise(2 * newX * wDiv, 2 * z * dDiv, 2 * y * hDiv);
                var newY = y + warp;
                var newZ = z + warp;*/
                var wPoint = this.noise.WarpPoint(x, z, y, wDiv, dDiv, hDiv, 2, 8, 2);
                var newX = wPoint[0];
                var newY = wPoint[2];
                var newZ = wPoint[1];
                
                var density = this.noise.OctaveNoiseOptimized(newX * wDiv, newZ * dDiv, newY * hDiv, this.Octaves);
                
                //density += Math.abs(Math.cos(2 * y * hDiv * Math.PI)) * 12;
                density += -0.75 * Math.max((newY - 40), 0);
                //density += Math.min(Math.max((newY - 96), 0), 1) * (newY-40) * (0.5 * (newY - 96) * (1/32));
                density += newY * hDiv * 8;
                density += Math.min(Math.max((40-y), 0), 1) * 20;
                //var sin = Math.sin(wDiv * x + (1/32) * density);
                //density += sin * 32;
                //density += -0.75 * (y - 48);
                
                if((x >= this.xOffset - 1 && z >= this.zOffset - 1) && (x < this.width + this.xOffset - 1 && z < this.depth + this.zOffset - 1)){
                    if(density >= 0)
                        this.voxels[(x - this.xOffset + 1) +
                                    ((y - this.yOffset + 1) * this.width) +
                                    ((z - this.zOffset + 1) * this.width * this.height)] = 0x01;
                    else
                        this.voxels[(x - this.xOffset + 1) +
                                    ((y - this.yOffset + 1) * this.width) +
                                    ((z - this.zOffset + 1) * this.width * this.height)] = 0x00;
                }
                
                if(density >= 0)
                    this.lightVoxels[(x - this.xOffset + this.lightRadius) +
                                    ((y - this.yOffset + 1) * (this.width  + (this.lightRadius * 2) - 2)) +
                                    ((z - this.zOffset + this.lightRadius) * (this.width + (this.lightRadius * 2) - 2) * (this.height))] = 100;
                else
                    this.lightVoxels[(x - this.xOffset + this.lightRadius) +
                                    ((y - this.yOffset + 1) * (this.width  + (this.lightRadius * 2) - 2)) +
                                    ((z - this.zOffset + this.lightRadius) * (this.width + (this.lightRadius * 2) - 2) * (this.height))] = 0;
                
                if(y == 128)
                    this.lightVoxels[(x - this.xOffset + this.lightRadius) +
                                    ((y - this.yOffset + 1) * (this.width  + (this.lightRadius * 2) - 2)) +
                                    ((z - this.zOffset + this.lightRadius) * (this.width + (this.lightRadius * 2) - 2) * (this.height))] = this.lightRadius;
            }
        }
    }
    var fin = new Date();
    //console.log('Vox Gen:' + (fin - start));
    self.postMessage({cmd:'stat', label:'Vox Gen:', value:(fin-start)+'ms'});
};

VoxelChunk.prototype.CalculateLighting = function(){
    var lightMask = [];
    var lWidth, lHeight, lDepth;
    var pass = [];
    var start = new Date();
    
    lWidth = this.width + (this.lightRadius * 2) - 2;
    lHeight = this.height;
    lDepth = this.depth + (this.lightRadius * 2) - 2;
    
    for(var i = 0; i < lWidth * lDepth; i++)
        lightMask.push(this.lightRadius);
        
    for(var y = lHeight - 2; y >= 0; y--){
        for(var z = 0; z < lDepth; z++){
            for(var x = 0; x < lWidth; x++){
                var index = x + (z * lWidth);
            
                if(this.lightVoxels[x + (y * lWidth) + (z * lWidth * lHeight)] != 100){
                    this.lightVoxels[x + (y * lWidth) + (z * lWidth * lHeight)] = lightMask[index];
                    
                    if(lightMask[index] == 0){
                        if((x > 0 && lightMask[(x - 1) + (z * lWidth)] == this.lightRadius) ||
                           (x < lWidth - 1 && lightMask[(x + 1) + (z * lWidth)] == this.lightRadius) ||
                           (z > 0 && lightMask[x + ((z - 1) * lWidth)] == this.lightRadius) ||
                           (z < lDepth - 1 && lightMask[x + ((z + 1) * lWidth)] == this.lightRadius)){
                            this.lightVoxels[x + (y * lWidth) + (z * lWidth * lHeight)] = this.lightRadius - 1;
                            pass.push(new Vector3(x, y, z));
                        }
                    }
                }
                else{
                    lightMask[index] = 0;
                }
            }
        }
    }
                                      
    while(pass.length > 0){
        var point = pass.pop();
        var value = this.lightVoxels[point.x + (point.y * lWidth) + (point.z * lWidth * lHeight)];
        
        if(value > 0 && value < 100){
            var _x, _y, _z;
            _x = point.x;
            _y = point.y;
            _z = point.z;
            
            // Back
            var tmpIndex = _x + (_y * lWidth) + ((_z - 1) * lWidth * lHeight);
            if(_z > 0 && this.lightVoxels[tmpIndex] < value - 1){
                this.lightVoxels[tmpIndex] = value - 1;
                pass.push(new Vector3(_x, _y, _z - 1));
            }
            
            // Front
            tmpIndex = _x + (_y * lWidth) + ((_z + 1) * lWidth * lHeight);
            if(_z < lDepth - 1 && this.lightVoxels[tmpIndex] < value - 1){
                this.lightVoxels[tmpIndex] = value - 1;
                pass.push(new Vector3(_x, _y, _z + 1));
            }
            
            // Bottom
            tmpIndex = _x + ((_y - 1) * lWidth) + (_z * lWidth * lHeight);
            if(_y > 0 && this.lightVoxels[tmpIndex] < value - 1){
                this.lightVoxels[tmpIndex] = value - 1;
                pass.push(new Vector3(_x, _y - 1, _z));
            }
            
            // Top
            tmpIndex = _x + ((_y + 1) * lWidth) + (_z * lWidth * lHeight);
            if(_y < lHeight - 1 && this.lightVoxels[tmpIndex] < value - 1){
                this.lightVoxels[tmpIndex] = value - 1;
                pass.push(new Vector3(_x, _y + 1, _z));
            }
            
            // Left
            tmpIndex = (_x - 1) + (_y * lWidth) + (_z * lWidth * lHeight);
            if(_x > 0 && this.lightVoxels[tmpIndex] < value - 1){
                this.lightVoxels[tmpIndex] = value - 1;
                pass.push(new Vector3(_x - 1, _y, _z));
            }
            
            // Right
            tmpIndex = (_x + 1) + (_y * lWidth) + (_z * lWidth * lHeight);
            if(_x < lWidth - 1 && this.lightVoxels[tmpIndex] < value - 1){
                this.lightVoxels[tmpIndex] = value - 1;
                pass.push(new Vector3(_x + 1, _y, _z));
            }
        }
    }
    
    var fin = new Date();
    //console.log('Light Calc:' + (fin - start));
    self.postMessage({cmd:'stat',label:'Light Calc:', value:(fin-start)+'ms'});
};

VoxelChunk.prototype.CreateGeometry = function(callBack){
    var start = new Date();
    for(var i = 0; i < this.yBlocks; i++){
        for(var j = 0; j < this.zBlocks; j++){
            for(var k = 0; k < this.xBlocks; k++){
                var geometry = new Geometry();
                
                // Don't use offsets, we can use the offets to position the mesh later.
                //  Potentially if we want to keep the player at (0,0) and move the world
                //  around them.
                for(var y = 0; y < 32; y++){
                    for(var z = 0; z < 32; z++){
                        for(var x = 0; x < 32; x++){
                            var _y = y + (1 + (i * 32));
                            var _x = x + (1 + (k * 32));
                            var _z = z + (1 + (j * 32));
                            
                            if(this.voxels[_x + (_y * this.width) + (_z * this.width * this.height)] != 0x00){                    
                                // BACK FACES
                                var tmpValues = this.GetSurroundingBlock(_x, _y, _z);
                                
                                if(this.voxels[_x + (_y * this.width) + ((_z - 1) * this.width * this.height)] == 0x00){
                                    var aoValues = this.GetAOValues(_x, _y, _z, 'BACK', tmpValues);
                                    
                                    geometry.faceColors.push(this.GetLightValue(_x, _y, _z - 1));
                                    
                                    var index = geometry.vertices.length - 1;
                                    geometry.vertices.push(new Vector3(x, y + 1, z));
                                    geometry.vertices.push(new Vector3(x + 1, y + 1, z));
                                    geometry.vertices.push(new Vector3(x + 1, y, z));
                                    geometry.vertices.push(new Vector3(x, y, z));
                                    
                                    if(this.FlipQuads(aoValues)){
                                        geometry.faces.push(new Face3(index + 4, index + 1, index + 2));
                                        geometry.faces.push(new Face3(index + 2, index + 3, index + 4));
                                        geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]);
                                        geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]);
                                    }
                                    else{
                                        geometry.faces.push(new Face3(index + 1, index + 2, index + 3));
                                        geometry.faces.push(new Face3(index + 3, index + 4, index + 1));
                                        geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]);
                                        geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]);
                                    }
                                }
                                // FRONT FACES
                                if(this.voxels[_x + (_y * this.width) + ((_z + 1) * this.width * this.height)] == 0x00){
                                    var aoValues = this.GetAOValues(_x, _y, _z, 'FRONT', tmpValues);
                                    
                                    geometry.faceColors.push(this.GetLightValue(_x, _y, _z + 1));
                                    
                                    var index = geometry.vertices.length - 1;
                                    geometry.vertices.push(new Vector3(x + 1, y + 1, z + 1));
                                    geometry.vertices.push(new Vector3(x, y + 1, z + 1));
                                    geometry.vertices.push(new Vector3(x, y, z + 1));
                                    geometry.vertices.push(new Vector3(x + 1, y, z + 1));
                                    
                                    if(this.FlipQuads(aoValues)){
                                        geometry.faces.push(new Face3(index + 4, index + 1, index + 2));
                                        geometry.faces.push(new Face3(index + 2, index + 3, index + 4));
                                        geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]);
                                        geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]);
                                    }
                                    else{
                                        geometry.faces.push(new Face3(index + 1, index + 2, index + 3));
                                        geometry.faces.push(new Face3(index + 3, index + 4, index + 1));
                                        geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]);
                                        geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]);
                                    }
                                }
                                // BOTTOM FACES
                                if(this.voxels[_x + ((_y - 1) * this.width) + (_z * this.width * this.height)] == 0x00){
                                    var aoValues = this.GetAOValues(_x, _y, _z, 'BOTTOM', tmpValues);
                                    
                                    geometry.faceColors.push(this.GetLightValue(_x, _y - 1, _z));
                                    
                                    var index = geometry.vertices.length - 1;
                                    geometry.vertices.push(new Vector3(x + 1, y, z + 1));
                                    geometry.vertices.push(new Vector3(x, y, z + 1));
                                    geometry.vertices.push(new Vector3(x, y, z))
                                    geometry.vertices.push(new Vector3(x + 1, y, z));
                                    
                                    if(this.FlipQuads(aoValues)){
                                        geometry.faces.push(new Face3(index + 4, index + 1, index + 2));
                                        geometry.faces.push(new Face3(index + 2, index + 3, index + 4));
                                        geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]);
                                        geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]);
                                    }
                                    else{
                                        geometry.faces.push(new Face3(index + 1, index + 2, index + 3));
                                        geometry.faces.push(new Face3(index + 3, index + 4, index + 1));
                                        geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]);
                                        geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]);
                                    }
                                }
                                // TOP FACES
                                if(_y + this.yOffset == 128 ||
                                   this.voxels[_x + ((_y + 1) * this.width) + (_z * this.width * this.height)] == 0x00){
                                    var aoValues = this.GetAOValues(_x, _y, _z, 'TOP', tmpValues);
                                    
                                    geometry.faceColors.push(this.GetLightValue(_x, _y + 1, _z));
                                    
                                    var index = geometry.vertices.length - 1;
                                    geometry.vertices.push(new Vector3(x + 1, y + 1, z));
                                    geometry.vertices.push(new Vector3(x, y + 1, z))
                                    geometry.vertices.push(new Vector3(x, y + 1, z + 1));
                                    geometry.vertices.push(new Vector3(x + 1, y + 1, z + 1));
                                    
                                    if(this.FlipQuads(aoValues)){
                                        geometry.faces.push(new Face3(index + 4, index + 1, index + 2));
                                        geometry.faces.push(new Face3(index + 2, index + 3, index + 4));
                                        geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]);
                                        geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]);
                                    }
                                    else{
                                        geometry.faces.push(new Face3(index + 1, index + 2, index + 3));
                                        geometry.faces.push(new Face3(index + 3, index + 4, index + 1));
                                        geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]);
                                        geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]);
                                    }
                                }
                                // LEFT FACES
                                if(this.voxels[(_x - 1) + (_y * this.width) + (_z * this.width * this.height)] == 0x00){
                                    var aoValues = this.GetAOValues(_x, _y, _z, 'LEFT', tmpValues);
                                    
                                    geometry.faceColors.push(this.GetLightValue(_x - 1, _y, _z));
                                    
                                    var index = geometry.vertices.length - 1;
                                    geometry.vertices.push(new Vector3(x, y + 1, z + 1));
                                    geometry.vertices.push(new Vector3(x, y + 1, z));
                                    geometry.vertices.push(new Vector3(x, y, z));
                                    geometry.vertices.push(new Vector3(x, y, z + 1));
                                    
                                    if(this.FlipQuads(aoValues)){
                                        geometry.faces.push(new Face3(index + 4, index + 1, index + 2));
                                        geometry.faces.push(new Face3(index + 2, index + 3, index + 4));
                                        geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]);
                                        geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]);
                                    }
                                    else{
                                        geometry.faces.push(new Face3(index + 1, index + 2, index + 3));
                                        geometry.faces.push(new Face3(index + 3, index + 4, index + 1));
                                        geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]);
                                        geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]);
                                    }
                                }
                                // RIGHT FACES
                                if(this.voxels[(_x + 1) + (_y * this.width) + (_z * this.width * this.height)] == 0x00){
                                    var aoValues = this.GetAOValues(x, _y, z, 'RIGHT', tmpValues);
                                    
                                    geometry.faceColors.push(this.GetLightValue(_x + 1, _y, _z));
                                    
                                    var index = geometry.vertices.length - 1;
                                    geometry.vertices.push(new Vector3(x + 1, y + 1, z));
                                    geometry.vertices.push(new Vector3(x + 1, y + 1, z + 1));
                                    geometry.vertices.push(new Vector3(x + 1, y, z + 1));
                                    geometry.vertices.push(new Vector3(x + 1, y, z));
                                    
                                    if(this.FlipQuads(aoValues)){
                                        geometry.faces.push(new Face3(index + 4, index + 1, index + 2));
                                        geometry.faces.push(new Face3(index + 2, index + 3, index + 4));
                                        geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]);
                                        geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]);
                                    }
                                    else{
                                        geometry.faces.push(new Face3(index + 1, index + 2, index + 3));
                                        geometry.faces.push(new Face3(index + 3, index + 4, index + 1));
                                        geometry.colors.push(aoValues[1]); geometry.colors.push(aoValues[0]); geometry.colors.push(aoValues[2]);
                                        geometry.colors.push(aoValues[2]); geometry.colors.push(aoValues[3]); geometry.colors.push(aoValues[1]);
                                    }
                                }
                            }
                        }
                    }
                }
                
                geometry.x = (k * 32) + this.xOffset;
                geometry.z = (j * 32) + this.zOffset;
                geometry.y = (i * 32) + this.yOffset;
                
                callBack(geometry);
            }
        }
    }
    var fin = new Date();
    //console.log('Geometry:' + (fin - start));
    self.postMessage({cmd:'stat',label:'Geometry:',value:(fin-start)+'ms'});
};

VoxelChunk.prototype.FlipQuads = function(aoValues){
    if(aoValues[1] + aoValues[2] == 3 && aoValues[3] + aoValues[0] == 4){
        return true;
    }
    else if(aoValues[1] + aoValues[2] == 4 && aoValues[3] + aoValues[0] == 3){
        return false;
    }

    if(aoValues[1] + aoValues[2] > aoValues[0] + aoValues[3]){
        return true;
    }
    else if(aoValues[1] + aoValues[2] == aoValues[0] + aoValues[3]){
        var val = aoValues[1] + aoValues[2] + aoValues[3];
        if(val % 3 != 0){
            return true;
        }
    }
    
    return false;
};

VoxelChunk.prototype.GetSurroundingBlock = function(x, y, z){
    var tmpValues = [];
    
    for(_y = y - 1; _y <= y + 1; _y++){
        for(_z = z - 1; _z <= z + 1; _z++){
            for(_x = x - 1; _x <= x + 1; _x++){
                if(this.voxels[_x + (_y * this.width) + (_z * this.width * this.height)] > 0)
                    tmpValues.push(1);
                else
                    tmpValues.push(0);
            }
        }
    }
    
    return tmpValues;
}

VoxelChunk.prototype.GetSurroundingLight = function(_x, _y, _z){
    var tmpValues = [];
    
    for(y = _y - 1; y <= _y + 1; y++){
        for(z = _z - 1; z <= _z + 1; z++){
            for(x = _x - 1; x <= _x + 1; x++){
                var val = this.lightVoxels[(x + this.lightRadius) + (y + ((z + this.lightRadius) * this.height)) * this.width];
                tmpValues.push(val == 100 ? 0 : val);
            }
        }
    }
    
    return tmpValues;
};

/*VoxelChunk.prototype.GetAOValues = function(dir, light){
    var aoValues = new Int8Array(4);
    
    switch(dir){
        case 'TOP':
            aoValues[0] = (light[18] + light[19] + light[21] + light[22]) * 0.25;
            aoValues[1] = (light[19] + light[20] + light[22] + light[23]) * 0.25;
            aoValues[2] = (light[21] + light[22] + light[24] + light[25]) * 0.25;
            aoValues[3] = (light[22] + light[23] + light[25] + light[26]) * 0.25;
            break;
        case 'BOTTOM':
            aoValues[0] = (light[3] + light[4] + light[6] + light[7]) * 0.25;
            aoValues[1] = (light[4] + light[5] + light[7] + light[8]) * 0.25;
            aoValues[2] = (light[3] + light[4] + light[0] + light[1]) * 0.25;
            aoValues[3] = (light[1] + light[2] + light[4] + light[5]) * 0.25;
            break;
    }
};

VoxelChunk.prototype.VoxToLightIndex = function(x, y, z){
    var lightWidth = this.width + (this.lightRadius * 2) - 2;
    var lightDepth = this.depth + (this.lightRadius * 2) - 2;
    
    return (x + this.lightRadius - 1) + (y  + (z + this.lightRadius - 1) * this.height) * lightWidth;
};*/

VoxelChunk.prototype.GetAOValues = function(x, y, z, dir, tmpValues){
    var i = 0;
    var valueTop = 0;
    var valueBottom = 0;
    var _x, _y, _z;
    var aoValues = new Int8Array(4);
    
    switch(dir){
        case 'TOP':
            aoValues[0] = (this.VertexAO(tmpValues[21], tmpValues[19], tmpValues[18]));
            aoValues[1] = (this.VertexAO(tmpValues[19], tmpValues[23], tmpValues[20]));
            aoValues[2] = (this.VertexAO(tmpValues[21], tmpValues[25], tmpValues[24]));
            aoValues[3] = (this.VertexAO(tmpValues[23], tmpValues[25], tmpValues[26]));
            break;
        case 'BOTTOM':
            aoValues[0] = (this.VertexAO(tmpValues[3], tmpValues[7], tmpValues[6]));
            aoValues[1] = (this.VertexAO(tmpValues[5], tmpValues[7], tmpValues[8]));
            aoValues[2] = (this.VertexAO(tmpValues[1], tmpValues[3], tmpValues[0]));
            aoValues[3] = (this.VertexAO(tmpValues[1], tmpValues[5], tmpValues[2]));
            break;
        case 'FRONT':
            aoValues[0] = (this.VertexAO(tmpValues[15], tmpValues[25], tmpValues[24]));
            aoValues[1] = (this.VertexAO(tmpValues[17], tmpValues[25], tmpValues[26]));
            aoValues[2] = (this.VertexAO(tmpValues[7], tmpValues[15], tmpValues[6]));
            aoValues[3] = (this.VertexAO(tmpValues[7], tmpValues[17], tmpValues[8]));
            break;
        case 'BACK':
            aoValues[0] = (this.VertexAO(tmpValues[11], tmpValues[19], tmpValues[20]));
            aoValues[1] = (this.VertexAO(tmpValues[9], tmpValues[19], tmpValues[18]));
            aoValues[2] = (this.VertexAO(tmpValues[1], tmpValues[11], tmpValues[2]));
            aoValues[3] = (this.VertexAO(tmpValues[1], tmpValues[9], tmpValues[0]));
            break;
        case 'LEFT':
            aoValues[0] = (this.VertexAO(tmpValues[9], tmpValues[21], tmpValues[18]));
            aoValues[1] = (this.VertexAO(tmpValues[15], tmpValues[21], tmpValues[24]));
            aoValues[2] = (this.VertexAO(tmpValues[3], tmpValues[9], tmpValues[0]));
            aoValues[3] = (this.VertexAO(tmpValues[3], tmpValues[15], tmpValues[6]));
            break;
        case 'RIGHT':
            aoValues[0] = (this.VertexAO(tmpValues[17], tmpValues[23], tmpValues[26]));
            aoValues[1] = (this.VertexAO(tmpValues[11], tmpValues[23], tmpValues[20]));
            aoValues[2] = (this.VertexAO(tmpValues[5], tmpValues[17], tmpValues[8]));
            aoValues[3] = (this.VertexAO(tmpValues[5], tmpValues[11], tmpValues[2]));
            break;
    }
    
    if(y + this.yOffset == 128 && dir != 'BOTTOM'){
        aoValues[1] = 0;
        aoValues[0] = 0;
        if(dir == 'TOP'){
            aoValues[2] = 0;
            aoValues[3] = 0;
        }
    }
    
    return aoValues;
};

VoxelChunk.prototype.VertexAO = function(side1, side2, corner){
    if(side1 && side2){
        return 3;
    }
    return side1 + side2 + corner;
};
  
var jobs = new Array();
var noise;
var isRunning = false;
var startedOn;
var date = new Date();

self.addEventListener('message', handleMessage);

function handleMessage(e){
    var data = e.data;
    switch(data.cmd){
        case 'init':
            noise = new ImprovedPerlin(data.seed * 1);
            self.postMessage({cmd: 'ready'});
            wakeUp();
            break;
        case 'gen':
            self.postMessage({cmd:'stat',label:'Gen Start:', value:'Okay'});
            jobs.push(data);
            if(!isRunning)
                wakeUp();
            break;
    }
}

function wakeUp(){
    if(!isRunning){
        startedOn = date.getTime();
        isRunning = true;
        monitorJobs();
    }
}

function monitorJobs(){
    if(jobs.length > 0){
        var job = jobs.shift();
        var chunk = new VoxelChunk(noise, job.x, job.y, job.z, job.w, job.h, job.d);
        chunk.CreateChunk();
        chunk.CalculateLighting();
        chunk.CreateGeometry(sendBlock);
    }
    else{
        if(date.getTime() - startedOn > (1000 * 60)){
            isRunning = false;
            return;
        }
    }
    setTimeout(monitorJobs, 1);
}

function sendBlock(geometry){
    if(geometry.vertices.length > 0){
        var vertexBuffer = geometry.GetVertexBuffer();
        var faceBuffer = geometry.GetFaceBuffer();
        var colorBuffer = geometry.GetColorBuffer();
        var lightBuffer = geometry.GetLightBuffer();
        
        self.postMessage({
            cmd: 'chunk',
            x: geometry.x,
            y: geometry.y,
            z: geometry.z,
            vertices: vertexBuffer,
            faces: faceBuffer,
            colors: colorBuffer,
            lights: lightBuffer
        }, [vertexBuffer, faceBuffer, colorBuffer, lightBuffer]);
    }
}
</script>
            
          
!

CSS

            
              body{
  background-color:#222222;
}
#screen{
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: 100%;
}
#scene{
  position:relative;
  background-color:#cbcbcb;
  width:100%;
  height:100%;
  border-radius:5px;
  top: 0; left: 0;
}
#start{
  background-color:#3c3c3c;
  color:#bdbdbd;
  border-radius:15px;
  height:25px;
  width:100px;
  text-align:center;
  line-height: 25px;
  z-index:100;
  top:calc(50% - 3px);
  left:calc((100% - 150px) * 0.5 - 50px);
  position:absolute;
  cursor:pointer;
}
#container{
  position:relative;
  width:calc(100% - 150px);
  height:calc(100% - 20px);
  left:10px;
  top:10px;
  background-color:#ffffff;
}
#stats{
  position:absolute;
  width:120px;
  height:calc(100% - 20px);
  right: 10px;
  top:10px;
  background-color:#3c3c3c;
  color:#bdbdbd;
  border-radius:5px;
}
.statLabel{
  font-weight:bold;
  text-align:left;
  margin-left:3px;
}
.statValue{
  text-align:right;
  margin-right:3px;
}
            
          
!

JS

            
              // The container for the whole thing
// ==================================
var view = document.getElementById('container');
var startDiv = document.getElementById('start');
var statsDiv = document.getElementById('stats');
var sceneDiv = document.getElementById('scene');

// The UI thread
// ==============
// This is where the calls to/from the generation
// thread occur.
// ------------------------------------------------
var camera, scene, renderer, controls, light, worker, clock;
var camOffset = new THREE.Vector3(2, 2, 2);
var jobs = new Array();
var lite = 0xffffff;
var dark = 0x505050;
var mid = 0xa7a7a7;

// Our render function, handles the creation of geometry
// as it is generated by our background thread.
function processJob(data){  
  var geometry = new THREE.Geometry();
  var vertexBuffer = new Float32Array(data.vertices);
  var faceBuffer = new Int32Array(data.faces);
  var colorBuffer = new Int8Array(data.colors);
  var lightBuffer = new Int8Array(data.lights);

  for (var i = 0; i < vertexBuffer.length; i += 3) {
    geometry.vertices.push(new THREE.Vector3(vertexBuffer[i], vertexBuffer[i + 1], vertexBuffer[i + 2]));
  }

  for (var j = 0; j < faceBuffer.length; j += 3) {
    geometry.faces.push(new THREE.Face3(faceBuffer[j], faceBuffer[j + 1], faceBuffer[j + 2]));
    var index = geometry.faces.length - 1;

    var l = lightBuffer[j / 3];
    var color;
    if (l > 1)
      color = 0x111111 * (l - 1);
    else if (l == 1)
      color = 0x080808;
    else
      color = 0x000000;

    var vColor = colorBuffer[j] == 0 ? lite : colorBuffer[j] == 1 ? mid : dark;
    vColor = vColor < color ? vColor : color;
    geometry.faces[index].vertexColors[0] = new THREE.Color(vColor);

    vColor = colorBuffer[j + 1] == 0 ? lite : colorBuffer[j + 1] == 1 ? mid : dark;
    vColor = vColor < color ? vColor : color;
    geometry.faces[index].vertexColors[1] = new THREE.Color(vColor);

    vColor = colorBuffer[j + 2] == 0 ? lite : colorBuffer[j + 2] == 1 ? mid : dark;
    vColor = vColor < color ? vColor : color;
    geometry.faces[index].vertexColors[2] = new THREE.Color(vColor);
  }

  geometry.computeFaceNormals(); // Pass Normals back? Would it help?
  geometry.computeBoundingBox();
  geometry.computeBoundingSphere();

  var material = new THREE.MeshBasicMaterial({
    vertexColors: THREE.VertexColors
  });

  var mesh = new THREE.Mesh(geometry, material);
  mesh.position.set(data.x, data.y, data.z);
  scene.add(mesh);
  Render();
}

var lastNow = 0;
function Animate() {
  lastNow = Date.now();
  var time = 0;
  clock.getDelta();
  while (jobs.length > 0 && (time += clock.getDelta()) < 0.016) {
    var data = jobs.shift();

    processJob(data);
  }

  requestAnimationFrame(Animate);
  controls.update();
}

function Render() {
  renderer.render(scene, camera);
}

function onWindowResize() {
  var h = window.innerHeight - 20;
  var w = window.innerWidth - 150;

  var fov = Math.atan(h / (2 * 482.84)) * 360 / Math.PI;
  camera.aspect = w / h;
  camera.fov = fov;
  camera.updateProjectionMatrix();

  renderer.setSize(w, h);
  Render();
}

function Init(height, width, depth) {
  scene = new THREE.Scene();
  clock = new THREE.Clock();

  var FOV, WIDTH, HEIGHT, ASPECT, NEAR, FAR;
  WIDTH = window.innerWidth - 150;
  HEIGHT = window.innerHeight - 20;
  FOV = Math.atan(HEIGHT / (2 * 482.84)) * 360 / Math.PI;
  ASPECT = WIDTH / HEIGHT;
  NEAR = 0.1;
  FAR = 10000;

  camera = new THREE.PerspectiveCamera(FOV, ASPECT, NEAR, FAR);
  camera.position.set(width / 2, height * 2, depth * 2);
  camera.lookAt(new THREE.Vector3(width / 2, height / 2, depth / 2));

  controls = new THREE.OrbitControls(camera);
  controls.addEventListener('change', Render);
  controls.target = new THREE.Vector3(width / 2, height / 2, depth / 2);

  renderer = new THREE.WebGLRenderer();
  renderer.setClearColor(0xededed);
  renderer.setSize(WIDTH, HEIGHT);

  document.getElementById('container').appendChild(renderer.domElement);

  renderer.render(scene, camera);

  window.addEventListener('resize', onWindowResize, false);
}

function Start(seed) {
  var blob = new Blob(Array.prototype.map.call(document.querySelectorAll("script[type=\"text\/js-worker\"]"), function(s) {
    return s.textContent;
  }), {
    type: "text/javascript"
  });

  worker = new Worker(window.URL.createObjectURL(blob));
  worker.postMessage({
    cmd: 'init',
    seed: seed
  });

  worker.addEventListener('message', function(e) {
    var data = e.data;
    switch (data.cmd) {
      case 'ready':
        worker.postMessage({
          cmd: 'gen',
          x: 0,
          y: 0,
          z: 0,
          w: 256,
          h: 128,
          d: 256
        });
        break;
      case 'chunk':
        jobs.push(data);
        break;
      case 'stat':
        var label = document.createElement('div');
        label.id = data.label;
        label.innerHTML = data.label;
        label.className += ' statLabel';
        var value = document.createElement('div');
        value.className += ' statValue';
        value.innerHTML = data.value;
        statsDiv.appendChild(label);
        statsDiv.appendChild(value);
        
        if (data.label.startsWith('Geometry') && Date.now() - lastNow > 1200){
          console.log('-.-');
          setTimeout(processPreview, 1);
        }
        break;
    }
  });
}

function processPreview(){
  if (jobs.length > 0){
    var data = jobs.shift();
    processJob(data);
    setTimeout(processPreview, 1);
  }
}

// Orbit Controls from three.js
// ==============================
// This code is here solely due to the limitations
// of a Codepen free account in linking to external
// resources. This could be gotten around via multiple
// pens, however.
/**
 * @author qiao / https://github.com/qiao
 * @author mrdoob / http://mrdoob.com
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / https://github.com/WestLangley
 * @author erich666 / http://erichaines.com
 */
THREE.OrbitControls = function(object, domElement) {

  this.object = object;
  this.domElement = (domElement !== undefined) ? domElement : document;

  // API

  // Set to false to disable this control
  this.enabled = true;

  // "target" sets the location of focus, where the control orbits around
  // and where it pans with respect to.
  this.target = new THREE.Vector3();
  // center is old, deprecated; use "target" instead
  this.center = this.target;

  // This option actually enables dollying in and out; left as "zoom" for
  // backwards compatibility
  this.noZoom = false;
  this.zoomSpeed = 1.0;
  // Limits to how far you can dolly in and out
  this.minDistance = 0;
  this.maxDistance = Infinity;

  // Set to true to disable this control
  this.noRotate = false;
  this.rotateSpeed = 1.0;

  // Set to true to disable this control
  this.noPan = false;
  this.keyPanSpeed = 7.0; // pixels moved per arrow key push

  // Set to true to automatically rotate around the target
  this.autoRotate = false;
  this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60

  // How far you can orbit vertically, upper and lower limits.
  // Range is 0 to Math.PI radians.
  this.minPolarAngle = 0; // radians
  this.maxPolarAngle = Math.PI; // radians

  // Set to true to disable use of the keys
  this.noKeys = false;
  // The four arrow keys
  this.keys = {
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    BOTTOM: 40
  };

  ////////////
  // internals

  var scope = this;

  var EPS = 0.000001;

  var rotateStart = new THREE.Vector2();
  var rotateEnd = new THREE.Vector2();
  var rotateDelta = new THREE.Vector2();

  var panStart = new THREE.Vector2();
  var panEnd = new THREE.Vector2();
  var panDelta = new THREE.Vector2();

  var dollyStart = new THREE.Vector2();
  var dollyEnd = new THREE.Vector2();
  var dollyDelta = new THREE.Vector2();

  var phiDelta = 0;
  var thetaDelta = 0;
  var scale = 1;
  var pan = new THREE.Vector3();

  var lastPosition = new THREE.Vector3();

  var STATE = {
    NONE: -1,
    ROTATE: 0,
    DOLLY: 1,
    PAN: 2,
    TOUCH_ROTATE: 3,
    TOUCH_DOLLY: 4,
    TOUCH_PAN: 5
  };
  var state = STATE.NONE;

  // events

  var changeEvent = {
    type: 'change'
  };

  this.rotateLeft = function(angle) {

    if (angle === undefined) {

      angle = getAutoRotationAngle();

    }

    thetaDelta -= angle;

  };

  this.rotateUp = function(angle) {

    if (angle === undefined) {

      angle = getAutoRotationAngle();

    }

    phiDelta -= angle;

  };

  // pass in distance in world space to move left
  this.panLeft = function(distance) {

    var panOffset = new THREE.Vector3();
    var te = this.object.matrix.elements;
    // get X column of matrix
    panOffset.set(te[0], te[1], te[2]);
    panOffset.multiplyScalar(-distance);

    pan.add(panOffset);

  };

  // pass in distance in world space to move up
  this.panUp = function(distance) {

    var panOffset = new THREE.Vector3();
    var te = this.object.matrix.elements;
    // get Y column of matrix
    panOffset.set(te[4], te[5], te[6]);
    panOffset.multiplyScalar(distance);

    pan.add(panOffset);
  };

  // main entry point; pass in Vector2 of change desired in pixel space,
  // right and down are positive
  this.pan = function(delta) {

    var cW = window.innerWidth - 150;
    var cH = window.innerHeight - 20;

    if (scope.object.fov !== undefined) {

      // perspective
      var position = scope.object.position;
      var offset = position.clone().sub(scope.target);
      var targetDistance = offset.length();

      // half of the fov is center to top of screen
      targetDistance *= Math.tan((scope.object.fov / 2) * Math.PI / 180.0);
      // we actually don't use screenWidth, since perspective camera is fixed to screen height
      scope.panLeft(2 * delta.x * targetDistance / cH);
      scope.panUp(2 * delta.y * targetDistance / cW);

    } else if (scope.object.top !== undefined) {

      // orthographic
      scope.panLeft(delta.x * (scope.object.right - scope.object.left) / cW);
      scope.panUp(delta.y * (scope.object.top - scope.object.bottom) / cH);

    } else {

      // camera neither orthographic or perspective - warn user
      console.warn('WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.');

    }

  };

  this.dollyIn = function(dollyScale) {

    if (dollyScale === undefined) {

      dollyScale = getZoomScale();

    }

    scale /= dollyScale;

  };

  this.dollyOut = function(dollyScale) {

    if (dollyScale === undefined) {

      dollyScale = getZoomScale();

    }

    scale *= dollyScale;

  };

  this.update = function() {

    var position = this.object.position;
    var offset = position.clone().sub(this.target);

    // angle from z-axis around y-axis

    var theta = Math.atan2(offset.x, offset.z);

    // angle from y-axis

    var phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.z * offset.z), offset.y);

    if (this.autoRotate) {

      this.rotateLeft(getAutoRotationAngle());

    }

    theta += thetaDelta;
    phi += phiDelta;

    // restrict phi to be between desired limits
    phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, phi));

    // restrict phi to be betwee EPS and PI-EPS
    phi = Math.max(EPS, Math.min(Math.PI - EPS, phi));

    var radius = offset.length() * scale;

    // restrict radius to be between desired limits
    radius = Math.max(this.minDistance, Math.min(this.maxDistance, radius));

    // move target to panned location
    this.target.add(pan);

    offset.x = radius * Math.sin(phi) * Math.sin(theta);
    offset.y = radius * Math.cos(phi);
    offset.z = radius * Math.sin(phi) * Math.cos(theta);

    position.copy(this.target).add(offset);

    this.object.lookAt(this.target);

    thetaDelta = 0;
    phiDelta = 0;
    scale = 1;
    pan.set(0, 0, 0);

    if (lastPosition.distanceTo(this.object.position) > 0) {

      this.dispatchEvent(changeEvent);

      lastPosition.copy(this.object.position);

    }

  };

  function getAutoRotationAngle() {

    return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;

  }

  function getZoomScale() {

    return Math.pow(0.95, scope.zoomSpeed);

  }

  function onMouseDown(event) {

    if (scope.enabled === false) {
      return;
    }
    event.preventDefault();

    if (event.button === 0) {
      if (scope.noRotate === true) {
        return;
      }

      state = STATE.ROTATE;

      rotateStart.set(event.offsetX, event.offsetY);

    } else if (event.button === 1) {
      if (scope.noZoom === true) {
        return;
      }

      state = STATE.DOLLY;

      dollyStart.set(event.clientX, event.clientY);

    } else if (event.button === 2) {
      if (scope.noPan === true) {
        return;
      }

      state = STATE.PAN;

      panStart.set(event.clientX, event.clientY);

    }

    // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
    scope.domElement.addEventListener('mousemove', onMouseMove, false);
    scope.domElement.addEventListener('mouseup', onMouseUp, false);

  }

  function onMouseMove(event) {

    if (scope.enabled === false) return;

    event.preventDefault();

    var cW = window.innerWidth - 150;
    var cH = window.innerHeight - 20;

    if (state === STATE.ROTATE) {

      if (scope.noRotate === true) return;

      rotateEnd.set(event.offsetX, event.offsetY);
      rotateDelta.subVectors(rotateEnd, rotateStart);

      // rotating across whole screen goes 360 degrees around
      scope.rotateLeft(2 * Math.PI * rotateDelta.x / cW * scope.rotateSpeed);
      // rotating up and down along whole screen attempts to go 360, but limited to 180
      scope.rotateUp(2 * Math.PI * rotateDelta.y / cH * scope.rotateSpeed);

      rotateStart.copy(rotateEnd);

    } else if (state === STATE.DOLLY) {

      if (scope.noZoom === true) return;

      dollyEnd.set(event.clientX, event.clientY);
      dollyDelta.subVectors(dollyEnd, dollyStart);

      if (dollyDelta.y > 0) {

        scope.dollyIn();

      } else {

        scope.dollyOut();

      }

      dollyStart.copy(dollyEnd);

    } else if (state === STATE.PAN) {

      if (scope.noPan === true) return;

      panEnd.set(event.clientX, event.clientY);
      panDelta.subVectors(panEnd, panStart);

      scope.pan(panDelta);

      panStart.copy(panEnd);

    }

    // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
    scope.update();

  }

  function onMouseUp( /* event */ ) {

    if (scope.enabled === false) return;

    // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
    scope.domElement.removeEventListener('mousemove', onMouseMove, false);
    scope.domElement.removeEventListener('mouseup', onMouseUp, false);

    state = STATE.NONE;

  }

  function onMouseWheel(event) {

    if (scope.enabled === false || scope.noZoom === true) return;

    var delta = 0;

    if (event.wheelDelta) { // WebKit / Opera / Explorer 9

      delta = event.wheelDelta;

    } else if (event.detail) { // Firefox

      delta = -event.detail;

    }

    if (delta > 0) {

      scope.dollyOut();

    } else {

      scope.dollyIn();

    }

  }

  function onKeyDown(event) {

    if (scope.enabled === false) {
      return;
    }
    if (scope.noKeys === true) {
      return;
    }
    if (scope.noPan === true) {
      return;
    }

    // pan a pixel - I guess for precise positioning?
    // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
    var needUpdate = false;

    switch (event.keyCode) {

      case scope.keys.UP:
        scope.pan(new THREE.Vector2(0, scope.keyPanSpeed));
        needUpdate = true;
        break;
      case scope.keys.BOTTOM:
        scope.pan(new THREE.Vector2(0, -scope.keyPanSpeed));
        needUpdate = true;
        break;
      case scope.keys.LEFT:
        scope.pan(new THREE.Vector2(scope.keyPanSpeed, 0));
        needUpdate = true;
        break;
      case scope.keys.RIGHT:
        scope.pan(new THREE.Vector2(-scope.keyPanSpeed, 0));
        needUpdate = true;
        break;
    }

    // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
    if (needUpdate) {

      scope.update();

    }

  }

  function touchstart(event) {

    if (scope.enabled === false) {
      return;
    }

    switch (event.touches.length) {

      case 1: // one-fingered touch: rotate
        if (scope.noRotate === true) {
          return;
        }

        state = STATE.TOUCH_ROTATE;

        rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
        break;

      case 2: // two-fingered touch: dolly
        if (scope.noZoom === true) {
          return;
        }

        state = STATE.TOUCH_DOLLY;

        var dx = event.touches[0].pageX - event.touches[1].pageX;
        var dy = event.touches[0].pageY - event.touches[1].pageY;
        var distance = Math.sqrt(dx * dx + dy * dy);
        dollyStart.set(0, distance);
        break;

      case 3: // three-fingered touch: pan
        if (scope.noPan === true) {
          return;
        }

        state = STATE.TOUCH_PAN;

        panStart.set(event.touches[0].pageX, event.touches[0].pageY);
        break;

      default:
        state = STATE.NONE;

    }
  }

  function touchmove(event) {

    if (scope.enabled === false) {
      return;
    }

    event.preventDefault();
    event.stopPropagation();

    var cW = window.innerWidth - 150;
    var cH = window.innerHeight - 20;

    switch (event.touches.length) {

      case 1: // one-fingered touch: rotate
        if (scope.noRotate === true) {
          return;
        }
        if (state !== STATE.TOUCH_ROTATE) {
          return;
        }

        rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
        rotateDelta.subVectors(rotateEnd, rotateStart);

        // rotating across whole screen goes 360 degrees around
        scope.rotateLeft(2 * Math.PI * rotateDelta.x / cW * scope.rotateSpeed);
        // rotating up and down along whole screen attempts to go 360, but limited to 180
        scope.rotateUp(2 * Math.PI * rotateDelta.y / cH * scope.rotateSpeed);

        rotateStart.copy(rotateEnd);
        break;

      case 2: // two-fingered touch: dolly
        if (scope.noZoom === true) {
          return;
        }
        if (state !== STATE.TOUCH_DOLLY) {
          return;
        }

        var dx = event.touches[0].pageX - event.touches[1].pageX;
        var dy = event.touches[0].pageY - event.touches[1].pageY;
        var distance = Math.sqrt(dx * dx + dy * dy);

        dollyEnd.set(0, distance);
        dollyDelta.subVectors(dollyEnd, dollyStart);

        if (dollyDelta.y > 0) {

          scope.dollyOut();

        } else {

          scope.dollyIn();

        }

        dollyStart.copy(dollyEnd);
        break;

      case 3: // three-fingered touch: pan
        if (scope.noPan === true) {
          return;
        }
        if (state !== STATE.TOUCH_PAN) {
          return;
        }

        panEnd.set(event.touches[0].pageX, event.touches[0].pageY);
        panDelta.subVectors(panEnd, panStart);

        scope.pan(panDelta);

        panStart.copy(panEnd);
        break;

      default:
        state = STATE.NONE;

    }

  }

  function touchend( /* event */ ) {

    if (scope.enabled === false) {
      return;
    }

    state = STATE.NONE;
  }

  this.domElement.addEventListener('contextmenu', function(event) {
    event.preventDefault();
  }, false);
  this.domElement.addEventListener('mousedown', onMouseDown, false);
  this.domElement.addEventListener('mousewheel', onMouseWheel, false);
  this.domElement.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox

  this.domElement.addEventListener('keydown', onKeyDown, false);

  this.domElement.addEventListener('touchstart', touchstart, false);
  this.domElement.addEventListener('touchend', touchend, false);
  this.domElement.addEventListener('touchmove', touchmove, false);

};

THREE.OrbitControls.prototype = Object.create(THREE.EventDispatcher.prototype);

// Spawn the voxel mesh
// ======================
startDiv.onclick = function() {
  sceneDiv.removeChild(startDiv);
  Init(128, 256, 256);
  lastNow = Date.now();
  Animate();
  Start(7664812);
};

startDiv.click();
            
          
!
999px

Console