소스 검색

Merge pull request #7534 from Popov72/scrollviewer-optimization

Scroll Viewer rendering optimization
David Catuhe 5 년 전
부모
커밋
12531732fe

+ 1 - 0
dist/preview release/what's new.md

@@ -219,6 +219,7 @@
 - Added `StackPanel.ignoreLayoutWarnings` to disable console warnings when controls with percentage size are added to a StackPanel ([Deltakosh](https://github.com/deltakosh/))
 - Added `StackPanel.ignoreLayoutWarnings` to disable console warnings when controls with percentage size are added to a StackPanel ([Deltakosh](https://github.com/deltakosh/))
 - Added `_getSVGAttribs` functionality for loading multiple svg icons from an external svg file via icon id. Fixed bug for Chrome. Strip icon id from image url for firefox.([lockphase](https://github.com/lockphase/))
 - Added `_getSVGAttribs` functionality for loading multiple svg icons from an external svg file via icon id. Fixed bug for Chrome. Strip icon id from image url for firefox.([lockphase](https://github.com/lockphase/))
 - Scroll Viewer extended to include the use of images in the scroll bars([JohnK](https://github.com/BabylonJSGuide/))
 - Scroll Viewer extended to include the use of images in the scroll bars([JohnK](https://github.com/BabylonJSGuide/))
+- Added `ScrollViewer.freezeControls` property to speed up rendering ([Popov72](https://github.com/Popov72))
 
 
 ### Particles
 ### Particles
 
 

+ 2 - 0
gui/src/2D/advancedDynamicTexture.ts

@@ -550,6 +550,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         // Layout
         // Layout
         this.onBeginLayoutObservable.notifyObservers(this);
         this.onBeginLayoutObservable.notifyObservers(this);
         var measure = new Measure(0, 0, renderWidth, renderHeight);
         var measure = new Measure(0, 0, renderWidth, renderHeight);
+        Control.NumLayoutCalls = 0;
         this._rootContainer._layout(measure, context);
         this._rootContainer._layout(measure, context);
         this.onEndLayoutObservable.notifyObservers(this);
         this.onEndLayoutObservable.notifyObservers(this);
         this._isDirty = false; // Restoring the dirty state that could have been set by controls during layout processing
         this._isDirty = false; // Restoring the dirty state that could have been set by controls during layout processing
@@ -570,6 +571,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
 
 
         // Render
         // Render
         this.onBeginRenderObservable.notifyObservers(this);
         this.onBeginRenderObservable.notifyObservers(this);
+        Control.NumRenderCalls = 0;
         this._rootContainer._render(context, this._invalidatedRectangle);
         this._rootContainer._render(context, this._invalidatedRectangle);
         this.onEndRenderObservable.notifyObservers(this);
         this.onEndRenderObservable.notifyObservers(this);
         this._invalidatedRectangle = null;
         this._invalidatedRectangle = null;

+ 3 - 1
gui/src/2D/controls/container.ts

@@ -12,7 +12,7 @@ import { _TypeStore } from 'babylonjs/Misc/typeStore';
  */
  */
 export class Container extends Control {
 export class Container extends Control {
     /** @hidden */
     /** @hidden */
-    protected _children = new Array<Control>();
+    public _children = new Array<Control>();
     /** @hidden */
     /** @hidden */
     protected _measureForChildren = Measure.Empty();
     protected _measureForChildren = Measure.Empty();
     /** @hidden */
     /** @hidden */
@@ -304,6 +304,8 @@ export class Container extends Control {
             return false;
             return false;
         }
         }
 
 
+        Control.NumLayoutCalls++;
+
         if (this._isDirty) {
         if (this._isDirty) {
             this._currentMeasure.transformToRef(this._transformMatrix, this._prevCurrentMeasureTransformedIntoGlobalSpace);
             this._currentMeasure.transformToRef(this._transformMatrix, this._prevCurrentMeasureTransformedIntoGlobalSpace);
         }
         }

+ 13 - 0
gui/src/2D/controls/control.ts

@@ -25,6 +25,11 @@ export class Control {
      */
      */
     public static AllowAlphaInheritance = false;
     public static AllowAlphaInheritance = false;
 
 
+    /** Gets the number of layout calls made the last time the ADT has been rendered */
+    public static NumLayoutCalls = 0;
+    /** Gets the number of render calls made the last time the ADT has been rendered */
+    public static NumRenderCalls = 0;
+
     private _alpha = 1;
     private _alpha = 1;
     private _alphaSet = false;
     private _alphaSet = false;
     private _zIndex = 0;
     private _zIndex = 0;
@@ -100,6 +105,9 @@ export class Control {
     protected _rebuildLayout = false;
     protected _rebuildLayout = false;
 
 
     /** @hidden */
     /** @hidden */
+    public _customData: any = {};
+
+    /** @hidden */
     public _isClipped = false;
     public _isClipped = false;
 
 
     /** @hidden */
     /** @hidden */
@@ -1356,6 +1364,8 @@ export class Control {
         }
         }
 
 
         if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
         if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
+            Control.NumLayoutCalls++;
+
             this._currentMeasure.transformToRef(this._transformMatrix, this._prevCurrentMeasureTransformedIntoGlobalSpace);
             this._currentMeasure.transformToRef(this._transformMatrix, this._prevCurrentMeasureTransformedIntoGlobalSpace);
 
 
             context.save();
             context.save();
@@ -1596,6 +1606,9 @@ export class Control {
             this._isDirty = false;
             this._isDirty = false;
             return false;
             return false;
         }
         }
+
+        Control.NumRenderCalls++;
+
         context.save();
         context.save();
 
 
         this._applyStates(context);
         this._applyStates(context);

+ 100 - 30
gui/src/2D/controls/scrollViewers/scrollViewer.ts

@@ -29,8 +29,6 @@ export class ScrollViewer extends Rectangle {
     private _barImage: Image;
     private _barImage: Image;
     private _barBackgroundImage: Image;
     private _barBackgroundImage: Image;
     private _barSize: number = 20;
     private _barSize: number = 20;
-    private _endLeft: number;
-    private _endTop: number;
     private _window: _ScrollViewerWindow;
     private _window: _ScrollViewerWindow;
     private _pointerIsOver: Boolean = false;
     private _pointerIsOver: Boolean = false;
     private _wheelPrecision: number = 0.05;
     private _wheelPrecision: number = 0.05;
@@ -93,6 +91,73 @@ export class ScrollViewer extends Rectangle {
     }
     }
 
 
     /**
     /**
+     * Freezes or unfreezes the controls in the window.
+     * When controls are frozen, the scroll viewer can render a lot more quickly but updates to positions/sizes of controls
+     * are not taken into account. If you want to change positions/sizes, unfreeze, perform the changes then freeze again
+     */
+    public get freezeControls(): boolean {
+        return this._window.freezeControls;
+    }
+
+    public set freezeControls(value: boolean) {
+        this._window.freezeControls = value;
+    }
+
+    /** Gets the bucket width */
+    public get bucketWidth(): number {
+        return this._window.bucketWidth;
+    }
+
+    /** Gets the bucket height */
+    public get bucketHeight(): number {
+        return this._window.bucketHeight;
+    }
+
+    /**
+     * Sets the bucket sizes.
+     * When freezeControls is true, setting a non-zero bucket size will improve performances by updating only
+     * controls that are visible. The bucket sizes is used to subdivide (internally) the window area to smaller areas into which
+     * controls are dispatched. So, the size should be roughly equals to the mean size of all the controls of
+     * the window. To disable the usage of buckets, sets either width or height (or both) to 0.
+     * Please note that using this option will raise the memory usage (the higher the bucket sizes, the less memory
+     * used), that's why it is not enabled by default.
+     * @param width width of the bucket
+     * @param height height of the bucket
+     */
+    public setBucketSizes(width: number, height: number): void {
+        this._window.setBucketSizes(width, height);
+    }
+
+    private _forceHorizontalBar: boolean = false;
+    private _forceVerticalBar: boolean = false;
+
+    /**
+     * Forces the horizontal scroll bar to be displayed
+     */
+    public get forceHorizontalBar(): boolean {
+        return this._forceHorizontalBar;
+    }
+
+    public set forceHorizontalBar(value: boolean) {
+        this._grid.setRowDefinition(1, value ? this._barSize : 0, true);
+        this._horizontalBar.isVisible = value;
+        this._forceHorizontalBar = value;
+    }
+
+    /**
+     * Forces the vertical scroll bar to be displayed
+     */
+    public get forceVerticalBar(): boolean {
+        return this._forceVerticalBar;
+    }
+
+    public set forceVerticalBar(value: boolean) {
+        this._grid.setColumnDefinition(1, value ? this._barSize : 0, true);
+        this._verticalBar.isVisible = value;
+        this._forceVerticalBar = value;
+    }
+
+    /**
     * Creates a new ScrollViewer
     * Creates a new ScrollViewer
     * @param name of ScrollViewer
     * @param name of ScrollViewer
     */
     */
@@ -125,7 +190,7 @@ export class ScrollViewer extends Rectangle {
             this._verticalBar = new ScrollBar();
             this._verticalBar = new ScrollBar();
         }
         }
 
 
-        this._window = new _ScrollViewerWindow();
+        this._window = new _ScrollViewerWindow("scrollViewer_window");
         this._window.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
         this._window.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
         this._window.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
         this._window.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
 
 
@@ -173,8 +238,8 @@ export class ScrollViewer extends Rectangle {
     }
     }
 
 
     private _buildClientSizes() {
     private _buildClientSizes() {
-        this._window.parentClientWidth = this._currentMeasure.width - (this._verticalBar.isVisible ? this._barSize : 0) - 2 * this.thickness;
-        this._window.parentClientHeight = this._currentMeasure.height - (this._horizontalBar.isVisible ? this._barSize : 0) - 2 * this.thickness;
+        this._window.parentClientWidth = this._currentMeasure.width - (this._verticalBar.isVisible || this.forceVerticalBar ? this._barSize : 0) - 2 * this.thickness;
+        this._window.parentClientHeight = this._currentMeasure.height - (this._horizontalBar.isVisible || this.forceHorizontalBar ? this._barSize : 0) - 2 * this.thickness;
 
 
         this._clientWidth = this._window.parentClientWidth;
         this._clientWidth = this._window.parentClientWidth;
         this._clientHeight = this._window.parentClientHeight;
         this._clientHeight = this._window.parentClientHeight;
@@ -385,51 +450,61 @@ export class ScrollViewer extends Rectangle {
         vb.backgroundImage = value;
         vb.backgroundImage = value;
     }
     }
 
 
+    private _setWindowPosition(): void {
+        let windowContentsWidth = this._window._currentMeasure.width;
+        let windowContentsHeight = this._window._currentMeasure.height;
+
+        const _endLeft = this._clientWidth - windowContentsWidth;
+        const _endTop = this._clientHeight - windowContentsHeight;
+
+        const newLeft = this._horizontalBar.value * _endLeft + "px";
+        const newTop = this._verticalBar.value * _endTop + "px";
+
+        if (newLeft !== this._window.left) {
+            this._window.left = newLeft;
+            if (!this.freezeControls) {
+                this._rebuildLayout = true;
+            }
+        }
+
+        if (newTop !== this._window.top) {
+            this._window.top = newTop;
+            if (!this.freezeControls) {
+                this._rebuildLayout = true;
+            }
+        }
+    }
+
     /** @hidden */
     /** @hidden */
     private _updateScroller(): void {
     private _updateScroller(): void {
         let windowContentsWidth = this._window._currentMeasure.width;
         let windowContentsWidth = this._window._currentMeasure.width;
         let windowContentsHeight = this._window._currentMeasure.height;
         let windowContentsHeight = this._window._currentMeasure.height;
 
 
-        if (this._horizontalBar.isVisible && windowContentsWidth <= this._clientWidth) {
+        if (this._horizontalBar.isVisible && windowContentsWidth <= this._clientWidth && !this.forceHorizontalBar) {
             this._grid.setRowDefinition(1, 0, true);
             this._grid.setRowDefinition(1, 0, true);
             this._horizontalBar.isVisible = false;
             this._horizontalBar.isVisible = false;
             this._horizontalBar.value = 0;
             this._horizontalBar.value = 0;
             this._rebuildLayout = true;
             this._rebuildLayout = true;
         }
         }
-        else if (!this._horizontalBar.isVisible && windowContentsWidth > this._clientWidth) {
+        else if (!this._horizontalBar.isVisible && (windowContentsWidth > this._clientWidth || this.forceHorizontalBar)) {
             this._grid.setRowDefinition(1, this._barSize, true);
             this._grid.setRowDefinition(1, this._barSize, true);
             this._horizontalBar.isVisible = true;
             this._horizontalBar.isVisible = true;
             this._rebuildLayout = true;
             this._rebuildLayout = true;
         }
         }
 
 
-        if (this._verticalBar.isVisible && windowContentsHeight <= this._clientHeight) {
+        if (this._verticalBar.isVisible && windowContentsHeight <= this._clientHeight && !this.forceVerticalBar) {
             this._grid.setColumnDefinition(1, 0, true);
             this._grid.setColumnDefinition(1, 0, true);
             this._verticalBar.isVisible = false;
             this._verticalBar.isVisible = false;
             this._verticalBar.value = 0;
             this._verticalBar.value = 0;
             this._rebuildLayout = true;
             this._rebuildLayout = true;
         }
         }
-        else if (!this._verticalBar.isVisible && windowContentsHeight > this._clientHeight) {
+        else if (!this._verticalBar.isVisible && (windowContentsHeight > this._clientHeight || this.forceVerticalBar)) {
             this._grid.setColumnDefinition(1, this._barSize, true);
             this._grid.setColumnDefinition(1, this._barSize, true);
             this._verticalBar.isVisible = true;
             this._verticalBar.isVisible = true;
             this._rebuildLayout = true;
             this._rebuildLayout = true;
         }
         }
 
 
         this._buildClientSizes();
         this._buildClientSizes();
-        this._endLeft = this._clientWidth - windowContentsWidth;
-        this._endTop = this._clientHeight - windowContentsHeight;
-
-        const newLeft = this._horizontalBar.value * this._endLeft + "px";
-        const newTop = this._verticalBar.value * this._endTop + "px";
-
-        if (newLeft !== this._window.left) {
-            this._window.left = newLeft;
-            this._rebuildLayout = true;
-        }
-
-        if (newTop !== this._window.top) {
-            this._window.top = newTop;
-            this._rebuildLayout = true;
-        }
 
 
         this._horizontalBar.thumbWidth = this._thumbLength * 0.9 * this._clientWidth + "px";
         this._horizontalBar.thumbWidth = this._thumbLength * 0.9 * this._clientWidth + "px";
         this._verticalBar.thumbWidth = this._thumbLength *  0.9 * this._clientHeight + "px";
         this._verticalBar.thumbWidth = this._thumbLength *  0.9 * this._clientHeight + "px";
@@ -458,12 +533,7 @@ export class ScrollViewer extends Rectangle {
         barContainer.addControl(barControl);
         barContainer.addControl(barControl);
 
 
         barControl.onValueChangedObservable.add((value) => {
         barControl.onValueChangedObservable.add((value) => {
-            if (rotation > 0) {
-                this._window.top = value * this._endTop + "px";
-            }
-            else {
-                this._window.left = value * this._endLeft + "px";
-            }
+            this._setWindowPosition();
         });
         });
     }
     }
 
 

+ 226 - 0
gui/src/2D/controls/scrollViewers/scrollViewerWindow.ts

@@ -11,6 +11,143 @@ export class _ScrollViewerWindow extends Container {
     public parentClientWidth: number;
     public parentClientWidth: number;
     public parentClientHeight: number;
     public parentClientHeight: number;
 
 
+    private _freezeControls = false;
+    private _parentMeasure: Measure;
+    private _oldLeft: number;
+    private _oldTop: number;
+
+    public get freezeControls(): boolean {
+        return this._freezeControls;
+    }
+
+    public set freezeControls(value: boolean) {
+        if (this._freezeControls === value) {
+            return;
+        }
+
+        // trigger a full normal layout calculation to be sure all children have their measures up to date
+        this._freezeControls = false;
+
+        var textureSize = this.host.getSize();
+        var renderWidth = textureSize.width;
+        var renderHeight = textureSize.height;
+
+        var context = this.host.getContext();
+
+        var measure = new Measure(0, 0, renderWidth, renderHeight);
+
+        Control.NumLayoutCalls = 0;
+
+        this.host._rootContainer._layout(measure, context);
+
+        // in freeze mode, prepare children measures accordingly
+        if (value) {
+            this._updateMeasures();
+            if (this._useBuckets()) {
+                this._makeBuckets();
+            }
+        }
+
+        this._freezeControls = value;
+
+        this.host.markAsDirty(); // redraw with the (new) current settings
+    }
+
+    private _bucketWidth: number = 0;
+    private _bucketHeight: number = 0;
+    private _buckets: { [key: number]: Array<Control> } = {};
+    private _bucketLen: number;
+
+    public get bucketWidth(): number {
+        return this._bucketWidth;
+    }
+
+    public get bucketHeight(): number {
+        return this._bucketHeight;
+    }
+
+    public setBucketSizes(width: number, height: number): void {
+        this._bucketWidth = width;
+        this._bucketHeight = height;
+
+        if (this._useBuckets()) {
+            if (this._freezeControls) {
+                this._makeBuckets();
+            }
+        } else {
+            this._buckets = {};
+        }
+    }
+
+    private _useBuckets(): boolean {
+        return this._bucketWidth > 0 && this._bucketHeight > 0;
+    }
+
+    private _makeBuckets(): void {
+        this._buckets = {};
+        this._bucketLen = Math.ceil(this.widthInPixels / this._bucketWidth);
+        this._dispatchInBuckets(this._children);
+    }
+
+    private _dispatchInBuckets(children: Control[]): void {
+        for (let i = 0; i < children.length; ++i) {
+            let child = children[i];
+
+            let bStartX = Math.max(0, Math.floor((child._currentMeasure.left - this._currentMeasure.left) / this._bucketWidth)),
+                bEndX = Math.floor((child._currentMeasure.left - this._currentMeasure.left + child._currentMeasure.width - 1) / this._bucketWidth),
+                bStartY = Math.max(0, Math.floor((child._currentMeasure.top - this._currentMeasure.top) / this._bucketHeight)),
+                bEndY = Math.floor((child._currentMeasure.top - this._currentMeasure.top + child._currentMeasure.height - 1) / this._bucketHeight);
+
+            while (bStartY <= bEndY) {
+                for (let x = bStartX; x <= bEndX; ++x) {
+                    let bucket = bStartY * this._bucketLen + x,
+                        lstc = this._buckets[bucket];
+
+                    if (!lstc) {
+                        lstc = [];
+                        this._buckets[bucket] = lstc;
+                    }
+
+                    lstc.push(child);
+                }
+                bStartY++;
+            }
+
+            if (child instanceof Container && child._children.length > 0) {
+                this._dispatchInBuckets(child._children);
+            }
+        }
+    }
+
+    // reset left and top measures for the window and all its children
+    private _updateMeasures(): void {
+        let left = this.leftInPixels | 0,
+            top = this.topInPixels | 0;
+
+        this._measureForChildren.left -= left;
+        this._measureForChildren.top -= top;
+        this._currentMeasure.left -= left;
+        this._currentMeasure.top -= top;
+
+        this._updateChildrenMeasures(this._children, left, top);
+    }
+
+    private _updateChildrenMeasures(children: Control[], left: number, top: number): void {
+        for (let i = 0; i < children.length; ++i) {
+            let child = children[i];
+
+            child._currentMeasure.left -= left;
+            child._currentMeasure.top -= top;
+
+            child._customData._origLeft = child._currentMeasure.left; // save the original left and top values for each child
+            child._customData._origTop = child._currentMeasure.top;
+
+            if (child instanceof Container && child._children.length > 0) {
+                this._updateChildrenMeasures(child._children, left, top);
+            }
+        }
+    }
+
     /**
     /**
     * Creates a new ScrollViewerWindow
     * Creates a new ScrollViewerWindow
     * @param name of ScrollViewerWindow
     * @param name of ScrollViewerWindow
@@ -27,6 +164,8 @@ export class _ScrollViewerWindow extends Container {
     protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
     protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
         super._additionalProcessing(parentMeasure, context);
         super._additionalProcessing(parentMeasure, context);
 
 
+        this._parentMeasure = parentMeasure;
+
         this._measureForChildren.left = this._currentMeasure.left;
         this._measureForChildren.left = this._currentMeasure.left;
         this._measureForChildren.top = this._currentMeasure.top;
         this._measureForChildren.top = this._currentMeasure.top;
 
 
@@ -34,7 +173,94 @@ export class _ScrollViewerWindow extends Container {
         this._measureForChildren.height = parentMeasure.height;
         this._measureForChildren.height = parentMeasure.height;
     }
     }
 
 
+    /** @hidden */
+    public _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean {
+        if (this._freezeControls) {
+            this.invalidateRect(); // will trigger a redraw of the window
+            return false;
+        }
+
+        return super._layout(parentMeasure, context);
+    }
+
+    private _scrollChildren(children: Control[], left: number, top: number): void {
+        for (let i = 0; i < children.length; ++i) {
+            let child = children[i];
+
+            child._currentMeasure.left = child._customData._origLeft + left;
+            child._currentMeasure.top = child._customData._origTop + top;
+            child._isClipped = false; // clipping will be handled by _draw and the call to _intersectsRect()
+
+            if (child instanceof Container && child._children.length > 0) {
+                this._scrollChildren(child._children, left, top);
+            }
+        }
+    }
+
+    private _scrollChildrenWithBuckets(left: number, top: number, scrollLeft: number, scrollTop: number): void {
+        let bStartX = Math.max(0, Math.floor(-left / this._bucketWidth)),
+            bEndX = Math.floor((-left + this._parentMeasure.width - 1) / this._bucketWidth),
+            bStartY = Math.max(0, Math.floor(-top / this._bucketHeight)),
+            bEndY = Math.floor((-top + this._parentMeasure.height - 1) / this._bucketHeight);
+
+        while (bStartY <= bEndY) {
+            for (let x = bStartX; x <= bEndX; ++x) {
+                let bucket = bStartY * this._bucketLen + x,
+                    lstc = this._buckets[bucket];
+
+                if (lstc) {
+                    for (let i = 0; i < lstc.length; ++i) {
+                        let child = lstc[i];
+                        child._currentMeasure.left = child._customData._origLeft + scrollLeft;
+                        child._currentMeasure.top = child._customData._origTop + scrollTop;
+                        child._isClipped = false; // clipping will be handled by _draw and the call to _intersectsRect()
+                    }
+                }
+            }
+            bStartY++;
+        }
+    }
+
+    /** @hidden */
+    public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void {
+        if (!this._freezeControls) {
+            super._draw(context, invalidatedRectangle);
+            return;
+        }
+
+        this._localDraw(context);
+
+        if (this.clipChildren) {
+            this._clipForChildren(context);
+        }
+
+        let left = this.leftInPixels,
+            top = this.topInPixels;
+
+        if (this._useBuckets()) {
+            this._scrollChildrenWithBuckets(this._oldLeft, this._oldTop, left, top);
+            this._scrollChildrenWithBuckets(left, top, left, top);
+        } else {
+            this._scrollChildren(this._children, left, top);
+        }
+
+        this._oldLeft = left;
+        this._oldTop = top;
+
+        for (var child of this._children) {
+            if (!child._intersectsRect(this._parentMeasure)) {
+                continue;
+            }
+            child._render(context, this._parentMeasure);
+        }
+    }
+
     protected _postMeasure(): void {
     protected _postMeasure(): void {
+        if (this._freezeControls) {
+            super._postMeasure();
+            return;
+        }
+
         var maxWidth = this.parentClientWidth;
         var maxWidth = this.parentClientWidth;
         var maxHeight = this.parentClientHeight;
         var maxHeight = this.parentClientHeight;
         for (var child of this.children) {
         for (var child of this.children) {

+ 33 - 13
gui/src/2D/measure.ts

@@ -1,6 +1,22 @@
 import { Matrix2D } from "./math2D";
 import { Matrix2D } from "./math2D";
 import { Vector2 } from "babylonjs/Maths/math";
 import { Vector2 } from "babylonjs/Maths/math";
-import { Polygon } from "babylonjs/Meshes/polygonMesh";
+
+let tmpRect = [
+    new Vector2(0, 0),
+    new Vector2(0, 0),
+    new Vector2(0, 0),
+    new Vector2(0, 0),
+];
+
+let tmpRect2 = [
+    new Vector2(0, 0),
+    new Vector2(0, 0),
+    new Vector2(0, 0),
+    new Vector2(0, 0),
+];
+
+let tmpV1 = new Vector2(0, 0);
+let tmpV2 = new Vector2(0, 0);
 
 
 /**
 /**
  * Class used to store 2D control sizes
  * Class used to store 2D control sizes
@@ -73,20 +89,24 @@ export class Measure {
      * @param result the resulting AABB
      * @param result the resulting AABB
      */
      */
     public transformToRef(transform: Matrix2D, result: Measure) {
     public transformToRef(transform: Matrix2D, result: Measure) {
-        var rectanglePoints = Polygon.Rectangle(this.left, this.top, this.left + this.width, this.top + this.height);
-        var min = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
-        var max = new Vector2(0, 0);
+        tmpRect[0].copyFromFloats(this.left, this.top);
+        tmpRect[1].copyFromFloats(this.left + this.width, this.top);
+        tmpRect[2].copyFromFloats(this.left + this.width, this.top + this.height);
+        tmpRect[3].copyFromFloats(this.left, this.top + this.height);
+
+        tmpV1.copyFromFloats(Number.MAX_VALUE, Number.MAX_VALUE);
+        tmpV2.copyFromFloats(0, 0);
         for (var i = 0; i < 4; i++) {
         for (var i = 0; i < 4; i++) {
-            transform.transformCoordinates(rectanglePoints[i].x, rectanglePoints[i].y, rectanglePoints[i]);
-            min.x = Math.floor(Math.min(min.x, rectanglePoints[i].x));
-            min.y = Math.floor(Math.min(min.y, rectanglePoints[i].y));
-            max.x = Math.ceil(Math.max(max.x, rectanglePoints[i].x));
-            max.y = Math.ceil(Math.max(max.y, rectanglePoints[i].y));
+            transform.transformCoordinates(tmpRect[i].x, tmpRect[i].y, tmpRect2[i]);
+            tmpV1.x = Math.floor(Math.min(tmpV1.x, tmpRect2[i].x));
+            tmpV1.y = Math.floor(Math.min(tmpV1.y, tmpRect2[i].y));
+            tmpV2.x = Math.ceil(Math.max(tmpV2.x, tmpRect2[i].x));
+            tmpV2.y = Math.ceil(Math.max(tmpV2.y, tmpRect2[i].y));
         }
         }
-        result.left = min.x;
-        result.top = min.y;
-        result.width = max.x - min.x;
-        result.height = max.y - min.y;
+        result.left = tmpV1.x;
+        result.top = tmpV1.y;
+        result.width = tmpV2.x - tmpV1.x;
+        result.height = tmpV2.y - tmpV1.y;
     }
     }
 
 
     /**
     /**