瀏覽代碼

update from upstream

nockawa 9 年之前
父節點
當前提交
ee0c2d31ab
共有 35 個文件被更改,包括 2984 次插入1700 次删除
  1. 20 20
      dist/preview release/babylon.core.js
  2. 667 550
      dist/preview release/babylon.d.ts
  3. 31 31
      dist/preview release/babylon.js
  4. 427 51
      dist/preview release/babylon.max.js
  5. 28 28
      dist/preview release/babylon.noworker.js
  6. 5 3
      dist/preview release/what's new.md
  7. 59 0
      src/Actions/babylon.action.js
  8. 71 0
      src/Actions/babylon.action.ts
  9. 51 0
      src/Actions/babylon.actionManager.js
  10. 57 0
      src/Actions/babylon.actionManager.ts
  11. 45 5
      src/Actions/babylon.condition.js
  12. 51 5
      src/Actions/babylon.condition.ts
  13. 103 10
      src/Actions/babylon.directActions.js
  14. 119 10
      src/Actions/babylon.directActions.ts
  15. 17 5
      src/Actions/babylon.interpolateValueAction.js
  16. 19 5
      src/Actions/babylon.interpolateValueAction.ts
  17. 4 2
      src/Lights/Shadows/babylon.shadowGenerator.js
  18. 4 3
      src/Lights/Shadows/babylon.shadowGenerator.ts
  19. 1 1
      src/Loading/Plugins/babylon.babylonFileLoader.js
  20. 1 1
      src/Loading/Plugins/babylon.babylonFileLoader.ts
  21. 4 0
      src/Mesh/babylon.linesMesh.js
  22. 6 1
      src/Mesh/babylon.linesMesh.ts
  23. 94 17
      src/Mesh/babylon.mesh.js
  24. 99 28
      src/Mesh/babylon.mesh.ts
  25. 28 5
      src/PostProcess/babylon.postProcess.js
  26. 32 5
      src/PostProcess/babylon.postProcess.ts
  27. 3 1
      src/Shaders/postprocess.vertex.fx
  28. 8 0
      src/Tools/babylon.sceneSerializer.js
  29. 13 4
      src/Tools/babylon.sceneSerializer.ts
  30. 895 901
      src/Tools/babylon.tools.js
  31. 1 1
      src/Tools/babylon.tools.ts
  32. 2 2
      src/babylon.engine.js
  33. 2 2
      src/babylon.engine.ts
  34. 8 1
      src/babylon.scene.js
  35. 9 2
      src/babylon.scene.ts

File diff suppressed because it is too large
+ 20 - 20
dist/preview release/babylon.core.js


File diff suppressed because it is too large
+ 667 - 550
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 31 - 31
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 427 - 51
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 28 - 28
dist/preview release/babylon.noworker.js


+ 5 - 3
dist/preview release/what's new.md

@@ -4,7 +4,7 @@
     - Added support for HDR cubemaps ([sebavan](https://github.com/sebavan))
     - Support for shaders includes ([deltakosh](https://github.com/deltakosh))
     - new mesh type : `LineSystem` ([jerome](https://github.com/jbousquie))
-    - SerializationHelper for complex classes using TypeScript decorators  ([deltakosh](https://github.com/deltakosh))
+    - SerializationHelper for complex classes using TypeScript decorators ([deltakosh](https://github.com/deltakosh))
     - StandardMaterial now supports Parallax and Parallax Occlusion Mapping ([nockawa](https://github.com/nockawa))
     - Animations blending. See [demo here](http://www.babylonjs-playground.com/#2BLI9T#3). More [info here](NEED DOC!) ([deltakosh](https://github.com/deltakosh))
     - New debuger tool: SkeletonViewer. See [demo here](Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8) (Adam & [deltakosh](https://github.com/deltakosh))
@@ -15,6 +15,7 @@
     - Unity3D exporter: Added support for export and run (local webserver) ([davrous](https://github.com/davrous), [deltakosh](https://github.com/deltakosh))
     - Moved PBR Material to core ([deltakosh](https://github.com/deltakosh))
   - **Updates**
+    - Added postprocess.enablePixelPerfectMode to avoid texture scaling/stretching when dealing with non-power of 2 resolutions. cannot be used on post-processes chain ([deltakosh](https://github.com/deltakosh))
     - Added skeleton.getBoneIndexByName(boneName: string) [dad72](https://github.com/dad72)
     - Added node._children to track children hierarchy ([deltakosh](https://github.com/deltakosh))
     - Added Camera.ForceAttachControlToAlwaysPreventDefault to help embedding Babylon.js in iFrames ([deltakosh](https://github.com/deltakosh))
@@ -33,8 +34,9 @@
 	- Scene.onPointerObservable property added to enable a unique Observable event for user input (see ArcRotateCamera inputs for examples) ([nockawa](https://github.com/nockawa))
 
   - **API doc**
-    - class `SolidParticleSystem` documented
-    - class `MeshBuilder` documented
+    - class `SolidParticleSystem` documented ([jerome](https://github.com/jbousquie))
+    - class `MeshBuilder` documented ([jerome](https://github.com/jbousquie))
+    - class `Mesh` documented ([jerome](https://github.com/jbousquie))
   - **Bug fixes**
     - Fixed bug with billboards and parenting ([deltakosh](https://github.com/deltakosh))
     - Fixed bug with ArcRotateCamera.setTarget ([deltakosh](https://github.com/deltakosh))

+ 59 - 0
src/Actions/babylon.action.js

@@ -66,6 +66,65 @@ 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 value.toString();
+            }
+            if (typeof value === "boolean") {
+                return value ? "true" : "false";
+            }
+            if (value instanceof BABYLON.Vector2) {
+                return value.x + ", " + value.y;
+            }
+            if (value instanceof BABYLON.Vector3) {
+                return value.x + ", " + value.y + ", " + value.z;
+            }
+            if (value instanceof BABYLON.Color3) {
+                return value.r + ", " + value.g + ", " + value.b;
+            }
+            if (value instanceof BABYLON.Color4) {
+                return 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;

+ 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 value.toString();
+            }
+            
+            if (typeof value === "boolean") {
+                return value ? "true" : "false";
+            }
+            
+            if (value instanceof Vector2) {
+                return value.x + ", " + value.y;
+            }
+            if (value instanceof Vector3) {
+                return value.x + ", " + value.y + ", " + value.z;
+            }
+            
+            if (value instanceof Color3) {
+                return value.r + ", " + value.g + ", " + value.b;
+            }
+            if (value instanceof Color4) {
+                return 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" : (<Node>target).name
+            }  
+        };
     }
 }

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

@@ -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;

+ 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 "";
+            }
+        }
     }
 } 

+ 45 - 5
src/Actions/babylon.condition.js

@@ -18,6 +18,16 @@ 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;
@@ -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,22 +75,42 @@ 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;
@@ -111,6 +142,15 @@ 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);
     BABYLON.StateCondition = StateCondition;

+ 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 }
+                ]
+            });
+        }
     }
 
 }

+ 103 - 10
src/Actions/babylon.directActions.js

@@ -10,14 +10,23 @@ 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);
@@ -32,6 +41,15 @@ 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.SetStateAction = SetStateAction;
@@ -41,14 +59,24 @@ 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);
@@ -59,17 +87,27 @@ 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);
@@ -89,6 +127,17 @@ 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.PlayAnimationAction = PlayAnimationAction;
@@ -104,6 +153,12 @@ 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.StopAnimationAction = StopAnimationAction;
@@ -115,6 +170,12 @@ 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.DoNothingAction = DoNothingAction;
@@ -135,6 +196,17 @@ 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.CombineAction = CombineAction;
@@ -168,6 +240,15 @@ 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.SetParentAction = SetParentAction;
@@ -183,6 +264,12 @@ 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.PlaySoundAction = PlaySoundAction;
@@ -198,6 +285,12 @@ 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.StopSoundAction = StopSoundAction;

+ 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);
+        }
     }
 } 

+ 17 - 5
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,9 +55,21 @@ 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);

+ 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);
         }
     }
 } 

+ 4 - 2
src/Lights/Shadows/babylon.shadowGenerator.js

@@ -371,8 +371,10 @@ var BABYLON;
             var light = scene.getLightByID(parsedShadowGenerator.lightId);
             var shadowGenerator = new ShadowGenerator(parsedShadowGenerator.mapSize, light);
             for (var meshIndex = 0; meshIndex < parsedShadowGenerator.renderList.length; meshIndex++) {
-                var mesh = scene.getMeshByID(parsedShadowGenerator.renderList[meshIndex]);
-                shadowGenerator.getShadowMap().renderList.push(mesh);
+                var meshes = scene.getMeshesByID(parsedShadowGenerator.renderList[meshIndex]);
+                meshes.forEach(function (mesh) {
+                    shadowGenerator.getShadowMap().renderList.push(mesh);
+                });
             }
             if (parsedShadowGenerator.usePoissonSampling) {
                 shadowGenerator.usePoissonSampling = true;

+ 4 - 3
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -436,9 +436,10 @@
             var shadowGenerator = new ShadowGenerator(parsedShadowGenerator.mapSize, light);
 
             for (var meshIndex = 0; meshIndex < parsedShadowGenerator.renderList.length; meshIndex++) {
-                var mesh = scene.getMeshByID(parsedShadowGenerator.renderList[meshIndex]);
-
-                shadowGenerator.getShadowMap().renderList.push(mesh);
+                var meshes = scene.getMeshesByID(parsedShadowGenerator.renderList[meshIndex]);
+                meshes.forEach(function (mesh) {
+                    shadowGenerator.getShadowMap().renderList.push(mesh);
+                });
             }
 
             if (parsedShadowGenerator.usePoissonSampling) {

+ 1 - 1
src/Loading/Plugins/babylon.babylonFileLoader.js

@@ -208,7 +208,7 @@ var BABYLON;
                     // Scene
                     scene.useDelayedTextureLoading = parsedData.useDelayedTextureLoading && !BABYLON.SceneLoader.ForceFullSceneLoadingForIncremental;
                     scene.autoClear = parsedData.autoClear;
-                    scene.clearColor = BABYLON.Color3.FromArray(parsedData.clearColor);
+                    scene.clearColor = BABYLON.Color4.FromArray(parsedData.clearColor);
                     scene.ambientColor = BABYLON.Color3.FromArray(parsedData.ambientColor);
                     if (parsedData.gravity) {
                         scene.gravity = BABYLON.Vector3.FromArray(parsedData.gravity);

+ 1 - 1
src/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -218,7 +218,7 @@
                 // Scene
                 scene.useDelayedTextureLoading = parsedData.useDelayedTextureLoading && !BABYLON.SceneLoader.ForceFullSceneLoadingForIncremental;
                 scene.autoClear = parsedData.autoClear;
-                scene.clearColor = BABYLON.Color3.FromArray(parsedData.clearColor);
+                scene.clearColor = BABYLON.Color4.FromArray(parsedData.clearColor);
                 scene.ambientColor = BABYLON.Color3.FromArray(parsedData.ambientColor);
                 if (parsedData.gravity) {
                     scene.gravity = BABYLON.Vector3.FromArray(parsedData.gravity);

+ 4 - 0
src/Mesh/babylon.linesMesh.js

@@ -12,6 +12,10 @@ var BABYLON;
             _super.call(this, name, scene, parent, source, doNotCloneChildren);
             this.color = new BABYLON.Color3(1, 1, 1);
             this.alpha = 1;
+            if (source) {
+                this.color = source.color.clone();
+                this.alpha = source.alpha;
+            }
             this._intersectionThreshold = 0.1;
             this._colorShader = new BABYLON.ShaderMaterial("colorShader", scene, "color", {
                 attributes: ["position"],

+ 6 - 1
src/Mesh/babylon.linesMesh.ts

@@ -32,9 +32,14 @@
         private _intersectionThreshold: number;
         private _colorShader: ShaderMaterial;
 
-        constructor(name: string, scene: Scene, parent: Node = null, source?: Mesh, doNotCloneChildren?: boolean) {
+        constructor(name: string, scene: Scene, parent: Node = null, source?: LinesMesh, doNotCloneChildren?: boolean) {
             super(name, scene, parent, source, doNotCloneChildren);
 
+            if (source) {
+                this.color = source.color.clone();
+                this.alpha = source.alpha;
+            }
+
             this._intersectionThreshold = 0.1;
             this._colorShader = new ShaderMaterial("colorShader", scene, "color",
                 {

+ 94 - 17
src/Mesh/babylon.mesh.js

@@ -333,7 +333,7 @@ var BABYLON;
         };
         /**
          * Returns an array of integers or floats, or a Float32Array, depending on the requested `kind` (positions, indices, normals, etc).
-         * If `copywhenShared` is true (default false) and if the mesh has submeshes, the submesh data are duplicated in the returned array.
+         * If `copywhenShared` is true (default false) and if the mesh geometry is shared among some other meshes, the returned array is a copy of the internal one.
          * Returns null if the mesh has no geometry or no vertex buffer.
          * Possible `kind` values :
          * - BABYLON.VertexBuffer.PositionKind
@@ -443,7 +443,7 @@ var BABYLON;
         };
         /**
          * Returns an array of integers or a Int32Array populated with the mesh indices.
-         * If the parameter `copyWhenShared` is true (default false) and if the mesh has submeshes, the submesh indices are duplicated in the returned array.
+         * If the parameter `copyWhenShared` is true (default false) and and if the mesh geometry is shared among some other meshes, the returned array is a copy of the internal one.
          * Returns an empty array if the mesh has no geometry.
          */
         Mesh.prototype.getIndices = function (copyWhenShared) {
@@ -542,7 +542,7 @@ var BABYLON;
         };
         /**
          * This method recomputes and sets a new `BoundingInfo` to the mesh unless it is locked.
-         * This means the mesh underlying bounding box and shpere are recomputed.
+         * This means the mesh underlying bounding box and sphere are recomputed.
          */
         Mesh.prototype.refreshBoundingInfo = function () {
             if (this._boundingInfo.isLocked) {
@@ -593,10 +593,10 @@ var BABYLON;
          * Sets the vertex data of the mesh geometry for the requested `kind`.
          * If the mesh has no geometry, a new `Geometry` object is set to the mesh and then passed this vertex data.
          * The `data` are either a numeric array either a Float32Array.
+         * The parameter `updatable` is passed as is to the underlying `Geometry` object constructor (if initianilly none) or updater.
          * The parameter `stride` is an optional positive integer, it is usually automatically deducted from the `kind` (3 for positions or normals, 2 for UV, etc).
          * Note that a new underlying `VertexBuffer` object is created each call.
          * If the `kind` is the `PositionKind`, the mesh `BoundingInfo` is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.
-         * The same for the mesh submeshes if any.
          *
          * Possible `kind` values :
          * - BABYLON.VertexBuffer.PositionKind
@@ -629,7 +629,6 @@ var BABYLON;
          * The `data` are either a numeric array either a Float32Array.
          * No new underlying `VertexBuffer` object is created.
          * If the `kind` is the `PositionKind` and if `updateExtends` is true, the mesh `BoundingInfo` is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.
-         * The same for the mesh submeshes if any.
          * If the parameter `makeItUnique` is true, a new global geometry is created from this positions and is set to the mesh.
          *
          * Possible `kind` values :
@@ -769,7 +768,7 @@ var BABYLON;
             }
         };
         /**
-         * Registers a javascript function for this mesh that will be called just before the rendering process.
+         * Registers for this mesh a javascript function called just before the rendering process.
          * This function is passed the current mesh and doesn't return anything.
          */
         Mesh.prototype.registerBeforeRender = function (func) {
@@ -783,7 +782,7 @@ var BABYLON;
             this.onBeforeRenderObservable.removeCallback(func);
         };
         /**
-         * Registers a javascript function for this mesh that will be called just after the rendering is complete.
+         * Registers for this mesh a javascript function called just after the rendering is complete.
          * This function is passed the current mesh and doesn't return anything.
          */
         Mesh.prototype.registerAfterRender = function (func) {
@@ -893,7 +892,7 @@ var BABYLON;
         };
         /**
          * Triggers the draw call for the mesh.
-         * You don't need to call this method by your own usually because the mesh rendering is handled by the scene rendering manager.
+         * Usually, you don't need to call this method by your own because the mesh rendering is handled by the scene rendering manager.
          */
         Mesh.prototype.render = function (subMesh, enableAlphaMode) {
             var scene = this.getScene();
@@ -1021,6 +1020,11 @@ var BABYLON;
             this._checkDelayState();
             return true;
         };
+        /**
+         * Sets the mesh material by the material or multiMaterial `id` property.
+         * The material `id` is a string identifying the material or the multiMaterial.
+         * This method returns nothing.
+         */
         Mesh.prototype.setMaterialByID = function (id) {
             var materials = this.getScene().materials;
             var index;
@@ -1039,6 +1043,9 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Returns as a new array populated with the mesh material and/or skeleton, if any.
+         */
         Mesh.prototype.getAnimatables = function () {
             var results = [];
             if (this.material) {
@@ -1049,7 +1056,13 @@ var BABYLON;
             }
             return results;
         };
-        // Geometry
+        /**
+         * Modifies the mesh geometry according to the passed transformation matrix.
+         * This method returns nothing but it really modifies the mesh even if it's originally not set as updatable.
+         * The mesh normals are modified accordingly the same transformation.
+         * tuto : http://doc.babylonjs.com/tutorials/How_Rotations_and_Translations_Work#baking-transform
+         * Note that, under the hood, this method sets a new VertexBuffer each call.
+         */
         Mesh.prototype.bakeTransformIntoVertices = function (transform) {
             // Position
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
@@ -1078,7 +1091,13 @@ var BABYLON;
                 this.flipFaces();
             }
         };
-        // Will apply current transform to mesh and reset world matrix
+        /**
+         * Modifies the mesh geometry according to its own current World Matrix.
+         * The mesh World Matrix is then reset.
+         * This method returns nothing but really modifies the mesh even if it's originally not set as updatable.
+         * tuto : tuto : http://doc.babylonjs.com/tutorials/How_Rotations_and_Translations_Work#baking-transform
+         * Note that, under the hood, this method sets a new VertexBuffer each call.
+         */
         Mesh.prototype.bakeCurrentTransformIntoVertices = function () {
             this.bakeTransformIntoVertices(this.computeWorldMatrix(true));
             this.scaling.copyFromFloats(1, 1, 1);
@@ -1107,12 +1126,22 @@ var BABYLON;
             }
             return true;
         };
-        // Clone
+        /**
+         * Returns a new `Mesh` object generated from the current mesh properties.
+         * This method must not get confused with createInstance().
+         * The parameter `name` is a string, the name given to the new mesh.
+         * The optional parameter `newParent` can be any `Node` object (default `null`).
+         * The optional parameter `doNotCloneChildren` (default `false`) allows/denies the recursive cloning of the original mesh children if any.
+         * The parameter `clonePhysicsImpostor` (default `true`)  allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any.
+         */
         Mesh.prototype.clone = function (name, newParent, doNotCloneChildren, clonePhysicsImpostor) {
             if (clonePhysicsImpostor === void 0) { clonePhysicsImpostor = true; }
             return new Mesh(name, this.getScene(), newParent, this, doNotCloneChildren, clonePhysicsImpostor);
         };
-        // Dispose
+        /**
+         * Disposes the mesh.
+         * This also frees the memory allocated under the hood to all the buffers used by WebGL.
+         */
         Mesh.prototype.dispose = function (doNotRecurse) {
             if (this._geometry) {
                 this._geometry.releaseForMesh(this, true);
@@ -1127,7 +1156,15 @@ var BABYLON;
             }
             _super.prototype.dispose.call(this, doNotRecurse);
         };
-        // Geometric tools
+        /**
+         * Modifies the mesh geometry according to a displacement map.
+         * A displacement map is a colored image. Each pixel color value (actually a gradient computed from red, green, blue values) will give the displacement to apply to each mesh vertex.
+         * The mesh must be set as updatable. Its internal geometry is directly modified, no new buffer are allocated.
+         * This method returns nothing.
+         * The parameter `url` is a string, the URL from the image file is to be downloaded.
+         * The parameters `minHeight` and `maxHeight` are the lower and upper limits of the displacement.
+         * The parameter `onSuccess` is an optional Javascript function to be called just after the mesh is modified. It is passed the modified mesh and must return nothing.
+         */
         Mesh.prototype.applyDisplacementMap = function (url, minHeight, maxHeight, onSuccess) {
             var _this = this;
             var scene = this.getScene();
@@ -1151,6 +1188,15 @@ var BABYLON;
             };
             BABYLON.Tools.LoadImage(url, onload, function () { }, scene.database);
         };
+        /**
+         * Modifies the mesh geometry according to a displacementMap buffer.
+         * A displacement map is a colored image. Each pixel color value (actually a gradient computed from red, green, blue values) will give the displacement to apply to each mesh vertex.
+         * The mesh must be set as updatable. Its internal geometry is directly modified, no new buffer are allocated.
+         * This method returns nothing.
+         * The parameter `buffer` is a `Uint8Array` buffer containing series of `Uint8` lower than 255, the red, green, blue and alpha values of each successive pixel.
+         * The parameters `heightMapWidth` and `heightMapHeight` are positive integers to set the width and height of the buffer image.
+         * The parameters `minHeight` and `maxHeight` are the lower and upper limits of the displacement.
+         */
         Mesh.prototype.applyDisplacementMapFromBuffer = function (buffer, heightMapWidth, heightMapHeight, minHeight, maxHeight) {
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)
                 || !this.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)
@@ -1188,7 +1234,8 @@ var BABYLON;
         /**
          * Modify the mesh to get a flat shading rendering.
          * This means each mesh facet will then have its own normals. Usually new vertices are added in the mesh geometry to get this result.
-         * Warning : the mesh is really modified.
+         * This method returns nothing.
+         * Warning : the mesh is really modified even if not set originally as updatable and, under the hood, a new VertexBuffer is allocated.
          */
         Mesh.prototype.convertToFlatShadedMesh = function () {
             /// <summary>Update normals and vertices to get a flat shading rendering.</summary>
@@ -1267,6 +1314,9 @@ var BABYLON;
         /**
          * This method removes all the mesh indices and add new vertices (duplication) in order to unfold facets into buffers.
          * In other words, more vertices, no more indices and a single bigger VBO.
+         * This method returns nothing.
+         * The mesh is really modified even if not set originally as updatable. Under the hood, a new VertexBuffer is allocated.
+         *
          */
         Mesh.prototype.convertToUnIndexedMesh = function () {
             /// <summary>Remove indices by unfolding faces into buffers</summary>
@@ -1323,8 +1373,9 @@ var BABYLON;
             this.synchronizeInstances();
         };
         /**
-         * Inverses facet orientations and inverts also the normals with `flipNormals` (default false) if true.
-         * Warning : the mesh is really modified.
+         * Inverses facet orientations and inverts also the normals with `flipNormals` (default `false`) if true.
+         * This method returns nothing.
+         * Warning : the mesh is really modified even if not set originally as updatable. A new VertexBuffer is created under the hood each call.
          */
         Mesh.prototype.flipFaces = function (flipNormals) {
             if (flipNormals === void 0) { flipNormals = false; }
@@ -1347,10 +1398,24 @@ var BABYLON;
         // Instances
         /**
          * Creates a new `InstancedMesh` object from the mesh model.
+         * An instance shares the same properties and the same material than its model.
+         * Only these properties of each instance can then be set individually :
+         * - position
+         * - rotation
+         * - rotationQuaternion
+         * - setPivotMatrix
+         * - scaling
+         * tuto : http://doc.babylonjs.com/tutorials/How_to_use_Instances
+         * Warning : this method is not supported for `Line` mesh and `LineSystem`
          */
         Mesh.prototype.createInstance = function (name) {
             return new BABYLON.InstancedMesh(name, this);
         };
+        /**
+         * Synchronises all the mesh instance submeshes to the current mesh submeshes, if any.
+         * After this call, all the mesh instances have the same submeshes than the current mesh.
+         * This method returns nothing.
+         */
         Mesh.prototype.synchronizeInstances = function () {
             for (var instanceIndex = 0; instanceIndex < this.instances.length; instanceIndex++) {
                 var instance = this.instances[instanceIndex];
@@ -1359,7 +1424,7 @@ var BABYLON;
         };
         /**
          * Simplify the mesh according to the given array of settings.
-         * Function will return immediately and will simplify async.
+         * Function will return immediately and will simplify async. It returns nothing.
          * @param settings a collection of simplification settings.
          * @param parallelProcessing should all levels calculate parallel or one after the other.
          * @param type the type of simplification to run.
@@ -1415,6 +1480,11 @@ var BABYLON;
             });
         };
         // Statics
+        /**
+         * Returns a new `Mesh` object what is a deep copy of the passed mesh.
+         * The parameter `parsedMesh` is the mesh to be copied.
+         * The parameter `rootUrl` is a string, it's the root URL to prefix the `delayLoadingFile` property with
+         */
         Mesh.Parse = function (parsedMesh, scene, rootUrl) {
             var mesh = new Mesh(parsedMesh.name, scene);
             mesh.id = parsedMesh.id;
@@ -2157,6 +2227,10 @@ var BABYLON;
             return this;
         };
         // Tools
+        /**
+         * Returns an object `{min: Vector3, max: Vector3}`
+         * This min and max `Vector3` are the minimum and maximum vectors of each mesh bounding box from the passed array, in the World system
+         */
         Mesh.MinMax = function (meshes) {
             var minVector = null;
             var maxVector = null;
@@ -2176,6 +2250,9 @@ var BABYLON;
                 max: maxVector
             };
         };
+        /**
+         * Returns a `Vector3`, the center of the `{min: Vector3, max: Vector3}` or the center of MinMax vector3 computed from a mesh array.
+         */
         Mesh.Center = function (meshesOrMinMaxVector) {
             var minMaxVector = meshesOrMinMaxVector.min !== undefined ? meshesOrMinMaxVector : Mesh.MinMax(meshesOrMinMaxVector);
             return BABYLON.Vector3.Center(minMaxVector.min, minMaxVector.max);

+ 99 - 28
src/Mesh/babylon.mesh.ts

@@ -167,7 +167,7 @@
                     if (impostor) {
                         this.physicsImpostor = impostor.clone(this);
                     }
-                }  
+                }
 
                 // Particles
                 for (index = 0; index < scene.particleSystems.length; index++) {
@@ -344,7 +344,7 @@
 
         /**
          * Returns an array of integers or floats, or a Float32Array, depending on the requested `kind` (positions, indices, normals, etc).  
-         * If `copywhenShared` is true (default false) and if the mesh has submeshes, the submesh data are duplicated in the returned array.
+         * If `copywhenShared` is true (default false) and if the mesh geometry is shared among some other meshes, the returned array is a copy of the internal one.
          * Returns null if the mesh has no geometry or no vertex buffer.    
          * Possible `kind` values :
          * - BABYLON.VertexBuffer.PositionKind
@@ -458,7 +458,7 @@
 
         /**
          * Returns an array of integers or a Int32Array populated with the mesh indices.  
-         * If the parameter `copyWhenShared` is true (default false) and if the mesh has submeshes, the submesh indices are duplicated in the returned array.
+         * If the parameter `copyWhenShared` is true (default false) and and if the mesh geometry is shared among some other meshes, the returned array is a copy of the internal one.
          * Returns an empty array if the mesh has no geometry.
          */
         public getIndices(copyWhenShared?: boolean): number[] | Int32Array {
@@ -562,7 +562,7 @@
 
         /**
          * This method recomputes and sets a new `BoundingInfo` to the mesh unless it is locked.
-         * This means the mesh underlying bounding box and shpere are recomputed. 
+         * This means the mesh underlying bounding box and sphere are recomputed. 
          */
         public refreshBoundingInfo(): void {
             if (this._boundingInfo.isLocked) {
@@ -626,10 +626,10 @@
          * Sets the vertex data of the mesh geometry for the requested `kind`.
          * If the mesh has no geometry, a new `Geometry` object is set to the mesh and then passed this vertex data.  
          * The `data` are either a numeric array either a Float32Array. 
+         * The parameter `updatable` is passed as is to the underlying `Geometry` object constructor (if initianilly none) or updater. 
          * The parameter `stride` is an optional positive integer, it is usually automatically deducted from the `kind` (3 for positions or normals, 2 for UV, etc).  
          * Note that a new underlying `VertexBuffer` object is created each call. 
          * If the `kind` is the `PositionKind`, the mesh `BoundingInfo` is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed. 
-         * The same for the mesh submeshes if any. 
          *
          * Possible `kind` values :
          * - BABYLON.VertexBuffer.PositionKind
@@ -665,7 +665,6 @@
          * The `data` are either a numeric array either a Float32Array. 
          * No new underlying `VertexBuffer` object is created. 
          * If the `kind` is the `PositionKind` and if `updateExtends` is true, the mesh `BoundingInfo` is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.  
-         * The same for the mesh submeshes if any.
          * If the parameter `makeItUnique` is true, a new global geometry is created from this positions and is set to the mesh.
          *
          * Possible `kind` values :
@@ -819,7 +818,7 @@
         }
 
         /**
-         * Registers a javascript function for this mesh that will be called just before the rendering process.
+         * Registers for this mesh a javascript function called just before the rendering process.
          * This function is passed the current mesh and doesn't return anything.  
          */
         public registerBeforeRender(func: (mesh: AbstractMesh) => void): void {
@@ -835,7 +834,7 @@
         }
 
         /**
-         * Registers a javascript function for this mesh that will be called just after the rendering is complete.
+         * Registers for this mesh a javascript function called just after the rendering is complete.
          * This function is passed the current mesh and doesn't return anything.  
          */
         public registerAfterRender(func: (mesh: AbstractMesh) => void): void {
@@ -973,7 +972,7 @@
 
         /**
          * Triggers the draw call for the mesh.
-         * You don't need to call this method by your own usually because the mesh rendering is handled by the scene rendering manager.  
+         * Usually, you don't need to call this method by your own because the mesh rendering is handled by the scene rendering manager.  
          */
         public render(subMesh: SubMesh, enableAlphaMode: boolean): void {
             var scene = this.getScene();
@@ -1136,6 +1135,11 @@
             return true;
         }
 
+        /**
+         * Sets the mesh material by the material or multiMaterial `id` property.  
+         * The material `id` is a string identifying the material or the multiMaterial.  
+         * This method returns nothing. 
+         */
         public setMaterialByID(id: string): void {
             var materials = this.getScene().materials;
             var index: number;
@@ -1156,6 +1160,9 @@
             }
         }
 
+        /**
+         * Returns as a new array populated with the mesh material and/or skeleton, if any.
+         */
         public getAnimatables(): IAnimatable[] {
             var results = [];
 
@@ -1170,7 +1177,13 @@
             return results;
         }
 
-        // Geometry
+        /**
+         * Modifies the mesh geometry according to the passed transformation matrix.  
+         * This method returns nothing but it really modifies the mesh even if it's originally not set as updatable. 
+         * The mesh normals are modified accordingly the same transformation.  
+         * tuto : http://doc.babylonjs.com/tutorials/How_Rotations_and_Translations_Work#baking-transform  
+         * Note that, under the hood, this method sets a new VertexBuffer each call.  
+         */
         public bakeTransformIntoVertices(transform: Matrix): void {
             // Position
             if (!this.isVerticesDataPresent(VertexBuffer.PositionKind)) {
@@ -1203,7 +1216,13 @@
             if (transform.m[0] * transform.m[5] * transform.m[10] < 0) { this.flipFaces(); }
         }
 
-        // Will apply current transform to mesh and reset world matrix
+        /**
+         * Modifies the mesh geometry according to its own current World Matrix.  
+         * The mesh World Matrix is then reset.
+         * This method returns nothing but really modifies the mesh even if it's originally not set as updatable.
+         * tuto : tuto : http://doc.babylonjs.com/tutorials/How_Rotations_and_Translations_Work#baking-transform 
+         * Note that, under the hood, this method sets a new VertexBuffer each call.
+         */
         public bakeCurrentTransformIntoVertices(): void {
             this.bakeTransformIntoVertices(this.computeWorldMatrix(true));
             this.scaling.copyFromFloats(1, 1, 1);
@@ -1240,12 +1259,22 @@
             return true;
         }
 
-        // Clone
+        /**
+         * Returns a new `Mesh` object generated from the current mesh properties.
+         * This method must not get confused with createInstance().  
+         * The parameter `name` is a string, the name given to the new mesh. 
+         * The optional parameter `newParent` can be any `Node` object (default `null`).  
+         * The optional parameter `doNotCloneChildren` (default `false`) allows/denies the recursive cloning of the original mesh children if any.
+         * The parameter `clonePhysicsImpostor` (default `true`)  allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any. 
+         */
         public clone(name: string, newParent?: Node, doNotCloneChildren?: boolean, clonePhysicsImpostor: boolean = true): Mesh {
             return new Mesh(name, this.getScene(), newParent, this, doNotCloneChildren, clonePhysicsImpostor);
         }
 
-        // Dispose
+        /**
+         * Disposes the mesh.
+         * This also frees the memory allocated under the hood to all the buffers used by WebGL.
+         */
         public dispose(doNotRecurse?: boolean): void {
             if (this._geometry) {
                 this._geometry.releaseForMesh(this, true);
@@ -1264,7 +1293,15 @@
             super.dispose(doNotRecurse);
         }
 
-        // Geometric tools
+        /**
+         * Modifies the mesh geometry according to a displacement map.
+         * A displacement map is a colored image. Each pixel color value (actually a gradient computed from red, green, blue values) will give the displacement to apply to each mesh vertex.  
+         * The mesh must be set as updatable. Its internal geometry is directly modified, no new buffer are allocated.
+         * This method returns nothing.   
+         * The parameter `url` is a string, the URL from the image file is to be downloaded.  
+         * The parameters `minHeight` and `maxHeight` are the lower and upper limits of the displacement.
+         * The parameter `onSuccess` is an optional Javascript function to be called just after the mesh is modified. It is passed the modified mesh and must return nothing.
+         */
         public applyDisplacementMap(url: string, minHeight: number, maxHeight: number, onSuccess?: (mesh: Mesh) => void): void {
             var scene = this.getScene();
 
@@ -1293,6 +1330,15 @@
             Tools.LoadImage(url, onload, () => { }, scene.database);
         }
 
+        /**
+         * Modifies the mesh geometry according to a displacementMap buffer.
+         * A displacement map is a colored image. Each pixel color value (actually a gradient computed from red, green, blue values) will give the displacement to apply to each mesh vertex.  
+         * The mesh must be set as updatable. Its internal geometry is directly modified, no new buffer are allocated.
+         * This method returns nothing.   
+         * The parameter `buffer` is a `Uint8Array` buffer containing series of `Uint8` lower than 255, the red, green, blue and alpha values of each successive pixel.
+         * The parameters `heightMapWidth` and `heightMapHeight` are positive integers to set the width and height of the buffer image.     
+         * The parameters `minHeight` and `maxHeight` are the lower and upper limits of the displacement.
+         */
         public applyDisplacementMapFromBuffer(buffer: Uint8Array, heightMapWidth: number, heightMapHeight: number, minHeight: number, maxHeight: number): void {
             if (!this.isVerticesDataPresent(VertexBuffer.PositionKind)
                 || !this.isVerticesDataPresent(VertexBuffer.NormalKind)
@@ -1340,7 +1386,8 @@
         /**
          * Modify the mesh to get a flat shading rendering.
          * This means each mesh facet will then have its own normals. Usually new vertices are added in the mesh geometry to get this result.
-         * Warning : the mesh is really modified.
+         * This method returns nothing.
+         * Warning : the mesh is really modified even if not set originally as updatable and, under the hood, a new VertexBuffer is allocated.
          */
         public convertToFlatShadedMesh(): void {
             /// <summary>Update normals and vertices to get a flat shading rendering.</summary>
@@ -1437,6 +1484,9 @@
         /**
          * This method removes all the mesh indices and add new vertices (duplication) in order to unfold facets into buffers.
          * In other words, more vertices, no more indices and a single bigger VBO.
+         * This method returns nothing.
+         * The mesh is really modified even if not set originally as updatable. Under the hood, a new VertexBuffer is allocated.
+         * 
          */
         public convertToUnIndexedMesh(): void {
             /// <summary>Remove indices by unfolding faces into buffers</summary>
@@ -1506,8 +1556,9 @@
         }
 
         /**
-         * Inverses facet orientations and inverts also the normals with `flipNormals` (default false) if true.
-         * Warning : the mesh is really modified.
+         * Inverses facet orientations and inverts also the normals with `flipNormals` (default `false`) if true.
+         * This method returns nothing.
+         * Warning : the mesh is really modified even if not set originally as updatable. A new VertexBuffer is created under the hood each call.
          */
         public flipFaces(flipNormals: boolean = false): void {
             var vertex_data = VertexData.ExtractFromMesh(this);
@@ -1532,11 +1583,25 @@
         // Instances
         /**
          * Creates a new `InstancedMesh` object from the mesh model.
+         * An instance shares the same properties and the same material than its model.
+         * Only these properties of each instance can then be set individually :
+         * - position
+         * - rotation
+         * - rotationQuaternion
+         * - setPivotMatrix
+         * - scaling
+         * tuto : http://doc.babylonjs.com/tutorials/How_to_use_Instances
+         * Warning : this method is not supported for `Line` mesh and `LineSystem`
          */
         public createInstance(name: string): InstancedMesh {
             return new InstancedMesh(name, this);
         }
 
+        /**
+         * Synchronises all the mesh instance submeshes to the current mesh submeshes, if any.
+         * After this call, all the mesh instances have the same submeshes than the current mesh.
+         * This method returns nothing.   
+         */
         public synchronizeInstances(): void {
             for (var instanceIndex = 0; instanceIndex < this.instances.length; instanceIndex++) {
                 var instance = this.instances[instanceIndex];
@@ -1546,7 +1611,7 @@
 
         /**
          * Simplify the mesh according to the given array of settings.
-         * Function will return immediately and will simplify async.
+         * Function will return immediately and will simplify async. It returns nothing.  
          * @param settings a collection of simplification settings.
          * @param parallelProcessing should all levels calculate parallel or one after the other.
          * @param type the type of simplification to run.
@@ -1603,7 +1668,11 @@
         }
 
         // Statics
-
+        /**
+         * Returns a new `Mesh` object what is a deep copy of the passed mesh. 
+         * The parameter `parsedMesh` is the mesh to be copied.
+         * The parameter `rootUrl` is a string, it's the root URL to prefix the `delayLoadingFile` property with
+         */
         public static Parse(parsedMesh: any, scene: Scene, rootUrl: string): Mesh {
             var mesh = new Mesh(parsedMesh.name, scene);
             mesh.id = parsedMesh.id;
@@ -1765,8 +1834,8 @@
             } else {
                 mesh.layerMask = 0x0FFFFFFF;
             }
-            
-             
+
+
             //(Deprecated) physics
             if (parsedMesh.physicsImpostor) {
                 mesh.physicsImpostor = new BABYLON.PhysicsImpostor(mesh, parsedMesh.physicsImpostor, {
@@ -1809,7 +1878,7 @@
 
             return mesh;
         }
-        
+
         /**
          * Creates a ribbon mesh.   
          * Please consider using the same method from the `MeshBuilder` class instead.   
@@ -2436,6 +2505,10 @@
         }
 
         // Tools
+        /**
+         * Returns an object `{min: Vector3, max: Vector3}`
+         * This min and max `Vector3` are the minimum and maximum vectors of each mesh bounding box from the passed array, in the World system
+         */
         public static MinMax(meshes: AbstractMesh[]): { min: Vector3; max: Vector3 } {
             var minVector: Vector3 = null;
             var maxVector: Vector3 = null;
@@ -2456,7 +2529,9 @@
                 max: maxVector
             };
         }
-
+        /**
+         * Returns a `Vector3`, the center of the `{min: Vector3, max: Vector3}` or the center of MinMax vector3 computed from a mesh array.
+         */
         public static Center(meshesOrMinMaxVector): Vector3 {
             var minMaxVector = meshesOrMinMaxVector.min !== undefined ? meshesOrMinMaxVector : Mesh.MinMax(meshesOrMinMaxVector);
             return Vector3.Center(minMaxVector.min, minMaxVector.max);
@@ -2528,8 +2603,4 @@
             return meshSubclass;
         }
     }
-}
-
-
-
-
+}

+ 28 - 5
src/PostProcess/babylon.postProcess.js

@@ -7,9 +7,15 @@ var BABYLON;
             this.name = name;
             this.width = -1;
             this.height = -1;
+            /*
+                Enable Pixel Perfect mode where texture is not scaled to be power of 2.
+                Can only be used on a single postprocess or on the last one of a chain.
+            */
+            this.enablePixelPerfectMode = false;
             this._reusable = false;
             this._textures = new BABYLON.SmartArray(2);
             this._currentRenderTextureInd = 0;
+            this._scaleRatio = new BABYLON.Vector2(1, 1);
             if (camera != null) {
                 this._camera = camera;
                 this._scene = camera.getScene();
@@ -27,6 +33,7 @@ var BABYLON;
             this._samplers.push("textureSampler");
             this._fragmentUrl = fragmentUrl;
             this._parameters = parameters || [];
+            this._parameters.push("scale");
             this.updateEffect(defines);
         }
         PostProcess.prototype.updateEffect = function (defines) {
@@ -39,10 +46,18 @@ var BABYLON;
             camera = camera || this._camera;
             var scene = camera.getScene();
             var maxSize = camera.getEngine().getCaps().maxTextureSize;
-            var desiredWidth = ((sourceTexture ? sourceTexture._width : this._engine.getRenderingCanvas().width) * this._renderRatio) | 0;
-            var desiredHeight = ((sourceTexture ? sourceTexture._height : this._engine.getRenderingCanvas().height) * this._renderRatio) | 0;
-            desiredWidth = this._renderRatio.width || BABYLON.Tools.GetExponentOfTwo(desiredWidth, maxSize);
-            desiredHeight = this._renderRatio.height || BABYLON.Tools.GetExponentOfTwo(desiredHeight, maxSize);
+            var requiredWidth = ((sourceTexture ? sourceTexture._width : this._engine.getRenderingCanvas().width) * this._renderRatio) | 0;
+            var requiredHeight = ((sourceTexture ? sourceTexture._height : this._engine.getRenderingCanvas().height) * this._renderRatio) | 0;
+            var desiredWidth = this._renderRatio.width || requiredWidth;
+            var desiredHeight = this._renderRatio.height || requiredHeight;
+            if (this.renderTargetSamplingMode !== BABYLON.Texture.NEAREST_SAMPLINGMODE) {
+                if (!this._renderRatio.width) {
+                    desiredWidth = BABYLON.Tools.GetExponentOfTwo(desiredWidth, maxSize);
+                }
+                if (!this._renderRatio.height) {
+                    desiredHeight = BABYLON.Tools.GetExponentOfTwo(desiredHeight, maxSize);
+                }
+            }
             if (this.width !== desiredWidth || this.height !== desiredHeight) {
                 if (this._textures.length > 0) {
                     for (var i = 0; i < this._textures.length; i++) {
@@ -60,7 +75,14 @@ var BABYLON;
                     this.onSizeChanged();
                 }
             }
-            this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
+            if (this.enablePixelPerfectMode) {
+                this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
+                this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd], 0, requiredWidth, requiredHeight);
+            }
+            else {
+                this._scaleRatio.copyFromFloats(1, 1);
+                this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
+            }
             if (this.onActivate) {
                 this.onActivate(camera);
             }
@@ -95,6 +117,7 @@ var BABYLON;
             // Texture
             this._effect._bindTexture("textureSampler", this._textures.data[this._currentRenderTextureInd]);
             // Parameters
+            this._effect.setVector2("scale", this._scaleRatio);
             if (this.onApply) {
                 this.onApply(this._effect);
             }

+ 32 - 5
src/PostProcess/babylon.postProcess.ts

@@ -10,6 +10,12 @@
         public renderTargetSamplingMode: number;
         public clearColor: Color4;
 
+        /*
+            Enable Pixel Perfect mode where texture is not scaled to be power of 2.
+            Can only be used on a single postprocess or on the last one of a chain.
+        */ 
+        public enablePixelPerfectMode = false;
+
         private _camera: Camera;
         private _scene: Scene;
         private _engine: Engine;
@@ -22,6 +28,7 @@
         private _samplers: string[];
         private _fragmentUrl: string;
         private _parameters: string[];
+        private _scaleRatio = new Vector2(1, 1);
 
         constructor(public name: string, fragmentUrl: string, parameters: string[], samplers: string[], ratio: number|any, camera: Camera, samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines?: string, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
             if (camera != null) {
@@ -45,6 +52,8 @@
             this._fragmentUrl = fragmentUrl;
             this._parameters = parameters || [];
 
+            this._parameters.push("scale");
+
             this.updateEffect(defines);
         }
 
@@ -65,11 +74,21 @@
             var scene = camera.getScene();
             var maxSize = camera.getEngine().getCaps().maxTextureSize;
 
-            var desiredWidth = ((sourceTexture ? sourceTexture._width : this._engine.getRenderingCanvas().width) * this._renderRatio) | 0;
-            var desiredHeight = ((sourceTexture ? sourceTexture._height : this._engine.getRenderingCanvas().height) * this._renderRatio) | 0;
+            var requiredWidth = ((sourceTexture ? sourceTexture._width : this._engine.getRenderingCanvas().width) * this._renderRatio) | 0;
+            var requiredHeight = ((sourceTexture ? sourceTexture._height : this._engine.getRenderingCanvas().height) * this._renderRatio) | 0;
+
+            var desiredWidth = this._renderRatio.width || requiredWidth;
+            var desiredHeight = this._renderRatio.height || requiredHeight;
+
+            if (this.renderTargetSamplingMode !== Texture.NEAREST_SAMPLINGMODE) {
+                if (!this._renderRatio.width) {
+                    desiredWidth = Tools.GetExponentOfTwo(desiredWidth, maxSize);
+                }
 
-            desiredWidth = this._renderRatio.width || Tools.GetExponentOfTwo(desiredWidth, maxSize);
-            desiredHeight = this._renderRatio.height || Tools.GetExponentOfTwo(desiredHeight, maxSize);
+                if (!this._renderRatio.height) {
+                    desiredHeight = Tools.GetExponentOfTwo(desiredHeight, maxSize);
+                }
+            }
 
             if (this.width !== desiredWidth || this.height !== desiredHeight) {
                 if (this._textures.length > 0) {
@@ -91,7 +110,14 @@
                 }
             }
 
-            this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
+            if (this.enablePixelPerfectMode) {
+                this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
+                this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd], 0, requiredWidth, requiredHeight);
+            }
+            else {
+                this._scaleRatio.copyFromFloats(1, 1);
+                this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
+            }
 
             if (this.onActivate) {
                 this.onActivate(camera);
@@ -129,6 +155,7 @@
             this._effect._bindTexture("textureSampler", this._textures.data[this._currentRenderTextureInd]);
 
             // Parameters
+            this._effect.setVector2("scale", this._scaleRatio);
             if (this.onApply) {
                 this.onApply(this._effect);
             }

+ 3 - 1
src/Shaders/postprocess.vertex.fx

@@ -1,6 +1,8 @@
 // Attributes
 attribute vec2 position;
 
+
+uniform vec2 scale;
 // Output
 varying vec2 vUV;
 
@@ -8,6 +10,6 @@ const vec2 madd = vec2(0.5, 0.5);
 
 void main(void) {	
 
-	vUV = position * madd + madd;
+	vUV = (position * madd + madd) * scale;
 	gl_Position = vec4(position, 0.0, 1.0);
 }

+ 8 - 0
src/Tools/babylon.sceneSerializer.js

@@ -128,6 +128,10 @@ var BABYLON;
         serializationObject.ranges = mesh.serializeAnimationRanges();
         // Layer mask
         serializationObject.layerMask = mesh.layerMask;
+        // Action Manager
+        if (mesh.actionManager) {
+            serializationObject.actions = mesh.actionManager.serialize(mesh.name);
+        }
         return serializationObject;
     };
     var finalizeSingleMesh = function (mesh, serializationObject) {
@@ -289,6 +293,10 @@ var BABYLON;
                     serializationObject.shadowGenerators.push(light.getShadowGenerator().serialize());
                 }
             }
+            // Action Manager
+            if (scene.actionManager) {
+                serializationObject.actions = scene.actionManager.serialize("scene");
+            }
             return serializationObject;
         };
         SceneSerializer.SerializeMesh = function (toSerialize /* Mesh || Mesh[] */, withParents, withChildren) {

+ 13 - 4
src/Tools/babylon.sceneSerializer.ts

@@ -148,6 +148,11 @@
         // Layer mask
         serializationObject.layerMask = mesh.layerMask;
 
+        // Action Manager
+        if (mesh.actionManager) {
+            serializationObject.actions = mesh.actionManager.serialize(mesh.name);
+        }
+
         return serializationObject;
     };
 
@@ -215,7 +220,7 @@
             serializationObject.gravity = scene.gravity.asArray();
             serializationObject.collisionsEnabled = scene.collisionsEnabled;
             serializationObject.workerCollisions = scene.workerCollisions;
-            
+
             // Fog
             if (scene.fogMode && scene.fogMode !== 0) {
                 serializationObject.fogMode = scene.fogMode;
@@ -224,7 +229,7 @@
                 serializationObject.fogEnd = scene.fogEnd;
                 serializationObject.fogDensity = scene.fogDensity;
             }
-            
+
             //Physics
             if (scene.isPhysicsEnabled()) {
                 serializationObject.physicsEnabled = true;
@@ -270,7 +275,7 @@
                 var multiMaterial = scene.multiMaterials[index];
                 serializationObject.multiMaterials.push(multiMaterial.serialize());
             }
-            
+
             // Skeletons
             serializationObject.skeletons = [];
             for (index = 0; index < scene.skeletons.length; index++) {
@@ -334,6 +339,11 @@
                 }
             }
 
+            // Action Manager
+            if (scene.actionManager) {
+                serializationObject.actions = scene.actionManager.serialize("scene");
+            }
+
             return serializationObject;
         }
 
@@ -368,4 +378,3 @@
     }
 }
 
-

File diff suppressed because it is too large
+ 895 - 901
src/Tools/babylon.tools.js


+ 1 - 1
src/Tools/babylon.tools.ts

@@ -316,7 +316,7 @@
                 }
                 else {
                     try {
-                        var textureName = url.substring(5);
+                        var textureName = url.substring(5).toLowerCase();
                         var blobURL;
                         try {
                             blobURL = URL.createObjectURL(FilesInput.FilesTextures[textureName], { oneTimeOnly: true });

+ 2 - 2
src/babylon.engine.js

@@ -635,7 +635,7 @@ var BABYLON;
                 }
             }
         };
-        Engine.prototype.bindFramebuffer = function (texture, faceIndex) {
+        Engine.prototype.bindFramebuffer = function (texture, faceIndex, requiredWidth, requiredHeight) {
             this._currentRenderTarget = texture;
             var gl = this._gl;
             gl.bindFramebuffer(gl.FRAMEBUFFER, texture._framebuffer);
@@ -645,7 +645,7 @@ var BABYLON;
             else {
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
             }
-            this._gl.viewport(0, 0, texture._width, texture._height);
+            this._gl.viewport(0, 0, requiredWidth || texture._width, requiredHeight || texture._height);
             this.wipeCaches();
         };
         Engine.prototype.unBindFramebuffer = function (texture, disableGenerateMipMaps) {

+ 2 - 2
src/babylon.engine.ts

@@ -750,7 +750,7 @@
             }
         }
 
-        public bindFramebuffer(texture: WebGLTexture, faceIndex?: number): void {
+        public bindFramebuffer(texture: WebGLTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number): void {
             this._currentRenderTarget = texture;
 
             var gl = this._gl;
@@ -762,7 +762,7 @@
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
             }
 
-            this._gl.viewport(0, 0, texture._width, texture._height);
+            this._gl.viewport(0, 0, requiredWidth || texture._width, requiredHeight || texture._height);
 
             this.wipeCaches();
         }

+ 8 - 1
src/babylon.scene.js

@@ -1244,6 +1244,11 @@ var BABYLON;
             }
             return null;
         };
+        Scene.prototype.getMeshesByID = function (id) {
+            return this.meshes.filter(function (m) {
+                return m.id === id;
+            });
+        };
         /**
          * Get a mesh with its auto-generated unique id
          * @param {number} uniqueId - the unique id to search for
@@ -1941,7 +1946,9 @@ var BABYLON;
             // Debug layer
             this.debugLayer.hide();
             // Events
-            this.onDisposeObservable.notifyObservers(this);
+            if (this.onDispose) {
+                this.onDispose();
+            }
             this.onBeforeRenderObservable.clear();
             this.onAfterRenderObservable.clear();
             this.detachControl();

+ 9 - 2
src/babylon.scene.ts

@@ -1506,6 +1506,12 @@
             return null;
         }
 
+        public getMeshesByID(id: string): Array<AbstractMesh> {
+            return this.meshes.filter(function (m) {
+                return m.id === id;
+            })
+        }
+
         /**
          * Get a mesh with its auto-generated unique id
          * @param {number} uniqueId - the unique id to search for
@@ -2355,7 +2361,9 @@
             this.debugLayer.hide();
 
             // Events
-            this.onDisposeObservable.notifyObservers(this);
+            if (this.onDispose) {
+                this.onDispose();
+            }
 
             this.onBeforeRenderObservable.clear();
             this.onAfterRenderObservable.clear();
@@ -2796,4 +2804,3 @@
         }
     }
 }
-