Mini Shell

Direktori : /home/eymajans/public_html/deneme2.eymajans.com/js/
Upload File :
Current File : /home/eymajans/public_html/deneme2.eymajans.com/js/geometryangle.js

//============================================================
//
// Copyright below.
// 
// CoAuthor: Patrick Geyer
//
// Twitter: https://twitter.com/PatrickGeyer_
//
//============================================================

//============================================================
//
// Copyright (C) 2013 Matthew Wagerfield
//
// Twitter: https://twitter.com/mwagerfield
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
// OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
//
//============================================================

/**
 * Defines the Flat Surface Shader namespace for all the awesomeness to exist upon.
 * @author Matthew Wagerfield
 */
FSS = {
    FRONT: 0,
    BACK: 1,
    DOUBLE: 2,
    SVGNS: 'http://www.w3.org/2000/svg'
};

/**
 * @class Array
 * @author Matthew Wagerfield
 */
FSS.Array = typeof Float32Array === 'function' ? Float32Array : Array;

/**
 * @class Utils
 * @author Matthew Wagerfield
 */
FSS.Utils = {
    isNumber: function (value) {
        return !isNaN(parseFloat(value)) && isFinite(value);
    }
};

/**
 * Request Animation Frame Polyfill.
 * @author Paul Irish
 * @see https://gist.github.com/paulirish/1579671
 */
(function () {

    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];

    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
    }

    if (!window.requestAnimationFrame) {
        window.requestAnimationFrame = function (callback, element) {
            var currentTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currentTime - lastTime));
            var id = window.setTimeout(function () {
                callback(currentTime + timeToCall);
            }, timeToCall);
            lastTime = currentTime + timeToCall;
            return id;
        };
    }

    if (!window.cancelAnimationFrame) {
        window.cancelAnimationFrame = function (id) {
            clearTimeout(id);
        };
    }

}());

/**
 * @object Math Augmentation
 * @author Matthew Wagerfield
 */
Math.PIM2 = Math.PI * 2;
Math.PID2 = Math.PI / 2;
Math.randomInRange = function (min, max) {
    return min + (max - min) * Math.random();
};
Math.clamp = function (value, min, max) {
    value = Math.max(value, min);
    value = Math.min(value, max);
    return value;
};

/**
 * @object Vector3
 * @author Matthew Wagerfield
 */
FSS.Vector3 = {
    create: function (x, y, z) {
        var vector = new FSS.Array(3);
        this.set(vector, x, y, z);
        return vector;
    },
    clone: function (a) {
        var vector = this.create();
        this.copy(vector, a);
        return vector;
    },
    set: function (target, x, y, z) {
        target[0] = x || 0;
        target[1] = y || 0;
        target[2] = z || 0;
        return this;
    },
    setX: function (target, x) {
        target[0] = x || 0;
        return this;
    },
    setY: function (target, y) {
        target[1] = y || 0;
        return this;
    },
    setZ: function (target, z) {
        target[2] = z || 0;
        return this;
    },
    copy: function (target, a) {
        target[0] = a[0];
        target[1] = a[1];
        target[2] = a[2];
        return this;
    },
    add: function (target, a) {
        target[0] += a[0];
        target[1] += a[1];
        target[2] += a[2];
        return this;
    },
    addVectors: function (target, a, b) {
        target[0] = a[0] + b[0];
        target[1] = a[1] + b[1];
        target[2] = a[2] + b[2];
        return this;
    },
    addScalar: function (target, s) {
        target[0] += s;
        target[1] += s;
        target[2] += s;
        return this;
    },
    subtract: function (target, a) {
        target[0] -= a[0];
        target[1] -= a[1];
        target[2] -= a[2];
        return this;
    },
    subtractVectors: function (target, a, b) {
        target[0] = a[0] - b[0];
        target[1] = a[1] - b[1];
        target[2] = a[2] - b[2];
        return this;
    },
    subtractScalar: function (target, s) {
        target[0] -= s;
        target[1] -= s;
        target[2] -= s;
        return this;
    },
    multiply: function (target, a) {
        target[0] *= a[0];
        target[1] *= a[1];
        target[2] *= a[2];
        return this;
    },
    multiplyVectors: function (target, a, b) {
        target[0] = a[0] * b[0];
        target[1] = a[1] * b[1];
        target[2] = a[2] * b[2];
        return this;
    },
    multiplyScalar: function (target, s) {
        target[0] *= s;
        target[1] *= s;
        target[2] *= s;
        return this;
    },
    divide: function (target, a) {
        target[0] /= a[0];
        target[1] /= a[1];
        target[2] /= a[2];
        return this;
    },
    divideVectors: function (target, a, b) {
        target[0] = a[0] / b[0];
        target[1] = a[1] / b[1];
        target[2] = a[2] / b[2];
        return this;
    },
    divideScalar: function (target, s) {
        if (s !== 0) {
            target[0] /= s;
            target[1] /= s;
            target[2] /= s;
        } else {
            target[0] = 0;
            target[1] = 0;
            target[2] = 0;
        }
        return this;
    },
    cross: function (target, a) {
        var x = target[0];
        var y = target[1];
        var z = target[2];
        target[0] = y * a[2] - z * a[1];
        target[1] = z * a[0] - x * a[2];
        target[2] = x * a[1] - y * a[0];
        return this;
    },
    crossVectors: function (target, a, b) {
        target[0] = a[1] * b[2] - a[2] * b[1];
        target[1] = a[2] * b[0] - a[0] * b[2];
        target[2] = a[0] * b[1] - a[1] * b[0];
        return this;
    },
    min: function (target, value) {
        if (target[0] < value) {
            target[0] = value;
        }
        if (target[1] < value) {
            target[1] = value;
        }
        if (target[2] < value) {
            target[2] = value;
        }
        return this;
    },
    max: function (target, value) {
        if (target[0] > value) {
            target[0] = value;
        }
        if (target[1] > value) {
            target[1] = value;
        }
        if (target[2] > value) {
            target[2] = value;
        }
        return this;
    },
    clamp: function (target, min, max) {
        this.min(target, min);
        this.max(target, max);
        return this;
    },
    limit: function (target, min, max) {
        var length = this.length(target);
        if (min !== null && length < min) {
            this.setLength(target, min);
        } else if (max !== null && length > max) {
            this.setLength(target, max);
        }
        return this;
    },
    dot: function (a, b) {
        return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
    },
    normalise: function (target) {
        return this.divideScalar(target, this.length(target));
    },
    negate: function (target) {
        return this.multiplyScalar(target, -1);
    },
    distanceSquared: function (a, b) {
        var dx = a[0] - b[0];
        var dy = a[1] - b[1];
        var dz = a[2] - b[2];
        return dx * dx + dy * dy + dz * dz;
    },
    distance: function (a, b) {
        return Math.sqrt(this.distanceSquared(a, b));
    },
    lengthSquared: function (a) {
        return a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
    },
    length: function (a) {
        return Math.sqrt(this.lengthSquared(a));
    },
    setLength: function (target, l) {
        var length = this.length(target);
        if (length !== 0 && l !== length) {
            this.multiplyScalar(target, l / length);
        }
        return this;
    },
    floor: function (target) {
        target[0] = Math.floor(target[0]);
        target[1] = Math.floor(target[1]);
        target[2] = Math.floor(target[2]);
        return target;
    }
};

/**
 * @object Vector4
 * @author Matthew Wagerfield
 */
FSS.Vector4 = {
    create: function (x, y, z, w) {
        var vector = new FSS.Array(4);
        this.set(vector, x, y, z);
        return vector;
    },
    set: function (target, x, y, z, w) {
        target[0] = x || 0;
        target[1] = y || 0;
        target[2] = z || 0;
        target[3] = w || 0;
        return this;
    },
    setX: function (target, x) {
        target[0] = x || 0;
        return this;
    },
    setY: function (target, y) {
        target[1] = y || 0;
        return this;
    },
    setZ: function (target, z) {
        target[2] = z || 0;
        return this;
    },
    setW: function (target, w) {
        target[3] = w || 0;
        return this;
    },
    add: function (target, a) {
        target[0] += a[0];
        target[1] += a[1];
        target[2] += a[2];
        target[3] += a[3];
        return this;
    },
    multiplyVectors: function (target, a, b) {
        target[0] = a[0] * b[0];
        target[1] = a[1] * b[1];
        target[2] = a[2] * b[2];
        target[3] = a[3] * b[3];
        return this;
    },
    multiplyScalar: function (target, s) {
        target[0] *= s;
        target[1] *= s;
        target[2] *= s;
        target[3] *= s;
        return this;
    },
    min: function (target, value) {
        if (target[0] < value) {
            target[0] = value;
        }
        if (target[1] < value) {
            target[1] = value;
        }
        if (target[2] < value) {
            target[2] = value;
        }
        if (target[3] < value) {
            target[3] = value;
        }
        return this;
    },
    max: function (target, value) {
        if (target[0] > value) {
            target[0] = value;
        }
        if (target[1] > value) {
            target[1] = value;
        }
        if (target[2] > value) {
            target[2] = value;
        }
        if (target[3] > value) {
            target[3] = value;
        }
        return this;
    },
    clamp: function (target, min, max) {
        this.min(target, min);
        this.max(target, max);
        return this;
    }
};

/**
 * @class Color
 * @author Matthew Wagerfield
 */
FSS.Color = function (color, opacity) {
    this.rgba = [];
    this.color = color || '#000000';
    this.opacity = FSS.Utils.isNumber(opacity) ? opacity : 1;
    this.set(this.color, this.opacity);
};

FSS.Color.prototype = {
    set: function (color, opacity) {
        if (color.indexOf("#") === -1) {
            if (color.indexOf('rgb(') === 0) {
                var pars = color.indexOf(',');
                this.rgba[0] = parseInt(color.substr(4, pars));
                this.rgba[1] = parseInt(color.substr(pars + 1, color.indexOf(',', pars)));
                this.rgba[2] = parseInt(color.substr(color.indexOf(',', pars + 1) + 1, color.indexOf(')')));
                this.rgba[3] = 1;
            } else if (color.indexOf('rgba(') === 0) {

                var pars = color.indexOf(',');
                var repars = color.indexOf(',', pars + 1);
                this.rgba[0] = parseInt(color.substr(5, pars));
                this.rgba[1] = parseInt(color.substr(pars + 1, repars));
                this.rgba[2] = parseInt(color.substr(color.indexOf(',', pars + 1) + 1, color.indexOf(',', repars)));
                this.rgba[3] = parseFloat(color.substr(color.indexOf(',', repars + 1) + 1, color.indexOf(')')));
            }
        } else {
            color = color.replace('#', '');
            var size = color.length / 3;
            this.rgba[0] = parseInt(color.substring(size * 0, size * 1), 16) / 255;
            this.rgba[1] = parseInt(color.substring(size * 1, size * 2), 16) / 255;
            this.rgba[2] = parseInt(color.substring(size * 2, size * 3), 16) / 255;
            this.rgba[3] = FSS.Utils.isNumber(opacity) ? opacity : this.rgba[3];
        }

        return this;
    },
    //    hexify: function (channel) {
    //        var hex = Math.ceil(channel * 255).toString(16);
    //        if (hex.length === 1) {
    //            hex = '0' + hex;
    //        }
    //        return hex;
    //    },
    format: function () {
        return "rgba(" + this.rgba[0] + "," + this.rgba[1] + "," + this.rgba[2] + "," + this.rgba[3] + ")"; //this.hex
        //        var r = this.hexify(this.rgba[0]);
        //        var g = this.hexify(this.rgba[1]);
        //        var b = this.hexify(this.rgba[2]);
        //        this.hex = '#' + r + g + b;
        //        return this.hex;
    }
};

/**
 * @class Object
 * @author Matthew Wagerfield
 */
FSS.Object = function () {
    this.position = FSS.Vector3.create();
};

FSS.Object.prototype = {
    setPosition: function (x, y, z) {
        FSS.Vector3.set(this.position, x, y, z);
        return this;
    }
};

/**
 * @class Light
 * @author Matthew Wagerfield
 */
FSS.Light = function (ambient, diffuse) {
    FSS.Object.call(this);
    this.ambient = new FSS.Color(ambient || '#FFFFFF');
    this.diffuse = new FSS.Color(diffuse || '#FFFFFF');
    this.ray = FSS.Vector3.create();
};

FSS.Light.prototype = Object.create(FSS.Object.prototype);

/**
 * @class Vertex
 * @author Matthew Wagerfield
 */
FSS.Vertex = function (x, y, z) {
    this.position = FSS.Vector3.create(x, y, z);
};

FSS.Vertex.prototype = {
    setPosition: function (x, y, z) {
        FSS.Vector3.set(this.position, x, y, z);
        return this;
    }
};

/**
 * @class Triangle
 * @author Matthew Wagerfield
 */
FSS.Triangle = function (a, b, c) {
    this.a = a || new FSS.Vertex();
    this.b = b || new FSS.Vertex();
    this.c = c || new FSS.Vertex();
    this.vertices = [this.a, this.b, this.c];
    this.u = FSS.Vector3.create();
    this.v = FSS.Vector3.create();
    this.centroid = FSS.Vector3.create();
    this.normal = FSS.Vector3.create();
    this.color = new FSS.Color();
    this.polygon = document.createElementNS(FSS.SVGNS, 'polygon');
    this.polygon.setAttributeNS(null, 'stroke-linejoin', 'round');
    this.polygon.setAttributeNS(null, 'stroke-miterlimit', '1');
    this.polygon.setAttributeNS(null, 'stroke-width', '1');
    this.computeCentroid();
    this.computeNormal();
};

FSS.Triangle.prototype = {
    computeCentroid: function () {
        this.centroid[0] = this.a.position[0] + this.b.position[0] + this.c.position[0];
        this.centroid[1] = this.a.position[1] + this.b.position[1] + this.c.position[1];
        this.centroid[2] = this.a.position[2] + this.b.position[2] + this.c.position[2];
        FSS.Vector3.divideScalar(this.centroid, 3);
        return this;
    },
    computeNormal: function () {
        FSS.Vector3.subtractVectors(this.u, this.b.position, this.a.position);
        FSS.Vector3.subtractVectors(this.v, this.c.position, this.a.position);
        FSS.Vector3.crossVectors(this.normal, this.u, this.v);
        FSS.Vector3.normalise(this.normal);
        return this;
    }
};

/**
 * @class Geometry
 * @author Matthew Wagerfield
 */
FSS.Geometry = function () {
    this.vertices = [];
    this.triangles = [];
    this.dirty = false;
};

FSS.Geometry.prototype = {
    update: function () {
        if (this.dirty) {
            var t, triangle;
            for (t = this.triangles.length - 1; t >= 0; t--) {
                triangle = this.triangles[t];
                triangle.computeCentroid();
                triangle.computeNormal();
            }
            this.dirty = false;
        }
        return this;
    }
};

/**
 * @class Plane
 * @author Matthew Wagerfield
 */
FSS.Plane = function (width, height, segments, slices) {
    FSS.Geometry.call(this);
    this.width = width || 100;
    this.height = height || 100;
    this.segments = segments || 4;
    this.slices = slices || 4;
    this.segmentWidth = this.width / this.segments;
    this.sliceHeight = this.height / this.slices;

    // Cache Variables
    var x, y, v0, v1, v2, v3,
            vertex, triangle, vertices = [],
            offsetX = this.width * -0.5,
            offsetY = this.height * 0.5;

    // Add Vertices
    for (x = 0; x <= this.segments; x++) {
        vertices.push([]);
        for (y = 0; y <= this.slices; y++) {
            vertex = new FSS.Vertex(offsetX + x * this.segmentWidth, offsetY - y * this.sliceHeight);
            vertices[x].push(vertex);
            this.vertices.push(vertex);
        }
    }

    // Add Triangles
    for (x = 0; x < this.segments; x++) {
        for (y = 0; y < this.slices; y++) {
            v0 = vertices[x + 0][y + 0];
            v1 = vertices[x + 0][y + 1];
            v2 = vertices[x + 1][y + 0];
            v3 = vertices[x + 1][y + 1];
            t0 = new FSS.Triangle(v0, v1, v2);
            t1 = new FSS.Triangle(v2, v1, v3);
            this.triangles.push(t0, t1);
        }
    }
};

FSS.Plane.prototype = Object.create(FSS.Geometry.prototype);

/**
 * @class Material
 * @author Matthew Wagerfield
 */
FSS.Material = function (ambient, diffuse) {
    this.ambient = new FSS.Color(ambient || 'rgba(68,68,68, 1)');
    this.diffuse = new FSS.Color(diffuse || 'rgba(255,255,255, 1)');
    this.slave = new FSS.Color();
};

/**
 * @class Mesh
 * @author Matthew Wagerfield
 */
FSS.Mesh = function (geometry, material) {
    FSS.Object.call(this);
    this.geometry = geometry || new FSS.Geometry();
    this.material = material || new FSS.Material();
    this.side = FSS.FRONT;
    this.visible = true;
};

FSS.Mesh.prototype = Object.create(FSS.Object.prototype);

FSS.Mesh.prototype.update = function (lights, calculate) {
    var t, triangle, l, light, illuminance, light_count;
    light_count = lights.length;

    // Update Geometry
    this.geometry.update();

    // Calculate the triangle colors
    if (calculate) {

        // Iterate through Triangles
        for (t = this.geometry.triangles.length - 1; t >= 0; t--) {
            triangle = this.geometry.triangles[t];

            // Reset Triangle Color
            FSS.Vector4.set(triangle.color.rgba);

            // Iterate through Lights
            for (l = lights.length - 1; l >= 0; l--) {
                light = lights[l];


                // Calculate Illuminance
                FSS.Vector3.subtractVectors(light.ray, light.position, triangle.centroid);
                FSS.Vector3.normalise(light.ray);
                illuminance = FSS.Vector3.dot(triangle.normal, light.ray);
                if (this.side === FSS.FRONT) {
                    illuminance = Math.max(illuminance, 0);
                } else if (this.side === FSS.BACK) {
                    illuminance = Math.abs(Math.min(illuminance, 0));
                } else if (this.side === FSS.DOUBLE) {
                    illuminance = Math.max(Math.abs(illuminance), 0);
                }



                //               Calculate Ambient Light
                for (var i = 0; i < 3; i++) {
                    this.material.slave.rgba[i] = (((1 / light_count) * this.material.ambient.rgba[i]) * ((1 / light_count) * light.ambient.rgba[i])) / 128;
                    if (i !== 3) {
                        this.material.slave.rgba[i] = Math.round(this.material.slave.rgba[i]);
                    }
                }
                /* 				Add the resultant values to the triangle color vector. Not required to factor illuminance because it is ambient light. */
                FSS.Vector4.add(triangle.color.rgba, this.material.slave.rgba);

                // Calculate Diffuse Light
                for (var i = 0; i < 3; i++) {
                    this.material.slave.rgba[i] = ((1 / light_count) * this.material.diffuse.rgba[i] * (1 / light_count) * light.diffuse.rgba[i]) / 128;
                    if (i !== 3) {
                        this.material.slave.rgba[i] = Math.round(this.material.slave.rgba[i]);
                    }
                }

                //              FSS.Vector4.multiplyVectors(this.material.slave.rgba, this.material.diffuse.rgba, light.diffuse.rgba);
                //              FSS.Vector4.multiplyScalar(this.material.slave.rgba, illuminance);
                for (var i = 0; i < 3; i++) {
                    this.material.slave.rgba[i] = Math.round(this.material.slave.rgba[i] * illuminance);
                }
                FSS.Vector4.add(triangle.color.rgba, this.material.slave.rgba);
            }



            // Clamp & Format Color
            FSS.Vector4.clamp(triangle.color.rgba, 0, 255);
            triangle.color.rgba[3] = this.material.diffuse.rgba[3]; //Math.min(triangle.color.rgba[3], 1);
        }
    }
    return this;
};

/**
 * @class Scene
 * @author Matthew Wagerfield
 */
FSS.Scene = function () {
    this.meshes = [];
    this.lights = [];
};

FSS.Scene.prototype = {
    add: function (object) {
        if (object instanceof FSS.Mesh && !~this.meshes.indexOf(object)) {
            this.meshes.push(object);
        } else if (object instanceof FSS.Light && !~this.lights.indexOf(object)) {
            this.lights.push(object);
        }
        return this;
    },
    remove: function (object) {
        if (object instanceof FSS.Mesh && ~this.meshes.indexOf(object)) {
            this.meshes.splice(this.meshes.indexOf(object), 1);
        } else if (object instanceof FSS.Light && ~this.lights.indexOf(object)) {
            this.lights.splice(this.lights.indexOf(object), 1);
        }
        return this;
    }
};

/**
 * @class Renderer
 * @author Matthew Wagerfield
 */
FSS.Renderer = function () {
    this.width = 0;
    this.height = 0;
    this.halfWidth = 0;
    this.halfHeight = 0;
};

FSS.Renderer.prototype = {
    setSize: function (width, height) {
        if (this.width === width && this.height === height)
            return;
        this.width = width;
        this.height = height;
        this.halfWidth = this.width * 0.5;
        this.halfHeight = this.height * 0.5;
        return this;
    },
    clear: function () {
        return this;
    },
    render: function (scene) {
        return this;
    }
};

/**
 * @class Canvas Renderer
 * @author Matthew Wagerfield
 */
FSS.CanvasRenderer = function () {
    FSS.Renderer.call(this);
    this.element = document.createElement('canvas');
    /* 	this.element.style.display = 'block'; */
    this.element.style.zIndex = "-100";
    this.element.style.pointerEvents = "none";
    this.context = this.element.getContext('2d');
    this.setSize(this.element.width, this.element.height);
};

FSS.CanvasRenderer.prototype = Object.create(FSS.Renderer.prototype);

FSS.CanvasRenderer.prototype.setSize = function (width, height) {
    FSS.Renderer.prototype.setSize.call(this, width, height);
    this.element.width = width;
    this.element.height = height;
    this.context.setTransform(1, 0, 0, 1, 0, 0);
    return this;
};

FSS.CanvasRenderer.prototype.clear = function () {
    FSS.Renderer.prototype.clear.call(this);
    this.context.clearRect(0, 0, this.width, this.height);
    return this;
};

var opacity = [];
FSS.CanvasRenderer.prototype.render = function (scene) {
    FSS.Renderer.prototype.render.call(this, scene);
    var m, mesh, t, triangle, color;
    var pi2 = 2 * Math.PI;

    // Clear Context
    this.clear();

    // Configure Context
    this.context.lineJoin = 'round';
    this.context.lineWidth = 0;

    // Update Meshes
    for (m = scene.meshes.length - 1; m >= 0; m--) {
        mesh = scene.meshes[m];
        if (typeof opacity[m] == "undefined") {
            opacity[m] = [];
        }
        if (mesh.visible) {
            mesh.update(scene.lights, true);

            // Render Triangles
            for (t = mesh.geometry.triangles.length - 1; t >= 0; t--) {

                var now = Date.now();
                if (typeof opacity[m][t] === "undefined") {
                    opacity[m][t] = {};
                    opacity[m][t].step = FSS.Vector3.create(
                            Math.randomInRange(0.2, 1.0),
                            Math.randomInRange(0.2, 1.0),
                            Math.randomInRange(0.2, 1.0)
                            );
                    opacity[m][t].time = Math.randomInRange(0, Math.PIM2);
                    opacity[m][t].line = 0;
                } else {
                    opacity[m][t].line = Math.sin(opacity[m][t].time + opacity[m][t].step[0] * now * (scene.LINE.fluctuationSpeed / 100)) * scene.LINE.fluctuationIntensity;
                    opacity[m][t].vertex = Math.sin(opacity[m][t].time + opacity[m][t].step[0] * now * (scene.VERTEX.fluctuationSpeed / 100)) * scene.VERTEX.fluctuationIntensity;
                    opacity[m][t].mesh = Math.sin(opacity[m][t].time + opacity[m][t].step[0] * now * (scene.MESH.fluctuationSpeed / 100)) * scene.MESH.fluctuationIntensity;
                }


                triangle = mesh.geometry.triangles[t];
                if (scene.MESH.draw !== false) {
                    c = triangle.color.rgba;
                    color = "rgba(" + c[0] + "," + c[1] + ", " + c[2] + "," + c[3] + ")";

                    this.context.beginPath();
                    this.context.moveTo(triangle.a.position[0], triangle.a.position[1]);
                    this.context.lineTo(triangle.b.position[0], triangle.b.position[1]);
                    this.context.lineTo(triangle.c.position[0], triangle.c.position[1]);
                    this.context.closePath();
                    this.context.fillStyle = color; //Color of triangle
                    this.context.fill();
                }


                if (scene.LINE.draw !== false) {
                    var c = new FSS.Color(scene.LINE.fill);
                    c = c.rgba;
                    c[3] = c[3] * (1 - opacity[m][t].line);
                    c = "rgba(" + c[0] + "," + c[1] + ", " + c[2] + "," + c[3] + ")";

                    this.context.beginPath();
                    this.context.moveTo(triangle.a.position[0], triangle.a.position[1]);
                    this.context.lineTo(triangle.b.position[0], triangle.b.position[1]);
                    this.context.lineWidth = scene.LINE.thickness;
                    this.context.fillStyle = c;
                    this.context.fill();
                    this.context.strokeStyle = c;
                    this.context.stroke();
                }

                if (scene.VERTEX.draw !== false) {
                    //                    var grd = this.context.createRadialGradient(triangle.a.position[0], triangle.a.position[1], scene.vertex.radius + 100, triangle.a.position[0], triangle.a.position[1], scene.vertex.radius + 105);
                    // light blue
                    //                    grd.addColorStop(0, '#8ED6FF');
                    // dark blue
                    //                    grd.addColorStop(1, '#004CB3');

                    var c = new FSS.Color(scene.VERTEX.fill);
                    c = c.rgba;
                    c[3] = c[3] * (1 - opacity[m][t].vertex);
                    c = "rgba(" + c[0] + "," + c[1] + ", " + c[2] + "," + c[3] + ")";
                    var c1 = new FSS.Color(scene.VERTEX.strokeColor);
                    c1 = c1.rgba;
                    c1[3] = c1[3] * (1 - opacity[m][t].vertex);
                    c1 = "rgba(" + c1[0] + "," + c1[1] + ", " + c1[2] + "," + c1[3] + ")";
                    this.context.beginPath();
                    this.context.arc(triangle.a.position[0], triangle.a.position[1], scene.VERTEX.radius, 0, pi2, false);
                    this.context.fillStyle = c; //scene.VERTEX.fill;
                    this.context.fill();
                    this.context.lineWidth = scene.VERTEX.strokeWidth;
                    this.context.strokeStyle = c1;
                    this.context.stroke();
                }

            }
        }
    }
    return this;
};

/**
 * @class WebGL Renderer
 * @author Matthew Wagerfield
 */
FSS.WebGLRenderer = function () {
    FSS.Renderer.call(this);
    this.element = document.createElement('canvas');
    this.element.style.display = 'block';

    // Set initial vertex and light count
    this.vertices = null;
    this.lights = null;

    // Create parameters object
    var parameters = {
        preserveDrawingBuffer: false,
        premultipliedAlpha: true,
        antialias: true,
        stencil: true,
        alpha: true
    };

    // Create and configure the gl context
    this.gl = this.getContext(this.element, parameters);

    // Set the internal support flag
    this.unsupported = !this.gl;

    // Setup renderer
    if (this.unsupported) {
        return 'WebGL is not supported by your browser.';
    } else {
        this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
        this.gl.enable(this.gl.DEPTH_TEST);
        this.setSize(this.element.width, this.element.height);
    }
};

FSS.WebGLRenderer.prototype = Object.create(FSS.Renderer.prototype);

FSS.WebGLRenderer.prototype.getContext = function (canvas, parameters) {
    var context = false;
    try {
        if (!(context = canvas.getContext('experimental-webgl', parameters))) {
            throw 'Error creating WebGL context.';
        }
    } catch (error) {
        console.error(error);
    }
    return context;
};

FSS.WebGLRenderer.prototype.setSize = function (width, height) {
    FSS.Renderer.prototype.setSize.call(this, width, height);
    if (this.unsupported)
        return;

    // Set the size of the canvas element
    this.element.width = width;
    this.element.height = height;

    // Set the size of the gl viewport
    this.gl.viewport(0, 0, width, height);
    return this;
};

FSS.WebGLRenderer.prototype.clear = function () {
    FSS.Renderer.prototype.clear.call(this);
    if (this.unsupported)
        return;
    this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
    return this;
};

FSS.WebGLRenderer.prototype.render = function (scene) {
    FSS.Renderer.prototype.render.call(this, scene);
    if (this.unsupported)
        return;
    var m, mesh, t, tl, triangle, l, light,
            attribute, uniform, buffer, data, location,
            update = false,
            lights = scene.lights.length,
            index, v, vl, vetex, vertices = 0;

    // Clear context
    this.clear();

    // Build the shader program
    if (this.lights !== lights) {
        this.lights = lights;
        if (this.lights > 0) {
            this.buildProgram(lights);
        } else {
            return;
        }
    }

    // Update program
    if (!!this.program) {

        // Increment vertex counter
        for (m = scene.meshes.length - 1; m >= 0; m--) {
            mesh = scene.meshes[m];
            if (mesh.geometry.dirty)
                update = true;
            mesh.update(scene.lights, false);
            vertices += mesh.geometry.triangles.length * 3;
        }

        // Compare vertex counter
        if (update || this.vertices !== vertices) {
            this.vertices = vertices;

            // Build buffers
            for (attribute in this.program.attributes) {
                buffer = this.program.attributes[attribute];
                buffer.data = new FSS.Array(vertices * buffer.size);

                // Reset vertex index
                index = 0;

                // Update attribute buffer data
                for (m = scene.meshes.length - 1; m >= 0; m--) {
                    mesh = scene.meshes[m];

                    for (t = 0, tl = mesh.geometry.triangles.length; t < tl; t++) {
                        triangle = mesh.geometry.triangles[t];

                        for (v = 0, vl = triangle.vertices.length; v < vl; v++) {
                            vertex = triangle.vertices[v];
                            switch (attribute) {
                                case 'side':
                                    this.setBufferData(index, buffer, mesh.side);
                                    break;
                                case 'position':
                                    this.setBufferData(index, buffer, vertex.position);
                                    break;
                                case 'centroid':
                                    this.setBufferData(index, buffer, triangle.centroid);
                                    break;
                                case 'normal':
                                    this.setBufferData(index, buffer, triangle.normal);
                                    break;
                                case 'ambient':
                                    this.setBufferData(index, buffer, mesh.material.ambient.rgba);
                                    break;
                                case 'diffuse':
                                    this.setBufferData(index, buffer, mesh.material.diffuse.rgba);
                                    break;
                            }
                            index++;
                        }
                    }
                }

                // Upload attribute buffer data
                this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer.buffer);
                this.gl.bufferData(this.gl.ARRAY_BUFFER, buffer.data, this.gl.DYNAMIC_DRAW);
                this.gl.enableVertexAttribArray(buffer.location);
                this.gl.vertexAttribPointer(buffer.location, buffer.size, this.gl.FLOAT, false, 0, 0);
            }
        }

        // Build uniform buffers
        this.setBufferData(0, this.program.uniforms.resolution, [this.width, this.height, this.width]);
        for (l = lights - 1; l >= 0; l--) {
            light = scene.lights[l];
            this.setBufferData(l, this.program.uniforms.lightPosition, light.position);
            this.setBufferData(l, this.program.uniforms.lightAmbient, light.ambient.rgba);
            this.setBufferData(l, this.program.uniforms.lightDiffuse, light.diffuse.rgba);
        }

        // Update uniforms
        for (uniform in this.program.uniforms) {
            buffer = this.program.uniforms[uniform];
            location = buffer.location;
            data = buffer.data;
            switch (buffer.structure) {
                case '3f':
                    this.gl.uniform3f(location, data[0], data[1], data[2]);
                    break;
                case '3fv':
                    this.gl.uniform3fv(location, data);
                    break;
                case '4fv':
                    this.gl.uniform4fv(location, data);
                    break;
            }
        }
    }

    // Draw those lovely triangles
    this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vertices);
    return this;
};

FSS.WebGLRenderer.prototype.setBufferData = function (index, buffer, value) {
    if (FSS.Utils.isNumber(value)) {
        buffer.data[index * buffer.size] = value;
    } else {
        for (var i = value.length - 1; i >= 0; i--) {
            buffer.data[index * buffer.size + i] = value[i];
        }
    }
};

/**
 * Concepts taken from three.js WebGLRenderer
 * @see https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js
 */
FSS.WebGLRenderer.prototype.buildProgram = function (lights) {
    if (this.unsupported)
        return;

    // Create shader source
    var vs = FSS.WebGLRenderer.VS(lights);
    var fs = FSS.WebGLRenderer.FS(lights);

    // Derive the shader fingerprint
    var code = vs + fs;

    // Check if the program has already been compiled
    if (!!this.program && this.program.code === code)
        return;

    // Create the program and shaders
    var program = this.gl.createProgram();
    var vertexShader = this.buildShader(this.gl.VERTEX_SHADER, vs);
    var fragmentShader = this.buildShader(this.gl.FRAGMENT_SHADER, fs);

    // Attach an link the shader
    this.gl.attachShader(program, vertexShader);
    this.gl.attachShader(program, fragmentShader);
    this.gl.linkProgram(program);

    // Add error handling
    if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
        var error = this.gl.getError();
        var status = this.gl.getProgramParameter(program, this.gl.VALIDATE_STATUS);
        console.error('Could not initialise shader.\nVALIDATE_STATUS: ' + status + '\nERROR: ' + error);
        return null;
    }

    // Delete the shader
    this.gl.deleteShader(fragmentShader);
    this.gl.deleteShader(vertexShader);

    // Set the program code
    program.code = code;

    // Add the program attributes
    program.attributes = {
        side: this.buildBuffer(program, 'attribute', 'aSide', 1, 'f'),
        position: this.buildBuffer(program, 'attribute', 'aPosition', 3, 'v3'),
        centroid: this.buildBuffer(program, 'attribute', 'aCentroid', 3, 'v3'),
        normal: this.buildBuffer(program, 'attribute', 'aNormal', 3, 'v3'),
        ambient: this.buildBuffer(program, 'attribute', 'aAmbient', 4, 'v4'),
        diffuse: this.buildBuffer(program, 'attribute', 'aDiffuse', 4, 'v4')
    };

    // Add the program uniforms
    program.uniforms = {
        resolution: this.buildBuffer(program, 'uniform', 'uResolution', 3, '3f', 1),
        lightPosition: this.buildBuffer(program, 'uniform', 'uLightPosition', 3, '3fv', lights),
        lightAmbient: this.buildBuffer(program, 'uniform', 'uLightAmbient', 4, '4fv', lights),
        lightDiffuse: this.buildBuffer(program, 'uniform', 'uLightDiffuse', 4, '4fv', lights)
    };

    // Set the renderer program
    this.program = program;

    // Enable program
    this.gl.useProgram(this.program);

    // Return the program
    return program;
};

FSS.WebGLRenderer.prototype.buildShader = function (type, source) {
    if (this.unsupported)
        return;

    // Create and compile shader
    var shader = this.gl.createShader(type);
    this.gl.shaderSource(shader, source);
    this.gl.compileShader(shader);

    // Add error handling
    if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
        console.error(this.gl.getShaderInfoLog(shader));
        return null;
    }

    // Return the shader
    return shader;
};

FSS.WebGLRenderer.prototype.buildBuffer = function (program, type, identifier, size, structure, count) {
    var buffer = {
        buffer: this.gl.createBuffer(),
        size: size,
        structure: structure,
        data: null
    };

    // Set the location
    switch (type) {
        case 'attribute':
            buffer.location = this.gl.getAttribLocation(program, identifier);
            break;
        case 'uniform':
            buffer.location = this.gl.getUniformLocation(program, identifier);
            break;
    }

    // Create the buffer if count is provided
    if (!!count) {
        buffer.data = new FSS.Array(count * size);
    }

    // Return the buffer
    return buffer;
};

FSS.WebGLRenderer.VS = function (lights) {
    var shader = [
        // Precision
        'precision mediump float;',
        // Lights
        '#define LIGHTS ' + lights,
        // Attributes
        'attribute float aSide;',
        'attribute vec3 aPosition;',
        'attribute vec3 aCentroid;',
        'attribute vec3 aNormal;',
        'attribute vec4 aAmbient;',
        'attribute vec4 aDiffuse;',
        // Uniforms
        'uniform vec3 uResolution;',
        'uniform vec3 uLightPosition[LIGHTS];',
        'uniform vec4 uLightAmbient[LIGHTS];',
        'uniform vec4 uLightDiffuse[LIGHTS];',
        // Varyings
        'varying vec4 vColor;',
        // Main
        'void main() {',
        // Create color
        'vColor = vec4(0.0);',
        // Calculate the vertex position
        'vec3 position = aPosition / uResolution * 2.0;',
        // Iterate through lights
        'for (int i = 0; i < LIGHTS; i++) {',
        'vec3 lightPosition = uLightPosition[i];',
        'vec4 lightAmbient = uLightAmbient[i];',
        'vec4 lightDiffuse = uLightDiffuse[i];',
        // Calculate illuminance
        'vec3 ray = normalize(lightPosition - aCentroid);',
        'float illuminance = dot(aNormal, ray);',
        'if (aSide == 0.0) {',
        'illuminance = max(illuminance, 0.0);',
        '} else if (aSide == 1.0) {',
        'illuminance = abs(min(illuminance, 0.0));',
        '} else if (aSide == 2.0) {',
        'illuminance = max(abs(illuminance), 0.0);',
        '}',
        // Calculate ambient light
        'vColor += aAmbient * lightAmbient;',
        // Calculate diffuse light
        'vColor += aDiffuse * lightDiffuse * illuminance;',
        '}',
        // Clamp color
        'vColor = clamp(vColor, 0.0, 1.0);',
        // Set gl_Position
        'gl_Position = vec4(position, 1.0);',
        '}'

                // Return the shader
    ].join('\n');
    return shader;
};

FSS.WebGLRenderer.FS = function (lights) {
    var shader = [
        // Precision
        'precision mediump float;',
        // Varyings
        'varying vec4 vColor;',
        // Main
        'void main() {',
        // Set gl_FragColor
        'gl_FragColor = vColor;',
        '}'

                // Return the shader
    ].join('\n');
    return shader;
};

/**
 * @class SVG Renderer
 * @author Matthew Wagerfield
 */
FSS.SVGRenderer = function () {
    FSS.Renderer.call(this);
    this.element = document.createElementNS(FSS.SVGNS, 'svg');
    this.element.setAttribute('xmlns', FSS.SVGNS);
    this.element.setAttribute('version', '1.1');
    this.element.style.display = 'block';
    this.setSize(300, 150);
};

FSS.SVGRenderer.prototype = Object.create(FSS.Renderer.prototype);

FSS.SVGRenderer.prototype.setSize = function (width, height) {
    FSS.Renderer.prototype.setSize.call(this, width, height);
    this.element.setAttribute('width', width);
    this.element.setAttribute('height', height);
    return this;
};

FSS.SVGRenderer.prototype.clear = function () {
    FSS.Renderer.prototype.clear.call(this);
    for (var i = this.element.childNodes.length - 1; i >= 0; i--) {
        this.element.removeChild(this.element.childNodes[i]);
    }
    return this;
};

FSS.SVGRenderer.prototype.render = function (scene) {
    FSS.Renderer.prototype.render.call(this, scene);
    var m, mesh, t, triangle, points, style;

    // Update Meshes
    for (m = scene.meshes.length - 1; m >= 0; m--) {
        mesh = scene.meshes[m];
        if (mesh.visible) {
            mesh.update(scene.lights, true);

            // Render Triangles
            for (t = mesh.geometry.triangles.length - 1; t >= 0; t--) {
                triangle = mesh.geometry.triangles[t];
                if (triangle.polygon.parentNode !== this.element) {
                    this.element.appendChild(triangle.polygon);
                }
                points = this.formatPoint(triangle.a) + ' ';
                points += this.formatPoint(triangle.b) + ' ';
                points += this.formatPoint(triangle.c);
                style = this.formatStyle(triangle.color.format());
                triangle.polygon.setAttributeNS(null, 'points', points);
                triangle.polygon.setAttributeNS(null, 'style', style);
            }
        }
    }
    return this;
};

FSS.SVGRenderer.prototype.formatPoint = function (vertex) {
    return (vertex.position[0]) + ',' + (vertex.position[1]);
};

FSS.SVGRenderer.prototype.formatStyle = function (color) {
    var style = 'fill:' + color + ';';
    style += 'stroke:' + color + ';';
    return style;
};

(function () {
    $.fn.Geometryangle = function (opt) {
        var fss = [];
        var element = $(this);
        var len = element.length, k;
        for (var j = 0; j < len; j++) {
            k = element[j];
            fss[fss.length] = FSS_Worker(opt, k);
        }
        return (fss.length == 1 ? fss[0] : fss);
    };
    var FSS_Worker = function (opt, k) {

        opt = opt || {};
        var MESH = {}, LIGHT = [{}],
                VERTEX = {}, LINE = {};

        var getDataAttr = function (element) {
            var data_option = [
                [],
                []
            ];
            //        var keys = Object.keys(option);
            var d = [MESH, LIGHT];
            $.each(d, function (u) {
                $.each(d[u], function (i, val) {
                    if (typeof element.getAttribute('data-fss-'  [i]) !== "undefined" && typeof element.getAttribute('data-fss-' + [i]) !== false) {
                        try {
                            data_option[u][i] = $.parseJSON(element.getAttribute('data-fss-' + [i]));
                            return true; //continue;
                        } catch (e) {
                        }
                        if (typeof data_option[u][i] !== "object") {
                            data_option[u][i] = element.getAttribute('data-fss-' + [i]);
                        }
                    }
                });

                var data_json = (typeof element.getAttribute('data-fss') !== "undefined" && typeof element.getAttribute('data-fss') !== false ? $.parseJSON(element.getAttribute('data-fss')) : []);

                $.extend(true, data_option[u], data_json);
            });

            return data_option;
        };

        var rgbaToRgb = function (rgba) {
            try {
                var bits = rgba.split("(");
            } catch (e) {
                return;
            }
            if (typeof bits[1] !== "undefined") {
                bits = bits[1].split(")")[0].split(",");
                return "rgb(" + bits[0] + "," + bits[1] + "," + bits[2] + ")";
            }
            return;
        };

        //------------------------------
        // Mesh Properties
        //------------------------------
        var mesh_default = {
            width: 1.2,
            height: 1.2,
            depth: 10,
            columns: undefined,
            columns_auto: true,
            rows: undefined,
            rows_auto: true,
            zoom: 1,
            xRange: 0.8,
            yRange: 0.1,
            zRange: 1.0,
            ambient: 'rgba(85, 85, 85, 1)',
            diffuse: 'rgba(255, 255, 255, 1)',
            background: 'rgb(255, 255, 255)',
            speed: 0.0002,
            fluctuationSpeed: 0.5,
            fluctuationIntensity: 0,
            onRender: function () {
            },
            floorPosition: false,
            draw: true
        };

        var vertex_default = {
            radius: 0,
            fill: "rgba(0, 0, 0, 0)",
            fluctuationSpeed: 0.5,
            fluctuationIntensity: 0,
            strokeWidth: 0,
            strokeColor: "rgba(0, 0, 0, 0)",
            draw: false
        };

        var line_default = {
            fill: "rgba(0, 0, 0, 0)",
            thickness: 1,
            fluctuationIntensity: 0,
            fluctuationSpeed: 0.5,
            draw: false
        };

        //------------------------------
        // Light Properties
        //------------------------------
        var light_default = {
            count: 1,
            xyScalar: 1,
            zOffset: 100,
            ambient: 'rgba(255,0,102, 1)',
            diffuse: 'rgba(255,136,0, 1)',
            speed: 0.010,
            gravity: 1200,
            dampening: 0.95,
            minLimit: 10,
            maxLimit: null,
            minDistance: 20,
            maxDistance: 400,
            autopilot: false,
            draw: false, //show circle
            bounds: FSS.Vector3.create(),
            step: FSS.Vector3.create(
                    Math.randomInRange(0.2, 1.0),
                    Math.randomInRange(0.2, 1.0),
                    Math.randomInRange(0.2, 1.0)
                    )
        };

        var self = k;

        var createValues = function (opt) {
            opt.mesh = opt.mesh || MESH;
            opt.lights = opt.lights || LIGHT;
            opt.vertex = opt.vertex || VERTEX;
            opt.line = opt.line || LINE;

            MESH = $.extend(true, mesh_default, MESH, opt.mesh);
            VERTEX = $.extend(true, vertex_default, VERTEX, opt.vertex);
            LINE = $.extend(true, line_default, LINE, opt.line);
            for (var i = 0; i < LIGHT.length; i++) {
                LIGHT[i] = $.extend(true, light_default, LIGHT[i], opt.lights[i]);
            }
            var box_data_option = getDataAttr(self);
            MESH = $.extend(true, box_data_option[0], MESH);

            MESH.columns_auto = (typeof opt.mesh.columns === "undefined");
            MESH.rows_auto = (typeof opt.mesh.rows === "undefined");
        };
        createValues({
            mesh: mesh_default,
            line: line_default,
            vertex: vertex_default,
            lights: [light_default]
        });
        createValues(opt);

        var container = document.createElement("div");
        container.style.position = "absolute";
        container.style.left = "0";
        container.style.right = "0";
        container.style.top = "0";
        container.style.bottom = "0";
        container.style.background = MESH.background;
        container.style.zIndex = "-100";
        container.setAttribute('class', 'fss-output');
        self.insertBefore(container, null);



        //------------------------------
        // Render Properties
        //------------------------------
        var WEBGL = 'webgl';
        var CANVAS = 'canvas';
        var SVG = 'svg';
        var RENDER = {
            renderer: CANVAS
        };

        //------------------------------
        // UI Properties
        //------------------------------
        var UI = {
            show: true
        };

        //------------------------------
        // Global Properties
        //------------------------------
        var now, start = Date.now();
        var center = FSS.Vector3.create();
        var attractor = FSS.Vector3.create();
        //var container = document.getElementById('container'); -- taken from JQuery element
        /* 		var output = document.getElementById('output'); */
        var ui = document.getElementById('ui');
        var renderer, scene, mesh, geometry, material;
        var webglRenderer, canvasRenderer, svgRenderer;
        var gui, autopilotController;

        //------------------------------
        // Methods
        //------------------------------
        function initialise() {
            createRenderer();
            createScene();
            createMesh();
            createLights();
            addEventListeners();
            callbacks.resize(container.offsetWidth, container.offsetHeight);
            animate();
        }

        function createRenderer() {
            webglRenderer = new FSS.WebGLRenderer();
            canvasRenderer = new FSS.CanvasRenderer();
            svgRenderer = new FSS.SVGRenderer();
            setRenderer(RENDER.renderer);
        }

        function setRenderer(index) {
            if (renderer) {
                /* 				output.removeChild(renderer.element); */
            }
            switch (index) {
                case WEBGL:
                    renderer = webglRenderer;
                    break;
                case CANVAS:
                    renderer = canvasRenderer;
                    break;
                case SVG:
                    renderer = svgRenderer;
                    break;
            }
            renderer.setSize(container.offsetWidth, container.offsetHeight);
            container.insertBefore(renderer.element, null);

            var style = window.getComputedStyle(self);

            if (style.getPropertyValue('position') == 'static' || style.getPropertyValue('position').length == 0) {
                self.style.position = 'relative';
            }

        }

        function createScene() {
            scene = new FSS.Scene();
            scene.VERTEX = VERTEX;
            scene.LINE = LINE;
            scene.MESH = MESH;
        }

        function createMesh() {
            scene.remove(mesh);
            renderer.clear();
            geometry = new FSS.Plane(MESH.width * renderer.width, MESH.height * renderer.height, MESH.columns, MESH.rows);
            material = new FSS.Material(MESH.ambient, MESH.diffuse);
            mesh = new FSS.Mesh(geometry, material);
            scene.add(mesh);

            // Augment vertices for animation
            var v, vertex;
            for (v = geometry.vertices.length - 1; v >= 0; v--) {
                vertex = geometry.vertices[v];
                vertex.anchor = FSS.Vector3.floor(FSS.Vector3.clone(vertex.position));
                vertex.step = FSS.Vector3.create(
                        Math.randomInRange(0.2, 1.0),
                        Math.randomInRange(0.2, 1.0),
                        Math.randomInRange(0.2, 1.0)
                        );
                vertex.time = Math.randomInRange(0, Math.PIM2);
            }
        }

        function createLights() {
            var l, light;
            for (l = scene.lights.length - 1; l >= 0; l--) {
                light = scene.lights[l];
                scene.remove(light);
            }
            renderer.clear();
            for (l = 0; l < LIGHT.length; l++) {
                for (var u = 0; u < LIGHT[l].count; u++) {
                    light = new FSS.Light(LIGHT[l].ambient, LIGHT[l].diffuse);
                    scene.add(light);

                    // Augment light for animation
                    light.mass = Math.randomInRange(0.5, 1);
                    light.velocity = FSS.Vector3.create();
                    light.acceleration = FSS.Vector3.create();
                    light.force = FSS.Vector3.create();

                    // Ring SVG Circle
                    light.ring = document.createElementNS(FSS.SVGNS, 'circle');
                    light.ring.setAttributeNS(null, 'stroke', light.ambient);
                    light.ring.setAttributeNS(null, 'stroke-width', '0.5');
                    light.ring.setAttributeNS(null, 'fill', 'none');
                    light.ring.setAttributeNS(null, 'r', '10');

                    // Core SVG Circle
                    light.core = document.createElementNS(FSS.SVGNS, 'circle');
                    light.core.setAttributeNS(null, 'fill', light.diffuseHex);
                    light.core.setAttributeNS(null, 'r', '4');
                }
            }
        }
        var callbacks = {
            resize: function (width, height) {

                if (typeof width == "undefined" || typeof width === undefined) {
                    width = self.width();
                }
                if (typeof height == "undefined" || typeof height === undefined) {
                    height = self.height();
                }
                var ratio_x = width / 1000;
                var ratio_y = height / 1000;
                var x_tiles = Math.round(ratio_x * 10) * MESH.zoom;
                var y_tiles = Math.round(ratio_y * 10) * MESH.zoom;
                MESH.columns = (MESH.columns_auto === true ? x_tiles : MESH.columns);
                MESH.rows = (MESH.rows_auto === true ? y_tiles : MESH.rows);
                renderer.setSize(width, height);
                FSS.Vector3.set(center, renderer.halfWidth, renderer.halfHeight);
                createMesh();
            },
            update: function (opt) {
                createValues(opt);
                scene.vertex = VERTEX;
                scene.line = LINE;
                //Ambient
                for (i = 0, l = scene.meshes.length; i < l; i++) {
                    scene.meshes[i].material.ambient.set(MESH.ambient);
                    scene.meshes[i].material.diffuse.set(MESH.diffuse);
                }
                //width
                if (geometry.width !== MESH.width * renderer.width) {
                    createMesh();
                }
                if (geometry.height !== MESH.height * renderer.height) {
                    createMesh();
                }
                if (geometry.segments !== MESH.columns) {
                    createMesh();
                }
                if (geometry.slices !== MESH.rows) {
                    createMesh();
                }

                var light_index = 0;

                for (l = 0; l < LIGHT.length; l++) {

                    for (var i = 0; i < LIGHT[l].count; i++) {
                        light = scene.lights[light_index];
                        light.ambient.set(LIGHT[l].ambient);

                        light = scene.lights[light_index];
                        light.diffuse.set(LIGHT[l].diffuse);

                        light_index++;
                    }
                }

                if (scene.lights.length !== light_index) {
                    createLights();
                }

            },
            animateValues: function (colors) {

                var body = document.body,
                        html = document.documentElement, scrollTop = ((window.pageYOffset || html.scrollTop) - (html.clientTop || 0));

                var height = Math.max(body.scrollHeight, body.offsetHeight,
                        html.clientHeight, html.scrollHeight, html.offsetHeight);


                var length = colors.length;
                var height = Math.round(height / length); // Height of the segment between two colors
                var i = Math.floor(scrollTop / height); // Start color index
                var d = scrollTop % height / height; // Which part of the segment between start color and end color is passed
                var c1 = colors[i]; // Start color
                var c2 = colors[(i + 1) % length]; // End color
                var result = [];
                for (var i = 0; i < c1.length; i++) {
                    result[i] = c1[i] + ((c2[i] - c1[i]) * d);
                    if (i !== 3) {
                        result[i] = Math.round(result[i]);
                    }
                }
                return result;
            },
            formatRGBA: function (a) {
                var string = "rgba(" + a[0] + "," + a[1] + "," + a[2] + "," + a[3] + ")";
                return string;
            }
        };


        function animate() {
            now = Date.now() - start;
            update();
            render();
            requestAnimationFrame(animate);
        }

        function update() {
            var ox, oy, oz, l, light, v, vertex, offset = MESH.depth / 2;
            var light_index = 0;
            var render_vector = FSS.Vector3.floor(FSS.Vector3.create(renderer.halfWidth, renderer.halfHeight, 0));

            // Animate Lights
            for (l = 0; l < LIGHT.length; l++) {

                for (var i = 0; i < LIGHT[l].count; i++) {

                    light = scene.lights[light_index];

                    // Update Bounds
                    FSS.Vector3.copy(LIGHT[l].bounds, center);
                    FSS.Vector3.multiplyScalar(LIGHT[l].bounds, LIGHT[l].xyScalar);

                    // Update Attractor
                    FSS.Vector3.setZ(attractor, LIGHT[l].zOffset);

                    // Overwrite the Attractor position
                    if (LIGHT[l].autopilot && typeof LIGHT[l].position === "undefined") {
                        ox = Math.sin(LIGHT[l].step[0] * now * LIGHT[l].speed);
                        oy = Math.cos(LIGHT[l].step[1] * now * LIGHT[l].speed);
                        FSS.Vector3.set(attractor,
                                LIGHT[l].bounds[0] * ox,
                                LIGHT[l].bounds[1] * oy,
                                LIGHT[l].zOffset);
                    }

                    // Reset the z position of the light
                    FSS.Vector3.setZ(light.position, LIGHT[l].zOffset);

                    if (typeof LIGHT[l].position !== "undefined") {
                        FSS.Vector3.set(light.position);
                        FSS.Vector3.add(light.position, FSS.Vector3.create(LIGHT[l].position[0], LIGHT[l].position[1], LIGHT[l].zOffset));
                    } else {
                        // Calculate the force Luke!
                        var D = Math.clamp(FSS.Vector3.distanceSquared(light.position, attractor), LIGHT[l].minDistance, LIGHT[l].maxDistance);
                        var F = LIGHT[l].gravity * light.mass / D;
                        FSS.Vector3.subtractVectors(light.force, attractor, light.position);
                        FSS.Vector3.normalise(light.force);
                        FSS.Vector3.multiplyScalar(light.force, F);
                        // Update the light position
                        FSS.Vector3.set(light.acceleration);
                        FSS.Vector3.add(light.acceleration, light.force);
                        FSS.Vector3.add(light.velocity, light.acceleration);
                        FSS.Vector3.multiplyScalar(light.velocity, LIGHT[l].dampening);
                        FSS.Vector3.limit(light.velocity, LIGHT[l].minLimit, LIGHT[l].maxLimit);
                        FSS.Vector3.add(light.position, light.velocity);
                    }

                    light_index++;
                }
            }



            // Animate Vertices
            for (v = geometry.vertices.length - 1; v >= 0; v--) {
                vertex = geometry.vertices[v];
                ox = Math.sin(vertex.time + vertex.step[0] * now * MESH.speed);
                oy = Math.cos(vertex.time + vertex.step[1] * now * MESH.speed);
                oz = Math.sin(vertex.time + vertex.step[2] * now * MESH.speed);
                vertex.position = FSS.Vector3.create(
                        MESH.xRange * geometry.segmentWidth * ox,
                        MESH.yRange * geometry.sliceHeight * oy,
                        MESH.zRange * offset * oz - offset);
                if (MESH.positionFloor === true) {
                    vertex.position = FSS.Vector3.floor(vertex.position);
                }
                FSS.Vector3.add(vertex.position, vertex.anchor);
                FSS.Vector3.add(vertex.position, render_vector);
            }

            // Set the Geometry to dirty
            geometry.dirty = true;
        }

        function render() {
            renderer.render(scene);

            // Draw Lights
            if (LIGHT.draw) {
                var l, lx, ly, light;
                for (l = scene.lights.length - 1; l >= 0; l--) {
                    light = scene.lights[l];
                    lx = light.position[0];
                    ly = light.position[1];
                    switch (RENDER.renderer) {
                        case CANVAS:
                            renderer.context.lineWidth = 0.5;
                            renderer.context.beginPath();
                            renderer.context.arc(lx, ly, 10, 0, Math.PIM2);
                            renderer.context.strokeStyle = light.ambient;
                            renderer.context.stroke();
                            renderer.context.beginPath();
                            renderer.context.arc(lx, ly, 4, 0, Math.PIM2);
                            renderer.context.fillStyle = light.diffuse;
                            renderer.context.fill();
                            break;
                        case SVG:
                            /* 							lx += renderer.halfWidth; */
                            /* 							ly = renderer.halfHeight - ly; */
                            light.core.setAttributeNS(null, 'fill', light.diffuse);
                            light.core.setAttributeNS(null, 'cx', lx);
                            light.core.setAttributeNS(null, 'cy', ly);
                            renderer.element.appendChild(light.core);
                            light.ring.setAttributeNS(null, 'stroke', light.ambient);
                            light.ring.setAttributeNS(null, 'cx', lx);
                            light.ring.setAttributeNS(null, 'cy', ly);
                            renderer.element.appendChild(light.ring);
                            break;
                    }
                }
            }
            MESH.onRender(scene, renderer.context);
        }

        function addEventListeners() {
            if(window.attachEvent) {
                window.addEventHandler = window.attachEvent;
            }
            window.addEventListener('resize', onWindowResize, false);
            self.addEventListener('click', onMouseClick, false);
            self.addEventListener('mousemove', onMouseMove, true);
        }

        //------------------------------
        // Callbacks
        //------------------------------
        function onMouseClick(event) {
            FSS.Vector3.set(attractor, event.x, event.y);
            /* 			FSS.Vector3.subtract(attractor, center); */
            LIGHT.autopilot = !LIGHT.autopilot;
        }

        function onMouseMove(event) {
            console.log(event);
            FSS.Vector3.set(attractor, event.x, event.y);
            /* 			FSS.Vector3.subtract(attractor, center); */
        }

        function onWindowResize(event) {
            callbacks.resize(self.offsetWidth, self.offsetHeight);
            render();
        }


        // Let there be light!
        initialise();
        return callbacks;
    };
})();



$(document).ready(function(){
$('.background').Geometryangle({

// handle transparent colors
mesh:{

  width: 1.2,
  height: 1.2,

  // How far should the mesh vary into z-space.
  depth: 10,

  // Number of columns for the mesh.
  columns: 12,

  columns_auto: false,

  // Number of rows for the mesh.
  rows: 7,

  rows_auto: true,
  zoom: 1,
  xRange: 0.8,
  yRange: 0.1,
  zRange: 3.0,
  ambient: 'rgba(14, 9, 131, 1)',
  diffuse: 'rgba(136, 12, 131, 1)',
  background: 'rgb(241, 173, 27)',
  speed: 0.0002,
  fluctuationSpeed: .2,
  fluctuationIntensity: 0,
  onRender: function () {
  },
  floorPosition: false,
  draw: true

}, 


lights: {

  // How many light sources belong to this light.
  count: 1,

  xyScalar: 1,

  // Position of light source.
  zOffset: 100,

  ambient: 'rgba(97,0,94, 1)',
  diffuse: 'rgba(97,18,94, 1)',
  speed: 0.001,
  gravity: 100,

  // Dampening of light's movements.
  dampening: 0.95,

  minLimit: 10,
  maxLimit: null,
  minDistance: 20,
  maxDistance: 400,
  autopilot: false,
  draw: false, //show circle
  bounds: FSS.Vector3.create(),
  step: FSS.Vector3.create(
    Math.randomInRange(0.2, 1.0),
    Math.randomInRange(0.2, 1.0),
    Math.randomInRange(0.2, 1.0)
  )

},

// specify the thickness, color, stroke, etc. 
line: {

  fill: "rgba(0, 0, 0, 0)",
  thickness: 1,
  fluctuationIntensity: 0,
  fluctuationSpeed: 0.5,
  draw: false

}, 

// Set the point attributes for the vertex. 
vertex: {

  // Radius of vertice circle.
  radius: 0,

  fill: "rgba(0, 0, 0, 0)",

  // Fluctuates opacity of vertex.
  fluctuationSpeed: 0.5,

  fluctuationIntensity: 0,
  strokeWidth: 0,
  strokeColor: "rgba(0, 0, 0, 0)",

  // Instead of setting alpha channel to zero
  // Set draw to false to avoid computing.
  draw: false

}

});
});