David Catuhe 9 年之前
父节点
当前提交
019f4e59c2

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


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


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


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


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


+ 3 - 0
src/Actions/babylon.actionManager.js

@@ -46,6 +46,9 @@ var BABYLON;
         ActionEvent.CreateNewFromScene = function (scene, evt) {
             return new ActionEvent(null, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt);
         };
+        ActionEvent.CreateNewFromPrimitive = function (prim, pointerPos, evt, additionalData) {
+            return new ActionEvent(prim, pointerPos.x, pointerPos.y, null, evt, additionalData);
+        };
         return ActionEvent;
     })();
     BABYLON.ActionEvent = ActionEvent;

+ 6 - 0
src/Actions/babylon.directActions.js

@@ -67,6 +67,9 @@ var BABYLON;
         };
         SetValueAction.prototype.execute = function () {
             this._effectiveTarget[this._property] = this.value;
+            if (this._target.markAsDirty) {
+                this._target.markAsDirty(this._property);
+            }
         };
         SetValueAction.prototype.serialize = function (parent) {
             return _super.prototype._serialize.call(this, {
@@ -98,6 +101,9 @@ var BABYLON;
         };
         IncrementValueAction.prototype.execute = function () {
             this._effectiveTarget[this._property] += this.value;
+            if (this._target.markAsDirty) {
+                this._target.markAsDirty(this._property);
+            }
         };
         IncrementValueAction.prototype.serialize = function (parent) {
             return _super.prototype._serialize.call(this, {

+ 30 - 0
src/Animations/babylon.animation.js

@@ -120,6 +120,9 @@ var BABYLON;
             else if (from instanceof BABYLON.Color3) {
                 dataType = Animation.ANIMATIONTYPE_COLOR3;
             }
+            else if (from instanceof BABYLON.Size) {
+                dataType = Animation.ANIMATIONTYPE_SIZE;
+            }
             if (dataType == undefined) {
                 return null;
             }
@@ -248,6 +251,9 @@ var BABYLON;
         Animation.prototype.vector2InterpolateFunction = function (startValue, endValue, gradient) {
             return BABYLON.Vector2.Lerp(startValue, endValue, gradient);
         };
+        Animation.prototype.sizeInterpolateFunction = function (startValue, endValue, gradient) {
+            return BABYLON.Size.Lerp(startValue, endValue, gradient);
+        };
         Animation.prototype.color3InterpolateFunction = function (startValue, endValue, gradient) {
             return BABYLON.Color3.Lerp(startValue, endValue, gradient);
         };
@@ -342,6 +348,15 @@ var BABYLON;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                     return this.vector2InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
                             }
+                        // Size
+                        case Animation.ANIMATIONTYPE_SIZE:
+                            switch (loopMode) {
+                                case Animation.ANIMATIONLOOPMODE_CYCLE:
+                                case Animation.ANIMATIONLOOPMODE_CONSTANT:
+                                    return this.sizeInterpolateFunction(startValue, endValue, gradient);
+                                case Animation.ANIMATIONLOOPMODE_RELATIVE:
+                                    return this.sizeInterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
+                            }
                         // Color3
                         case Animation.ANIMATIONTYPE_COLOR3:
                             switch (loopMode) {
@@ -481,6 +496,9 @@ var BABYLON;
                             // Vector2
                             case Animation.ANIMATIONTYPE_VECTOR2:
                                 this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
+                            // Size
+                            case Animation.ANIMATIONTYPE_SIZE:
+                                this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
                             // Color3
                             case Animation.ANIMATIONTYPE_COLOR3:
                                 this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
@@ -511,6 +529,10 @@ var BABYLON;
                     case Animation.ANIMATIONTYPE_VECTOR2:
                         offsetValue = BABYLON.Vector2.Zero();
                         break;
+                    // Size
+                    case Animation.ANIMATIONTYPE_SIZE:
+                        offsetValue = BABYLON.Size.Zero();
+                        break;
                     // Color3
                     case Animation.ANIMATIONTYPE_COLOR3:
                         offsetValue = BABYLON.Color3.Black();
@@ -604,6 +626,13 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(Animation, "ANIMATIONTYPE_SIZE", {
+            get: function () {
+                return Animation._ANIMATIONTYPE_SIZE;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Animation, "ANIMATIONTYPE_QUATERNION", {
             get: function () {
                 return Animation._ANIMATIONTYPE_QUATERNION;
@@ -702,6 +731,7 @@ var BABYLON;
         Animation._ANIMATIONTYPE_MATRIX = 3;
         Animation._ANIMATIONTYPE_COLOR3 = 4;
         Animation._ANIMATIONTYPE_VECTOR2 = 5;
+        Animation._ANIMATIONTYPE_SIZE = 6;
         Animation._ANIMATIONLOOPMODE_RELATIVE = 0;
         Animation._ANIMATIONLOOPMODE_CYCLE = 1;
         Animation._ANIMATIONLOOPMODE_CONSTANT = 2;

+ 92 - 14
src/Canvas2d/babylon.canvas2d.js

@@ -114,6 +114,7 @@ var BABYLON;
             this._hierarchySiblingZDelta = this._hierarchyLevelZFactor / this._hierarchyLevelMaxSiblingCount;
             this._primPointerInfo = new BABYLON.PrimitivePointerInfo();
             this._capturedPointers = new BABYLON.StringDictionary();
+            this._pickStartingPosition = BABYLON.Vector2.Zero();
             this.setupGroup2D(this, null, name, BABYLON.Vector2.Zero(), size, this._cachingStrategy === Canvas2D.CACHESTRATEGY_ALLGROUPS ? BABYLON.Group2D.GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE : BABYLON.Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY);
             this._scene = scene;
             this._engine = engine;
@@ -178,7 +179,7 @@ var BABYLON;
             catch (e) {
             }
             this._primPointerInfo.updateRelatedTarget(primitive, BABYLON.Vector2.Zero());
-            this._bubbleNotifyPrimPointerObserver(primitive, BABYLON.PrimitivePointerInfo.PointerGotCapture);
+            this._bubbleNotifyPrimPointerObserver(primitive, BABYLON.PrimitivePointerInfo.PointerGotCapture, null);
             this._capturedPointers.add(pointerId.toString(), primitive);
             return true;
         };
@@ -196,7 +197,7 @@ var BABYLON;
             catch (e) {
             }
             this._primPointerInfo.updateRelatedTarget(primitive, BABYLON.Vector2.Zero());
-            this._bubbleNotifyPrimPointerObserver(primitive, BABYLON.PrimitivePointerInfo.PointerLostCapture);
+            this._bubbleNotifyPrimPointerObserver(primitive, BABYLON.PrimitivePointerInfo.PointerLostCapture, null);
             this._capturedPointers.remove(pointerId.toString());
             return true;
         };
@@ -234,16 +235,16 @@ var BABYLON;
             this._primPointerInfo.updateRelatedTarget(targetPrim, targetPointerPos);
             // Analyze the pointer event type and fire proper events on the primitive
             if (eventData.type === BABYLON.PointerEventTypes.POINTERWHEEL) {
-                this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerMouseWheel);
+                this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerMouseWheel, eventData.event);
             }
             else if (eventData.type === BABYLON.PointerEventTypes.POINTERMOVE) {
-                this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerMove);
+                this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerMove, eventData.event);
             }
             else if (eventData.type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerDown);
+                this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerDown, eventData.event);
             }
             else if (eventData.type === BABYLON.PointerEventTypes.POINTERUP) {
-                this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerUp);
+                this._bubbleNotifyPrimPointerObserver(targetPrim, BABYLON.PrimitivePointerInfo.PointerUp, eventData.event);
             }
         };
         Canvas2D.prototype._updatePointerInfo = function (eventData) {
@@ -318,12 +319,12 @@ var BABYLON;
                 // Notify the previous "over" prim that the pointer is no longer over it
                 if ((capturedPrim && capturedPrim === prevPrim) || (!capturedPrim && prevPrim)) {
                     this._primPointerInfo.updateRelatedTarget(prevPrim, this._previousOverPrimitive.intersectionLocation);
-                    this._bubbleNotifyPrimPointerObserver(prevPrim, BABYLON.PrimitivePointerInfo.PointerOut);
+                    this._bubbleNotifyPrimPointerObserver(prevPrim, BABYLON.PrimitivePointerInfo.PointerOut, null);
                 }
                 // Notify the new "over" prim that the pointer is over it
                 if ((capturedPrim && capturedPrim === actualPrim) || (!capturedPrim && actualPrim)) {
                     this._primPointerInfo.updateRelatedTarget(actualPrim, this._actualOverPrimitive.intersectionLocation);
-                    this._bubbleNotifyPrimPointerObserver(actualPrim, BABYLON.PrimitivePointerInfo.PointerOver);
+                    this._bubbleNotifyPrimPointerObserver(actualPrim, BABYLON.PrimitivePointerInfo.PointerOver, null);
                 }
             }
             this._hoverStatusRenderId = this.scene.getRenderId();
@@ -354,8 +355,8 @@ var BABYLON;
             debug += "[RID:" + this.scene.getRenderId() + "] [" + prim.hierarchyDepth + "] event:" + BABYLON.PrimitivePointerInfo.getEventTypeName(mask) + ", id: " + prim.id + " (" + BABYLON.Tools.getClassName(prim) + "), primPos: " + pii.primitivePointerPos.toString() + ", canvasPos: " + pii.canvasPointerPos.toString();
             console.log(debug);
         };
-        Canvas2D.prototype._bubbleNotifyPrimPointerObserver = function (prim, mask) {
-            var pii = this._primPointerInfo;
+        Canvas2D.prototype._bubbleNotifyPrimPointerObserver = function (prim, mask, eventData) {
+            var ppi = this._primPointerInfo;
             // In case of PointerOver/Out we will first notify the children (but the deepest to the closest) with PointerEnter/Leave
             if ((mask & (BABYLON.PrimitivePointerInfo.PointerOver | BABYLON.PrimitivePointerInfo.PointerOut)) !== 0) {
                 this._notifChildren(prim, mask);
@@ -368,10 +369,11 @@ var BABYLON;
                     this._updatePrimPointerPos(cur);
                     // Exec the observers
                     this._debugExecObserver(cur, mask);
-                    cur._pointerEventObservable.notifyObservers(pii, mask);
+                    cur._pointerEventObservable.notifyObservers(ppi, mask);
+                    this._triggerActionManager(cur, ppi, mask, eventData);
                     // Bubble canceled? If we're not executing PointerOver or PointerOut, quit immediately
                     // If it's PointerOver/Out we have to trigger PointerEnter/Leave no matter what
-                    if (pii.cancelBubble) {
+                    if (ppi.cancelBubble) {
                         if ((mask & (BABYLON.PrimitivePointerInfo.PointerOver | BABYLON.PrimitivePointerInfo.PointerOut)) === 0) {
                             return;
                         }
@@ -386,16 +388,92 @@ var BABYLON;
                 // Trigger a PointerEnter corresponding to the PointerOver
                 if (mask === BABYLON.PrimitivePointerInfo.PointerOver) {
                     this._debugExecObserver(cur, BABYLON.PrimitivePointerInfo.PointerEnter);
-                    cur._pointerEventObservable.notifyObservers(pii, BABYLON.PrimitivePointerInfo.PointerEnter);
+                    cur._pointerEventObservable.notifyObservers(ppi, BABYLON.PrimitivePointerInfo.PointerEnter);
                 }
                 else if (mask === BABYLON.PrimitivePointerInfo.PointerOut) {
                     this._debugExecObserver(cur, BABYLON.PrimitivePointerInfo.PointerLeave);
-                    cur._pointerEventObservable.notifyObservers(pii, BABYLON.PrimitivePointerInfo.PointerLeave);
+                    cur._pointerEventObservable.notifyObservers(ppi, BABYLON.PrimitivePointerInfo.PointerLeave);
                 }
                 // Loop to the parent
                 cur = cur.parent;
             }
         };
+        Canvas2D.prototype._triggerActionManager = function (prim, ppi, mask, eventData) {
+            var _this = this;
+            // Process Trigger related to PointerDown
+            if ((mask & BABYLON.PrimitivePointerInfo.PointerDown) !== 0) {
+                // On pointer down, record the current position and time to be able to trick PickTrigger and LongPressTrigger
+                this._pickStartingPosition = ppi.primitivePointerPos.clone();
+                this._pickStartingTime = new Date().getTime();
+                this._pickedDownPrim = null;
+                if (prim.actionManager) {
+                    this._pickedDownPrim = prim;
+                    if (prim.actionManager.hasPickTriggers) {
+                        var actionEvent = BABYLON.ActionEvent.CreateNewFromPrimitive(prim, ppi.primitivePointerPos, eventData);
+                        switch (eventData.button) {
+                            case 0:
+                                prim.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, actionEvent);
+                                break;
+                            case 1:
+                                prim.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, actionEvent);
+                                break;
+                            case 2:
+                                prim.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, actionEvent);
+                                break;
+                        }
+                        prim.actionManager.processTrigger(BABYLON.ActionManager.OnPickDownTrigger, actionEvent);
+                    }
+                    if (prim.actionManager.hasSpecificTrigger(BABYLON.ActionManager.OnLongPressTrigger)) {
+                        window.setTimeout(function () {
+                            var ppi = _this._primPointerInfo;
+                            var capturedPrim = _this.getCapturedPrimitive(ppi.pointerId);
+                            _this._updateIntersectionList(ppi.canvasPointerPos, capturedPrim !== null);
+                            var ii = new BABYLON.IntersectInfo2D();
+                            ii.pickPosition = ppi.canvasPointerPos.clone();
+                            ii.findFirstOnly = false;
+                            _this.intersect(ii);
+                            if (ii.isIntersected) {
+                                var iprim = ii.topMostIntersectedPrimitive.prim;
+                                if (iprim.actionManager) {
+                                    if (_this._pickStartingTime !== 0 && ((new Date().getTime() - _this._pickStartingTime) > BABYLON.ActionManager.LongPressDelay) && (Math.abs(_this._pickStartingPosition.x - ii.pickPosition.x) < BABYLON.ActionManager.DragMovementThreshold && Math.abs(_this._pickStartingPosition.y - ii.pickPosition.y) < BABYLON.ActionManager.DragMovementThreshold)) {
+                                        _this._pickStartingTime = 0;
+                                        iprim.actionManager.processTrigger(BABYLON.ActionManager.OnLongPressTrigger, BABYLON.ActionEvent.CreateNewFromPrimitive(prim, ppi.primitivePointerPos, eventData));
+                                    }
+                                }
+                            }
+                        }, BABYLON.ActionManager.LongPressDelay);
+                    }
+                }
+            }
+            else if ((mask & BABYLON.PrimitivePointerInfo.PointerUp) !== 0) {
+                this._pickStartingTime = 0;
+                var actionEvent = BABYLON.ActionEvent.CreateNewFromPrimitive(prim, ppi.primitivePointerPos, eventData);
+                if (prim.actionManager) {
+                    // OnPickUpTrigger
+                    prim.actionManager.processTrigger(BABYLON.ActionManager.OnPickUpTrigger, actionEvent);
+                    // OnPickTrigger
+                    if (Math.abs(this._pickStartingPosition.x - ppi.canvasPointerPos.x) < BABYLON.ActionManager.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ppi.canvasPointerPos.y) < BABYLON.ActionManager.DragMovementThreshold) {
+                        prim.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, actionEvent);
+                    }
+                }
+                // OnPickOutTrigger
+                if (this._pickedDownPrim && this._pickedDownPrim.actionManager && (this._pickedDownPrim !== prim)) {
+                    this._pickedDownPrim.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, actionEvent);
+                }
+            }
+            else if ((mask & BABYLON.PrimitivePointerInfo.PointerOver) !== 0) {
+                if (prim.actionManager) {
+                    var actionEvent = BABYLON.ActionEvent.CreateNewFromPrimitive(prim, ppi.primitivePointerPos, eventData);
+                    prim.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger, actionEvent);
+                }
+            }
+            else if ((mask & BABYLON.PrimitivePointerInfo.PointerOut) !== 0) {
+                if (prim.actionManager) {
+                    var actionEvent = BABYLON.ActionEvent.CreateNewFromPrimitive(prim, ppi.primitivePointerPos, eventData);
+                    prim.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger, actionEvent);
+                }
+            }
+        };
         Canvas2D.prototype._notifChildren = function (prim, mask) {
             var _this = this;
             var pii = this._primPointerInfo;

+ 16 - 2
src/Canvas2d/babylon.prim2dBase.js

@@ -258,6 +258,16 @@ var BABYLON;
             this.levelVisible = isVisible;
             this.origin = new BABYLON.Vector2(0.5, 0.5);
         };
+        Object.defineProperty(Prim2DBase.prototype, "actionManager", {
+            get: function () {
+                if (!this._actionManager) {
+                    this._actionManager = new BABYLON.ActionManager(this.owner.scene);
+                }
+                return this._actionManager;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
          * From 'this' primitive, traverse up (from parent to parent) until the given predicate is true
          * @param predicate the predicate to test on each parent
@@ -610,6 +620,10 @@ var BABYLON;
             if (!_super.prototype.dispose.call(this)) {
                 return false;
             }
+            if (!this._actionManager) {
+                this._actionManager.dispose();
+                this._actionManager = null;
+            }
             // If there's a parent, remove this object from its parent list
             if (this._parent) {
                 var i = this._parent._children.indexOf(this);
@@ -635,7 +649,7 @@ var BABYLON;
             }
         };
         Prim2DBase.prototype._needPrepare = function () {
-            return (this.isVisible || this._visibilityChanged) && (this._modelDirty || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep));
+            return this._visibilityChanged && (this._modelDirty || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep));
         };
         Prim2DBase.prototype._prepareRender = function (context) {
             this._prepareRenderPre(context);
@@ -710,7 +724,7 @@ var BABYLON;
                 var curVisibleState = this.isVisible;
                 this.isVisible = (!this._parent || this._parent.isVisible) && this.levelVisible;
                 // Detect a change of visibility
-                this._visibilityChanged = (curVisibleState !== undefined) && curVisibleState !== this.isVisible;
+                this._visibilityChanged = curVisibleState !== this.isVisible;
                 // Get/compute the localTransform
                 var localDirty = this._updateLocalTransform();
                 // Check if we have to update the globalTransform

+ 81 - 18
src/Canvas2d/babylon.smartPropertyPrim.js

@@ -140,22 +140,45 @@ var BABYLON;
             this._instanceDirtyFlags = 0;
             this._isDisposed = false;
             this._levelBoundingInfo = new BABYLON.BoundingInfo2D();
+            this.animations = new Array();
         };
         Object.defineProperty(SmartPropertyPrim.prototype, "isDisposed", {
+            /**
+             * Check if the object is disposed or not.
+             * @returns true if the object is dispose, false otherwise.
+             */
             get: function () {
                 return this._isDisposed;
             },
             enumerable: true,
             configurable: true
         });
+        /**
+         * Disposable pattern, this method must be overloaded by derived types in order to clean up hardware related resources.
+         * @returns false if the object is already dispose, true otherwise. Your implementation must call super.dispose() and check for a false return and return immediately if it's the case.
+         */
         SmartPropertyPrim.prototype.dispose = function () {
             if (this.isDisposed) {
                 return false;
             }
+            // Don't set to null, it may upset somebody...
+            this.animations.splice(0);
             this._isDisposed = true;
             return true;
         };
+        /**
+         * Returns as a new array populated with the Animatable used by the primitive. Must be overloaded by derived primitives.
+         * Look at Sprite2D for more information
+         */
+        SmartPropertyPrim.prototype.getAnimatables = function () {
+            return new Array();
+        };
         Object.defineProperty(SmartPropertyPrim.prototype, "modelKey", {
+            /**
+             * Property giving the Model Key associated to the property.
+             * This value is constructed from the type of the primitive and all the name/value of its properties declared with the modelLevelProperty decorator
+             * @returns the model key string.
+             */
             get: function () {
                 var _this = this;
                 // No need to compute it?
@@ -178,6 +201,10 @@ var BABYLON;
             configurable: true
         });
         Object.defineProperty(SmartPropertyPrim.prototype, "isDirty", {
+            /**
+             * States if the Primitive is dirty and should be rendered again next time.
+             * @returns true is dirty, false otherwise
+             */
             get: function () {
                 return (this._instanceDirtyFlags !== 0) || this._modelDirty;
             },
@@ -185,6 +212,10 @@ var BABYLON;
             configurable: true
         });
         Object.defineProperty(SmartPropertyPrim.prototype, "propDic", {
+            /**
+             * Access the dictionary of properties metadata. Only properties decorated with XXXXLevelProperty are concerned
+             * @returns the dictionary, the key is the property name as declared in Javascript, the value is the metadata object
+             */
             get: function () {
                 if (!this._propInfo) {
                     var cti = ClassTreeInfo.get(Object.getPrototypeOf(this));
@@ -213,7 +244,7 @@ var BABYLON;
             propInfo.name = propName;
             propInfo.dirtyBoundingInfo = dirtyBoundingInfo;
             propInfo.typeLevelCompare = typeLevelCompare;
-            node.levelContent.add(propId.toString(), propInfo);
+            node.levelContent.add(propName, propInfo);
             return propInfo;
         };
         SmartPropertyPrim._checkUnchanged = function (curValue, newValue) {
@@ -236,7 +267,36 @@ var BABYLON;
             }
             return false;
         };
+        SmartPropertyPrim.prototype.markAsDirty = function (propertyName) {
+            var i = propertyName.indexOf(".");
+            if (i !== -1) {
+                propertyName = propertyName.substr(0, i);
+            }
+            var propInfo = this.propDic.get(propertyName);
+            if (!propInfo) {
+                return;
+            }
+            var newValue = this[propertyName];
+            this._handlePropChanged(undefined, newValue, propertyName, propInfo, propInfo.typeLevelCompare);
+        };
         SmartPropertyPrim.prototype._handlePropChanged = function (curValue, newValue, propName, propInfo, typeLevelCompare) {
+            // If the property change also dirty the boundingInfo, update the boundingInfo dirty flags
+            if (propInfo.dirtyBoundingInfo) {
+                this._levelBoundingInfoDirty = true;
+                // Escalate the dirty flag in the instance hierarchy, stop when a renderable group is found or at the end
+                if (this instanceof BABYLON.Prim2DBase) {
+                    var curprim = this.parent;
+                    while (curprim) {
+                        curprim._boundingInfoDirty = true;
+                        if (curprim instanceof BABYLON.Group2D) {
+                            if (curprim.isRenderableGroup) {
+                                break;
+                            }
+                        }
+                        curprim = curprim.parent;
+                    }
+                }
+            }
             // Trigger property changed
             var info = SmartPropertyPrim.propChangedInfo;
             info.oldValue = curValue;
@@ -273,14 +333,28 @@ var BABYLON;
         };
         SmartPropertyPrim.prototype.handleGroupChanged = function (prop) {
         };
+        /**
+         * Check if a given set of properties are dirty or not.
+         * @param flags a ORed combination of Prim2DPropInfo.flagId values
+         * @return true if at least one property is dirty, false if none of them are.
+         */
         SmartPropertyPrim.prototype.checkPropertiesDirty = function (flags) {
             return (this._instanceDirtyFlags & flags) !== 0;
         };
+        /**
+         * Clear a given set of properties.
+         * @param flags a ORed combination of Prim2DPropInfo.flagId values
+         * @return the new set of property still marked as dirty
+         */
         SmartPropertyPrim.prototype.clearPropertiesDirty = function (flags) {
             this._instanceDirtyFlags &= ~flags;
             return this._instanceDirtyFlags;
         };
         Object.defineProperty(SmartPropertyPrim.prototype, "levelBoundingInfo", {
+            /**
+             * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
+             * @returns {}
+             */
             get: function () {
                 if (this._levelBoundingInfoDirty) {
                     this.updateLevelBoundingInfo();
@@ -291,8 +365,14 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        /**
+         * This method must be overridden by a given Primitive implementation to compute its boundingInfo
+         */
         SmartPropertyPrim.prototype.updateLevelBoundingInfo = function () {
         };
+        /**
+         * Property method called when the Primitive becomes dirty
+         */
         SmartPropertyPrim.prototype.onPrimBecomesDirty = function () {
         };
         SmartPropertyPrim._hookProperty = function (propId, piStore, typeLevelCompare, dirtyBoundingInfo, kind) {
@@ -316,23 +396,6 @@ var BABYLON;
                     var prim = this;
                     // Change the value
                     setter.call(this, val);
-                    // If the property change also dirty the boundingInfo, update the boundingInfo dirty flags
-                    if (propInfo.dirtyBoundingInfo) {
-                        prim._levelBoundingInfoDirty = true;
-                        // Escalate the dirty flag in the instance hierarchy, stop when a renderable group is found or at the end
-                        if (prim instanceof BABYLON.Prim2DBase) {
-                            var curprim = prim.parent;
-                            while (curprim) {
-                                curprim._boundingInfoDirty = true;
-                                if (curprim instanceof BABYLON.Group2D) {
-                                    if (curprim.isRenderableGroup) {
-                                        break;
-                                    }
-                                }
-                                curprim = curprim.parent;
-                            }
-                        }
-                    }
                     // Notify change, dirty flags update
                     prim._handlePropChanged(curVal, val, propName, propInfo, typeLevelCompare);
                 };

+ 2 - 2
src/Canvas2d/babylon.smartPropertyPrim.ts

@@ -91,7 +91,7 @@
                     }
                 }
                 let node = new ClassTreeInfo<TClass, TProp>(this, type, this._classContentFactory);
-                let info = { type: type, node: node};
+                let info = { type: type, node: node };
                 this._subClasses.push(info);
                 return info.node;
             }
@@ -126,7 +126,7 @@
         private _type: Object;
         private _classContent: TClass;
         private _baseClass: ClassTreeInfo<TClass, TProp>;
-        private _subClasses: Array<{type: Object, node: ClassTreeInfo<TClass, TProp>}>;
+        private _subClasses: Array<{ type: Object, node: ClassTreeInfo<TClass, TProp> }>;
         private _levelContent: StringDictionary<TProp>;
         private _fullContent: StringDictionary<TProp>;
         private _classContentFactory: (base: TClass) => TClass;

+ 7 - 0
src/Canvas2d/babylon.sprite2d.js

@@ -194,6 +194,13 @@ var BABYLON;
         Sprite2D.prototype.updateLevelBoundingInfo = function () {
             BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.spriteSize, this._levelBoundingInfo, this.origin);
         };
+        Sprite2D.prototype.getAnimatables = function () {
+            var res = new Array();
+            if (this.texture && this.texture.animations && this.texture.animations.length > 0) {
+                res.push(this.texture);
+            }
+            return res;
+        };
         Sprite2D.prototype.setupSprite2D = function (owner, parent, id, position, texture, spriteSize, spriteLocation, invertY) {
             this.setupRenderablePrim2D(owner, parent, id, position, true);
             this.texture = texture;

+ 2 - 6
src/Canvas2d/babylon.text2d.js

@@ -31,7 +31,7 @@ var BABYLON;
             this.effect.setTexture("diffuseSampler", this.fontTexture);
             engine.bindBuffers(this.vb, this.ib, [1], 4, this.effect);
             var cur = engine.getAlphaMode();
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+            engine.setAlphaMode(BABYLON.Engine.ALPHA_ADD);
             var count = instanceInfo._instancesPartsData[0].usedElementCount;
             if (instanceInfo._owner.owner.supportInstancedArray) {
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
@@ -238,7 +238,6 @@ var BABYLON;
             this.hAlign = hAlign;
             this._tabulationSize = tabulationSize;
             this._isTransparent = true;
-            this.origin = BABYLON.Vector2.Zero();
         };
         Text2D.Create = function (parent, id, x, y, fontName, text, defaultFontColor, areaSize, vAlign, hAlign, tabulationSize) {
             if (vAlign === void 0) { vAlign = Text2D.TEXT2D_VALIGN_TOP; }
@@ -272,9 +271,7 @@ var BABYLON;
             renderCache.ib = engine.createIndexBuffer(ib);
             // Effects
             var ei = this.getDataPartEffectInfo(Text2D.TEXT2D_MAINPARTID, ["index"]);
-            renderCache.effect = engine.createEffect("text2d", ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null, function (e) {
-                //                renderCache.setupUniformsLocation(e, ei.uniforms, Text2D.TEXT2D_MAINPARTID);
-            });
+            renderCache.effect = engine.createEffect("text2d", ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null);
             return renderCache;
         };
         Text2D.prototype.createInstanceDataParts = function () {
@@ -309,7 +306,6 @@ var BABYLON;
                 var charxpos = 0;
                 d.dataElementCount = this._charCount;
                 d.curElement = 0;
-                var customOrigin = BABYLON.Vector2.Zero();
                 for (var _i = 0, _a = this.text; _i < _a.length; _i++) {
                     var char = _a[_i];
                     // Line feed

+ 2 - 2
src/Materials/Textures/babylon.fontTexture.js

@@ -95,7 +95,7 @@ var BABYLON;
                 ++ft._usedCounter;
                 return ft;
             }
-            ft = new FontTexture(null, lfn, scene);
+            ft = new FontTexture(null, lfn, scene, 200, BABYLON.Texture.NEAREST_SAMPLINGMODE);
             dic.add(lfn, ft);
             return ft;
         };
@@ -144,7 +144,7 @@ var BABYLON;
             this._context.fillText(char, this._currentFreePosition.x - 0.5, this._currentFreePosition.y - this._offset - 0.5);
             // Fill the CharInfo object
             info.topLeftUV = new BABYLON.Vector2(this._currentFreePosition.x / textureSize.width, this._currentFreePosition.y / textureSize.height);
-            info.bottomRightUV = new BABYLON.Vector2(info.topLeftUV.x + (width / textureSize.width), info.topLeftUV.y + ((this._lineHeight + 1) / textureSize.height));
+            info.bottomRightUV = new BABYLON.Vector2(info.topLeftUV.x + (width / textureSize.width), info.topLeftUV.y + ((this._lineHeight + 2) / textureSize.height));
             info.charWidth = width;
             // Add the info structure
             this._charInfos[char] = info;

+ 13 - 0
src/Math/babylon.math.js

@@ -1287,6 +1287,19 @@ var BABYLON;
         Size.Zero = function () {
             return new Size(0, 0);
         };
+        Size.prototype.add = function (otherSize) {
+            var r = new Size(this.width + otherSize.width, this.height + otherSize.height);
+            return r;
+        };
+        Size.prototype.substract = function (otherSize) {
+            var r = new Size(this.width - otherSize.width, this.height - otherSize.height);
+            return r;
+        };
+        Size.Lerp = function (start, end, amount) {
+            var w = start.width + ((end.width - start.width) * amount);
+            var h = start.height + ((end.height - start.height) * amount);
+            return new Size(w, h);
+        };
         return Size;
     })();
     BABYLON.Size = Size;