Browse Source

Vector4, EulerAngles, Quaternions, toEulerAngleToRef

U-REDMOND\v-oniobi 10 years ago
parent
commit
42dd5053fa
4 changed files with 1383 additions and 72 deletions
  1. 428 24
      Babylon/Math/babylon.math.js
  2. 435 24
      Babylon/Math/babylon.math.ts
  3. 445 24
      babylon.2.0-alpha.debug.js
  4. 75 0
      babylon.2.0.d.ts

+ 428 - 24
Babylon/Math/babylon.math.js

@@ -898,6 +898,272 @@
     })();
     })();
     BABYLON.Vector3 = Vector3;
     BABYLON.Vector3 = Vector3;
 
 
+    var Vector4 = (function () {
+        function Vector4(x, y, z, w) {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+            this.w = w;
+        }
+
+        Vector4.prototype.toString = function ()
+        { return "{X: " + this.x + " Y:" + this.y + " Z:" + this.z + "W:" + this.w + "}"; };
+
+        Vector4.prototype.asArray = function () {
+            var result = [];
+
+            this.toArray(result, 0);
+
+            return result;
+        };
+
+        Vector4.prototype.toArray = function (array, index) {
+            if (index === undefined) {
+                index = 0;
+            }
+
+            array[index] = this.x;
+            array[index + 1] = this.y;
+            array[index + 2] = this.z;
+            array[index + 3] = this.w;
+        };
+
+        Vector4.prototype.addInPlace = function (otherVector) {
+            this.x += otherVector.x;
+            this.y += otherVector.y;
+            this.z += otherVector.z;
+            this.w += otherVector.w;
+        };
+
+        Vector4.prototype.add = function (otherVector) {
+            return new Vector4(this.x + otherVector.x, this.y + otherVector.y, this.z + otherVector.z, this.w + otherVector.w);
+        };
+
+        Vector4.prototype.addToRef = function (otherVector, result) {
+            result.x = this.x + otherVector.x;
+            result.y = this.y + otherVector.y;
+            result.z = this.z + otherVector.z;
+            result.w = this.w + otherVector.w;
+        };
+
+        Vector4.prototype.subtractInPlace = function (otherVector) {
+            this.x -= otherVector.x;
+            this.y -= otherVector.y;
+            this.z -= otherVector.z;
+            this.w -= otherVector.w;
+        };
+
+        Vector4.prototype.subtract = function (otherVector)
+        { return new Vector4(this.x - otherVector.x, this.y - otherVector.y, this.z - otherVector.z, this.w - otherVector.w); };
+
+        Vector4.prototype.subtractToRef = function (otherVector, result) {
+            result.x = this.x - otherVector.x;
+            result.y = this.y - otherVector.y;
+            result.z = this.z - otherVector.z;
+            result.w = this.w - otherVector.w;
+        };
+
+        Vector4.prototype.subtractFromFloats = function (x, y, z, w)
+        { return new Vector4(this.x - x, this.y - y, this.z - z, this.w - w); };
+
+        Vector4.prototype.subtractFromFloatsToRef = function (x, y, z, w, result) {
+            result.x = this.x - x;
+            result.y = this.y - y;
+            result.z = this.z - z;
+            result.w = this.w - w;
+        };
+
+        Vector4.prototype.negate = function ()
+        { return new Vector4(-this.x, -this.y, -this.z, -this.w); };
+
+        Vector4.prototype.scaleInPlace = function (scale) {
+            this.x *= scale;
+            this.y *= scale;
+            this.z *= scale;
+            this.w *= scale;
+            return this;
+        };
+
+        Vector4.prototype.scale = function (scale)
+        { return new Vector4(this.x * scale, this.y * scale, this.z * scale, this.w * scale); };
+
+        Vector4.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+        };
+
+        Vector4.prototype.equals = function (otherVector)
+        { return otherVector && this.x === otherVector.x && this.y === otherVector.y && this.z === otherVector.z && this.w === otherVector.w; };
+
+        Vector4.prototype.equalsWithEpsilon = function (otherVector) {
+            return Math.abs(this.x - otherVector.x) < Engine.Epsilon &&
+                Math.abs(this.y - otherVector.y) < Engine.Epsilon &&
+                Math.abs(this.z - otherVector.z) < Engine.Epsilon &&
+                Math.abs(this.w - otherVector.w) < Engine.Epsilon;
+        };
+
+        Vector4.prototype.equalsToFloats = function (x, y, z, w)
+        { return this.x === x && this.y === y && this.z === z && this.w === w; };
+
+        Vector4.prototype.multiplyInPlace = function (otherVector) {
+            this.x *= otherVector.x;
+            this.y *= otherVector.y;
+            this.z *= otherVector.z;
+            this.w *= otherVector.w;
+        };
+
+        Vector4.prototype.multiply = function (otherVector)
+        { return new Vector4(this.x * otherVector.x, this.y * otherVector.y, this.z * otherVector.z, this.w * otherVector.w); };
+
+        Vector4.prototype.multiplyToRef = function (otherVector, result) {
+            result.x = this.x * otherVector.x;
+            result.y = this.y * otherVector.y;
+            result.z = this.z * otherVector.z;
+            result.w = this.w * otherVector.w;
+        };
+
+        Vector4.prototype.multiplyByFloats = function (x, y, z, w)
+        { return new Vector4(this.x * x, this.y * y, this.z * z, this.w * w); };
+
+        Vector4.prototype.divide = function (otherVector)
+        { return new Vector4(this.x / otherVector.x, this.y / otherVector.y, this.z / otherVector.z, this.w / otherVector.w); };
+
+        Vector4.prototype.divideToRef = function (otherVector, result) {
+            result.x = this.x / otherVector.x;
+            result.y = this.y / otherVector.y;
+            result.z = this.z / otherVector.z;
+            result.w = this.w / otherVector.w;
+        };
+
+        Vector4.prototype.minimizeInPlace = function (other) {
+            if (other.x < this.x) this.x = other.x;
+            if (other.y < this.y) this.y = other.y;
+            if (other.z < this.z) this.z = other.z;
+            if (other.w < this.w) this.w = other.w;
+        };
+
+        Vector4.prototype.MaximizeInPlace = function (other) {
+            if (other.x > this.x) this.x = other.x;
+            if (other.y > this.y) this.y = other.y;
+            if (other.z > this.z) this.z = other.z;
+            if (other.w > this.w) this.w = other.w;
+        };
+
+        Vector4.prototype.length = function ()
+        { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); };
+
+        Vector4.prototype.lengthSquared = function ()
+        { return (this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); };
+
+        Vector4.prototype.normalize = function () {
+            var len = this.length();
+
+            if (len === 0)
+                return this;
+
+            var num = 1.0 / len;
+
+            this.x *= num;
+            this.y *= num;
+            this.z *= num;
+            this.w *= num;
+
+            return this;
+        };
+
+        Vector4.prototype.clone = function ()
+        { return new Vector4(this.x, this.y, this.z, this.w); };
+
+        Vector4.prototype.copyFrom = function (source) {
+            this.x = source.x;
+            this.y = source.y;
+            this.z = source.z;
+            this.w = source.w;
+        };
+
+        Vector4.prototype.copyFromFloats = function (x, y, z, w) {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+            this.w = w;
+        };
+
+        Vector4.FromArray = function (array, offset) {
+            if (!offset) { offset = 0; }
+
+            return new Vector4(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
+        };
+
+        Vector4.FromArrayToRef = function (array, offset, result) {
+            result.x = array[offset];
+            result.y = array[offset + 1];
+            result.z = array[offset + 2];
+            result.w = array[offset + 3];
+        };
+
+        Vector4.FromFloatArrayToRef = function (array, offset, result) {
+            result.x = array[offset];
+            result.y = array[offset + 1];
+            result.z = array[offset + 2];
+            result.w = array[offset + 3];
+        };
+
+        Vector4.FromFloatsToRef = function (x, y, z, w, result) {
+            result.x = x;
+            result.y = y;
+            result.z = z;
+            result.w = w;
+        };
+
+        Vector4.Zero = function () { return new Vector4(0, 0, 0, 0); };
+
+        Vector4.Normalize = function (vector) {
+            var result = Vector4.Zero();
+            Vector4.NormalizeToRef(vector, result);
+            return result;
+        };
+
+        Vector4.NormalizeToRef = function (vector, result) {
+            result.copyFrom(vector);
+            result.normalize();
+        };
+
+        Vector4.Minimize = function (left, right) {
+            var min = left.clone();
+            min.MinimizeInPlace(right);
+            return min;
+        };
+
+        Vector4.Maximize = function (left, right) {
+            var max = left.clone();
+            max.MaximizeInPlace(right);
+            return max;
+        };
+
+        Vector4.Distance = function (value1, value2) { return Math.sqrt(Vector4.DistanceSquared(value1, value2)); };
+
+        Vector4.DistanceSquared = function (value1, value2) {
+            var x = value1.x - value2.x;
+            var y = value1.y - value2.y;
+            var z = value1.z - value2.z;
+            var w = value1.w - value2.w;
+
+            return (x * x) + (y * y) + (z * z) + (w * w);
+        };
+
+        Vector4.Center = function (value1, value2) {
+            var center = value1.add(value2);
+            center.scaleInPlace(0.5);
+            return center;
+        };
+
+        return Vector4;
+
+    })();
+    BABYLON.Vector4 = Vector4;
+
     var Quaternion = (function () {
     var Quaternion = (function () {
         function Quaternion(x, y, z, w) {
         function Quaternion(x, y, z, w) {
             if (typeof x === "undefined") { x = 0; }
             if (typeof x === "undefined") { x = 0; }
@@ -987,31 +1253,39 @@
         };
         };
 
 
         Quaternion.prototype.toEulerAnglesToRef = function (result) {
         Quaternion.prototype.toEulerAnglesToRef = function (result) {
-            var qx = this.x;
-            var qy = this.y;
-            var qz = this.z;
-            var qw = this.w;
-
-            var sqx = qx * qx;
-            var sqy = qy * qy;
-            var sqz = qz * qz;
-
-            var yaw = Math.atan2(2.0 * (qy * qw - qx * qz), 1.0 - 2.0 * (sqy + sqz));
-            var pitch = Math.asin(2.0 * (qx * qy + qz * qw));
-            var roll = Math.atan2(2.0 * (qx * qw - qy * qz), 1.0 - 2.0 * (sqx + sqz));
-
-            var gimbaLockTest = qx * qy + qz * qw;
-            if (gimbaLockTest > 0.499) {
-                yaw = 2.0 * Math.atan2(qx, qw);
-                roll = 0;
-            } else if (gimbaLockTest < -0.499) {
-                yaw = -2.0 * Math.atan2(qx, qw);
-                roll = 0;
+            //result is an EulerAngles in the in the z-x-z convention
+            var qx = this.x;
+            var qy = this.y;
+            var qz = this.z;
+            var qw = this.w;
+            var qxy = qx * qy;
+            var qxz = qx * qz;
+            var qwy = qw * qy;
+            var qwz = qw * qz;
+            var qwx = qw * qx;
+            var qyz = qy * qz;
+            var sqx = qx * qx;
+            var sqy = qy * qy;
+
+            var determinant = sqx + sqy;
+
+            if (determinant != 0.000 && determinant != 1.000) {
+                result.x = Math.atan2(qxz + qwy, qwx - qyz);
+                result.y = Math.acos(1 - 2 * determinant);
+                result.z = Math.atan2(qxz - qwy, qwx + qyz);
+            }
+            else
+            if (determinant == 0.000) {
+                result.x = 0.0;
+                result.y = 0.0;
+                result.z = Math.atan2(qxy - qwz, 0.5 - sqy - qz * qz); //actually, degeneracy gives us choice with x+z=Math.atan2(qxy-qwz,0.5-sqy-qz*qz)
+            }
+            else //determinant == 1.000
+            {
+                result.x = Math.atan2(qxy - qwz, 0.5 - sqy - qz * qz); //actually, degeneracy gives us choice with x-z=Math.atan2(qxy-qwz,0.5-sqy-qz*qz)
+                result.y = Math.PI;
+                result.z = 0.0;
             }
             }
-
-            result.x = pitch;
-            result.y = yaw;
-            result.z = roll;
         };
         };
 
 
         Quaternion.prototype.toRotationMatrix = function (result) {
         Quaternion.prototype.toRotationMatrix = function (result) {
@@ -1171,6 +1445,136 @@
     })();
     })();
     BABYLON.Quaternion = Quaternion;
     BABYLON.Quaternion = Quaternion;
 
 
+    var EulerAngles = (function () {
+        function EulerAngles(x, y, z) {
+            if (typeof x === "undefined") { x = 0; }
+            if (typeof y === "undefined") { y = 0; }
+            if (typeof z === "undefined") { z = 0; }
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        }
+        EulerAngles.prototype.toString = function () {
+            return "{x: " + this.x + " y:" + this.y + " z:" + this.z + "}";
+        };
+
+        EulerAngles.prototype.asArray = function () {
+            return [this.x, this.y, this.z];
+        };
+
+        EulerAngles.prototype.equals = function (otherEulerAngles) {
+            return otherEulerAngles && this.x === otherEulerAngles.x && this.y === otherEulerAngles.y && this.z === otherEulerAngles.z;
+        };
+
+        EulerAngles.prototype.clone = function () {
+            return new EulerAngles(this.x, this.y, this.z);
+        };
+
+        EulerAngles.prototype.copyFrom = function (other) {
+            this.x = other.x;
+            this.y = other.y;
+            this.z = other.z;
+        };
+
+        EulerAngles.prototype.copyFromFloats = function (x, y, z) {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        };
+
+        EulerAngles.prototype.add = function (other) {
+            return new EulerAngles(this.x + other.x, this.y + other.y, this.z + other.z);
+        };
+
+        EulerAngles.prototype.subtract = function (other) {
+            return new EulerAngles(this.x - other.x, this.y - other.y, this.z - other.z);
+        };
+
+        EulerAngles.prototype.scale = function (value) {
+            return new EulerAngles(this.x * value, this.y * value, this.z * value);
+        };
+
+        EulerAngles.prototype.length = function () {
+            return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
+        };
+
+        EulerAngles.prototype.normalize = function () {
+            var length = 1.0 / this.length();
+            this.x *= length;
+            this.y *= length;
+            this.z *= length;
+        };
+
+        EulerAngles.prototype.toQuaternion = function () {
+            var result;
+
+            //result is a Quaternion in the z-x-z rotation convention
+            var cosxPlusz = Math.cos((this.x + this.z) * 0.5);
+            var sinxPlusz = Math.sin((this.x + this.z) * 0.5);
+            var coszMinusx = Math.cos((this.z - this.x) * 0.5);
+            var sinzMinusx = Math.sin((this.z - this.x) * 0.5);
+            var cosy = Math.cos(this.y * 0.5);
+            var siny = Math.sin(this.y * 0.5);
+
+            result.x = coszMinusx * siny;
+            result.y = -sinzMinusx * siny;
+            result.z = sinxPlusz * cosy;
+            result.w = cosxPlusz * cosy;
+
+            return result;
+        };
+
+        EulerAngles.prototype.toRotationMatrix = function (result) {
+            //returns matrix with result.m[0]=m11,result.m[1]=m21,result.m[2]=m31,result.m[4]=12, etc
+            //done in the z-x-z rotation convention
+            var cosx = Math.cos(this.x);
+            var sinx = Math.sin(this.x);
+            var cosy = Math.cos(this.y);
+            var siny = Math.sin(this.y);
+            var cosz = Math.cos(this.z);
+            var sinz = Math.sin(this.z);
+
+            result.m[0] = cosx * cosz - cosy * sinx * sinz;
+            result.m[1] = cosy * sinx * cosz + cosx * sinz;
+            result.m[2] = siny * sinx;
+            result.m[4] = -sinx * cosz - cosy * cosx * sinz;
+            result.m[5] = cosy * cosx * cosz - sinx * sinz;
+            result.m[6] = siny * cosx;
+            result.m[8] = siny * sinz;
+            result.m[9] = -siny * cosz;
+            result.m[10] = cosy;
+
+        };
+
+        EulerAngles.prototype.fromRotationMatrix = function (matrix) {
+            var data = matrix.m;
+            var m11 = data[0], m12 = data[4], m13 = data[8];
+            var m21 = data[1], m22 = data[5], m23 = data[9];
+            var m31 = data[2], m32 = data[6], m33 = data[10];
+
+            if (m33 == -1) {
+                this.x = 0; //any angle works here
+                this.y = Math.PI;
+                this.z = Math.atan2(m21, m11); //generally, atan2(m21,m11)-x
+
+            }
+            else
+                if (m33 == 1) {
+                    this.x = 0; //any angle works here
+                    this.y = 0;
+                    this.z = Math.atan2(m21, m11); //generally, atan2(m21,m11)-x
+                }
+                else {
+                    this.x = Math.atan2(m31, m32);
+                    this.y = Math.acos(m33); //principal value (between 0 and PI)
+                    this.z = Math.atan2(m13, -m23);
+                }
+        };
+
+        return EulerAngles;
+    })();
+    BABYLON.EulerAngles = EulerAngles;
+
     var Matrix = (function () {
     var Matrix = (function () {
         function Matrix() {
         function Matrix() {
             this.m = new Float32Array(16);
             this.m = new Float32Array(16);

+ 435 - 24
Babylon/Math/babylon.math.ts

@@ -869,6 +869,288 @@
         }
         }
     }
     }
 
 
+    //Vector4 class created for EulerAngle class conversion to Quaternion
+    export class Vector4 {
+
+        constructor(public x: number, public y: number, public z: number, public w: number) { }
+
+        public toString(): string {
+            return "{X: " + this.x + " Y:" + this.y + " Z:" + this.z + "W:" + this.w + "}";
+        }
+
+        // Operators
+        public asArray(): number[] {
+            var result = [];
+
+            this.toArray(result, 0);
+
+            return result;
+        }
+
+        public toArray(array: number[], index?: number): void {
+            if (index === undefined) {
+                index = 0;
+            }
+
+            array[index] = this.x;
+            array[index + 1] = this.y;
+            array[index + 2] = this.z;
+            array[index + 3] = this.w;
+        }
+
+        public addInPlace(otherVector: Vector4): void {
+            this.x += otherVector.x;
+            this.y += otherVector.y;
+            this.z += otherVector.z;
+            this.w += otherVector.w;
+        }
+
+        public add(otherVector: Vector4): Vector4 {
+            return new Vector4(this.x + otherVector.x, this.y + otherVector.y, this.z + otherVector.z, this.w + otherVector.w);
+        }
+
+        public addToRef(otherVector: Vector4, result: Vector4): void {
+            result.x = this.x + otherVector.x;
+            result.y = this.y + otherVector.y;
+            result.z = this.z + otherVector.z;
+            result.w = this.w + otherVector.w;
+        }
+
+        public subtractInPlace(otherVector: Vector4): void {
+            this.x -= otherVector.x;
+            this.y -= otherVector.y;
+            this.z -= otherVector.z;
+            this.w -= otherVector.w;
+        }
+
+        public subtract(otherVector: Vector4): Vector4 {
+            return new Vector4(this.x - otherVector.x, this.y - otherVector.y, this.z - otherVector.z, this.w - otherVector.w);
+        }
+
+        public subtractToRef(otherVector: Vector4, result: Vector4): void {
+            result.x = this.x - otherVector.x;
+            result.y = this.y - otherVector.y;
+            result.z = this.z - otherVector.z;
+            result.w = this.w - otherVector.w;
+        }
+
+        public subtractFromFloats(x: number, y: number, z: number, w: number): Vector4 {
+            return new Vector4(this.x - x, this.y - y, this.z - z, this.w - w);
+        }
+
+        public subtractFromFloatsToRef(x: number, y: number, z: number, w: number, result: Vector4): void {
+            result.x = this.x - x;
+            result.y = this.y - y;
+            result.z = this.z - z;
+            result.w = this.w - w;
+        }
+
+        public negate(): Vector4 {
+            return new Vector4(-this.x, -this.y, -this.z, -this.w);
+        }
+
+        public scaleInPlace(scale: number): Vector4 {
+            this.x *= scale;
+            this.y *= scale;
+            this.z *= scale;
+            this.w *= scale;
+            return this;
+        }
+
+        public scale(scale: number): Vector4 {
+            return new Vector4(this.x * scale, this.y * scale, this.z * scale, this.w * scale);
+        }
+
+        public scaleToRef(scale: number, result: Vector4) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+        }
+
+        public equals(otherVector: Vector4): boolean {
+            return otherVector && this.x === otherVector.x && this.y === otherVector.y && this.z === otherVector.z && this.w === otherVector.w;
+        }
+
+        public equalsWithEpsilon(otherVector: Vector4): boolean {
+            return Math.abs(this.x - otherVector.x) < Engine.Epsilon &&
+                Math.abs(this.y - otherVector.y) < Engine.Epsilon &&
+                Math.abs(this.z - otherVector.z) < Engine.Epsilon &&
+                Math.abs(this.w - otherVector.w) < Engine.Epsilon;
+        }
+
+        public equalsToFloats(x: number, y: number, z: number, w: number): boolean {
+            return this.x === x && this.y === y && this.z === z && this.w === w;
+        }
+
+        public multiplyInPlace(otherVector: Vector4): void {
+            this.x *= otherVector.x;
+            this.y *= otherVector.y;
+            this.z *= otherVector.z;
+            this.w *= otherVector.w;
+        }
+
+        public multiply(otherVector: Vector4): Vector4 {
+            return new Vector4(this.x * otherVector.x, this.y * otherVector.y, this.z * otherVector.z, this.w * otherVector.w);
+        }
+
+        public multiplyToRef(otherVector: Vector4, result: Vector4): void {
+            result.x = this.x * otherVector.x;
+            result.y = this.y * otherVector.y;
+            result.z = this.z * otherVector.z;
+            result.w = this.w * otherVector.w;
+        }
+
+        public multiplyByFloats(x: number, y: number, z: number, w: number): Vector4 {
+            return new Vector4(this.x * x, this.y * y, this.z * z, this.w * w);
+        }
+
+        public divide(otherVector: Vector4): Vector4 {
+            return new Vector4(this.x / otherVector.x, this.y / otherVector.y, this.z / otherVector.z, this.w / otherVector.w);
+        }
+
+        public divideToRef(otherVector: Vector4, result: Vector4): void {
+            result.x = this.x / otherVector.x;
+            result.y = this.y / otherVector.y;
+            result.z = this.z / otherVector.z;
+            result.w = this.w / otherVector.w;
+        }
+
+        public MinimizeInPlace(other: Vector4): void {
+            if (other.x < this.x) this.x = other.x;
+            if (other.y < this.y) this.y = other.y;
+            if (other.z < this.z) this.z = other.z;
+            if (other.w < this.w) this.w = other.w;
+        }
+
+        public MaximizeInPlace(other: Vector4): void {
+            if (other.x > this.x) this.x = other.x;
+            if (other.y > this.y) this.y = other.y;
+            if (other.z > this.z) this.z = other.z;
+            if (other.w > this.w) this.w = other.w;
+        }
+
+        // Properties
+        public length(): number {
+            return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
+        }
+
+        public lengthSquared(): number {
+            return (this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
+        }
+
+        // Methods
+        public normalize(): Vector4 {
+            var len = this.length();
+
+            if (len === 0)
+                return this;
+
+            var num = 1.0 / len;
+
+            this.x *= num;
+            this.y *= num;
+            this.z *= num;
+            this.w *= num;
+
+            return this;
+        }
+
+        public clone(): Vector4 {
+            return new Vector4(this.x, this.y, this.z, this.w);
+        }
+
+        public copyFrom(source: Vector4): void {
+            this.x = source.x;
+            this.y = source.y;
+            this.z = source.z;
+            this.w = source.w;
+        }
+
+        public copyFromFloats(x: number, y: number, z: number, w: number): void {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+            this.w = w;
+        }
+
+        // Statics
+        public static FromArray(array: number[], offset?: number): Vector4 {
+            if (!offset) {
+                offset = 0;
+            }
+
+            return new Vector4(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
+        }
+
+        public static FromArrayToRef(array: number[], offset: number, result: Vector4): void {
+            result.x = array[offset];
+            result.y = array[offset + 1];
+            result.z = array[offset + 2];
+            result.w = array[offset + 3];
+        }
+
+        public static FromFloatArrayToRef(array: Float32Array, offset: number, result: Vector4): void {
+            result.x = array[offset];
+            result.y = array[offset + 1];
+            result.z = array[offset + 2];
+            result.w = array[offset + 3];
+        }
+
+        public static FromFloatsToRef(x: number, y: number, z: number, w: number, result: Vector4): void {
+            result.x = x;
+            result.y = y;
+            result.z = z;
+            result.w = w;
+        }
+
+        public static Zero(): Vector4 {
+            return new Vector4(0, 0, 0, 0);
+        }
+
+        public static Normalize(vector: Vector4): Vector4 {
+            var result = Vector4.Zero();
+            Vector4.NormalizeToRef(vector, result);
+            return result;
+        }
+
+        public static NormalizeToRef(vector: Vector4, result: Vector4): void {
+            result.copyFrom(vector);
+            result.normalize();
+        }
+
+        public static Minimize(left: Vector4, right: Vector4): Vector4 {
+            var min = left.clone();
+            min.MinimizeInPlace(right);
+            return min;
+        }
+
+        public static Maximize(left: Vector4, right: Vector4): Vector4 {
+            var max = left.clone();
+            max.MaximizeInPlace(right);
+            return max;
+        }
+
+        public static Distance(value1: Vector4, value2: Vector4): number {
+            return Math.sqrt(Vector4.DistanceSquared(value1, value2));
+        }
+
+        public static DistanceSquared(value1: Vector4, value2: Vector4): number {
+            var x = value1.x - value2.x;
+            var y = value1.y - value2.y;
+            var z = value1.z - value2.z;
+            var w = value1.w - value2.w;
+
+            return (x * x) + (y * y) + (z * z) + (w * w);
+        }
+
+        public static Center(value1: Vector4, value2: Vector4): Vector4 {
+            var center = value1.add(value2);
+            center.scaleInPlace(0.5);
+            return center;
+        }
+    }
+
     export class Quaternion {
     export class Quaternion {
         constructor(public x: number = 0, public y: number = 0, public z: number = 0, public w: number = 1) {
         constructor(public x: number = 0, public y: number = 0, public z: number = 0, public w: number = 1) {
 
 
@@ -952,31 +1234,39 @@
         }
         }
 
 
         public toEulerAnglesToRef(result: Vector3): void {
         public toEulerAnglesToRef(result: Vector3): void {
-            var qx = this.x;
-            var qy = this.y;
-            var qz = this.z;
-            var qw = this.w;
-
-            var sqx = qx * qx;
-            var sqy = qy * qy;
-            var sqz = qz * qz;
-
-            var yaw = Math.atan2(2.0 * (qy * qw - qx * qz), 1.0 - 2.0 * (sqy + sqz));
-            var pitch = Math.asin(2.0 * (qx * qy + qz * qw));
-            var roll = Math.atan2(2.0 * (qx * qw - qy * qz), 1.0 - 2.0 * (sqx + sqz));
-
-            var gimbaLockTest = qx * qy + qz * qw;
-            if (gimbaLockTest > 0.499) {
-                yaw = 2.0 * Math.atan2(qx, qw);
-                roll = 0;
-            } else if (gimbaLockTest < -0.499) {
-                yaw = -2.0 * Math.atan2(qx, qw);
-                roll = 0;
+            //result is an EulerAngles in the in the z-x-z convention
+            var qx = this.x;
+            var qy = this.y;
+            var qz = this.z;
+            var qw = this.w;
+            var qxy = qx * qy;
+            var qxz = qx * qz;
+            var qwy = qw * qy;
+            var qwz = qw * qz;
+            var qwx = qw * qx;
+            var qyz = qy * qz;
+            var sqx = qx * qx;
+            var sqy = qy * qy;
+
+            var determinant = sqx + sqy;
+
+            if (determinant != 0.000 && determinant != 1.000) {
+                result.x = Math.atan2(qxz + qwy, qwx - qyz);
+                result.y = Math.acos(1 - 2 * determinant);
+                result.z = Math.atan2(qxz - qwy, qwx + qyz);
+            }
+            else
+            if (determinant == 0.000) {
+                result.x = 0.0;
+                result.y = 0.0;
+                result.z = Math.atan2(qxy - qwz, 0.5 - sqy - qz * qz); //actually, degeneracy gives us choice with x+z=Math.atan2(qxy-qwz,0.5-sqy-qz*qz)
+            }
+            else //determinant == 1.000
+            {
+                result.x = Math.atan2(qxy - qwz, 0.5 - sqy - qz * qz); //actually, degeneracy gives us choice with x-z=Math.atan2(qxy-qwz,0.5-sqy-qz*qz)
+                result.y = Math.PI;
+                result.z = 0.0;
             }
             }
-
-            result.x = pitch;
-            result.y = yaw;
-            result.z = roll;
         }
         }
 
 
         public toRotationMatrix(result: Matrix): void {
         public toRotationMatrix(result: Matrix): void {
@@ -1138,6 +1428,127 @@
         }
         }
     }
     }
 
 
+    export class EulerAngles {
+        constructor(public x: number = 0, public y: number = 0, public z: number = 0) { }
+
+        public toString(): string {
+            return "{x: " + this.x + " y:" + this.y + " z:" + this.z + "}";
+        }
+
+        public asArray(): number[] {
+            return [this.x, this.y, this.z];
+        }
+
+        public equals(otherEulerAngles: EulerAngles): boolean {
+            return otherEulerAngles && this.x === otherEulerAngles.x && this.y === otherEulerAngles.y && this.z === otherEulerAngles.z;
+        }
+
+        public clone(): EulerAngles {
+            return new EulerAngles(this.x, this.y, this.z);
+        }
+
+        public copyFrom(other: EulerAngles): void {
+            this.x = other.x;
+            this.y = other.y;
+            this.z = other.z;
+        }
+
+        public copyFromFloats(x: number, y: number, z: number): void {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        }
+
+        public add(other: EulerAngles): EulerAngles {
+            return new EulerAngles(this.x + other.x, this.y + other.y, this.z + other.z);
+        }
+
+        public subtract(other: EulerAngles): EulerAngles {
+            return new EulerAngles(this.x - other.x, this.y - other.y, this.z - other.z);
+        }
+
+        public scale(value: number): EulerAngles {
+            return new EulerAngles(this.x * value, this.y * value, this.z * value);
+        }
+
+        public length(): number {
+            return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
+        }
+
+        public normalize(): void {
+            var length = 1.0 / this.length();
+            this.x *= length;
+            this.y *= length;
+            this.z *= length;
+        }
+
+        public toQuaternion(): Vector4 {
+            var result;
+
+            //result is a Quaternion in the z-x-z rotation convention
+            var cosxPlusz = Math.cos((this.x + this.z) * 0.5);
+            var sinxPlusz = Math.sin((this.x + this.z) * 0.5);
+            var coszMinusx = Math.cos((this.z - this.x) * 0.5);
+            var sinzMinusx = Math.sin((this.z - this.x) * 0.5);
+            var cosy = Math.cos(this.y * 0.5);
+            var siny = Math.sin(this.y * 0.5);
+
+            result.x = coszMinusx * siny;
+            result.y = -sinzMinusx * siny; 
+            result.z = sinxPlusz * cosy;
+            result.w = cosxPlusz * cosy;
+
+            return result;
+
+        }
+
+        public toRotationMatrix(result: Matrix): void {
+            //returns matrix with result.m[0]=m11,result.m[1]=m21,result.m[2]=m31,result.m[4]=12, etc
+            //done in the z-x-z rotation convention
+            var cosx = Math.cos(this.x);
+            var sinx = Math.sin(this.x);
+            var cosy = Math.cos(this.y);
+            var siny = Math.sin(this.y);
+            var cosz = Math.cos(this.z);
+            var sinz = Math.sin(this.z);
+
+            result.m[0] = cosx * cosz - cosy * sinx * sinz;
+            result.m[1] = cosy * sinx * cosz + cosx * sinz;
+            result.m[2] = siny * sinx;
+            result.m[4] = -sinx * cosz - cosy * cosx * sinz;
+            result.m[5] = cosy * cosx * cosz - sinx * sinz;
+            result.m[6] = siny * cosx;
+            result.m[8] = siny * sinz;
+            result.m[9] = -siny * cosz;
+            result.m[10] = cosy;
+        }
+
+        public fromRotationMatrix(matrix: Matrix): void {
+            var data = matrix.m;
+            var m11 = data[0], m12 = data[4], m13 = data[8];
+            var m21 = data[1], m22 = data[5], m23 = data[9];
+            var m31 = data[2], m32 = data[6], m33 = data[10];
+
+            if (m33 == -1) {
+                this.x = 0; //any angle works here
+                this.y = Math.PI;
+                this.z = Math.atan2(m21, m11); //generally, atan2(m21,m11)-x
+
+            }
+            else
+            if (m33 == 1) {
+                this.x = 0; //any angle works here
+                this.y = 0;
+                this.z = Math.atan2(m21, m11); //generally, atan2(m21,m11)-x
+            }
+            else {
+                this.x = Math.atan2(m31, m32);
+                this.y = Math.acos(m33); //principal value (between 0 and PI)
+                this.z = Math.atan2(m13, -m23);
+            }
+        }
+    }
+
     export class Matrix {
     export class Matrix {
         private static _tempQuaternion: Quaternion = new Quaternion();
         private static _tempQuaternion: Quaternion = new Quaternion();
         private static _xAxis: Vector3 = Vector3.Zero();
         private static _xAxis: Vector3 = Vector3.Zero();

+ 445 - 24
babylon.2.0-alpha.debug.js

@@ -898,6 +898,272 @@ var BABYLON;
     })();
     })();
     BABYLON.Vector3 = Vector3;
     BABYLON.Vector3 = Vector3;
 
 
+    var Vector4 = (function () {
+        function Vector4(x, y, z, w) {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+            this.w = w;
+        }
+
+        Vector4.prototype.toString = function ()
+        { return "{X: " + this.x + " Y:" + this.y + " Z:" + this.z + "W:" + this.w + "}"; };
+
+        Vector4.prototype.asArray = function () {
+            var result = [];
+
+            this.toArray(result, 0);
+
+            return result;
+        };
+
+        Vector4.prototype.toArray = function (array, index) {
+            if (index === undefined) {
+                index = 0;
+            }
+
+            array[index] = this.x;
+            array[index + 1] = this.y;
+            array[index + 2] = this.z;
+            array[index + 3] = this.w;
+        };
+
+        Vector4.prototype.addInPlace = function (otherVector) {
+            this.x += otherVector.x;
+            this.y += otherVector.y;
+            this.z += otherVector.z;
+            this.w += otherVector.w;
+        };
+
+        Vector4.prototype.add = function (otherVector) {
+            return new Vector4(this.x + otherVector.x, this.y + otherVector.y, this.z + otherVector.z, this.w + otherVector.w);
+        };
+
+        Vector4.prototype.addToRef = function (otherVector, result) {
+            result.x = this.x + otherVector.x;
+            result.y = this.y + otherVector.y;
+            result.z = this.z + otherVector.z;
+            result.w = this.w + otherVector.w;
+        };
+
+        Vector4.prototype.subtractInPlace = function (otherVector) {
+            this.x -= otherVector.x;
+            this.y -= otherVector.y;
+            this.z -= otherVector.z;
+            this.w -= otherVector.w;
+        };
+
+        Vector4.prototype.subtract = function (otherVector)
+        { return new Vector4(this.x - otherVector.x, this.y - otherVector.y, this.z - otherVector.z, this.w - otherVector.w); };
+
+        Vector4.prototype.subtractToRef = function (otherVector, result) {
+            result.x = this.x - otherVector.x;
+            result.y = this.y - otherVector.y;
+            result.z = this.z - otherVector.z;
+            result.w = this.w - otherVector.w;
+        };
+
+        Vector4.prototype.subtractFromFloats = function (x, y, z, w)
+        { return new Vector4(this.x - x, this.y - y, this.z - z, this.w - w); };
+
+        Vector4.prototype.subtractFromFloatsToRef = function (x, y, z, w, result) {
+            result.x = this.x - x;
+            result.y = this.y - y;
+            result.z = this.z - z;
+            result.w = this.w - w;
+        };
+
+        Vector4.prototype.negate = function ()
+        { return new Vector4(-this.x, -this.y, -this.z, -this.w); };
+
+        Vector4.prototype.scaleInPlace = function (scale) {
+            this.x *= scale;
+            this.y *= scale;
+            this.z *= scale;
+            this.w *= scale;
+            return this;
+        };
+
+        Vector4.prototype.scale = function (scale)
+        { return new Vector4(this.x * scale, this.y * scale, this.z * scale, this.w * scale); };
+
+        Vector4.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+        };
+
+        Vector4.prototype.equals = function (otherVector)
+        { return otherVector && this.x === otherVector.x && this.y === otherVector.y && this.z === otherVector.z && this.w === otherVector.w; };
+
+        Vector4.prototype.equalsWithEpsilon = function (otherVector) {
+            return Math.abs(this.x - otherVector.x) < Engine.Epsilon &&
+                Math.abs(this.y - otherVector.y) < Engine.Epsilon &&
+                Math.abs(this.z - otherVector.z) < Engine.Epsilon &&
+                Math.abs(this.w - otherVector.w) < Engine.Epsilon;
+        };
+
+        Vector4.prototype.equalsToFloats = function (x, y, z, w)
+        { return this.x === x && this.y === y && this.z === z && this.w === w; };
+
+        Vector4.prototype.multiplyInPlace = function (otherVector) {
+            this.x *= otherVector.x;
+            this.y *= otherVector.y;
+            this.z *= otherVector.z;
+            this.w *= otherVector.w;
+        };
+
+        Vector4.prototype.multiply = function (otherVector)
+        { return new Vector4(this.x * otherVector.x, this.y * otherVector.y, this.z * otherVector.z, this.w * otherVector.w); };
+
+        Vector4.prototype.multiplyToRef = function (otherVector, result) {
+            result.x = this.x * otherVector.x;
+            result.y = this.y * otherVector.y;
+            result.z = this.z * otherVector.z;
+            result.w = this.w * otherVector.w;
+        };
+
+        Vector4.prototype.multiplyByFloats = function (x, y, z, w)
+        { return new Vector4(this.x * x, this.y * y, this.z * z, this.w * w); };
+
+        Vector4.prototype.divide = function (otherVector)
+        { return new Vector4(this.x / otherVector.x, this.y / otherVector.y, this.z / otherVector.z, this.w / otherVector.w); };
+
+        Vector4.prototype.divideToRef = function (otherVector, result) {
+            result.x = this.x / otherVector.x;
+            result.y = this.y / otherVector.y;
+            result.z = this.z / otherVector.z;
+            result.w = this.w / otherVector.w;
+        };
+
+        Vector4.prototype.minimizeInPlace = function (other) {
+            if (other.x < this.x) this.x = other.x;
+            if (other.y < this.y) this.y = other.y;
+            if (other.z < this.z) this.z = other.z;
+            if (other.w < this.w) this.w = other.w;
+        };
+
+        Vector4.prototype.MaximizeInPlace = function (other) {
+            if (other.x > this.x) this.x = other.x;
+            if (other.y > this.y) this.y = other.y;
+            if (other.z > this.z) this.z = other.z;
+            if (other.w > this.w) this.w = other.w;
+        };
+
+        Vector4.prototype.length = function ()
+        { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); };
+
+        Vector4.prototype.lengthSquared = function ()
+        { return (this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); };
+
+        Vector4.prototype.normalize = function () {
+            var len = this.length();
+
+            if (len === 0)
+                return this;
+
+            var num = 1.0 / len;
+
+            this.x *= num;
+            this.y *= num;
+            this.z *= num;
+            this.w *= num;
+
+            return this;
+        };
+
+        Vector4.prototype.clone = function ()
+        { return new Vector4(this.x, this.y, this.z, this.w); };
+
+        Vector4.prototype.copyFrom = function (source) {
+            this.x = source.x;
+            this.y = source.y;
+            this.z = source.z;
+            this.w = source.w;
+        };
+
+        Vector4.prototype.copyFromFloats = function (x, y, z, w) {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+            this.w = w;
+        };
+
+        Vector4.FromArray = function (array, offset) {
+            if (!offset) { offset = 0; }
+
+            return new Vector4(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
+        };
+
+        Vector4.FromArrayToRef = function (array, offset, result) {
+            result.x = array[offset];
+            result.y = array[offset + 1];
+            result.z = array[offset + 2];
+            result.w = array[offset + 3];
+        };
+
+        Vector4.FromFloatArrayToRef = function (array, offset, result) {
+            result.x = array[offset];
+            result.y = array[offset + 1];
+            result.z = array[offset + 2];
+            result.w = array[offset + 3];
+        };
+
+        Vector4.FromFloatsToRef = function (x, y, z, w, result) {
+            result.x = x;
+            result.y = y;
+            result.z = z;
+            result.w = w;
+        };
+
+        Vector4.Zero = function () { return new Vector4(0, 0, 0, 0); };
+
+        Vector4.Normalize = function (vector) {
+            var result = Vector4.Zero();
+            Vector4.NormalizeToRef(vector, result);
+            return result;
+        };
+
+        Vector4.NormalizeToRef = function (vector, result) {
+            result.copyFrom(vector);
+            result.normalize();
+        };
+
+        Vector4.Minimize = function (left, right) {
+            var min = left.clone();
+            min.MinimizeInPlace(right);
+            return min;
+        };
+
+        Vector4.Maximize = function (left, right) {
+            var max = left.clone();
+            max.MaximizeInPlace(right);
+            return max;
+        };
+
+        Vector4.Distance = function (value1, value2) { return Math.sqrt(Vector4.DistanceSquared(value1, value2)); };
+
+        Vector4.DistanceSquared = function (value1, value2) {
+            var x = value1.x - value2.x;
+            var y = value1.y - value2.y;
+            var z = value1.z - value2.z;
+            var w = value1.w - value2.w;
+
+            return (x * x) + (y * y) + (z * z) + (w * w);
+        };
+
+        Vector4.Center = function (value1, value2) {
+            var center = value1.add(value2);
+            center.scaleInPlace(0.5);
+            return center;
+        };
+
+        return Vector4;
+
+    })();
+    BABYLON.Vector4 = Vector4;
+
     var Quaternion = (function () {
     var Quaternion = (function () {
         function Quaternion(x, y, z, w) {
         function Quaternion(x, y, z, w) {
             if (typeof x === "undefined") { x = 0; }
             if (typeof x === "undefined") { x = 0; }
@@ -987,31 +1253,39 @@ var BABYLON;
         };
         };
 
 
         Quaternion.prototype.toEulerAnglesToRef = function (result) {
         Quaternion.prototype.toEulerAnglesToRef = function (result) {
-            var qx = this.x;
-            var qy = this.y;
-            var qz = this.z;
-            var qw = this.w;
-
-            var sqx = qx * qx;
-            var sqy = qy * qy;
-            var sqz = qz * qz;
-
-            var yaw = Math.atan2(2.0 * (qy * qw - qx * qz), 1.0 - 2.0 * (sqy + sqz));
-            var pitch = Math.asin(2.0 * (qx * qy + qz * qw));
-            var roll = Math.atan2(2.0 * (qx * qw - qy * qz), 1.0 - 2.0 * (sqx + sqz));
-
-            var gimbaLockTest = qx * qy + qz * qw;
-            if (gimbaLockTest > 0.499) {
-                yaw = 2.0 * Math.atan2(qx, qw);
-                roll = 0;
-            } else if (gimbaLockTest < -0.499) {
-                yaw = -2.0 * Math.atan2(qx, qw);
-                roll = 0;
+            //result is an EulerAngles in the in the z-x-z convention
+            var qx = this.x;
+            var qy = this.y;
+            var qz = this.z;
+            var qw = this.w;
+            var qxy = qx * qy;
+            var qxz = qx * qz;
+            var qwy = qw * qy;
+            var qwz = qw * qz;
+            var qwx = qw * qx;
+            var qyz = qy * qz;
+            var sqx = qx * qx;
+            var sqy = qy * qy;
+
+            var determinant = sqx + sqy;
+
+            if (determinant != 0.000 && determinant != 1.000) {
+                result.x = Math.atan2(qxz + qwy, qwx - qyz);
+                result.y = Math.acos(1 - 2 * determinant);
+                result.z = Math.atan2(qxz - qwy, qwx + qyz);
+            }
+            else
+            if (determinant == 0.000) {
+                result.x = 0.0;
+                result.y = 0.0;
+                result.z = Math.atan2(qxy - qwz, 0.5 - sqy - qz * qz); //actually, degeneracy gives us choice with x+z=Math.atan2(qxy-qwz,0.5-sqy-qz*qz)
+            }
+            else //determinant == 1.000
+            {
+                result.x = Math.atan2(qxy - qwz, 0.5 - sqy - qz * qz); //actually, degeneracy gives us choice with x-z=Math.atan2(qxy-qwz,0.5-sqy-qz*qz)
+                result.y = Math.PI;
+                result.z = 0.0;
             }
             }
-
-            result.x = pitch;
-            result.y = yaw;
-            result.z = roll;
         };
         };
 
 
         Quaternion.prototype.toRotationMatrix = function (result) {
         Quaternion.prototype.toRotationMatrix = function (result) {
@@ -1171,6 +1445,153 @@ var BABYLON;
     })();
     })();
     BABYLON.Quaternion = Quaternion;
     BABYLON.Quaternion = Quaternion;
 
 
+    var EulerAngles = (function () {
+        function EulerAngles(x, y, z) {
+            if (typeof x === "undefined") { x = 0; }
+            if (typeof y === "undefined") { y = 0; }
+            if (typeof z === "undefined") { z = 0; }
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        }
+        EulerAngles.prototype.toString = function () {
+            return "{x: " + this.x + " y:" + this.y + " z:" + this.z + "}";
+        };
+
+        EulerAngles.prototype.asArray = function () {
+            return [this.x, this.y, this.z];
+        };
+
+        EulerAngles.prototype.equals = function (otherEulerAngles) {
+            return otherEulerAngles && this.x === otherEulerAngles.x && this.y === otherEulerAngles.y && this.z === otherEulerAngles.z;
+        };
+
+        EulerAngles.prototype.clone = function () {
+            return new EulerAngles(this.x, this.y, this.z);
+        };
+
+        EulerAngles.prototype.copyFrom = function (other) {
+            this.x = other.x;
+            this.y = other.y;
+            this.z = other.z;
+        };
+
+        EulerAngles.prototype.copyFromFloats = function (x, y, z) {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        };
+
+        EulerAngles.prototype.add = function (other) {
+            return new EulerAngles(this.x + other.x, this.y + other.y, this.z + other.z);
+        };
+
+        EulerAngles.prototype.subtract = function (other) {
+            return new EulerAngles(this.x - other.x, this.y - other.y, this.z - other.z);
+        };
+
+        EulerAngles.prototype.scale = function (value) {
+            return new EulerAngles(this.x * value, this.y * value, this.z * value);
+        };
+
+        EulerAngles.prototype.multiply = function (ea) {
+            var result = new EulerAngles(0, 0, 0);
+
+            this.multiplyToRef(ea, result);
+
+            return result;
+        };
+
+        EulerAngles.prototype.length = function () {
+            return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
+        };
+
+        EulerAngles.prototype.normalize = function () {
+            var length = 1.0 / this.length();
+            this.x *= length;
+            this.y *= length;
+            this.z *= length;
+        };
+
+        EulerAngles.prototype.toQuaternion = function () {
+            var result;
+
+            //result is a Quaternion in the z-x-z rotation convention
+            var cosxPlusz = Math.cos((this.x + this.z) * 0.5);
+            var sinxPlusz = Math.sin((this.x + this.z) * 0.5);
+            var coszMinusx = Math.cos((this.z - this.x) * 0.5);
+            var sinzMinusx = Math.sin((this.z - this.x) * 0.5);
+            var cosy = Math.cos(this.y * 0.5);
+            var siny = Math.sin(this.y * 0.5);
+
+            result.x = coszMinusx * siny;
+            result.y = -sinzMinusx * siny;
+            result.z = sinxPlusz * cosy;
+            result.w = cosxPlusz * cosy;
+
+            return result;
+        };
+
+        EulerAngles.prototype.toRotationMatrix = function (result) {
+            //returns matrix with result.m[0]=m11,result.m[1]=m21,result.m[2]=m31,result.m[4]=12, etc
+            //done in the z-x-z rotation convention
+            var cosx = Math.cos(this.x);
+            var sinx = Math.sin(this.x);
+            var cosy = Math.cos(this.y);
+            var siny = Math.sin(this.y);
+            var cosz = Math.cos(this.z);
+            var sinz = Math.sin(this.z);
+
+            result.m[0] = cosx * cosz - cosy * sinx * sinz;
+            result.m[1] = cosy * sinx * cosz + cosx * sinz;
+            result.m[2] = siny * sinx;
+            result.m[4] = -sinx * cosz - cosy * cosx * sinz;
+            result.m[5] = cosy * cosx * cosz - sinx * sinz;
+            result.m[6] = siny * cosx;
+            result.m[8] = siny * sinz;
+            result.m[9] = -siny * cosz;
+            result.m[10] = cosy;
+
+        };
+
+        EulerAngles.prototype.fromRotationMatrix = function (matrix) {
+            var data = matrix.m;
+            var m11 = data[0], m12 = data[4], m13 = data[8];
+            var m21 = data[1], m22 = data[5], m23 = data[9];
+            var m31 = data[2], m32 = data[6], m33 = data[10];
+
+            if (m33 == -1) {
+                this.x = 0; //any angle works here
+                this.y = Math.PI;
+                this.z = Math.atan2(m21, m11); //generally, atan2(m21,m11)-x
+
+            }
+            else
+            if (m33 == 1) {
+                this.x = 0; //any angle works here
+                this.y = 0;
+                this.z = Math.atan2(m21, m11); //generally, atan2(m21,m11)-x
+            }
+            else {
+                this.x = Math.atan2(m31, m32);
+                this.y = Math.acos(m33); //principal value (between 0 and PI)
+                this.z = Math.atan2(m13, -m23);
+            }
+
+        };
+
+        EulerAngles.FromArray = function (array, offset) {
+            if (!offset) {
+                offset = 0;
+            }
+
+            return new EulerAngles(array[offset], array[offset + 1], array[offset + 2]);
+        };
+
+        return EulerAngles;
+    })();
+    BABYLON.EulerAngles = EulerAngles;
+
     var Matrix = (function () {
     var Matrix = (function () {
         function Matrix() {
         function Matrix() {
             this.m = new Float32Array(16);
             this.m = new Float32Array(16);

+ 75 - 0
babylon.2.0.d.ts

@@ -2139,6 +2139,59 @@ declare module BABYLON {
         static DistanceSquared(value1: Vector3, value2: Vector3): number;
         static DistanceSquared(value1: Vector3, value2: Vector3): number;
         static Center(value1: Vector3, value2: Vector3): Vector3;
         static Center(value1: Vector3, value2: Vector3): Vector3;
     }
     }
+
+    class Vector4 {
+        public x: number;
+        public y: number;
+        public z: number;
+        public w: number;
+        constructor(x: number, y: number, z: number, w: number);
+        public toString(): string;
+        public asArray(): number[];
+        public toArray(array: number[], index?: number): void;
+        public addInPlace(otherVector: Vector4): void;
+        public add(otherVector: Vector4): Vector4;
+        public addToRef(otherVector: Vector4, result: Vector4): void;
+        public subtractInPlace(otherVector: Vector4): void;
+        public subtract(otherVector: Vector4): Vector4;
+        public subtractToRef(otherVector: Vector4, result: Vector4): void;
+        public subtractFromFloats(x: number, y: number, z: number, w: number): Vector4;
+        public subtractFromFloatsToRef(x: number, y: number, z: number, w: number, result: Vector4): void;
+        public negate(): Vector4;
+        public scaleInPlace(scale: number): Vector4;
+        public scale(scale: number): Vector4;
+        public scaleToRef(scale: number, result: Vector4);
+        public equals(otherVector: Vector4): boolean;
+        public equalsWithEpsilon(otherVector: Vector4): boolean;
+        public equalsToFloats(x: number, y: number, z: number, w: number): boolean;
+        public multiplyInPlace(otherVector: Vector4): void;
+        public multiply(otherVector: Vector4): Vector4;
+        public multiplyToRef(otherVector: Vector4, result: Vector4): void
+        public multiplyByFloats(x: number, y: number, z: number, w: number): Vector4;
+        public divide(otherVector: Vector4): Vector4;
+        public divideToRef(otherVector: Vector4, result: Vector4): void;
+        public MinimizeInPlace(other: Vector4): void;
+        public MaximizeInPlace(other: Vector4): void;
+        public length(): number;
+        public lengthSquared(): number;
+        public normalize(): Vector4;
+        public clone(): Vector4;
+        public copyFrom(source: Vector4): void;
+        public copyFromFloats(x: number, y: number, z: number, w: number): void;
+        static FromArray(array: number[], offset?: number): Vector4;
+        static FromArrayToRef(array: number[], offset: number, result: Vector4): void;
+        static FromFloatArrayToRef(array: Float32Array, offset: number, result: Vector4): void;
+        static FromFloatsToRef(x: number, y: number, z: number, w: number, result: Vector4): void;
+        static Zero(): Vector4;
+        static Normalize(vector: Vector4): Vector4;
+        static NormalizeToRef(vector: Vector4, result: Vector4): void;
+        static Minimize(left: Vector4, right: Vector4): Vector4;
+        static Maximize(left: Vector4, right: Vector4): Vector4;
+        static Distance(value1: Vector4, value2: Vector4): number;
+        static DistanceSquared(value1: Vector4, value2: Vector4): number;
+        static Center(value1: Vector4, value2: Vector4): Vector4;
+    }
+
     class Quaternion {
     class Quaternion {
         public x: number;
         public x: number;
         public y: number;
         public y: number;
@@ -2169,6 +2222,28 @@ declare module BABYLON {
         static RotationYawPitchRollToRef(yaw: number, pitch: number, roll: number, result: Quaternion): void;
         static RotationYawPitchRollToRef(yaw: number, pitch: number, roll: number, result: Quaternion): void;
         static Slerp(left: Quaternion, right: Quaternion, amount: number): Quaternion;
         static Slerp(left: Quaternion, right: Quaternion, amount: number): Quaternion;
     }
     }
+
+    class EulerAngles {
+        public x: number;
+        public y: number;
+        public z: number;
+        constructor(x?: number, y?: number, z?: number);
+        public toString(): string;
+        public asArray(): number[];
+        public equals(otherEulerAngles: EulerAngles): boolean;
+        public clone(): EulerAngles;
+        public copyFrom(other: EulerAngles): void;
+        public copyFromFloats(x: number, y: number, z: number): void;
+        public add(other: EulerAngles): EulerAngles;
+        public subtract(other: EulerAngles): EulerAngles;
+        public scale(value: number): EulerAngles;
+        public length(): number;
+        public normalize(): void;
+        public toQuaternion(): Vector4;
+        public toRotationMatrix(result: Matrix): void;
+        public fromRotationMatrix(matrix: Matrix): void;
+    }
+
     class Matrix {
     class Matrix {
         private static _tempQuaternion;
         private static _tempQuaternion;
         private static _xAxis;
         private static _xAxis;