浏览代码

Canvas2D: switch to Matrix2D

Now computations are using the Matrix2D class, which is a 2x3 matrix (last column is considered to be [0,0,1]).
The overall computation is much much faster!
nockawa 8 年之前
父节点
当前提交
2e5919b296

+ 6 - 6
canvas2D/src/Engine/babylon.bounding2d.ts

@@ -236,7 +236,7 @@
          * @param matrix the transformation matrix to apply
          * @return the new instance containing the result of the transformation applied on this BoundingInfo2D
          */
-        public transform(matrix: Matrix): BoundingInfo2D {
+        public transform(matrix: Matrix2D): BoundingInfo2D {
             var r = new BoundingInfo2D();
             this.transformToRef(matrix, r);
             return r;
@@ -268,7 +268,7 @@
          * @param matrix The matrix to use to compute the transformation
          * @param result A VALID (i.e. allocated) BoundingInfo2D object where the result will be stored
          */
-        public transformToRef(matrix: Matrix, result: BoundingInfo2D) {
+        public transformToRef(matrix: Matrix2D, result: BoundingInfo2D) {
             // Construct a bounding box based on the extent values
             let p = BoundingInfo2D._transform;
             p[0].x = this.center.x + this.extent.x;
@@ -282,12 +282,12 @@
 
             // Transform the four points of the bounding box with the matrix
             for (let i = 0; i < 4; i++) {
-                Vector2.TransformToRef(p[i], matrix, p[i]);
+                matrix.transformPointToRef(p[i], p[i]);
             }
             BoundingInfo2D.CreateFromPointsToRef(p, result);
         }
 
-        private _updateWorldAABB(worldMatrix: Matrix) {
+        private _updateWorldAABB(worldMatrix: Matrix2D) {
             // Construct a bounding box based on the extent values
             let p = BoundingInfo2D._transform;
             p[0].x = this.center.x + this.extent.x;
@@ -301,7 +301,7 @@
 
             // Transform the four points of the bounding box with the matrix
             for (let i = 0; i < 4; i++) {
-                Vector2.TransformToRef(p[i], worldMatrix, p[i]);
+                worldMatrix.transformPointToRef(p[i], p[i]);
             }
 
             this._worldAABB.x = Math.min(Math.min(p[0].x, p[1].x), Math.min(p[2].x, p[3].x));
@@ -310,7 +310,7 @@
             this._worldAABB.w = Math.max(Math.max(p[0].y, p[1].y), Math.max(p[2].y, p[3].y));
         }
 
-        public worldMatrixAccess: () => Matrix;
+        public worldMatrixAccess: () => Matrix2D;
 
         public get worldAABBDirtyObservable(): Observable<BoundingInfo2D> {
             if (!this._worldAABBDirtyObservable) {

+ 1 - 1
canvas2D/src/Engine/babylon.canvas2d.ts

@@ -533,7 +533,7 @@
             // Update the relatedTarget info with the over primitive or the captured one (if any)
             let targetPrim = capturedPrim || this._actualOverPrimitive.prim;
 
-            let targetPointerPos = capturedPrim ? this._primPointerInfo.canvasPointerPos.subtract(new Vector2(targetPrim.globalTransform.m[12], targetPrim.globalTransform.m[13])) : this._actualOverPrimitive.intersectionLocation;
+            let targetPointerPos = capturedPrim ? this._primPointerInfo.canvasPointerPos.subtract(new Vector2(targetPrim.globalTransform.m[4], targetPrim.globalTransform.m[5])) : this._actualOverPrimitive.intersectionLocation;
 
             this._primPointerInfo.updateRelatedTarget(targetPrim, targetPointerPos);
 

+ 1 - 1
canvas2D/src/Engine/babylon.modelRenderCache.ts

@@ -1,6 +1,6 @@
 module BABYLON {
     export const enum ShaderDataType {
-        Vector2, Vector3, Vector4, Matrix, float, Color3, Color4, Size
+        Vector2, Vector3, Vector4, float, Color3, Color4, Size
     }
 
     export class GroupInstanceInfo {

+ 64 - 79
canvas2D/src/Engine/babylon.prim2dBase.ts

@@ -1544,8 +1544,8 @@
             this._marginAlignment            = null;
             this._id                         = settings.id;
             this._children                   = new Array<Prim2DBase>();
-            this._localTransform             = new Matrix();
-            this._localLayoutTransform       = new Matrix();
+            this._localTransform             = new Matrix2D();
+            this._localLayoutTransform       = new Matrix2D();
             this._globalTransform            = null;
             this._invGlobalTransform         = null;
             this._globalTransformProcessStep = 0;
@@ -2791,7 +2791,7 @@
         /**
          * Get the global transformation matrix of the primitive
          */
-        public get globalTransform(): Matrix {
+        public get globalTransform(): Matrix2D {
             if (!this._globalTransform || (this._globalTransformProcessStep !== this.owner._globalTransformProcessStep)) {
                 this.updateCachedStates(false);
             }
@@ -2812,14 +2812,14 @@
          * @param v the valid Vector2 object where the global position will be stored
          */
         public getGlobalPositionByRef(v: Vector2) {
-            v.x = this.globalTransform.m[12];
-            v.y = this.globalTransform.m[13];
+            v.x = this.globalTransform.m[4];
+            v.y = this.globalTransform.m[5];
         }
 
         /**
          * Get invert of the global transformation matrix of the primitive
          */
-        public get invGlobalTransform(): Matrix {
+        public get invGlobalTransform(): Matrix2D {
             this._updateLocalTransform();
             return this._invGlobalTransform;
         }
@@ -2827,12 +2827,12 @@
         /**
          * Get the local transformation of the primitive
          */
-        public get localTransform(): Matrix {
+        public get localTransform(): Matrix2D {
             this._updateLocalTransform();
             return this._localTransform;
         }
 
-        public get localLayoutTransform(): Matrix {
+        public get localLayoutTransform(): Matrix2D {
             this._updateLocalTransform();
             return this._localLayoutTransform;
         }
@@ -3327,7 +3327,7 @@
             if (firstLevel) {
                 // Compute the pickPosition in global space and use it to find the local position for each level down, always relative from the world to get the maximum accuracy (and speed). The other way would have been to compute in local every level down relative to its parent's local, which wouldn't be as accurate (even if javascript number is 80bits accurate).
                 intersectInfo._globalPickPosition = Vector2.Zero();
-                Vector2.TransformToRef(intersectInfo.pickPosition, this.globalTransform, intersectInfo._globalPickPosition);
+                this.globalTransform.transformPointToRef(intersectInfo.pickPosition, intersectInfo._globalPickPosition);
                 intersectInfo._localPickPosition = intersectInfo.pickPosition.clone();
                 intersectInfo.intersectedPrimitives = new Array<PrimitiveIntersectedInfo>();
                 intersectInfo.topMostIntersectedPrimitive = null;
@@ -3406,7 +3406,7 @@
                     }
 
                     // Must compute the localPickLocation for the children level
-                    Vector2.TransformToRef(intersectInfo._globalPickPosition, curChild.invGlobalTransform, intersectInfo._localPickPosition);
+                    curChild.invGlobalTransform.transformPointToRef(intersectInfo._globalPickPosition, intersectInfo._localPickPosition);
 
                     // If we got an intersection with the child and we only need to find the first one, quit!
                     if (curChild.intersect(intersectInfo) && intersectInfo.findFirstOnly) {
@@ -3703,9 +3703,9 @@
             this._layoutEngine = engine;
         }
 
-        private static _t0: Matrix = new Matrix();
-        private static _t1: Matrix = new Matrix();
-        private static _t2: Matrix = new Matrix();
+        private static _t0: Matrix2D = new Matrix2D();
+        private static _t1: Matrix2D = new Matrix2D();
+        private static _t2: Matrix2D = new Matrix2D();
         private static _v0: Vector2 = Vector2.Zero();   // Must stay with the value 0,0
         private static _v30: Vector3 = Vector3.Zero();   // Must stay with the value 0,0,0
         private static _iv3: Vector3 = new Vector3(1,1,1); // Must stay identity vector
@@ -3724,10 +3724,9 @@
                     this._updatePositioning();
                 }
 
-                var rot = Quaternion.RotationAxis(new Vector3(0, 0, 1), this._rotation);
-                var local: Matrix;
+                var rot = this._rotation;
+                var local: Matrix2D;
                 let pos = this._position ? this.position : (this.layoutAreaPos || Prim2DBase._v0);
-                let scale = new Vector3(this._scale.x, this._scale.y, 1);
                 let postScale = this._postScale;
                 let canvasScale = Prim2DBase._iv3;
                 let hasCanvasScale = false;
@@ -3735,55 +3734,45 @@
                     hasCanvasScale = true;
                     canvasScale = (this._parent as Canvas2D)._canvasLevelScale || Prim2DBase._iv3;
                 }
-                let globalScale = scale.multiplyByFloats(postScale.x*canvasScale.x, postScale.y*canvasScale.y, 1);
+                let globalScale = this._scale.multiplyByFloats(postScale.x*canvasScale.x, postScale.y*canvasScale.y);
 
                 if ((this._origin.x === 0 && this._origin.y === 0) || this._hasMargin) {
-                    // ###MATRIX PART###
-                    {
-                        local = Matrix.Compose(globalScale, rot, new Vector3(pos.x + this._marginOffset.x, pos.y + this._marginOffset.y, 0));
-                        this._localTransform = local;
-                        this._localLayoutTransform = Matrix.Compose(globalScale, rot, new Vector3(pos.x, pos.y, 0));
-                    }
+                    local = Matrix2D.Compose(globalScale, rot, new Vector2(pos.x + this._marginOffset.x, pos.y + this._marginOffset.y));
+                    this._localTransform = local;
+                    this._localLayoutTransform = Matrix2D.Compose(globalScale, rot, new Vector2(pos.x, pos.y));
                 } else {
-                    // ###MATRIX PART###
-                    {
-                        // -Origin offset
-                        let t0 = Prim2DBase._t0;
-                        let t1 = Prim2DBase._t1;
-                        let t2 = Prim2DBase._t2;
-                        let as = Prim2DBase._ts0;
-                        as.copyFrom(this.actualSize);
-                        as.width /= postScale.x;
-                        as.height /= postScale.y;
-                        Matrix.TranslationToRef((-as.width * this._origin.x), (-as.height * this._origin.y), 0, t0);
-
-                        // -Origin * rotation
-                        rot.toRotationMatrix(t1);
-                        t0.multiplyToRef(t1, t2);
-
-                        // -Origin * rotation * scale
-                        Matrix.ScalingToRef(this._scale.x, this._scale.y, 1, t0);
-                        t2.multiplyToRef(t0, t1);
-
-                        // -Origin * rotation * scale * Origin
-                        Matrix.TranslationToRef((as.width * this._origin.x), (as.height * this._origin.y), 0, t2);
-                        t1.multiplyToRef(t2, t0);
-
-                        // -Origin * rotation * scale * Origin * postScale
-                        Matrix.ScalingToRef(postScale.x, postScale.y, 1, t1);
-                        t0.multiplyToRef(t1, t2);
-
-                        // -Origin * rotation * scale * Origin * postScale * Position
-                        Matrix.TranslationToRef(pos.x + this._marginOffset.x, pos.y + this._marginOffset.y, 0, t0);
-                        t2.multiplyToRef(t0, this._localTransform);
-
-                        if (hasCanvasScale) {
-                            Matrix.ScalingToRef(canvasScale.x, canvasScale.y, canvasScale.z, Prim2DBase._t1);
-                            this._localTransform.multiplyToRef(Prim2DBase._t1, this._localTransform);
-                        }
-
-                        this._localLayoutTransform = Matrix.Compose(globalScale, rot, new Vector3(pos.x, pos.y, 0));
+                    // -Origin offset
+                    let t0 = Prim2DBase._t0;
+                    let t1 = Prim2DBase._t1;
+                    let t2 = Prim2DBase._t2;
+                    let as = Prim2DBase._ts0;
+                    as.copyFrom(this.actualSize);
+                    as.width /= postScale.x;
+                    as.height /= postScale.y;
+                    Matrix2D.TranslationToRef((-as.width * this._origin.x), (-as.height * this._origin.y), t0);
+
+                    // -Origin * rotation
+                    Matrix2D.RotationToRef(rot, t1);
+                    t0.multiplyToRef(t1, t2);
+
+                    Matrix2D.ScalingToRef(this._scale.x, this._scale.y, t0);
+                    t2.multiplyToRef(t0, t1);
+
+                    Matrix2D.TranslationToRef((as.width * this._origin.x), (as.height * this._origin.y), t2);
+                    t1.multiplyToRef(t2, t0);
+
+                    Matrix2D.ScalingToRef(postScale.x, postScale.y, t1);
+                    t0.multiplyToRef(t1, t2);
+
+                    Matrix2D.TranslationToRef(pos.x + this._marginOffset.x, pos.y + this._marginOffset.y, t0);
+                    t2.multiplyToRef(t0, this._localTransform);
+
+                    if (hasCanvasScale) {
+                        Matrix2D.ScalingToRef(canvasScale.x, canvasScale.y, Prim2DBase._t1);
+                        this._localTransform.multiplyToRef(Prim2DBase._t1, this._localTransform);
                     }
+
+                    this._localLayoutTransform = Matrix2D.Compose(globalScale, rot, pos);
                 }
 
                 this.clearPropertiesDirty(tflags);
@@ -3794,8 +3783,7 @@
             return false;
         }
 
-        private static _transMtx = Matrix.Zero();
-        private static _transTT = Transform2D.Zero();
+        private static _transMtx = Matrix2D.Zero();
 
         @logMethod()
         protected updateCachedStates(recurse: boolean) {
@@ -3889,20 +3877,17 @@
 
                 // Check if we have to update the globalTransform
                 if (!this._globalTransform || localDirty || parentDirty || parentPaddingChanged || this._areSomeFlagsSet(SmartPropertyPrim.flagGlobalTransformDirty)) {
-                    //###MATRIX PART###
-                    {
-                        let globalTransform = this._parent ? this._parent._globalTransform : null;
+                    let globalTransform = this._parent ? this._parent._globalTransform : null;
 
-                        let localTransform: Matrix;
-                        Prim2DBase._transMtx.copyFrom(this._localTransform);
-                        Prim2DBase._transMtx.m[12] += parentPaddingOffset.x;
-                        Prim2DBase._transMtx.m[13] += parentPaddingOffset.y;
-                        localTransform = Prim2DBase._transMtx;
+                    let localTransform: Matrix2D;
+                    Prim2DBase._transMtx.copyFrom(this._localTransform);
+                    Prim2DBase._transMtx.m[4] += parentPaddingOffset.x;
+                    Prim2DBase._transMtx.m[5] += parentPaddingOffset.y;
+                    localTransform = Prim2DBase._transMtx;
 
-                        this._globalTransform = this._parent ? localTransform.multiply(globalTransform) : localTransform.clone();
+                    this._globalTransform = this._parent ? localTransform.multiply(globalTransform) : localTransform.clone();
 
-                        this._invGlobalTransform = Matrix.Invert(this._globalTransform);
-                    }
+                    this._invGlobalTransform = Matrix2D.Invert(this._globalTransform);
 
                     this._levelBoundingInfo.dirtyWorldAABB();
                     this._boundingInfo.dirtyWorldAABB();
@@ -3990,7 +3975,7 @@
                 let bSize = Prim2DBase._size4;
                 let bi = this.boundingInfo;
                 let tbi = Prim2DBase._tbi;
-                bi.transformToRef(Matrix.RotationZ(this.rotation), tbi);
+                bi.transformToRef(Matrix2D.Rotation(this.rotation), tbi);
                 tbi.sizeToRef(transformedBSize);
                 bi.sizeToRef(bSize);
                 bi.extent.subtractToRef(bi.center, Prim2DBase._pv1);
@@ -4473,10 +4458,10 @@
         protected _globalTransformProcessStep: number;
         protected _prepareProcessStep: number;
         protected _updateCachesProcessStep: number;
-        protected _localTransform: Matrix;
-        protected _localLayoutTransform: Matrix;
-        protected _globalTransform: Matrix;
-        protected _invGlobalTransform: Matrix;
+        protected _localTransform: Matrix2D;
+        protected _localLayoutTransform: Matrix2D;
+        protected _globalTransform: Matrix2D;
+        protected _invGlobalTransform: Matrix2D;
 
         // Intersection related data
         protected _primTriArrayDirty: boolean;

+ 11 - 21
canvas2D/src/Engine/babylon.renderablePrim2d.ts

@@ -116,8 +116,8 @@
                 this.dataType = ShaderDataType.Vector4;
                 return;
             }
-            if (val instanceof Matrix) {
-                throw new Error("Matrix type is not supported by WebGL Instance Buffer, you have to use four Vector4 properties instead");
+            if (val instanceof Matrix2D) {
+                throw new Error("Matrix2D type is not supported by WebGL Instance Buffer, you have to use four Vector4 properties instead");
             }
             if (typeof (val) === "number") {
                 this.size = 4;
@@ -190,14 +190,6 @@
                         array[offset] = v;
                         break;
                     }
-                case ShaderDataType.Matrix:
-                    {
-                        let v = <Matrix>val;
-                        for (let i = 0; i < 16; i++) {
-                            array[offset + i] = v.m[i];
-                        }
-                        break;
-                    }
                 case ShaderDataType.Size:
                     {
                         let s = <Size>val;
@@ -939,10 +931,10 @@
         }
 
         private static _uV = new Vector2(1, 1);
-        private static _s = Vector3.Zero();
+        private static _s = Vector2.Zero();
         private static _r = Quaternion.Identity();
-        private static _t = Vector3.Zero();
-        private static _iV3 = new Vector3(1, 1, 1); // Must stay identity vector3
+        private static _t = Vector2.Zero();
+        private static _iV2 = new Vector2(1, 1); // Must stay identity vector3
 
         /**
          * Update the instanceDataBase level properties of a part
@@ -952,15 +944,13 @@
         protected updateInstanceDataPart(part: InstanceDataBase, positionOffset: Vector2 = null) {
             let t = this._globalTransform.multiply(this.renderGroup.invGlobalTransform);    // Compute the transformation into the renderGroup's space
             let scl = RenderablePrim2D._s;
-            let rot = RenderablePrim2D._r;
             let trn = RenderablePrim2D._t;
-            t.decompose(scl, rot, trn);
+            let rot = t.decompose(scl, trn);
             let pas = this.actualScale;
             let canvasScale = this.owner._canvasLevelScale;
             scl.x = pas.x * canvasScale.x * this._postScale.x;
             scl.y = pas.y * canvasScale.y * this._postScale.y;
-            scl.z = 1;
-            t = Matrix.Compose(this.applyActualScaleOnTransform() ? scl : RenderablePrim2D._iV3, rot, trn);
+            t = Matrix2D.Compose(this.applyActualScaleOnTransform() ? scl : RenderablePrim2D._iV2, rot, trn);
 
             let size = (<Size>this.renderGroup.viewportSize);
             let zBias = this.actualZOffset;
@@ -970,8 +960,8 @@
 
             // If there's an offset, apply the global transformation matrix on it to get a global offset
             if (positionOffset) {
-                offX = positionOffset.x * t.m[0] + positionOffset.y * t.m[4];
-                offY = positionOffset.x * t.m[1] + positionOffset.y * t.m[5];
+                offX = positionOffset.x * t.m[0] + positionOffset.y * t.m[2];
+                offY = positionOffset.x * t.m[1] + positionOffset.y * t.m[3];
             }
 
             // Have to convert the coordinates to clip space which is ranged between [-1;1] on X and Y axis, with 0,0 being the left/bottom corner
@@ -984,8 +974,8 @@
             let h = size.height;
             let invZBias = 1 / zBias;
 
-            let tx = new Vector4(t.m[0] * 2 / w, t.m[4] * 2 / w, 0, ((t.m[12] + offX) * 2 / w) - 1);
-            let ty = new Vector4(t.m[1] * 2 / h, t.m[5] * 2 / h, 0, ((t.m[13] + offY) * 2 / h) - 1);
+            let tx = new Vector4(t.m[0] * 2 / w, t.m[2] * 2 / w, 0, ((t.m[4] + offX) * 2 / w) - 1);
+            let ty = new Vector4(t.m[1] * 2 / h, t.m[3] * 2 / h, 0, ((t.m[5] + offY) * 2 / h) - 1);
 
             part.renderingInfo = new Vector3(w, h, this.alignToPixel ? 1 : 0);
             part.transformX = tx;

+ 4 - 4
canvas2D/src/Engine/babylon.shape2d.ts

@@ -146,9 +146,9 @@
                     } else if (fill instanceof GradientColorBrush2D) {
                         d.fillGradientColor1 = fill.color1;
                         d.fillGradientColor2 = fill.color2;
-                        var t = Matrix.Compose(new Vector3(fill.scale, fill.scale, fill.scale), Quaternion.RotationAxis(new Vector3(0, 0, 1), fill.rotation), new Vector3(fill.translation.x, fill.translation.y, 0));
+                        var t = Matrix2D.Compose(new Vector2(fill.scale, fill.scale), fill.rotation, new Vector2(fill.translation.x, fill.translation.y));
 
-                        let ty = new Vector4(t.m[1], t.m[5], t.m[9], t.m[13]);
+                        let ty = new Vector4(t.m[1], t.m[3], 0, t.m[5]);
                         d.fillGradientTY = ty;
                     }
                 }
@@ -166,9 +166,9 @@
                     } else if (border instanceof GradientColorBrush2D) {
                         d.borderGradientColor1 = border.color1;
                         d.borderGradientColor2 = border.color2;
-                        var t = Matrix.Compose(new Vector3(border.scale, border.scale, border.scale), Quaternion.RotationAxis(new Vector3(0, 0, 1), border.rotation), new Vector3(border.translation.x, border.translation.y, 0));
+                        var t = Matrix2D.Compose(new Vector2(border.scale, border.scale), border.rotation, new Vector2(border.translation.x, border.translation.y));
 
-                        let ty = new Vector4(t.m[1], t.m[5], t.m[9], t.m[13]);
+                        let ty = new Vector4(t.m[1], t.m[3], 0, t.m[5]);
                         d.borderGradientTY = ty;
                     }
                 }

+ 160 - 432
canvas2D/src/Tools/babylon.math2D.ts

@@ -1,407 +1,152 @@
 module BABYLON {
 
     /**
-     * This class stores the data to make 2D transformation using a Translation (tX, tY), a Scale (sX, sY) and a rotation around the Z axis (rZ).
-     * You can multiply two Transform2D object to produce the result of their concatenation.
-     * You can transform a given Point (a Vector2D instance) with a Transform2D object or with the Invert of the Transform2D object.
-     * There no need to compute/store the Invert of a Transform2D as the invertTranform methods are almost as fast as the transform ones.
-     * This class is as light as it could be and the transformation operations are pretty optimal.
-     */
-    export class Transform2D {
-        /**
-         * A 2D Vector representing the translation to the origin
-         */
-        public translation: Vector2;
-
-        /**
-         * A number (in radian) representing the rotation around the Z axis at the origin
-         */
-        public rotation: number;
-
-        /**
-         * A 2D Vector representing the scale to apply at the origin
-         */
-        public scale: Vector2;
+       * A class storing a Matrix2D for 2D transformations
+       * The stored matrix is a 3*3 Matrix2D
+       * I   [0,1]   [mX, mY]   R   [ CosZ, SinZ]  T    [ 0,  0]  S   [Sx,  0]
+       * D = [2,3] = [nX, nY]   O = [-SinZ, CosZ]  R =  [ 0,  0]  C = [ 0, Sy]
+       * X   [4,5]   [tX, tY]   T   [  0  ,  0  ]  N    [Tx, Ty]  L   [ 0,  0]
+       *
+       * IDX = index, zero based. ROT = Z axis Rotation. TRN = Translation. SCL = Scale.
+       */
+    export class Matrix2D {
 
-        constructor() {
-            this.translation = Vector2.Zero();
-            this.rotation = 0;
-            this.scale = new Vector2(1, 1);
+        public static Zero(): Matrix2D {
+            return new Matrix2D();
         }
-
-        /**
-         * Set the Transform2D object with the given values
-         * @param translation The translation to set
-         * @param rotation The rotation (in radian) to set
-         * @param scale The scale to set
-         */
-        public set(translation: Vector2, rotation: number, scale: Vector2) {
-            this.translation.copyFrom(translation);
-            this.rotation = rotation;
-            this.scale.copyFrom(scale);
+        
+        public static FromValuesToRef(m0: number, m1: number, m2: number, m3: number, m4: number, m5: number, result: Matrix2D) {
+            result.m[0] = m0;   result.m[1] = m1;
+            result.m[2] = m2;   result.m[3] = m3;
+            result.m[4] = m4;   result.m[5] = m5;
         }
 
-        /**
-         * Set the Transform2D object from float values
-         * @param transX The translation on X axis, nothing is set if not specified
-         * @param transY The translation on Y axis, nothing is set if not specified
-         * @param rotation The rotation in radian, nothing is set if not specified
-         * @param scaleX The scale along the X axis, nothing is set if not specified
-         * @param scaleY The scale along the Y axis, nothing is set if not specified
-         */
-        public setFromFloats(transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number) {
-            if (transX) {
-                this.translation.x = transX;
-            }
-
-            if (transY) {
-                this.translation.y = transY;
-            }
-
-            if (rotation) {
-                this.rotation = rotation;
-            }
-
-            if (scaleX) {
-                this.scale.x = scaleX;
-            }
-
-            if (scaleY) {
-                this.scale.y = scaleY;
-            }
-        }
-
-        /**
-         * Return a copy of the object
-         */
-        public clone(): Transform2D {
-            let res = new Transform2D();
-            res.translation.copyFrom(this.translation);
-            res.rotation = this.rotation;
-            res.scale.copyFrom(this.scale);
-
-            return res;
+        public static FromMatrix(source: Matrix): Matrix2D {
+            let result = new Matrix2D();
+            Matrix2D.FromMatrixToRef(source, result);
+            return result;
         }
 
-        /**
-         * Convert a given degree angle into its radian equivalent
-         * @param angleDegree the number to convert
-         */
-        public static ToRadian(angleDegree: number): number {
-            return angleDegree * Math.PI * 2 / 360;
+        public static FromMatrixToRef(source: Matrix, result: Matrix2D) {
+            result.m[0] = source.m[0];    result.m[1] = source.m[1];
+            result.m[2] = source.m[4];    result.m[3] = source.m[5];
+            result.m[4] = source.m[8];    result.m[5] = source.m[9];
         }
 
-        /**
-         * Create a new instance and returns it
-         * @param translation The translation to store, default is (0,0)
-         * @param rotation The rotation to store, default is 0
-         * @param scale The scale to store, default is (1,1)
-         */
-        public static Make(translation?: Vector2, rotation?: number, scale?: Vector2): Transform2D {
-            let res = new Transform2D();
-            if (translation) {
-                res.translation.copyFrom(translation);
-            }
-            if (rotation) {
-                res.rotation = rotation;
-            }
-            if (scale) {
-                res.scale.copyFrom(scale);
-            }
+        public static Rotation(angle: number): Matrix2D {
+            var result = new Matrix2D();
 
-            return res;
-        }
+            Matrix2D.RotationToRef(angle, result);
 
-        /**
-         * Set the given Transform2D object with the given values
-         * @param translation The translation to store, default is (0,0)
-         * @param rotation The rotation to store, default is 0
-         * @param scale The scale to store, default is (1,1)
-         */
-        public static MakeToRef(res: Transform2D, translation?: Vector2, rotation?: number, scale?: Vector2) {
-            if (translation) {
-                res.translation.copyFrom(translation);
-            } else {
-                res.translation.copyFromFloats(0, 0);
-            }
-            if (rotation) {
-                res.rotation = rotation;
-            } else {
-                res.rotation = 0;
-            }
-            if (scale) {
-                res.scale.copyFrom(scale);
-            } else {
-                res.scale.copyFromFloats(1, 1);
-            }
+            return result;
         }
 
-        /**
-         * Create a Transform2D object from float values
-         * @param transX The translation on X axis, 0 per default
-         * @param transY The translation on Y axis, 0 per default
-         * @param rotation The rotation in radian, 0 per default
-         * @param scaleX The scale along the X axis, 1 per default
-         * @param scaleY The scale along the Y axis, 1 per default
-         */
-        public static MakeFromFloats(transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number): Transform2D {
-            let res = new Transform2D();
-
-            if (transX) {
-                res.translation.x = transX;
-            }
-
-            if (transY) {
-                res.translation.y = transY;
-            }
-
-            if (rotation) {
-                res.rotation = rotation;
-            }
-
-            if (scaleX) {
-                res.scale.x = scaleX;
-            }
-
-            if (scaleY) {
-                res.scale.y = scaleY;
-            }
+        public static RotationToRef(angle: number, result: Matrix2D): void {
+            var s = Math.sin(angle);
+            var c = Math.cos(angle);
 
-            return res;
+            result.m[0] = c;    result.m[1] = s;
+            result.m[2] = -s;   result.m[3] = c;
+            result.m[4] = 0;    result.m[5] = 0;
         }
 
-        /**
-         * Set the given Transform2D object with the given float values
-         * @param transX The translation on X axis, 0 per default
-         * @param transY The translation on Y axis, 0 per default
-         * @param rotation The rotation in radian, 0 per default
-         * @param scaleX The scale along the X axis, 1 per default
-         * @param scaleY The scale along the Y axis, 1 per default
-         */
-        public static MakeFromFloatsToRef(res: Transform2D, transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number) {
-            res.translation.x = (transX!=null)   ? transX   : 0;
-            res.translation.y = (transY!=null)   ? transY   : 0;
-            res.rotation      = (rotation!=null) ? rotation : 0;
-            res.scale.x       = (scaleX!=null)   ? scaleX   : 1;
-            res.scale.y       = (scaleY!=null)   ? scaleY   : 1;
-        }
+        public static Translation(x: number, y: number): Matrix2D {
+            var result = new Matrix2D();
 
-        /**
-         * Create a Transform2D containing only Zeroed values
-         */
-        public static Zero(): Transform2D {
-            let res = new Transform2D();
-            res.scale.copyFromFloats(0, 0);
-            return res;
-        }
+            Matrix2D.TranslationToRef(x, y, result);
 
-        /**
-         * Copy the value of the other object into 'this'
-         * @param other The other object to copy values from
-         */
-        public copyFrom(other: Transform2D) {
-            this.translation.copyFrom(other.translation);
-            this.rotation = other.rotation;
-            this.scale.copyFrom(other.scale);
+            return result;
         }
 
-        public toMatrix2D(): Matrix2D {
-            let res = new Matrix2D();
-            this.toMatrix2DToRef(res);
-            return res;
+        public static TranslationToRef(x: number, y: number, result: Matrix2D): void {
+            result.m[0] = 1;    result.m[1] = 0;
+            result.m[2] = 0;    result.m[3] = 1;
+            result.m[4] = x;    result.m[5] = y;
         }
 
-        public toMatrix2DToRef(res: Matrix2D) {
-            let tx = this.translation.x;
-            let ty = this.translation.y;
-            let r = this.rotation;
-            let cosr = Math.cos(r);
-            let sinr = Math.sin(r);
-            let sx = this.scale.x;
-            let sy = this.scale.y;
+        public static Scaling(x: number, y: number): Matrix2D {
+            var result = new Matrix2D();
 
-            res.m[0] = cosr * sx;   res.m[1] = sinr * sy;
-            res.m[2] = -sinr* sx;   res.m[3] = cosr * sy;
-            res.m[4] = tx;          res.m[5] = ty;
-        }
+            Matrix2D.ScalingToRef(x, y, result);
 
-        /**
-         * In place transformation from a parent matrix.
-         * @param parent transform object. "this" will be the result of parent * this
-         */
-        public multiplyToThis(parent: Transform2D) {
-            this.multiplyToRef(parent, this);
-        }
-
-        /**
-         * Transform this object with a parent and return the result. Result = parent * this
-         * @param parent The parent transformation
-         */
-        public multiply(parent: Transform2D): Transform2D {
-            let res = new Transform2D();
-            this.multiplyToRef(parent, res);
-            return res;
+            return result;
         }
 
-        /**
-         * Transform a point and store the result in the very same object
-         * @param p Transform this point and change the values with the transformed ones
-         */
-        public transformPointInPlace(p: Vector2) {
-            this.transformPointToRef(p, p);
+        public static ScalingToRef(x: number, y: number, result: Matrix2D): void {
+            result.m[0] = x;    result.m[1] = 0;
+            result.m[2] = 0;    result.m[3] = y;
+            result.m[4] = 0;    result.m[5] = 0;
         }
 
-        /**
-         * Transform a point and store the result into a reference object
-         * @param p The point to transform
-         * @param res Will contain the new transformed coordinates. Can be the object of 'p'.
-         */
-        public transformPointToRef(p: Vector2, res: Vector2) {
-            this.transformFloatsToRef(p.x, p.y, res);
-        }
+        public m = new Float32Array(6);
 
-        /**
-         * Transform this object with a parent and store the result in reference object
-         * @param parent The parent transformation
-         * @param result Will contain parent * this. Can be the object of either parent or 'this'
-         */
-        public multiplyToRef(parent: Transform2D, result: Transform2D) {
-            if (!parent || !result) {
-                throw new Error("Valid parent and result objects must be specified");
-            }
-            let tx = this.translation.x;
-            let ty = this.translation.y;
-            let ptx = parent.translation.x;
-            let pty = parent.translation.y;
-            let pr = parent.rotation;
-            let psx = parent.scale.x;
-            let psy = parent.scale.y;
-            let cosr = Math.cos(pr);
-            let sinr = Math.sin(pr);
-            result.translation.x = (((tx * cosr) - (ty * sinr)) * psx) + ptx;
-            result.translation.y = (((tx * sinr) + (ty * cosr)) * psy) + pty;
-            this.scale.multiplyToRef(parent.scale, result.scale);
-            result.rotation = this.rotation;
+        public static Identity(): Matrix2D {
+            let res = new Matrix2D();
+            Matrix2D.IdentityToRef(res);
+            return res;
         }
 
-        /**
-         * Transform the given coordinates and store the result in a Vector2 object
-         * @param x The X coordinate to transform
-         * @param y The Y coordinate to transform
-         * @param res The Vector2 object that will contain the result of the transformation
-         */
-        public transformFloatsToRef(x: number, y: number, res: Vector2) {
-            let tx = this.translation.x;
-            let ty = this.translation.y;
-            let pr = this.rotation;
-            let sx = this.scale.x;
-            let sy = this.scale.y;
-            let cosr = Math.cos(pr);
-            let sinr = Math.sin(pr);
-            res.x = (((x * cosr) - (y * sinr)) * sx) + tx;
-            res.y = (((x * sinr) + (y * cosr)) * sy) + ty;
+        public static IdentityToRef(res: Matrix2D) {
+            res.m[1] = res.m[2] = res.m[4] = res[5] = 0;
+            res.m[0] = res.m[3] = 1;
         }
 
-        /**
-         * Invert transform the given coordinates and store the result in a reference object. res = invert(this) * (x,y)
-         * @param p Transform this point and change the values with the transformed ones
-         * @param res Will contain the result of the invert transformation.
-         */
-        public invertTransformFloatsToRef(x: number, y: number, res: Vector2) {
-            let px = x - this.translation.x;
-            let py = y - this.translation.y;
-
-            let pr = -this.rotation;
-            let sx = this.scale.x;
-            let sy = this.scale.y;
-            let psx = (sx===1) ? 1 : (1/sx);
-            let psy = (sy===1) ? 1 : (1/sy);
-            let cosr = Math.cos(pr);
-            let sinr = Math.sin(pr);
-            res.x = (((px * cosr) - (py * sinr)) * psx);
-            res.y = (((px * sinr) + (py * cosr)) * psy);
+        public static FromQuaternion(quaternion: Quaternion): Matrix2D {
+            let result = new Matrix2D();
+            Matrix2D.FromQuaternionToRef(quaternion, result);
+            return result;
         }
 
-        /**
-         * Transform a point and return the result
-         * @param p the point to transform
-         */
-        public transformPoint(p: Vector2): Vector2 {
-            let res = Vector2.Zero();
-            this.transformPointToRef(p, res);
-            return res;
-        }
+        public static FromQuaternionToRef(quaternion: Quaternion, result: Matrix2D) {
+            var xx = quaternion.x * quaternion.x;
+            var yy = quaternion.y * quaternion.y;
+            var zz = quaternion.z * quaternion.z;
+            var xy = quaternion.x * quaternion.y;
+            var zw = quaternion.z * quaternion.w;
+            //var zx = quaternion.z * quaternion.x;
+            //var yw = quaternion.y * quaternion.w;
+            //var yz = quaternion.y * quaternion.z;
+            //var xw = quaternion.x * quaternion.w;
 
-        /**
-         * Transform the given coordinates and return the result in a Vector2 object
-         * @param x The X coordinate to transform
-         * @param y The Y coordinate to transform
-         */
-        public transformFloats(x: number, y: number): Vector2 {
-            let res = Vector2.Zero();
-            this.transformFloatsToRef(x, y, res);
-            return res;
+            result.m[0] = 1.0 - (2.0 * (yy + zz));
+            result.m[1] = 2.0 * (xy + zw);
+            //result.m[2] = 2.0 * (zx - yw);
+            //result.m[3] = 0;
+            result.m[2] = 2.0 * (xy - zw);
+            result.m[3] = 1.0 - (2.0 * (zz + xx));
+            //result.m[6] = 2.0 * (yz + xw);
+            //result.m[7] = 0;
+            //result.m[8] = 2.0 * (zx + yw);
+            //result.m[9] = 2.0 * (yz - xw);
+            //result.m[10] = 1.0 - (2.0 * (yy + xx));
+            //result.m[11] = 0;
+            //result.m[12] = 0;
+            //result.m[13] = 0;
+            //result.m[14] = 0;
+            //result.m[15] = 1.0;
         }
 
-        /**
-         * Invert transform a given point and store the result in the very same object. p = invert(this) * p
-         * @param p Transform this point and change the values with the transformed ones
-         */
-        public invertTransformPointInPlace(p: Vector2) {
-            this.invertTransformPointToRef(p, p);
-        }
+        public static Compose(scale: Vector2, rotation: number, translation: Vector2): Matrix2D {
+            var result = Matrix2D.Scaling(scale.x, scale.y);
 
-        /**
-         * Invert transform a given point and store the result in a reference object. res = invert(this) * p
-         * @param p Transform this point and change the values with the transformed ones
-         * @param res Will contain the result of the invert transformation. 'res' can be the same object as 'p'
-         */
-        public invertTransformPointToRef(p: Vector2, res: Vector2) {
-            this.invertTransformFloatsToRef(p.x, p.y, res);
-        }
+            var rotationMatrix = Matrix2D.Rotation(rotation);
+            result = result.multiply(rotationMatrix);
 
-        /**
-         * Invert transform a given point and return the result. return = invert(this) * p
-         * @param p The Point to transform
-         */
-        public invertTransformPoint(p: Vector2): Vector2 {
-            let res = Vector2.Zero();
-            this.invertTransformPointToRef(p, res);
-            return res;
-        }
+            result.setTranslation(translation);
 
-        /**
-         * Invert transform the given coordinates and return the result. return = invert(this) * (x,y)
-         * @param x The X coordinate to transform
-         * @param y The Y coordinate to transform
-         */
-        public invertTransformFloats(x: number, y: number): Vector2 {
-            let res = Vector2.Zero();
-            this.invertTransformFloatsToRef(x, y, res);
-            return res;
+            return result;
         }
-    }
 
-    /**
-     * A class storing a Matrix for 2D transformations
-     * The stored matrix is a 2*3 Matrix
-     * I   [0,1]   [mX, mY]   R   [ CosZ, SinZ]  T    [ 0,  0]  S   [Sx,  0]
-     * D = [2,3] = [nX, nY]   O = [-SinZ, CosZ]  R =  [ 0,  0]  C = [ 0, Sy]
-     * X   [4,5]   [tX, tY]   T   [  0  ,  0  ]  N    [Tx, Ty]  L   [ 0,  0]
-     *
-     * IDX = index, zero based. ROT = Z axis Rotation. TRN = Translation. SCL = Scale.
-     */
-    export class Matrix2D {
-
-        public static Identity(): Matrix2D {
-            let res = new Matrix2D();
-            Matrix2D.IdentityToRef(res);
-            return res;
+        public static Invert(source: Matrix2D): Matrix2D {
+            let result = new Matrix2D();
+            source.invertToRef(result);
+            return result;
         }
 
-        public static IdentityToRef(res: Matrix2D) {
-            res.m[1] = res.m[2] = res.m[4] = res.m[5] = 0;
-            res.m[0] = res.m[3] = 1;           
+        public clone(): Matrix2D {
+            let result = new Matrix2D();
+            result.copyFrom(this);
+            return result;
         }
 
         public copyFrom(other: Matrix2D) {
@@ -410,8 +155,17 @@
             }
         }
 
+        public getTranslation(): Vector2 {
+            return new Vector2(this.m[4], this.m[5]);
+        }
+
+        public setTranslation(translation: Vector2) {
+            this.m[4] = translation.x;
+            this.m[5] = translation.y;
+        }
+
         public determinant(): number {
-            return (this.m[0] * this.m[3]) - (this.m[1] * this.m[2]);
+            return this.m[0] * this.m[3] - this.m[1] * this.m[2];
         }
 
         public invertToThis() {
@@ -424,26 +178,25 @@
             return res;
         }
 
+        // http://mathworld.wolfram.com/MatrixInverse.html
         public invertToRef(res: Matrix2D) {
-            let a00 = this.m[0], a01 = this.m[1],
-                a10 = this.m[2], a11 = this.m[3],
-                a20 = this.m[4], a21 = this.m[5];
+            let l0 = this.m[0]; let l1 = this.m[1];
+            let l2 = this.m[2]; let l3 = this.m[3];
+            let l4 = this.m[4]; let l5 = this.m[5];
 
-            let det21 = a21 * a10 - a11 * a20;
-
-            let det = (a00 * a11) - (a01 * a10);
-            if (det < (Epsilon*Epsilon)) {
+            let det = this.determinant();
+            if (det < (Epsilon * Epsilon)) {
                 throw new Error("Can't invert matrix, near null determinant");
             }
 
-            det = 1 / det;
+            let detDiv = 1 / det;
+
+            let det4 = l2 * l5 - l3 * l4;
+            let det5 = l1 * l4 - l0 * l5;
 
-            res.m[0] = a11 * det;
-            res.m[1] = -a01 * det;
-            res.m[2] = -a10 * det;
-            res.m[3] = a00 * det;
-            res.m[4] = det21 * det;
-            res.m[5] = (-a21 * a00 + a01 * a20) * det;
+            res.m[0] = l3 * detDiv;     res.m[1] = -l1 * detDiv;
+            res.m[2] = -l2 * detDiv;    res.m[3] = l0 * detDiv;
+            res.m[4] = det4 * detDiv;   res.m[5] = det5 * detDiv;
         }
 
         public multiplyToThis(other: Matrix2D) {
@@ -457,59 +210,17 @@
         }
 
         public multiplyToRef(other: Matrix2D, result: Matrix2D) {
-            var tm0 = this.m[0];
-            var tm1 = this.m[1];
-            //var tm2 = this.m[2];
-            //var tm3 = this.m[3];
-            var tm4 = this.m[2];
-            var tm5 = this.m[3];
-            //var tm6 = this.m[6];
-            //var tm7 = this.m[7];
-            var tm8 = this.m[4];
-            var tm9 = this.m[5];
-            //var tm10 = this.m[10];
-            //var tm11 = this.m[11];
-            //var tm12 = this.m[12];
-            //var tm13 = this.m[13];
-            //var tm14 = this.m[14];
-            //var tm15 = this.m[15];
-
-            var om0 = other.m[0];
-            var om1 = other.m[1];
-            //var om2 = other.m[2];
-            //var om3 = other.m[3];
-            var om4 = other.m[2];
-            var om5 = other.m[3];
-            //var om6 = other.m[6];
-            //var om7 = other.m[7];
-            var om8 = other.m[4];
-            var om9 = other.m[5];
-            //var om10 = other.m[10];
-            //var om11 = other.m[11];
-            //var om12 = other.m[12];
-            //var om13 = other.m[13];
-            //var om14 = other.m[14];
-            //var om15 = other.m[15];
-
-            result.m[0] = tm0 * om0 + tm1 * om4;
-            result.m[1] = tm0 * om1 + tm1 * om5;
-            //result.m[2] = tm0 * om2 + tm1 * om6 + tm2 * om10 + tm3 * om14;
-            //result.m[3] = tm0 * om3 + tm1 * om7 + tm2 * om11 + tm3 * om15;
-
-            result.m[2] = tm4 * om0 + tm5 * om4;
-            result.m[3] = tm4 * om1 + tm5 * om5;
-            //result.m[6] = tm4 * om2 + tm5 * om6 + tm6 * om10 + tm7 * om14;
-            //result.m[7] = tm4 * om3 + tm5 * om7 + tm6 * om11 + tm7 * om15;
-
-            result.m[4] = tm8 * om0 + tm9 * om4 + om8;
-            result.m[5] = tm8 * om1 + tm9 * om5 + om9;
-            //result.m[10] = tm8 * om2 + tm9 * om6 + tm10 * om10 + tm11 * om14;
-            //result.m[11] = tm8 * om3 + tm9 * om7 + tm10 * om11 + tm11 * om15;
-
-            //result.m[12] = tm12 * om0 + tm13 * om4 + tm14 * om8 + tm15 * om12;
-            //result.m[13] = tm12 * om1 + tm13 * om5 + tm14 * om9 + tm15 * om13;
-            //result.m[14] = tm12 * om2 + tm13 * om6 + tm14 * om10 + tm15 * om14;
-            //result.m[15] = tm12 * om3 + tm13 * om7 + tm14 * om11 + tm15 * om15;
+            let l0 = this.m[0];     let l1 = this.m[1];
+            let l2 = this.m[2];     let l3 = this.m[3];
+            let l4 = this.m[4];     let l5 = this.m[5];
+
+            let r0 = other.m[0];    let r1 = other.m[1];
+            let r2 = other.m[2];    let r3 = other.m[3];
+            let r4 = other.m[4];    let r5 = other.m[5];
+
+            result.m[0] = l0 * r0 + l1 * r2;        result.m[1] = l0 * r1 + l1 * r3;
+            result.m[2] = l2 * r0 + l3 * r2;        result.m[3] = l2 * r1 + l3 * r3;
+            result.m[4] = l4 * r0 + l5 * r2 + r4;   result.m[5] = l4 * r1 + l5 * r3 + r5;
         }
 
         public transformFloats(x: number, y: number): Vector2 {
@@ -533,7 +244,21 @@
             this.transformFloatsToRef(p.x, p.y, r);
         }
 
-        public m = new Float32Array(6);
+        private static _decomp: Matrix2D = new Matrix2D();
+
+        public decompose(scale: Vector2, translation: Vector2): number {
+            translation.x = this.m[4];
+            translation.y = this.m[5];
+
+            scale.x = Math.sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1]);
+            scale.y = Math.sqrt(this.m[2] * this.m[2] + this.m[3] * this.m[3]);
+
+            if (scale.x === 0 || scale.y === 0) {
+                return null;
+            }
+
+            return Math.atan2(-this.m[2] / scale.y, this.m[0] / scale.x);
+        }
     }
 
     /**
@@ -579,10 +304,13 @@
             this._updateCenterRadius();
         }
 
-        public transformInPlace(transform: Matrix) {
-            Vector2.TransformToRef(this.a, transform, this.a);
-            Vector2.TransformToRef(this.b, transform, this.b);
-            Vector2.TransformToRef(this.c, transform, this.c);
+        public transformInPlace(transform: Matrix2D) {
+            transform.transformPointToRef(this.a, this.a);
+            transform.transformPointToRef(this.b, this.b);
+            transform.transformPointToRef(this.c, this.c);
+            //Vector2.TransformToRef(this.a, transform, this.a);
+            //Vector2.TransformToRef(this.b, transform, this.b);
+            //Vector2.TransformToRef(this.c, transform, this.c);
 
             this._updateCenterRadius();
         }
@@ -686,7 +414,7 @@
          * @param tri2dInfo The triangle to transform
          * @param transform The transformation matrix
          */
-        public transformAndStoreToTri2DInfo(index: number, tri2dInfo: Tri2DInfo, transform: Matrix) {
+        public transformAndStoreToTri2DInfo(index: number, tri2dInfo: Tri2DInfo, transform: Matrix2D) {
             if (index >= this._count) {
                 throw new Error(`Can't fetch the triangle at index ${index}, max index is ${this._count - 1}`);
             }
@@ -735,7 +463,7 @@
          * @param setB The second set of triangles
          * @param bToATransform The transformation matrix to transform the setB triangles into the frame of reference of the setA
          */
-        public static doesIntersect(setA: Tri2DArray, setB: Tri2DArray, bToATransform: Matrix): boolean {
+        public static doesIntersect(setA: Tri2DArray, setB: Tri2DArray, bToATransform: Matrix2D): boolean {
             Tri2DArray._checkInitStatics();
 
             let a = Tri2DArray.tempT[0];