Browse Source

TGA support
Several fixes
AbstractMesh
InstancedMesh

David Catuhe 11 years ago
parent
commit
8068325c97
56 changed files with 2921 additions and 1413 deletions
  1. 36 4
      Babylon/Actions/babylon.condition.js
  2. 20 4
      Babylon/Actions/babylon.condition.ts
  3. 1 1
      Babylon/Cameras/babylon.arcRotateCamera.ts
  4. 3 3
      Babylon/Cameras/babylon.touchCamera.js
  5. 1 1
      Babylon/Collisions/babylon.collider.ts
  6. 2 2
      Babylon/Culling/Octrees/babylon.octree.ts
  7. 1 1
      Babylon/Culling/Octrees/babylon.octreeBlock.ts
  8. 2 2
      Babylon/Culling/babylon.boundingSphere.js
  9. 2 2
      Babylon/Culling/babylon.boundingSphere.ts
  10. 1 1
      Babylon/Lights/Shadows/babylon.shadowGenerator.js
  11. 2 2
      Babylon/Lights/Shadows/babylon.shadowGenerator.ts
  12. 1 1
      Babylon/Lights/babylon.light.ts
  13. 5 2
      Babylon/Loading/Plugins/babylon.babylonFileLoader.js
  14. 5 2
      Babylon/Loading/babylon.sceneLoader.js
  15. 2 2
      Babylon/Materials/babylon.material.ts
  16. 1 1
      Babylon/Materials/babylon.multiMaterial.ts
  17. 1 1
      Babylon/Materials/babylon.shaderMaterial.js
  18. 1 1
      Babylon/Materials/babylon.shaderMaterial.ts
  19. 3 3
      Babylon/Materials/babylon.standardMaterial.ts
  20. 2 2
      Babylon/Materials/textures/babylon.renderTargetTexture.ts
  21. 3 0
      Babylon/Math/babylon.math.js
  22. 1 0
      Babylon/Math/babylon.math.ts
  23. 163 0
      Babylon/Mesh/babylon.InstancedMesh.js
  24. 133 0
      Babylon/Mesh/babylon.InstancedMesh.ts
  25. 690 0
      Babylon/Mesh/babylon.abstractMesh.js
  26. 673 0
      Babylon/Mesh/babylon.abstractMesh.ts
  27. 110 633
      Babylon/Mesh/babylon.mesh.js
  28. 119 634
      Babylon/Mesh/babylon.mesh.ts
  29. 42 0
      Babylon/Mesh/babylon.mesh.vertexData.js
  30. 43 0
      Babylon/Mesh/babylon.mesh.vertexData.ts
  31. 31 11
      Babylon/Mesh/babylon.subMesh.js
  32. 36 13
      Babylon/Mesh/babylon.subMesh.ts
  33. 1 1
      Babylon/Particles/babylon.particleSystem.ts
  34. 10 10
      Babylon/Physics/Plugins/babylon.cannonJSPlugin.ts
  35. 11 11
      Babylon/Physics/babylon.physicsEngine.ts
  36. 1 1
      Babylon/PostProcess/babylon.postProcess.ts
  37. 1 1
      Babylon/Rendering/babylon.boundingBoxRenderer.ts
  38. 1 0
      Babylon/Rendering/babylon.renderingGroup.js
  39. 7 6
      Babylon/Rendering/babylon.renderingGroup.ts
  40. 1 1
      Babylon/Rendering/babylon.renderingManager.ts
  41. 6 3
      Babylon/Tools/babylon.sceneSerializer.js
  42. 6 3
      Babylon/Tools/babylon.sceneSerializer.ts
  43. 4 4
      Babylon/Tools/babylon.smartArray.ts
  44. 2 2
      Babylon/Tools/babylon.tools.dds.ts
  45. 9 0
      Babylon/Tools/babylon.tools.js
  46. 312 0
      Babylon/Tools/babylon.tools.tga.js
  47. 318 0
      Babylon/Tools/babylon.tools.tga.ts
  48. 9 0
      Babylon/Tools/babylon.tools.ts
  49. 14 2
      Babylon/babylon.engine.js
  50. 14 2
      Babylon/babylon.engine.ts
  51. 1 1
      Babylon/babylon.node.js
  52. 1 1
      Babylon/babylon.node.ts
  53. 10 4
      Babylon/babylon.scene.js
  54. 31 20
      Babylon/babylon.scene.ts
  55. 4 0
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml
  56. 11 11
      babylon.1.12-beta.js

+ 36 - 4
Babylon/Actions/babylon.condition.js

@@ -37,6 +37,38 @@ var BABYLON;
             this._target = this._getEffectiveTarget(target, this.propertyPath);
             this._property = this._getProperty(this.propertyPath);
         }
+        Object.defineProperty(StateCondition, "IsEqual", {
+            get: function () {
+                return StateCondition._IsEqual;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(StateCondition, "IsDifferent", {
+            get: function () {
+                return StateCondition._IsDifferent;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(StateCondition, "IsGreater", {
+            get: function () {
+                return StateCondition._IsGreater;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(StateCondition, "IsLesser", {
+            get: function () {
+                return StateCondition._IsLesser;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         // Methods
         StateCondition.prototype.isValid = function () {
             switch (this.operator) {
@@ -58,10 +90,10 @@ var BABYLON;
 
             return false;
         };
-        StateCondition.IsEqual = 0;
-        StateCondition.IsDifferent = 1;
-        StateCondition.IsGreater = 2;
-        StateCondition.IsLesser = 3;
+        StateCondition._IsEqual = 0;
+        StateCondition._IsDifferent = 1;
+        StateCondition._IsGreater = 2;
+        StateCondition._IsLesser = 3;
         return StateCondition;
     })(Condition);
     BABYLON.StateCondition = StateCondition;

+ 20 - 4
Babylon/Actions/babylon.condition.ts

@@ -24,10 +24,26 @@
 
     export class StateCondition extends Condition {
         // Statics
-        public static IsEqual = 0;
-        public static IsDifferent = 1;
-        public static IsGreater= 2;
-        public static IsLesser = 3;
+        private static _IsEqual = 0;
+        private static _IsDifferent = 1;
+        private static _IsGreater = 2;
+        private static _IsLesser = 3;
+
+        public static get IsEqual(): number {
+            return StateCondition._IsEqual;
+        }
+
+        public static get IsDifferent(): number {
+            return StateCondition._IsDifferent;
+        }
+
+        public static get IsGreater(): number {
+            return StateCondition._IsGreater;
+        }
+
+        public static get IsLesser(): number {
+            return StateCondition._IsLesser;
+        }
 
         // Members
         public _actionManager: ActionManager;

+ 1 - 1
Babylon/Cameras/babylon.arcRotateCamera.ts

@@ -380,7 +380,7 @@
             return this._viewMatrix;
         }
 
-        public zoomOn(meshes?: Mesh[]): void {
+        public zoomOn(meshes?: AbstractMesh[]): void {
             meshes = meshes || this.getScene().meshes;
 
             var minMaxVector = BABYLON.Mesh.MinMax(meshes);

+ 3 - 3
Babylon/Cameras/babylon.touchCamera.js

@@ -11,13 +11,13 @@ var BABYLON = BABYLON || {};
         this._offsetY = null;
         this._pointerCount = 0;
         this._pointerPressed = [];
+
+        this.angularSensibility = 200000.0;
+        this.moveSensibility = 500.0;
     };
 
     BABYLON.TouchCamera.prototype = Object.create(BABYLON.FreeCamera.prototype);
 
-    BABYLON.TouchCamera.prototype.angularSensibility = 200000.0;
-    BABYLON.TouchCamera.prototype.moveSensibility = 500.0;
-
 
     // Controls
     BABYLON.TouchCamera.prototype.attachControl = function (canvas, noPreventDefault) {

+ 1 - 1
Babylon/Collisions/babylon.collider.ts

@@ -68,7 +68,7 @@
         public initialPosition: Vector3;
         public nearestDistance: number;
         public intersectionPoint: Vector3;
-        public collidedMesh: Mesh
+        public collidedMesh: AbstractMesh
 
         private _collisionPoint = BABYLON.Vector3.Zero();
         private _planeIntersectionPoint = BABYLON.Vector3.Zero();

+ 2 - 2
Babylon/Culling/Octrees/babylon.octree.ts

@@ -11,7 +11,7 @@
 
         constructor(maxBlockCapacity?: number) {
             this._maxBlockCapacity = maxBlockCapacity || 64;
-            this._selection = new BABYLON.SmartArray(256);
+            this._selection = new BABYLON.SmartArray<OctreeBlock>(256);
         }
 
         // Methods
@@ -26,7 +26,7 @@
             }
         }
 
-        public select(frustumPlanes: Plane[]) {
+        public select(frustumPlanes: Plane[]): SmartArray<OctreeBlock> {
             this._selection.reset();
 
             for (var index = 0; index < this.blocks.length; index++) {

+ 1 - 1
Babylon/Culling/Octrees/babylon.octreeBlock.ts

@@ -1,6 +1,6 @@
 module BABYLON {
     export class OctreeBlock {
-        public meshes = new Array<Mesh>();
+        public meshes = new Array<AbstractMesh>();
         public subMeshes = new Array <Array<SubMesh>>();
         public blocks: Array<OctreeBlock>;
 

+ 2 - 2
Babylon/Culling/babylon.boundingSphere.js

@@ -17,8 +17,8 @@
         // Methods
         BoundingSphere.prototype._update = function (world) {
             BABYLON.Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 0, 0, world, this._tempRadiusVector);
-            this.radiusWorld = this._tempRadiusVector.length() * this.radius;
+            BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, this._tempRadiusVector);
+            this.radiusWorld = Math.max(Math.abs(this._tempRadiusVector.x), Math.abs(this._tempRadiusVector.y), Math.abs(this._tempRadiusVector.z)) * this.radius;
         };
 
         BoundingSphere.prototype.isInFrustum = function (frustumPlanes) {

+ 2 - 2
Babylon/Culling/babylon.boundingSphere.ts

@@ -20,8 +20,8 @@
         // Methods
         public _update(world: Matrix): void {
             BABYLON.Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 0, 0, world, this._tempRadiusVector);
-            this.radiusWorld = this._tempRadiusVector.length() * this.radius;
+            BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, this._tempRadiusVector);
+            this.radiusWorld = Math.max(Math.abs(this._tempRadiusVector.x), Math.abs(this._tempRadiusVector.y), Math.abs(this._tempRadiusVector.z)) * this.radius;
         }
 
         public isInFrustum(frustumPlanes: Plane[]): boolean {

+ 1 - 1
Babylon/Lights/Shadows/babylon.shadowGenerator.js

@@ -24,7 +24,7 @@
 
             // Custom render function
             var renderSubMesh = function (subMesh) {
-                var mesh = subMesh.getMesh();
+                var mesh = subMesh.getRenderingMesh();
                 var world = mesh.getWorldMatrix();
                 var engine = _this._scene.getEngine();
 

+ 2 - 2
Babylon/Lights/Shadows/babylon.shadowGenerator.ts

@@ -33,7 +33,7 @@
 
             // Custom render function
             var renderSubMesh = (subMesh: SubMesh): void => {
-                var mesh = subMesh.getMesh();
+                var mesh = subMesh.getRenderingMesh();
                 var world = mesh.getWorldMatrix();
                 var engine = this._scene.getEngine();
 
@@ -56,7 +56,7 @@
                 }
             };
 
-            this._shadowMap.customRenderFunction = (opaqueSubMeshes: SmartArray, alphaTestSubMeshes: SmartArray, transparentSubMeshes: SmartArray): void => {
+            this._shadowMap.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void => {
                 var index;
 
                 for (index = 0; index < opaqueSubMeshes.length; index++) {

+ 1 - 1
Babylon/Lights/babylon.light.ts

@@ -4,7 +4,7 @@
         public specular = new Color3(1.0, 1.0, 1.0);
         public intensity = 1.0;
         public range = Number.MAX_VALUE;
-        public excludedMeshes = new Array<Mesh>();
+        public excludedMeshes = new Array<AbstractMesh>();
 
         public _shadowGenerator: ShadowGenerator;
         private _parentedWorldMatrix: Matrix;

+ 5 - 2
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -484,7 +484,6 @@ var BABYLON = BABYLON || {};
             }
 
             geometry._delayLoadingFunction = importVertexData;
-
         } else {
             importVertexData(parsedVertexData, geometry);
         }
@@ -567,6 +566,10 @@ var BABYLON = BABYLON || {};
 
             mesh._delayLoadingFunction = importGeometry;
 
+            if (BABYLON.SceneLoader.ForceFullSceneLoadingForIncremental) {
+                mesh._checkDelayState();
+            }
+
         } else {
             importGeometry(parsedMesh, mesh);
         }
@@ -849,7 +852,7 @@ var BABYLON = BABYLON || {};
             var parsedData = JSON.parse(data);
 
             // Scene
-            scene.useDelayedTextureLoading = parsedData.useDelayedTextureLoading;
+            scene.useDelayedTextureLoading = parsedData.useDelayedTextureLoading && !BABYLON.SceneLoader.ForceFullSceneLoadingForIncremental;
             scene.autoClear = parsedData.autoClear;
             scene.clearColor = BABYLON.Color3.FromArray(parsedData.clearColor);
             scene.ambientColor = BABYLON.Color3.FromArray(parsedData.ambientColor);

+ 5 - 2
Babylon/Loading/babylon.sceneLoader.js

@@ -6,7 +6,7 @@ var BABYLON = BABYLON || {};
     BABYLON.SceneLoader = {
         _registeredPlugins: [],
 
-        _getPluginForFilename: function (sceneFilename) {
+        _getPluginForFilename: function(sceneFilename) {
             var dotPosition = sceneFilename.lastIndexOf(".");
             var extension = sceneFilename.substring(dotPosition).toLowerCase();
 
@@ -18,9 +18,12 @@ var BABYLON = BABYLON || {};
                 }
             }
 
-            throw new Error("No plugin found to load this file: " + sceneFilename);
+            return this._registeredPlugins[this._registeredPlugins.length - 1];
         },
 
+        // Flags
+        ForceFullSceneLoadingForIncremental: false,
+
         // Public functions
         RegisterPlugin: function (plugin) {
             plugin.extensions = plugin.extensions.toLowerCase();

+ 2 - 2
Babylon/Materials/babylon.material.ts

@@ -9,7 +9,7 @@
         public onCompiled: (effect: Effect) => void;
         public onError: (effect: Effect, errors: string) => void;
         public onDispose: () => void;
-        public getRenderTargetTextures: () => SmartArray;
+        public getRenderTargetTextures: () => SmartArray<RenderTargetTexture>;
 
         public _effect: Effect;
         public _wasPreviouslyReady = false;
@@ -25,7 +25,7 @@
             }
         }
 
-        public isReady(mesh?: Mesh): boolean {
+        public isReady(mesh?: AbstractMesh): boolean {
             return true;
         }
 

+ 1 - 1
Babylon/Materials/babylon.multiMaterial.ts

@@ -18,7 +18,7 @@
         }
 
         // Methods
-        public isReady(mesh?: Mesh): boolean {
+        public isReady(mesh?: AbstractMesh): boolean {
             for (var index = 0; index < this.subMaterials.length; index++) {
                 var subMaterial = this.subMaterials[index];
                 if (subMaterial) {

+ 1 - 1
Babylon/Materials/babylon.shaderMaterial.js

@@ -101,7 +101,7 @@ var BABYLON;
             return this;
         };
 
-        ShaderMaterial.prototype.isReady = function (mesh) {
+        ShaderMaterial.prototype.isReady = function () {
             var engine = this.getScene().getEngine();
 
             this._effect = engine.createEffect(this._shaderPath, this._options.attributes, this._options.uniforms, this._options.samplers, "", null, this.onCompiled, this.onError);

+ 1 - 1
Babylon/Materials/babylon.shaderMaterial.ts

@@ -97,7 +97,7 @@
             return this;
         }
 
-        public isReady(mesh?: Mesh): boolean {
+        public isReady(): boolean {
             var engine = this.getScene().getEngine();
 
             this._effect = engine.createEffect(this._shaderPath,

+ 3 - 3
Babylon/Materials/babylon.standardMaterial.ts

@@ -18,7 +18,7 @@
         public useAlphaFromDiffuseTexture = false;
 
         private _cachedDefines = null;
-        private _renderTargets = new BABYLON.SmartArray(16);
+        private _renderTargets = new BABYLON.SmartArray<RenderTargetTexture>(16);
         private _worldViewProjectionMatrix = BABYLON.Matrix.Zero();
         private _lightMatrix = BABYLON.Matrix.Zero();
         private _globalAmbientColor = new BABYLON.Color3(0, 0, 0);
@@ -30,7 +30,7 @@
         constructor(name: string, scene: Scene) {
             super(name, scene);
 
-            this.getRenderTargetTextures = (): SmartArray => {
+            this.getRenderTargetTextures = (): SmartArray<RenderTargetTexture> => {
                 this._renderTargets.reset();
 
                 if (this.reflectionTexture && this.reflectionTexture.isRenderTarget) {
@@ -54,7 +54,7 @@
         }
 
         // Methods   
-        public isReady(mesh?: Mesh): boolean {
+        public isReady(mesh?: AbstractMesh): boolean {
             if (this.checkReadyOnlyOnce) {
                 if (this._wasPreviouslyReady) {
                     return true;

+ 2 - 2
Babylon/Materials/textures/babylon.renderTargetTexture.ts

@@ -1,12 +1,12 @@
 module BABYLON {
     export class RenderTargetTexture extends Texture {
-        public renderList = new Array<Mesh>();
+        public renderList = new Array<AbstractMesh>();
         public renderParticles = true;
         public renderSprites = false;
         public coordinatesMode = BABYLON.Texture.PROJECTION_MODE;
         public onBeforeRender: () => void;
         public onAfterRender: () => void;
-        public customRenderFunction: (opaqueSubMeshes: SmartArray, transparentSubMeshes: SmartArray, alphaTestSubMeshes: SmartArray, beforeTransparents?: () => void) => void;
+        public customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents?: () => void) => void;
 
         private _size: number;
         public _generateMipMaps: boolean;

+ 3 - 0
Babylon/Math/babylon.math.js

@@ -133,6 +133,9 @@
         Color3.Yellow = function () {
             return new Color3(1, 1, 0);
         };
+        Color3.Gray = function () {
+            return new Color3(0.5, 0.5, 0.5);
+        };
         return Color3;
     })();
     BABYLON.Color3 = Color3;

+ 1 - 0
Babylon/Math/babylon.math.ts

@@ -111,6 +111,7 @@
         public static Purple(): Color3 { return new Color3(0.5, 0, 0.5); }
         public static Magenta(): Color3 { return new Color3(1, 0, 1); }
         public static Yellow(): Color3 { return new Color3(1, 1, 0); }
+        public static Gray(): Color3 { return new Color3(0.5, 0.5, 0.5); }
     }
 
     export class Color4 {

+ 163 - 0
Babylon/Mesh/babylon.InstancedMesh.js

@@ -0,0 +1,163 @@
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    var InstancedMesh = (function (_super) {
+        __extends(InstancedMesh, _super);
+        function InstancedMesh(name, source) {
+            _super.call(this, name, source.getScene());
+
+            source.instances.push(this);
+
+            this._sourceMesh = source;
+
+            this.position.copyFrom(source.position);
+            this.rotation.copyFrom(source.rotation);
+            this.scaling.copyFrom(source.scaling);
+
+            if (source.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(source.rotationQuaternion);
+            }
+
+            this.infiniteDistance = source.infiniteDistance;
+
+            this.setPivotMatrix(source.getPivotMatrix());
+
+            this.refreshBoundingInfo();
+            this._syncSubMeshes();
+        }
+        Object.defineProperty(InstancedMesh.prototype, "receiveShadows", {
+            // Methods
+            get: function () {
+                return this._sourceMesh.receiveShadows;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(InstancedMesh.prototype, "material", {
+            get: function () {
+                return this._sourceMesh.material;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(InstancedMesh.prototype, "visibility", {
+            get: function () {
+                return this._sourceMesh.visibility;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(InstancedMesh.prototype, "skeleton", {
+            get: function () {
+                return this._sourceMesh.skeleton;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        InstancedMesh.prototype.getTotalVertices = function () {
+            return this._sourceMesh.getTotalVertices();
+        };
+
+        Object.defineProperty(InstancedMesh.prototype, "sourceMesh", {
+            get: function () {
+                return this._sourceMesh;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        InstancedMesh.prototype.getVerticesData = function (kind) {
+            return this._sourceMesh.getVerticesData(kind);
+        };
+
+        InstancedMesh.prototype.isVerticesDataPresent = function (kind) {
+            return this._sourceMesh.isVerticesDataPresent(kind);
+        };
+
+        InstancedMesh.prototype.getIndices = function () {
+            return this._sourceMesh.getIndices();
+        };
+
+        Object.defineProperty(InstancedMesh.prototype, "_positions", {
+            get: function () {
+                return this._sourceMesh._positions;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        InstancedMesh.prototype.refreshBoundingInfo = function () {
+            var data = this._sourceMesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+
+            if (data) {
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._sourceMesh.getTotalVertices());
+                this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+            }
+
+            this._updateBoundingInfo();
+        };
+
+        InstancedMesh.prototype._syncSubMeshes = function () {
+            this.releaseSubMeshes();
+            this.subMeshes = [];
+            for (var index = 0; index < this._sourceMesh.subMeshes.length; index++) {
+                this._sourceMesh.subMeshes[index].clone(this, this._sourceMesh);
+            }
+        };
+
+        InstancedMesh.prototype._generatePointsArray = function () {
+            return this._sourceMesh._generatePointsArray();
+        };
+
+        // Clone
+        InstancedMesh.prototype.clone = function (name, newParent, doNotCloneChildren) {
+            var result = this._sourceMesh.createInstance(name);
+
+            // Deep copy
+            BABYLON.Tools.DeepCopy(this, result, ["name"], []);
+
+            // Bounding info
+            this.refreshBoundingInfo();
+
+            // Parent
+            if (newParent) {
+                result.parent = newParent;
+            }
+
+            if (!doNotCloneChildren) {
+                for (var index = 0; index < this.getScene().meshes.length; index++) {
+                    var mesh = this.getScene().meshes[index];
+
+                    if (mesh.parent == this) {
+                        mesh.clone(mesh.name, result);
+                    }
+                }
+            }
+
+            result.computeWorldMatrix(true);
+
+            return result;
+        };
+
+        // Dispoe
+        InstancedMesh.prototype.dispose = function (doNotRecurse) {
+            // Remove from mesh
+            var index = this._sourceMesh.instances.indexOf(this);
+            this._sourceMesh.instances.splice(index, 1);
+
+            _super.prototype.dispose.call(this, doNotRecurse);
+        };
+        return InstancedMesh;
+    })(BABYLON.AbstractMesh);
+    BABYLON.InstancedMesh = InstancedMesh;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.InstancedMesh.js.map

+ 133 - 0
Babylon/Mesh/babylon.InstancedMesh.ts

@@ -0,0 +1,133 @@
+module BABYLON {
+    export class InstancedMesh extends AbstractMesh {
+        private _sourceMesh: Mesh;
+
+        constructor(name: string, source: Mesh) {
+            super(name, source.getScene());
+
+            source.instances.push(this);
+
+            this._sourceMesh = source;
+
+            this.position.copyFrom(source.position);
+            this.rotation.copyFrom(source.rotation);
+            this.scaling.copyFrom(source.scaling);
+
+            if (source.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(source.rotationQuaternion);
+            }
+
+            this.infiniteDistance = source.infiniteDistance;
+
+            this.setPivotMatrix(source.getPivotMatrix());
+
+            this.refreshBoundingInfo();
+            this._syncSubMeshes();
+        }
+
+        // Methods
+        public get receiveShadows(): boolean {
+            return this._sourceMesh.receiveShadows;
+        }
+
+        public get material(): Material {
+            return this._sourceMesh.material;
+        }
+
+        public get visibility(): number {
+            return this._sourceMesh.visibility;
+        }
+
+        public get skeleton(): Skeleton {
+            return this._sourceMesh.skeleton;
+        }
+
+        public getTotalVertices(): number {
+            return this._sourceMesh.getTotalVertices();
+        }
+
+        public get sourceMesh(): Mesh {
+            return this._sourceMesh;
+        }
+
+        public getVerticesData(kind: string): number[] {
+            return this._sourceMesh.getVerticesData(kind);
+        }
+
+        public isVerticesDataPresent(kind: string): boolean {
+            return this._sourceMesh.isVerticesDataPresent(kind);
+        }
+
+        public getIndices(): number[] {
+            return this._sourceMesh.getIndices();
+        }
+
+        public get _positions(): Vector3[] {
+            return this._sourceMesh._positions;
+        }
+
+        public refreshBoundingInfo(): void {
+            var data = this._sourceMesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+
+            if (data) {
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._sourceMesh.getTotalVertices());
+                this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+            }
+
+            this._updateBoundingInfo();
+        }
+
+        public _syncSubMeshes(): void {
+            this.releaseSubMeshes();
+            this.subMeshes = [];
+            for (var index = 0; index < this._sourceMesh.subMeshes.length; index++) {
+                this._sourceMesh.subMeshes[index].clone(this, this._sourceMesh);
+            }
+        }
+
+        public _generatePointsArray(): boolean {
+            return this._sourceMesh._generatePointsArray();
+        }
+
+        // Clone
+        public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): InstancedMesh {
+            var result = this._sourceMesh.createInstance(name);
+
+            // Deep copy
+            BABYLON.Tools.DeepCopy(this, result, ["name"], []);
+
+            // Bounding info
+            this.refreshBoundingInfo();
+
+            // Parent
+            if (newParent) {
+                result.parent = newParent;
+            }
+
+            if (!doNotCloneChildren) {
+                // Children
+                for (var index = 0; index < this.getScene().meshes.length; index++) {
+                    var mesh = this.getScene().meshes[index];
+
+                    if (mesh.parent == this) {
+                        mesh.clone(mesh.name, result);
+                    }
+                }
+            }
+
+            result.computeWorldMatrix(true);
+
+            return result;
+        }
+
+        // Dispoe
+        public dispose(doNotRecurse?: boolean): void {
+
+            // Remove from mesh
+            var index = this._sourceMesh.instances.indexOf(this);
+            this._sourceMesh.instances.splice(index, 1);
+
+            super.dispose(doNotRecurse);
+        }
+    }
+} 

+ 690 - 0
Babylon/Mesh/babylon.abstractMesh.js

@@ -0,0 +1,690 @@
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    var AbstractMesh = (function (_super) {
+        __extends(AbstractMesh, _super);
+        function AbstractMesh(name, scene) {
+            _super.call(this, name, scene);
+            // Properties
+            this.position = new BABYLON.Vector3(0, 0, 0);
+            this.rotation = new BABYLON.Vector3(0, 0, 0);
+            this.scaling = new BABYLON.Vector3(1, 1, 1);
+            this.billboardMode = BABYLON.AbstractMesh.BILLBOARDMODE_NONE;
+            this.visibility = 1.0;
+            this.infiniteDistance = false;
+            this.isVisible = true;
+            this.isPickable = true;
+            this.showBoundingBox = false;
+            this.onDispose = null;
+            this.checkCollisions = false;
+            this.renderingGroupId = 0;
+            this.receiveShadows = false;
+            // Physics
+            this._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
+            // Cache
+            this._localScaling = BABYLON.Matrix.Zero();
+            this._localRotation = BABYLON.Matrix.Zero();
+            this._localTranslation = BABYLON.Matrix.Zero();
+            this._localBillboard = BABYLON.Matrix.Zero();
+            this._localPivotScaling = BABYLON.Matrix.Zero();
+            this._localPivotScalingRotation = BABYLON.Matrix.Zero();
+            this._localWorld = BABYLON.Matrix.Zero();
+            this._worldMatrix = BABYLON.Matrix.Zero();
+            this._rotateYByPI = BABYLON.Matrix.RotationY(Math.PI);
+            this._absolutePosition = BABYLON.Vector3.Zero();
+            this._collisionsTransformMatrix = BABYLON.Matrix.Zero();
+            this._collisionsScalingMatrix = BABYLON.Matrix.Zero();
+            this._isDirty = false;
+            this._pivotMatrix = BABYLON.Matrix.Identity();
+            this._isDisposed = false;
+            this._renderId = 0;
+
+            scene.meshes.push(this);
+        }
+        Object.defineProperty(AbstractMesh, "BILLBOARDMODE_NONE", {
+            get: function () {
+                return AbstractMesh._BILLBOARDMODE_NONE;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(AbstractMesh, "BILLBOARDMODE_X", {
+            get: function () {
+                return AbstractMesh._BILLBOARDMODE_X;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(AbstractMesh, "BILLBOARDMODE_Y", {
+            get: function () {
+                return AbstractMesh._BILLBOARDMODE_Y;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(AbstractMesh, "BILLBOARDMODE_Z", {
+            get: function () {
+                return AbstractMesh._BILLBOARDMODE_Z;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(AbstractMesh, "BILLBOARDMODE_ALL", {
+            get: function () {
+                return AbstractMesh._BILLBOARDMODE_ALL;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        // Methods
+        AbstractMesh.prototype.getTotalVertices = function () {
+            return 0;
+        };
+
+        AbstractMesh.prototype.getIndices = function () {
+            return null;
+        };
+
+        AbstractMesh.prototype.getVerticesData = function (kind) {
+            return null;
+        };
+
+        AbstractMesh.prototype.isVerticesDataPresent = function (kind) {
+            return false;
+        };
+
+        AbstractMesh.prototype.getBoundingInfo = function () {
+            return this._boundingInfo;
+        };
+
+        AbstractMesh.prototype._activate = function (renderId) {
+            this._renderId = renderId;
+        };
+
+        AbstractMesh.prototype.getWorldMatrix = function () {
+            if (this._currentRenderId !== this.getScene().getRenderId()) {
+                this.computeWorldMatrix();
+            }
+            return this._worldMatrix;
+        };
+
+        Object.defineProperty(AbstractMesh.prototype, "worldMatrixFromCache", {
+            get: function () {
+                return this._worldMatrix;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(AbstractMesh.prototype, "absolutePosition", {
+            get: function () {
+                return this._absolutePosition;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        AbstractMesh.prototype.rotate = function (axis, amount, space) {
+            if (!this.rotationQuaternion) {
+                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
+                this.rotation = BABYLON.Vector3.Zero();
+            }
+
+            if (!space || space == 0 /* LOCAL */) {
+                var rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
+                this.rotationQuaternion = this.rotationQuaternion.multiply(rotationQuaternion);
+            } else {
+                if (this.parent) {
+                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
+                    invertParentWorldMatrix.invert();
+
+                    axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
+                }
+                rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
+                this.rotationQuaternion = rotationQuaternion.multiply(this.rotationQuaternion);
+            }
+        };
+
+        AbstractMesh.prototype.translate = function (axis, distance, space) {
+            var displacementVector = axis.scale(distance);
+
+            if (!space || space == 0 /* LOCAL */) {
+                var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
+                this.setPositionWithLocalVector(tempV3);
+            } else {
+                this.setAbsolutePosition(this.getAbsolutePosition().add(displacementVector));
+            }
+        };
+
+        AbstractMesh.prototype.getAbsolutePosition = function () {
+            this.computeWorldMatrix();
+            return this._absolutePosition;
+        };
+
+        AbstractMesh.prototype.setAbsolutePosition = function (absolutePosition) {
+            if (!absolutePosition) {
+                return;
+            }
+
+            var absolutePositionX;
+            var absolutePositionY;
+            var absolutePositionZ;
+
+            if (absolutePosition.x === undefined) {
+                if (arguments.length < 3) {
+                    return;
+                }
+                absolutePositionX = arguments[0];
+                absolutePositionY = arguments[1];
+                absolutePositionZ = arguments[2];
+            } else {
+                absolutePositionX = absolutePosition.x;
+                absolutePositionY = absolutePosition.y;
+                absolutePositionZ = absolutePosition.z;
+            }
+
+            if (this.parent) {
+                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
+                invertParentWorldMatrix.invert();
+
+                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
+
+                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+            } else {
+                this.position.x = absolutePositionX;
+                this.position.y = absolutePositionY;
+                this.position.z = absolutePositionZ;
+            }
+        };
+
+        AbstractMesh.prototype.setPivotMatrix = function (matrix) {
+            this._pivotMatrix = matrix;
+            this._cache.pivotMatrixUpdated = true;
+        };
+
+        AbstractMesh.prototype.getPivotMatrix = function () {
+            return this._pivotMatrix;
+        };
+
+        AbstractMesh.prototype._isSynchronized = function () {
+            if (this._isDirty) {
+                return false;
+            }
+
+            if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE)
+                return false;
+
+            if (this._cache.pivotMatrixUpdated) {
+                return false;
+            }
+
+            if (this.infiniteDistance) {
+                return false;
+            }
+
+            if (!this._cache.position.equals(this.position))
+                return false;
+
+            if (this.rotationQuaternion) {
+                if (!this._cache.rotationQuaternion.equals(this.rotationQuaternion))
+                    return false;
+            } else {
+                if (!this._cache.rotation.equals(this.rotation))
+                    return false;
+            }
+
+            if (!this._cache.scaling.equals(this.scaling))
+                return false;
+
+            return true;
+        };
+
+        AbstractMesh.prototype._initCache = function () {
+            _super.prototype._initCache.call(this);
+
+            this._cache.localMatrixUpdated = false;
+            this._cache.position = BABYLON.Vector3.Zero();
+            this._cache.scaling = BABYLON.Vector3.Zero();
+            this._cache.rotation = BABYLON.Vector3.Zero();
+            this._cache.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 0);
+        };
+
+        AbstractMesh.prototype.markAsDirty = function (property) {
+            if (property === "rotation") {
+                this.rotationQuaternion = null;
+            }
+            this._currentRenderId = Number.MAX_VALUE;
+            this._isDirty = true;
+        };
+
+        AbstractMesh.prototype._updateBoundingInfo = function () {
+            this._boundingInfo = this._boundingInfo || new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition);
+
+            this._boundingInfo._update(this.worldMatrixFromCache);
+
+            if (!this.subMeshes) {
+                return;
+            }
+
+            for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
+                var subMesh = this.subMeshes[subIndex];
+
+                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+            }
+        };
+
+        AbstractMesh.prototype.computeWorldMatrix = function (force) {
+            if (!force && (this._currentRenderId == this.getScene().getRenderId() || this.isSynchronized(true))) {
+                return this._worldMatrix;
+            }
+
+            this._cache.position.copyFrom(this.position);
+            this._cache.scaling.copyFrom(this.scaling);
+            this._cache.pivotMatrixUpdated = false;
+            this._currentRenderId = this.getScene().getRenderId();
+            this._isDirty = false;
+
+            // Scaling
+            BABYLON.Matrix.ScalingToRef(this.scaling.x, this.scaling.y, this.scaling.z, this._localScaling);
+
+            // Rotation
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.toRotationMatrix(this._localRotation);
+                this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
+            } else {
+                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
+                this._cache.rotation.copyFrom(this.rotation);
+            }
+
+            // Translation
+            if (this.infiniteDistance && !this.parent) {
+                var camera = this.getScene().activeCamera;
+                var cameraWorldMatrix = camera.getWorldMatrix();
+
+                var cameraGlobalPosition = new BABYLON.Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
+
+                BABYLON.Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y, this.position.z + cameraGlobalPosition.z, this._localTranslation);
+            } else {
+                BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
+            }
+
+            // Composing transformations
+            this._pivotMatrix.multiplyToRef(this._localScaling, this._localPivotScaling);
+            this._localPivotScaling.multiplyToRef(this._localRotation, this._localPivotScalingRotation);
+
+            // Billboarding
+            if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE) {
+                var localPosition = this.position.clone();
+                var zero = this.getScene().activeCamera.position.clone();
+
+                if (this.parent && this.parent.position) {
+                    localPosition.addInPlace(this.parent.position);
+                    BABYLON.Matrix.TranslationToRef(localPosition.x, localPosition.y, localPosition.z, this._localTranslation);
+                }
+
+                if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) === AbstractMesh.BILLBOARDMODE_ALL) {
+                    zero = this.getScene().activeCamera.position;
+                } else {
+                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_X)
+                        zero.x = localPosition.x + BABYLON.Engine.Epsilon;
+                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_Y)
+                        zero.y = localPosition.y + 0.001;
+                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_Z)
+                        zero.z = localPosition.z + 0.001;
+                }
+
+                BABYLON.Matrix.LookAtLHToRef(localPosition, zero, BABYLON.Vector3.Up(), this._localBillboard);
+                this._localBillboard.m[12] = this._localBillboard.m[13] = this._localBillboard.m[14] = 0;
+
+                this._localBillboard.invert();
+
+                this._localPivotScalingRotation.multiplyToRef(this._localBillboard, this._localWorld);
+                this._rotateYByPI.multiplyToRef(this._localWorld, this._localPivotScalingRotation);
+            }
+
+            // Local world
+            this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
+
+            // Parent
+            if (this.parent && this.parent.getWorldMatrix && this.billboardMode === BABYLON.AbstractMesh.BILLBOARDMODE_NONE) {
+                this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
+            } else {
+                this._worldMatrix.copyFrom(this._localWorld);
+            }
+
+            // Bounding info
+            this._updateBoundingInfo();
+
+            // Absolute position
+            this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
+
+            return this._worldMatrix;
+        };
+
+        AbstractMesh.prototype.setPositionWithLocalVector = function (vector3) {
+            this.computeWorldMatrix();
+
+            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localWorld);
+        };
+
+        AbstractMesh.prototype.getPositionExpressedInLocalSpace = function () {
+            this.computeWorldMatrix();
+            var invLocalWorldMatrix = this._localWorld.clone();
+            invLocalWorldMatrix.invert();
+
+            return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
+        };
+
+        AbstractMesh.prototype.locallyTranslate = function (vector3) {
+            this.computeWorldMatrix();
+
+            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localWorld);
+        };
+
+        AbstractMesh.prototype.lookAt = function (targetPoint, yawCor, pitchCor, rollCor) {
+            /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
+            /// <param name="targetPoint" type="BABYLON.Vector3">The position (must be in same space as current mesh) to look at</param>
+            /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
+            /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
+            /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
+            /// <returns>Mesh oriented towards targetMesh</returns>
+            yawCor = yawCor || 0; // default to zero if undefined
+            pitchCor = pitchCor || 0;
+            rollCor = rollCor || 0;
+
+            var dv = targetPoint.subtract(this.position);
+            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
+            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
+            var pitch = Math.atan2(dv.y, len);
+            this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(yaw + yawCor, pitch + pitchCor, rollCor);
+        };
+
+        AbstractMesh.prototype.isInFrustum = function (frustumPlanes) {
+            if (!this._boundingInfo.isInFrustum(frustumPlanes)) {
+                return false;
+            }
+
+            return true;
+        };
+
+        AbstractMesh.prototype.intersectsMesh = function (mesh, precise) {
+            if (!this._boundingInfo || !mesh._boundingInfo) {
+                return false;
+            }
+
+            return this._boundingInfo.intersects(mesh._boundingInfo, precise);
+        };
+
+        AbstractMesh.prototype.intersectsPoint = function (point) {
+            if (!this._boundingInfo) {
+                return false;
+            }
+
+            return this._boundingInfo.intersectsPoint(point);
+        };
+
+        // Physics
+        AbstractMesh.prototype.setPhysicsState = function (impostor, options) {
+            var physicsEngine = this.getScene().getPhysicsEngine();
+
+            if (!physicsEngine) {
+                return;
+            }
+
+            if (impostor.impostor) {
+                // Old API
+                options = impostor;
+                impostor = impostor.impostor;
+            }
+
+            impostor = impostor || BABYLON.PhysicsEngine.NoImpostor;
+
+            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
+                physicsEngine._unregisterMesh(this);
+                return;
+            }
+
+            options.mass = options.mass || 0;
+            options.friction = options.friction || 0.2;
+            options.restitution = options.restitution || 0.9;
+
+            this._physicImpostor = impostor;
+            this._physicsMass = options.mass;
+            this._physicsFriction = options.friction;
+            this._physicRestitution = options.restitution;
+
+            physicsEngine._registerMesh(this, impostor, options);
+        };
+
+        AbstractMesh.prototype.getPhysicsImpostor = function () {
+            if (!this._physicImpostor) {
+                return BABYLON.PhysicsEngine.NoImpostor;
+            }
+
+            return this._physicImpostor;
+        };
+
+        AbstractMesh.prototype.getPhysicsMass = function () {
+            if (!this._physicsMass) {
+                return 0;
+            }
+
+            return this._physicsMass;
+        };
+
+        AbstractMesh.prototype.getPhysicsFriction = function () {
+            if (!this._physicsFriction) {
+                return 0;
+            }
+
+            return this._physicsFriction;
+        };
+
+        AbstractMesh.prototype.getPhysicsRestitution = function () {
+            if (!this._physicRestitution) {
+                return 0;
+            }
+
+            return this._physicRestitution;
+        };
+
+        AbstractMesh.prototype.applyImpulse = function (force, contactPoint) {
+            if (!this._physicImpostor) {
+                return;
+            }
+
+            this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
+        };
+
+        AbstractMesh.prototype.setPhysicsLinkWith = function (otherMesh, pivot1, pivot2) {
+            if (!this._physicImpostor) {
+                return;
+            }
+
+            this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2);
+        };
+
+        // Collisions
+        AbstractMesh.prototype._collideForSubMesh = function (subMesh, transformMatrix, collider) {
+            this._generatePointsArray();
+
+            // Transformation
+            if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix.equals(transformMatrix)) {
+                subMesh._lastColliderTransformMatrix = transformMatrix.clone();
+                subMesh._lastColliderWorldVertices = [];
+                subMesh._trianglePlanes = [];
+                var start = subMesh.verticesStart;
+                var end = (subMesh.verticesStart + subMesh.verticesCount);
+                for (var i = start; i < end; i++) {
+                    subMesh._lastColliderWorldVertices.push(BABYLON.Vector3.TransformCoordinates(this._positions[i], transformMatrix));
+                }
+            }
+
+            // Collide
+            collider._collide(subMesh, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
+        };
+
+        AbstractMesh.prototype._processCollisionsForSubModels = function (collider, transformMatrix) {
+            for (var index = 0; index < this.subMeshes.length; index++) {
+                var subMesh = this.subMeshes[index];
+
+                // Bounding test
+                if (this.subMeshes.length > 1 && !subMesh._checkCollision(collider))
+                    continue;
+
+                this._collideForSubMesh(subMesh, transformMatrix, collider);
+            }
+        };
+
+        AbstractMesh.prototype._checkCollision = function (collider) {
+            // Bounding box test
+            if (!this._boundingInfo._checkCollision(collider))
+                return;
+
+            // Transformation matrix
+            BABYLON.Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
+            this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
+
+            this._processCollisionsForSubModels(collider, this._collisionsTransformMatrix);
+        };
+
+        // Picking
+        AbstractMesh.prototype._generatePointsArray = function () {
+            return false;
+        };
+
+        AbstractMesh.prototype.intersects = function (ray, fastCheck) {
+            var pickingInfo = new BABYLON.PickingInfo();
+
+            if (!this.subMeshes || !this._boundingInfo || !ray.intersectsSphere(this._boundingInfo.boundingSphere) || !ray.intersectsBox(this._boundingInfo.boundingBox)) {
+                return pickingInfo;
+            }
+
+            if (!this._generatePointsArray()) {
+                return pickingInfo;
+            }
+
+            var intersectInfo = null;
+
+            for (var index = 0; index < this.subMeshes.length; index++) {
+                var subMesh = this.subMeshes[index];
+
+                // Bounding test
+                if (this.subMeshes.length > 1 && !subMesh.canIntersects(ray))
+                    continue;
+
+                var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);
+
+                if (currentIntersectInfo) {
+                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
+                        intersectInfo = currentIntersectInfo;
+
+                        if (fastCheck) {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (intersectInfo) {
+                // Get picked point
+                var world = this.getWorldMatrix();
+                var worldOrigin = BABYLON.Vector3.TransformCoordinates(ray.origin, world);
+                var direction = ray.direction.clone();
+                direction.normalize();
+                direction = direction.scale(intersectInfo.distance);
+                var worldDirection = BABYLON.Vector3.TransformNormal(direction, world);
+
+                var pickedPoint = worldOrigin.add(worldDirection);
+
+                // Return result
+                pickingInfo.hit = true;
+                pickingInfo.distance = BABYLON.Vector3.Distance(worldOrigin, pickedPoint);
+                pickingInfo.pickedPoint = pickedPoint;
+                pickingInfo.pickedMesh = this;
+                pickingInfo.bu = intersectInfo.bu;
+                pickingInfo.bv = intersectInfo.bv;
+                pickingInfo.faceId = intersectInfo.faceId;
+                return pickingInfo;
+            }
+
+            return pickingInfo;
+        };
+
+        AbstractMesh.prototype.clone = function (name, newParent, doNotCloneChildren) {
+            return null;
+        };
+
+        AbstractMesh.prototype.releaseSubMeshes = function () {
+            if (this.subMeshes) {
+                while (this.subMeshes.length) {
+                    this.subMeshes[0].dispose();
+                }
+            }
+        };
+
+        AbstractMesh.prototype.dispose = function (doNotRecurse) {
+            // Physics
+            if (this.getPhysicsImpostor() != BABYLON.PhysicsEngine.NoImpostor) {
+                this.setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
+            }
+
+            // SubMeshes
+            this.releaseSubMeshes();
+
+            // Remove from scene
+            var index = this.getScene().meshes.indexOf(this);
+            this.getScene().meshes.splice(index, 1);
+
+            if (!doNotRecurse) {
+                for (index = 0; index < this.getScene().particleSystems.length; index++) {
+                    if (this.getScene().particleSystems[index].emitter == this) {
+                        this.getScene().particleSystems[index].dispose();
+                        index--;
+                    }
+                }
+
+                // Children
+                var objects = this.getScene().meshes.slice(0);
+                for (index = 0; index < objects.length; index++) {
+                    if (objects[index].parent == this) {
+                        objects[index].dispose();
+                    }
+                }
+            } else {
+                for (index = 0; index < this.getScene().meshes.length; index++) {
+                    var obj = this.getScene().meshes[index];
+                    if (obj.parent === this) {
+                        obj.parent = null;
+                        obj.computeWorldMatrix(true);
+                    }
+                }
+            }
+
+            this._isDisposed = true;
+
+            // Callback
+            if (this.onDispose) {
+                this.onDispose();
+            }
+        };
+        AbstractMesh._BILLBOARDMODE_NONE = 0;
+        AbstractMesh._BILLBOARDMODE_X = 1;
+        AbstractMesh._BILLBOARDMODE_Y = 2;
+        AbstractMesh._BILLBOARDMODE_Z = 4;
+        AbstractMesh._BILLBOARDMODE_ALL = 7;
+        return AbstractMesh;
+    })(BABYLON.Node);
+    BABYLON.AbstractMesh = AbstractMesh;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.abstractMesh.js.map

+ 673 - 0
Babylon/Mesh/babylon.abstractMesh.ts

@@ -0,0 +1,673 @@
+module BABYLON {
+    export class AbstractMesh extends Node implements IDisposable {
+        // Statics
+        private static _BILLBOARDMODE_NONE = 0;
+        private static _BILLBOARDMODE_X = 1;
+        private static _BILLBOARDMODE_Y = 2;
+        private static _BILLBOARDMODE_Z = 4;
+        private static _BILLBOARDMODE_ALL = 7;
+
+        public static get BILLBOARDMODE_NONE(): number {
+            return AbstractMesh._BILLBOARDMODE_NONE;
+        }
+
+        public static get BILLBOARDMODE_X(): number {
+            return AbstractMesh._BILLBOARDMODE_X;
+        }
+
+        public static get BILLBOARDMODE_Y(): number {
+            return AbstractMesh._BILLBOARDMODE_Y;
+        }
+
+        public static get BILLBOARDMODE_Z(): number {
+            return AbstractMesh._BILLBOARDMODE_Z;
+        }
+
+        public static get BILLBOARDMODE_ALL(): number {
+            return AbstractMesh._BILLBOARDMODE_ALL;
+        }
+
+        // Properties
+        public position = new BABYLON.Vector3(0, 0, 0);
+        public rotation = new BABYLON.Vector3(0, 0, 0);
+        public rotationQuaternion: Quaternion;
+        public scaling = new BABYLON.Vector3(1, 1, 1);
+        public billboardMode = BABYLON.AbstractMesh.BILLBOARDMODE_NONE;
+        public visibility = 1.0;
+        public infiniteDistance = false;
+        public isVisible = true;
+        public isPickable = true;
+        public showBoundingBox = false;
+        public onDispose = null;
+        public checkCollisions = false;
+        public skeleton: Skeleton;
+        public renderingGroupId = 0;
+        public material: Material;
+        public receiveShadows = false;
+        public actionManager: ActionManager;
+
+        // Physics
+        public _physicImpostor = PhysicsEngine.NoImpostor;
+        public _physicsMass: number;
+        public _physicsFriction: number;
+        public _physicRestitution: number;
+
+        // Cache
+        private _localScaling = BABYLON.Matrix.Zero();
+        private _localRotation = BABYLON.Matrix.Zero();
+        private _localTranslation = BABYLON.Matrix.Zero();
+        private _localBillboard = BABYLON.Matrix.Zero();
+        private _localPivotScaling = BABYLON.Matrix.Zero();
+        private _localPivotScalingRotation = BABYLON.Matrix.Zero();
+        private _localWorld = BABYLON.Matrix.Zero();
+        private _worldMatrix = BABYLON.Matrix.Zero();
+        private _rotateYByPI = BABYLON.Matrix.RotationY(Math.PI);
+        private _absolutePosition = BABYLON.Vector3.Zero();
+        private _collisionsTransformMatrix = BABYLON.Matrix.Zero();
+        private _collisionsScalingMatrix = BABYLON.Matrix.Zero();
+        public _positions: Vector3[];
+        private _isDirty = false;
+
+        public _boundingInfo: BoundingInfo;
+        private _pivotMatrix = BABYLON.Matrix.Identity();
+        public _isDisposed = false;
+        public _renderId = 0;
+
+        public subMeshes: SubMesh[];
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+
+            scene.meshes.push(this);
+        }
+
+        // Methods
+        public getTotalVertices(): number {
+            return 0;
+        }
+
+        public getIndices(): number[] {
+            return null;
+        }
+
+        public getVerticesData(kind: string): number[] {
+            return null;
+        }
+
+        public isVerticesDataPresent(kind: string): boolean {
+            return false;
+        }
+
+        public getBoundingInfo(): BoundingInfo {
+            return this._boundingInfo;
+        }
+
+        public _activate(renderId: number): void {
+            this._renderId = renderId;
+        }
+
+        public getWorldMatrix(): Matrix {
+            if (this._currentRenderId !== this.getScene().getRenderId()) {
+                this.computeWorldMatrix();
+            }
+            return this._worldMatrix;
+        }
+
+        public get worldMatrixFromCache(): Matrix {
+            return this._worldMatrix;
+        }
+
+        public get absolutePosition(): Vector3 {
+            return this._absolutePosition;
+        }
+
+        public rotate(axis: Vector3, amount: number, space: Space): void {
+            if (!this.rotationQuaternion) {
+                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
+                this.rotation = BABYLON.Vector3.Zero();
+            }
+
+            if (!space || space == BABYLON.Space.LOCAL) {
+                var rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
+                this.rotationQuaternion = this.rotationQuaternion.multiply(rotationQuaternion);
+            }
+            else {
+                if (this.parent) {
+                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
+                    invertParentWorldMatrix.invert();
+
+                    axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
+                }
+                rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
+                this.rotationQuaternion = rotationQuaternion.multiply(this.rotationQuaternion);
+            }
+        }
+
+        public translate(axis: Vector3, distance: number, space: Space): void {
+            var displacementVector = axis.scale(distance);
+
+            if (!space || space == BABYLON.Space.LOCAL) {
+                var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
+                this.setPositionWithLocalVector(tempV3);
+            }
+            else {
+                this.setAbsolutePosition(this.getAbsolutePosition().add(displacementVector));
+            }
+        }
+
+        public getAbsolutePosition(): Vector3 {
+            this.computeWorldMatrix();
+            return this._absolutePosition;
+        }
+
+        public setAbsolutePosition(absolutePosition: Vector3): void {
+            if (!absolutePosition) {
+                return;
+            }
+
+            var absolutePositionX;
+            var absolutePositionY;
+            var absolutePositionZ;
+
+            if (absolutePosition.x === undefined) {
+                if (arguments.length < 3) {
+                    return;
+                }
+                absolutePositionX = arguments[0];
+                absolutePositionY = arguments[1];
+                absolutePositionZ = arguments[2];
+            }
+            else {
+                absolutePositionX = absolutePosition.x;
+                absolutePositionY = absolutePosition.y;
+                absolutePositionZ = absolutePosition.z;
+            }
+
+            if (this.parent) {
+                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
+                invertParentWorldMatrix.invert();
+
+                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
+
+                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+            } else {
+                this.position.x = absolutePositionX;
+                this.position.y = absolutePositionY;
+                this.position.z = absolutePositionZ;
+            }
+        }
+
+        public setPivotMatrix(matrix: Matrix): void {
+            this._pivotMatrix = matrix;
+            this._cache.pivotMatrixUpdated = true;
+        }
+
+        public getPivotMatrix(): Matrix {
+            return this._pivotMatrix;
+        }
+
+        public _isSynchronized(): boolean {
+            if (this._isDirty) {
+                return false;
+            }
+
+            if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE)
+                return false;
+
+            if (this._cache.pivotMatrixUpdated) {
+                return false;
+            }
+
+            if (this.infiniteDistance) {
+                return false;
+            }
+
+            if (!this._cache.position.equals(this.position))
+                return false;
+
+            if (this.rotationQuaternion) {
+                if (!this._cache.rotationQuaternion.equals(this.rotationQuaternion))
+                    return false;
+            } else {
+                if (!this._cache.rotation.equals(this.rotation))
+                    return false;
+            }
+
+            if (!this._cache.scaling.equals(this.scaling))
+                return false;
+
+            return true;
+        }
+
+        public _initCache() {
+            super._initCache();
+
+            this._cache.localMatrixUpdated = false;
+            this._cache.position = BABYLON.Vector3.Zero();
+            this._cache.scaling = BABYLON.Vector3.Zero();
+            this._cache.rotation = BABYLON.Vector3.Zero();
+            this._cache.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 0);
+        }
+
+        public markAsDirty(property: string): void {
+            if (property === "rotation") {
+                this.rotationQuaternion = null;
+            }
+            this._currentRenderId = Number.MAX_VALUE;
+            this._isDirty = true;
+        }
+
+        public _updateBoundingInfo(): void {
+            this._boundingInfo = this._boundingInfo || new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition);
+
+            this._boundingInfo._update(this.worldMatrixFromCache);
+
+            if (!this.subMeshes) {
+                return;
+            }
+
+            for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
+                var subMesh = this.subMeshes[subIndex];
+
+                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+            }
+        }
+
+        public computeWorldMatrix(force?: boolean): Matrix {
+            if (!force && (this._currentRenderId == this.getScene().getRenderId() || this.isSynchronized(true))) {
+                return this._worldMatrix;
+            }
+
+            this._cache.position.copyFrom(this.position);
+            this._cache.scaling.copyFrom(this.scaling);
+            this._cache.pivotMatrixUpdated = false;
+            this._currentRenderId = this.getScene().getRenderId();
+            this._isDirty = false;
+
+            // Scaling
+            BABYLON.Matrix.ScalingToRef(this.scaling.x, this.scaling.y, this.scaling.z, this._localScaling);
+
+            // Rotation
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.toRotationMatrix(this._localRotation);
+                this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
+            } else {
+                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
+                this._cache.rotation.copyFrom(this.rotation);
+            }
+
+            // Translation
+            if (this.infiniteDistance && !this.parent) {
+                var camera = this.getScene().activeCamera;
+                var cameraWorldMatrix = camera.getWorldMatrix();
+
+                var cameraGlobalPosition = new BABYLON.Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
+
+                BABYLON.Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y, this.position.z + cameraGlobalPosition.z, this._localTranslation);
+            } else {
+                BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
+            }
+
+            // Composing transformations
+            this._pivotMatrix.multiplyToRef(this._localScaling, this._localPivotScaling);
+            this._localPivotScaling.multiplyToRef(this._localRotation, this._localPivotScalingRotation);
+
+            // Billboarding
+            if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE) {
+                var localPosition = this.position.clone();
+                var zero = this.getScene().activeCamera.position.clone();
+
+                if (this.parent && (<any>this.parent).position) {
+                    localPosition.addInPlace((<any>this.parent).position);
+                    BABYLON.Matrix.TranslationToRef(localPosition.x, localPosition.y, localPosition.z, this._localTranslation);
+                }
+
+                if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) === AbstractMesh.BILLBOARDMODE_ALL) {
+                    zero = this.getScene().activeCamera.position;
+                } else {
+                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_X)
+                        zero.x = localPosition.x + BABYLON.Engine.Epsilon;
+                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_Y)
+                        zero.y = localPosition.y + 0.001;
+                    if (this.billboardMode & BABYLON.AbstractMesh.BILLBOARDMODE_Z)
+                        zero.z = localPosition.z + 0.001;
+                }
+
+                BABYLON.Matrix.LookAtLHToRef(localPosition, zero, BABYLON.Vector3.Up(), this._localBillboard);
+                this._localBillboard.m[12] = this._localBillboard.m[13] = this._localBillboard.m[14] = 0;
+
+                this._localBillboard.invert();
+
+                this._localPivotScalingRotation.multiplyToRef(this._localBillboard, this._localWorld);
+                this._rotateYByPI.multiplyToRef(this._localWorld, this._localPivotScalingRotation);
+            }
+
+            // Local world
+            this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
+
+            // Parent
+            if (this.parent && this.parent.getWorldMatrix && this.billboardMode === BABYLON.AbstractMesh.BILLBOARDMODE_NONE) {
+                this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
+            } else {
+                this._worldMatrix.copyFrom(this._localWorld);
+            }
+
+            // Bounding info
+            this._updateBoundingInfo();
+
+            // Absolute position
+            this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
+
+            return this._worldMatrix;
+        }
+
+        public setPositionWithLocalVector(vector3: Vector3): void {
+            this.computeWorldMatrix();
+
+            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localWorld);
+        }
+
+        public getPositionExpressedInLocalSpace(): Vector3 {
+            this.computeWorldMatrix();
+            var invLocalWorldMatrix = this._localWorld.clone();
+            invLocalWorldMatrix.invert();
+
+            return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
+        }
+
+        public locallyTranslate(vector3: Vector3): void {
+            this.computeWorldMatrix();
+
+            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localWorld);
+        }
+
+        public lookAt(targetPoint: Vector3, yawCor: number, pitchCor: number, rollCor: number): void {
+            /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
+            /// <param name="targetPoint" type="BABYLON.Vector3">The position (must be in same space as current mesh) to look at</param>
+            /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
+            /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
+            /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
+            /// <returns>Mesh oriented towards targetMesh</returns>
+
+            yawCor = yawCor || 0; // default to zero if undefined 
+            pitchCor = pitchCor || 0;
+            rollCor = rollCor || 0;
+
+            var dv = targetPoint.subtract(this.position);
+            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
+            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
+            var pitch = Math.atan2(dv.y, len);
+            this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(yaw + yawCor, pitch + pitchCor, rollCor);
+        }
+
+        public isInFrustum(frustumPlanes: Plane[]): boolean {
+            if (!this._boundingInfo.isInFrustum(frustumPlanes)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        public intersectsMesh(mesh: Mesh, precise?: boolean): boolean {
+            if (!this._boundingInfo || !mesh._boundingInfo) {
+                return false;
+            }
+
+            return this._boundingInfo.intersects(mesh._boundingInfo, precise);
+        }
+
+        public intersectsPoint(point: Vector3): boolean {
+            if (!this._boundingInfo) {
+                return false;
+            }
+
+            return this._boundingInfo.intersectsPoint(point);
+        }
+
+        // Physics
+        public setPhysicsState(impostor?: any, options?: PhysicsBodyCreationOptions): void {
+            var physicsEngine = this.getScene().getPhysicsEngine();
+
+            if (!physicsEngine) {
+                return;
+            }
+
+            if (impostor.impostor) {
+                // Old API
+                options = impostor;
+                impostor = impostor.impostor;
+            }
+
+            impostor = impostor || PhysicsEngine.NoImpostor;
+
+            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
+                physicsEngine._unregisterMesh(this);
+                return;
+            }
+
+            options.mass = options.mass || 0;
+            options.friction = options.friction || 0.2;
+            options.restitution = options.restitution || 0.9;
+
+            this._physicImpostor = impostor;
+            this._physicsMass = options.mass;
+            this._physicsFriction = options.friction;
+            this._physicRestitution = options.restitution;
+
+
+            physicsEngine._registerMesh(this, impostor, options);
+        }
+
+        public getPhysicsImpostor(): number {
+            if (!this._physicImpostor) {
+                return BABYLON.PhysicsEngine.NoImpostor;
+            }
+
+            return this._physicImpostor;
+        }
+
+        public getPhysicsMass(): number {
+            if (!this._physicsMass) {
+                return 0;
+            }
+
+            return this._physicsMass;
+        }
+
+        public getPhysicsFriction(): number {
+            if (!this._physicsFriction) {
+                return 0;
+            }
+
+            return this._physicsFriction;
+        }
+
+        public getPhysicsRestitution(): number {
+            if (!this._physicRestitution) {
+                return 0;
+            }
+
+            return this._physicRestitution;
+        }
+
+        public applyImpulse(force: Vector3, contactPoint: Vector3): void {
+            if (!this._physicImpostor) {
+                return;
+            }
+
+            this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
+        }
+
+        public setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3): void {
+            if (!this._physicImpostor) {
+                return;
+            }
+
+            this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2);
+        }
+
+        // Collisions
+        public _collideForSubMesh(subMesh: SubMesh, transformMatrix: Matrix, collider: Collider): void {
+            this._generatePointsArray();
+            // Transformation
+            if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix.equals(transformMatrix)) {
+                subMesh._lastColliderTransformMatrix = transformMatrix.clone();
+                subMesh._lastColliderWorldVertices = [];
+                subMesh._trianglePlanes = [];
+                var start = subMesh.verticesStart;
+                var end = (subMesh.verticesStart + subMesh.verticesCount);
+                for (var i = start; i < end; i++) {
+                    subMesh._lastColliderWorldVertices.push(BABYLON.Vector3.TransformCoordinates(this._positions[i], transformMatrix));
+                }
+            }
+            // Collide
+            collider._collide(subMesh, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
+        }
+
+        public _processCollisionsForSubModels(collider: Collider, transformMatrix: Matrix): void {
+            for (var index = 0; index < this.subMeshes.length; index++) {
+                var subMesh = this.subMeshes[index];
+
+                // Bounding test
+                if (this.subMeshes.length > 1 && !subMesh._checkCollision(collider))
+                    continue;
+
+                this._collideForSubMesh(subMesh, transformMatrix, collider);
+            }
+        }
+
+        public _checkCollision(collider: Collider): void {
+            // Bounding box test
+            if (!this._boundingInfo._checkCollision(collider))
+                return;
+
+            // Transformation matrix
+            BABYLON.Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
+            this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
+
+            this._processCollisionsForSubModels(collider, this._collisionsTransformMatrix);
+        }
+
+        // Picking
+        public _generatePointsArray(): boolean {
+            return false;
+        }
+
+        public intersects(ray: Ray, fastCheck?: boolean): PickingInfo {
+            var pickingInfo = new BABYLON.PickingInfo();
+
+            if (!this.subMeshes || !this._boundingInfo || !ray.intersectsSphere(this._boundingInfo.boundingSphere) || !ray.intersectsBox(this._boundingInfo.boundingBox)) {
+                return pickingInfo;
+            }
+
+            if (!this._generatePointsArray()) {
+                return pickingInfo;
+            }
+
+            var intersectInfo: IntersectionInfo = null;
+
+            for (var index = 0; index < this.subMeshes.length; index++) {
+                var subMesh = this.subMeshes[index];
+
+                // Bounding test
+                if (this.subMeshes.length > 1 && !subMesh.canIntersects(ray))
+                    continue;
+
+                var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);
+
+                if (currentIntersectInfo) {
+                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
+                        intersectInfo = currentIntersectInfo;
+
+                        if (fastCheck) {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (intersectInfo) {
+                // Get picked point
+                var world = this.getWorldMatrix();
+                var worldOrigin = BABYLON.Vector3.TransformCoordinates(ray.origin, world);
+                var direction = ray.direction.clone();
+                direction.normalize();
+                direction = direction.scale(intersectInfo.distance);
+                var worldDirection = BABYLON.Vector3.TransformNormal(direction, world);
+
+                var pickedPoint = worldOrigin.add(worldDirection);
+
+                // Return result
+                pickingInfo.hit = true;
+                pickingInfo.distance = BABYLON.Vector3.Distance(worldOrigin, pickedPoint);
+                pickingInfo.pickedPoint = pickedPoint;
+                pickingInfo.pickedMesh = this;
+                pickingInfo.bu = intersectInfo.bu;
+                pickingInfo.bv = intersectInfo.bv;
+                pickingInfo.faceId = intersectInfo.faceId;
+                return pickingInfo;
+            }
+
+            return pickingInfo;
+        }
+
+        public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): AbstractMesh {
+            return null;
+        }
+
+        public releaseSubMeshes(): void {
+            if (this.subMeshes) {
+                while (this.subMeshes.length) {
+                    this.subMeshes[0].dispose();
+                }
+            }
+        }
+
+        public dispose(doNotRecurse?: boolean): void {
+            // Physics
+            if (this.getPhysicsImpostor() != PhysicsEngine.NoImpostor) {
+                this.setPhysicsState(PhysicsEngine.NoImpostor);
+            }
+
+            // SubMeshes
+            this.releaseSubMeshes();
+
+            // Remove from scene
+            var index = this.getScene().meshes.indexOf(this);
+            this.getScene().meshes.splice(index, 1);
+
+            if (!doNotRecurse) {
+                // Particles
+                for (index = 0; index < this.getScene().particleSystems.length; index++) {
+                    if (this.getScene().particleSystems[index].emitter == this) {
+                        this.getScene().particleSystems[index].dispose();
+                        index--;
+                    }
+                }
+
+                // Children
+                var objects = this.getScene().meshes.slice(0);
+                for (index = 0; index < objects.length; index++) {
+                    if (objects[index].parent == this) {
+                        objects[index].dispose();
+                    }
+                }
+            } else {
+                for (index = 0; index < this.getScene().meshes.length; index++) {
+                    var obj = this.getScene().meshes[index];
+                    if (obj.parent === this) {
+                        obj.parent = null;
+                        obj.computeWorldMatrix(true);
+                    }
+                }
+            }
+
+            this._isDisposed = true;
+
+            // Callback
+            if (this.onDispose) {
+                this.onDispose();
+            }
+        }
+    }
+}

+ 110 - 633
Babylon/Mesh/babylon.mesh.js

@@ -11,172 +11,12 @@ var BABYLON;
         function Mesh(name, scene) {
             _super.call(this, name, scene);
             // Members
-            this.position = new BABYLON.Vector3(0, 0, 0);
-            this.rotation = new BABYLON.Vector3(0, 0, 0);
-            this.rotationQuaternion = null;
-            this.scaling = new BABYLON.Vector3(1, 1, 1);
             this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
-            this.material = null;
-            this.isVisible = true;
-            this.isPickable = true;
-            this.visibility = 1.0;
-            this.billboardMode = BABYLON.Mesh.BILLBOARDMODE_NONE;
-            this.checkCollisions = false;
-            this.receiveShadows = false;
-            this._isDisposed = false;
-            this.onDispose = null;
-            this.skeleton = null;
-            this.renderingGroupId = 0;
-            this.infiniteDistance = false;
-            this.showBoundingBox = false;
-            // Cache
-            this._positions = null;
-            this._localScaling = BABYLON.Matrix.Zero();
-            this._localRotation = BABYLON.Matrix.Zero();
-            this._localTranslation = BABYLON.Matrix.Zero();
-            this._localBillboard = BABYLON.Matrix.Zero();
-            this._localPivotScaling = BABYLON.Matrix.Zero();
-            this._localPivotScalingRotation = BABYLON.Matrix.Zero();
-            this._localWorld = BABYLON.Matrix.Zero();
-            this._worldMatrix = BABYLON.Matrix.Zero();
-            this._rotateYByPI = BABYLON.Matrix.RotationY(Math.PI);
-            this._collisionsTransformMatrix = BABYLON.Matrix.Zero();
-            this._collisionsScalingMatrix = BABYLON.Matrix.Zero();
-            this._absolutePosition = BABYLON.Vector3.Zero();
-            this._isDirty = false;
-            // Physics
-            this._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
-            this._pivotMatrix = BABYLON.Matrix.Identity();
-            this._renderId = 0;
+            this.instances = new Array();
             this._onBeforeRenderCallbacks = [];
-            this._animationStarted = false;
-
-            scene.meshes.push(this);
+            this._visibleInstances = new BABYLON.SmartArray(32);
+            this._renderIdForInstances = -1;
         }
-        Object.defineProperty(Mesh, "BILLBOARDMODE_NONE", {
-            get: function () {
-                return Mesh._BILLBOARDMODE_NONE;
-            },
-            enumerable: true,
-            configurable: true
-        });
-
-        Object.defineProperty(Mesh, "BILLBOARDMODE_X", {
-            get: function () {
-                return Mesh._BILLBOARDMODE_X;
-            },
-            enumerable: true,
-            configurable: true
-        });
-
-        Object.defineProperty(Mesh, "BILLBOARDMODE_Y", {
-            get: function () {
-                return Mesh._BILLBOARDMODE_Y;
-            },
-            enumerable: true,
-            configurable: true
-        });
-
-        Object.defineProperty(Mesh, "BILLBOARDMODE_Z", {
-            get: function () {
-                return Mesh._BILLBOARDMODE_Z;
-            },
-            enumerable: true,
-            configurable: true
-        });
-
-        Object.defineProperty(Mesh, "BILLBOARDMODE_ALL", {
-            get: function () {
-                return Mesh._BILLBOARDMODE_ALL;
-            },
-            enumerable: true,
-            configurable: true
-        });
-
-        Mesh.prototype.getBoundingInfo = function () {
-            return this._boundingInfo;
-        };
-
-        Mesh.prototype.getWorldMatrix = function () {
-            if (this._currentRenderId !== this.getScene().getRenderId()) {
-                this.computeWorldMatrix();
-            }
-            return this._worldMatrix;
-        };
-
-        Mesh.prototype.rotate = function (axis, amount, space) {
-            if (!this.rotationQuaternion) {
-                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = BABYLON.Vector3.Zero();
-            }
-
-            if (!space || space == 0 /* LOCAL */) {
-                var rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
-                this.rotationQuaternion = this.rotationQuaternion.multiply(rotationQuaternion);
-            } else {
-                if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
-
-                    axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
-                }
-                rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
-                this.rotationQuaternion = rotationQuaternion.multiply(this.rotationQuaternion);
-            }
-        };
-
-        Mesh.prototype.translate = function (axis, distance, space) {
-            var displacementVector = axis.scale(distance);
-
-            if (!space || space == 0 /* LOCAL */) {
-                var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
-                this.setPositionWithLocalVector(tempV3);
-            } else {
-                this.setAbsolutePosition(this.getAbsolutePosition().add(displacementVector));
-            }
-        };
-
-        Mesh.prototype.getAbsolutePosition = function () {
-            this.computeWorldMatrix();
-            return this._absolutePosition;
-        };
-
-        Mesh.prototype.setAbsolutePosition = function (absolutePosition) {
-            if (!absolutePosition) {
-                return;
-            }
-
-            var absolutePositionX;
-            var absolutePositionY;
-            var absolutePositionZ;
-
-            if (absolutePosition.x === undefined) {
-                if (arguments.length < 3) {
-                    return;
-                }
-                absolutePositionX = arguments[0];
-                absolutePositionY = arguments[1];
-                absolutePositionZ = arguments[2];
-            } else {
-                absolutePositionX = absolutePosition.x;
-                absolutePositionY = absolutePosition.y;
-                absolutePositionZ = absolutePosition.z;
-            }
-
-            if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-
-                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-
-                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
-            } else {
-                this.position.x = absolutePositionX;
-                this.position.y = absolutePositionY;
-                this.position.z = absolutePositionZ;
-            }
-        };
-
         Mesh.prototype.getTotalVertices = function () {
             if (!this._geometry) {
                 return 0;
@@ -235,54 +75,12 @@ var BABYLON;
             return this._geometry.getIndices();
         };
 
-        Mesh.prototype.setPivotMatrix = function (matrix) {
-            this._pivotMatrix = matrix;
-            this._cache.pivotMatrixUpdated = true;
-        };
-
-        Mesh.prototype.getPivotMatrix = function () {
-            return this._pivotMatrix;
-        };
-
-        Mesh.prototype._isSynchronized = function () {
-            if (this._isDirty) {
-                return false;
-            }
-
-            if (this.billboardMode !== Mesh.BILLBOARDMODE_NONE)
-                return false;
-
-            if (this._cache.pivotMatrixUpdated) {
-                return false;
-            }
-
-            if (this.infiniteDistance) {
+        Mesh.prototype.isReady = function () {
+            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
                 return false;
             }
 
-            if (!this._cache.position.equals(this.position))
-                return false;
-
-            if (this.rotationQuaternion) {
-                if (!this._cache.rotationQuaternion.equals(this.rotationQuaternion))
-                    return false;
-            } else {
-                if (!this._cache.rotation.equals(this.rotation))
-                    return false;
-            }
-
-            if (!this._cache.scaling.equals(this.scaling))
-                return false;
-
-            return true;
-        };
-
-        Mesh.prototype.isReady = function () {
-            return this._isReady;
-        };
-
-        Mesh.prototype.isAnimated = function () {
-            return this._animationStarted;
+            return _super.prototype.isReady.call(this);
         };
 
         Mesh.prototype.isDisposed = function () {
@@ -290,22 +88,9 @@ var BABYLON;
         };
 
         // Methods
-        Mesh.prototype._initCache = function () {
-            _super.prototype._initCache.call(this);
-
-            this._cache.localMatrixUpdated = false;
-            this._cache.position = BABYLON.Vector3.Zero();
-            this._cache.scaling = BABYLON.Vector3.Zero();
-            this._cache.rotation = BABYLON.Vector3.Zero();
-            this._cache.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 0);
-        };
-
-        Mesh.prototype.markAsDirty = function (property) {
-            if (property === "rotation") {
-                this.rotationQuaternion = null;
-            }
-            this._currentRenderId = Number.MAX_VALUE;
-            this._isDirty = true;
+        Mesh.prototype._activate = function (renderId) {
+            this._visibleInstances.reset();
+            _super.prototype._activate.call(this, renderId);
         };
 
         Mesh.prototype.refreshBoundingInfo = function () {
@@ -325,116 +110,13 @@ var BABYLON;
             this._updateBoundingInfo();
         };
 
-        Mesh.prototype._updateBoundingInfo = function () {
-            this._boundingInfo = this._boundingInfo || new BABYLON.BoundingInfo(this._absolutePosition, this._absolutePosition);
-
-            this._boundingInfo._update(this._worldMatrix);
-
-            if (!this.subMeshes) {
-                return;
-            }
-
-            for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
-                var subMesh = this.subMeshes[subIndex];
-
-                subMesh.updateBoundingInfo(this._worldMatrix);
-            }
-        };
-
-        Mesh.prototype.computeWorldMatrix = function (force) {
-            if (!force && (this._currentRenderId == this.getScene().getRenderId() || this.isSynchronized(true))) {
-                return this._worldMatrix;
-            }
-
-            this._cache.position.copyFrom(this.position);
-            this._cache.scaling.copyFrom(this.scaling);
-            this._cache.pivotMatrixUpdated = false;
-            this._currentRenderId = this.getScene().getRenderId();
-            this._isDirty = false;
-
-            // Scaling
-            BABYLON.Matrix.ScalingToRef(this.scaling.x, this.scaling.y, this.scaling.z, this._localScaling);
-
-            // Rotation
-            if (this.rotationQuaternion) {
-                this.rotationQuaternion.toRotationMatrix(this._localRotation);
-                this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
-            } else {
-                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
-                this._cache.rotation.copyFrom(this.rotation);
-            }
-
-            // Translation
-            if (this.infiniteDistance && !this.parent) {
-                var camera = this.getScene().activeCamera;
-                var cameraWorldMatrix = camera.getWorldMatrix();
-
-                var cameraGlobalPosition = new BABYLON.Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
-
-                BABYLON.Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y, this.position.z + cameraGlobalPosition.z, this._localTranslation);
-            } else {
-                BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
-            }
-
-            // Composing transformations
-            this._pivotMatrix.multiplyToRef(this._localScaling, this._localPivotScaling);
-            this._localPivotScaling.multiplyToRef(this._localRotation, this._localPivotScalingRotation);
-
-            // Billboarding
-            if (this.billboardMode !== Mesh.BILLBOARDMODE_NONE) {
-                var localPosition = this.position.clone();
-                var zero = this.getScene().activeCamera.position.clone();
-
-                if (this.parent && this.parent.position) {
-                    localPosition.addInPlace(this.parent.position);
-                    BABYLON.Matrix.TranslationToRef(localPosition.x, localPosition.y, localPosition.z, this._localTranslation);
-                }
-
-                if ((this.billboardMode & Mesh.BILLBOARDMODE_ALL) === Mesh.BILLBOARDMODE_ALL) {
-                    zero = this.getScene().activeCamera.position;
-                } else {
-                    if (this.billboardMode & BABYLON.Mesh.BILLBOARDMODE_X)
-                        zero.x = localPosition.x + BABYLON.Engine.Epsilon;
-                    if (this.billboardMode & BABYLON.Mesh.BILLBOARDMODE_Y)
-                        zero.y = localPosition.y + 0.001;
-                    if (this.billboardMode & BABYLON.Mesh.BILLBOARDMODE_Z)
-                        zero.z = localPosition.z + 0.001;
-                }
-
-                BABYLON.Matrix.LookAtLHToRef(localPosition, zero, BABYLON.Vector3.Up(), this._localBillboard);
-                this._localBillboard.m[12] = this._localBillboard.m[13] = this._localBillboard.m[14] = 0;
-
-                this._localBillboard.invert();
-
-                this._localPivotScalingRotation.multiplyToRef(this._localBillboard, this._localWorld);
-                this._rotateYByPI.multiplyToRef(this._localWorld, this._localPivotScalingRotation);
-            }
-
-            // Local world
-            this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
-
-            // Parent
-            if (this.parent && this.parent.getWorldMatrix && this.billboardMode === BABYLON.Mesh.BILLBOARDMODE_NONE) {
-                this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
-            } else {
-                this._worldMatrix.copyFrom(this._localWorld);
-            }
-
-            // Bounding info
-            this._updateBoundingInfo();
-
-            // Absolute position
-            this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
-
-            return this._worldMatrix;
-        };
-
         Mesh.prototype._createGlobalSubMesh = function () {
             var totalVertices = this.getTotalVertices();
             if (!totalVertices || !this.getIndices()) {
                 return null;
             }
 
+            this.releaseSubMeshes();
             this.subMeshes = [];
             return new BABYLON.SubMesh(0, 0, totalVertices, 0, this.getTotalIndices(), this);
         };
@@ -448,12 +130,15 @@ var BABYLON;
             var subdivisionSize = totalIndices / count;
             var offset = 0;
 
+            this.releaseSubMeshes();
             this.subMeshes = [];
             for (var index = 0; index < count; index++) {
                 BABYLON.SubMesh.CreateFromIndices(0, offset, Math.min(subdivisionSize, totalIndices - offset), this);
 
                 offset += subdivisionSize;
             }
+
+            this.synchronizeInstances();
         };
 
         Mesh.prototype.setVerticesData = function (data, kind, updatable) {
@@ -502,30 +187,37 @@ var BABYLON;
             }
         };
 
-        // ANY
-        Mesh.prototype.bindAndDraw = function (subMesh, effect, wireframe) {
-            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
-                return;
-            }
-
+        Mesh.prototype._bind = function (subMesh, effect, wireframe) {
             var engine = this.getScene().getEngine();
 
             // Wireframe
             var indexToBind = this._geometry.getIndexBuffer();
-            var useTriangles = true;
 
             if (wireframe) {
                 indexToBind = subMesh.getLinesIndexBuffer(this.getIndices(), engine);
-                useTriangles = false;
             }
 
             // VBOs
             engine.bindMultiBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
+        };
+
+        Mesh.prototype._draw = function (subMesh, useTriangles) {
+            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
+                return;
+            }
+
+            var engine = this.getScene().getEngine();
 
             // Draw order
             engine.draw(useTriangles, useTriangles ? subMesh.indexStart : 0, useTriangles ? subMesh.indexCount : subMesh.linesIndexCount);
         };
 
+        Mesh.prototype.bindAndDraw = function (subMesh, effect, wireframe) {
+            this._bind(subMesh, effect, wireframe);
+
+            this._draw(subMesh, !wireframe);
+        };
+
         Mesh.prototype.registerBeforeRender = function (func) {
             this._onBeforeRenderCallbacks.push(func);
         };
@@ -539,6 +231,22 @@ var BABYLON;
         };
 
         Mesh.prototype.render = function (subMesh) {
+            var renderSelf = true;
+            var scene = this.getScene();
+
+            // Managing instances
+            if (this._visibleInstances.length) {
+                if (this._renderIdForInstances === scene.getRenderId()) {
+                    return;
+                }
+
+                if (scene.getRenderId() !== this._renderId) {
+                    renderSelf = false;
+                }
+            }
+            this._renderIdForInstances = scene.getRenderId();
+
+            // Checking geometry state
             if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
                 return;
             }
@@ -547,9 +255,6 @@ var BABYLON;
                 this._onBeforeRenderCallbacks[callbackIndex]();
             }
 
-            // World
-            var world = this.getWorldMatrix();
-
             // Material
             var effectiveMaterial = subMesh.getMaterial();
 
@@ -557,12 +262,33 @@ var BABYLON;
                 return;
             }
 
+            var engine = scene.getEngine();
+            var effect = effectiveMaterial.getEffect();
+
+            // Bind
+            var wireFrame = engine.forceWireframe || effectiveMaterial.wireframe;
+            this._bind(subMesh, effect, wireFrame);
             effectiveMaterial._preBind();
-            effectiveMaterial.bind(world, this);
 
-            // Bind and draw
-            var engine = this.getScene().getEngine();
-            this.bindAndDraw(subMesh, effectiveMaterial.getEffect(), engine.forceWireframe || effectiveMaterial.wireframe);
+            if (renderSelf) {
+                // World
+                var world = this.getWorldMatrix();
+                effectiveMaterial.bind(world, this);
+
+                // Draw
+                this._draw(subMesh, !wireFrame);
+            }
+
+            for (var instanceIndex = 0; instanceIndex < this._visibleInstances.length; instanceIndex++) {
+                var instance = this._visibleInstances.data[instanceIndex];
+
+                // World
+                world = instance.getWorldMatrix();
+                effectiveMaterial.bind(world, this);
+
+                // Draw
+                this._draw(subMesh, !wireFrame);
+            }
 
             // Unbind
             effectiveMaterial.unbind();
@@ -607,15 +333,8 @@ var BABYLON;
             return results;
         };
 
-        Mesh.prototype.isInFrustum = function (frustumPlanes) {
-            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
-                return false;
-            }
-
-            if (!this._boundingInfo.isInFrustum(frustumPlanes)) {
-                return false;
-            }
-
+        Mesh.prototype._checkDelayState = function () {
+            var _this = this;
             var that = this;
             var scene = this.getScene();
 
@@ -627,12 +346,24 @@ var BABYLON;
                 scene._addPendingData(that);
 
                 BABYLON.Tools.LoadFile(this.delayLoadingFile, function (data) {
-                    that._delayLoadingFunction(JSON.parse(data), that);
-                    that.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
-                    scene._removePendingData(that);
+                    _this._delayLoadingFunction(JSON.parse(data), _this);
+                    _this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
+                    scene._removePendingData(_this);
                 }, function () {
                 }, scene.database);
             }
+        };
+
+        Mesh.prototype.isInFrustum = function (frustumPlanes) {
+            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                return false;
+            }
+
+            if (!_super.prototype.isInFrustum.call(this, frustumPlanes)) {
+                return false;
+            }
+
+            this._checkDelayState();
 
             return true;
         };
@@ -667,26 +398,6 @@ var BABYLON;
         };
 
         // Geometry
-        Mesh.prototype.setPositionWithLocalVector = function (vector3) {
-            this.computeWorldMatrix();
-
-            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localWorld);
-        };
-
-        Mesh.prototype.getPositionExpressedInLocalSpace = function () {
-            this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
-
-            return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
-        };
-
-        Mesh.prototype.locallyTranslate = function (vector3) {
-            this.computeWorldMatrix();
-
-            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localWorld);
-        };
-
         Mesh.prototype.bakeTransformIntoVertices = function (transform) {
             // Position
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
@@ -716,24 +427,6 @@ var BABYLON;
             this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable());
         };
 
-        Mesh.prototype.lookAt = function (targetPoint, yawCor, pitchCor, rollCor) {
-            /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
-            /// <param name="targetPoint" type="BABYLON.Vector3">The position (must be in same space as current mesh) to look at</param>
-            /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
-            /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
-            /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
-            /// <returns>Mesh oriented towards targetMesh</returns>
-            yawCor = yawCor || 0; // default to zero if undefined
-            pitchCor = pitchCor || 0;
-            rollCor = rollCor || 0;
-
-            var dv = targetPoint.subtract(this.position);
-            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
-            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
-            var pitch = Math.atan2(dv.y, len);
-            this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(yaw + yawCor, pitch + pitchCor, rollCor);
-        };
-
         // Cache
         Mesh.prototype._resetPointsArrayCache = function () {
             this._positions = null;
@@ -741,131 +434,21 @@ var BABYLON;
 
         Mesh.prototype._generatePointsArray = function () {
             if (this._positions)
-                return;
+                return true;
 
             this._positions = [];
 
             var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            for (var index = 0; index < data.length; index += 3) {
-                this._positions.push(BABYLON.Vector3.FromArray(data, index));
-            }
-        };
-
-        // Collisions
-        Mesh.prototype._collideForSubMesh = function (subMesh, transformMatrix, collider) {
-            this._generatePointsArray();
-
-            // Transformation
-            if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix.equals(transformMatrix)) {
-                subMesh._lastColliderTransformMatrix = transformMatrix.clone();
-                subMesh._lastColliderWorldVertices = [];
-                subMesh._trianglePlanes = [];
-                var start = subMesh.verticesStart;
-                var end = (subMesh.verticesStart + subMesh.verticesCount);
-                for (var i = start; i < end; i++) {
-                    subMesh._lastColliderWorldVertices.push(BABYLON.Vector3.TransformCoordinates(this._positions[i], transformMatrix));
-                }
-            }
-
-            // Collide
-            collider._collide(subMesh, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
-        };
-
-        Mesh.prototype._processCollisionsForSubModels = function (collider, transformMatrix) {
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                var subMesh = this.subMeshes[index];
-
-                // Bounding test
-                if (this.subMeshes.length > 1 && !subMesh._checkCollision(collider))
-                    continue;
-
-                this._collideForSubMesh(subMesh, transformMatrix, collider);
-            }
-        };
-
-        Mesh.prototype._checkCollision = function (collider) {
-            // Bounding box test
-            if (!this._boundingInfo._checkCollision(collider))
-                return;
-
-            // Transformation matrix
-            BABYLON.Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
-            this._worldMatrix.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
-
-            this._processCollisionsForSubModels(collider, this._collisionsTransformMatrix);
-        };
 
-        Mesh.prototype.intersectsMesh = function (mesh, precise) {
-            if (!this._boundingInfo || !mesh._boundingInfo) {
+            if (!data) {
                 return false;
             }
 
-            return this._boundingInfo.intersects(mesh._boundingInfo, precise);
-        };
-
-        Mesh.prototype.intersectsPoint = function (point) {
-            if (!this._boundingInfo) {
-                return false;
-            }
-
-            return this._boundingInfo.intersectsPoint(point);
-        };
-
-        // Picking
-        Mesh.prototype.intersects = function (ray, fastCheck) {
-            var pickingInfo = new BABYLON.PickingInfo();
-
-            if (!this._boundingInfo || !ray.intersectsSphere(this._boundingInfo.boundingSphere) || !ray.intersectsBox(this._boundingInfo.boundingBox)) {
-                return pickingInfo;
-            }
-
-            this._generatePointsArray();
-
-            var intersectInfo = null;
-
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                var subMesh = this.subMeshes[index];
-
-                // Bounding test
-                if (this.subMeshes.length > 1 && !subMesh.canIntersects(ray))
-                    continue;
-
-                var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);
-
-                if (currentIntersectInfo) {
-                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
-                        intersectInfo = currentIntersectInfo;
-
-                        if (fastCheck) {
-                            break;
-                        }
-                    }
-                }
-            }
-
-            if (intersectInfo) {
-                // Get picked point
-                var world = this.getWorldMatrix();
-                var worldOrigin = BABYLON.Vector3.TransformCoordinates(ray.origin, world);
-                var direction = ray.direction.clone();
-                direction.normalize();
-                direction = direction.scale(intersectInfo.distance);
-                var worldDirection = BABYLON.Vector3.TransformNormal(direction, world);
-
-                var pickedPoint = worldOrigin.add(worldDirection);
-
-                // Return result
-                pickingInfo.hit = true;
-                pickingInfo.distance = BABYLON.Vector3.Distance(worldOrigin, pickedPoint);
-                pickingInfo.pickedPoint = pickedPoint;
-                pickingInfo.pickedMesh = this;
-                pickingInfo.bu = intersectInfo.bu;
-                pickingInfo.bv = intersectInfo.bv;
-                pickingInfo.faceId = intersectInfo.faceId;
-                return pickingInfo;
+            for (var index = 0; index < data.length; index += 3) {
+                this._positions.push(BABYLON.Vector3.FromArray(data, index));
             }
 
-            return pickingInfo;
+            return true;
         };
 
         // Clone
@@ -919,127 +502,11 @@ var BABYLON;
                 this._geometry.releaseForMesh(this);
             }
 
-            // Physics
-            if (this.getPhysicsImpostor() != BABYLON.PhysicsEngine.NoImpostor) {
-                this.setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
-            }
-
-            // Remove from scene
-            var index = this.getScene().meshes.indexOf(this);
-            this.getScene().meshes.splice(index, 1);
-
-            if (!doNotRecurse) {
-                for (index = 0; index < this.getScene().particleSystems.length; index++) {
-                    if (this.getScene().particleSystems[index].emitter == this) {
-                        this.getScene().particleSystems[index].dispose();
-                        index--;
-                    }
-                }
-
-                // Children
-                var objects = this.getScene().meshes.slice(0);
-                for (index = 0; index < objects.length; index++) {
-                    if (objects[index].parent == this) {
-                        objects[index].dispose();
-                    }
-                }
-            } else {
-                for (index = 0; index < this.getScene().meshes.length; index++) {
-                    var obj = this.getScene().meshes[index];
-                    if (obj.parent === this) {
-                        obj.parent = null;
-                        obj.computeWorldMatrix(true);
-                    }
-                }
-            }
-
-            this._isDisposed = true;
-
-            // Callback
-            if (this.onDispose) {
-                this.onDispose();
-            }
-        };
-
-        // Physics
-        Mesh.prototype.setPhysicsState = function (impostor, options) {
-            var physicsEngine = this.getScene().getPhysicsEngine();
-
-            if (!physicsEngine) {
-                return;
-            }
-
-            if (impostor.impostor) {
-                // Old API
-                options = impostor;
-                impostor = impostor.impostor;
-            }
-
-            impostor = impostor || BABYLON.PhysicsEngine.NoImpostor;
-
-            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
-                physicsEngine._unregisterMesh(this);
-                return;
-            }
-
-            options.mass = options.mass || 0;
-            options.friction = options.friction || 0.2;
-            options.restitution = options.restitution || 0.9;
-
-            this._physicImpostor = impostor;
-            this._physicsMass = options.mass;
-            this._physicsFriction = options.friction;
-            this._physicRestitution = options.restitution;
-
-            physicsEngine._registerMesh(this, impostor, options);
-        };
-
-        Mesh.prototype.getPhysicsImpostor = function () {
-            if (!this._physicImpostor) {
-                return BABYLON.PhysicsEngine.NoImpostor;
-            }
-
-            return this._physicImpostor;
-        };
-
-        Mesh.prototype.getPhysicsMass = function () {
-            if (!this._physicsMass) {
-                return 0;
+            while (this.instances.length) {
+                this.instances[0].dispose();
             }
 
-            return this._physicsMass;
-        };
-
-        Mesh.prototype.getPhysicsFriction = function () {
-            if (!this._physicsFriction) {
-                return 0;
-            }
-
-            return this._physicsFriction;
-        };
-
-        Mesh.prototype.getPhysicsRestitution = function () {
-            if (!this._physicRestitution) {
-                return 0;
-            }
-
-            return this._physicRestitution;
-        };
-
-        Mesh.prototype.applyImpulse = function (force, contactPoint) {
-            if (!this._physicImpostor) {
-                return;
-            }
-
-            this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
-        };
-
-        Mesh.prototype.setPhysicsLinkWith = function (otherMesh, pivot1, pivot2) {
-            if (!this._physicImpostor) {
-                return;
-            }
-
-            this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2);
+            _super.prototype.dispose.call(this, doNotRecurse);
         };
 
         // Geometric tools
@@ -1120,10 +587,25 @@ var BABYLON;
 
             // Updating submeshes
             this.subMeshes = [];
+            this.releaseSubMeshes();
             for (var submeshIndex = 0; submeshIndex < previousSubmeshes.length; submeshIndex++) {
                 var previousOne = previousSubmeshes[submeshIndex];
                 var subMesh = new BABYLON.SubMesh(previousOne.materialIndex, previousOne.indexStart, previousOne.indexCount, previousOne.indexStart, previousOne.indexCount, this);
             }
+
+            this.synchronizeInstances();
+        };
+
+        // Instances
+        Mesh.prototype.createInstance = function (name) {
+            return new BABYLON.InstancedMesh(name, this);
+        };
+
+        Mesh.prototype.synchronizeInstances = function () {
+            for (var instanceIndex = 0; instanceIndex < this.instances.length; instanceIndex++) {
+                var instance = this.instances[instanceIndex];
+                instance._syncSubMeshes();
+            }
         };
 
         // Statics
@@ -1250,13 +732,8 @@ var BABYLON;
             var minMaxVector = meshesOrMinMaxVector.min !== undefined ? meshesOrMinMaxVector : BABYLON.Mesh.MinMax(meshesOrMinMaxVector);
             return BABYLON.Vector3.Center(minMaxVector.min, minMaxVector.max);
         };
-        Mesh._BILLBOARDMODE_NONE = 0;
-        Mesh._BILLBOARDMODE_X = 1;
-        Mesh._BILLBOARDMODE_Y = 2;
-        Mesh._BILLBOARDMODE_Z = 4;
-        Mesh._BILLBOARDMODE_ALL = 7;
         return Mesh;
-    })(BABYLON.Node);
+    })(BABYLON.AbstractMesh);
     BABYLON.Mesh = Mesh;
 })(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.mesh.js.map

+ 119 - 634
Babylon/Mesh/babylon.mesh.ts

@@ -1,178 +1,20 @@
 module BABYLON {
-    export class Mesh extends Node implements IGetSetVerticesData {
-        // Statics
-        private static _BILLBOARDMODE_NONE = 0;
-        private static _BILLBOARDMODE_X = 1;
-        private static _BILLBOARDMODE_Y = 2;
-        private static _BILLBOARDMODE_Z = 4;
-        private static _BILLBOARDMODE_ALL = 7;
-
-        public static get BILLBOARDMODE_NONE(): number {
-            return Mesh._BILLBOARDMODE_NONE;
-        }
-
-        public static get BILLBOARDMODE_X(): number {
-            return Mesh._BILLBOARDMODE_X;
-        }
-
-        public static get BILLBOARDMODE_Y(): number {
-            return Mesh._BILLBOARDMODE_Y;
-        }
-
-        public static get BILLBOARDMODE_Z(): number {
-            return Mesh._BILLBOARDMODE_Z;
-        }
-
-        public static get BILLBOARDMODE_ALL(): number {
-            return Mesh._BILLBOARDMODE_ALL;
-        }
-
+    export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         // Members
-        public position = new BABYLON.Vector3(0, 0, 0);
-        public rotation = new BABYLON.Vector3(0, 0, 0);
-        public rotationQuaternion = null;
-        public scaling = new BABYLON.Vector3(1, 1, 1);
         public delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
-        public material = null;
-        public isVisible = true;
-        public isPickable = true;
-        public visibility = 1.0;
-        public billboardMode = BABYLON.Mesh.BILLBOARDMODE_NONE;
-        public checkCollisions = false;
-        public receiveShadows = false;
-        public _isDisposed = false;
-        public onDispose = null;
-        public skeleton = null;
-        public renderingGroupId = 0;
-        public infiniteDistance = false;
-        public showBoundingBox = false;
-        public subMeshes: SubMesh[];
+        public instances = new Array<InstancedMesh>();
         public delayLoadingFile: string;
-        public actionManager: ActionManager;
-
-        // Cache
-        private _positions = null;
-        private _localScaling = BABYLON.Matrix.Zero();
-        private _localRotation = BABYLON.Matrix.Zero();
-        private _localTranslation = BABYLON.Matrix.Zero();
-        private _localBillboard = BABYLON.Matrix.Zero();
-        private _localPivotScaling = BABYLON.Matrix.Zero();
-        private _localPivotScalingRotation = BABYLON.Matrix.Zero();
-        private _localWorld = BABYLON.Matrix.Zero();
-        private _worldMatrix = BABYLON.Matrix.Zero();
-        private _rotateYByPI = BABYLON.Matrix.RotationY(Math.PI);
-        private _collisionsTransformMatrix = BABYLON.Matrix.Zero();
-        private _collisionsScalingMatrix = BABYLON.Matrix.Zero();
-        private _absolutePosition = BABYLON.Vector3.Zero();
-        private _isDirty = false;
-
-        // Physics
-        public _physicImpostor = PhysicsEngine.NoImpostor;
-        public _physicsMass: number;
-        public _physicsFriction: number;
-        public _physicRestitution: number;
 
         // Private
         public _geometry: Geometry;
-        public _boundingInfo: BoundingInfo;
-        private _pivotMatrix = BABYLON.Matrix.Identity();
-        private _renderId = 0;
         private _onBeforeRenderCallbacks = [];
         private _delayInfo; //ANY
-        private _animationStarted = false;
         private _delayLoadingFunction: (any, Mesh) => void;
+        public _visibleInstances = new SmartArray<InstancedMesh>(32);
+        private _renderIdForInstances = -1;
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
-
-            scene.meshes.push(this);
-        }
-
-        public getBoundingInfo(): BoundingInfo {
-            return this._boundingInfo;
-        }
-
-        public getWorldMatrix(): Matrix {
-            if (this._currentRenderId !== this.getScene().getRenderId()) {
-                this.computeWorldMatrix();
-            }
-            return this._worldMatrix;
-        }
-
-        public rotate(axis: Vector3, amount: number, space: Space): void {
-            if (!this.rotationQuaternion) {
-                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = BABYLON.Vector3.Zero();
-            }
-
-            if (!space || space == BABYLON.Space.LOCAL) {
-                var rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
-                this.rotationQuaternion = this.rotationQuaternion.multiply(rotationQuaternion);
-            }
-            else {
-                if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
-
-                    axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
-                }
-                rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, amount);
-                this.rotationQuaternion = rotationQuaternion.multiply(this.rotationQuaternion);
-            }
-        }
-
-        public translate(axis: Vector3, distance: number, space: Space): void {
-            var displacementVector = axis.scale(distance);
-
-            if (!space || space == BABYLON.Space.LOCAL) {
-                var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
-                this.setPositionWithLocalVector(tempV3);
-            }
-            else {
-                this.setAbsolutePosition(this.getAbsolutePosition().add(displacementVector));
-            }
-        }
-
-        public getAbsolutePosition(): Vector3 {
-            this.computeWorldMatrix();
-            return this._absolutePosition;
-        }
-
-        public setAbsolutePosition(absolutePosition: Vector3): void {
-            if (!absolutePosition) {
-                return;
-            }
-
-            var absolutePositionX;
-            var absolutePositionY;
-            var absolutePositionZ;
-
-            if (absolutePosition.x === undefined) {
-                if (arguments.length < 3) {
-                    return;
-                }
-                absolutePositionX = arguments[0];
-                absolutePositionY = arguments[1];
-                absolutePositionZ = arguments[2];
-            }
-            else {
-                absolutePositionX = absolutePosition.x;
-                absolutePositionY = absolutePosition.y;
-                absolutePositionZ = absolutePosition.z;
-            }
-
-            if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-
-                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-
-                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
-            } else {
-                this.position.x = absolutePositionX;
-                this.position.y = absolutePositionY;
-                this.position.z = absolutePositionZ;
-            }
         }
 
         public getTotalVertices(): number {
@@ -182,7 +24,7 @@
             return this._geometry.getTotalVertices();
         }
 
-        public getVerticesData(kind): number[] {
+        public getVerticesData(kind:  string): number[] {
             if (!this._geometry) {
                 return null;
             }
@@ -233,77 +75,22 @@
             return this._geometry.getIndices();
         }
 
-        public setPivotMatrix(matrix: Matrix): void {
-            this._pivotMatrix = matrix;
-            this._cache.pivotMatrixUpdated = true;
-        }
-
-        public getPivotMatrix(): Matrix {
-            return this._pivotMatrix;
-        }
-
-        public _isSynchronized(): boolean {
-            if (this._isDirty) {
-                return false;
-            }
-
-            if (this.billboardMode !== Mesh.BILLBOARDMODE_NONE)
-                return false;
-
-            if (this._cache.pivotMatrixUpdated) {
-                return false;
-            }
-
-            if (this.infiniteDistance) {
-                return false;
-            }
-
-            if (!this._cache.position.equals(this.position))
+        public isReady(): boolean {
+            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
                 return false;
-
-            if (this.rotationQuaternion) {
-                if (!this._cache.rotationQuaternion.equals(this.rotationQuaternion))
-                    return false;
-            } else {
-                if (!this._cache.rotation.equals(this.rotation))
-                    return false;
             }
 
-            if (!this._cache.scaling.equals(this.scaling))
-                return false;
-
-            return true;
-        }
-
-        public isReady(): boolean {
-            return this._isReady;
-        }
-
-        public isAnimated(): boolean {
-            return this._animationStarted;
+            return super.isReady();
         }
 
         public isDisposed(): boolean {
             return this._isDisposed;
         }
 
-        // Methods
-        public _initCache() {
-            super._initCache();
-
-            this._cache.localMatrixUpdated = false;
-            this._cache.position = BABYLON.Vector3.Zero();
-            this._cache.scaling = BABYLON.Vector3.Zero();
-            this._cache.rotation = BABYLON.Vector3.Zero();
-            this._cache.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 0);
-        }
-
-        public markAsDirty(property: string): void {
-            if (property === "rotation") {
-                this.rotationQuaternion = null;
-            }
-            this._currentRenderId = Number.MAX_VALUE;
-            this._isDirty = true;
+        // Methods  
+        public _activate(renderId: number): void {
+            this._visibleInstances.reset();
+            super._activate(renderId);
         }
 
         public refreshBoundingInfo(): void {
@@ -323,117 +110,13 @@
             this._updateBoundingInfo();
         }
 
-        public _updateBoundingInfo(): void {
-            this._boundingInfo = this._boundingInfo || new BABYLON.BoundingInfo(this._absolutePosition, this._absolutePosition);
-
-            this._boundingInfo._update(this._worldMatrix);
-
-            if (!this.subMeshes) {
-                return;
-            }
-
-            for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
-                var subMesh = this.subMeshes[subIndex];
-
-                subMesh.updateBoundingInfo(this._worldMatrix);
-            }
-        }
-
-        public computeWorldMatrix(force?: boolean): Matrix {
-            if (!force && (this._currentRenderId == this.getScene().getRenderId() || this.isSynchronized(true))) {
-                return this._worldMatrix;
-            }
-
-            this._cache.position.copyFrom(this.position);
-            this._cache.scaling.copyFrom(this.scaling);
-            this._cache.pivotMatrixUpdated = false;
-            this._currentRenderId = this.getScene().getRenderId();
-            this._isDirty = false;
-
-            // Scaling
-            BABYLON.Matrix.ScalingToRef(this.scaling.x, this.scaling.y, this.scaling.z, this._localScaling);
-
-            // Rotation
-            if (this.rotationQuaternion) {
-                this.rotationQuaternion.toRotationMatrix(this._localRotation);
-                this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
-            } else {
-                BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
-                this._cache.rotation.copyFrom(this.rotation);
-            }
-
-            // Translation
-            if (this.infiniteDistance && !this.parent) {
-                var camera = this.getScene().activeCamera;
-                var cameraWorldMatrix = camera.getWorldMatrix();
-
-                var cameraGlobalPosition = new BABYLON.Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
-
-                BABYLON.Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y, this.position.z + cameraGlobalPosition.z, this._localTranslation);
-            } else {
-                BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
-            }
-
-            // Composing transformations
-            this._pivotMatrix.multiplyToRef(this._localScaling, this._localPivotScaling);
-            this._localPivotScaling.multiplyToRef(this._localRotation, this._localPivotScalingRotation);
-
-            // Billboarding
-            if (this.billboardMode !== Mesh.BILLBOARDMODE_NONE) {
-                var localPosition = this.position.clone();
-                var zero = this.getScene().activeCamera.position.clone();
-
-                if (this.parent && (<any>this.parent).position) {
-                    localPosition.addInPlace((<any>this.parent).position);
-                    BABYLON.Matrix.TranslationToRef(localPosition.x, localPosition.y, localPosition.z, this._localTranslation);
-                }
-
-                if ((this.billboardMode & Mesh.BILLBOARDMODE_ALL) === Mesh.BILLBOARDMODE_ALL) {
-                    zero = this.getScene().activeCamera.position;
-                } else {
-                    if (this.billboardMode & BABYLON.Mesh.BILLBOARDMODE_X)
-                        zero.x = localPosition.x + BABYLON.Engine.Epsilon;
-                    if (this.billboardMode & BABYLON.Mesh.BILLBOARDMODE_Y)
-                        zero.y = localPosition.y + 0.001;
-                    if (this.billboardMode & BABYLON.Mesh.BILLBOARDMODE_Z)
-                        zero.z = localPosition.z + 0.001;
-                }
-
-                BABYLON.Matrix.LookAtLHToRef(localPosition, zero, BABYLON.Vector3.Up(), this._localBillboard);
-                this._localBillboard.m[12] = this._localBillboard.m[13] = this._localBillboard.m[14] = 0;
-
-                this._localBillboard.invert();
-
-                this._localPivotScalingRotation.multiplyToRef(this._localBillboard, this._localWorld);
-                this._rotateYByPI.multiplyToRef(this._localWorld, this._localPivotScalingRotation);
-            }
-
-            // Local world
-            this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
-
-            // Parent
-            if (this.parent && this.parent.getWorldMatrix && this.billboardMode === BABYLON.Mesh.BILLBOARDMODE_NONE) {
-                this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
-            } else {
-                this._worldMatrix.copyFrom(this._localWorld);
-            }
-
-            // Bounding info
-            this._updateBoundingInfo();
-
-            // Absolute position
-            this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
-
-            return this._worldMatrix;
-        }
-
-
         public _createGlobalSubMesh(): SubMesh {
             var totalVertices = this.getTotalVertices();
             if (!totalVertices || !this.getIndices()) {
                 return null;
             }
 
+            this.releaseSubMeshes();
             this.subMeshes = [];
             return new BABYLON.SubMesh(0, 0, totalVertices, 0, this.getTotalIndices(), this);
         }
@@ -447,12 +130,15 @@
             var subdivisionSize = totalIndices / count;
             var offset = 0;
 
+            this.releaseSubMeshes();
             this.subMeshes = [];
             for (var index = 0; index < count; index++) {
                 BABYLON.SubMesh.CreateFromIndices(0, offset, Math.min(subdivisionSize, totalIndices - offset), this);
 
                 offset += subdivisionSize;
             }
+
+            this.synchronizeInstances();
         }
 
         public setVerticesData(data: number[], kind: string, updatable?: boolean): void {
@@ -504,30 +190,37 @@
             }
         }
 
-        // ANY
-        public bindAndDraw(subMesh: SubMesh, effect, wireframe?: boolean): void {
-            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
-                return;
-            }
-
+        private _bind(subMesh: SubMesh, effect: Effect, wireframe?: boolean): void {
             var engine = this.getScene().getEngine();
 
             // Wireframe
             var indexToBind = this._geometry.getIndexBuffer();
-            var useTriangles = true;
 
             if (wireframe) {
                 indexToBind = subMesh.getLinesIndexBuffer(this.getIndices(), engine);
-                useTriangles = false;
             }
 
             // VBOs
             engine.bindMultiBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
+        }
+
+        private _draw(subMesh: SubMesh, useTriangles: boolean): void {
+            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
+                return;
+            }
+
+            var engine = this.getScene().getEngine();
 
             // Draw order
             engine.draw(useTriangles, useTriangles ? subMesh.indexStart : 0, useTriangles ? subMesh.indexCount : subMesh.linesIndexCount);
         }
 
+        public bindAndDraw(subMesh: SubMesh, effect: Effect, wireframe?: boolean): void {
+            this._bind(subMesh, effect, wireframe);
+
+            this._draw(subMesh, !wireframe);
+        }
+
         public registerBeforeRender(func: () => void): void {
             this._onBeforeRenderCallbacks.push(func);
         }
@@ -541,6 +234,23 @@
         }
 
         public render(subMesh: SubMesh): void {
+            var renderSelf = true;
+            var scene = this.getScene();
+
+            // Managing instances
+            if (this._visibleInstances.length) {
+                if (this._renderIdForInstances === scene.getRenderId()) {
+                    return;
+                }
+
+                if (scene.getRenderId() !== this._renderId) {
+                    renderSelf = false;
+                }
+
+            }
+            this._renderIdForInstances = scene.getRenderId();
+
+            // Checking geometry state
             if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
                 return;
             }
@@ -549,9 +259,6 @@
                 this._onBeforeRenderCallbacks[callbackIndex]();
             }
 
-            // World
-            var world = this.getWorldMatrix();
-
             // Material
             var effectiveMaterial = subMesh.getMaterial();
 
@@ -559,12 +266,33 @@
                 return;
             }
 
+            var engine = scene.getEngine();
+            var effect = effectiveMaterial.getEffect();
+
+            // Bind
+            var wireFrame = engine.forceWireframe || effectiveMaterial.wireframe;
+            this._bind(subMesh, effect, wireFrame);
             effectiveMaterial._preBind();
-            effectiveMaterial.bind(world, this);
 
-            // Bind and draw
-            var engine = this.getScene().getEngine();
-            this.bindAndDraw(subMesh, effectiveMaterial.getEffect(), engine.forceWireframe || effectiveMaterial.wireframe);
+            if (renderSelf) {
+                // World
+                var world = this.getWorldMatrix();
+                effectiveMaterial.bind(world, this);
+
+                // Draw
+                this._draw(subMesh, !wireFrame);
+            }
+
+            for (var instanceIndex = 0; instanceIndex < this._visibleInstances.length; instanceIndex++) {
+                var instance = this._visibleInstances.data[instanceIndex];
+
+                // World
+                world = instance.getWorldMatrix();
+                effectiveMaterial.bind(world, this);
+
+                // Draw
+                this._draw(subMesh, !wireFrame);
+            }
 
             // Unbind
             effectiveMaterial.unbind();
@@ -609,15 +337,7 @@
             return results;
         }
 
-        public isInFrustum(frustumPlanes: Plane[]): boolean {
-            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
-                return false;
-            }
-
-            if (!this._boundingInfo.isInFrustum(frustumPlanes)) {
-                return false;
-            }
-
+        public _checkDelayState(): void {
             var that = this;
             var scene = this.getScene();
 
@@ -629,12 +349,24 @@
 
                 scene._addPendingData(that);
 
-                BABYLON.Tools.LoadFile(this.delayLoadingFile, function (data) {
-                    that._delayLoadingFunction(JSON.parse(data), that);
-                    that.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
-                    scene._removePendingData(that);
-                }, function () { }, scene.database);
+                BABYLON.Tools.LoadFile(this.delayLoadingFile, data => {
+                    this._delayLoadingFunction(JSON.parse(data), this);
+                    this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
+                    scene._removePendingData(this);
+                }, () => { }, scene.database);
             }
+        }
+
+        public isInFrustum(frustumPlanes: Plane[]): boolean {
+            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                return false;
+            }
+
+            if (!super.isInFrustum(frustumPlanes)) {
+                return false;
+            }
+
+            this._checkDelayState();
 
             return true;
         }
@@ -669,26 +401,6 @@
         }
 
         // Geometry
-        public setPositionWithLocalVector(vector3: Vector3): void {
-            this.computeWorldMatrix();
-
-            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localWorld);
-        }
-
-        public getPositionExpressedInLocalSpace(): Vector3 {
-            this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
-
-            return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
-        }
-
-        public locallyTranslate(vector3: Vector3): void {
-            this.computeWorldMatrix();
-
-            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localWorld);
-        }
-
         public bakeTransformIntoVertices(transform: Matrix): void {
             // Position
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
@@ -718,156 +430,31 @@
             this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable());
         }
 
-        public lookAt(targetPoint: Vector3, yawCor: number, pitchCor: number, rollCor: number): void {
-            /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
-            /// <param name="targetPoint" type="BABYLON.Vector3">The position (must be in same space as current mesh) to look at</param>
-            /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
-            /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
-            /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
-            /// <returns>Mesh oriented towards targetMesh</returns>
-
-            yawCor = yawCor || 0; // default to zero if undefined 
-            pitchCor = pitchCor || 0;
-            rollCor = rollCor || 0;
-
-            var dv = targetPoint.subtract(this.position);
-            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
-            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
-            var pitch = Math.atan2(dv.y, len);
-            this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(yaw + yawCor, pitch + pitchCor, rollCor);
-        }
+     
 
         // Cache
         public _resetPointsArrayCache(): void {
             this._positions = null;
         }
 
-        public _generatePointsArray(): void {
+        public _generatePointsArray(): boolean {
             if (this._positions)
-                return;
+                return true;
 
             this._positions = [];
 
             var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            for (var index = 0; index < data.length; index += 3) {
-                this._positions.push(BABYLON.Vector3.FromArray(data, index));
-            }
-        }
-
-        // Collisions
-        public _collideForSubMesh(subMesh: SubMesh, transformMatrix: Matrix, collider: Collider): void {
-            this._generatePointsArray();
-            // Transformation
-            if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix.equals(transformMatrix)) {
-                subMesh._lastColliderTransformMatrix = transformMatrix.clone();
-                subMesh._lastColliderWorldVertices = [];
-                subMesh._trianglePlanes = [];
-                var start = subMesh.verticesStart;
-                var end = (subMesh.verticesStart + subMesh.verticesCount);
-                for (var i = start; i < end; i++) {
-                    subMesh._lastColliderWorldVertices.push(BABYLON.Vector3.TransformCoordinates(this._positions[i], transformMatrix));
-                }
-            }
-            // Collide
-            collider._collide(subMesh, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
-        }
-
-        public _processCollisionsForSubModels(collider: Collider, transformMatrix: Matrix): void {
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                var subMesh = this.subMeshes[index];
-
-                // Bounding test
-                if (this.subMeshes.length > 1 && !subMesh._checkCollision(collider))
-                    continue;
-
-                this._collideForSubMesh(subMesh, transformMatrix, collider);
-            }
-        }
-
-        public _checkCollision(collider: Collider): void {
-            // Bounding box test
-            if (!this._boundingInfo._checkCollision(collider))
-                return;
-
-            // Transformation matrix
-            BABYLON.Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
-            this._worldMatrix.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
-
-            this._processCollisionsForSubModels(collider, this._collisionsTransformMatrix);
-        }
 
-        public intersectsMesh(mesh: Mesh, precise?: boolean): boolean {
-            if (!this._boundingInfo || !mesh._boundingInfo) {
+            if (!data) {
                 return false;
             }
 
-            return this._boundingInfo.intersects(mesh._boundingInfo, precise);
-        }
-
-        public intersectsPoint(point: Vector3): boolean {
-            if (!this._boundingInfo) {
-                return false;
-            }
-
-            return this._boundingInfo.intersectsPoint(point);
-        }
-
-        // Picking
-        public intersects(ray: Ray, fastCheck?: boolean): PickingInfo {
-            var pickingInfo = new BABYLON.PickingInfo();
-
-            if (!this._boundingInfo || !ray.intersectsSphere(this._boundingInfo.boundingSphere) || !ray.intersectsBox(this._boundingInfo.boundingBox)) {
-                return pickingInfo;
-            }
-
-            this._generatePointsArray();
-
-            var intersectInfo: IntersectionInfo = null;
-
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                var subMesh = this.subMeshes[index];
-
-                // Bounding test
-                if (this.subMeshes.length > 1 && !subMesh.canIntersects(ray))
-                    continue;
-
-                var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);
-
-                if (currentIntersectInfo) {
-                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
-                        intersectInfo = currentIntersectInfo;
-
-                        if (fastCheck) {
-                            break;
-                        }
-                    }
-                }
-            }
-
-            if (intersectInfo) {
-                // Get picked point
-                var world = this.getWorldMatrix();
-                var worldOrigin = BABYLON.Vector3.TransformCoordinates(ray.origin, world);
-                var direction = ray.direction.clone();
-                direction.normalize();
-                direction = direction.scale(intersectInfo.distance);
-                var worldDirection = BABYLON.Vector3.TransformNormal(direction, world);
-
-                var pickedPoint = worldOrigin.add(worldDirection);
-
-                // Return result
-                pickingInfo.hit = true;
-                pickingInfo.distance = BABYLON.Vector3.Distance(worldOrigin, pickedPoint);
-                pickingInfo.pickedPoint = pickedPoint;
-                pickingInfo.pickedMesh = this;
-                pickingInfo.bu = intersectInfo.bu;
-                pickingInfo.bv = intersectInfo.bv;
-                pickingInfo.faceId = intersectInfo.faceId;
-                return pickingInfo;
+            for (var index = 0; index < data.length; index += 3) {
+                this._positions.push(BABYLON.Vector3.FromArray(data, index));
             }
 
-            return pickingInfo;
-        }
+            return true;
+        }     
 
         // Clone
         public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): Mesh {
@@ -922,129 +509,12 @@
                 this._geometry.releaseForMesh(this);
             }
 
-            // Physics
-            if (this.getPhysicsImpostor() != PhysicsEngine.NoImpostor) {
-                this.setPhysicsState(PhysicsEngine.NoImpostor);
-            }
-
-            // Remove from scene
-            var index = this.getScene().meshes.indexOf(this);
-            this.getScene().meshes.splice(index, 1);
-
-            if (!doNotRecurse) {
-                // Particles
-                for (index = 0; index < this.getScene().particleSystems.length; index++) {
-                    if (this.getScene().particleSystems[index].emitter == this) {
-                        this.getScene().particleSystems[index].dispose();
-                        index--;
-                    }
-                }
-
-                // Children
-                var objects = this.getScene().meshes.slice(0);
-                for (index = 0; index < objects.length; index++) {
-                    if (objects[index].parent == this) {
-                        objects[index].dispose();
-                    }
-                }
-            } else {
-                for (index = 0; index < this.getScene().meshes.length; index++) {
-                    var obj = this.getScene().meshes[index];
-                    if (obj.parent === this) {
-                        obj.parent = null;
-                        obj.computeWorldMatrix(true);
-                    }
-                }
-            }
-
-            this._isDisposed = true;
-
-            // Callback
-            if (this.onDispose) {
-                this.onDispose();
-            }
-        }
-
-        // Physics
-        public setPhysicsState(impostor?: any, options?: PhysicsBodyCreationOptions): void {
-            var physicsEngine = this.getScene().getPhysicsEngine();
-
-            if (!physicsEngine) {
-                return;
-            }
-
-            if (impostor.impostor) {
-                // Old API
-                options = impostor;
-                impostor = impostor.impostor;
-            }
-
-            impostor = impostor || PhysicsEngine.NoImpostor;
-
-            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
-                physicsEngine._unregisterMesh(this);
-                return;
-            }
-
-            options.mass = options.mass || 0;
-            options.friction = options.friction || 0.2;
-            options.restitution = options.restitution || 0.9;
-
-            this._physicImpostor = impostor;
-            this._physicsMass = options.mass;
-            this._physicsFriction = options.friction;
-            this._physicRestitution = options.restitution;
-
-
-            physicsEngine._registerMesh(this, impostor, options);
-        }
-
-        public getPhysicsImpostor(): number {
-            if (!this._physicImpostor) {
-                return BABYLON.PhysicsEngine.NoImpostor;
-            }
-
-            return this._physicImpostor;
-        }
-
-        public getPhysicsMass(): number {
-            if (!this._physicsMass) {
-                return 0;
-            }
-
-            return this._physicsMass;
-        }
-
-        public getPhysicsFriction(): number {
-            if (!this._physicsFriction) {
-                return 0;
-            }
-
-            return this._physicsFriction;
-        }
-
-        public getPhysicsRestitution(): number {
-            if (!this._physicRestitution) {
-                return 0;
-            }
-
-            return this._physicRestitution;
-        }
-
-        public applyImpulse(force: Vector3, contactPoint: Vector3): void {
-            if (!this._physicImpostor) {
-                return;
-            }
-
-            this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
-        }
-
-        public setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3): void {
-            if (!this._physicImpostor) {
-                return;
+            // Instances
+            while (this.instances.length) {
+                this.instances[0].dispose();
             }
 
-            this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2);
+            super.dispose(doNotRecurse);
         }
 
         // Geometric tools
@@ -1129,10 +599,25 @@
 
             // Updating submeshes
             this.subMeshes = [];
+            this.releaseSubMeshes();
             for (var submeshIndex = 0; submeshIndex < previousSubmeshes.length; submeshIndex++) {
                 var previousOne = previousSubmeshes[submeshIndex];
                 var subMesh = new BABYLON.SubMesh(previousOne.materialIndex, previousOne.indexStart, previousOne.indexCount, previousOne.indexStart, previousOne.indexCount, this);
             }
+
+            this.synchronizeInstances();
+        }
+
+        // Instances
+        public createInstance(name: string): InstancedMesh {
+            return new InstancedMesh(name, this);
+        }
+
+        public synchronizeInstances(): void {
+            for (var instanceIndex = 0; instanceIndex < this.instances.length; instanceIndex++) {
+                var instance = this.instances[instanceIndex];
+                instance._syncSubMeshes();
+            }
         }
 
         // Statics
@@ -1233,7 +718,7 @@
         }
 
         // Tools
-        public static MinMax(meshes: Mesh[]): {min: Vector3; max: Vector3} {
+        public static MinMax(meshes: AbstractMesh[]): {min: Vector3; max: Vector3} {
             var minVector = null;
             var maxVector = null;
             for (var i in meshes) {

+ 42 - 0
Babylon/Mesh/babylon.mesh.vertexData.js

@@ -37,6 +37,14 @@
             this._applyTo(geometry, updatable);
         };
 
+        VertexData.prototype.updateMesh = function (mesh, updateExtends, makeItUnique) {
+            this._update(mesh);
+        };
+
+        VertexData.prototype.updateGeometry = function (geometry, updateExtends, makeItUnique) {
+            this._update(geometry);
+        };
+
         VertexData.prototype._applyTo = function (meshOrGeometry, updatable) {
             if (this.positions) {
                 meshOrGeometry.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
@@ -71,6 +79,40 @@
             }
         };
 
+        VertexData.prototype._update = function (meshOrGeometry, updateExtends, makeItUnique) {
+            if (this.positions) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.PositionKind, this.positions, updateExtends, makeItUnique);
+            }
+
+            if (this.normals) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.NormalKind, this.normals, updateExtends, makeItUnique);
+            }
+
+            if (this.uvs) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.UVKind, this.uvs, updateExtends, makeItUnique);
+            }
+
+            if (this.uv2s) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.UV2Kind, this.uv2s, updateExtends, makeItUnique);
+            }
+
+            if (this.colors) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.ColorKind, this.colors, updateExtends, makeItUnique);
+            }
+
+            if (this.matricesIndices) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind, this.matricesIndices, updateExtends, makeItUnique);
+            }
+
+            if (this.matricesWeights) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind, this.matricesWeights, updateExtends, makeItUnique);
+            }
+
+            if (this.indices) {
+                meshOrGeometry.setIndices(this.indices);
+            }
+        };
+
         VertexData.prototype.transform = function (matrix) {
             var transformed = BABYLON.Vector3.Zero();
 

+ 43 - 0
Babylon/Mesh/babylon.mesh.vertexData.ts

@@ -4,6 +4,7 @@
         getVerticesData(kind: string): number[];
         getIndices(): number[];
         setVerticesData(data: number[], kind: string, updatable?: boolean): void;
+        updateVerticesData(kind: string, data: number[], updateExtends?: boolean, makeItUnique?: boolean): void;
         setIndices(indices: number[]): void;
     }
 
@@ -51,6 +52,14 @@
             this._applyTo(geometry, updatable);
         }
 
+        public updateMesh(mesh: Mesh, updateExtends?: boolean, makeItUnique?: boolean): void {
+            this._update(mesh);
+        }
+
+        public updateGeometry(geometry: Geometry, updateExtends?: boolean, makeItUnique?: boolean): void {
+            this._update(geometry);
+        }
+
         private _applyTo(meshOrGeometry: IGetSetVerticesData, updatable?: boolean) {
             if (this.positions) {
                 meshOrGeometry.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
@@ -85,6 +94,40 @@
             }
         }
 
+        private _update(meshOrGeometry: IGetSetVerticesData, updateExtends?: boolean, makeItUnique?: boolean) {
+            if (this.positions) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.PositionKind, this.positions, updateExtends, makeItUnique);
+            }
+
+            if (this.normals) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.NormalKind, this.normals, updateExtends, makeItUnique);
+            }
+
+            if (this.uvs) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.UVKind, this.uvs, updateExtends, makeItUnique);
+            }
+
+            if (this.uv2s) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.UV2Kind, this.uv2s, updateExtends, makeItUnique);
+            }
+
+            if (this.colors) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.ColorKind, this.colors, updateExtends, makeItUnique);
+            }
+
+            if (this.matricesIndices) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind, this.matricesIndices, updateExtends, makeItUnique);
+            }
+
+            if (this.matricesWeights) {
+                meshOrGeometry.updateVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind, this.matricesWeights, updateExtends, makeItUnique);
+            }
+
+            if (this.indices) {
+                meshOrGeometry.setIndices(this.indices);
+            }
+        }
+
         public transform(matrix: Matrix): void {
             var transformed = BABYLON.Vector3.Zero();
 

+ 31 - 11
Babylon/Mesh/babylon.subMesh.js

@@ -1,13 +1,15 @@
 var BABYLON;
 (function (BABYLON) {
     var SubMesh = (function () {
-        function SubMesh(materialIndex, verticesStart, verticesCount, indexStart, indexCount, mesh) {
+        function SubMesh(materialIndex, verticesStart, verticesCount, indexStart, indexCount, mesh, renderingMesh) {
             this.materialIndex = materialIndex;
             this.verticesStart = verticesStart;
             this.verticesCount = verticesCount;
             this.indexStart = indexStart;
             this.indexCount = indexCount;
+            this._renderId = 0;
             this._mesh = mesh;
+            this._renderingMesh = renderingMesh || mesh;
             mesh.subMeshes.push(this);
 
             this.refreshBoundingInfo();
@@ -20,11 +22,16 @@
             return this._mesh;
         };
 
+        SubMesh.prototype.getRenderingMesh = function () {
+            return this._renderingMesh;
+        };
+
         SubMesh.prototype.getMaterial = function () {
-            var rootMaterial = this._mesh.material;
+            var rootMaterial = this._renderingMesh.material;
 
-            if (rootMaterial && rootMaterial.getSubMaterial) {
-                return rootMaterial.getSubMaterial(this.materialIndex);
+            if (rootMaterial && rootMaterial instanceof BABYLON.MultiMaterial) {
+                var multiMaterial = rootMaterial;
+                return multiMaterial.getSubMaterial(this.materialIndex);
             }
 
             if (!rootMaterial) {
@@ -36,7 +43,7 @@
 
         // Methods
         SubMesh.prototype.refreshBoundingInfo = function () {
-            var data = this._mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            var data = this._renderingMesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
 
             if (!data) {
                 this._boundingInfo = this._mesh._boundingInfo;
@@ -63,7 +70,7 @@
         };
 
         SubMesh.prototype.render = function () {
-            this._mesh.render(this);
+            this._renderingMesh.render(this);
         };
 
         SubMesh.prototype.getLinesIndexBuffer = function (indices, engine) {
@@ -110,16 +117,29 @@
         };
 
         // Clone
-        SubMesh.prototype.clone = function (newMesh) {
-            return new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh);
+        SubMesh.prototype.clone = function (newMesh, newRenderingMesh) {
+            return new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh, newRenderingMesh);
+        };
+
+        // Dispose
+        SubMesh.prototype.dispose = function () {
+            if (this._linesIndexBuffer) {
+                this._mesh.getScene().getEngine()._releaseBuffer(this._linesIndexBuffer);
+                this._linesIndexBuffer = null;
+            }
+
+            // Remove from mesh
+            var index = this._mesh.subMeshes.indexOf(this);
+            this._mesh.subMeshes.splice(index, 1);
         };
 
         // Statics
-        SubMesh.CreateFromIndices = function (materialIndex, startIndex, indexCount, mesh) {
+        SubMesh.CreateFromIndices = function (materialIndex, startIndex, indexCount, mesh, renderingMesh) {
             var minVertexIndex = Number.MAX_VALUE;
             var maxVertexIndex = -Number.MAX_VALUE;
 
-            var indices = mesh.getIndices();
+            renderingMesh = renderingMesh || mesh;
+            var indices = renderingMesh.getIndices();
 
             for (var index = startIndex; index < startIndex + indexCount; index++) {
                 var vertexIndex = indices[index];
@@ -130,7 +150,7 @@
                     maxVertexIndex = vertexIndex;
             }
 
-            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh);
+            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh, renderingMesh);
         };
         return SubMesh;
     })();

+ 36 - 13
Babylon/Mesh/babylon.subMesh.ts

@@ -2,15 +2,20 @@
     export class SubMesh {
         public linesIndexCount: number;
 
-        private _mesh: Mesh;
+        private _mesh: AbstractMesh;
+        private _renderingMesh: Mesh;
         private _boundingInfo: BoundingInfo;
         private _linesIndexBuffer: WebGLBuffer;
         public _lastColliderWorldVertices: Vector3[];
         public _trianglePlanes: Plane[];
         public _lastColliderTransformMatrix: Matrix;
 
-        constructor(public materialIndex: number, public verticesStart: number, public verticesCount: number, public indexStart, public indexCount: number, mesh: Mesh) {
+        public _renderId = 0;
+        public _distanceToCamera: number;
+
+        constructor(public materialIndex: number, public verticesStart: number, public verticesCount: number, public indexStart, public indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh) {
             this._mesh = mesh;
+            this._renderingMesh = renderingMesh || <Mesh>mesh;
             mesh.subMeshes.push(this);
 
             this.refreshBoundingInfo();
@@ -20,15 +25,20 @@
             return this._boundingInfo;
         }
 
-        public getMesh(): Mesh {
+        public getMesh(): AbstractMesh {
             return this._mesh;
         }
 
+        public getRenderingMesh(): Mesh {
+            return this._renderingMesh;
+        }
+
         public getMaterial(): Material {
-            var rootMaterial = this._mesh.material;
+            var rootMaterial = this._renderingMesh.material;
 
-            if (rootMaterial && rootMaterial.getSubMaterial) {
-                return rootMaterial.getSubMaterial(this.materialIndex);
+            if (rootMaterial && rootMaterial instanceof MultiMaterial) {
+                var multiMaterial = <MultiMaterial>rootMaterial;
+                return multiMaterial.getSubMaterial(this.materialIndex);
             }
 
             if (!rootMaterial) {
@@ -40,7 +50,7 @@
 
         // Methods
         public refreshBoundingInfo(): void {
-            var data = this._mesh.getVerticesData(VertexBuffer.PositionKind);
+            var data = this._renderingMesh.getVerticesData(VertexBuffer.PositionKind);
 
             if (!data) {
                 this._boundingInfo = this._mesh._boundingInfo;
@@ -67,7 +77,7 @@
         }
 
         public render(): void {
-            this._mesh.render(this);
+            this._renderingMesh.render(this);
         }
 
         public getLinesIndexBuffer(indices: number[], engine): WebGLBuffer {
@@ -117,16 +127,29 @@
         }
 
         // Clone    
-        public clone(newMesh: Mesh): SubMesh {
-            return new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh);
+        public clone(newMesh: AbstractMesh, newRenderingMesh?: Mesh): SubMesh {
+            return new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh, newRenderingMesh);
+        }
+
+        // Dispose
+        public dispose() {
+            if (this._linesIndexBuffer) {
+                this._mesh.getScene().getEngine()._releaseBuffer(this._linesIndexBuffer);
+                this._linesIndexBuffer = null;
+            }
+
+            // Remove from mesh
+            var index = this._mesh.subMeshes.indexOf(this);
+            this._mesh.subMeshes.splice(index, 1);
         }
 
         // Statics
-        public static CreateFromIndices(materialIndex: number, startIndex: number, indexCount: number, mesh: Mesh): SubMesh {
+        public static CreateFromIndices(materialIndex: number, startIndex: number, indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh): SubMesh {
             var minVertexIndex = Number.MAX_VALUE;
             var maxVertexIndex = -Number.MAX_VALUE;
 
-            var indices = mesh.getIndices();
+            renderingMesh = renderingMesh || <Mesh>mesh;
+            var indices = renderingMesh.getIndices();
 
             for (var index = startIndex; index < startIndex + indexCount; index++) {
                 var vertexIndex = indices[index];
@@ -137,7 +160,7 @@
                     maxVertexIndex = vertexIndex;
             }
 
-            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh);
+            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh, renderingMesh);
         }
     }
 }

+ 1 - 1
Babylon/Particles/babylon.particleSystem.ts

@@ -9,7 +9,7 @@
         return ((random * (max - min)) + min);
     }
 
-    export class ParticleSystem {
+    export class ParticleSystem implements IDisposable {
         // Statics
         public static BLENDMODE_ONEONE = 0;
         public static BLENDMODE_STANDARD = 1;

+ 10 - 10
Babylon/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -2,7 +2,7 @@
     declare var CANNON;
     declare var window;
 
-    export class CannonJSPlugin {
+    export class CannonJSPlugin implements IPhysicsEnginePlugin {
         public checkWithEpsilon: (value: number) => number;
 
         private _world: any;
@@ -48,7 +48,7 @@
             this._world.gravity.set(gravity.x, gravity.z, gravity.y);
         }
 
-        public registerMesh(mesh: Mesh, impostor: number, options?: PhysicsBodyCreationOptions): any {
+        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsBodyCreationOptions): any {
             this.unregisterMesh(mesh);
 
             mesh.computeWorldMatrix(true);
@@ -79,7 +79,7 @@
             return null;
         }
 
-        private _createSphere(radius: number, mesh: Mesh, options?: PhysicsBodyCreationOptions): any {
+        private _createSphere(radius: number, mesh: AbstractMesh, options?: PhysicsBodyCreationOptions): any {
             var shape = new CANNON.Sphere(radius);
 
             if (!options) {
@@ -89,7 +89,7 @@
             return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
         }
 
-        private _createBox(x: number, y: number, z: number, mesh: Mesh, options?: PhysicsBodyCreationOptions): any {
+        private _createBox(x: number, y: number, z: number, mesh: AbstractMesh, options?: PhysicsBodyCreationOptions): any {
             var shape = new CANNON.Box(new CANNON.Vec3(x, z, y));
 
             if (!options) {
@@ -99,7 +99,7 @@
             return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
         }
 
-        private _createPlane(mesh: Mesh, options?: PhysicsBodyCreationOptions): any {
+        private _createPlane(mesh: AbstractMesh, options?: PhysicsBodyCreationOptions): any {
             var shape = new CANNON.Plane();
 
             if (!options) {
@@ -109,7 +109,7 @@
             return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
         }
 
-        private _createConvexPolyhedron(rawVerts: number[], rawFaces: number[], mesh: Mesh, options?: PhysicsBodyCreationOptions): any {
+        private _createConvexPolyhedron(rawVerts: number[], rawFaces: number[], mesh: AbstractMesh, options?: PhysicsBodyCreationOptions): any {
             var verts = [], faces = [];
 
             mesh.computeWorldMatrix(true);
@@ -166,7 +166,7 @@
             return currentMat;
         }
 
-        private _createRigidBodyFromShape(shape: any, mesh: Mesh, mass: number, friction: number, restitution: number): any {
+        private _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, mass: number, friction: number, restitution: number): any {
             var initialRotation: Quaternion = null;
 
             if (mesh.rotationQuaternion) {
@@ -225,7 +225,7 @@
             }
         }
 
-        public unregisterMesh(mesh: Mesh): void {
+        public unregisterMesh(mesh: AbstractMesh): void {
             for (var index = 0; index < this._registeredMeshes.length; index++) {
                 var registeredMesh = this._registeredMeshes[index];
 
@@ -243,7 +243,7 @@
             }
         }
 
-        public applyImpulse(mesh: Mesh, force: Vector3, contactPoint: Vector3): void {
+        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
             var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.z, contactPoint.y);
             var impulse = new CANNON.Vec3(force.x, force.z, force.y);
 
@@ -257,7 +257,7 @@
             }
         }
 
-        public createLink(mesh1: Mesh, mesh2: Mesh, pivot1: Vector3, pivot2: Vector3): boolean {
+        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3): boolean {
             var body1 = null, body2 = null;
             for (var index = 0; index < this._registeredMeshes.length; index++) {
                 var registeredMesh = this._registeredMeshes[index];

+ 11 - 11
Babylon/Physics/babylon.physicsEngine.ts

@@ -1,15 +1,15 @@
 module BABYLON {
     declare var CANNON;
 
-    export interface PhysicsEnginePlugin {
+    export interface IPhysicsEnginePlugin {
         initialize(iterations?: number);
         setGravity(gravity: Vector3): void;
         runOneStep(delta: number): void;
-        registerMesh(mesh: Mesh, impostor: number, options: PhysicsBodyCreationOptions): any;
+        registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any;
         registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any;
-        unregisterMesh(mesh: Mesh);
-        applyImpulse(mesh: Mesh, force: Vector3, contactPoint: Vector3): void;
-        createLink(mesh1: Mesh, mesh2: Mesh, pivot1: Vector3, pivot2: Vector3): boolean;
+        unregisterMesh(mesh: AbstractMesh);
+        applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void;
+        createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3): boolean;
         dispose(): void;
         isSupported(): boolean;
     }
@@ -28,9 +28,9 @@
     export class PhysicsEngine {
         public gravity: Vector3;
 
-        private _currentPlugin: PhysicsEnginePlugin;
+        private _currentPlugin: IPhysicsEnginePlugin;
 
-        constructor(plugin?: PhysicsEnginePlugin) {
+        constructor(plugin?: IPhysicsEnginePlugin) {
             this._currentPlugin = plugin || new CannonJSPlugin();
         }
 
@@ -54,7 +54,7 @@
             this._currentPlugin.setGravity(this.gravity);
         }
 
-        public _registerMesh(mesh: Mesh, impostor: number, options: PhysicsBodyCreationOptions): any {
+        public _registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
             return this._currentPlugin.registerMesh(mesh, impostor, options);
         }
 
@@ -62,15 +62,15 @@
             return this._currentPlugin.registerMeshesAsCompound(parts, options);
         }
 
-        public _unregisterMesh(mesh: Mesh): void {
+        public _unregisterMesh(mesh: AbstractMesh): void {
             this._currentPlugin.unregisterMesh(mesh);
         }
 
-        public _applyImpulse(mesh: Mesh, force: Vector3, contactPoint: Vector3): void {
+        public _applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
             this._currentPlugin.applyImpulse(mesh, force, contactPoint);
         }
 
-        public _createLink(mesh1: Mesh, mesh2: Mesh, pivot1: Vector3, pivot2: Vector3): boolean {
+        public _createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3): boolean {
             return this._currentPlugin.createLink(mesh1, mesh2, pivot1, pivot2);
         }
 

+ 1 - 1
Babylon/PostProcess/babylon.postProcess.ts

@@ -12,7 +12,7 @@
         private _engine: Engine;
         private _renderRatio: number;
         private _reusable = false;
-        public _textures = new BABYLON.SmartArray(2);
+        public _textures = new BABYLON.SmartArray<WebGLTexture>(2);
         public _currentRenderTextureInd = 0;
         private _effect: Effect;
 

+ 1 - 1
Babylon/Rendering/babylon.boundingBoxRenderer.ts

@@ -3,7 +3,7 @@
         public frontColor = new BABYLON.Color3(1, 1, 1);
         public backColor = new BABYLON.Color3(0.1, 0.1, 0.1);
         public showBackLines = true;
-        public renderList = new BABYLON.SmartArray(32);
+        public renderList = new BABYLON.SmartArray<Mesh>(32);
 
         private _scene: Scene;
         private _colorShader: ShaderMaterial;

+ 1 - 0
Babylon/Rendering/babylon.renderingGroup.js

@@ -22,6 +22,7 @@
             // Opaque
             var subIndex;
             var submesh;
+
             for (subIndex = 0; subIndex < this._opaqueSubMeshes.length; subIndex++) {
                 submesh = this._opaqueSubMeshes.data[subIndex];
                 this._activeVertices += submesh.verticesCount;

+ 7 - 6
Babylon/Rendering/babylon.renderingGroup.ts

@@ -1,16 +1,16 @@
 module BABYLON {
     export class RenderingGroup {
         private _scene: Scene
-        private _opaqueSubMeshes = new BABYLON.SmartArray(256);
-        private _transparentSubMeshes = new BABYLON.SmartArray(256);
-        private _alphaTestSubMeshes = new BABYLON.SmartArray(256);
+        private _opaqueSubMeshes = new BABYLON.SmartArray<SubMesh>(256);
+        private _transparentSubMeshes = new BABYLON.SmartArray<SubMesh>(256);
+        private _alphaTestSubMeshes = new BABYLON.SmartArray<SubMesh>(256);
         private _activeVertices: number;
 
         constructor(public index: number, scene: Scene) {
             this._scene = scene;
         }
 
-        public render(customRenderFunction: (opaqueSubMeshes: SmartArray, transparentSubMeshes: SmartArray, alphaTestSubMeshes: SmartArray, beforeTransparents: () => void) => void,
+        public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents: () => void) => void,
                       beforeTransparents): boolean {
             if (customRenderFunction) {
                 customRenderFunction(this._opaqueSubMeshes, this._alphaTestSubMeshes, this._transparentSubMeshes, beforeTransparents);
@@ -22,8 +22,9 @@
             }
             var engine = this._scene.getEngine();
             // Opaque
-            var subIndex;
-            var submesh;
+            var subIndex: number;
+            var submesh: SubMesh;
+
             for (subIndex = 0; subIndex < this._opaqueSubMeshes.length; subIndex++) {
                 submesh = this._opaqueSubMeshes.data[subIndex];
                 this._activeVertices += submesh.verticesCount;

+ 1 - 1
Babylon/Rendering/babylon.renderingManager.ts

@@ -60,7 +60,7 @@
             this._depthBufferAlreadyCleaned = true;
         }
 
-        public render(customRenderFunction: (opaqueSubMeshes: SmartArray, transparentSubMeshes: SmartArray, alphaTestSubMeshes: SmartArray, beforeTransparents: () => void) => void,
+        public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents: () => void) => void,
             activeMeshes: Mesh[], renderParticles: boolean, renderSprites: boolean): void {
             for (var index = 0; index < BABYLON.RenderingManager.MAX_RENDERINGGROUPS; index++) {
                 this._depthBufferAlreadyCleaned = false;

+ 6 - 3
Babylon/Tools/babylon.sceneSerializer.js

@@ -692,10 +692,13 @@
             // Meshes
             serializationObject.meshes = [];
             for (index = 0; index < scene.meshes.length; index++) {
-                var mesh = scene.meshes[index];
+                var abstractMesh = scene.meshes[index];
 
-                if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) {
-                    serializationObject.meshes.push(serializeMesh(mesh, serializationObject));
+                if (abstractMesh instanceof BABYLON.Mesh) {
+                    var mesh = abstractMesh;
+                    if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) {
+                        serializationObject.meshes.push(serializeMesh(mesh, serializationObject));
+                    }
                 }
             }
 

+ 6 - 3
Babylon/Tools/babylon.sceneSerializer.ts

@@ -700,10 +700,13 @@
             // Meshes
             serializationObject.meshes = [];
             for (index = 0; index < scene.meshes.length; index++) {
-                var mesh = scene.meshes[index];
+                var abstractMesh = scene.meshes[index];
 
-                if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) {
-                    serializationObject.meshes.push(serializeMesh(mesh, serializationObject));
+                if (abstractMesh instanceof Mesh) {
+                    var mesh = <Mesh>abstractMesh;
+                    if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) {
+                        serializationObject.meshes.push(serializeMesh(mesh, serializationObject));
+                    }
                 }
             }
 

+ 4 - 4
Babylon/Tools/babylon.smartArray.ts

@@ -1,6 +1,6 @@
 module BABYLON {
-    export class SmartArray {
-        public data: Array<any>;
+    export class SmartArray<T> {
+        public data: Array<T>;
         public length: number = 0;
 
         constructor(capacity: number) {
@@ -30,7 +30,7 @@
             this.length = 0;
         }
 
-        public concat(array: SmartArray): void {
+        public concat(array: SmartArray<T>): void {
             if (array.length === 0) {
                 return;
             }
@@ -43,7 +43,7 @@
             }
         }
 
-        public concatWithNoDuplicate(array: SmartArray): void {
+        public concatWithNoDuplicate(array: SmartArray<T>): void {
             if (array.length === 0) {
                 return;
             }

+ 2 - 2
Babylon/Tools/babylon.tools.dds.ts

@@ -69,7 +69,7 @@
     var off_pfFourCC = 21;
 
     export class DDSTools {
-        public static GetDDSInfo(arrayBuffer): { width: number; height: number; mipmapCount: number } {
+        public static GetDDSInfo(arrayBuffer: any): { width: number; height: number; mipmapCount: number } {
             var header = new Int32Array(arrayBuffer, 0, headerLengthInt);
 
             var mipmapCount = 1;
@@ -84,7 +84,7 @@
             };
         }
 
-        public static UploadDDSLevels(gl, ext, arrayBuffer, loadMipmaps?: boolean): void {
+        public static UploadDDSLevels(gl: WebGLRenderingContext, ext: any, arrayBuffer: any, loadMipmaps?: boolean): void {
             var header = new Int32Array(arrayBuffer, 0, headerLengthInt),
                 fourCC, blockBytes, internalFormat,
                 width, height, dataLength, dataOffset,

+ 9 - 0
Babylon/Tools/babylon.tools.js

@@ -134,7 +134,14 @@
         };
 
         // External files
+        Tools.CleanUrl = function (url) {
+            url = url.replace(/#/mg, "%23");
+            return url;
+        };
+
         Tools.LoadImage = function (url, onload, onerror, database) {
+            url = Tools.CleanUrl(url);
+
             var img = new Image();
             img.crossOrigin = 'anonymous';
 
@@ -183,6 +190,8 @@
 
         //ANY
         Tools.LoadFile = function (url, callback, progressCallBack, database, useArrayBuffer) {
+            url = Tools.CleanUrl(url);
+
             var noIndexedDB = function () {
                 var request = new XMLHttpRequest();
                 var loadUrl = Tools.BaseUrl + url;

+ 312 - 0
Babylon/Tools/babylon.tools.tga.js

@@ -0,0 +1,312 @@
+/**
+* Based on jsTGALoader - Javascript loader for TGA file
+* By Vincent Thibault
+* @blog http://blog.robrowser.com/javascript-tga-loader.html
+*/
+var BABYLON;
+(function (BABYLON) {
+    (function (Internals) {
+        var TGATools = (function () {
+            function TGATools() {
+            }
+            TGATools.GetTGAHeader = function (data) {
+                var offset = 0;
+
+                var header = {
+                    id_length: data[offset++],
+                    colormap_type: data[offset++],
+                    image_type: data[offset++],
+                    colormap_index: data[offset++] | data[offset++] << 8,
+                    colormap_length: data[offset++] | data[offset++] << 8,
+                    colormap_size: data[offset++],
+                    origin: [
+                        data[offset++] | data[offset++] << 8,
+                        data[offset++] | data[offset++] << 8
+                    ],
+                    width: data[offset++] | data[offset++] << 8,
+                    height: data[offset++] | data[offset++] << 8,
+                    pixel_size: data[offset++],
+                    flags: data[offset++]
+                };
+
+                return header;
+            };
+
+            TGATools.UploadContent = function (gl, data) {
+                // Not enough data to contain header ?
+                if (data.length < 19) {
+                    BABYLON.Tools.Error("Unable to load TGA file - Not enough data to contain header");
+                    return;
+                }
+
+                // Read Header
+                var offset = 18;
+                var header = TGATools.GetTGAHeader(data);
+
+                // Assume it's a valid Targa file.
+                if (header.id_length + offset > data.length) {
+                    BABYLON.Tools.Error("Unable to load TGA file - Not enough data");
+                    return;
+                }
+
+                // Skip not needed data
+                offset += header.id_length;
+
+                var use_rle = false;
+                var use_pal = false;
+                var use_rgb = false;
+                var use_grey = false;
+
+                switch (header.image_type) {
+                    case TGATools._TYPE_RLE_INDEXED:
+                        use_rle = true;
+                    case TGATools._TYPE_INDEXED:
+                        use_pal = true;
+                        break;
+
+                    case TGATools._TYPE_RLE_RGB:
+                        use_rle = true;
+                    case TGATools._TYPE_RGB:
+                        use_rgb = true;
+                        break;
+
+                    case TGATools._TYPE_RLE_GREY:
+                        use_rle = true;
+                    case TGATools._TYPE_GREY:
+                        use_grey = true;
+                        break;
+                }
+
+                var pixel_data;
+
+                var numAlphaBits = header.flags & 0xf;
+                var pixel_size = header.pixel_size >> 3;
+                var pixel_total = header.width * header.height * pixel_size;
+
+                // Read palettes
+                var palettes;
+
+                if (use_pal) {
+                    palettes = data.subarray(offset, offset += header.colormap_length * pixel_size);
+                }
+
+                // Read LRE
+                if (use_rle) {
+                    pixel_data = new Uint8Array(pixel_total);
+
+                    var c, count, i;
+                    var localOffset = 0;
+                    var pixels = new Uint8Array(pixel_size);
+
+                    while (offset < pixel_total) {
+                        c = data[offset++];
+                        count = (c & 0x7f) + 1;
+
+                        // RLE pixels
+                        if (c & 0x80) {
+                            for (i = 0; i < pixel_size; ++i) {
+                                pixels[i] = data[offset++];
+                            }
+
+                            for (i = 0; i < count; ++i) {
+                                pixel_data.set(pixels, localOffset + i * pixel_size);
+                            }
+
+                            localOffset += pixel_size * count;
+                        } else {
+                            count *= pixel_size;
+                            for (i = 0; i < count; ++i) {
+                                pixel_data[localOffset + i] = data[offset++];
+                            }
+                            localOffset += count;
+                        }
+                    }
+                } else {
+                    pixel_data = data.subarray(offset, offset += (use_pal ? header.width * header.height : pixel_total));
+                }
+
+                // Load to texture
+                var x_start, y_start, x_step, y_step, y_end, x_end;
+
+                switch ((header.flags & TGATools._ORIGIN_MASK) >> TGATools._ORIGIN_SHIFT) {
+                    default:
+                    case TGATools._ORIGIN_UL:
+                        x_start = 0;
+                        x_step = 1;
+                        x_end = header.width;
+                        y_start = 0;
+                        y_step = 1;
+                        y_end = header.height;
+                        break;
+
+                    case TGATools._ORIGIN_BL:
+                        x_start = 0;
+                        x_step = 1;
+                        x_end = header.width;
+                        y_start = header.height - 1;
+                        y_step = -1;
+                        y_end = -1;
+                        break;
+
+                    case TGATools._ORIGIN_UR:
+                        x_start = header.width - 1;
+                        x_step = -1;
+                        x_end = -1;
+                        y_start = 0;
+                        y_step = 1;
+                        y_end = header.height;
+                        break;
+
+                    case TGATools._ORIGIN_BR:
+                        x_start = header.width - 1;
+                        x_step = -1;
+                        x_end = -1;
+                        y_start = header.height - 1;
+                        y_step = -1;
+                        y_end = -1;
+                        break;
+                }
+
+                // Load the specify method
+                var func = '_getImageData' + (use_grey ? 'Grey' : '') + (header.pixel_size) + 'bits';
+                var imageData = TGATools[func](header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end);
+
+                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, header.width, header.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
+            };
+
+            TGATools._getImageData8bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
+                var image = pixel_data, colormap = palettes;
+                var width = header.width, height = header.height;
+                var color, i = 0, x, y;
+
+                var imageData = new Uint8Array(width * height * 4);
+
+                for (y = y_start; y !== y_end; y += y_step) {
+                    for (x = x_start; x !== x_end; x += x_step, i++) {
+                        color = image[i];
+                        imageData[(x + width * y) * 4 + 3] = 255;
+                        imageData[(x + width * y) * 4 + 2] = colormap[(color * 3) + 0];
+                        imageData[(x + width * y) * 4 + 1] = colormap[(color * 3) + 1];
+                        imageData[(x + width * y) * 4 + 0] = colormap[(color * 3) + 2];
+                    }
+                }
+
+                return imageData;
+            };
+
+            TGATools._getImageData16bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
+                var image = pixel_data;
+                var width = header.width, height = header.height;
+                var color, i = 0, x, y;
+
+                var imageData = new Uint8Array(width * height * 4);
+
+                for (y = y_start; y !== y_end; y += y_step) {
+                    for (x = x_start; x !== x_end; x += x_step, i += 2) {
+                        color = image[i + 0] + (image[i + 1] << 8); // Inversed ?
+                        imageData[(x + width * y) * 4 + 0] = (color & 0x7C00) >> 7;
+                        imageData[(x + width * y) * 4 + 1] = (color & 0x03E0) >> 2;
+                        imageData[(x + width * y) * 4 + 2] = (color & 0x001F) >> 3;
+                        imageData[(x + width * y) * 4 + 3] = (color & 0x8000) ? 0 : 255;
+                    }
+                }
+
+                return imageData;
+            };
+
+            TGATools._getImageData24bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
+                var image = pixel_data;
+                var width = header.width, height = header.height;
+                var i = 0, x, y;
+
+                var imageData = new Uint8Array(width * height * 4);
+
+                for (y = y_start; y !== y_end; y += y_step) {
+                    for (x = x_start; x !== x_end; x += x_step, i += 3) {
+                        imageData[(x + width * y) * 4 + 3] = 255;
+                        imageData[(x + width * y) * 4 + 2] = image[i + 0];
+                        imageData[(x + width * y) * 4 + 1] = image[i + 1];
+                        imageData[(x + width * y) * 4 + 0] = image[i + 2];
+                    }
+                }
+
+                return imageData;
+            };
+
+            TGATools._getImageData32bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
+                var image = pixel_data;
+                var width = header.width, height = header.height;
+                var i = 0, x, y;
+
+                var imageData = new Uint8Array(width * height * 4);
+
+                for (y = y_start; y !== y_end; y += y_step) {
+                    for (x = x_start; x !== x_end; x += x_step, i += 4) {
+                        imageData[(x + width * y) * 4 + 2] = image[i + 0];
+                        imageData[(x + width * y) * 4 + 1] = image[i + 1];
+                        imageData[(x + width * y) * 4 + 0] = image[i + 2];
+                        imageData[(x + width * y) * 4 + 3] = image[i + 3];
+                    }
+                }
+
+                return imageData;
+            };
+
+            TGATools._getImageDataGrey8bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
+                var image = pixel_data;
+                var width = header.width, height = header.height;
+                var color, i = 0, x, y;
+
+                var imageData = new Uint8Array(width * height * 4);
+
+                for (y = y_start; y !== y_end; y += y_step) {
+                    for (x = x_start; x !== x_end; x += x_step, i++) {
+                        color = image[i];
+                        imageData[(x + width * y) * 4 + 0] = color;
+                        imageData[(x + width * y) * 4 + 1] = color;
+                        imageData[(x + width * y) * 4 + 2] = color;
+                        imageData[(x + width * y) * 4 + 3] = 255;
+                    }
+                }
+
+                return imageData;
+            };
+
+            TGATools._getImageDataGrey16bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
+                var image = pixel_data;
+                var width = header.width, height = header.height;
+                var i = 0, x, y;
+
+                var imageData = new Uint8Array(width * height * 4);
+
+                for (y = y_start; y !== y_end; y += y_step) {
+                    for (x = x_start; x !== x_end; x += x_step, i += 2) {
+                        imageData[(x + width * y) * 4 + 0] = image[i + 0];
+                        imageData[(x + width * y) * 4 + 1] = image[i + 0];
+                        imageData[(x + width * y) * 4 + 2] = image[i + 0];
+                        imageData[(x + width * y) * 4 + 3] = image[i + 1];
+                    }
+                }
+
+                return imageData;
+            };
+            TGATools._TYPE_NO_DATA = 0;
+            TGATools._TYPE_INDEXED = 1;
+            TGATools._TYPE_RGB = 2;
+            TGATools._TYPE_GREY = 3;
+            TGATools._TYPE_RLE_INDEXED = 9;
+            TGATools._TYPE_RLE_RGB = 10;
+            TGATools._TYPE_RLE_GREY = 11;
+            TGATools._ORIGIN_MASK = 0x30;
+            TGATools._ORIGIN_SHIFT = 0x04;
+            TGATools._ORIGIN_BL = 0x00;
+            TGATools._ORIGIN_BR = 0x01;
+            TGATools._ORIGIN_UL = 0x02;
+            TGATools._ORIGIN_UR = 0x03;
+            return TGATools;
+        })();
+        Internals.TGATools = TGATools;
+    })(BABYLON.Internals || (BABYLON.Internals = {}));
+    var Internals = BABYLON.Internals;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.tools.tga.js.map

+ 318 - 0
Babylon/Tools/babylon.tools.tga.ts

@@ -0,0 +1,318 @@
+/**
+* Based on jsTGALoader - Javascript loader for TGA file
+* By Vincent Thibault
+* @blog http://blog.robrowser.com/javascript-tga-loader.html
+*/
+
+module BABYLON.Internals {
+    export class TGATools {
+
+        private static _TYPE_NO_DATA = 0;
+        private static _TYPE_INDEXED = 1;
+        private static _TYPE_RGB = 2;
+        private static _TYPE_GREY = 3;
+        private static _TYPE_RLE_INDEXED = 9;
+        private static _TYPE_RLE_RGB = 10;
+        private static _TYPE_RLE_GREY = 11;
+        private static _ORIGIN_MASK = 0x30;
+        private static _ORIGIN_SHIFT = 0x04;
+        private static _ORIGIN_BL = 0x00;
+        private static _ORIGIN_BR = 0x01;
+        private static _ORIGIN_UL = 0x02;
+        private static _ORIGIN_UR = 0x03;
+
+        public static GetTGAHeader(data: Uint8Array): any {
+            var offset = 0;
+
+            var header = {
+                id_length: data[offset++],
+                colormap_type: data[offset++],
+                image_type: data[offset++],
+                colormap_index: data[offset++] | data[offset++] << 8,
+                colormap_length: data[offset++] | data[offset++] << 8,
+                colormap_size: data[offset++],
+                origin: [
+                    data[offset++] | data[offset++] << 8,
+                    data[offset++] | data[offset++] << 8
+                ],
+                width: data[offset++] | data[offset++] << 8,
+                height: data[offset++] | data[offset++] << 8,
+                pixel_size: data[offset++],
+                flags: data[offset++]
+            };
+
+            return header;
+        }
+
+        public static UploadContent(gl: WebGLRenderingContext, data: Uint8Array): void {
+            // Not enough data to contain header ?
+            if (data.length < 19) {
+                Tools.Error("Unable to load TGA file - Not enough data to contain header");
+                return;
+            }
+
+            // Read Header
+            var offset = 18;
+            var header = TGATools.GetTGAHeader(data);
+
+            // Assume it's a valid Targa file.
+            if (header.id_length + offset > data.length) {
+                Tools.Error("Unable to load TGA file - Not enough data");
+                return;
+            }
+
+            // Skip not needed data
+            offset += header.id_length;
+
+            var use_rle = false;
+            var use_pal = false;
+            var use_rgb = false;
+            var use_grey = false;
+
+            // Get some informations.
+            switch (header.image_type) {
+                case TGATools._TYPE_RLE_INDEXED:
+                    use_rle = true;
+                case TGATools._TYPE_INDEXED:
+                    use_pal = true;
+                    break;
+
+                case TGATools._TYPE_RLE_RGB:
+                    use_rle = true;
+                case TGATools._TYPE_RGB:
+                    use_rgb = true;
+                    break;
+
+                case TGATools._TYPE_RLE_GREY:
+                    use_rle = true;
+                case TGATools._TYPE_GREY:
+                    use_grey = true;
+                    break;
+            }
+
+            var pixel_data;
+
+            var numAlphaBits = header.flags & 0xf;
+            var pixel_size = header.pixel_size >> 3;
+            var pixel_total = header.width * header.height * pixel_size;
+
+            // Read palettes
+            var palettes;
+
+            if (use_pal) {
+                palettes = data.subarray(offset, offset += header.colormap_length * pixel_size);
+            }
+
+            // Read LRE
+            if (use_rle) {
+                pixel_data = new Uint8Array(pixel_total);
+
+                var c, count, i;
+                var localOffset = 0;
+                var pixels = new Uint8Array(pixel_size);
+
+                while (offset < pixel_total) {
+                    c = data[offset++];
+                    count = (c & 0x7f) + 1;
+
+                    // RLE pixels
+                    if (c & 0x80) {
+                        // Bind pixel tmp array
+                        for (i = 0; i < pixel_size; ++i) {
+                            pixels[i] = data[offset++];
+                        }
+
+                        // Copy pixel array
+                        for (i = 0; i < count; ++i) {
+                            pixel_data.set(pixels, localOffset + i * pixel_size);
+                        }
+
+                        localOffset += pixel_size * count;
+                    }
+                    // Raw pixels
+                    else {
+                        count *= pixel_size;
+                        for (i = 0; i < count; ++i) {
+                            pixel_data[localOffset + i] = data[offset++];
+                        }
+                        localOffset += count;
+                    }
+                }
+            }
+            // RAW Pixels
+            else {
+                pixel_data = data.subarray(
+                    offset,
+                    offset += (use_pal ? header.width * header.height : pixel_total)
+                    );
+            }
+
+            // Load to texture
+            var x_start, y_start, x_step, y_step, y_end, x_end;
+
+            switch ((header.flags & TGATools._ORIGIN_MASK) >> TGATools._ORIGIN_SHIFT) {
+                default:
+                case TGATools._ORIGIN_UL:
+                    x_start = 0;
+                    x_step = 1;
+                    x_end = header.width;
+                    y_start = 0;
+                    y_step = 1;
+                    y_end = header.height;
+                    break;
+
+                case TGATools._ORIGIN_BL:
+                    x_start = 0;
+                    x_step = 1;
+                    x_end = header.width;
+                    y_start = header.height - 1;
+                    y_step = -1;
+                    y_end = -1;
+                    break;
+
+                case TGATools._ORIGIN_UR:
+                    x_start = header.width - 1;
+                    x_step = -1;
+                    x_end = -1;
+                    y_start = 0;
+                    y_step = 1;
+                    y_end = header.height;
+                    break;
+
+                case TGATools._ORIGIN_BR:
+                    x_start = header.width - 1;
+                    x_step = -1;
+                    x_end = -1;
+                    y_start = header.height - 1;
+                    y_step = -1;
+                    y_end = -1;
+                    break;
+            }
+
+            // Load the specify method
+            var func = '_getImageData' + (use_grey ? 'Grey' : '') + (header.pixel_size) + 'bits';
+            var imageData = TGATools[func](header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end);
+
+            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, header.width, header.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
+
+        }
+
+        static _getImageData8bits(header: any, palettes: Uint8Array, pixel_data: Uint8Array, y_start: number, y_step: number, y_end: number, x_start: number, x_step: number, x_end: number): Uint8Array {
+            var image = pixel_data, colormap = palettes;
+            var width = header.width, height = header.height;
+            var color, i = 0, x, y;
+
+            var imageData = new Uint8Array(width * height * 4);
+
+            for (y = y_start; y !== y_end; y += y_step) {
+                for (x = x_start; x !== x_end; x += x_step, i++) {
+                    color = image[i];
+                    imageData[(x + width * y) * 4 + 3] = 255;
+                    imageData[(x + width * y) * 4 + 2] = colormap[(color * 3) + 0];
+                    imageData[(x + width * y) * 4 + 1] = colormap[(color * 3) + 1];
+                    imageData[(x + width * y) * 4 + 0] = colormap[(color * 3) + 2];
+                }
+            }
+
+            return imageData;
+        }
+
+        static _getImageData16bits(header: any, palettes: Uint8Array, pixel_data: Uint8Array, y_start: number, y_step: number, y_end: number, x_start: number, x_step: number, x_end: number): Uint8Array {
+            var image = pixel_data;
+            var width = header.width, height = header.height;
+            var color, i = 0, x, y;
+
+            var imageData = new Uint8Array(width * height * 4);
+
+            for (y = y_start; y !== y_end; y += y_step) {
+                for (x = x_start; x !== x_end; x += x_step, i += 2) {
+                    color = image[i + 0] + (image[i + 1] << 8); // Inversed ?
+                    imageData[(x + width * y) * 4 + 0] = (color & 0x7C00) >> 7;
+                    imageData[(x + width * y) * 4 + 1] = (color & 0x03E0) >> 2;
+                    imageData[(x + width * y) * 4 + 2] = (color & 0x001F) >> 3;
+                    imageData[(x + width * y) * 4 + 3] = (color & 0x8000) ? 0 : 255;
+                }
+            }
+
+            return imageData;
+        }
+
+        static _getImageData24bits(header: any, palettes: Uint8Array, pixel_data: Uint8Array, y_start: number, y_step: number, y_end: number, x_start: number, x_step: number, x_end: number): Uint8Array {
+            var image = pixel_data;
+            var width = header.width, height = header.height;
+            var i = 0, x, y;
+
+            var imageData = new Uint8Array(width * height * 4);
+
+            for (y = y_start; y !== y_end; y += y_step) {
+                for (x = x_start; x !== x_end; x += x_step, i += 3) {
+                    imageData[(x + width * y) * 4 + 3] = 255;
+                    imageData[(x + width * y) * 4 + 2] = image[i + 0];
+                    imageData[(x + width * y) * 4 + 1] = image[i + 1];
+                    imageData[(x + width * y) * 4 + 0] = image[i + 2];
+                }
+            }
+
+            return imageData;
+        }
+
+        static _getImageData32bits(header: any, palettes: Uint8Array, pixel_data: Uint8Array, y_start: number, y_step: number, y_end: number, x_start: number, x_step: number, x_end: number): Uint8Array {
+            var image = pixel_data;
+            var width = header.width, height = header.height;
+            var i = 0, x, y;
+
+            var imageData = new Uint8Array(width * height * 4);
+
+            for (y = y_start; y !== y_end; y += y_step) {
+                for (x = x_start; x !== x_end; x += x_step, i += 4) {
+                    imageData[(x + width * y) * 4 + 2] = image[i + 0];
+                    imageData[(x + width * y) * 4 + 1] = image[i + 1];
+                    imageData[(x + width * y) * 4 + 0] = image[i + 2];
+                    imageData[(x + width * y) * 4 + 3] = image[i + 3];
+                }
+            }
+
+            return imageData;
+        }
+
+        static _getImageDataGrey8bits(header: any, palettes: Uint8Array, pixel_data: Uint8Array, y_start: number, y_step: number, y_end: number, x_start: number, x_step: number, x_end: number): Uint8Array {
+            var image = pixel_data;
+            var width = header.width, height = header.height;
+            var color, i = 0, x, y;
+
+            var imageData = new Uint8Array(width * height * 4);
+
+            for (y = y_start; y !== y_end; y += y_step) {
+                for (x = x_start; x !== x_end; x += x_step, i++) {
+                    color = image[i];
+                    imageData[(x + width * y) * 4 + 0] = color;
+                    imageData[(x + width * y) * 4 + 1] = color;
+                    imageData[(x + width * y) * 4 + 2] = color;
+                    imageData[(x + width * y) * 4 + 3] = 255;
+                }
+            }
+
+            return imageData;
+        }
+
+        static _getImageDataGrey16bits(header: any, palettes: Uint8Array, pixel_data: Uint8Array, y_start: number, y_step: number, y_end: number, x_start: number, x_step: number, x_end: number): Uint8Array {
+            var image = pixel_data;
+            var width = header.width, height = header.height;
+            var i = 0, x, y;
+
+            var imageData = new Uint8Array(width * height * 4);
+
+            for (y = y_start; y !== y_end; y += y_step) {
+                for (x = x_start; x !== x_end; x += x_step, i += 2) {
+                    imageData[(x + width * y) * 4 + 0] = image[i + 0];
+                    imageData[(x + width * y) * 4 + 1] = image[i + 0];
+                    imageData[(x + width * y) * 4 + 2] = image[i + 0];
+                    imageData[(x + width * y) * 4 + 3] = image[i + 1];
+                }
+            }
+
+            return imageData;
+        }
+
+    }
+} 

+ 9 - 0
Babylon/Tools/babylon.tools.ts

@@ -148,7 +148,14 @@
         }
 
         // External files
+        public static CleanUrl(url: string): string {
+            url = url.replace(/#/mg, "%23");
+            return url;
+        }
+
         public static LoadImage(url: string, onload, onerror, database): HTMLImageElement {
+            url = Tools.CleanUrl(url);
+
             var img = new Image();
             img.crossOrigin = 'anonymous';
 
@@ -202,6 +209,8 @@
 
         //ANY
         public static LoadFile(url: string, callback: (data: any) => void, progressCallBack?: () => void, database?, useArrayBuffer?: boolean): void {
+            url = Tools.CleanUrl(url);
+
             var noIndexedDB = () => {
                 var request = new XMLHttpRequest();
                 var loadUrl = Tools.BaseUrl + url;

+ 14 - 2
Babylon/babylon.engine.js

@@ -809,7 +809,9 @@
             var _this = this;
             var texture = this._gl.createTexture();
 
-            var isDDS = this.getCaps().s3tc && (url.substr(url.length - 4, 4).toLowerCase() === ".dds");
+            var extension = url.substr(url.length - 4, 4).toLowerCase();
+            var isDDS = this.getCaps().s3tc && (extension === ".dds");
+            var isTGA = (extension === ".tga");
 
             scene._addPendingData(texture);
             texture.url = url;
@@ -817,7 +819,17 @@
             texture.references = 1;
             this._loadedTexturesCache.push(texture);
 
-            if (isDDS) {
+            if (isTGA) {
+                BABYLON.Tools.LoadFile(url, function (arrayBuffer) {
+                    var data = new Uint8Array(arrayBuffer);
+
+                    var header = BABYLON.Internals.TGATools.GetTGAHeader(data);
+
+                    prepareWebGLTexture(texture, _this._gl, scene, header.width, header.height, invertY, noMipmap, false, function () {
+                        BABYLON.Internals.TGATools.UploadContent(_this._gl, data);
+                    });
+                }, null, scene.database, true);
+            } else if (isDDS) {
                 BABYLON.Tools.LoadFile(url, function (data) {
                     var info = BABYLON.Internals.DDSTools.GetDDSInfo(data);
 

+ 14 - 2
Babylon/babylon.engine.ts

@@ -841,7 +841,9 @@
         public createTexture(url: string, noMipmap: boolean, invertY: boolean, scene: Scene): WebGLTexture {
             var texture = this._gl.createTexture();
 
-            var isDDS = this.getCaps().s3tc && (url.substr(url.length - 4, 4).toLowerCase() === ".dds");
+            var extension = url.substr(url.length - 4, 4).toLowerCase();
+            var isDDS = this.getCaps().s3tc && (extension === ".dds");
+            var isTGA = (extension === ".tga");
 
             scene._addPendingData(texture);
             texture.url = url;
@@ -849,7 +851,17 @@
             texture.references = 1;
             this._loadedTexturesCache.push(texture);
 
-            if (isDDS) {
+            if (isTGA) {
+                BABYLON.Tools.LoadFile(url, arrayBuffer => {
+                    var data = new Uint8Array(arrayBuffer);
+
+                    var header = BABYLON.Internals.TGATools.GetTGAHeader(data);
+
+                    prepareWebGLTexture(texture, this._gl, scene, header.width, header.height, invertY, noMipmap, false, () => {
+                        Internals.TGATools.UploadContent(this._gl, data);
+                    });
+                }, null, scene.database, true);
+            } else if (isDDS) {
                 BABYLON.Tools.LoadFile(url, data => {
                     var info = BABYLON.Internals.DDSTools.GetDDSInfo(data);
 

+ 1 - 1
Babylon/babylon.node.js

@@ -83,7 +83,7 @@
         };
 
         Node.prototype.isEnabled = function () {
-            if (!this.isReady() || !this._isEnabled) {
+            if (!this._isEnabled) {
                 return false;
             }
 

+ 1 - 1
Babylon/babylon.node.ts

@@ -92,7 +92,7 @@
         }
 
         public isEnabled(): boolean {
-            if (!this.isReady() || !this._isEnabled) {
+            if (!this._isEnabled) {
                 return false;
             }
 

+ 10 - 4
Babylon/babylon.scene.js

@@ -219,14 +219,14 @@
                 }
             }
 
-            for (var index = 0; index < this.meshes.length; index++) {
+            for (index = 0; index < this.meshes.length; index++) {
                 var mesh = this.meshes[index];
-                var mat = mesh.material;
 
-                if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                if (!mesh.isReady()) {
                     return false;
                 }
 
+                var mat = mesh.material;
                 if (mat) {
                     if (!mat.isReady(mesh)) {
                         return false;
@@ -597,6 +597,11 @@
                     this._activeVertices += subMesh.verticesCount;
                     this._renderingManager.dispatch(subMesh);
                 }
+
+                if (mesh instanceof BABYLON.InstancedMesh) {
+                    var instance = mesh;
+                    instance.sourceMesh._visibleInstances.pushNoDuplicate(instance);
+                }
             }
         };
 
@@ -679,6 +684,7 @@
 
                     if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && mesh.isInFrustum(this._frustumPlanes)) {
                         this._activeMeshes.push(mesh);
+                        mesh._activate(this._renderId);
 
                         if (mesh.skeleton) {
                             this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
@@ -1088,7 +1094,7 @@
                 var ray = rayFunction(world);
 
                 var result = mesh.intersects(ray, fastCheck);
-                if (!result.hit)
+                if (!result || !result.hit)
                     continue;
 
                 if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)

+ 31 - 20
Babylon/babylon.scene.ts

@@ -15,6 +15,10 @@
             max.z = v.z;
     };
 
+    export interface IDisposable {
+        dispose(): void;
+    }
+
     export class Scene {
         // Statics
         public static FOGMODE_NONE = 0;
@@ -28,7 +32,7 @@
         public ambientColor = new BABYLON.Color3(0, 0, 0);
         public beforeRender: () => void;
         public afterRender: () => void;
-        public beforeCameraRender: (camera:Camera) => void;
+        public beforeCameraRender: (camera: Camera) => void;
         public afterCameraRender: (camera: Camera) => void;
         public forceWireframe = false;
         public clipPlane: Plane;
@@ -55,7 +59,7 @@
         public activeCamera: Camera;
 
         // Meshes
-        public meshes = new Array<Mesh>();
+        public meshes = new Array<AbstractMesh>();
 
         // Geometries
         private _geometries = new Array<Geometry>();
@@ -125,18 +129,18 @@
         private _renderId = 0;
         private _executeWhenReadyTimeoutId = -1;
 
-        public _toBeDisposed = new SmartArray(256);
+        public _toBeDisposed = new SmartArray<IDisposable>(256);
 
         private _onReadyCallbacks = new Array<() => void>();
         private _pendingData = [];//ANY
 
         private _onBeforeRenderCallbacks = new Array<() => void>();
 
-        private _activeMeshes = new SmartArray(256);
-        private _processedMaterials = new SmartArray(256);
-        private _renderTargets = new SmartArray(256);
-        public _activeParticleSystems = new SmartArray(256);
-        private _activeSkeletons = new SmartArray(32);
+        private _activeMeshes = new SmartArray<Mesh>(256);
+        private _processedMaterials = new SmartArray<Material>(256);
+        private _renderTargets = new SmartArray<RenderTargetTexture>(256);
+        public _activeParticleSystems = new SmartArray<ParticleSystem>(256);
+        private _activeSkeletons = new SmartArray<Skeleton>(32);
 
         private _renderingManager: RenderingManager;
         private _physicsEngine: PhysicsEngine;
@@ -204,7 +208,7 @@
             return this._evaluateActiveMeshesDuration;
         }
 
-        public getActiveMeshes(): SmartArray {
+        public getActiveMeshes(): SmartArray<Mesh> {
             return this._activeMeshes;
         }
 
@@ -287,19 +291,20 @@
                 }
             }
 
-            for (var index = 0; index < this.meshes.length; index++) {
+            for (index = 0; index < this.meshes.length; index++) {
                 var mesh = this.meshes[index];
-                var mat = mesh.material;
-
-                if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                
+                if (!mesh.isReady()) {
                     return false;
                 }
 
+                var mat = mesh.material;
                 if (mat) {
                     if (!mat.isReady(mesh)) {
                         return false;
                     }
                 }
+
             }
 
             return true;
@@ -558,7 +563,7 @@
             return this._geometries;
         }
 
-        public getMeshByID(id: string): Mesh {
+        public getMeshByID(id: string): AbstractMesh {
             for (var index = 0; index < this.meshes.length; index++) {
                 if (this.meshes[index].id === id) {
                     return this.meshes[index];
@@ -568,7 +573,7 @@
             return null;
         }
 
-        public getLastMeshByID(id: string): Mesh {
+        public getLastMeshByID(id: string): AbstractMesh {
             for (var index = this.meshes.length - 1; index >= 0; index--) {
                 if (this.meshes[index].id === id) {
                     return this.meshes[index];
@@ -600,7 +605,7 @@
             return null;
         }
 
-        public getMeshByName(name: string): Mesh {
+        public getMeshByName(name: string): AbstractMesh {
             for (var index = 0; index < this.meshes.length; index++) {
                 if (this.meshes[index].name === name) {
                     return this.meshes[index];
@@ -644,7 +649,7 @@
             return (this._activeMeshes.indexOf(mesh) !== -1);
         }
 
-        private _evaluateSubMesh(subMesh: SubMesh, mesh: Mesh): void {
+        private _evaluateSubMesh(subMesh: SubMesh, mesh: AbstractMesh): void {
             if (mesh.subMeshes.length == 1 || subMesh.isInFrustum(this._frustumPlanes)) {
                 var material = subMesh.getMaterial();
 
@@ -662,6 +667,11 @@
                     this._activeVertices += subMesh.verticesCount;
                     this._renderingManager.dispatch(subMesh);
                 }
+
+                if (mesh instanceof InstancedMesh) {
+                    var instance = <InstancedMesh>mesh;
+                    instance.sourceMesh._visibleInstances.pushNoDuplicate(instance);
+                }
             }
         }
 
@@ -744,6 +754,7 @@
 
                     if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && mesh.isInFrustum(this._frustumPlanes)) {
                         this._activeMeshes.push(mesh);
+                        mesh._activate(this._renderId);
 
                         if (mesh.skeleton) {
                             this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
@@ -1150,7 +1161,7 @@
             return BABYLON.Ray.CreateNew(x, y, viewport.width, viewport.height, world ? world : BABYLON.Matrix.Identity(), camera.getViewMatrix(), camera.getProjectionMatrix());
         }
 
-        private _internalPick(rayFunction: (world: Matrix) => Ray, predicate: (mesh: Mesh) => boolean, fastCheck?: boolean): PickingInfo {
+        private _internalPick(rayFunction: (world: Matrix) => Ray, predicate: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): PickingInfo {
             var pickingInfo = null;
 
             for (var meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) {
@@ -1168,7 +1179,7 @@
                 var ray = rayFunction(world);
 
                 var result = mesh.intersects(ray, fastCheck);
-                if (!result.hit)
+                if (! result || !result.hit)
                     continue;
 
                 if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)
@@ -1228,7 +1239,7 @@
             return this._physicsEngine;
         }
 
-        public enablePhysics(gravity: Vector3, plugin?: PhysicsEnginePlugin): boolean {
+        public enablePhysics(gravity: Vector3, plugin?: IPhysicsEnginePlugin): boolean {
             if (this._physicsEngine) {
                 return true;
             }

+ 4 - 0
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml

@@ -60,6 +60,8 @@
   <script src="Babylon/Materials/textures/babylon.baseTexture.js"></script>
   <script src="Babylon/Mesh/babylon.subMesh.js"></script>
   <script src="Babylon/Mesh/babylon.mesh.js"></script>
+  <script src="Babylon/Mesh/babylon.InstancedMesh.js"></script>
+  <script src="Babylon/Mesh/babylon.AbstractMesh.js"></script>
   <script src="Babylon/Mesh/babylon.geometry.js"></script>
   <script src="Babylon/Mesh/babylon.mesh.vertexData.js"></script>
   <script src="Babylon/Mesh/babylon.vertexBuffer.js"></script>
@@ -91,6 +93,8 @@
   <script src="Babylon/Tools/babylon.tags.js"></script>
   <script src="Babylon/Tools/babylon.andOrNotEvaluator.js"></script>
   <script src="Babylon/Tools/babylon.smartArray.js"></script>
+  <script src="Babylon/Tools/babylon.tools.tga.js"></script>
+  <script src="Babylon/Tools/babylon.tools.dds.js"></script>
   <script src="Babylon/Tools/babylon.tools.js"></script>
   <script src="Babylon/babylon.node.js"></script>
 </files>

File diff suppressed because it is too large
+ 11 - 11
babylon.1.12-beta.js