Переглянути джерело

Animation support in Canvas2D Primitives

Math:
 - Adding methods to Size class: add, substract and Lerp()

Animation engine:
 - Now support the Size animation type.
 - The markAsDirty() method now takes a second parameter given the "previous" value (before the animation step occurs)

Primitive:
 - Now has an animations property and a getAnimatables() method which needs to be overriden by derived primitives when needed (see Sprite2D for an example)
nockawa 9 роки тому
батько
коміт
b8dd646321

+ 36 - 8
src/Animations/babylon.animation.ts

@@ -124,6 +124,8 @@
                 dataType = Animation.ANIMATIONTYPE_VECTOR2;
             } else if (from instanceof Color3) {
                 dataType = Animation.ANIMATIONTYPE_COLOR3;
+            } else if (from instanceof Size) {
+                dataType = Animation.ANIMATIONTYPE_SIZE;
             }
 
             if (dataType == undefined) {
@@ -293,6 +295,10 @@
             return Vector2.Lerp(startValue, endValue, gradient);
         }
 
+        public sizeInterpolateFunction(startValue: Size, endValue: Size, gradient: number): Size {
+            return Size.Lerp(startValue, endValue, gradient);
+        }
+
         public color3InterpolateFunction(startValue: Color3, endValue: Color3, gradient: number): Color3 {
             return Color3.Lerp(startValue, endValue, gradient);
         }
@@ -405,6 +411,15 @@
                                 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) {
@@ -453,15 +468,16 @@
                 destination = this._target;
             }
 
+            if (!this._originalBlendValue) {
+                if (destination[path].clone) {
+                    this._originalBlendValue = destination[path].clone();
+                } else {
+                    this._originalBlendValue = destination[path];
+                }
+            }
+
             // Blending
             if (this.enableBlending && this._blendingFactor <= 1.0) {
-                if (!this._originalBlendValue) {
-                    if (destination[path].clone) {
-                        this._originalBlendValue = destination[path].clone();
-                    } else {
-                        this._originalBlendValue = destination[path];
-                    }
-                }
 
                 if (this._originalBlendValue.prototype) { // Complex value
                     
@@ -482,7 +498,7 @@
             }
 
             if (this._target.markAsDirty) {
-                this._target.markAsDirty(this.targetProperty);
+                this._target.markAsDirty(this.targetProperty, this._originalBlendValue);
             }
         }
 
@@ -553,6 +569,9 @@
                             // 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);
@@ -586,6 +605,10 @@
                     case Animation.ANIMATIONTYPE_VECTOR2:
                         offsetValue = Vector2.Zero();
                         break;
+                    // Size
+                    case Animation.ANIMATIONTYPE_SIZE:
+                        offsetValue = Size.Zero();
+                        break;
                     // Color3
                     case Animation.ANIMATIONTYPE_COLOR3:
                         offsetValue = Color3.Black();
@@ -676,6 +699,7 @@
         private static _ANIMATIONTYPE_MATRIX = 3;
         private static _ANIMATIONTYPE_COLOR3 = 4;
         private static _ANIMATIONTYPE_VECTOR2 = 5;
+        private static _ANIMATIONTYPE_SIZE = 6;
         private static _ANIMATIONLOOPMODE_RELATIVE = 0;
         private static _ANIMATIONLOOPMODE_CYCLE = 1;
         private static _ANIMATIONLOOPMODE_CONSTANT = 2;
@@ -692,6 +716,10 @@
             return Animation._ANIMATIONTYPE_VECTOR2;
         }
 
+        public static get ANIMATIONTYPE_SIZE(): number {
+            return Animation._ANIMATIONTYPE_SIZE;
+        }
+
         public static get ANIMATIONTYPE_QUATERNION(): number {
             return Animation._ANIMATIONTYPE_QUATERNION;
         }

+ 47 - 22
src/Canvas2d/babylon.smartPropertyPrim.ts

@@ -142,6 +142,7 @@
             this._instanceDirtyFlags = 0;
             this._isDisposed = false;
             this._levelBoundingInfo = new BoundingInfo2D();
+            this.animations = new Array<Animation>();
         }
 
         public propertyChanged: Observable<PropertyChangedInfo>;
@@ -159,6 +160,15 @@
             return true;
         }
 
+        public animations;
+
+        /**
+         * Returns as a new array populated with the Animatable used by the primitive. Must be overridden.
+         */
+        public getAnimatables(): IAnimatable[] {
+            return new Array<IAnimatable>();
+        }
+
         public get modelKey(): string {
 
             // No need to compute it?
@@ -214,7 +224,7 @@
             propInfo.name = propName;
             propInfo.dirtyBoundingInfo = dirtyBoundingInfo;
             propInfo.typeLevelCompare = typeLevelCompare;
-            node.levelContent.add(propId.toString(), propInfo);
+            node.levelContent.add(propName, propInfo);
 
             return propInfo;
         }
@@ -243,7 +253,43 @@
 
         private static propChangedInfo = new PropertyChangedInfo();
 
+        public markAsDirty(propertyName: string, oldValue: any) {
+            let 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(oldValue, newValue, propertyName, propInfo, propInfo.typeLevelCompare);
+        }
+
         private _handlePropChanged<T>(curValue: T, newValue: T, propName: string, propInfo: Prim2DPropInfo, typeLevelCompare: boolean) {
+            // 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 Prim2DBase) {
+                    let curprim = (<any>this).parent;
+                    while (curprim) {
+                        curprim._boundingInfoDirty = true;
+
+                        if (curprim instanceof Group2D) {
+                            if (curprim.isRenderableGroup) {
+                                break;
+                            }
+                        }
+
+                        curprim = curprim.parent;
+                    }
+                }
+            }
+
             // Trigger property changed
             let info = SmartPropertyPrim.propChangedInfo;
             info.oldValue = curValue;
@@ -339,27 +385,6 @@
                     // 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 Prim2DBase) {
-                            let curprim = prim.parent;
-                            while (curprim) {
-                                curprim._boundingInfoDirty = true;
-
-                                if (curprim instanceof Group2D) {
-                                    if (curprim.isRenderableGroup) {
-                                        break;
-                                    }
-                                }
-
-                                curprim = curprim.parent;
-                            }
-                        }
-                    }
-
                     // Notify change, dirty flags update
                     prim._handlePropChanged(curVal, val, <string>propName, propInfo, typeLevelCompare);
                 }

+ 9 - 0
src/Canvas2d/babylon.sprite2d.ts

@@ -165,6 +165,15 @@
             BoundingInfo2D.CreateFromSizeToRef(this.spriteSize, this._levelBoundingInfo, this.origin);
         }
 
+        public getAnimatables(): IAnimatable[] {
+            let res = new Array<IAnimatable>();
+
+            if (this.texture && this.texture.animations && this.texture.animations.length > 0) {
+                res.push(this.texture);
+            }
+            return res;
+        }
+
         protected setupSprite2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, texture: Texture, spriteSize: Size, spriteLocation: Vector2, invertY: boolean) {
             this.setupRenderablePrim2D(owner, parent, id, position, true);
             this.texture = texture;

+ 18 - 0
src/Math/babylon.math.ts

@@ -1598,6 +1598,24 @@
         public static Zero(): Size {
             return new Size(0, 0);
         }
+
+        public add(otherSize: Size): Size {
+            let r = new Size(this.width + otherSize.width, this.height + otherSize.height);
+            return r;
+        }
+
+        public substract(otherSize: Size): Size {
+            let r = new Size(this.width - otherSize.width, this.height - otherSize.height);
+            return r;
+        }
+
+        public static Lerp(start: Size, end: Size, amount: number): Size {
+            var w = start.width + ((end.width - start.width) * amount);
+            var h = start.height + ((end.height - start.height) * amount);
+
+            return new Size(w, h);
+        }
+
     }