Sfoglia il codice sorgente

Merge pull request #1794 from nockawa/shapeFillBug

Canvas2D: big refactoring of the Positioning Engine!
Loïc Baumann 8 anni fa
parent
commit
6900730446

+ 7 - 0
canvas2D/src/Engine/babylon.bounding2d.ts

@@ -153,6 +153,13 @@
             this._worldAABBDirty = true;
             this._worldAABBDirty = true;
         }
         }
 
 
+        public equals(other: BoundingInfo2D): boolean {
+            if (!other) {
+                return false;
+            }
+            return other.center.equals(this.center) && other.extent.equals(this.extent);
+        }
+
         /**
         /**
          * return the max extend of the bounding info
          * return the max extend of the bounding info
          */
          */

+ 64 - 35
canvas2D/src/Engine/babylon.canvas2d.ts

@@ -87,18 +87,19 @@
         }) {
         }) {
             super(settings);
             super(settings);
 
 
-            this._drawCallsOpaqueCounter       = new PerfCounter();
-            this._drawCallsAlphaTestCounter    = new PerfCounter();
-            this._drawCallsTransparentCounter  = new PerfCounter();
-            this._groupRenderCounter           = new PerfCounter();
-            this._updateTransparentDataCounter = new PerfCounter();
-            this._cachedGroupRenderCounter     = new PerfCounter();
-            this._updateCachedStateCounter     = new PerfCounter();
-            this._updateLayoutCounter          = new PerfCounter();
-            this._updatePositioningCounter     = new PerfCounter();
-            this._updateLocalTransformCounter  = new PerfCounter();
-            this._updateGlobalTransformCounter = new PerfCounter();
-            this._boundingInfoRecomputeCounter = new PerfCounter();
+            this._drawCallsOpaqueCounter          = new PerfCounter();
+            this._drawCallsAlphaTestCounter       = new PerfCounter();
+            this._drawCallsTransparentCounter     = new PerfCounter();
+            this._groupRenderCounter              = new PerfCounter();
+            this._updateTransparentDataCounter    = new PerfCounter();
+            this._cachedGroupRenderCounter        = new PerfCounter();
+            this._updateCachedStateCounter        = new PerfCounter();
+            this._updateLayoutCounter             = new PerfCounter();
+            this._updatePositioningCounter        = new PerfCounter();
+            this._updateLocalTransformCounter     = new PerfCounter();
+            this._updateGlobalTransformCounter    = new PerfCounter();
+            this._boundingInfoRecomputeCounter    = new PerfCounter();
+            this._layoutBoundingInfoUpdateCounter = new PerfCounter();
 
 
             this._cachedCanvasGroup = null;
             this._cachedCanvasGroup = null;
 
 
@@ -276,6 +277,10 @@
             return this._boundingInfoRecomputeCounter;
             return this._boundingInfoRecomputeCounter;
         }
         }
 
 
+        public get layoutBoundingInfoUpdateCounter(): PerfCounter {
+            return this._layoutBoundingInfoUpdateCounter;
+        }
+
         public static get instances() : Array<Canvas2D> {
         public static get instances() : Array<Canvas2D> {
             return Canvas2D._INSTANCES;
             return Canvas2D._INSTANCES;
         }
         }
@@ -1134,6 +1139,7 @@
             this._updateLocalTransformCounter.fetchNewFrame();
             this._updateLocalTransformCounter.fetchNewFrame();
             this._updateGlobalTransformCounter.fetchNewFrame();
             this._updateGlobalTransformCounter.fetchNewFrame();
             this._boundingInfoRecomputeCounter.fetchNewFrame();
             this._boundingInfoRecomputeCounter.fetchNewFrame();
+            this._layoutBoundingInfoUpdateCounter.fetchNewFrame();
         }
         }
 
 
         private _fetchPerfMetrics() {
         private _fetchPerfMetrics() {
@@ -1149,6 +1155,7 @@
             this._updateLocalTransformCounter.addCount(0, true);
             this._updateLocalTransformCounter.addCount(0, true);
             this._updateGlobalTransformCounter.addCount(0, true);
             this._updateGlobalTransformCounter.addCount(0, true);
             this._boundingInfoRecomputeCounter.addCount(0, true);
             this._boundingInfoRecomputeCounter.addCount(0, true);
+            this._layoutBoundingInfoUpdateCounter.addCount(0, true);
         }
         }
 
 
         private _updateProfileCanvas() {
         private _updateProfileCanvas() {
@@ -1170,7 +1177,8 @@
                     ` - Update Positioning: ${this.updatePositioningCounter.current}, (avg:${format(this.updatePositioningCounter.lastSecAverage)}, t:${format(this.updatePositioningCounter.total)})\n` + 
                     ` - Update Positioning: ${this.updatePositioningCounter.current}, (avg:${format(this.updatePositioningCounter.lastSecAverage)}, t:${format(this.updatePositioningCounter.total)})\n` + 
                     ` - Update Local  Trans: ${this.updateLocalTransformCounter.current}, (avg:${format(this.updateLocalTransformCounter.lastSecAverage)}, t:${format(this.updateLocalTransformCounter.total)})\n` + 
                     ` - Update Local  Trans: ${this.updateLocalTransformCounter.current}, (avg:${format(this.updateLocalTransformCounter.lastSecAverage)}, t:${format(this.updateLocalTransformCounter.total)})\n` + 
                     ` - Update Global Trans: ${this.updateGlobalTransformCounter.current}, (avg:${format(this.updateGlobalTransformCounter.lastSecAverage)}, t:${format(this.updateGlobalTransformCounter.total)})\n` + 
                     ` - Update Global Trans: ${this.updateGlobalTransformCounter.current}, (avg:${format(this.updateGlobalTransformCounter.lastSecAverage)}, t:${format(this.updateGlobalTransformCounter.total)})\n` + 
-                    ` - BoundingInfo Recompute: ${this.boundingInfoRecomputeCounter.current}, (avg:${format(this.boundingInfoRecomputeCounter.lastSecAverage)}, t:${format(this.boundingInfoRecomputeCounter.total)})`;
+                    ` - BoundingInfo Recompute: ${this.boundingInfoRecomputeCounter.current}, (avg:${format(this.boundingInfoRecomputeCounter.lastSecAverage)}, t:${format(this.boundingInfoRecomputeCounter.total)})\n` +
+                    ` - LayoutBoundingInfo Recompute: ${this.layoutBoundingInfoUpdateCounter.current}, (avg:${format(this.layoutBoundingInfoUpdateCounter.lastSecAverage)}, t:${format(this.layoutBoundingInfoUpdateCounter.total)})` ;
             this._profileInfoText.text = p;
             this._profileInfoText.text = p;
         }
         }
 
 
@@ -1189,35 +1197,57 @@
         }
         }
 
 
         public _addGroupRenderCount(count: number) {
         public _addGroupRenderCount(count: number) {
-            this._groupRenderCounter.addCount(count, false);
+            if (this._groupRenderCounter) {
+                this._groupRenderCounter.addCount(count, false);
+            }
         }
         }
 
 
         public _addUpdateTransparentDataCount(count: number) {
         public _addUpdateTransparentDataCount(count: number) {
-            this._updateTransparentDataCounter.addCount(count, false);
+            if (this._updateTransparentDataCounter) {
+                this._updateTransparentDataCounter.addCount(count, false);
+            }
         }
         }
 
 
         public addCachedGroupRenderCounter(count: number) {
         public addCachedGroupRenderCounter(count: number) {
-            this._cachedGroupRenderCounter.addCount(count, false);
+            if (this._cachedGroupRenderCounter) {
+                this._cachedGroupRenderCounter.addCount(count, false);
+            }
         }
         }
 
 
         public addUpdateCachedStateCounter(count: number) {
         public addUpdateCachedStateCounter(count: number) {
-            this._updateCachedStateCounter.addCount(count, false);
+            if (this._updateCachedStateCounter) {
+                this._updateCachedStateCounter.addCount(count, false);
+            }
         }
         }
 
 
         public addUpdateLayoutCounter(count: number) {
         public addUpdateLayoutCounter(count: number) {
-            this._updateLayoutCounter.addCount(count, false);
+            if (this._updateLayoutCounter) {
+                this._updateLayoutCounter.addCount(count, false);
+            }
         }
         }
 
 
         public addUpdatePositioningCounter(count: number) {
         public addUpdatePositioningCounter(count: number) {
-            this._updatePositioningCounter.addCount(count, false);
+            if (this._updatePositioningCounter) {
+                this._updatePositioningCounter.addCount(count, false);
+            }
         }
         }
 
 
         public addupdateLocalTransformCounter(count: number) {
         public addupdateLocalTransformCounter(count: number) {
-            this._updateLocalTransformCounter.addCount(count, false);
+            if (this._updateLocalTransformCounter) {
+                this._updateLocalTransformCounter.addCount(count, false);
+            }
         }
         }
 
 
         public addUpdateGlobalTransformCounter(count: number) {
         public addUpdateGlobalTransformCounter(count: number) {
-            this._updateGlobalTransformCounter.addCount(count, false);
+            if (this._updateGlobalTransformCounter) {
+                this._updateGlobalTransformCounter.addCount(count, false);
+            }
+        }
+
+        public addLayoutBoundingInfoUpdateCounter(count: number) {
+            if (this._layoutBoundingInfoUpdateCounter) {
+                this._layoutBoundingInfoUpdateCounter.addCount(count, false);
+            }
         }
         }
 
 
         private _renderObservable: Observable<Canvas2D>;
         private _renderObservable: Observable<Canvas2D>;
@@ -1264,18 +1294,19 @@
 
 
         public _renderingSize: Size;
         public _renderingSize: Size;
 
 
-        private _drawCallsOpaqueCounter      : PerfCounter;
-        private _drawCallsAlphaTestCounter   : PerfCounter;
-        private _drawCallsTransparentCounter : PerfCounter;
-        private _groupRenderCounter          : PerfCounter;
-        private _updateTransparentDataCounter: PerfCounter;
-        private _cachedGroupRenderCounter    : PerfCounter;
-        private _updateCachedStateCounter    : PerfCounter;
-        private _updateLayoutCounter         : PerfCounter;
-        private _updatePositioningCounter    : PerfCounter;
-        private _updateGlobalTransformCounter: PerfCounter;
-        private _updateLocalTransformCounter : PerfCounter;
-        private _boundingInfoRecomputeCounter: PerfCounter;
+        private _drawCallsOpaqueCounter          : PerfCounter;
+        private _drawCallsAlphaTestCounter       : PerfCounter;
+        private _drawCallsTransparentCounter     : PerfCounter;
+        private _groupRenderCounter              : PerfCounter;
+        private _updateTransparentDataCounter    : PerfCounter;
+        private _cachedGroupRenderCounter        : PerfCounter;
+        private _updateCachedStateCounter        : PerfCounter;
+        private _updateLayoutCounter             : PerfCounter;
+        private _updatePositioningCounter        : PerfCounter;
+        private _updateGlobalTransformCounter    : PerfCounter;
+        private _updateLocalTransformCounter     : PerfCounter;
+        private _boundingInfoRecomputeCounter    : PerfCounter;
+        private _layoutBoundingInfoUpdateCounter : PerfCounter;
 
 
         private _profilingCanvas: Canvas2D;
         private _profilingCanvas: Canvas2D;
         private _profileInfoText: Text2D;
         private _profileInfoText: Text2D;
@@ -1443,7 +1474,6 @@
 
 
             // If the canvas fit the rendering size and it changed, update
             // If the canvas fit the rendering size and it changed, update
             if (renderingSizeChanged && this._fitRenderingDevice) {
             if (renderingSizeChanged && this._fitRenderingDevice) {
-                this.actualSize = this._renderingSize.clone();
                 this.size = this._renderingSize.clone();
                 this.size = this._renderingSize.clone();
                 if (this._background) {
                 if (this._background) {
                     this._background.size = this.size;
                     this._background.size = this.size;
@@ -1462,7 +1492,6 @@
                     scale = this._renderingSize.height / this._designSize.height;
                     scale = this._renderingSize.height / this._designSize.height;
                 }
                 }
                 this.size = this._designSize.clone();
                 this.size = this._designSize.clone();
-                this.actualSize = this._designSize.clone();
                 this.scale = scale;
                 this.scale = scale;
             }
             }
 
 

+ 61 - 14
canvas2D/src/Engine/babylon.canvas2dLayoutEngine.ts

@@ -65,10 +65,10 @@
 
 
             // If this prim is layoutDiry we update  its layoutArea and also the one of its direct children
             // If this prim is layoutDiry we update  its layoutArea and also the one of its direct children
             if (prim._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
             if (prim._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
+                prim._clearFlags(SmartPropertyPrim.flagLayoutDirty);
                 for (let child of prim.children) {
                 for (let child of prim.children) {
                     this._doUpdate(child);
                     this._doUpdate(child);
                 }
                 }
-                prim._clearFlags(SmartPropertyPrim.flagLayoutDirty);
             }
             }
 
 
         }
         }
@@ -86,7 +86,12 @@
 
 
             // Indirect child of Canvas
             // Indirect child of Canvas
             else {
             else {
-                prim.layoutArea = prim.parent.contentArea;
+                let contentArea = prim.parent.contentArea;
+
+                // Can be null if the parent's content area depend of its children, the computation will be done in many passes
+                if (contentArea) {
+                    prim.layoutArea = contentArea;
+                }
             }
             }
         }
         }
 
 
@@ -143,47 +148,89 @@
 
 
         private _isHorizontal: boolean = true;
         private _isHorizontal: boolean = true;
 
 
+        private static stackPanelLayoutArea = Size.Zero();
         private static dstOffset = Vector4.Zero();
         private static dstOffset = Vector4.Zero();
         private static dstArea = Size.Zero();
         private static dstArea = Size.Zero();
 
 
+        private static computeCounter = 0;
+
         public updateLayout(prim: Prim2DBase) {
         public updateLayout(prim: Prim2DBase) {
             if (prim._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
             if (prim._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
 
 
+                let primLayoutArea = prim.layoutArea;
+                let isSizeAuto = prim.isSizeAuto;
+
+                // If we're not in autoSize the layoutArea of the prim having the stack panel must be computed in order for us to compute the children' position.
+                // If there's at least one auto size (Horizontal or Vertical) we will have to figure the layoutArea ourselves
+                if (!primLayoutArea && !isSizeAuto) {
+                    return;
+                }
+
+//                console.log("Compute Stack Panel Layout " + ++StackPanelLayoutEngine.computeCounter);
+
                 let x = 0;
                 let x = 0;
                 let y = 0;
                 let y = 0;
-                let h = this.isHorizontal;
+                let horizonStackPanel = this.isHorizontal;
+
+                // If the stack panel is horizontal we check if the primitive height is auto or not, if it's auto then we have to compute the required height, otherwise we just take the actualHeight. If the stack panel is vertical we do the same but with width
                 let max = 0;
                 let max = 0;
 
 
+                let stackPanelLayoutArea = StackPanelLayoutEngine.stackPanelLayoutArea;
+                if (horizonStackPanel) {
+                    if (prim.isVerticalSizeAuto) {
+                        max = 0;
+                        stackPanelLayoutArea.height = 0;
+                    } else {
+                        max = prim.layoutArea.height;
+                        stackPanelLayoutArea.height = prim.layoutArea.height;
+                        stackPanelLayoutArea.width = 0;
+                    }
+                } else {
+                    if (prim.isHorizontalSizeAuto) {
+                        max = 0;
+                        stackPanelLayoutArea.width = 0;
+                    } else {
+                        max = prim.layoutArea.width;
+                        stackPanelLayoutArea.width = prim.layoutArea.width;
+                        stackPanelLayoutArea.height = 0;
+                    }
+                }
+
                 for (let child of prim.children) {
                 for (let child of prim.children) {
                     if (child._isFlagSet(SmartPropertyPrim.flagNoPartOfLayout)) {
                     if (child._isFlagSet(SmartPropertyPrim.flagNoPartOfLayout)) {
                         continue;
                         continue;
                     }
                     }
-                    let layoutArea: Size;
+
                     if (child._hasMargin) {
                     if (child._hasMargin) {
-                        child.margin.computeWithAlignment(prim.layoutArea, child.actualSize, child.marginAlignment, child.actualScale, StackPanelLayoutEngine.dstOffset, StackPanelLayoutEngine.dstArea, true);
-                        layoutArea = StackPanelLayoutEngine.dstArea.clone();
-                        child.layoutArea = layoutArea;
+
+                        // Calling computeWithAlignment will return us the area taken by "child" which is its layoutArea
+                        // We also have the dstOffset which will give us the y position in horizontal mode or x position in vertical mode.
+                        //  The alignment offset on the other axis is simply ignored as it doesn't make any sense (e.g. horizontal alignment is ignored in horizontal mode)
+                        child.margin.computeWithAlignment(stackPanelLayoutArea, child.actualSize, child.marginAlignment, child.actualScale, StackPanelLayoutEngine.dstOffset, StackPanelLayoutEngine.dstArea, true);
+
+                        child.layoutArea = StackPanelLayoutEngine.dstArea;
+
                     } else {
                     } else {
-                        layoutArea = child.layoutArea;
-                        child.margin.computeArea(child.actualSize, layoutArea);
+                        child.margin.computeArea(child.actualSize, child.actualScale, StackPanelLayoutEngine.dstArea);
+                        child.layoutArea = StackPanelLayoutEngine.dstArea;
                     }
                     }
 
 
-                    max = Math.max(max, h ? layoutArea.height : layoutArea.width);
-
+                    max = Math.max(max, horizonStackPanel ? StackPanelLayoutEngine.dstArea.height : StackPanelLayoutEngine.dstArea.width);
                 }
                 }
 
 
                 for (let child of prim.children) {
                 for (let child of prim.children) {
                     if (child._isFlagSet(SmartPropertyPrim.flagNoPartOfLayout)) {
                     if (child._isFlagSet(SmartPropertyPrim.flagNoPartOfLayout)) {
                         continue;
                         continue;
                     }
                     }
-                    child.layoutAreaPos = new Vector2(x, y);
 
 
                     let layoutArea = child.layoutArea;
                     let layoutArea = child.layoutArea;
 
 
-                    if (h) {
+                    if (horizonStackPanel) {
+                        child.layoutAreaPos = new Vector2(x, 0);
                         x += layoutArea.width;
                         x += layoutArea.width;
                         child.layoutArea = new Size(layoutArea.width, max);
                         child.layoutArea = new Size(layoutArea.width, max);
                     } else {
                     } else {
+                        child.layoutAreaPos = new Vector2(0, y);
                         y += layoutArea.height;
                         y += layoutArea.height;
                         child.layoutArea = new Size(max, layoutArea.height);
                         child.layoutArea = new Size(max, layoutArea.height);
                     }
                     }
@@ -333,7 +380,7 @@
                         child.margin.computeWithAlignment(prim.layoutArea, child.actualSize, child.marginAlignment, child.actualScale, GridPanelLayoutEngine.dstOffset, GridPanelLayoutEngine.dstArea, true);
                         child.margin.computeWithAlignment(prim.layoutArea, child.actualSize, child.marginAlignment, child.actualScale, GridPanelLayoutEngine.dstOffset, GridPanelLayoutEngine.dstArea, true);
                         child.layoutArea = GridPanelLayoutEngine.dstArea.clone();
                         child.layoutArea = GridPanelLayoutEngine.dstArea.clone();
                     } else {
                     } else {
-                        child.margin.computeArea(child.actualSize, child.layoutArea);
+                        child.margin.computeArea(child.actualSize, child.actualScale, child.layoutArea);
                     }
                     }
                 }
                 }
 
 

+ 1 - 16
canvas2D/src/Engine/babylon.ellipse2d.ts

@@ -168,21 +168,6 @@
         public static acutalSizeProperty: Prim2DPropInfo;
         public static acutalSizeProperty: Prim2DPropInfo;
         public static subdivisionsProperty: Prim2DPropInfo;
         public static subdivisionsProperty: Prim2DPropInfo;
 
 
-        @instanceLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 1, pi => Ellipse2D.acutalSizeProperty = pi, false, true)
-        /**
-         * Get/Set the size of the ellipse
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
-        }
-
-        public set actualSize(value: Size) {
-            this._actualSize = value;
-        }
-
         @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Ellipse2D.subdivisionsProperty = pi)
         @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Ellipse2D.subdivisionsProperty = pi)
         /**
         /**
          * Get/set the number of subdivisions used to draw the ellipsis. Default is 64.
          * Get/set the number of subdivisions used to draw the ellipsis. Default is 64.
@@ -289,7 +274,7 @@
             paddingLeft           ?: number | string,
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
         }) {
 
 
             // Avoid checking every time if the object exists
             // Avoid checking every time if the object exists

+ 2 - 45
canvas2D/src/Engine/babylon.group2d.ts

@@ -113,7 +113,7 @@
             paddingLeft             ?: number | string,
             paddingLeft             ?: number | string,
             paddingRight            ?: number | string,
             paddingRight            ?: number | string,
             paddingBottom           ?: number | string,
             paddingBottom           ?: number | string,
-            padding                 ?: string,
+            padding                 ?: number | string,
 
 
         }) {
         }) {
             if (settings == null) {
             if (settings == null) {
@@ -249,7 +249,7 @@
 
 
         @instanceLevelProperty(Prim2DBase.PRIM2DBASE_PROPCOUNT + 1, pi => Group2D.sizeProperty = pi, false, true)
         @instanceLevelProperty(Prim2DBase.PRIM2DBASE_PROPCOUNT + 1, pi => Group2D.sizeProperty = pi, false, true)
         public get size(): Size {
         public get size(): Size {
-            return this._size;
+            return this.internalGetSize();
         }
         }
 
 
         /**
         /**
@@ -264,49 +264,6 @@
             return this._viewportSize;
             return this._viewportSize;
         }
         }
 
 
-        @instanceLevelProperty(Prim2DBase.PRIM2DBASE_PROPCOUNT + 2, pi => Group2D.actualSizeProperty = pi)
-        /**
-         * Get the actual size of the group, if the size property is not null, this value will be the same, but if size is null, actualSize will return the size computed from the group's bounding content.
-         */
-        public get actualSize(): Size {
-            // The computed size will be floor on both width and height
-            let actualSize: Size;
-
-            // Return the actualSize if set
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-
-            // Return the size if set by the user
-            if (this._size) {
-                actualSize = new Size(Math.ceil(this._size.width), Math.ceil(this._size.height));
-            }
-
-            // Otherwise the size is computed based on the boundingInfo of the layout (or bounding info) content
-            else {
-                let m = this.layoutBoundingInfo.max();
-                actualSize = new Size(Math.ceil(m.x), Math.ceil(m.y));
-            }
-
-            // Compare the size with the one we previously had, if it differs we set the property dirty and trigger a GroupChanged to synchronize a displaySprite (if any)
-            if (!actualSize.equals(this._actualSize)) {
-                this.onPrimitivePropertyDirty(Group2D.actualSizeProperty.flagId);
-                this._actualSize = actualSize;
-                this.handleGroupChanged(Group2D.actualSizeProperty);
-            }
-
-            return actualSize;
-        }
-
-        public set actualSize(value: Size) {
-            if (!this._actualSize) {
-                this._actualSize = value.clone();
-            } else {
-                this._actualSize.copyFrom(value);
-            }
-        }
-
-
         /**
         /**
          * Get/set the Cache Behavior, used in case the Canvas Cache Strategy is set to CACHESTRATEGY_ALLGROUPS. Can be either GROUPCACHEBEHAVIOR_CACHEINPARENTGROUP, GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE or GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY. See their documentation for more information.
          * Get/set the Cache Behavior, used in case the Canvas Cache Strategy is set to CACHESTRATEGY_ALLGROUPS. Can be either GROUPCACHEBEHAVIOR_CACHEINPARENTGROUP, GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE or GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY. See their documentation for more information.
          * GROUPCACHEBEHAVIOR_NORESIZEONSCALE can also be set if you set it at creation time.
          * GROUPCACHEBEHAVIOR_NORESIZEONSCALE can also be set if you set it at creation time.

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

@@ -409,7 +409,7 @@
             paddingLeft           ?: number | string,
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
         }) {
 
 
             if (!settings) {
             if (!settings) {

File diff suppressed because it is too large
+ 649 - 284
canvas2D/src/Engine/babylon.prim2dBase.ts


+ 7 - 22
canvas2D/src/Engine/babylon.rectangle2d.ts

@@ -170,25 +170,6 @@
         public static notRoundedProperty: Prim2DPropInfo;
         public static notRoundedProperty: Prim2DPropInfo;
         public static roundRadiusProperty: Prim2DPropInfo;
         public static roundRadiusProperty: Prim2DPropInfo;
 
 
-        @instanceLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 1, pi => Rectangle2D.actualSizeProperty = pi, false, true)
-        /**
-         * Get/set the rectangle size (width/height)
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
-        }
-
-        public set actualSize(value: Size) {
-            if (!this._actualSize) {
-                this._actualSize = value.clone();
-            } else {
-                this._actualSize.copyFrom(value);
-            }
-        }
-
         @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Rectangle2D.notRoundedProperty = pi)
         @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Rectangle2D.notRoundedProperty = pi)
         /**
         /**
          * Get if the rectangle is notRound (returns true) or rounded (returns false).
          * Get if the rectangle is notRound (returns true) or rounded (returns false).
@@ -377,7 +358,7 @@
             paddingLeft           ?: number | string,
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
         }) {
 
 
             // Avoid checking every time if the object exists
             // Avoid checking every time if the object exists
@@ -577,15 +558,19 @@
             }
             }
         }
         }
 
 
-        protected _getActualSizeFromContentToRef(primSize: Size, newPrimSize: Size) {
+        protected _getActualSizeFromContentToRef(primSize: Size, paddingOffset: Vector4, newPrimSize: Size) {
             // Fall back to default implementation if there's no round Radius
             // Fall back to default implementation if there's no round Radius
             if (this._notRounded) {
             if (this._notRounded) {
-                super._getActualSizeFromContentToRef(primSize, newPrimSize);
+                super._getActualSizeFromContentToRef(primSize, paddingOffset, newPrimSize);
             } else {
             } else {
                 let rr = Math.round((this.roundRadius - (this.roundRadius / Math.sqrt(2))) * 1.3);
                 let rr = Math.round((this.roundRadius - (this.roundRadius / Math.sqrt(2))) * 1.3);
                 newPrimSize.copyFrom(primSize);
                 newPrimSize.copyFrom(primSize);
                 newPrimSize.width  += rr * 2;
                 newPrimSize.width  += rr * 2;
                 newPrimSize.height += rr * 2;
                 newPrimSize.height += rr * 2;
+                paddingOffset.x += rr;
+                paddingOffset.y += rr;
+                paddingOffset.z += rr;
+                paddingOffset.w += rr;
             }
             }
         }
         }
 
 

+ 19 - 19
canvas2D/src/Engine/babylon.renderablePrim2d.ts

@@ -960,25 +960,25 @@
             let w = size.width;
             let w = size.width;
             let h = size.height;
             let h = size.height;
             let invZBias = 1 / zBias;
             let invZBias = 1 / zBias;
-            let tx = new Vector4(t.m[0] * rgScale.x * 2/* / w*/, t.m[4] * rgScale.x * 2/* / w*/, 0/*t.m[8]*/, ((t.m[12] + offX) * rgScale.x * 2 / w) - 1);
-            let ty = new Vector4(t.m[1] * rgScale.y * 2/* / h*/, t.m[5] * rgScale.y * 2/* / h*/, 0/*t.m[9]*/, ((t.m[13] + offY) * rgScale.y * 2 / h) - 1);
-
-            if (!this.applyActualScaleOnTransform()) {
-                t.m[0] = tx.x, t.m[4] = tx.y, t.m[12] = tx.w;
-                t.m[1] = ty.x, t.m[5] = ty.y, t.m[13] = ty.w;
-                let las = this.actualScale;
-                t.decompose(RenderablePrim2D._s, RenderablePrim2D._r, RenderablePrim2D._t);
-                let scale = new Vector3(RenderablePrim2D._s.x / las.x, RenderablePrim2D._s.y / las.y, 1);
-                t = Matrix.Compose(scale, RenderablePrim2D._r, RenderablePrim2D._t);
-                tx = new Vector4(t.m[0], t.m[4], 0, t.m[12]);
-                ty = new Vector4(t.m[1], t.m[5], 0, t.m[13]);
-            }
-
-            tx.x /= w;
-            tx.y /= w;
-
-            ty.x /= h;
-            ty.y /= h;
+            let tx = new Vector4(t.m[0] * rgScale.x * 2 / w, t.m[4] * rgScale.x * 2 / w, 0/*t.m[8]*/, ((t.m[12] + offX) * rgScale.x * 2 / w) - 1);
+            let ty = new Vector4(t.m[1] * rgScale.y * 2 / h, t.m[5] * rgScale.y * 2 / h, 0/*t.m[9]*/, ((t.m[13] + offY) * rgScale.y * 2 / h) - 1);
+
+            //if (!this.applyActualScaleOnTransform()) {
+            //    t.m[0] = tx.x, t.m[4] = tx.y, t.m[12] = tx.w;
+            //    t.m[1] = ty.x, t.m[5] = ty.y, t.m[13] = ty.w;
+            //    let las = this.actualScale;
+            //    t.decompose(RenderablePrim2D._s, RenderablePrim2D._r, RenderablePrim2D._t);
+            //    let scale = new Vector3(RenderablePrim2D._s.x / las.x, RenderablePrim2D._s.y / las.y, 1);
+            //    t = Matrix.Compose(scale, RenderablePrim2D._r, RenderablePrim2D._t);
+            //    tx = new Vector4(t.m[0], t.m[4], 0, t.m[12]);
+            //    ty = new Vector4(t.m[1], t.m[5], 0, t.m[13]);
+            //}
+
+            //tx.x /= w;
+            //tx.y /= w;
+
+            //ty.x /= h;
+            //ty.y /= h;
 
 
             part.transformX = tx;
             part.transformX = tx;
             part.transformY = ty;
             part.transformY = ty;

+ 6 - 1
canvas2D/src/Engine/babylon.smartPropertyPrim.ts

@@ -1112,7 +1112,9 @@
                     curprim._setFlags(SmartPropertyPrim.flagBoundingInfoDirty);
                     curprim._setFlags(SmartPropertyPrim.flagBoundingInfoDirty);
                     if (curprim.isSizeAuto) {
                     if (curprim.isSizeAuto) {
                         curprim.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
                         curprim.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
-                        curprim._setFlags(SmartPropertyPrim.flagPositioningDirty);
+                        if (curprim._isFlagSet(SmartPropertyPrim.flagUsePositioning)) {
+                            curprim._setFlags(SmartPropertyPrim.flagPositioningDirty);
+                        }
                     }
                     }
 
 
                     if (curprim instanceof Group2D) {
                     if (curprim instanceof Group2D) {
@@ -1305,6 +1307,9 @@
         public static flagLayoutBoundingInfoDirty = 0x0200000;    // set if the layout bounding info is dirty
         public static flagLayoutBoundingInfoDirty = 0x0200000;    // set if the layout bounding info is dirty
         public static flagCollisionActor          = 0x0400000;    // set if the primitive is part of the collision engine
         public static flagCollisionActor          = 0x0400000;    // set if the primitive is part of the collision engine
         public static flagModelUpdate             = 0x0800000;    // set if the primitive's model data is to update
         public static flagModelUpdate             = 0x0800000;    // set if the primitive's model data is to update
+        public static flagLocalTransformDirty     = 0x1000000;    // set if the local transformation matrix must be recomputed
+        public static flagUsePositioning          = 0x2000000;    // set if the primitive rely on the positioning engine (padding or margin is used)
+        public static flagComputingPositioning    = 0x4000000;    // set if the positioning engine is computing the primitive, used to avoid re entrance
 
 
         private   _uid                : string;
         private   _uid                : string;
         private   _flags              : number;
         private   _flags              : number;

+ 1 - 19
canvas2D/src/Engine/babylon.sprite2d.ts

@@ -145,24 +145,6 @@
             this._updateSpriteScaleFactor();
             this._updateSpriteScaleFactor();
         }
         }
 
 
-        @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 3, pi => Sprite2D.actualSizeProperty = pi, false, true)
-        /**
-         * Get/set the actual size of the sprite to display
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
-        }
-
-        public set actualSize(value: Size) {
-            if (!this._actualSize) {
-                this._actualSize = value.clone();
-            } else {
-                this._actualSize.copyFrom(value);
-            }
-        }
 
 
         @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 4, pi => Sprite2D.spriteSizeProperty = pi, false, true)
         @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 4, pi => Sprite2D.spriteSizeProperty = pi, false, true)
         /**
         /**
@@ -363,7 +345,7 @@
             paddingLeft           ?: number | string,
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
         }) {
 
 
             if (!settings) {
             if (!settings) {

+ 16 - 9
canvas2D/src/Engine/babylon.text2d.ts

@@ -271,14 +271,12 @@
             return false;
             return false;
         }
         }
 
 
-        /**
-         * Get the actual size of the Text2D primitive
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
+        public get isVerticalSizeAuto(): boolean {
+            return false;
+        }
+
+        public get isHorizontalSizeAuto(): boolean {
+            return false;
         }
         }
 
 
         /**
         /**
@@ -301,6 +299,15 @@
             return this._textSize;
             return this._textSize;
         }
         }
 
 
+        protected onSetOwner() {
+            if (!this._textSize) {
+                this.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
+                this._setLayoutDirty();
+                this._positioningDirty();
+                this._actualSize = null;
+            }
+        }
+
         protected get fontTexture(): BaseFontTexture {
         protected get fontTexture(): BaseFontTexture {
             if (this._fontTexture) {
             if (this._fontTexture) {
                 return this._fontTexture;
                 return this._fontTexture;
@@ -437,7 +444,7 @@
             paddingLeft             ?: number | string,
             paddingLeft             ?: number | string,
             paddingRight            ?: number | string,
             paddingRight            ?: number | string,
             paddingBottom           ?: number | string,
             paddingBottom           ?: number | string,
-            padding                 ?: string,
+            padding                 ?: number | string,
             textAlignmentH          ?: number,
             textAlignmentH          ?: number,
             textAlignmentV          ?: number,
             textAlignmentV          ?: number,
             textAlignment           ?: string,
             textAlignment           ?: string,

+ 1 - 20
canvas2D/src/Engine/babylon.wireFrame2d.ts

@@ -233,25 +233,6 @@
             this.internalSetSize(value);
             this.internalSetSize(value);
         }
         }
 
 
-        @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 2, pi => WireFrame2D.actualSizeProperty = pi, false, true)
-        /**
-         * Get/set the actual size of the sprite to display
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
-        }
-
-        public set actualSize(value: Size) {
-            if (!this._actualSize) {
-                this._actualSize.clone();
-            } else {
-                this._actualSize.copyFrom(value);
-            }
-        }
-
         protected updateLevelBoundingInfo(): boolean {
         protected updateLevelBoundingInfo(): boolean {
             let v = this._computeMinMaxTrans();
             let v = this._computeMinMaxTrans();
             BoundingInfo2D.CreateFromMinMaxToRef(v.x, v.z, v.y, v.w, this._levelBoundingInfo);
             BoundingInfo2D.CreateFromMinMaxToRef(v.x, v.z, v.y, v.w, this._levelBoundingInfo);
@@ -337,7 +318,7 @@
             paddingLeft           ?: number | string,
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
         }) {
 
 
             if (!settings) {
             if (!settings) {

+ 582 - 0
canvas2D/src/Tools/babylon.math2D.ts

@@ -1,5 +1,545 @@
 module BABYLON {
 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;
+
+        constructor() {
+            this.translation = Vector2.Zero();
+            this.rotation = 0;
+            this.scale = new Vector2(1, 1);
+        }
+
+        /**
+         * 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);
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * 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);
+            }
+
+            return res;
+        }
+
+        /**
+         * 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);
+            }
+        }
+
+        /**
+         * 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;
+            }
+
+            return res;
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * Create a Transform2D containing only Zeroed values
+         */
+        public static Zero(): Transform2D {
+            let res = new Transform2D();
+            res.scale.copyFromFloats(0, 0);
+            return res;
+        }
+
+        /**
+         * 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);
+        }
+
+        public toMatrix2D(): Matrix2D {
+            let res = new Matrix2D();
+            this.toMatrix2DToRef(res);
+            return res;
+        }
+
+        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;
+
+            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;
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * 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);
+        }
+
+        /**
+         * 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);
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * 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);
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * 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);
+        }
+
+        /**
+         * 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);
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * 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;
+        }
+    }
+
+    /**
+     * 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 IdentityToRef(res: Matrix2D) {
+            res.m[1] = res.m[2] = res.m[4] = res.m[5] = 0;
+            res.m[0] = res.m[3] = 1;           
+        }
+
+        public copyFrom(other: Matrix2D) {
+            for (let i = 0; i < 6; i++) {
+                this.m[i] = other.m[i];
+            }
+        }
+
+        public determinant(): number {
+            return (this.m[0] * this.m[3]) - (this.m[1] * this.m[2]);
+        }
+
+        public invertToThis() {
+            this.invertToRef(this);
+        }
+
+        public invert(): Matrix2D {
+            let res = new Matrix2D();
+            this.invertToRef(res);
+            return res;
+        }
+
+        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 det21 = a21 * a10 - a11 * a20;
+
+            let det = (a00 * a11) - (a01 * a10);
+            if (det < (Epsilon*Epsilon)) {
+                throw new Error("Can't invert matrix, near null determinant");
+            }
+
+            det = 1 / det;
+
+            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;
+        }
+
+        public multiplyToThis(other: Matrix2D) {
+            this.multiplyToRef(other, this);
+        }
+
+        public multiply(other: Matrix2D): Matrix2D {
+            let res = new Matrix2D();
+            this.multiplyToRef(other, res);
+            return res;
+        }
+
+        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;
+        }
+
+        public transformFloats(x: number, y: number): Vector2 {
+            let res = Vector2.Zero();
+            this.transformFloatsToRef(x, y, res);
+            return res;
+        }
+
+        public transformFloatsToRef(x: number, y: number, r: Vector2) {
+            r.x = x * this.m[0] + y * this.m[2] + this.m[4];
+            r.y = x * this.m[1] + y * this.m[3] + this.m[5];
+        }
+
+        public transformPoint(p: Vector2): Vector2 {
+            let res = Vector2.Zero();
+            this.transformFloatsToRef(p.x, p.y, res);
+            return res;
+        }
+
+        public transformPointToRef(p: Vector2, r: Vector2) {
+            this.transformFloatsToRef(p.x, p.y, r);
+        }
+
+        public m = new Float32Array(6);
+    }
+
+    /**
+     * Stores information about a 2D Triangle.
+     * This class stores the 3 vertices but also the center and radius of the triangle
+     */
     export class Tri2DInfo {
     export class Tri2DInfo {
         /**
         /**
          * Construct an instance of Tri2DInfo, you can either pass null to a, b and c and the instance will be allocated "clear", or give actual triangle info and the center/radius will be computed
          * Construct an instance of Tri2DInfo, you can either pass null to a, b and c and the instance will be allocated "clear", or give actual triangle info and the center/radius will be computed
@@ -64,12 +604,22 @@
         }
         }
     }
     }
 
 
+    /**
+     * Stores an array of 2D Triangles.
+     * Internally the data is stored as a Float32Array to minimize the memory footprint.
+     * This can use the Tri2DInfo class as proxy for storing/retrieving data.
+     * The array can't grow, it's fixed size.
+     */
     export class Tri2DArray {
     export class Tri2DArray {
         constructor(count: number) {
         constructor(count: number) {
             this._count = count;
             this._count = count;
             this._array = new Float32Array(9 * count);
             this._array = new Float32Array(9 * count);
         }
         }
 
 
+        /**
+         * Clear the content and allocate a new array to store the given count of triangles
+         * @param count The new count of triangles to store
+         */
         public clear(count: number) {
         public clear(count: number) {
             if (this._count === count) {
             if (this._count === count) {
                 return;
                 return;
@@ -79,6 +629,13 @@
             this._array = new Float32Array(9 * count);
             this._array = new Float32Array(9 * count);
         }
         }
 
 
+        /**
+         * Store a given triangle at the given index
+         * @param index the 0 based index to store the triangle in the array
+         * @param a the A vertex of the triangle
+         * @param b the B vertex of the triangle
+         * @param c the C vertex of the triangle
+         */
         public storeTriangle(index: number, a: Vector2, b: Vector2, c: Vector2) {
         public storeTriangle(index: number, a: Vector2, b: Vector2, c: Vector2) {
             let center = new Vector2((a.x + b.x + c.x) / 3, (a.y + b.y + c.y) / 3);
             let center = new Vector2((a.x + b.x + c.x) / 3, (a.y + b.y + c.y) / 3);
 
 
@@ -123,6 +680,12 @@
             tri2dInfo.radius   = this._array[offset + 8];
             tri2dInfo.radius   = this._array[offset + 8];
         }
         }
 
 
+        /**
+         * Transform the given triangle and store its result in the array
+         * @param index The index to store the result to
+         * @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: Matrix) {
             if (index >= this._count) {
             if (index >= this._count) {
                 throw new Error(`Can't fetch the triangle at index ${index}, max index is ${this._count - 1}`);
                 throw new Error(`Can't fetch the triangle at index ${index}, max index is ${this._count - 1}`);
@@ -139,10 +702,19 @@
             tri2dInfo.transformInPlace(transform);
             tri2dInfo.transformInPlace(transform);
         }
         }
 
 
+        /**
+         * Get the element count that can be stored in this array
+         * @returns {} 
+         */
         public get count(): number {
         public get count(): number {
             return this._count;
             return this._count;
         }
         }
 
 
+        /**
+         * Check if a given point intersects with at least one of the triangles stored in the array.
+         * If true is returned the point is intersecting with at least one triangle, false if it doesn't intersect with any of them
+         * @param p The point to check
+         */
         public doesContain(p: Vector2): boolean {
         public doesContain(p: Vector2): boolean {
             Tri2DArray._checkInitStatics();
             Tri2DArray._checkInitStatics();
             let a = Tri2DArray.tempT[0];
             let a = Tri2DArray.tempT[0];
@@ -156,6 +728,13 @@
             return false;
             return false;
         }
         }
 
 
+        /**
+         * Make a intersection test between two sets of triangles. The triangles of setB will be transformed to the frame of reference of the setA using the given bToATransform matrix.
+         * If true is returned at least one triangle intersects with another of the other set, otherwise false is returned.
+         * @param setA The first set of triangles
+         * @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: Matrix): boolean {
             Tri2DArray._checkInitStatics();
             Tri2DArray._checkInitStatics();
 
 
@@ -209,6 +788,9 @@
         private static tempT: Tri2DInfo[] = null;
         private static tempT: Tri2DInfo[] = null;
     }
     }
 
 
+    /**
+     * Some 2D Math helpers functions
+     */
     class Math2D {
     class Math2D {
 
 
         static Dot(a: Vector2, b: Vector2): number {
         static Dot(a: Vector2, b: Vector2): number {

+ 288 - 25
dist/preview release/canvas2D/babylon.canvas2d.d.ts

@@ -1,4 +1,197 @@
 declare module BABYLON {
 declare 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.
+     */
+    class Transform2D {
+        /**
+         * A 2D Vector representing the translation to the origin
+         */
+        translation: Vector2;
+        /**
+         * A number (in radian) representing the rotation around the Z axis at the origin
+         */
+        rotation: number;
+        /**
+         * A 2D Vector representing the scale to apply at the origin
+         */
+        scale: Vector2;
+        constructor();
+        /**
+         * 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
+         */
+        set(translation: Vector2, rotation: number, scale: Vector2): void;
+        /**
+         * 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
+         */
+        setFromFloats(transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number): void;
+        /**
+         * Return a copy of the object
+         */
+        clone(): Transform2D;
+        /**
+         * Convert a given degree angle into its radian equivalent
+         * @param angleDegree the number to convert
+         */
+        static ToRadian(angleDegree: number): number;
+        /**
+         * 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)
+         */
+        static Make(translation?: Vector2, rotation?: number, scale?: Vector2): Transform2D;
+        /**
+         * 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)
+         */
+        static MakeToRef(res: Transform2D, translation?: Vector2, rotation?: number, scale?: Vector2): void;
+        /**
+         * 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
+         */
+        static MakeFromFloats(transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number): Transform2D;
+        /**
+         * 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
+         */
+        static MakeFromFloatsToRef(res: Transform2D, transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number): void;
+        /**
+         * Create a Transform2D containing only Zeroed values
+         */
+        static Zero(): Transform2D;
+        /**
+         * Copy the value of the other object into 'this'
+         * @param other The other object to copy values from
+         */
+        copyFrom(other: Transform2D): void;
+        toMatrix2D(): Matrix2D;
+        toMatrix2DToRef(res: Matrix2D): void;
+        /**
+         * In place transformation from a parent matrix.
+         * @param parent transform object. "this" will be the result of parent * this
+         */
+        multiplyToThis(parent: Transform2D): void;
+        /**
+         * Transform this object with a parent and return the result. Result = parent * this
+         * @param parent The parent transformation
+         */
+        multiply(parent: Transform2D): Transform2D;
+        /**
+         * 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
+         */
+        transformPointInPlace(p: Vector2): void;
+        /**
+         * 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'.
+         */
+        transformPointToRef(p: Vector2, res: Vector2): void;
+        /**
+         * 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'
+         */
+        multiplyToRef(parent: Transform2D, result: Transform2D): void;
+        /**
+         * 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
+         */
+        transformFloatsToRef(x: number, y: number, res: Vector2): void;
+        /**
+         * 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.
+         */
+        invertTransformFloatsToRef(x: number, y: number, res: Vector2): void;
+        /**
+         * Transform a point and return the result
+         * @param p the point to transform
+         */
+        transformPoint(p: Vector2): Vector2;
+        /**
+         * 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
+         */
+        transformFloats(x: number, y: number): Vector2;
+        /**
+         * 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
+         */
+        invertTransformPointInPlace(p: Vector2): void;
+        /**
+         * 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'
+         */
+        invertTransformPointToRef(p: Vector2, res: Vector2): void;
+        /**
+         * Invert transform a given point and return the result. return = invert(this) * p
+         * @param p The Point to transform
+         */
+        invertTransformPoint(p: Vector2): Vector2;
+        /**
+         * 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
+         */
+        invertTransformFloats(x: number, y: number): Vector2;
+    }
+    /**
+     * 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.
+     */
+    class Matrix2D {
+        static Identity(): Matrix2D;
+        static IdentityToRef(res: Matrix2D): void;
+        copyFrom(other: Matrix2D): void;
+        determinant(): number;
+        invertToThis(): void;
+        invert(): Matrix2D;
+        invertToRef(res: Matrix2D): void;
+        multiplyToThis(other: Matrix2D): void;
+        multiply(other: Matrix2D): Matrix2D;
+        multiplyToRef(other: Matrix2D, result: Matrix2D): void;
+        transformFloats(x: number, y: number): Vector2;
+        transformFloatsToRef(x: number, y: number, r: Vector2): void;
+        transformPoint(p: Vector2): Vector2;
+        transformPointToRef(p: Vector2, r: Vector2): void;
+        m: Float32Array;
+    }
+    /**
+     * Stores information about a 2D Triangle.
+     * This class stores the 3 vertices but also the center and radius of the triangle
+     */
     class Tri2DInfo {
     class Tri2DInfo {
         /**
         /**
          * Construct an instance of Tri2DInfo, you can either pass null to a, b and c and the instance will be allocated "clear", or give actual triangle info and the center/radius will be computed
          * Construct an instance of Tri2DInfo, you can either pass null to a, b and c and the instance will be allocated "clear", or give actual triangle info and the center/radius will be computed
@@ -15,9 +208,26 @@ declare module BABYLON {
         doesContain(p: Vector2): boolean;
         doesContain(p: Vector2): boolean;
         private _updateCenterRadius();
         private _updateCenterRadius();
     }
     }
+    /**
+     * Stores an array of 2D Triangles.
+     * Internally the data is stored as a Float32Array to minimize the memory footprint.
+     * This can use the Tri2DInfo class as proxy for storing/retrieving data.
+     * The array can't grow, it's fixed size.
+     */
     class Tri2DArray {
     class Tri2DArray {
         constructor(count: number);
         constructor(count: number);
+        /**
+         * Clear the content and allocate a new array to store the given count of triangles
+         * @param count The new count of triangles to store
+         */
         clear(count: number): void;
         clear(count: number): void;
+        /**
+         * Store a given triangle at the given index
+         * @param index the 0 based index to store the triangle in the array
+         * @param a the A vertex of the triangle
+         * @param b the B vertex of the triangle
+         * @param c the C vertex of the triangle
+         */
         storeTriangle(index: number, a: Vector2, b: Vector2, c: Vector2): void;
         storeTriangle(index: number, a: Vector2, b: Vector2, c: Vector2): void;
         /**
         /**
          * Store a triangle in a Tri2DInfo object
          * Store a triangle in a Tri2DInfo object
@@ -25,9 +235,31 @@ declare module BABYLON {
          * @param tri2dInfo the instance that will contain the data, it must be already allocated with its inner object also allocated
          * @param tri2dInfo the instance that will contain the data, it must be already allocated with its inner object also allocated
          */
          */
         storeToTri2DInfo(index: number, tri2dInfo: Tri2DInfo): void;
         storeToTri2DInfo(index: number, tri2dInfo: Tri2DInfo): void;
+        /**
+         * Transform the given triangle and store its result in the array
+         * @param index The index to store the result to
+         * @param tri2dInfo The triangle to transform
+         * @param transform The transformation matrix
+         */
         transformAndStoreToTri2DInfo(index: number, tri2dInfo: Tri2DInfo, transform: Matrix): void;
         transformAndStoreToTri2DInfo(index: number, tri2dInfo: Tri2DInfo, transform: Matrix): void;
+        /**
+         * Get the element count that can be stored in this array
+         * @returns {}
+         */
         readonly count: number;
         readonly count: number;
+        /**
+         * Check if a given point intersects with at least one of the triangles stored in the array.
+         * If true is returned the point is intersecting with at least one triangle, false if it doesn't intersect with any of them
+         * @param p The point to check
+         */
         doesContain(p: Vector2): boolean;
         doesContain(p: Vector2): boolean;
+        /**
+         * Make a intersection test between two sets of triangles. The triangles of setB will be transformed to the frame of reference of the setA using the given bToATransform matrix.
+         * If true is returned at least one triangle intersects with another of the other set, otherwise false is returned.
+         * @param setA The first set of triangles
+         * @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
+         */
         static doesIntersect(setA: Tri2DArray, setB: Tri2DArray, bToATransform: Matrix): boolean;
         static doesIntersect(setA: Tri2DArray, setB: Tri2DArray, bToATransform: Matrix): boolean;
         private static _checkInitStatics();
         private static _checkInitStatics();
         private _count;
         private _count;
@@ -712,6 +944,7 @@ declare module BABYLON {
         clone(): BoundingInfo2D;
         clone(): BoundingInfo2D;
         clear(): void;
         clear(): void;
         copyFrom(src: BoundingInfo2D): void;
         copyFrom(src: BoundingInfo2D): void;
+        equals(other: BoundingInfo2D): boolean;
         /**
         /**
          * return the max extend of the bounding info
          * return the max extend of the bounding info
          */
          */
@@ -898,8 +1131,10 @@ declare module BABYLON {
         private static _vertical;
         private static _vertical;
         isHorizontal: boolean;
         isHorizontal: boolean;
         private _isHorizontal;
         private _isHorizontal;
+        private static stackPanelLayoutArea;
         private static dstOffset;
         private static dstOffset;
         private static dstArea;
         private static dstArea;
+        private static computeCounter;
         updateLayout(prim: Prim2DBase): void;
         updateLayout(prim: Prim2DBase): void;
         readonly isChildPositionAllowed: boolean;
         readonly isChildPositionAllowed: boolean;
     }
     }
@@ -1403,6 +1638,9 @@ declare module BABYLON {
         static flagLayoutBoundingInfoDirty: number;
         static flagLayoutBoundingInfoDirty: number;
         static flagCollisionActor: number;
         static flagCollisionActor: number;
         static flagModelUpdate: number;
         static flagModelUpdate: number;
+        static flagLocalTransformDirty: number;
+        static flagUsePositioning: number;
+        static flagComputingPositioning: number;
         private _uid;
         private _uid;
         private _flags;
         private _flags;
         private _modelKey;
         private _modelKey;
@@ -1677,6 +1915,7 @@ declare module BABYLON {
          */
          */
         fromString(value: string): void;
         fromString(value: string): void;
         copyFrom(pa: PrimitiveAlignment): void;
         copyFrom(pa: PrimitiveAlignment): void;
+        clone(): PrimitiveAlignment;
         readonly isDefault: boolean;
         readonly isDefault: boolean;
     }
     }
     /**
     /**
@@ -1821,6 +2060,9 @@ declare module BABYLON {
         static Inherit: number;
         static Inherit: number;
         static Percentage: number;
         static Percentage: number;
         static Pixel: number;
         static Pixel: number;
+        static ComputeH: number;
+        static ComputeV: number;
+        static ComputeAll: number;
         private _computePixels(index, sourceArea, emitChanged);
         private _computePixels(index, sourceArea, emitChanged);
         private onChangeCallback();
         private onChangeCallback();
         /**
         /**
@@ -1831,21 +2073,21 @@ declare module BABYLON {
          * @param dstOffset the position of the content, x, y, z, w are left, bottom, right, top
          * @param dstOffset the position of the content, x, y, z, w are left, bottom, right, top
          * @param dstArea the new size of the content
          * @param dstArea the new size of the content
          */
          */
-        computeWithAlignment(sourceArea: Size, contentSize: Size, alignment: PrimitiveAlignment, contentScale: Vector2, dstOffset: Vector4, dstArea: Size, computeLayoutArea?: boolean): void;
+        computeWithAlignment(sourceArea: Size, contentSize: Size, alignment: PrimitiveAlignment, contentScale: Vector2, dstOffset: Vector4, dstArea: Size, computeLayoutArea?: boolean, computeAxis?: number): void;
         /**
         /**
          * Compute an area and its position considering this thickness properties based on a given source area
          * Compute an area and its position considering this thickness properties based on a given source area
          * @param sourceArea the source area
          * @param sourceArea the source area
          * @param dstOffset the position of the resulting area
          * @param dstOffset the position of the resulting area
          * @param dstArea the size of the resulting area
          * @param dstArea the size of the resulting area
          */
          */
-        compute(sourceArea: Size, dstOffset: Vector4, dstArea: Size): void;
+        compute(sourceArea: Size, sourceAreaScale: Vector2, dstOffset: Vector4, dstArea: Size, computeLayoutArea?: boolean): void;
         /**
         /**
          * Compute an area considering this thickness properties based on a given source area
          * Compute an area considering this thickness properties based on a given source area
          * @param sourceArea the source area
          * @param sourceArea the source area
          * @param result the resulting area
          * @param result the resulting area
          */
          */
-        computeArea(sourceArea: Size, result: Size): void;
-        enlarge(sourceArea: Size, dstOffset: Vector4, enlargedArea: Size): void;
+        computeArea(sourceArea: Size, sourceScale: Vector2, result: Size): void;
+        enlarge(sourceArea: Size, sourceScale: Vector2, dstOffset: Vector4, enlargedArea: Size): void;
     }
     }
     /**
     /**
      * Main class used for the Primitive Intersection API
      * Main class used for the Primitive Intersection API
@@ -1919,7 +2161,7 @@ declare module BABYLON {
             paddingLeft?: number | string;
             paddingLeft?: number | string;
             paddingRight?: number | string;
             paddingRight?: number | string;
             paddingBottom?: number | string;
             paddingBottom?: number | string;
-            padding?: string;
+            padding?: number | string;
         });
         });
         /**
         /**
          * Return the ChangedDictionary observable of the StringDictionary containing the primitives intersecting with this one
          * Return the ChangedDictionary observable of the StringDictionary containing the primitives intersecting with this one
@@ -2059,6 +2301,7 @@ declare module BABYLON {
          */
          */
         actualPosition: Vector2;
         actualPosition: Vector2;
         private static _nullPosition;
         private static _nullPosition;
+        private static _nullSize;
         /**
         /**
          * Shortcut to actualPosition.x
          * Shortcut to actualPosition.x
          */
          */
@@ -2160,6 +2403,7 @@ declare module BABYLON {
          * Check if there a marginAlignment specified (non null and not default)
          * Check if there a marginAlignment specified (non null and not default)
          */
          */
         readonly _hasMarginAlignment: boolean;
         readonly _hasMarginAlignment: boolean;
+        protected _updatePositioningState(): void;
         opacity: number;
         opacity: number;
         scaleX: number;
         scaleX: number;
         scaleY: number;
         scaleY: number;
@@ -2236,10 +2480,12 @@ declare module BABYLON {
          * Get the local transformation of the primitive
          * Get the local transformation of the primitive
          */
          */
         readonly localTransform: Matrix;
         readonly localTransform: Matrix;
+        readonly localLayoutTransform: Matrix;
         private static _bMinMax;
         private static _bMinMax;
         private static _bMax;
         private static _bMax;
         private static _bSize;
         private static _bSize;
         private static _tpsBB;
         private static _tpsBB;
+        private static _tpsBB2;
         /**
         /**
          * Get the boundingInfo associated to the primitive and its children.
          * Get the boundingInfo associated to the primitive and its children.
          * The value is supposed to be always up to date
          * The value is supposed to be always up to date
@@ -2257,6 +2503,18 @@ declare module BABYLON {
          */
          */
         readonly isSizeAuto: boolean;
         readonly isSizeAuto: boolean;
         /**
         /**
+         * Determine if the horizontal size is automatically computed or fixed because manually specified.
+         * Use the actualSize property to get the final/real size of the primitive
+         * @returns true if the horizontal size is automatically computed, false if it were manually specified.
+         */
+        readonly isHorizontalSizeAuto: boolean;
+        /**
+         * Determine if the vertical size is automatically computed or fixed because manually specified.
+         * Use the actualSize property to get the final/real size of the primitive
+         * @returns true if the vertical size is automatically computed, false if it were manually specified.
+         */
+        readonly isVerticalSizeAuto: boolean;
+        /**
          * Return true if this prim has an auto size which is set by the children's global bounding box
          * Return true if this prim has an auto size which is set by the children's global bounding box
          */
          */
         readonly isSizedByContent: boolean;
         readonly isSizedByContent: boolean;
@@ -2346,20 +2604,26 @@ declare module BABYLON {
         private static _t1;
         private static _t1;
         private static _t2;
         private static _t2;
         private static _v0;
         private static _v0;
+        private static _v30;
         private _updateLocalTransform();
         private _updateLocalTransform();
         private static _transMtx;
         private static _transMtx;
+        private static _transTT;
         protected updateCachedStates(recurse: boolean): void;
         protected updateCachedStates(recurse: boolean): void;
         private static _icPos;
         private static _icPos;
         private static _icZone;
         private static _icZone;
         private static _icArea;
         private static _icArea;
         private static _size;
         private static _size;
+        private static _size2;
+        private static _curContentArea;
         private _updatePositioning();
         private _updatePositioning();
         /**
         /**
-         * Get the content are of this primitive, this area is computed using the padding property and also possibly the primitive type itself.
+         * Get the content are of this primitive, this area is computed the primitive size and using the padding property.
          * Children of this primitive will be positioned relative to the bottom/left corner of this area.
          * Children of this primitive will be positioned relative to the bottom/left corner of this area.
          */
          */
         readonly contentArea: Size;
         readonly contentArea: Size;
+        readonly marginSize: Size;
         _patchHierarchy(owner: Canvas2D): void;
         _patchHierarchy(owner: Canvas2D): void;
+        protected onSetOwner(): void;
         private static _zOrderChangedNotifList;
         private static _zOrderChangedNotifList;
         private static _zRebuildReentrency;
         private static _zRebuildReentrency;
         private _updateZOrder();
         private _updateZOrder();
@@ -2383,7 +2647,7 @@ declare module BABYLON {
          * @param primSize the current size of the primitive
          * @param primSize the current size of the primitive
          * @param newPrimSize the new size of the primitive. PLEASE ROUND THE values, we're talking about pixels and fraction of them are not our friends!
          * @param newPrimSize the new size of the primitive. PLEASE ROUND THE values, we're talking about pixels and fraction of them are not our friends!
          */
          */
-        protected _getActualSizeFromContentToRef(primSize: Size, newPrimSize: Size): void;
+        protected _getActualSizeFromContentToRef(primSize: Size, paddingOffset: Vector4, newPrimSize: Size): void;
         /**
         /**
          * Get/set the layout data to use for this primitive.
          * Get/set the layout data to use for this primitive.
          */
          */
@@ -2409,7 +2673,7 @@ declare module BABYLON {
         private _actualPosition;
         private _actualPosition;
         protected _size: Size;
         protected _size: Size;
         protected _actualSize: Size;
         protected _actualSize: Size;
-        _boundingSize: Size;
+        private _internalSize;
         protected _minSize: Size;
         protected _minSize: Size;
         protected _maxSize: Size;
         protected _maxSize: Size;
         protected _desiredSize: Size;
         protected _desiredSize: Size;
@@ -2423,6 +2687,7 @@ declare module BABYLON {
         private _layoutArea;
         private _layoutArea;
         private _layoutData;
         private _layoutData;
         private _contentArea;
         private _contentArea;
+        private _marginSize;
         private _rotation;
         private _rotation;
         private _scale;
         private _scale;
         private _origin;
         private _origin;
@@ -2436,6 +2701,7 @@ declare module BABYLON {
         protected _globalTransformStep: number;
         protected _globalTransformStep: number;
         protected _globalTransformProcessStep: number;
         protected _globalTransformProcessStep: number;
         protected _localTransform: Matrix;
         protected _localTransform: Matrix;
+        protected _localLayoutTransform: Matrix;
         protected _globalTransform: Matrix;
         protected _globalTransform: Matrix;
         protected _invGlobalTransform: Matrix;
         protected _invGlobalTransform: Matrix;
         protected _primTriArrayDirty: boolean;
         protected _primTriArrayDirty: boolean;
@@ -2816,7 +3082,7 @@ declare module BABYLON {
             paddingLeft?: number | string;
             paddingLeft?: number | string;
             paddingRight?: number | string;
             paddingRight?: number | string;
             paddingBottom?: number | string;
             paddingBottom?: number | string;
-            padding?: string;
+            padding?: number | string;
         });
         });
         static _createCachedCanvasGroup(owner: Canvas2D): Group2D;
         static _createCachedCanvasGroup(owner: Canvas2D): Group2D;
         protected applyCachedTexture(vertexData: VertexData, material: StandardMaterial): void;
         protected applyCachedTexture(vertexData: VertexData, material: StandardMaterial): void;
@@ -2853,7 +3119,6 @@ declare module BABYLON {
          */
          */
         size: Size;
         size: Size;
         readonly viewportSize: ISize;
         readonly viewportSize: ISize;
-        actualSize: Size;
         /**
         /**
          * Get/set the Cache Behavior, used in case the Canvas Cache Strategy is set to CACHESTRATEGY_ALLGROUPS. Can be either GROUPCACHEBEHAVIOR_CACHEINPARENTGROUP, GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE or GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY. See their documentation for more information.
          * Get/set the Cache Behavior, used in case the Canvas Cache Strategy is set to CACHESTRATEGY_ALLGROUPS. Can be either GROUPCACHEBEHAVIOR_CACHEINPARENTGROUP, GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE or GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY. See their documentation for more information.
          * GROUPCACHEBEHAVIOR_NORESIZEONSCALE can also be set if you set it at creation time.
          * GROUPCACHEBEHAVIOR_NORESIZEONSCALE can also be set if you set it at creation time.
@@ -3003,7 +3268,6 @@ declare module BABYLON {
          */
          */
         wireFrameGroupsDirty(): void;
         wireFrameGroupsDirty(): void;
         size: Size;
         size: Size;
-        actualSize: Size;
         protected updateLevelBoundingInfo(): boolean;
         protected updateLevelBoundingInfo(): boolean;
         protected levelIntersect(intersectInfo: IntersectInfo2D): boolean;
         protected levelIntersect(intersectInfo: IntersectInfo2D): boolean;
         /**
         /**
@@ -3079,7 +3343,7 @@ declare module BABYLON {
             paddingLeft?: number | string;
             paddingLeft?: number | string;
             paddingRight?: number | string;
             paddingRight?: number | string;
             paddingBottom?: number | string;
             paddingBottom?: number | string;
-            padding?: string;
+            padding?: number | string;
         });
         });
         /**
         /**
          * Get/set if the sprite rendering should be aligned to the target rendering device pixel or not
          * Get/set if the sprite rendering should be aligned to the target rendering device pixel or not
@@ -3128,7 +3392,6 @@ declare module BABYLON {
         static actualSizeProperty: Prim2DPropInfo;
         static actualSizeProperty: Prim2DPropInfo;
         static notRoundedProperty: Prim2DPropInfo;
         static notRoundedProperty: Prim2DPropInfo;
         static roundRadiusProperty: Prim2DPropInfo;
         static roundRadiusProperty: Prim2DPropInfo;
-        actualSize: Size;
         notRounded: boolean;
         notRounded: boolean;
         roundRadius: number;
         roundRadius: number;
         private static _i0;
         private static _i0;
@@ -3216,14 +3479,14 @@ declare module BABYLON {
             paddingLeft?: number | string;
             paddingLeft?: number | string;
             paddingRight?: number | string;
             paddingRight?: number | string;
             paddingBottom?: number | string;
             paddingBottom?: number | string;
-            padding?: string;
+            padding?: number | string;
         });
         });
         static roundSubdivisions: number;
         static roundSubdivisions: number;
         protected createModelRenderCache(modelKey: string): ModelRenderCache;
         protected createModelRenderCache(modelKey: string): ModelRenderCache;
         protected updateTriArray(): void;
         protected updateTriArray(): void;
         protected setupModelRenderCache(modelRenderCache: ModelRenderCache): Rectangle2DRenderCache;
         protected setupModelRenderCache(modelRenderCache: ModelRenderCache): Rectangle2DRenderCache;
         protected _getInitialContentAreaToRef(primSize: Size, initialContentPosition: Vector4, initialContentArea: Size): void;
         protected _getInitialContentAreaToRef(primSize: Size, initialContentPosition: Vector4, initialContentArea: Size): void;
-        protected _getActualSizeFromContentToRef(primSize: Size, newPrimSize: Size): void;
+        protected _getActualSizeFromContentToRef(primSize: Size, paddingOffset: Vector4, newPrimSize: Size): void;
         protected createInstanceDataParts(): InstanceDataBase[];
         protected createInstanceDataParts(): InstanceDataBase[];
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean;
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean;
         private _notRounded;
         private _notRounded;
@@ -3257,7 +3520,6 @@ declare module BABYLON {
     class Ellipse2D extends Shape2D {
     class Ellipse2D extends Shape2D {
         static acutalSizeProperty: Prim2DPropInfo;
         static acutalSizeProperty: Prim2DPropInfo;
         static subdivisionsProperty: Prim2DPropInfo;
         static subdivisionsProperty: Prim2DPropInfo;
-        actualSize: Size;
         subdivisions: number;
         subdivisions: number;
         protected levelIntersect(intersectInfo: IntersectInfo2D): boolean;
         protected levelIntersect(intersectInfo: IntersectInfo2D): boolean;
         protected updateLevelBoundingInfo(): boolean;
         protected updateLevelBoundingInfo(): boolean;
@@ -3341,7 +3603,7 @@ declare module BABYLON {
             paddingLeft?: number | string;
             paddingLeft?: number | string;
             paddingRight?: number | string;
             paddingRight?: number | string;
             paddingBottom?: number | string;
             paddingBottom?: number | string;
-            padding?: string;
+            padding?: number | string;
         });
         });
         protected updateTriArray(): void;
         protected updateTriArray(): void;
         protected createModelRenderCache(modelKey: string): ModelRenderCache;
         protected createModelRenderCache(modelKey: string): ModelRenderCache;
@@ -3378,7 +3640,6 @@ declare module BABYLON {
         texture: Texture;
         texture: Texture;
         useAlphaFromTexture: boolean;
         useAlphaFromTexture: boolean;
         size: Size;
         size: Size;
-        actualSize: Size;
         spriteSize: Size;
         spriteSize: Size;
         spriteLocation: Vector2;
         spriteLocation: Vector2;
         spriteFrame: number;
         spriteFrame: number;
@@ -3478,7 +3739,7 @@ declare module BABYLON {
             paddingLeft?: number | string;
             paddingLeft?: number | string;
             paddingRight?: number | string;
             paddingRight?: number | string;
             paddingBottom?: number | string;
             paddingBottom?: number | string;
-            padding?: string;
+            padding?: number | string;
         });
         });
         protected createModelRenderCache(modelKey: string): ModelRenderCache;
         protected createModelRenderCache(modelKey: string): ModelRenderCache;
         protected setupModelRenderCache(modelRenderCache: ModelRenderCache): Sprite2DRenderCache;
         protected setupModelRenderCache(modelRenderCache: ModelRenderCache): Sprite2DRenderCache;
@@ -3736,14 +3997,13 @@ declare module BABYLON {
         readonly fontSuperSample: boolean;
         readonly fontSuperSample: boolean;
         readonly fontSignedDistanceField: boolean;
         readonly fontSignedDistanceField: boolean;
         readonly isSizeAuto: boolean;
         readonly isSizeAuto: boolean;
-        /**
-         * Get the actual size of the Text2D primitive
-         */
-        readonly actualSize: Size;
+        readonly isVerticalSizeAuto: boolean;
+        readonly isHorizontalSizeAuto: boolean;
         /**
         /**
          * Get the area that bounds the text associated to the primitive
          * Get the area that bounds the text associated to the primitive
          */
          */
         readonly textSize: Size;
         readonly textSize: Size;
+        protected onSetOwner(): void;
         protected readonly fontTexture: BaseFontTexture;
         protected readonly fontTexture: BaseFontTexture;
         /**
         /**
          * Dispose the primitive, remove it from its parent
          * Dispose the primitive, remove it from its parent
@@ -3840,7 +4100,7 @@ declare module BABYLON {
             paddingLeft?: number | string;
             paddingLeft?: number | string;
             paddingRight?: number | string;
             paddingRight?: number | string;
             paddingBottom?: number | string;
             paddingBottom?: number | string;
-            padding?: string;
+            padding?: number | string;
             textAlignmentH?: number;
             textAlignmentH?: number;
             textAlignmentV?: number;
             textAlignmentV?: number;
             textAlignment?: string;
             textAlignment?: string;
@@ -4033,7 +4293,7 @@ declare module BABYLON {
             paddingLeft?: number | string;
             paddingLeft?: number | string;
             paddingRight?: number | string;
             paddingRight?: number | string;
             paddingBottom?: number | string;
             paddingBottom?: number | string;
-            padding?: string;
+            padding?: number | string;
         });
         });
         protected createModelRenderCache(modelKey: string): ModelRenderCache;
         protected createModelRenderCache(modelKey: string): ModelRenderCache;
         private _perp(v, res);
         private _perp(v, res);
@@ -4154,6 +4414,7 @@ declare module BABYLON {
         readonly updateLocalTransformCounter: PerfCounter;
         readonly updateLocalTransformCounter: PerfCounter;
         readonly updateGlobalTransformCounter: PerfCounter;
         readonly updateGlobalTransformCounter: PerfCounter;
         readonly boundingInfoRecomputeCounter: PerfCounter;
         readonly boundingInfoRecomputeCounter: PerfCounter;
+        readonly layoutBoundingInfoUpdateCounter: PerfCounter;
         static readonly instances: Array<Canvas2D>;
         static readonly instances: Array<Canvas2D>;
         readonly primitiveCollisionManager: PrimitiveCollisionManagerBase;
         readonly primitiveCollisionManager: PrimitiveCollisionManagerBase;
         protected _canvasPreInit(settings: any): void;
         protected _canvasPreInit(settings: any): void;
@@ -4292,6 +4553,7 @@ declare module BABYLON {
         addUpdatePositioningCounter(count: number): void;
         addUpdatePositioningCounter(count: number): void;
         addupdateLocalTransformCounter(count: number): void;
         addupdateLocalTransformCounter(count: number): void;
         addUpdateGlobalTransformCounter(count: number): void;
         addUpdateGlobalTransformCounter(count: number): void;
+        addLayoutBoundingInfoUpdateCounter(count: number): void;
         private _renderObservable;
         private _renderObservable;
         private __engineData;
         private __engineData;
         private _interactionEnabled;
         private _interactionEnabled;
@@ -4346,6 +4608,7 @@ declare module BABYLON {
         private _updateGlobalTransformCounter;
         private _updateGlobalTransformCounter;
         private _updateLocalTransformCounter;
         private _updateLocalTransformCounter;
         private _boundingInfoRecomputeCounter;
         private _boundingInfoRecomputeCounter;
+        private _layoutBoundingInfoUpdateCounter;
         private _profilingCanvas;
         private _profilingCanvas;
         private _profileInfoText;
         private _profileInfoText;
         private static _v;
         private static _v;

File diff suppressed because it is too large
+ 1342 - 507
dist/preview release/canvas2D/babylon.canvas2d.js


File diff suppressed because it is too large
+ 12 - 12
dist/preview release/canvas2D/babylon.canvas2d.min.js