浏览代码

Fix several issues with InvalidateRect

David Catuhe 6 年之前
父节点
当前提交
63e3b8dd6f

文件差异内容过多而无法显示
+ 9530 - 9518
Playground/babylon.d.txt


文件差异内容过多而无法显示
+ 9523 - 9523
dist/preview release/babylon.d.ts


+ 23 - 10
dist/preview release/gui/babylon.gui.d.ts

@@ -172,13 +172,21 @@ declare module BABYLON.GUI {
              */
              */
             executeOnAllControls(func: (control: Control) => void, container?: Container): void;
             executeOnAllControls(func: (control: Control) => void, container?: Container): void;
             /**
             /**
+                * Gets or sets a boolean indicating if the InvalidateRect optimization should be turned on
+                */
+            useInvalidateRectOptimization: boolean;
+            /**
                 * Invalidates a rectangle area on the gui texture
                 * Invalidates a rectangle area on the gui texture
-                * @param minX left most position of the rectangle to invalidate in pixels
-                * @param minY top most position of the rectangle to invalidate in pixels
-                * @param maxX right most position of the rectangle to invalidate in pixels
-                * @param maxY bottom most position of the rectangle to invalidate in pixels
+                * @param clearMinX left most position of the rectangle to clear in the texture
+                * @param clearMinY top most position of the rectangle to clear in the texture
+                * @param clearMaxX right most position of the rectangle to clear in the texture
+                * @param clearMaxY bottom most position of the rectangle to clear in the texture
+                * @param minX left most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param minY top most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param maxX right most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param maxY bottom most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
                 */
                 */
-            invalidateRect(minX: number, minY: number, maxX: number, maxY: number): void;
+            invalidateRect(clearMinX: number, clearMinY: number, clearMaxX: number, clearMaxY: number, minX: number, minY: number, maxX: number, maxY: number): void;
             /**
             /**
              * Marks the texture as dirty forcing a complete update
              * Marks the texture as dirty forcing a complete update
              */
              */
@@ -917,13 +925,15 @@ declare module BABYLON.GUI {
             /** @hidden */
             /** @hidden */
             _markAllAsDirty(): void;
             _markAllAsDirty(): void;
             /** @hidden */
             /** @hidden */
-            protected _localDraw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
+            protected _localDraw(context: CanvasRenderingContext2D): void;
             /** @hidden */
             /** @hidden */
             _link(host: AdvancedDynamicTexture): void;
             _link(host: AdvancedDynamicTexture): void;
             /** @hidden */
             /** @hidden */
             protected _beforeLayout(): void;
             protected _beforeLayout(): void;
             /** @hidden */
             /** @hidden */
-            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): boolean;
+            protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            /** @hidden */
+            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
             protected _postMeasure(): void;
             protected _postMeasure(): void;
             /** @hidden */
             /** @hidden */
             _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
             _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
@@ -976,6 +986,8 @@ declare module BABYLON.GUI {
             /** @hidden */
             /** @hidden */
             _tempParentMeasure: Measure;
             _tempParentMeasure: Measure;
             /** @hidden */
             /** @hidden */
+            _tempCurrentMeasure: Measure;
+            /** @hidden */
             protected _cachedParentMeasure: Measure;
             protected _cachedParentMeasure: Measure;
             /** @hidden */
             /** @hidden */
             _left: ValueAndUnit;
             _left: ValueAndUnit;
@@ -1333,7 +1345,7 @@ declare module BABYLON.GUI {
             /** @hidden */
             /** @hidden */
             _intersectsRect(rect: Measure): boolean;
             _intersectsRect(rect: Measure): boolean;
             /** @hidden */
             /** @hidden */
-            protected invalidateRect(): void;
+            protected invalidateRect(left: number, top: number, right: number, bottom: number): void;
             /** @hidden */
             /** @hidden */
             _markAsDirty(force?: boolean): void;
             _markAsDirty(force?: boolean): void;
             /** @hidden */
             /** @hidden */
@@ -1349,9 +1361,10 @@ declare module BABYLON.GUI {
             /** @hidden */
             /** @hidden */
             protected _applyStates(context: CanvasRenderingContext2D): void;
             protected _applyStates(context: CanvasRenderingContext2D): void;
             /** @hidden */
             /** @hidden */
-            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): boolean;
+            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
             /** @hidden */
             /** @hidden */
             protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            protected _evaluateClippingState(parentMeasure: Measure): void;
             /** @hidden */
             /** @hidden */
             _measure(): void;
             _measure(): void;
             /** @hidden */
             /** @hidden */
@@ -2373,7 +2386,7 @@ declare module BABYLON.GUI {
                 */
                 */
             constructor(name?: string | undefined);
             constructor(name?: string | undefined);
             protected _getTypeName(): string;
             protected _getTypeName(): string;
-            protected _localDraw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
+            protected _localDraw(context: CanvasRenderingContext2D): void;
             protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _clipForChildren(context: CanvasRenderingContext2D): void;
             protected _clipForChildren(context: CanvasRenderingContext2D): void;
     }
     }

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/gui/babylon.gui.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 46 - 20
dist/preview release/gui/babylon.gui.module.d.ts

@@ -219,13 +219,21 @@ declare module 'babylonjs-gui/2D/advancedDynamicTexture' {
              */
              */
             executeOnAllControls(func: (control: Control) => void, container?: Container): void;
             executeOnAllControls(func: (control: Control) => void, container?: Container): void;
             /**
             /**
+                * Gets or sets a boolean indicating if the InvalidateRect optimization should be turned on
+                */
+            useInvalidateRectOptimization: boolean;
+            /**
                 * Invalidates a rectangle area on the gui texture
                 * Invalidates a rectangle area on the gui texture
-                * @param minX left most position of the rectangle to invalidate in pixels
-                * @param minY top most position of the rectangle to invalidate in pixels
-                * @param maxX right most position of the rectangle to invalidate in pixels
-                * @param maxY bottom most position of the rectangle to invalidate in pixels
+                * @param clearMinX left most position of the rectangle to clear in the texture
+                * @param clearMinY top most position of the rectangle to clear in the texture
+                * @param clearMaxX right most position of the rectangle to clear in the texture
+                * @param clearMaxY bottom most position of the rectangle to clear in the texture
+                * @param minX left most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param minY top most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param maxX right most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param maxY bottom most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
                 */
                 */
-            invalidateRect(minX: number, minY: number, maxX: number, maxY: number): void;
+            invalidateRect(clearMinX: number, clearMinY: number, clearMaxX: number, clearMaxY: number, minX: number, minY: number, maxX: number, maxY: number): void;
             /**
             /**
              * Marks the texture as dirty forcing a complete update
              * Marks the texture as dirty forcing a complete update
              */
              */
@@ -1020,13 +1028,15 @@ declare module 'babylonjs-gui/2D/controls/container' {
             /** @hidden */
             /** @hidden */
             _markAllAsDirty(): void;
             _markAllAsDirty(): void;
             /** @hidden */
             /** @hidden */
-            protected _localDraw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
+            protected _localDraw(context: CanvasRenderingContext2D): void;
             /** @hidden */
             /** @hidden */
             _link(host: AdvancedDynamicTexture): void;
             _link(host: AdvancedDynamicTexture): void;
             /** @hidden */
             /** @hidden */
             protected _beforeLayout(): void;
             protected _beforeLayout(): void;
             /** @hidden */
             /** @hidden */
-            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): boolean;
+            protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            /** @hidden */
+            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
             protected _postMeasure(): void;
             protected _postMeasure(): void;
             /** @hidden */
             /** @hidden */
             _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
             _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
@@ -1087,6 +1097,8 @@ declare module 'babylonjs-gui/2D/controls/control' {
             /** @hidden */
             /** @hidden */
             _tempParentMeasure: Measure;
             _tempParentMeasure: Measure;
             /** @hidden */
             /** @hidden */
+            _tempCurrentMeasure: Measure;
+            /** @hidden */
             protected _cachedParentMeasure: Measure;
             protected _cachedParentMeasure: Measure;
             /** @hidden */
             /** @hidden */
             _left: ValueAndUnit;
             _left: ValueAndUnit;
@@ -1444,7 +1456,7 @@ declare module 'babylonjs-gui/2D/controls/control' {
             /** @hidden */
             /** @hidden */
             _intersectsRect(rect: Measure): boolean;
             _intersectsRect(rect: Measure): boolean;
             /** @hidden */
             /** @hidden */
-            protected invalidateRect(): void;
+            protected invalidateRect(left: number, top: number, right: number, bottom: number): void;
             /** @hidden */
             /** @hidden */
             _markAsDirty(force?: boolean): void;
             _markAsDirty(force?: boolean): void;
             /** @hidden */
             /** @hidden */
@@ -1460,9 +1472,10 @@ declare module 'babylonjs-gui/2D/controls/control' {
             /** @hidden */
             /** @hidden */
             protected _applyStates(context: CanvasRenderingContext2D): void;
             protected _applyStates(context: CanvasRenderingContext2D): void;
             /** @hidden */
             /** @hidden */
-            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): boolean;
+            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
             /** @hidden */
             /** @hidden */
             protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            protected _evaluateClippingState(parentMeasure: Measure): void;
             /** @hidden */
             /** @hidden */
             _measure(): void;
             _measure(): void;
             /** @hidden */
             /** @hidden */
@@ -2542,7 +2555,7 @@ declare module 'babylonjs-gui/2D/controls/rectangle' {
                 */
                 */
             constructor(name?: string | undefined);
             constructor(name?: string | undefined);
             protected _getTypeName(): string;
             protected _getTypeName(): string;
-            protected _localDraw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
+            protected _localDraw(context: CanvasRenderingContext2D): void;
             protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _clipForChildren(context: CanvasRenderingContext2D): void;
             protected _clipForChildren(context: CanvasRenderingContext2D): void;
     }
     }
@@ -3483,13 +3496,21 @@ declare module BABYLON.GUI {
              */
              */
             executeOnAllControls(func: (control: Control) => void, container?: Container): void;
             executeOnAllControls(func: (control: Control) => void, container?: Container): void;
             /**
             /**
+                * Gets or sets a boolean indicating if the InvalidateRect optimization should be turned on
+                */
+            useInvalidateRectOptimization: boolean;
+            /**
                 * Invalidates a rectangle area on the gui texture
                 * Invalidates a rectangle area on the gui texture
-                * @param minX left most position of the rectangle to invalidate in pixels
-                * @param minY top most position of the rectangle to invalidate in pixels
-                * @param maxX right most position of the rectangle to invalidate in pixels
-                * @param maxY bottom most position of the rectangle to invalidate in pixels
+                * @param clearMinX left most position of the rectangle to clear in the texture
+                * @param clearMinY top most position of the rectangle to clear in the texture
+                * @param clearMaxX right most position of the rectangle to clear in the texture
+                * @param clearMaxY bottom most position of the rectangle to clear in the texture
+                * @param minX left most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param minY top most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param maxX right most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+                * @param maxY bottom most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
                 */
                 */
-            invalidateRect(minX: number, minY: number, maxX: number, maxY: number): void;
+            invalidateRect(clearMinX: number, clearMinY: number, clearMaxX: number, clearMaxY: number, minX: number, minY: number, maxX: number, maxY: number): void;
             /**
             /**
              * Marks the texture as dirty forcing a complete update
              * Marks the texture as dirty forcing a complete update
              */
              */
@@ -4228,13 +4249,15 @@ declare module BABYLON.GUI {
             /** @hidden */
             /** @hidden */
             _markAllAsDirty(): void;
             _markAllAsDirty(): void;
             /** @hidden */
             /** @hidden */
-            protected _localDraw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
+            protected _localDraw(context: CanvasRenderingContext2D): void;
             /** @hidden */
             /** @hidden */
             _link(host: AdvancedDynamicTexture): void;
             _link(host: AdvancedDynamicTexture): void;
             /** @hidden */
             /** @hidden */
             protected _beforeLayout(): void;
             protected _beforeLayout(): void;
             /** @hidden */
             /** @hidden */
-            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): boolean;
+            protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            /** @hidden */
+            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
             protected _postMeasure(): void;
             protected _postMeasure(): void;
             /** @hidden */
             /** @hidden */
             _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
             _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
@@ -4287,6 +4310,8 @@ declare module BABYLON.GUI {
             /** @hidden */
             /** @hidden */
             _tempParentMeasure: Measure;
             _tempParentMeasure: Measure;
             /** @hidden */
             /** @hidden */
+            _tempCurrentMeasure: Measure;
+            /** @hidden */
             protected _cachedParentMeasure: Measure;
             protected _cachedParentMeasure: Measure;
             /** @hidden */
             /** @hidden */
             _left: ValueAndUnit;
             _left: ValueAndUnit;
@@ -4644,7 +4669,7 @@ declare module BABYLON.GUI {
             /** @hidden */
             /** @hidden */
             _intersectsRect(rect: Measure): boolean;
             _intersectsRect(rect: Measure): boolean;
             /** @hidden */
             /** @hidden */
-            protected invalidateRect(): void;
+            protected invalidateRect(left: number, top: number, right: number, bottom: number): void;
             /** @hidden */
             /** @hidden */
             _markAsDirty(force?: boolean): void;
             _markAsDirty(force?: boolean): void;
             /** @hidden */
             /** @hidden */
@@ -4660,9 +4685,10 @@ declare module BABYLON.GUI {
             /** @hidden */
             /** @hidden */
             protected _applyStates(context: CanvasRenderingContext2D): void;
             protected _applyStates(context: CanvasRenderingContext2D): void;
             /** @hidden */
             /** @hidden */
-            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): boolean;
+            _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
             /** @hidden */
             /** @hidden */
             protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            protected _evaluateClippingState(parentMeasure: Measure): void;
             /** @hidden */
             /** @hidden */
             _measure(): void;
             _measure(): void;
             /** @hidden */
             /** @hidden */
@@ -5684,7 +5710,7 @@ declare module BABYLON.GUI {
                 */
                 */
             constructor(name?: string | undefined);
             constructor(name?: string | undefined);
             protected _getTypeName(): string;
             protected _getTypeName(): string;
-            protected _localDraw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
+            protected _localDraw(context: CanvasRenderingContext2D): void;
             protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             protected _clipForChildren(context: CanvasRenderingContext2D): void;
             protected _clipForChildren(context: CanvasRenderingContext2D): void;
     }
     }

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


+ 58 - 32
gui/src/2D/advancedDynamicTexture.ts

@@ -317,35 +317,57 @@ export class AdvancedDynamicTexture extends DynamicTexture {
             func(child);
             func(child);
         }
         }
     }
     }
-    private _disableInvalidateRect = false;
+
+    private _useInvalidateRectOptimization = true;
+
+    /**
+     * Gets or sets a boolean indicating if the InvalidateRect optimization should be turned on
+     */
+    public get useInvalidateRectOptimization(): boolean {
+        return this._useInvalidateRectOptimization;
+    }
+
+    public set useInvalidateRectOptimization(value: boolean) {
+        this._useInvalidateRectOptimization = value;
+    }
+
+    private _clearRectangle: Nullable<Measure> = null;
     private _invalidatedRectangle: Nullable<Measure> = null;
     private _invalidatedRectangle: Nullable<Measure> = null;
     /**
     /**
      * Invalidates a rectangle area on the gui texture
      * Invalidates a rectangle area on the gui texture
-     * @param minX left most position of the rectangle to invalidate in pixels
-     * @param minY top most position of the rectangle to invalidate in pixels
-     * @param maxX right most position of the rectangle to invalidate in pixels
-     * @param maxY bottom most position of the rectangle to invalidate in pixels
+     * @param clearMinX left most position of the rectangle to clear in the texture
+     * @param clearMinY top most position of the rectangle to clear in the texture
+     * @param clearMaxX right most position of the rectangle to clear in the texture
+     * @param clearMaxY bottom most position of the rectangle to clear in the texture
+     * @param minX left most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+     * @param minY top most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+     * @param maxX right most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+     * @param maxY bottom most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
      */
      */
-    public invalidateRect(minX: number, minY: number, maxX: number, maxY: number) {
-        if (this._disableInvalidateRect) {
+    public invalidateRect(clearMinX: number, clearMinY: number, clearMaxX: number, clearMaxY: number, minX: number, minY: number, maxX: number, maxY: number) {
+        if (!this._useInvalidateRectOptimization) {
             return;
             return;
         }
         }
-        if (!this._invalidatedRectangle) {
-            this._invalidatedRectangle = new Measure(minX, minY, maxX - minX, maxY - minY);
+        if (!this._clearRectangle || !this._invalidatedRectangle) {
+            this._clearRectangle = new Measure(clearMinX, clearMinY, clearMaxX - clearMinX + 1, clearMaxY - clearMinY + 1);
+            this._invalidatedRectangle = new Measure(minX, minY, maxX - minX + 1, maxY - minY + 1);
         } else {
         } else {
             // Compute intersection
             // Compute intersection
-            var maxLeft = Math.max(this._invalidatedRectangle.left + this._invalidatedRectangle.width, maxX);
-            var maxTop = Math.max(this._invalidatedRectangle.top + this._invalidatedRectangle.height, maxY);
+            var maxX = Math.max(this._clearRectangle.left + this._clearRectangle.width - 1, clearMaxX);
+            var maxY = Math.max(this._clearRectangle.top + this._clearRectangle.height - 1, clearMaxY);
+            this._clearRectangle.left = Math.min(this._clearRectangle.left, clearMinX);
+            this._clearRectangle.top = Math.min(this._clearRectangle.top, clearMinY);
+            this._clearRectangle.width = maxX - this._clearRectangle.left + 1;
+            this._clearRectangle.height = maxY - this._clearRectangle.top + 1;
+
+            maxX = Math.max(this._invalidatedRectangle.left + this._invalidatedRectangle.width - 1, maxX);
+            maxY = Math.max(this._invalidatedRectangle.top + this._invalidatedRectangle.height - 1, maxY);
             this._invalidatedRectangle.left = Math.min(this._invalidatedRectangle.left, minX);
             this._invalidatedRectangle.left = Math.min(this._invalidatedRectangle.left, minX);
             this._invalidatedRectangle.top = Math.min(this._invalidatedRectangle.top, minY);
             this._invalidatedRectangle.top = Math.min(this._invalidatedRectangle.top, minY);
-            this._invalidatedRectangle.width = maxLeft - this._invalidatedRectangle.left;
-            this._invalidatedRectangle.height = maxTop - this._invalidatedRectangle.top;
+            this._invalidatedRectangle.width = maxX - this._invalidatedRectangle.left + 1;
+            this._invalidatedRectangle.height = maxY - this._invalidatedRectangle.top + 1;
+
         }
         }
-        // Ensure there are no pixel fractions
-        this._invalidatedRectangle.left = Math.floor(this._invalidatedRectangle.left);
-        this._invalidatedRectangle.top = Math.floor(this._invalidatedRectangle.top);
-        this._invalidatedRectangle.width = Math.ceil(this._invalidatedRectangle.width);
-        this._invalidatedRectangle.height = Math.ceil(this._invalidatedRectangle.height);
     }
     }
     /**
     /**
     * Marks the texture as dirty forcing a complete update
     * Marks the texture as dirty forcing a complete update
@@ -444,7 +466,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
                 this._rootContainer._markAllAsDirty();
                 this._rootContainer._markAllAsDirty();
             }
             }
         }
         }
-        this.invalidateRect(0, 0, textureSize.width, textureSize.height);
+        this.invalidateRect(0, 0, textureSize.width - 1, textureSize.height - 1, 0, 0, textureSize.width - 1, textureSize.height - 1);
     }
     }
     /** @hidden */
     /** @hidden */
     public _getGlobalViewport(scene: Scene): Viewport {
     public _getGlobalViewport(scene: Scene): Viewport {
@@ -514,13 +536,24 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         var textureSize = this.getSize();
         var textureSize = this.getSize();
         var renderWidth = textureSize.width;
         var renderWidth = textureSize.width;
         var renderHeight = textureSize.height;
         var renderHeight = textureSize.height;
-        if (this._invalidatedRectangle) {
-            this._clearMeasure.copyFrom(this._invalidatedRectangle);
+
+        var context = this.getContext();
+        context.font = "18px Arial";
+        context.strokeStyle = "white";
+
+        // Layout
+        this.onBeginLayoutObservable.notifyObservers(this);
+        var measure = new Measure(0, 0, renderWidth, renderHeight);
+        this._rootContainer._layout(measure, context);
+        this.onEndLayoutObservable.notifyObservers(this);
+        this._isDirty = false; // Restoring the dirty state that could have been set by controls during layout processing
+
+        // Clear
+        if (this._clearRectangle) {
+            this._clearMeasure.copyFrom(this._clearRectangle);
         } else {
         } else {
             this._clearMeasure.copyFromFloats(0, 0, renderWidth, renderHeight);
             this._clearMeasure.copyFromFloats(0, 0, renderWidth, renderHeight);
         }
         }
-        // Clear
-        var context = this.getContext();
         context.clearRect(this._clearMeasure.left, this._clearMeasure.top, this._clearMeasure.width, this._clearMeasure.height);
         context.clearRect(this._clearMeasure.left, this._clearMeasure.top, this._clearMeasure.width, this._clearMeasure.height);
         if (this._background) {
         if (this._background) {
             context.save();
             context.save();
@@ -528,19 +561,12 @@ export class AdvancedDynamicTexture extends DynamicTexture {
             context.fillRect(this._clearMeasure.left, this._clearMeasure.top, this._clearMeasure.width, this._clearMeasure.height);
             context.fillRect(this._clearMeasure.left, this._clearMeasure.top, this._clearMeasure.width, this._clearMeasure.height);
             context.restore();
             context.restore();
         }
         }
-        // Render
-        context.font = "18px Arial";
-        context.strokeStyle = "white";
-        this.onBeginLayoutObservable.notifyObservers(this);
-        var measure = new Measure(0, 0, renderWidth, renderHeight);
-        this._rootContainer._layout(measure, context, this._invalidatedRectangle);
-        this.onEndLayoutObservable.notifyObservers(this);
-
-        this._isDirty = false; // Restoring the dirty state that could have been set by controls during layout processing
 
 
+        // Render
         this.onBeginRenderObservable.notifyObservers(this);
         this.onBeginRenderObservable.notifyObservers(this);
         this._rootContainer._render(context, this._invalidatedRectangle);
         this._rootContainer._render(context, this._invalidatedRectangle);
         this.onEndRenderObservable.notifyObservers(this);
         this.onEndRenderObservable.notifyObservers(this);
+        this._clearRectangle = null;
         this._invalidatedRectangle = null;
         this._invalidatedRectangle = null;
     }
     }
     /** @hidden */
     /** @hidden */

+ 28 - 13
gui/src/2D/controls/container.ts

@@ -243,7 +243,7 @@ export class Container extends Control {
     }
     }
 
 
     /** @hidden */
     /** @hidden */
-    protected _localDraw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void {
+    protected _localDraw(context: CanvasRenderingContext2D): void {
         if (this._background) {
         if (this._background) {
             context.save();
             context.save();
             if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
             if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
@@ -274,11 +274,23 @@ export class Container extends Control {
     }
     }
 
 
     /** @hidden */
     /** @hidden */
-    public _layout(parentMeasure: Measure, context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): boolean {
+    protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+        if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
+            super._processMeasures(parentMeasure, context);
+            this._evaluateClippingState(parentMeasure);
+        }
+    }
+
+    /** @hidden */
+    public _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean {
         if (!this.isVisible || this.notRenderable) {
         if (!this.isVisible || this.notRenderable) {
             return false;
             return false;
         }
         }
 
 
+        if (this._isDirty) {
+            this._tempCurrentMeasure.copyFrom(this._currentMeasure);
+        }
+
         let rebuildCount = 0;
         let rebuildCount = 0;
 
 
         context.save();
         context.save();
@@ -295,15 +307,9 @@ export class Container extends Control {
 
 
             if (!this._isClipped) {
             if (!this._isClipped) {
                 for (var child of this._children) {
                 for (var child of this._children) {
-                    // Only redraw parts of the screen that are invalidated
-                    if (invalidatedRectangle) {
-                        if (!child._intersectsRect(invalidatedRectangle)) {
-                            continue;
-                        }
-                    }
                     child._tempParentMeasure.copyFrom(this._measureForChildren);
                     child._tempParentMeasure.copyFrom(this._measureForChildren);
 
 
-                    if (child._layout(this._measureForChildren, context, invalidatedRectangle)) {
+                    if (child._layout(this._measureForChildren, context)) {
 
 
                         if (this.adaptWidthToChildren && child._width.isPixel) {
                         if (this.adaptWidthToChildren && child._width.isPixel) {
                             computedWidth = Math.max(computedWidth, child._currentMeasure.width);
                             computedWidth = Math.max(computedWidth, child._currentMeasure.width);
@@ -334,12 +340,21 @@ export class Container extends Control {
         while (this._rebuildLayout && rebuildCount < 3);
         while (this._rebuildLayout && rebuildCount < 3);
 
 
         if (rebuildCount >= 3) {
         if (rebuildCount >= 3) {
-            BABYLON.Tools.Error(`Layout cycle detected in GUI (Container uniqueId=${this.uniqueId})`);
+            BABYLON.Tools.Error(`Layout cycle detected in GUI (Container name=${this.name}, uniqueId=${this.uniqueId})`);
         }
         }
 
 
         context.restore();
         context.restore();
 
 
-        this._isDirty = false;
+        if (this._isDirty) {
+            this.invalidateRect(
+                Math.min(this._currentMeasure.left, this._tempCurrentMeasure.left),
+                Math.min(this._currentMeasure.top, this._tempCurrentMeasure.top),
+                Math.max(this._currentMeasure.left + this._currentMeasure.width, this._tempCurrentMeasure.left + this._tempCurrentMeasure.width) - 1,
+                Math.max(this._currentMeasure.top + this._currentMeasure.height, this._tempCurrentMeasure.top + this._tempCurrentMeasure.height) - 1
+            );
+
+            this._isDirty = false;
+        }
 
 
         return true;
         return true;
     }
     }
@@ -351,7 +366,7 @@ export class Container extends Control {
     /** @hidden */
     /** @hidden */
     public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void {
     public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void {
 
 
-        this._localDraw(context, invalidatedRectangle);
+        this._localDraw(context);
 
 
         if (this.clipChildren) {
         if (this.clipChildren) {
             this._clipForChildren(context);
             this._clipForChildren(context);
@@ -361,7 +376,7 @@ export class Container extends Control {
             // Only redraw parts of the screen that are invalidated
             // Only redraw parts of the screen that are invalidated
             if (invalidatedRectangle) {
             if (invalidatedRectangle) {
                 if (!child._intersectsRect(invalidatedRectangle)) {
                 if (!child._intersectsRect(invalidatedRectangle)) {
-                    continue;
+                    // continue;
                 }
                 }
             }
             }
             child._render(context, invalidatedRectangle);
             child._render(context, invalidatedRectangle);

+ 78 - 53
gui/src/2D/controls/control.ts

@@ -50,6 +50,8 @@ export class Control {
     /** @hidden */
     /** @hidden */
     public _tempParentMeasure = Measure.Empty();
     public _tempParentMeasure = Measure.Empty();
     /** @hidden */
     /** @hidden */
+    public _tempCurrentMeasure = Measure.Empty();
+    /** @hidden */
     protected _cachedParentMeasure = Measure.Empty();
     protected _cachedParentMeasure = Measure.Empty();
     private _paddingLeft = new ValueAndUnit(0);
     private _paddingLeft = new ValueAndUnit(0);
     private _paddingRight = new ValueAndUnit(0);
     private _paddingRight = new ValueAndUnit(0);
@@ -1075,36 +1077,49 @@ export class Control {
 
 
     /** @hidden */
     /** @hidden */
     public _intersectsRect(rect: Measure) {
     public _intersectsRect(rect: Measure) {
-        var hit = !(this._currentMeasure.left > rect.left + rect.width ||
-            this._currentMeasure.left + this._currentMeasure.width < rect.left ||
-            this._currentMeasure.top > rect.top + rect.height ||
-            this._currentMeasure.top + this._currentMeasure.height < rect.top
-        );
-        return hit;
+        if (this._currentMeasure.left >= rect.left + rect.width) {
+            return false;
+        }
+
+        if (this._currentMeasure.top >= rect.top + rect.height) {
+            return false;
+        }
+
+        if (this._currentMeasure.left + this._currentMeasure.width <= rect.left) {
+            return false;
+        }
+
+        if (this._currentMeasure.top + this._currentMeasure.height <= rect.top) {
+            return false;
+        }
+
+        return true;
     }
     }
 
 
     /** @hidden */
     /** @hidden */
-    protected invalidateRect() {
-        if (this.host) {
-            // Compute aabb of rotated container box (eg. to handle rotation)
-            var rectanglePoints = BABYLON.Polygon.Rectangle(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.left + this._currentMeasure.width, this._currentMeasure.top + this._currentMeasure.height);
+    protected invalidateRect(left: number, top: number, right: number, bottom: number) {
+        if (this.host && this.host.useInvalidateRectOptimization) {
+            // Compute AABB of transformed container box (eg. to handle rotation and scaling)
+            var rectanglePoints = BABYLON.Polygon.Rectangle(left, top, right, bottom);
             var min = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
             var min = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
             var max = new Vector2(0, 0);
             var max = new Vector2(0, 0);
-            this._invertTransformMatrix.invertToRef(this._invertTransformMatrix);
             for (var i = 0; i < 4; i++) {
             for (var i = 0; i < 4; i++) {
-                this._invertTransformMatrix.transformCoordinates(rectanglePoints[i].x, rectanglePoints[i].y, rectanglePoints[i]);
+                this._transformMatrix.transformCoordinates(rectanglePoints[i].x, rectanglePoints[i].y, rectanglePoints[i]);
                 min.x = Math.min(min.x, rectanglePoints[i].x);
                 min.x = Math.min(min.x, rectanglePoints[i].x);
                 min.y = Math.min(min.y, rectanglePoints[i].y);
                 min.y = Math.min(min.y, rectanglePoints[i].y);
                 max.x = Math.max(max.x, rectanglePoints[i].x);
                 max.x = Math.max(max.x, rectanglePoints[i].x);
                 max.y = Math.max(max.y, rectanglePoints[i].y);
                 max.y = Math.max(max.y, rectanglePoints[i].y);
             }
             }
-            this._invertTransformMatrix.invertToRef(this._invertTransformMatrix);
 
 
             this.host.invalidateRect(
             this.host.invalidateRect(
                 min.x,
                 min.x,
                 min.y,
                 min.y,
                 max.x,
                 max.x,
-                max.y
+                max.y,
+                left,
+                top,
+                right,
+                bottom
             );
             );
         }
         }
     }
     }
@@ -1120,7 +1135,6 @@ export class Control {
         // Redraw only this rectangle
         // Redraw only this rectangle
         if (this._host) {
         if (this._host) {
             this._host.markAsDirty();
             this._host.markAsDirty();
-            this.invalidateRect();
         }
         }
     }
     }
 
 
@@ -1221,27 +1235,39 @@ export class Control {
     }
     }
 
 
     /** @hidden */
     /** @hidden */
-    public _layout(parentMeasure: Measure, context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): boolean {
+    public _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean {
         if (!this.isVisible || this.notRenderable) {
         if (!this.isVisible || this.notRenderable) {
             return false;
             return false;
         }
         }
-        context.save();
 
 
-        this._applyStates(context);
+        if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
+            this._tempCurrentMeasure.copyFrom(this._currentMeasure);
 
 
-        let rebuildCount = 0;
-        do {
-            this._rebuildLayout = false;
-            this._processMeasures(parentMeasure, context);
-            rebuildCount++;
-        }
-        while (this._rebuildLayout && rebuildCount < 3);
+            context.save();
 
 
-        if (rebuildCount >= 3) {
-            BABYLON.Tools.Error(`Layout cycle detected in GUI (Control uniqueId=${this.uniqueId})`);
-        }
+            this._applyStates(context);
 
 
-        context.restore();
+            let rebuildCount = 0;
+            do {
+                this._rebuildLayout = false;
+                this._processMeasures(parentMeasure, context);
+                rebuildCount++;
+            }
+            while (this._rebuildLayout && rebuildCount < 3);
+
+            if (rebuildCount >= 3) {
+                BABYLON.Tools.Error(`Layout cycle detected in GUI (Control name=${this.name}, uniqueId=${this.uniqueId})`);
+            }
+
+            context.restore();
+            this.invalidateRect(
+                Math.min(this._currentMeasure.left, this._tempCurrentMeasure.left),
+                Math.min(this._currentMeasure.top, this._tempCurrentMeasure.top),
+                Math.max(this._currentMeasure.left + this._currentMeasure.width, this._tempCurrentMeasure.left + this._tempCurrentMeasure.width),
+                Math.max(this._currentMeasure.top + this._currentMeasure.height, this._tempCurrentMeasure.top + this._tempCurrentMeasure.height)
+            );
+            this._evaluateClippingState(parentMeasure);
+        }
 
 
         this._wasDirty = this._isDirty;
         this._wasDirty = this._isDirty;
         this._isDirty = false;
         this._isDirty = false;
@@ -1251,31 +1277,31 @@ export class Control {
 
 
     /** @hidden */
     /** @hidden */
     protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
     protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-        if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
-            this._currentMeasure.copyFrom(parentMeasure);
+        this._currentMeasure.copyFrom(parentMeasure);
 
 
-            // Let children take some pre-measurement actions
-            this._preMeasure(parentMeasure, context);
+        // Let children take some pre-measurement actions
+        this._preMeasure(parentMeasure, context);
 
 
-            this._measure();
-            this._computeAlignment(parentMeasure, context);
+        this._measure();
+        this._computeAlignment(parentMeasure, context);
 
 
-            // Convert to int values
-            this._currentMeasure.left = this._currentMeasure.left | 0;
-            this._currentMeasure.top = this._currentMeasure.top | 0;
-            this._currentMeasure.width = this._currentMeasure.width | 0;
-            this._currentMeasure.height = this._currentMeasure.height | 0;
+        // Convert to int values
+        this._currentMeasure.left = this._currentMeasure.left | 0;
+        this._currentMeasure.top = this._currentMeasure.top | 0;
+        this._currentMeasure.width = this._currentMeasure.width | 0;
+        this._currentMeasure.height = this._currentMeasure.height | 0;
 
 
-            // Let children add more features
-            this._additionalProcessing(parentMeasure, context);
+        // Let children add more features
+        this._additionalProcessing(parentMeasure, context);
 
 
-            this._cachedParentMeasure.copyFrom(parentMeasure);
+        this._cachedParentMeasure.copyFrom(parentMeasure);
 
 
-            if (this.onDirtyObservable.hasObservers()) {
-                this.onDirtyObservable.notifyObservers(this);
-            }
+        if (this.onDirtyObservable.hasObservers()) {
+            this.onDirtyObservable.notifyObservers(this);
         }
         }
+    }
 
 
+    protected _evaluateClippingState(parentMeasure: Measure) {
         if (this.parent && this.parent.clipChildren) {
         if (this.parent && this.parent.clipChildren) {
             // Early clip
             // Early clip
             if (this._currentMeasure.left > parentMeasure.left + parentMeasure.width) {
             if (this._currentMeasure.left > parentMeasure.left + parentMeasure.width) {
@@ -1416,14 +1442,13 @@ export class Control {
     private static _ClipMeasure = new Measure(0, 0, 0, 0);
     private static _ClipMeasure = new Measure(0, 0, 0, 0);
     private _clip(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>) {
     private _clip(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>) {
         context.beginPath();
         context.beginPath();
+
         Control._ClipMeasure.copyFrom(this._currentMeasure);
         Control._ClipMeasure.copyFrom(this._currentMeasure);
-        if (invalidatedRectangle) {
-            var right = Math.min(invalidatedRectangle.left + invalidatedRectangle.width, this._currentMeasure.left + this._currentMeasure.width);
-            var bottom = Math.min(invalidatedRectangle.top + invalidatedRectangle.height, this._currentMeasure.top + this._currentMeasure.height);
-            Control._ClipMeasure.left = Math.max(invalidatedRectangle.left, this._currentMeasure.left);
-            Control._ClipMeasure.top = Math.max(invalidatedRectangle.top, this._currentMeasure.top);
-            Control._ClipMeasure.width = right - Control._ClipMeasure.left;
-            Control._ClipMeasure.height = bottom - Control._ClipMeasure.top;
+        if (invalidatedRectangle && this._wasDirty) {
+            context.rect(invalidatedRectangle.left, invalidatedRectangle.top, invalidatedRectangle.width, invalidatedRectangle.height);
+            context.clip();
+
+            return;
         }
         }
 
 
         if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
         if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {

+ 1 - 1
gui/src/2D/controls/rectangle.ts

@@ -50,7 +50,7 @@ export class Rectangle extends Container {
         return "Rectangle";
         return "Rectangle";
     }
     }
 
 
-    protected _localDraw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void {
+    protected _localDraw(context: CanvasRenderingContext2D): void {
         context.save();
         context.save();
 
 
         if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
         if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {

+ 2 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/ellipsePropertyGridComponent.tsx

@@ -6,6 +6,7 @@ import { LockObject } from "../lockObject";
 import { Ellipse } from "babylonjs-gui";
 import { Ellipse } from "babylonjs-gui";
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
 
 
 interface IEllipsePropertyGridComponentProps {
 interface IEllipsePropertyGridComponentProps {
     ellipse: Ellipse,
     ellipse: Ellipse,
@@ -25,6 +26,7 @@ export class EllipsePropertyGridComponent extends React.Component<IEllipseProper
             <div className="pane">
             <div className="pane">
                 <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={ellipse} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={ellipse} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="ELLIPSE">
                 <LineContainerComponent title="ELLIPSE">
+                    <CheckBoxLineComponent label="Clip children" target={ellipse} propertyName="clipChildren" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Thickness" target={ellipse} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Thickness" target={ellipse} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 </LineContainerComponent>
             </div>
             </div>

+ 2 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/rectanglePropertyGridComponent.tsx

@@ -6,6 +6,7 @@ import { LockObject } from "../lockObject";
 import { Rectangle } from "babylonjs-gui";
 import { Rectangle } from "babylonjs-gui";
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
 
 
 interface IRectanglePropertyGridComponentProps {
 interface IRectanglePropertyGridComponentProps {
     rectangle: Rectangle,
     rectangle: Rectangle,
@@ -25,6 +26,7 @@ export class RectanglePropertyGridComponent extends React.Component<IRectanglePr
             <div className="pane">
             <div className="pane">
                 <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={rectangle} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={rectangle} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="RECTANGLE">
                 <LineContainerComponent title="RECTANGLE">
+                    <CheckBoxLineComponent label="Clip children" target={rectangle} propertyName="clipChildren" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Thickness" target={rectangle} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Thickness" target={rectangle} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Corner radius" target={rectangle} propertyName="cornerRadius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Corner radius" target={rectangle} propertyName="cornerRadius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 </LineContainerComponent>

+ 1 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/stackPanelPropertyGridComponent.tsx

@@ -25,6 +25,7 @@ export class StackPanelPropertyGridComponent extends React.Component<IStackPanel
             <div className="pane">
             <div className="pane">
                 <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={stackPanel} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={stackPanel} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="STACKPANEL">
                 <LineContainerComponent title="STACKPANEL">
+                    <CheckBoxLineComponent label="Clip children" target={stackPanel} propertyName="clipChildren" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Vertical" target={stackPanel} propertyName="isVertical" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Vertical" target={stackPanel} propertyName="isVertical" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 </LineContainerComponent>
             </div>
             </div>

+ 1 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx

@@ -111,6 +111,7 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
                         <FloatLineComponent lockObject={this.props.lockObject} label="Ideal height" target={texture} propertyName="idealHeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <FloatLineComponent lockObject={this.props.lockObject} label="Ideal height" target={texture} propertyName="idealHeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Use smallest ideal" target={texture} propertyName="useSmallestIdeal" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Use smallest ideal" target={texture} propertyName="useSmallestIdeal" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Render at ideal size" target={texture} propertyName="renderAtIdealSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Render at ideal size" target={texture} propertyName="renderAtIdealSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <CheckBoxLineComponent label="Invalidate Rect optimization" target={texture} propertyName="useInvalidateRectOptimization" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     </LineContainerComponent>
                     </LineContainerComponent>
                 }
                 }
                 <LineContainerComponent title="TRANSFORM">
                 <LineContainerComponent title="TRANSFORM">