Parcourir la source

Merge pull request #1194 from nockawa/GroupTracker

Canvas2D: TrackedNode feature + bug fixes
Raanan Weber il y a 9 ans
Parent
commit
5433eb5582

+ 58 - 7
src/Canvas2d/babylon.canvas2d.ts

@@ -110,6 +110,7 @@
             this._scene                         = scene;
             this._engine                        = engine;
             this._renderingSize                 = new Size(0, 0);
+            this._trackedGroups                 = new Array<Group2D>();
 
             this._patchHierarchy(this);
 
@@ -128,7 +129,7 @@
                 this.dispose();
             });
 
-            if (this._isScreeSpace) {
+            if (this._isScreenSpace) {
                 this._afterRenderObserver = this._scene.onAfterRenderObservable.add((d, s) => {
                     this._engine.clear(null, false, true);
                     this._render();
@@ -148,7 +149,7 @@
         protected _canvasPreInit(settings: any) {
             let cachingStrategy   = (settings.cachingStrategy == null) ? Canvas2D.CACHESTRATEGY_DONTCACHE : settings.cachingStrategy;
             this._cachingStrategy = cachingStrategy;
-            this._isScreeSpace = (settings.isScreenSpace == null) ? true : settings.isScreenSpace;
+            this._isScreenSpace = (settings.isScreenSpace == null) ? true : settings.isScreenSpace;
         }
 
         public static hierarchyLevelMaxSiblingCount: number = 10;
@@ -163,7 +164,7 @@
             this._interactionEnabled = enable;
 
             // ScreenSpace mode
-            if (this._isScreeSpace) {
+            if (this._isScreenSpace) {
                 // Disable interaction
                 if (!enable) {
                     if (this._scenePrePointerObserver) {
@@ -342,7 +343,7 @@
             var camera = this._scene.activeCamera;
             var engine = this._scene.getEngine();
 
-            if (this._isScreeSpace) {
+            if (this._isScreenSpace) {
                 var cameraViewport = camera.viewport;
                 var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
 
@@ -849,14 +850,15 @@
         private _scene: Scene;
         private _engine: Engine;
         private _fitRenderingDevice: boolean;
-        private _isScreeSpace: boolean;
+        private _isScreenSpace: boolean;
         private _cachedCanvasGroup: Group2D;
         private _cachingStrategy: number;
         private _hierarchyLevelMaxSiblingCount: number;
         private _groupCacheMaps: MapTexture[];
         private _beforeRenderObserver: Observer<Scene>;
         private _afterRenderObserver: Observer<Scene>;
-        private _supprtInstancedArray : boolean;
+        private _supprtInstancedArray: boolean;
+        private _trackedGroups: Array<Group2D>;
 
         public _renderingSize: Size;
 
@@ -864,6 +866,30 @@
             this._addPrimToDirtyList(this);
         }
 
+        private static _v = Vector3.Zero();
+        private static _m = Matrix.Identity();
+
+        private _updateTrackedNodes() {
+            let cam = this.scene.activeCamera;
+
+            cam.getViewMatrix().multiplyToRef(cam.getProjectionMatrix(), Canvas2D._m);
+            let rh = this.engine.getRenderHeight();
+            let v = cam.viewport.toGlobal(this.engine.getRenderWidth(), rh);
+
+            for (let group of this._trackedGroups) {
+                if (group.isDisposed || !group.isVisible) {
+                    continue;
+                }
+
+                let node = group.trackedNode;
+                let worldMtx = node.getWorldMatrix();
+
+                let proj = Vector3.Project(Canvas2D._v, worldMtx, Canvas2D._m, v);
+                group.x = Math.round(proj.x);
+                group.y = Math.round(rh - proj.y);
+            }
+        }
+
         private _updateCanvasState() {
             // Check if the update has already been made for this render Frame
             if (this.scene.getRenderId() === this._updateRenderId) {
@@ -911,6 +937,8 @@
          */
         private _render() {
 
+            this._updateTrackedNodes();
+
             this._updateCanvasState();
 
             if (this._primPointerInfo.canvasPointerPos) {
@@ -976,7 +1004,7 @@
 
             // Check if we have to create a Sprite that will display the content of the Canvas which is cached.
             // Don't do it in case of the group being a worldspace canvas (because its texture is bound to a WorldSpaceCanvas node)
-            if (group !== <any>this || this._isScreeSpace) {
+            if (group !== <any>this || this._isScreenSpace) {
                 let node: PackedRect = res.node;
 
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
@@ -1003,6 +1031,29 @@
          */
         private static _groupTextureCacheSize = 1024;
 
+
+        public _registerTrackedNode(group: Group2D) {
+            if (group._isFlagSet(SmartPropertyPrim.flagTrackedGroup)) {
+                return;
+            }
+            this._trackedGroups.push(group);
+
+            group._setFlags(SmartPropertyPrim.flagTrackedGroup);
+        }
+
+        public _unregisterTrackedNode(group: Group2D) {
+            if (!group._isFlagSet(SmartPropertyPrim.flagTrackedGroup)) {
+                return;
+            }
+
+            let i = this._trackedGroups.indexOf(group);
+            if (i !== -1) {
+                this._trackedGroups.splice(i, 1);
+            }
+
+            group._clearFlags(SmartPropertyPrim.flagTrackedGroup);
+        }
+
         /**
          * Get a Solid Color Brush instance matching the given color.
          * @param color The color to retrieve

+ 30 - 0
src/Canvas2d/babylon.group2d.ts

@@ -44,6 +44,7 @@
             position          ?: Vector2,
             x                 ?: number,
             y                 ?: number,
+            trackNode         ?: Node,
             origin            ?: Vector2,
             size              ?: Size,
             width             ?: number,
@@ -78,6 +79,11 @@
  
             let size = (!settings.size && !settings.width && !settings.height) ? null : (settings.size || (new Size(settings.width || 0, settings.height || 0)));
 
+            this._trackedNode = (settings.trackNode == null) ? null : settings.trackNode;
+            if (this._trackedNode && this.owner) {
+                this.owner._registerTrackedNode(this);
+            }
+
             this._cacheBehavior = (settings.cacheBehavior==null) ? Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY : settings.cacheBehavior;
             this.size = size;
             this._viewportPosition = Vector2.Zero();
@@ -135,6 +141,11 @@
                 return false;
             }
 
+            if (this._trackedNode != null) {
+                this.owner._unregisterTrackedNode(this);
+                this._trackedNode = null;
+            }
+
             if (this._renderableData) {
                 this._renderableData.dispose();
                 this._renderableData = null;
@@ -223,6 +234,24 @@
             this._groupRender();
         }
 
+        public get trackedNode(): Node {
+            return this._trackedNode;
+        }
+
+        public set trackedNode(val: Node) {
+            if (val!=null) {
+                if (!this._isFlagSet(SmartPropertyPrim.flagTrackedGroup)) {
+                    this.owner._registerTrackedNode(this);
+                }
+                this._trackedNode = val;
+            } else {
+                if (this._isFlagSet(SmartPropertyPrim.flagTrackedGroup)) {
+                    this.owner._unregisterTrackedNode(this);
+                }
+                this._trackedNode = null;
+            }
+        }
+
         protected levelIntersect(intersectInfo: IntersectInfo2D): boolean {
             // If we've made it so far it means the boundingInfo intersection test succeed, the Group2D is shaped the same, so we always return true
             return true;
@@ -767,6 +796,7 @@
             }
         }
 
+        private _trackedNode: Node;
         protected _isRenderableGroup: boolean;
         protected _isCachedGroup: boolean;
         private _cacheGroupDirty: boolean;

+ 4 - 1
src/Canvas2d/babylon.prim2dBase.ts

@@ -1519,7 +1519,7 @@
         }
 
         private static boundinbBoxReentrency = false;
-        private static nullSize = Size.Zero();
+        protected static nullSize = Size.Zero();
 
         /**
          * Size of the primitive or its bounding area
@@ -2408,6 +2408,9 @@
             if (this instanceof Group2D) {
                 var group: any = this;
                 group.detectGroupStates();
+                if (group._trackedNode && !group._isFlagSet(SmartPropertyPrim.flagTrackedGroup)) {
+                    group.owner._registerTrackedNode(this);
+                }
             }
 
             if (this._parent) {

+ 1 - 0
src/Canvas2d/babylon.smartPropertyPrim.ts

@@ -566,6 +566,7 @@
         public static flagIsVisible              = 0x0000080;    // set if the primitive is concretely visible (use the levelVisible of parents)
         public static flagVisibilityChanged      = 0x0000100;    // set if there was a transition between visible/hidden status
         public static flagPositioningDirty       = 0x0000200;    // set if the primitive positioning must be computed
+        public static flagTrackedGroup           = 0x0000400;    // set if the group2D is tracking a scene node
 
         private   _flags             : number;
         private   _externalData      : StringDictionary<Object>;

+ 10 - 5
src/Canvas2d/babylon.text2d.ts

@@ -178,13 +178,18 @@
         }
 
         public get textSize(): Size {
-            if (!this._textSize && this.owner) {
-                let newSize = this.fontTexture.measureText(this._text, this._tabulationSize);
-                if (newSize !== this._textSize) {
-                    this.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
+            if (!this._textSize) {
+                if (this.owner) {
+                    let newSize = this.fontTexture.measureText(this._text, this._tabulationSize);
+                    if (newSize !== this._textSize) {
+                        this.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
+                    }
+                    this._textSize = newSize;
+                } else {
+                    return Text2D.nullSize;
                 }
-                this._textSize = newSize;
             }
+            
             return this._textSize;
         }