Ver código fonte

Merge pull request #1106 from julien-moreau/master

Added Action Manager Serialization
David Catuhe 9 anos atrás
pai
commit
cdaf1d0dfa

+ 60 - 1
src/Actions/babylon.action.js

@@ -66,7 +66,66 @@ var BABYLON;
         Action.prototype._getEffectiveTarget = function (target, propertyPath) {
             return this._actionManager._getEffectiveTarget(target, propertyPath);
         };
+        Action.prototype.serialize = function (parent) {
+        };
+        // Called by BABYLON.Action objects in serialize(...). Internal use
+        Action.prototype._serialize = function (serializedAction, parent) {
+            var serializationObject = {
+                type: 1,
+                children: [],
+                name: serializedAction.name,
+                properties: serializedAction.properties || []
+            };
+            // Serialize child
+            if (this._child) {
+                this._child.serialize(serializationObject);
+            }
+            // Check if "this" has a condition
+            if (this._condition) {
+                var serializedCondition = this._condition.serialize();
+                serializedCondition.children.push(serializationObject);
+                if (parent) {
+                    parent.children.push(serializedCondition);
+                }
+                return serializedCondition;
+            }
+            if (parent) {
+                parent.children.push(serializationObject);
+            }
+            return serializationObject;
+        };
+        Action._SerializeValueAsString = function (value) {
+            if (typeof value === "number") {
+                return String(value);
+            }
+            if (typeof value === "boolean") {
+                return value ? "true" : "false";
+            }
+            if (value instanceof BABYLON.Vector2) {
+                return String(value.x + ", " + value.y);
+            }
+            if (value instanceof BABYLON.Vector3) {
+                return String(value.x + ", " + value.y + ", " + value.z);
+            }
+            if (value instanceof BABYLON.Color3) {
+                return String(value.r + ", " + value.g + ", " + value.b);
+            }
+            if (value instanceof BABYLON.Color4) {
+                return String(value.r + ", " + value.g + ", " + value.b + ", " + value.a);
+            }
+            return value; // String
+        };
+        Action._GetTargetProperty = function (target) {
+            return {
+                name: "target",
+                targetType: target instanceof BABYLON.Mesh ? "MeshProperties"
+                    : target instanceof BABYLON.Light ? "LightProperties"
+                        : target instanceof BABYLON.Camera ? "CameraProperties"
+                            : "SceneProperties",
+                value: target instanceof BABYLON.Scene ? "Scene" : target.name
+            };
+        };
         return Action;
-    })();
+    }());
     BABYLON.Action = Action;
 })(BABYLON || (BABYLON = {}));

+ 71 - 0
src/Actions/babylon.action.ts

@@ -89,5 +89,76 @@
         public _getEffectiveTarget(target: any, propertyPath: string): any {
             return this._actionManager._getEffectiveTarget(target, propertyPath);
         }
+        
+        public serialize(parent: any): any {
+        }
+        
+        // Called by BABYLON.Action objects in serialize(...). Internal use
+        protected _serialize(serializedAction: any, parent?: any): any {
+            var serializationObject: any = { 
+                type: 1,
+                children: [],
+                name: serializedAction.name,
+                properties: serializedAction.properties || []
+            };
+            
+            // Serialize child
+            if (this._child) {
+                this._child.serialize(serializationObject);
+            }
+            
+            // Check if "this" has a condition
+            if (this._condition) {
+                var serializedCondition = this._condition.serialize();
+                serializedCondition.children.push(serializationObject);
+                
+                if (parent) {
+                    parent.children.push(serializedCondition);
+                }
+                return serializedCondition;
+            }
+            
+            if (parent) {
+                parent.children.push(serializationObject);
+            }
+            return serializationObject;
+        }
+        
+        public static _SerializeValueAsString = (value: any): string => {
+            if (typeof value === "number") {
+                return String(value);
+            }
+            
+            if (typeof value === "boolean") {
+                return value ? "true" : "false";
+            }
+            
+            if (value instanceof Vector2) {
+                return String(value.x + ", " + value.y);
+            }
+            if (value instanceof Vector3) {
+                return String(value.x + ", " + value.y + ", " + value.z);
+            }
+            
+            if (value instanceof Color3) {
+                return String(value.r + ", " + value.g + ", " + value.b);
+            }
+            if (value instanceof Color4) {
+                return String(value.r + ", " + value.g + ", " + value.b + ", " + value.a);
+            }
+            
+            return value; // String
+        };
+    
+        public static _GetTargetProperty = (target: Scene | Node) => {
+            return {
+                name: "target",
+                targetType: target instanceof Mesh ? "MeshProperties"
+                            : target instanceof Light ? "LightProperties"
+                            : target instanceof Camera ? "CameraProperties"
+                            : "SceneProperties",
+                value: target instanceof Scene ? "Scene" : target.name
+            }  
+        };
     }
 }

+ 53 - 2
src/Actions/babylon.actionManager.js

@@ -47,7 +47,7 @@ var BABYLON;
             return new ActionEvent(null, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt);
         };
         return ActionEvent;
-    })();
+    }());
     BABYLON.ActionEvent = ActionEvent;
     /**
      * Action Manager manages all events to be triggered on a given mesh or the global scene.
@@ -297,6 +297,36 @@ var BABYLON;
             var properties = propertyPath.split(".");
             return properties[properties.length - 1];
         };
+        ActionManager.prototype.serialize = function (name) {
+            var root = {
+                children: [],
+                name: name,
+                type: 3,
+                properties: [] // Empty for root but required
+            };
+            for (var i = 0; i < this.actions.length; i++) {
+                var triggerObject = {
+                    type: 0,
+                    children: [],
+                    name: ActionManager.GetTriggerName(this.actions[i].trigger),
+                    properties: []
+                };
+                var triggerOptions = this.actions[i].triggerOptions;
+                if (triggerOptions && typeof triggerOptions !== "number") {
+                    if (triggerOptions.parameter instanceof BABYLON.Node) {
+                        triggerObject.properties.push(BABYLON.Action._GetTargetProperty(triggerOptions.parameter));
+                    }
+                    else {
+                        triggerObject.properties.push({ name: "parameter", targetType: null, value: triggerOptions.parameter });
+                    }
+                }
+                // Serialize child action, recursively
+                this.actions[i].serialize(triggerObject);
+                // Add serialized trigger
+                root.children.push(triggerObject);
+            }
+            return root;
+        };
         ActionManager.Parse = function (parsedActions, object, scene) {
             var actionManager = new BABYLON.ActionManager(scene);
             if (object === null)
@@ -448,6 +478,27 @@ var BABYLON;
                 }
             }
         };
+        ActionManager.GetTriggerName = function (trigger) {
+            switch (trigger) {
+                case 0: return "NothingTrigger";
+                case 1: return "OnPickTrigger";
+                case 2: return "OnLeftPickTrigger";
+                case 3: return "OnRightPickTrigger";
+                case 4: return "OnCenterPickTrigger";
+                case 5: return "OnPickDownTrigger";
+                case 6: return "OnPickUpTrigger";
+                case 7: return "OnLongPressTrigger";
+                case 8: return "OnPointerOverTrigger";
+                case 9: return "OnPointerOutTrigger";
+                case 10: return "OnEveryFrameTrigger";
+                case 11: return "OnIntersectionEnterTrigger";
+                case 12: return "OnIntersectionExitTrigger";
+                case 13: return "OnKeyDownTrigger";
+                case 14: return "OnKeyUpTrigger";
+                case 15: return "OnPickOutTrigger";
+                default: return "";
+            }
+        };
         // Statics
         ActionManager._NothingTrigger = 0;
         ActionManager._OnPickTrigger = 1;
@@ -468,6 +519,6 @@ var BABYLON;
         ActionManager.DragMovementThreshold = 10; // in pixels
         ActionManager.LongPressDelay = 500; // in milliseconds
         return ActionManager;
-    })();
+    }());
     BABYLON.ActionManager = ActionManager;
 })(BABYLON || (BABYLON = {}));

+ 57 - 0
src/Actions/babylon.actionManager.ts

@@ -291,6 +291,42 @@
 
             return properties[properties.length - 1];
         }
+        
+        public serialize(name: string): any {
+            var root = {
+                children: [],
+                name: name,
+                type: 3, // Root node
+                properties: [] // Empty for root but required
+            };
+            
+            for (var i = 0; i < this.actions.length; i++) {
+                var triggerObject = { 
+                    type: 0, // Trigger
+                    children: [],
+                    name: ActionManager.GetTriggerName(this.actions[i].trigger),
+                    properties: []
+                };
+                
+                var triggerOptions = this.actions[i].triggerOptions;
+                if (triggerOptions && typeof triggerOptions !== "number") {
+                    if (triggerOptions.parameter instanceof Node) {
+                        triggerObject.properties.push(Action._GetTargetProperty(triggerOptions.parameter));
+                    }
+                    else {
+                        triggerObject.properties.push({ name: "parameter", targetType: null, value: triggerOptions.parameter });
+                    }
+                }
+                
+                // Serialize child action, recursively
+                this.actions[i].serialize(triggerObject);
+                
+                // Add serialized trigger
+                root.children.push(triggerObject);
+            }
+            
+            return root;
+        }
 
         public static Parse(parsedActions: any, object: AbstractMesh, scene: Scene) {
             var actionManager = new BABYLON.ActionManager(scene);
@@ -471,5 +507,26 @@
             }
         }
 
+        public static GetTriggerName(trigger: number): string {
+            switch (trigger) {
+                case 0:  return "NothingTrigger";
+                case 1:  return "OnPickTrigger";
+                case 2:  return "OnLeftPickTrigger";
+                case 3:  return "OnRightPickTrigger";
+                case 4:  return "OnCenterPickTrigger";
+                case 5:  return "OnPickDownTrigger";
+                case 6:  return "OnPickUpTrigger";
+                case 7:  return "OnLongPressTrigger";
+                case 8:  return "OnPointerOverTrigger";
+                case 9:  return "OnPointerOutTrigger";
+                case 10: return "OnEveryFrameTrigger";
+                case 11: return "OnIntersectionEnterTrigger";
+                case 12: return "OnIntersectionExitTrigger";
+                case 13: return "OnKeyDownTrigger";
+                case 14: return "OnKeyUpTrigger";
+                case 15: return "OnPickOutTrigger";
+                default: return "";
+            }
+        }
     }
 } 

+ 49 - 9
src/Actions/babylon.condition.js

@@ -18,8 +18,18 @@ var BABYLON;
         Condition.prototype._getEffectiveTarget = function (target, propertyPath) {
             return this._actionManager._getEffectiveTarget(target, propertyPath);
         };
+        Condition.prototype.serialize = function () {
+        };
+        Condition.prototype._serialize = function (serializedCondition) {
+            return {
+                type: 2,
+                children: [],
+                name: serializedCondition.name,
+                properties: serializedCondition.properties
+            };
+        };
         return Condition;
-    })();
+    }());
     BABYLON.Condition = Condition;
     var ValueCondition = (function (_super) {
         __extends(ValueCondition, _super);
@@ -29,7 +39,8 @@ var BABYLON;
             this.propertyPath = propertyPath;
             this.value = value;
             this.operator = operator;
-            this._target = this._getEffectiveTarget(target, this.propertyPath);
+            this._target = target;
+            this._effectiveTarget = this._getEffectiveTarget(target, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         }
         Object.defineProperty(ValueCondition, "IsEqual", {
@@ -64,29 +75,49 @@ var BABYLON;
         ValueCondition.prototype.isValid = function () {
             switch (this.operator) {
                 case ValueCondition.IsGreater:
-                    return this._target[this._property] > this.value;
+                    return this._effectiveTarget[this._property] > this.value;
                 case ValueCondition.IsLesser:
-                    return this._target[this._property] < this.value;
+                    return this._effectiveTarget[this._property] < this.value;
                 case ValueCondition.IsEqual:
                 case ValueCondition.IsDifferent:
                     var check;
                     if (this.value.equals) {
-                        check = this.value.equals(this._target[this._property]);
+                        check = this.value.equals(this._effectiveTarget[this._property]);
                     }
                     else {
-                        check = this.value === this._target[this._property];
+                        check = this.value === this._effectiveTarget[this._property];
                     }
                     return this.operator === ValueCondition.IsEqual ? check : !check;
             }
             return false;
         };
+        ValueCondition.prototype.serialize = function () {
+            return this._serialize({
+                name: "ValueCondition",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath },
+                    { name: "value", value: BABYLON.Action._SerializeValueAsString(this.value) },
+                    { name: "operator", value: ValueCondition.GetOperatorName(this.operator) }
+                ]
+            });
+        };
+        ValueCondition.GetOperatorName = function (operator) {
+            switch (operator) {
+                case ValueCondition._IsEqual: return "IsEqual";
+                case ValueCondition._IsDifferent: return "IsDifferent";
+                case ValueCondition._IsGreater: return "IsGreater";
+                case ValueCondition._IsLesser: return "IsLesser";
+                default: return "";
+            }
+        };
         // Statics
         ValueCondition._IsEqual = 0;
         ValueCondition._IsDifferent = 1;
         ValueCondition._IsGreater = 2;
         ValueCondition._IsLesser = 3;
         return ValueCondition;
-    })(Condition);
+    }(Condition));
     BABYLON.ValueCondition = ValueCondition;
     var PredicateCondition = (function (_super) {
         __extends(PredicateCondition, _super);
@@ -98,7 +129,7 @@ var BABYLON;
             return this.predicate();
         };
         return PredicateCondition;
-    })(Condition);
+    }(Condition));
     BABYLON.PredicateCondition = PredicateCondition;
     var StateCondition = (function (_super) {
         __extends(StateCondition, _super);
@@ -111,7 +142,16 @@ var BABYLON;
         StateCondition.prototype.isValid = function () {
             return this._target.state === this.value;
         };
+        StateCondition.prototype.serialize = function () {
+            return this._serialize({
+                name: "StateCondition",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    { name: "value", value: this.value }
+                ]
+            });
+        };
         return StateCondition;
-    })(Condition);
+    }(Condition));
     BABYLON.StateCondition = StateCondition;
 })(BABYLON || (BABYLON = {}));

+ 51 - 5
src/Actions/babylon.condition.ts

@@ -20,6 +20,18 @@
         public _getEffectiveTarget(target: any, propertyPath: string): any {
             return this._actionManager._getEffectiveTarget(target, propertyPath);
         }
+        
+        public serialize(): any {
+        }
+        
+        protected _serialize(serializedCondition: any): any {
+            return { 
+                type: 2, // Condition
+                children: [],
+                name: serializedCondition.name,
+                properties: serializedCondition.properties
+            };
+        }
     }
 
     export class ValueCondition extends Condition {
@@ -49,12 +61,14 @@
         public _actionManager: ActionManager;
 
         private _target: any;
+        private _effectiveTarget: any;
         private _property: string;
 
         constructor(actionManager: ActionManager, target: any, public propertyPath: string, public value: any, public operator: number = ValueCondition.IsEqual) {
             super(actionManager);
 
-            this._target = this._getEffectiveTarget(target, this.propertyPath);
+            this._target = target;
+            this._effectiveTarget = this._getEffectiveTarget(target, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         }
 
@@ -62,23 +76,45 @@
         public isValid(): boolean {
             switch (this.operator) {
                 case ValueCondition.IsGreater:
-                    return this._target[this._property] > this.value;
+                    return this._effectiveTarget[this._property] > this.value;
                 case ValueCondition.IsLesser:
-                    return this._target[this._property] < this.value;
+                    return this._effectiveTarget[this._property] < this.value;
                 case ValueCondition.IsEqual:
                 case ValueCondition.IsDifferent:
                     var check: boolean;
 
                     if (this.value.equals) {
-                        check = this.value.equals(this._target[this._property]);
+                        check = this.value.equals(this._effectiveTarget[this._property]);
                     } else {
-                        check = this.value === this._target[this._property];
+                        check = this.value === this._effectiveTarget[this._property];
                     }
                     return this.operator === ValueCondition.IsEqual ? check : !check;
             }
 
             return false;
         }
+        
+        public serialize(): any {
+            return this._serialize({
+               name: "ValueCondition",
+               properties: [
+                   Action._GetTargetProperty(this._target),
+                   { name: "propertyPath", value: this.propertyPath },
+                   { name: "value", value: Action._SerializeValueAsString(this.value) },
+                   { name: "operator", value: ValueCondition.GetOperatorName(this.operator) }
+                ]
+            });
+        }
+        
+        public static GetOperatorName(operator: number): string {
+            switch (operator) {
+                case ValueCondition._IsEqual: return "IsEqual";
+                case ValueCondition._IsDifferent: return "IsDifferent";
+                case ValueCondition._IsGreater: return "IsGreater";
+                case ValueCondition._IsLesser: return "IsLesser";
+                default: return "";
+            }
+        }
     }
 
     export class PredicateCondition extends Condition {
@@ -111,6 +147,16 @@
         public isValid(): boolean {
             return this._target.state === this.value;
         }
+        
+        public serialize(): any {
+            return this._serialize({
+               name: "StateCondition",
+               properties: [
+                   Action._GetTargetProperty(this._target),
+                   { name: "value", value: this.value }
+                ]
+            });
+        }
     }
 
 }

+ 115 - 22
src/Actions/babylon.directActions.js

@@ -10,17 +10,26 @@ var BABYLON;
         function SwitchBooleanAction(triggerOptions, target, propertyPath, condition) {
             _super.call(this, triggerOptions, condition);
             this.propertyPath = propertyPath;
-            this._target = target;
+            this._target = this._effectiveTarget = target;
         }
         SwitchBooleanAction.prototype._prepare = function () {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._effectiveTarget = this._getEffectiveTarget(this._effectiveTarget, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         };
         SwitchBooleanAction.prototype.execute = function () {
-            this._target[this._property] = !this._target[this._property];
+            this._effectiveTarget[this._property] = !this._effectiveTarget[this._property];
+        };
+        SwitchBooleanAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "SwitchBooleanAction",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath }
+                ]
+            }, parent);
         };
         return SwitchBooleanAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.SwitchBooleanAction = SwitchBooleanAction;
     var SetStateAction = (function (_super) {
         __extends(SetStateAction, _super);
@@ -32,8 +41,17 @@ var BABYLON;
         SetStateAction.prototype.execute = function () {
             this._target.state = this.value;
         };
+        SetStateAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "SetStateAction",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    { name: "value", value: this.value }
+                ]
+            }, parent);
+        };
         return SetStateAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.SetStateAction = SetStateAction;
     var SetValueAction = (function (_super) {
         __extends(SetValueAction, _super);
@@ -41,17 +59,27 @@ var BABYLON;
             _super.call(this, triggerOptions, condition);
             this.propertyPath = propertyPath;
             this.value = value;
-            this._target = target;
+            this._target = this._effectiveTarget = target;
         }
         SetValueAction.prototype._prepare = function () {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._effectiveTarget = this._getEffectiveTarget(this._effectiveTarget, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         };
         SetValueAction.prototype.execute = function () {
-            this._target[this._property] = this.value;
+            this._effectiveTarget[this._property] = this.value;
+        };
+        SetValueAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "SetValueAction",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath },
+                    { name: "value", value: BABYLON.Action._SerializeValueAsString(this.value) }
+                ]
+            }, parent);
         };
         return SetValueAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.SetValueAction = SetValueAction;
     var IncrementValueAction = (function (_super) {
         __extends(IncrementValueAction, _super);
@@ -59,20 +87,30 @@ var BABYLON;
             _super.call(this, triggerOptions, condition);
             this.propertyPath = propertyPath;
             this.value = value;
-            this._target = target;
+            this._target = this._effectiveTarget = target;
         }
         IncrementValueAction.prototype._prepare = function () {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._effectiveTarget = this._getEffectiveTarget(this._effectiveTarget, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
-            if (typeof this._target[this._property] !== "number") {
+            if (typeof this._effectiveTarget[this._property] !== "number") {
                 BABYLON.Tools.Warn("Warning: IncrementValueAction can only be used with number values");
             }
         };
         IncrementValueAction.prototype.execute = function () {
-            this._target[this._property] += this.value;
+            this._effectiveTarget[this._property] += this.value;
+        };
+        IncrementValueAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "IncrementValueAction",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath },
+                    { name: "value", value: BABYLON.Action._SerializeValueAsString(this.value) }
+                ]
+            }, parent);
         };
         return IncrementValueAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.IncrementValueAction = IncrementValueAction;
     var PlayAnimationAction = (function (_super) {
         __extends(PlayAnimationAction, _super);
@@ -89,8 +127,19 @@ var BABYLON;
             var scene = this._actionManager.getScene();
             scene.beginAnimation(this._target, this.from, this.to, this.loop);
         };
+        PlayAnimationAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "PlayAnimationAction",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    { name: "from", value: String(this.from) },
+                    { name: "to", value: String(this.to) },
+                    { name: "loop", value: BABYLON.Action._SerializeValueAsString(this.loop) || false }
+                ]
+            }, parent);
+        };
         return PlayAnimationAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.PlayAnimationAction = PlayAnimationAction;
     var StopAnimationAction = (function (_super) {
         __extends(StopAnimationAction, _super);
@@ -104,8 +153,14 @@ var BABYLON;
             var scene = this._actionManager.getScene();
             scene.stopAnimation(this._target);
         };
+        StopAnimationAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "StopAnimationAction",
+                properties: [BABYLON.Action._GetTargetProperty(this._target)]
+            }, parent);
+        };
         return StopAnimationAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.StopAnimationAction = StopAnimationAction;
     var DoNothingAction = (function (_super) {
         __extends(DoNothingAction, _super);
@@ -115,8 +170,14 @@ var BABYLON;
         }
         DoNothingAction.prototype.execute = function () {
         };
+        DoNothingAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "DoNothingAction",
+                properties: []
+            }, parent);
+        };
         return DoNothingAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.DoNothingAction = DoNothingAction;
     var CombineAction = (function (_super) {
         __extends(CombineAction, _super);
@@ -135,8 +196,19 @@ var BABYLON;
                 this.children[index].execute(evt);
             }
         };
+        CombineAction.prototype.serialize = function (parent) {
+            var serializationObject = _super.prototype._serialize.call(this, {
+                name: "CombineAction",
+                properties: [],
+                combine: []
+            }, parent);
+            for (var i = 0; i < this.children.length; i++) {
+                serializationObject.combine.push(this.children[i].serialize(null));
+            }
+            return serializationObject;
+        };
         return CombineAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.CombineAction = CombineAction;
     var ExecuteCodeAction = (function (_super) {
         __extends(ExecuteCodeAction, _super);
@@ -148,7 +220,7 @@ var BABYLON;
             this.func(evt);
         };
         return ExecuteCodeAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.ExecuteCodeAction = ExecuteCodeAction;
     var SetParentAction = (function (_super) {
         __extends(SetParentAction, _super);
@@ -168,8 +240,17 @@ var BABYLON;
             this._target.position = BABYLON.Vector3.TransformCoordinates(this._target.position, invertParentWorldMatrix);
             this._target.parent = this._parent;
         };
+        SetParentAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "SetParentAction",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    BABYLON.Action._GetTargetProperty(this._parent),
+                ]
+            }, parent);
+        };
         return SetParentAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.SetParentAction = SetParentAction;
     var PlaySoundAction = (function (_super) {
         __extends(PlaySoundAction, _super);
@@ -183,8 +264,14 @@ var BABYLON;
             if (this._sound !== undefined)
                 this._sound.play();
         };
+        PlaySoundAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "PlaySoundAction",
+                properties: [{ name: "sound", value: this._sound.name }]
+            }, parent);
+        };
         return PlaySoundAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.PlaySoundAction = PlaySoundAction;
     var StopSoundAction = (function (_super) {
         __extends(StopSoundAction, _super);
@@ -198,7 +285,13 @@ var BABYLON;
             if (this._sound !== undefined)
                 this._sound.stop();
         };
+        StopSoundAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "StopSoundAction",
+                properties: [{ name: "sound", value: this._sound.name }]
+            }, parent);
+        };
         return StopSoundAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.StopSoundAction = StopSoundAction;
 })(BABYLON || (BABYLON = {}));

+ 119 - 10
src/Actions/babylon.directActions.ts

@@ -1,20 +1,31 @@
 module BABYLON {
     export class SwitchBooleanAction extends Action {
         private _target: any;
+        private _effectiveTarget: any;
         private _property: string;
 
         constructor(triggerOptions: any, target: any, public propertyPath: string, condition?: Condition) {
             super(triggerOptions, condition);
-            this._target = target;
+            this._target = this._effectiveTarget = target;
         }
 
         public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._effectiveTarget = this._getEffectiveTarget(this._effectiveTarget, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         }
 
         public execute(): void {
-            this._target[this._property] = !this._target[this._property];
+            this._effectiveTarget[this._property] = !this._effectiveTarget[this._property];
+        }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "SwitchBooleanAction",
+                properties: [
+                    Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath }
+                ]
+            }, parent);
         }
     }
 
@@ -29,47 +40,81 @@
         public execute(): void {
             this._target.state = this.value;
         }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "SetStateAction",
+                properties: [
+                    Action._GetTargetProperty(this._target),
+                    { name: "value", value: this.value }
+                ]
+            }, parent);
+        }
     }
 
     export class SetValueAction extends Action {
         private _target: any;
+        private _effectiveTarget: any;
         private _property: string;
 
         constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
             super(triggerOptions, condition);
-            this._target = target;
+            this._target = this._effectiveTarget = target;
         }
 
         public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._effectiveTarget = this._getEffectiveTarget(this._effectiveTarget, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         }
 
         public execute(): void {
-            this._target[this._property] = this.value;
+            this._effectiveTarget[this._property] = this.value;
+        }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "SetValueAction",
+                properties: [
+                    Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath },
+                    { name: "value", value: Action._SerializeValueAsString(this.value) }
+                ]
+            }, parent);
         }
     }
 
     export class IncrementValueAction extends Action {
         private _target: any;
+        private _effectiveTarget: any;
         private _property: string;
 
         constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
             super(triggerOptions, condition);
-            this._target = target;
+            this._target = this._effectiveTarget = target;
         }
 
         public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._effectiveTarget = this._getEffectiveTarget(this._effectiveTarget, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
 
-            if (typeof this._target[this._property] !== "number") {
+            if (typeof this._effectiveTarget[this._property] !== "number") {
                 Tools.Warn("Warning: IncrementValueAction can only be used with number values");
             }
         }
 
         public execute(): void {
-            this._target[this._property] += this.value;
+            this._effectiveTarget[this._property] += this.value;
+        }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "IncrementValueAction",
+                properties: [
+                    Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath },
+                    { name: "value", value: Action._SerializeValueAsString(this.value) }
+                ]
+            }, parent);
         }
     }
 
@@ -88,6 +133,18 @@
             var scene = this._actionManager.getScene();
             scene.beginAnimation(this._target, this.from, this.to, this.loop);
         }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "PlayAnimationAction",
+                properties: [
+                    Action._GetTargetProperty(this._target),
+                    { name: "from", value: String(this.from) },
+                    { name: "to", value: String(this.to) },
+                    { name: "loop", value: Action._SerializeValueAsString(this.loop) || false }
+                ]
+            }, parent);
+        }
     }
 
     export class StopAnimationAction extends Action {
@@ -105,6 +162,13 @@
             var scene = this._actionManager.getScene();
             scene.stopAnimation(this._target);
         }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "StopAnimationAction",
+                properties: [Action._GetTargetProperty(this._target)]
+            }, parent);
+        }
     }
 
     export class DoNothingAction extends Action {
@@ -114,6 +178,13 @@
 
         public execute(): void {
         }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "DoNothingAction",
+                properties: []
+            }, parent);
+        }
     }
 
     export class CombineAction extends Action {
@@ -133,6 +204,20 @@
                 this.children[index].execute(evt);
             }
         }
+        
+        public serialize(parent: any): any {
+            var serializationObject = super._serialize({
+                name: "CombineAction",
+                properties: [],
+                combine: []
+            }, parent);
+            
+            for (var i=0; i < this.children.length; i++) {
+                serializationObject.combine.push(this.children[i].serialize(null));
+            }
+            
+            return serializationObject;
+        }
     }
 
     export class ExecuteCodeAction extends Action {
@@ -170,6 +255,16 @@
 
             this._target.parent = this._parent;
         }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "SetParentAction",
+                properties: [
+                    Action._GetTargetProperty(this._target),
+                    Action._GetTargetProperty(this._parent),
+                ]
+            }, parent);
+        }
     }
 
     export class PlaySoundAction extends Action {
@@ -187,6 +282,13 @@
             if (this._sound !== undefined)
                 this._sound.play();
         }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "PlaySoundAction",
+                properties: [{ name: "sound", value: this._sound.name }]
+            }, parent);
+        }
     }
 
     export class StopSoundAction extends Action {
@@ -204,5 +306,12 @@
             if (this._sound !== undefined)
                 this._sound.stop();
         }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "StopSoundAction",
+                properties: [{ name: "sound", value: this._sound.name }]
+            }, parent);
+        }
     }
 } 

+ 18 - 6
src/Actions/babylon.interpolateValueAction.js

@@ -15,10 +15,10 @@ var BABYLON;
             this.duration = duration;
             this.stopOtherAnimations = stopOtherAnimations;
             this.onInterpolationDone = onInterpolationDone;
-            this._target = target;
+            this._target = this._effectiveTarget = target;
         }
         InterpolateValueAction.prototype._prepare = function () {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._effectiveTarget = this._getEffectiveTarget(this._effectiveTarget, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         };
         InterpolateValueAction.prototype.execute = function () {
@@ -26,7 +26,7 @@ var BABYLON;
             var keys = [
                 {
                     frame: 0,
-                    value: this._target[this._property]
+                    value: this._effectiveTarget[this._property]
                 }, {
                     frame: 100,
                     value: this.value
@@ -55,11 +55,23 @@ var BABYLON;
             var animation = new BABYLON.Animation("InterpolateValueAction", this._property, 100 * (1000.0 / this.duration), dataType, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
             animation.setKeys(keys);
             if (this.stopOtherAnimations) {
-                scene.stopAnimation(this._target);
+                scene.stopAnimation(this._effectiveTarget);
             }
-            scene.beginDirectAnimation(this._target, [animation], 0, 100, false, 1, this.onInterpolationDone);
+            scene.beginDirectAnimation(this._effectiveTarget, [animation], 0, 100, false, 1, this.onInterpolationDone);
+        };
+        InterpolateValueAction.prototype.serialize = function (parent) {
+            return _super.prototype._serialize.call(this, {
+                name: "InterpolateValueAction",
+                properties: [
+                    BABYLON.Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath },
+                    { name: "value", value: BABYLON.Action._SerializeValueAsString(this.value) },
+                    { name: "duration", value: BABYLON.Action._SerializeValueAsString(this.duration) },
+                    { name: "stopOtherAnimations", value: BABYLON.Action._SerializeValueAsString(this.stopOtherAnimations) || false }
+                ]
+            }, parent);
         };
         return InterpolateValueAction;
-    })(BABYLON.Action);
+    }(BABYLON.Action));
     BABYLON.InterpolateValueAction = InterpolateValueAction;
 })(BABYLON || (BABYLON = {}));

+ 19 - 5
src/Actions/babylon.interpolateValueAction.ts

@@ -1,16 +1,17 @@
 module BABYLON {
     export class InterpolateValueAction extends Action {
         private _target: any;
+        private _effectiveTarget: any;
         private _property: string;
 
         constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, public duration: number = 1000, condition?: Condition, public stopOtherAnimations?: boolean, public onInterpolationDone?: () => void) {
             super(triggerOptions, condition);
 
-            this._target = target;
+            this._target = this._effectiveTarget = target;
         }
 
         public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._effectiveTarget = this._getEffectiveTarget(this._effectiveTarget, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         }
 
@@ -19,7 +20,7 @@
             var keys = [
                 {
                     frame: 0,
-                    value: this._target[this._property]
+                    value: this._effectiveTarget[this._property]
                 }, {
                     frame: 100,
                     value: this.value
@@ -48,10 +49,23 @@
             animation.setKeys(keys);
 
             if (this.stopOtherAnimations) {
-                scene.stopAnimation(this._target);
+                scene.stopAnimation(this._effectiveTarget);
             }
 
-            scene.beginDirectAnimation(this._target, [animation], 0, 100, false, 1, this.onInterpolationDone);
+            scene.beginDirectAnimation(this._effectiveTarget, [animation], 0, 100, false, 1, this.onInterpolationDone);
+        }
+        
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "InterpolateValueAction",
+                properties: [
+                    Action._GetTargetProperty(this._target),
+                    { name: "propertyPath", value: this.propertyPath },
+                    { name: "value", value: Action._SerializeValueAsString(this.value) },
+                    { name: "duration", value: Action._SerializeValueAsString(this.duration) },
+                    { name: "stopOtherAnimations", value: Action._SerializeValueAsString(this.stopOtherAnimations) || false }
+                ]
+            }, parent);
         }
     }
 } 

+ 10 - 0
src/Tools/babylon.sceneSerializer.ts

@@ -147,6 +147,11 @@
 
         // Layer mask
         serializationObject.layerMask = mesh.layerMask;
+        
+        // Action Manager
+        if (mesh.actionManager) {
+            serializationObject.actions = mesh.actionManager.serialize(mesh.name);
+        }
 
         return serializationObject;
     };
@@ -333,6 +338,11 @@
                     serializationObject.shadowGenerators.push(light.getShadowGenerator().serialize());
                 }
             }
+            
+            // Action Manager
+            if (scene.actionManager) {
+                serializationObject.actions = scene.actionManager.serialize("scene");
+            }
 
             return serializationObject;
         }