소스 검색

Merge pull request #192 from gwenael-hagenmuller/geometry

Geometry system
deltakosh 11 년 전
부모
커밋
5ace0e2027

+ 1 - 1
Babylon/Culling/babylon.boundingBox.js

@@ -144,4 +144,4 @@
     })();
     BABYLON.BoundingBox = BoundingBox;
 })(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.boundingBox.js.map
+//# sourceMappingURL=babylon.BoundingBox.js.map

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

@@ -352,6 +352,148 @@ var BABYLON = BABYLON || {};
         return camera;
     };
 
+    var parseGeometry = function (parsedGeometry, scene) {
+        var id = parsedGeometry.id;
+        return scene.getGeometryByID(id);
+    };
+
+    var parseBox = function (parsedBox, scene) {
+        if (parseGeometry(parsedBox, scene)) {
+            return null; // null since geometry could be something else than a box...
+        }
+
+        var box = new BABYLON.Geometry.Primitives.Box(parsedBox.id, scene.getEngine(), parsedBox.size, parsedBox.canBeRegenerated, null);
+        BABYLON.Tags.AddTagsTo(box, parsedBox.tags);
+
+        scene.pushGeometry(box, true);
+
+        return box;
+    };
+
+    var parseSphere = function (parsedSphere, scene) {
+        if (parseGeometry(parsedSphere, scene)) {
+            return null; // null since geometry could be something else than a sphere...
+        }
+
+        var sphere = new BABYLON.Geometry.Primitives.Sphere(parsedSphere.id, scene.getEngine(), parsedSphere.segments, parsedSphere.diameter, parsedSphere.canBeRegenerated, null);
+        BABYLON.Tags.AddTagsTo(sphere, parsedSphere.tags);
+
+        scene.pushGeometry(sphere, true);
+
+        return sphere;
+    };
+
+    var parseCylinder = function (parsedCylinder, scene) {
+        if (parseGeometry(parsedCylinder, scene)) {
+            return null; // null since geometry could be something else than a cylinder...
+        }
+
+        var cylinder = new BABYLON.Geometry.Primitives.Cylinder(parsedCylinder.id, scene.getEngine(), parsedCylinder.height, parsedCylinder.diameterTop, parsedCylinder.diameterBottom, parsedCylinder.tessellation, parsedCylinder.canBeRegenerated, null);
+        BABYLON.Tags.AddTagsTo(cylinder, parsedCylinder.tags);
+
+        scene.pushGeometry(cylinder, true);
+
+        return cylinder;
+    };
+
+    var parseTorus = function (parsedTorus, scene) {
+        if (parseGeometry(parsedTorus, scene)) {
+            return null; // null since geometry could be something else than a torus...
+        }
+
+        var torus = new BABYLON.Geometry.Primitives.Torus(parsedTorus.id, scene.getEngine(), parsedTorus.diameter, parsedTorus.thickness, parsedTorus.tessellation, parsedTorus.canBeRegenerated, null);
+        BABYLON.Tags.AddTagsTo(torus, parsedTorus.tags);
+
+        scene.pushGeometry(torus, true);
+
+        return torus;
+    };
+
+    var parseGround = function (parsedGround, scene) {
+        if (parseGeometry(parsedGround, scene)) {
+            return null; // null since geometry could be something else than a ground...
+        }
+
+        var ground = new BABYLON.Geometry.Primitives.Ground(parsedGround.id, scene.getEngine(), parsedGround.width, parsedGround.height, parsedGround.subdivisions, parsedGround.canBeRegenerated, null);
+        BABYLON.Tags.AddTagsTo(ground, parsedGround.tags);
+
+        scene.pushGeometry(ground, true);
+
+        return ground;
+    };
+
+    var parsePlane = function (parsedPlane, scene) {
+        if (parseGeometry(parsedPlane, scene)) {
+            return null; // null since geometry could be something else than a plane...
+        }
+
+        var plane = new BABYLON.Geometry.Primitives.Plane(parsedPlane.id, scene.getEngine(), parsedPlane.size, parsedPlane.canBeRegenerated, null);
+        BABYLON.Tags.AddTagsTo(plane, parsedPlane.tags);
+
+        scene.pushGeometry(plane, true);
+
+        return plane;
+    };
+
+    var parseTorusKnot = function (parsedTorusKnot, scene) {
+        if (parseGeometry(parsedTorusKnot, scene)) {
+            return null; // null since geometry could be something else than a torusKnot...
+        }
+
+        var torusKnot = new BABYLON.Geometry.Primitives.TorusKnot(parsedTorusKnot.id, scene.getEngine(), parsedTorusKnot.radius, parsedTorusKnot.tube, parsedTorusKnot.radialSegments, parsedTorusKnot.tubularSegments, parsedTorusKnot.p, parsedTorusKnot.q, parsedTorusKnot.canBeRegenerated, null);
+        BABYLON.Tags.AddTagsTo(torusKnot, parsedTorusKnot.tags);
+
+        scene.pushGeometry(torusKnot, true);
+
+        return torusKnot;
+    };
+
+    var parseVertexData = function (parsedVertexData, scene, rootUrl) {
+        if (parseGeometry(parsedVertexData, scene)) {
+            return null; // null since geometry could be a primitive
+        }
+
+        var geometry = new BABYLON.Geometry(parsedVertexData.id, scene.getEngine());
+
+        BABYLON.Tags.AddTagsTo(geometry, parsedVertexData.tags);
+
+        if (parsedVertexData.delayLoadingFile) {
+            geometry.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NOTLOADED;
+            geometry.delayLoadingFile = rootUrl + parsedVertexData.delayLoadingFile;
+            geometry._boundingInfo = new BABYLON.BoundingInfo(BABYLON.Vector3.FromArray(parsedVertexData.boundingBoxMinimum), BABYLON.Vector3.FromArray(parsedVertexData.boundingBoxMaximum));
+
+            geometry._delayInfo = [];
+            if (parsedVertexData.hasUVs) {
+                geometry._delayInfo.push(BABYLON.VertexBuffer.UVKind);
+            }
+
+            if (parsedVertexData.hasUVs2) {
+                geometry._delayInfo.push(BABYLON.VertexBuffer.UV2Kind);
+            }
+
+            if (parsedVertexData.hasColors) {
+                geometry._delayInfo.push(BABYLON.VertexBuffer.ColorKind);
+            }
+
+            if (parsedVertexData.hasMatricesIndices) {
+                geometry._delayInfo.push(BABYLON.VertexBuffer.MatricesIndicesKind);
+            }
+
+            if (parsedVertexData.hasMatricesWeights) {
+                geometry._delayInfo.push(BABYLON.VertexBuffer.MatricesWeightsKind);
+            }
+
+            geometry._delayLoadingFunction = importVertexData;
+
+        } else {
+            importVertexData(parsedVertexData, geometry);
+        }
+
+        scene.pushGeometry(geometry, true);
+
+        return geometry;
+    };
+
     var parseMesh = function (parsedMesh, scene, rootUrl) {
         var mesh = new BABYLON.Mesh(parsedMesh.name, scene);
         mesh.id = parsedMesh.id;
@@ -489,9 +631,73 @@ var BABYLON = BABYLON || {};
         return false;
     };
 
+    var importVertexData = function (parsedVertexData, geometry) {
+        var vertexData = new BABYLON.VertexData();
+
+        // positions
+        var positions = parsedVertexData.positions;
+        if (positions) {
+            vertexData.set(positions, BABYLON.VertexBuffer.PositionKind);
+        }
+
+        // normals
+        var normals = parsedVertexData.normals;
+        if (normals) {
+            vertexData.set(normals, BABYLON.VertexBuffer.NormalKind);
+        }
+
+        // uvs
+        var uvs = parsedVertexData.uvs;
+        if (uvs) {
+            vertexData.set(uvs, BABYLON.VertexBuffer.UVKind);
+        }
+
+        // uv2s
+        var uv2s = parsedVertexData.uv2s;
+        if (uv2s) {
+            vertexData.set(uv2s, BABYLON.VertexBuffer.UV2Kind);
+        }
+
+        // colors
+        var colors = parsedVertexData.colors;
+        if (colors) {
+            vertexData.set(colors, BABYLON.VertexBuffer.ColorKind);
+        }
+
+        // matricesIndices
+        var matricesIndices = parsedVertexData.matricesIndices;
+        if (matricesIndices) {
+            vertexData.set(matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind);
+        }
+
+        // matricesWeights
+        var matricesWeights = parsedVertexData.matricesWeights;
+        if (matricesWeights) {
+            vertexData.set(matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind);
+        }
+
+        // indices
+        var indices = parsedVertexData.indices;
+        if (indices) {
+            vertexData.indices = indices;
+        }
+
+        geometry.setAllVerticesData(vertexData, parsedVertexData.updatable);
+    };
+
     var importGeometry = function (parsedGeometry, mesh) {
+        var scene = mesh.getScene();
+
         // Geometry
-        if (parsedGeometry.positions && parsedGeometry.normals && parsedGeometry.indices) {
+        var geometryId = parsedGeometry.geometryId;
+        if (geometryId) {
+            var geometry = scene.getGeometryByID(geometryId);
+            if (geometry) {
+                geometry.applyToMesh(mesh);
+            }
+        }
+
+        else if (parsedGeometry.positions && parsedGeometry.normals && parsedGeometry.indices) {
             mesh.setVerticesData(parsedGeometry.positions, BABYLON.VertexBuffer.PositionKind, false);
             mesh.setVerticesData(parsedGeometry.normals, BABYLON.VertexBuffer.NormalKind, false);
 
@@ -553,7 +759,6 @@ var BABYLON = BABYLON || {};
             delete mesh._shouldGenerateFlatShading;
         }
 
-        var scene = mesh.getScene();
         if (scene._selectionOctree) {
             scene._selectionOctree.addMesh(mesh);
         }
@@ -696,6 +901,82 @@ var BABYLON = BABYLON || {};
                 }
             }
 
+            // Geometries
+            var geometries = parsedData.geometries;
+            if (geometries) {
+                // Boxes
+                var boxes = geometries.boxes;
+                if (boxes) {
+                    for (var index = 0; index < boxes.length; index++) {
+                        var parsedBox = boxes[index];
+                        parseBox(parsedBox, scene);
+                    }
+                }
+
+                // Spheres
+                var spheres = geometries.spheres;
+                if (spheres) {
+                    for (var index = 0; index < spheres.length; index++) {
+                        var parsedSphere = spheres[index];
+                        parseSphere(parsedSphere, scene);
+                    }
+                }
+
+                // Cylinders
+                var cylinders = geometries.cylinders;
+                if (cylinders) {
+                    for (var index = 0; index < cylinders.length; index++) {
+                        var parsedCylinder = cylinders[index];
+                        parseCylinder(parsedCylinder, scene);
+                    }
+                }
+
+                // Toruses
+                var toruses = geometries.toruses;
+                if (toruses) {
+                    for (var index = 0; index < toruses.length; index++) {
+                        var parsedTorus = toruses[index];
+                        parseTorus(parsedTorus, scene);
+                    }
+                }
+
+                // Grounds
+                var grounds = geometries.grounds;
+                if (grounds) {
+                    for (var index = 0; index < grounds.length; index++) {
+                        var parsedGround = grounds[index];
+                        parseGround(parsedGround, scene);
+                    }
+                }
+
+                // Planes
+                var planes = geometries.planes;
+                if (planes) {
+                    for (var index = 0; index < planes.length; index++) {
+                        var parsedPlane = planes[index];
+                        parsePlane(parsedPlane, scene);
+                    }
+                }
+
+                // TorusKnots
+                var torusKnots = geometries.torusKnots;
+                if (torusKnots) {
+                    for (var index = 0; index < torusKnots.length; index++) {
+                        var parsedTorusKnot = torusKnots[index];
+                        parseTorusKnot(parsedTorusKnot, scene);
+                    }
+                }
+
+                // VertexData
+                var vertexData = geometries.vertexData;
+                if (vertexData) {
+                    for (var index = 0; index < vertexData.length; index++) {
+                        var parsedVertexData = vertexData[index];
+                        parseVertexData(parsedVertexData, scene, rootUrl);
+                    }
+                }
+            }
+
             // Meshes
             for (var index = 0; index < parsedData.meshes.length; index++) {
                 var parsedMesh = parsedData.meshes[index];

+ 603 - 0
Babylon/Mesh/babylon.geometry.js

@@ -0,0 +1,603 @@
+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 Geometry = (function () {
+        function Geometry(id, engine, vertexData, updatable, mesh) {
+            this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
+            this._totalVertices = 0;
+            this._indices = [];
+            this.id = id;
+            this._engine = engine;
+            this._meshes = [];
+
+            // vertexData
+            if (vertexData) {
+                this.setAllVerticesData(vertexData, updatable);
+            } else {
+                this._totalVertices = 0;
+                this._indices = [];
+            }
+
+            // applyToMesh
+            if (mesh) {
+                this.applyToMesh(mesh);
+            }
+        }
+        Geometry.prototype.getEngine = function () {
+            return this._engine;
+        };
+
+        Geometry.prototype.isReady = function () {
+            return this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE;
+        };
+
+        Geometry.prototype.setAllVerticesData = function (vertexData, updatable) {
+            vertexData.applyToGeometry(this, updatable);
+        };
+
+        Geometry.prototype.setVerticesData = function (data, kind, updatable) {
+            this._vertexBuffers = this._vertexBuffers || {};
+
+            if (this._vertexBuffers[kind]) {
+                this._vertexBuffers[kind].dispose();
+            }
+
+            this._vertexBuffers[kind] = new BABYLON.VertexBuffer(this._engine, data, kind, updatable, this._meshes.length === 0);
+
+            if (kind === BABYLON.VertexBuffer.PositionKind) {
+                var stride = this._vertexBuffers[kind].getStrideSize();
+
+                this._totalVertices = data.length / stride;
+
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
+
+                var meshes = this._meshes;
+                var numOfMeshes = meshes.length;
+
+                for (var index = 0; index < numOfMeshes; index++) {
+                    var mesh = meshes[index];
+                    mesh._resetPointsArrayCache();
+                    mesh._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                    mesh._createGlobalSubMesh();
+                }
+            }
+        };
+
+        Geometry.prototype.updateVerticesData = function (kind, data, updateExtends) {
+            var vertexBuffer = this.getVertexBuffer(kind);
+
+            if (!vertexBuffer) {
+                return;
+            }
+
+            vertexBuffer.update(data);
+
+            if (kind === BABYLON.VertexBuffer.PositionKind) {
+                var extend;
+
+                if (updateExtends) {
+                    var stride = vertexBuffer.getStrideSize();
+                    this._totalVertices = data.length / stride;
+                    extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
+                }
+
+                var meshes = this._meshes;
+                var numOfMeshes = meshes.length;
+
+                for (var index = 0; index < numOfMeshes; index++) {
+                    var mesh = meshes[index];
+                    mesh._resetPointsArrayCache();
+                    if (updateExtends) {
+                        mesh._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                    }
+                }
+            }
+        };
+
+        Geometry.prototype.getTotalVertices = function () {
+            if (!this.isReady()) {
+                return 0;
+            }
+
+            return this._totalVertices;
+        };
+
+        Geometry.prototype.getVerticesData = function (kind) {
+            var vertexBuffer = this.getVertexBuffer(kind);
+            if (!vertexBuffer) {
+                return null;
+            }
+            return vertexBuffer.getData();
+        };
+
+        Geometry.prototype.getVertexBuffer = function (kind) {
+            if (!this.isReady()) {
+                return null;
+            }
+            return this._vertexBuffers[kind];
+        };
+
+        Geometry.prototype.getVertexBuffers = function () {
+            if (!this.isReady()) {
+                return null;
+            }
+            return this._vertexBuffers;
+        };
+
+        Geometry.prototype.isVerticesDataPresent = function (kind) {
+            if (!this._vertexBuffers) {
+                if (this._delayInfo) {
+                    return this._delayInfo.indexOf(kind) !== -1;
+                }
+                return false;
+            }
+            return this._vertexBuffers[kind] !== undefined;
+        };
+
+        Geometry.prototype.getVerticesDataKinds = function () {
+            var result = [];
+            if (!this._vertexBuffers && this._delayInfo) {
+                for (var kind in this._delayInfo) {
+                    result.push(kind);
+                }
+            } else {
+                for (var kind in this._vertexBuffers) {
+                    result.push(kind);
+                }
+            }
+
+            return result;
+        };
+
+        Geometry.prototype.setIndices = function (indices) {
+            if (this._indexBuffer) {
+                this._engine._releaseBuffer(this._indexBuffer);
+            }
+
+            this._indices = indices;
+            if (this._meshes.length !== 0 && this._indices) {
+                this._indexBuffer = this._engine.createIndexBuffer(this._indices);
+            }
+
+            var meshes = this._meshes;
+            var numOfMeshes = meshes.length;
+
+            for (var index = 0; index < numOfMeshes; index++) {
+                meshes[index]._createGlobalSubMesh();
+            }
+        };
+
+        Geometry.prototype.getTotalIndices = function () {
+            if (!this.isReady()) {
+                return 0;
+            }
+            return this._indices.length;
+        };
+
+        Geometry.prototype.getIndices = function () {
+            if (!this.isReady()) {
+                return null;
+            }
+            return this._indices;
+        };
+
+        Geometry.prototype.getIndexBuffer = function () {
+            if (!this.isReady()) {
+                return null;
+            }
+            return this._indexBuffer;
+        };
+
+        Geometry.prototype.releaseForMesh = function (mesh) {
+            var meshes = this._meshes;
+            var index = meshes.indexOf(mesh);
+
+            if (index === -1) {
+                return;
+            }
+
+            for (var kind in this._vertexBuffers) {
+                this._vertexBuffers[kind].dispose();
+            }
+
+            if (this._indexBuffer && this._engine._releaseBuffer(this._indexBuffer)) {
+                this._indexBuffer = null;
+            }
+
+            meshes.splice(index, 1);
+
+            mesh._geometry = null;
+        };
+
+        Geometry.prototype.applyToMesh = function (mesh) {
+            if (mesh._geometry === this) {
+                return;
+            }
+
+            var previousGeometry = mesh._geometry;
+            if (previousGeometry) {
+                previousGeometry.releaseForMesh(mesh);
+            }
+
+            var meshes = this._meshes;
+            var numOfMeshes = meshes.length + 1;
+
+            // must be done before setting vertexBuffers because of mesh._createGlobalSubMesh()
+            mesh._geometry = this;
+
+            mesh.getScene().pushGeometry(this);
+
+            meshes.push(mesh);
+
+            if (this.isReady()) {
+                this._applyToMesh(mesh);
+            } else {
+                mesh._boundingInfo = this._boundingInfo;
+            }
+        };
+
+        Geometry.prototype._applyToMesh = function (mesh) {
+            var numOfMeshes = this._meshes.length;
+
+            for (var kind in this._vertexBuffers) {
+                if (numOfMeshes === 1) {
+                    this._vertexBuffers[kind].create();
+                }
+                this._vertexBuffers[kind]._buffer.references = numOfMeshes;
+
+                if (kind === BABYLON.VertexBuffer.PositionKind) {
+                    mesh._resetPointsArrayCache();
+
+                    var extend = BABYLON.Tools.ExtractMinAndMax(this._vertexBuffers[kind].getData(), 0, this._totalVertices);
+                    mesh._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+
+                    mesh._createGlobalSubMesh();
+                }
+            }
+
+            // indexBuffer
+            if (numOfMeshes === 1 && this._indices) {
+                this._indexBuffer = this._engine.createIndexBuffer(this._indices);
+            }
+            if (this._indexBuffer) {
+                this._indexBuffer.references = numOfMeshes;
+            }
+        };
+
+        Geometry.prototype.load = function (scene, onLoaded) {
+            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                return;
+            }
+
+            if (this.isReady()) {
+                if (onLoaded) {
+                    onLoaded();
+                }
+                return;
+            }
+
+            this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADING;
+
+            scene._addPendingData(this);
+
+            var that = this;
+
+            BABYLON.Tools.LoadFile(this.delayLoadingFile, function (data) {
+                that._delayLoadingFunction(JSON.parse(data), that);
+
+                that.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
+                that._delayInfo = [];
+
+                scene._removePendingData(that);
+
+                var meshes = that._meshes;
+                var numOfMeshes = meshes.length;
+                for (var index = 0; index < numOfMeshes; index++) {
+                    that._applyToMesh(meshes[index]);
+                }
+
+                if (onLoaded) {
+                    onLoaded();
+                }
+            }, function () {
+            }, scene.database);
+        };
+
+        Geometry.prototype.dispose = function () {
+            var meshes = this._meshes;
+            var numOfMeshes = meshes.length;
+
+            for (var index = 0; index < numOfMeshes; index++) {
+                this.releaseForMesh(meshes[index]);
+            }
+            this._meshes = [];
+
+            for (var kind in this._vertexBuffers) {
+                this._vertexBuffers[kind].dispose();
+            }
+            this._vertexBuffers = [];
+            this._totalVertices = 0;
+
+            if (this._indexBuffer) {
+                this._engine._releaseBuffer(this._indexBuffer);
+            }
+            this._indexBuffer = null;
+            this._indices = [];
+
+            this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
+            this.delayLoadingFile = null;
+            this._delayLoadingFunction = null;
+            this._delayInfo = [];
+
+            this._boundingInfo = null; // todo: .dispose()
+        };
+
+        Geometry.prototype.copy = function (id) {
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = [];
+
+            var indices = this.getIndices();
+            for (var index = 0; index < indices.length; index++) {
+                vertexData.indices.push(indices[index]);
+            }
+
+            var updatable = false;
+            var stopChecking = false;
+
+            for (var kind in this._vertexBuffers) {
+                vertexData.set(this.getVerticesData(kind), kind);
+
+                if (!stopChecking) {
+                    updatable = this.getVertexBuffer(kind).isUpdatable();
+                    stopChecking = !updatable;
+                }
+            }
+
+            var geometry = new BABYLON.Geometry(id, this._engine, vertexData, updatable, null);
+
+            geometry.delayLoadState = this.delayLoadState;
+            geometry.delayLoadingFile = this.delayLoadingFile;
+            geometry._delayLoadingFunction = this._delayLoadingFunction;
+
+            for (var kind in this._delayInfo) {
+                geometry._delayInfo = geometry._delayInfo || [];
+                geometry._delayInfo.push(kind);
+            }
+
+            // Bounding info
+            var extend = BABYLON.Tools.ExtractMinAndMax(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this.getTotalVertices());
+            geometry._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+
+            return geometry;
+        };
+
+        // Statics
+        Geometry.ExtractFromMesh = function (mesh, id) {
+            var geometry = mesh._geometry;
+
+            if (!geometry) {
+                return null;
+            }
+
+            return geometry.copy(id);
+        };
+
+        // from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#answer-2117523
+        // be aware Math.random() could cause collisions
+        Geometry.RandomId = function () {
+            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+                var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+                return v.toString(16);
+            });
+        };
+        return Geometry;
+    })();
+    BABYLON.Geometry = Geometry;
+
+    (function (Geometry) {
+        /////// Primitives //////////////////////////////////////////////
+        (function (Primitives) {
+            /// Abstract class
+            var _Primitive = (function (_super) {
+                __extends(_Primitive, _super);
+                function _Primitive(id, engine, vertexData, canBeRegenerated, mesh) {
+                    this._beingRegenerated = true;
+                    this._canBeRegenerated = canBeRegenerated;
+                    _super.call(this, id, engine, vertexData, false, mesh); // updatable = false to be sure not to update vertices
+                    this._beingRegenerated = false;
+                }
+                _Primitive.prototype.canBeRegenerated = function () {
+                    return this._canBeRegenerated;
+                };
+
+                _Primitive.prototype.regenerate = function () {
+                    if (!this._canBeRegenerated) {
+                        return;
+                    }
+                    this._beingRegenerated = true;
+                    this.setAllVerticesData(this._regenerateVertexData(), false);
+                    this._beingRegenerated = false;
+                };
+
+                _Primitive.prototype.asNewGeometry = function (id) {
+                    return _super.prototype.copy.call(this, id);
+                };
+
+                // overrides
+                _Primitive.prototype.setAllVerticesData = function (vertexData, updatable) {
+                    if (!this._beingRegenerated) {
+                        return;
+                    }
+                    return _super.prototype.setAllVerticesData.call(this, vertexData, false);
+                };
+
+                _Primitive.prototype.setVerticesData = function (data, kind, updatable) {
+                    if (!this._beingRegenerated) {
+                        return;
+                    }
+                    _super.prototype.setVerticesData.call(this, data, kind, false);
+                };
+
+                // to override
+                // protected
+                _Primitive.prototype._regenerateVertexData = function () {
+                    throw new Error("Abstract method");
+                };
+
+                _Primitive.prototype.copy = function (id) {
+                    throw new Error("Must be overriden in sub-classes.");
+                };
+                return _Primitive;
+            })(Geometry);
+            Primitives._Primitive = _Primitive;
+
+            var Box = (function (_super) {
+                __extends(Box, _super);
+                function Box(id, engine, size, canBeRegenerated, mesh) {
+                    this.size = size;
+
+                    _super.call(this, id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+                }
+                Box.prototype._regenerateVertexData = function () {
+                    return BABYLON.VertexData.CreateBox(this.size);
+                };
+
+                Box.prototype.copy = function (id) {
+                    return new Box(id, this.getEngine(), this.size, this.canBeRegenerated(), null);
+                };
+                return Box;
+            })(_Primitive);
+            Primitives.Box = Box;
+
+            var Sphere = (function (_super) {
+                __extends(Sphere, _super);
+                function Sphere(id, engine, segments, diameter, canBeRegenerated, mesh) {
+                    this.segments = segments;
+                    this.diameter = diameter;
+
+                    _super.call(this, id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+                }
+                Sphere.prototype._regenerateVertexData = function () {
+                    return BABYLON.VertexData.CreateSphere(this.segments, this.diameter);
+                };
+
+                Sphere.prototype.copy = function (id) {
+                    return new Sphere(id, this.getEngine(), this.segments, this.diameter, this.canBeRegenerated(), null);
+                };
+                return Sphere;
+            })(_Primitive);
+            Primitives.Sphere = Sphere;
+
+            var Cylinder = (function (_super) {
+                __extends(Cylinder, _super);
+                function Cylinder(id, engine, height, diameterTop, diameterBottom, tessellation, canBeRegenerated, mesh) {
+                    this.height = height;
+                    this.diameterTop = diameterTop;
+                    this.diameterBottom = diameterBottom;
+                    this.tessellation = tessellation;
+
+                    _super.call(this, id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+                }
+                Cylinder.prototype._regenerateVertexData = function () {
+                    return BABYLON.VertexData.CreateCylinder(this.height, this.diameterTop, this.diameterBottom, this.tessellation);
+                };
+
+                Cylinder.prototype.copy = function (id) {
+                    return new Cylinder(id, this.getEngine(), this.height, this.diameterTop, this.diameterBottom, this.tessellation, this.canBeRegenerated(), null);
+                };
+                return Cylinder;
+            })(_Primitive);
+            Primitives.Cylinder = Cylinder;
+
+            var Torus = (function (_super) {
+                __extends(Torus, _super);
+                function Torus(id, engine, diameter, thickness, tessellation, canBeRegenerated, mesh) {
+                    this.diameter = diameter;
+                    this.thickness = thickness;
+                    this.tessellation = tessellation;
+
+                    _super.call(this, id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+                }
+                Torus.prototype._regenerateVertexData = function () {
+                    return BABYLON.VertexData.CreateTorus(this.diameter, this.thickness, this.tessellation);
+                };
+
+                Torus.prototype.copy = function (id) {
+                    return new Torus(id, this.getEngine(), this.diameter, this.thickness, this.tessellation, this.canBeRegenerated(), null);
+                };
+                return Torus;
+            })(_Primitive);
+            Primitives.Torus = Torus;
+
+            var Ground = (function (_super) {
+                __extends(Ground, _super);
+                function Ground(id, engine, width, height, subdivisions, canBeRegenerated, mesh) {
+                    this.width = width;
+                    this.height = height;
+                    this.subdivisions = subdivisions;
+
+                    _super.call(this, id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+                }
+                Ground.prototype._regenerateVertexData = function () {
+                    return BABYLON.VertexData.CreateGround(this.width, this.height, this.subdivisions);
+                };
+
+                Ground.prototype.copy = function (id) {
+                    return new Ground(id, this.getEngine(), this.width, this.height, this.subdivisions, this.canBeRegenerated(), null);
+                };
+                return Ground;
+            })(_Primitive);
+            Primitives.Ground = Ground;
+
+            var Plane = (function (_super) {
+                __extends(Plane, _super);
+                function Plane(id, engine, size, canBeRegenerated, mesh) {
+                    this.size = size;
+
+                    _super.call(this, id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+                }
+                Plane.prototype._regenerateVertexData = function () {
+                    return BABYLON.VertexData.CreatePlane(this.size);
+                };
+
+                Plane.prototype.copy = function (id) {
+                    return new Plane(id, this.getEngine(), this.size, this.canBeRegenerated(), null);
+                };
+                return Plane;
+            })(_Primitive);
+            Primitives.Plane = Plane;
+
+            var TorusKnot = (function (_super) {
+                __extends(TorusKnot, _super);
+                function TorusKnot(id, engine, radius, tube, radialSegments, tubularSegments, p, q, canBeRegenerated, mesh) {
+                    this.radius = radius;
+                    this.tube = tube;
+                    this.radialSegments = radialSegments;
+                    this.tubularSegments = tubularSegments;
+                    this.p = p;
+                    this.q = q;
+
+                    _super.call(this, id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+                }
+                TorusKnot.prototype._regenerateVertexData = function () {
+                    return BABYLON.VertexData.CreateTorusKnot(this.radius, this.tube, this.radialSegments, this.tubularSegments, this.p, this.q);
+                };
+
+                TorusKnot.prototype.copy = function (id) {
+                    return new TorusKnot(id, this.getEngine(), this.radius, this.tube, this.radialSegments, this.tubularSegments, this.p, this.q, this.canBeRegenerated(), null);
+                };
+                return TorusKnot;
+            })(_Primitive);
+            Primitives.TorusKnot = TorusKnot;
+        })(Geometry.Primitives || (Geometry.Primitives = {}));
+        var Primitives = Geometry.Primitives;
+    })(BABYLON.Geometry || (BABYLON.Geometry = {}));
+    var Geometry = BABYLON.Geometry;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.geometry.js.map

+ 629 - 0
Babylon/Mesh/babylon.geometry.ts

@@ -0,0 +1,629 @@
+module BABYLON {
+    export class Geometry implements IGetSetVerticesData {
+        // Members
+        public id: string;
+        public delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
+        public delayLoadingFile: string;
+
+        // Private
+        private _engine: Engine;
+        private _meshes: Mesh[];
+        private _totalVertices = 0;
+        private _indices = [];
+        private _vertexBuffers;
+        private _delayInfo; //ANY
+        private _indexBuffer;
+        private _boundingInfo: BoundingInfo;
+        private _delayLoadingFunction: (any, Geometry) => void;
+
+        constructor(id: string, engine: Engine, vertexData?: VertexData, updatable?: boolean, mesh?: Mesh) {
+            this.id = id;
+            this._engine = engine;
+            this._meshes = [];
+
+            // vertexData
+            if (vertexData) {
+                this.setAllVerticesData(vertexData, updatable);
+            }
+            else {
+                this._totalVertices = 0;
+                this._indices = [];
+            }
+
+            // applyToMesh
+            if (mesh) {
+                this.applyToMesh(mesh);
+            }
+        }
+
+        public getEngine(): Engine {
+            return this._engine;
+        }
+
+        public isReady(): boolean {
+            return this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE;
+        }
+
+        public setAllVerticesData(vertexData: VertexData, updatable?: boolean): void {
+            vertexData.applyToGeometry(this, updatable);
+        }
+
+        public setVerticesData(data: number[], kind: string, updatable?: boolean): void {
+            this._vertexBuffers = this._vertexBuffers || {};
+
+            if (this._vertexBuffers[kind]) {
+                this._vertexBuffers[kind].dispose();
+            }
+
+            this._vertexBuffers[kind] = new VertexBuffer(this._engine, data, kind, updatable, this._meshes.length === 0);
+
+            if (kind === BABYLON.VertexBuffer.PositionKind) {
+                var stride = this._vertexBuffers[kind].getStrideSize();
+
+                this._totalVertices = data.length / stride;
+
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
+
+                var meshes = this._meshes;
+                var numOfMeshes = meshes.length;
+
+                for (var index = 0; index < numOfMeshes; index++) {
+                    var mesh = meshes[index];
+                    mesh._resetPointsArrayCache();
+                    mesh._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                    mesh._createGlobalSubMesh();
+                }
+            }
+        }
+
+        public updateVerticesData(kind: string, data: number[], updateExtends?: boolean): void {
+            var vertexBuffer = this.getVertexBuffer(kind);
+
+            if (!vertexBuffer) {
+                return;
+            }
+
+            vertexBuffer.update(data);
+
+            if (kind === BABYLON.VertexBuffer.PositionKind) {
+
+                var extend;
+
+                if (updateExtends) {
+                    var stride = vertexBuffer.getStrideSize();
+                    this._totalVertices = data.length / stride;
+                    extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
+                }
+
+                var meshes = this._meshes;
+                var numOfMeshes = meshes.length;
+
+                for (var index = 0; index < numOfMeshes; index++) {
+                    var mesh = meshes[index];
+                    mesh._resetPointsArrayCache();
+                    if (updateExtends) {
+                        mesh._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                    }
+                }
+            }
+        }
+
+        public getTotalVertices(): number {
+            if (!this.isReady()) {
+                return 0;
+            }
+
+            return this._totalVertices;
+        }
+
+        public getVerticesData(kind: string): number[] {
+            var vertexBuffer = this.getVertexBuffer(kind);
+            if (!vertexBuffer) {
+                return null;
+            }
+            return vertexBuffer.getData();
+        }
+
+        public getVertexBuffer(kind: string): VertexBuffer {
+            if (!this.isReady()) {
+                return null;
+            }
+            return this._vertexBuffers[kind];
+        }
+
+        public getVertexBuffers(): VertexBuffer[]{
+            if (!this.isReady()) {
+                return null;
+            }
+            return this._vertexBuffers;
+        }
+
+        public isVerticesDataPresent(kind: string): boolean {
+            if (!this._vertexBuffers) {
+                if (this._delayInfo) {
+                    return this._delayInfo.indexOf(kind) !== -1;
+                }
+                return false;
+            }
+            return this._vertexBuffers[kind] !== undefined;
+        }
+
+        public getVerticesDataKinds(): string[] {
+            var result = [];
+            if (!this._vertexBuffers && this._delayInfo) {
+                for (var kind in this._delayInfo) {
+                    result.push(kind);
+                }
+            } else {
+                for (var kind in this._vertexBuffers) {
+                    result.push(kind);
+                }
+            }
+
+            return result;
+        }
+
+        public setIndices(indices: number[]): void {
+            if (this._indexBuffer) {
+                this._engine._releaseBuffer(this._indexBuffer);
+            }
+
+            this._indices = indices;
+            if (this._meshes.length !== 0 && this._indices) {
+                this._indexBuffer = this._engine.createIndexBuffer(this._indices);
+            }
+
+            var meshes = this._meshes;
+            var numOfMeshes = meshes.length;
+
+            for (var index = 0; index < numOfMeshes; index++) {
+                meshes[index]._createGlobalSubMesh();
+            }
+        }
+
+        public getTotalIndices(): number {
+            if (!this.isReady()) {
+                return 0;
+            }
+            return this._indices.length;
+        }
+
+        public getIndices(): number[] {
+            if (!this.isReady()) {
+                return null;
+            }
+            return this._indices;
+        }
+
+        public getIndexBuffer(): any {
+            if (!this.isReady()) {
+                return null;
+            }
+            return this._indexBuffer;
+        }
+
+        public releaseForMesh(mesh: Mesh): void {
+            var meshes = this._meshes;
+            var index = meshes.indexOf(mesh);
+
+            if (index === -1) {
+                return;
+            }
+
+            for (var kind in this._vertexBuffers) {
+                this._vertexBuffers[kind].dispose();
+            }
+
+            if (this._indexBuffer && this._engine._releaseBuffer(this._indexBuffer)) {
+                this._indexBuffer = null;
+            }
+
+            meshes.splice(index, 1);
+
+            mesh._geometry = null;
+        }
+
+        public applyToMesh(mesh: Mesh): void {
+            if (mesh._geometry === this) {
+                return;
+            }
+
+            var previousGeometry = mesh._geometry;
+            if (previousGeometry) {
+                previousGeometry.releaseForMesh(mesh);
+            }
+
+            var meshes = this._meshes;
+            var numOfMeshes = meshes.length + 1;
+
+            // must be done before setting vertexBuffers because of mesh._createGlobalSubMesh()
+            mesh._geometry = this;
+
+            mesh.getScene().pushGeometry(this);
+
+            meshes.push(mesh);
+
+            if (this.isReady()) {
+                this._applyToMesh(mesh);
+            }
+            else {
+                mesh._boundingInfo = this._boundingInfo;
+            }
+        }
+
+        private _applyToMesh(mesh: Mesh): void {
+            var numOfMeshes = this._meshes.length;
+
+            // vertexBuffers
+            for (var kind in this._vertexBuffers) {
+                if (numOfMeshes === 1) {
+                    this._vertexBuffers[kind].create();
+                }
+                this._vertexBuffers[kind]._buffer.references = numOfMeshes;
+
+                if (kind === BABYLON.VertexBuffer.PositionKind) {
+                    mesh._resetPointsArrayCache();
+
+                    var extend = BABYLON.Tools.ExtractMinAndMax(this._vertexBuffers[kind].getData(), 0, this._totalVertices);
+                    mesh._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+
+                    mesh._createGlobalSubMesh();
+                }
+            }
+
+            // indexBuffer
+            if (numOfMeshes === 1 && this._indices) {
+                this._indexBuffer = this._engine.createIndexBuffer(this._indices);
+            }
+            if (this._indexBuffer) {
+                this._indexBuffer.references = numOfMeshes;
+            }
+        }
+
+        public load(scene: Scene, onLoaded?: () => void): void {
+            if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                return;
+            }
+
+            if (this.isReady()) {
+                if (onLoaded) {
+                    onLoaded();
+                }
+                return;
+            }
+
+            this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADING;
+
+            scene._addPendingData(this);
+
+            var that = this;
+
+            BABYLON.Tools.LoadFile(this.delayLoadingFile, function (data) {
+                that._delayLoadingFunction(JSON.parse(data), that);
+
+                that.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
+                that._delayInfo = [];
+
+                scene._removePendingData(that);
+
+                var meshes = that._meshes;
+                var numOfMeshes = meshes.length;
+                for (var index = 0; index < numOfMeshes; index++) {
+                    that._applyToMesh(meshes[index]);
+                }
+
+                if (onLoaded) {
+                    onLoaded();
+                }
+            }, function () { }, scene.database);
+        }
+
+        public dispose(): void {
+            var meshes = this._meshes;
+            var numOfMeshes = meshes.length;
+
+            for (var index = 0; index < numOfMeshes; index++) {
+                this.releaseForMesh(meshes[index]);
+            }
+            this._meshes = [];
+
+            for (var kind in this._vertexBuffers) {
+                this._vertexBuffers[kind].dispose();
+            }
+            this._vertexBuffers = [];
+            this._totalVertices = 0;
+
+            if (this._indexBuffer) {
+                this._engine._releaseBuffer(this._indexBuffer);
+            }
+            this._indexBuffer = null;
+            this._indices = [];
+
+            this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
+            this.delayLoadingFile = null;
+            this._delayLoadingFunction = null;
+            this._delayInfo = [];
+
+            this._boundingInfo = null; // todo: .dispose()
+        }
+
+        public copy(id: string): Geometry {
+            var vertexData = new BABYLON.VertexData();
+
+            vertexData.indices = [];
+
+            var indices = this.getIndices();
+            for (var index = 0; index < indices.length; index++) {
+                vertexData.indices.push(indices[index]);
+            }
+
+            var updatable = false;
+            var stopChecking = false;
+
+            for (var kind in this._vertexBuffers) {
+                vertexData.set(this.getVerticesData(kind), kind);
+
+                if (!stopChecking) {
+                    updatable = this.getVertexBuffer(kind).isUpdatable();
+                    stopChecking = !updatable;
+                }
+            }
+
+            var geometry = new BABYLON.Geometry(id, this._engine, vertexData, updatable, null);
+
+            geometry.delayLoadState = this.delayLoadState;
+            geometry.delayLoadingFile = this.delayLoadingFile;
+            geometry._delayLoadingFunction = this._delayLoadingFunction;
+
+            for (var kind in this._delayInfo) {
+                geometry._delayInfo = geometry._delayInfo || [];
+                geometry._delayInfo.push(kind);
+            }
+
+            // Bounding info
+            var extend = BABYLON.Tools.ExtractMinAndMax(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this.getTotalVertices());
+            geometry._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+
+            return geometry;
+        }
+
+        // Statics
+        public static ExtractFromMesh(mesh: Mesh, id: string): Geometry {
+            var geometry = mesh._geometry;
+
+            if (!geometry) {
+                return null;
+            }
+
+            return geometry.copy(id);
+        }
+    
+        // from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#answer-2117523
+        // be aware Math.random() could cause collisions
+        public static RandomId(): string {
+            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+                var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+                return v.toString(16);
+            });
+        }
+    }
+
+    /////// Primitives //////////////////////////////////////////////
+    export module Geometry.Primitives {
+
+        /// Abstract class
+        export class _Primitive extends Geometry {
+            // Private 
+            private _beingRegenerated: boolean;
+            private _canBeRegenerated: boolean;
+
+            constructor(id: string, engine: Engine, vertexData?: VertexData, canBeRegenerated?: boolean, mesh?: Mesh) {
+                this._beingRegenerated = true;
+                this._canBeRegenerated = canBeRegenerated;
+                super(id, engine, vertexData, false, mesh); // updatable = false to be sure not to update vertices
+                this._beingRegenerated = false;
+            }
+
+            public canBeRegenerated(): boolean {
+                return this._canBeRegenerated;
+            }
+
+            public regenerate(): void {
+                if (!this._canBeRegenerated) {
+                    return;
+                }
+                this._beingRegenerated = true;
+                this.setAllVerticesData(this._regenerateVertexData(), false);
+                this._beingRegenerated = false;
+            }
+
+            public asNewGeometry(id: string): Geometry {
+                return super.copy(id);
+            }
+
+            // overrides
+            public setAllVerticesData(vertexData: VertexData, updatable?: boolean) {
+                if (!this._beingRegenerated) {
+                    return;
+                }
+                return super.setAllVerticesData(vertexData, false);
+            }
+
+            public setVerticesData(data: number[], kind: string, updatable?: boolean) {
+                if (!this._beingRegenerated) {
+                    return;
+                }
+                super.setVerticesData(data, kind, false);
+            }
+
+            // to override
+            // protected
+            public _regenerateVertexData(): VertexData {
+                throw new Error("Abstract method");
+            }
+
+            public copy(id: string): Geometry {
+                throw new Error("Must be overriden in sub-classes.");
+            }
+        }
+
+        export class Box extends _Primitive {
+            // Members
+            public size: number;
+
+            constructor(id: string, engine: Engine, size: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+                this.size = size;
+
+                super(id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+            }
+
+            public _regenerateVertexData(): VertexData {
+                return VertexData.CreateBox(this.size);
+            }
+
+            public copy(id: string): Geometry {
+                return new Box(id, this.getEngine(), this.size, this.canBeRegenerated(), null);
+            }
+        }
+
+        export class Sphere extends _Primitive {
+            // Members
+            public segments: number;
+            public diameter: number;
+
+            constructor(id: string, engine: Engine, segments: number, diameter: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+                this.segments = segments;
+                this.diameter = diameter;
+
+                super(id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+            }
+
+            public _regenerateVertexData(): VertexData {
+                return VertexData.CreateSphere(this.segments, this.diameter);
+            }
+
+            public copy(id: string): Geometry {
+                return new Sphere(id, this.getEngine(), this.segments, this.diameter, this.canBeRegenerated(), null);
+            }
+        }
+
+        export class Cylinder extends _Primitive {
+            // Members
+            public height: number;
+            public diameterTop: number;
+            public diameterBottom: number;
+            public tessellation: number;
+
+            constructor(id: string, engine: Engine, height: number, diameterTop: number, diameterBottom: number, tessellation: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+                this.height = height;
+                this.diameterTop = diameterTop;
+                this.diameterBottom = diameterBottom;
+                this.tessellation = tessellation;
+
+                super(id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+            }
+
+            public _regenerateVertexData(): VertexData {
+                return VertexData.CreateCylinder(this.height, this.diameterTop, this.diameterBottom, this.tessellation);
+            }
+
+            public copy(id: string): Geometry {
+                return new Cylinder(id, this.getEngine(), this.height, this.diameterTop, this.diameterBottom, this.tessellation, this.canBeRegenerated(), null);
+            }
+        }
+
+        export class Torus extends _Primitive {
+            // Members
+            public diameter: number;
+            public thickness: number;
+            public tessellation: number;
+
+            constructor(id: string, engine: Engine, diameter: number, thickness: number, tessellation: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+                this.diameter = diameter;
+                this.thickness = thickness;
+                this.tessellation = tessellation;
+
+                super(id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+            }
+
+            public _regenerateVertexData(): VertexData {
+                return VertexData.CreateTorus(this.diameter, this.thickness, this.tessellation);
+            }
+
+            public copy(id: string): Geometry {
+                return new Torus(id, this.getEngine(), this.diameter, this.thickness, this.tessellation, this.canBeRegenerated(), null);
+            }
+        }
+
+        export class Ground extends _Primitive {
+            // Members
+            public width: number;
+            public height: number;
+            public subdivisions: number;
+
+            constructor(id: string, engine: Engine, width: number, height: number, subdivisions: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+                this.width = width;
+                this.height = height;
+                this.subdivisions = subdivisions;
+
+                super(id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+            }
+
+            public _regenerateVertexData(): VertexData {
+                return VertexData.CreateGround(this.width, this.height, this.subdivisions);
+            }
+
+            public copy(id: string): Geometry {
+                return new Ground(id, this.getEngine(), this.width, this.height, this.subdivisions, this.canBeRegenerated(), null);
+            }
+        }
+
+        export class Plane extends _Primitive {
+            // Members
+            public size: number;
+
+            constructor(id: string, engine: Engine, size: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+                this.size = size;
+
+                super(id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+            }
+
+            public _regenerateVertexData(): VertexData {
+                return VertexData.CreatePlane(this.size);
+            }
+
+            public copy(id: string): Geometry {
+                return new Plane(id, this.getEngine(), this.size, this.canBeRegenerated(), null);
+            }
+        }
+
+        export class TorusKnot extends _Primitive {
+            // Members
+            public radius: number;
+            public tube: number;
+            public radialSegments: number;
+            public tubularSegments: number;
+            public p: number;
+            public q: number;
+
+            constructor(id: string, engine: Engine, radius: number, tube: number, radialSegments: number, tubularSegments: number, p: number, q: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+                this.radius = radius;
+                this.tube = tube;
+                this.radialSegments = radialSegments;
+                this.tubularSegments = tubularSegments;
+                this.p = p;
+                this.q = q;
+
+                super(id, engine, this._regenerateVertexData(), canBeRegenerated, mesh);
+            }
+
+            public _regenerateVertexData(): VertexData {
+                return VertexData.CreateTorusKnot(this.radius, this.tube, this.radialSegments, this.tubularSegments, this.p, this.q);
+            }
+
+            public copy(id: string): Geometry {
+                return new TorusKnot(id, this.getEngine(), this.radius, this.tube, this.radialSegments, this.tubularSegments, this.p, this.q, this.canBeRegenerated(), null);
+            }
+        }
+    }
+} 

+ 118 - 113
Babylon/Mesh/babylon.mesh.js

@@ -46,9 +46,7 @@ var BABYLON;
             this._isDirty = false;
             // Physics
             this._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
-            this._totalVertices = 0;
             this._pivotMatrix = BABYLON.Matrix.Identity();
-            this._indices = [];
             this._renderId = 0;
             this._onBeforeRenderCallbacks = [];
             this._animationStarted = false;
@@ -140,48 +138,61 @@ var BABYLON;
         };
 
         Mesh.prototype.getTotalVertices = function () {
-            return this._totalVertices;
+            if (!this._geometry) {
+                return 0;
+            }
+            return this._geometry.getTotalVertices();
         };
 
         Mesh.prototype.getVerticesData = function (kind) {
-            return this._vertexBuffers[kind].getData();
+            if (!this._geometry) {
+                return null;
+            }
+            return this._geometry.getVerticesData(kind);
         };
 
         Mesh.prototype.getVertexBuffer = function (kind) {
-            return this._vertexBuffers[kind];
+            if (!this._geometry) {
+                return undefined;
+            }
+            return this._geometry.getVertexBuffer(kind);
         };
 
         Mesh.prototype.isVerticesDataPresent = function (kind) {
-            if (!this._vertexBuffers) {
+            if (!this._geometry) {
                 if (this._delayInfo) {
                     return this._delayInfo.indexOf(kind) !== -1;
                 }
                 return false;
             }
-            return this._vertexBuffers[kind] !== undefined;
+            return this._geometry.isVerticesDataPresent(kind);
         };
 
         Mesh.prototype.getVerticesDataKinds = function () {
-            var result = [];
-            if (!this._vertexBuffers && this._delayInfo) {
-                for (var kind in this._delayInfo) {
-                    result.push(kind);
-                }
-            } else {
-                for (kind in this._vertexBuffers) {
-                    result.push(kind);
+            if (!this._geometry) {
+                var result = [];
+                if (this._delayInfo) {
+                    for (var kind in this._delayInfo) {
+                        result.push(kind);
+                    }
                 }
+                return result;
             }
-
-            return result;
+            return this._geometry.getVerticesDataKinds();
         };
 
         Mesh.prototype.getTotalIndices = function () {
-            return this._indices.length;
+            if (!this._geometry) {
+                return 0;
+            }
+            return this._geometry.getTotalIndices();
         };
 
         Mesh.prototype.getIndices = function () {
-            return this._indices;
+            if (!this._geometry) {
+                return [];
+            }
+            return this._geometry.getIndices();
         };
 
         Mesh.prototype.setPivotMatrix = function (matrix) {
@@ -260,15 +271,15 @@ var BABYLON;
         Mesh.prototype.refreshBoundingInfo = function () {
             var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
 
-            if (!data) {
-                return;
+            if (data) {
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices());
+                this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
             }
 
-            var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
-            this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                this.subMeshes[index].refreshBoundingInfo();
+            if (this.subMeshes) {
+                for (var index = 0; index < this.subMeshes.length; index++) {
+                    this.subMeshes[index].refreshBoundingInfo();
+                }
             }
 
             this._updateBoundingInfo();
@@ -379,12 +390,13 @@ var BABYLON;
         };
 
         Mesh.prototype._createGlobalSubMesh = function () {
-            if (!this._totalVertices || !this._indices) {
+            var totalVertices = this.getTotalVertices();
+            if (!totalVertices || !this.getIndices()) {
                 return null;
             }
 
             this.subMeshes = [];
-            return new BABYLON.SubMesh(0, 0, this._totalVertices, 0, this._indices.length, this);
+            return new BABYLON.SubMesh(0, 0, totalVertices, 0, this.getTotalIndices(), this);
         };
 
         Mesh.prototype.subdivide = function (count) {
@@ -392,85 +404,83 @@ var BABYLON;
                 return;
             }
 
-            var subdivisionSize = this._indices.length / count;
+            var totalIndices = this.getTotalIndices();
+            var subdivisionSize = totalIndices / count;
             var offset = 0;
 
             this.subMeshes = [];
             for (var index = 0; index < count; index++) {
-                BABYLON.SubMesh.CreateFromIndices(0, offset, Math.min(subdivisionSize, this._indices.length - offset), this);
+                BABYLON.SubMesh.CreateFromIndices(0, offset, Math.min(subdivisionSize, totalIndices - offset), this);
 
                 offset += subdivisionSize;
             }
         };
 
         Mesh.prototype.setVerticesData = function (data, kind, updatable) {
-            if (!this._vertexBuffers) {
-                this._vertexBuffers = {};
-            }
-
-            if (this._vertexBuffers[kind]) {
-                this._vertexBuffers[kind].dispose();
-            }
-
-            this._vertexBuffers[kind] = new BABYLON.VertexBuffer(this, data, kind, updatable);
+            if (!this._geometry) {
+                var vertexData = new BABYLON.VertexData();
+                vertexData.set(data, kind);
 
-            if (kind === BABYLON.VertexBuffer.PositionKind) {
-                this._resetPointsArrayCache();
+                var scene = this.getScene();
 
-                var stride = this._vertexBuffers[kind].getStrideSize();
-                this._totalVertices = data.length / stride;
-
-                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
-                this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-
-                this._createGlobalSubMesh();
+                new BABYLON.Geometry(BABYLON.Geometry.RandomId(), scene.getEngine(), vertexData, updatable, this);
+            } else {
+                this._geometry.setVerticesData(data, kind, updatable);
             }
         };
 
-        Mesh.prototype.updateVerticesData = function (kind, data, updateExtends) {
-            if (this._vertexBuffers[kind]) {
-                this._vertexBuffers[kind].update(data);
-
-                if (kind === BABYLON.VertexBuffer.PositionKind) {
-                    this._resetPointsArrayCache();
-
-                    if (updateExtends) {
-                        var stride = this._vertexBuffers[kind].getStrideSize();
-                        this._totalVertices = data.length / stride;
+        Mesh.prototype.updateVerticesData = function (kind, data, updateExtends, makeItUnique) {
+            if (!this._geometry) {
+                return;
+            }
+            if (!makeItUnique) {
+                this._geometry.updateVerticesData(kind, data, updateExtends);
+            } else {
+                this.makeGeometryUnique();
+                this.updateVerticesData(kind, data, updateExtends, false);
+            }
+        };
 
-                        var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
-                        this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-                    }
-                }
+        Mesh.prototype.makeGeometryUnique = function () {
+            if (!this._geometry) {
+                return;
             }
+            var geometry = this._geometry.copy(BABYLON.Geometry.RandomId());
+            geometry.applyToMesh(this);
         };
 
         Mesh.prototype.setIndices = function (indices) {
-            if (this._indexBuffer) {
-                this.getScene().getEngine()._releaseBuffer(this._indexBuffer);
-            }
+            if (!this._geometry) {
+                var vertexData = new BABYLON.VertexData();
+                vertexData.indices = indices;
 
-            this._indexBuffer = this.getScene().getEngine().createIndexBuffer(indices);
-            this._indices = indices;
+                var scene = this.getScene();
 
-            this._createGlobalSubMesh();
+                new BABYLON.Geometry(BABYLON.Geometry.RandomId(), scene.getEngine(), vertexData, false, this);
+            } else {
+                this._geometry.setIndices(indices);
+            }
         };
 
         // ANY
         Mesh.prototype.bindAndDraw = function (subMesh, effect, wireframe) {
+            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
+                return;
+            }
+
             var engine = this.getScene().getEngine();
 
             // Wireframe
-            var indexToBind = this._indexBuffer;
+            var indexToBind = this._geometry.getIndexBuffer();
             var useTriangles = true;
 
             if (wireframe) {
-                indexToBind = subMesh.getLinesIndexBuffer(this._indices, engine);
+                indexToBind = subMesh.getLinesIndexBuffer(this.getIndices(), engine);
                 useTriangles = false;
             }
 
             // VBOs
-            engine.bindMultiBuffers(this._vertexBuffers, indexToBind, effect);
+            engine.bindMultiBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
 
             // Draw order
             engine.draw(useTriangles, useTriangles ? subMesh.indexStart : 0, useTriangles ? subMesh.indexCount : subMesh.linesIndexCount);
@@ -489,7 +499,7 @@ var BABYLON;
         };
 
         Mesh.prototype.render = function (subMesh) {
-            if (!this._vertexBuffers || !this._indexBuffer) {
+            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
                 return;
             }
 
@@ -558,26 +568,33 @@ var BABYLON;
         };
 
         Mesh.prototype.isInFrustum = function (frustumPlanes) {
-            var _this = this;
             if (this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
                 return false;
             }
 
-            var result = this._boundingInfo.isInFrustum(frustumPlanes);
+            if (!this._boundingInfo.isInFrustum(frustumPlanes)) {
+                return false;
+            }
+
+            var that = this;
+            var scene = this.getScene();
 
-            if (result && this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
-                this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADING;
-                this.getScene()._addPendingData(this);
+            if (this._geometry) {
+                this._geometry.load(scene);
+            } else if (that.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
+                that.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADING;
+
+                scene._addPendingData(that);
 
                 BABYLON.Tools.LoadFile(this.delayLoadingFile, function (data) {
-                    _this._delayLoadingFunction(JSON.parse(data), _this);
-                    _this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
-                    _this.getScene()._removePendingData(_this);
+                    that._delayLoadingFunction(JSON.parse(data), that);
+                    that.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED;
+                    scene._removePendingData(that);
                 }, function () {
-                }, this.getScene().database);
+                }, scene.database);
             }
 
-            return result;
+            return true;
         };
 
         Mesh.prototype.setMaterialByID = function (id) {
@@ -638,25 +655,25 @@ var BABYLON;
 
             this._resetPointsArrayCache();
 
-            var data = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].getData();
+            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             var temp = [];
             for (var index = 0; index < data.length; index += 3) {
                 BABYLON.Vector3.TransformCoordinates(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
             }
 
-            this.setVerticesData(temp, BABYLON.VertexBuffer.PositionKind, this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].isUpdatable());
+            this.setVerticesData(temp, BABYLON.VertexBuffer.PositionKind, this.getVertexBuffer(BABYLON.VertexBuffer.PositionKind).isUpdatable());
 
             // Normals
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
                 return;
             }
 
-            data = this._vertexBuffers[BABYLON.VertexBuffer.NormalKind].getData();
+            data = this.getVerticesData(BABYLON.VertexBuffer.NormalKind);
             for (index = 0; index < data.length; index += 3) {
                 BABYLON.Vector3.TransformNormal(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
             }
 
-            this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this._vertexBuffers[BABYLON.VertexBuffer.NormalKind].isUpdatable());
+            this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable());
         };
 
         Mesh.prototype.lookAt = function (targetPoint, yawCor, pitchCor, rollCor) {
@@ -688,7 +705,7 @@ var BABYLON;
 
             this._positions = [];
 
-            var data = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].getData();
+            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             for (var index = 0; index < data.length; index += 3) {
                 this._positions.push(BABYLON.Vector3.FromArray(data, index));
             }
@@ -711,7 +728,7 @@ var BABYLON;
             }
 
             // Collide
-            collider._collide(subMesh, subMesh._lastColliderWorldVertices, this._indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
+            collider._collide(subMesh, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
         };
 
         Mesh.prototype._processCollisionsForSubModels = function (collider, transformMatrix) {
@@ -773,7 +790,7 @@ var BABYLON;
                 if (this.subMeshes.length > 1 && !subMesh.canIntersects(ray))
                     continue;
 
-                var currentIntersectInfo = subMesh.intersects(ray, this._positions, this._indices, fastCheck);
+                var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);
 
                 if (currentIntersectInfo) {
                     if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
@@ -815,20 +832,14 @@ var BABYLON;
         Mesh.prototype.clone = function (name, newParent, doNotCloneChildren) {
             var result = new BABYLON.Mesh(name, this.getScene());
 
-            // Buffers
-            result._vertexBuffers = this._vertexBuffers;
-            for (var kind in result._vertexBuffers) {
-                result._vertexBuffers[kind]._buffer.references++;
-            }
-
-            result._indexBuffer = this._indexBuffer;
-            this._indexBuffer.references++;
+            // Geometry
+            this._geometry.applyToMesh(result);
 
             // Deep copy
-            BABYLON.Tools.DeepCopy(this, result, ["name", "material", "skeleton"], ["_indices", "_totalVertices"]);
+            BABYLON.Tools.DeepCopy(this, result, ["name", "material", "skeleton"], []);
 
             // Bounding info
-            var extend = BABYLON.Tools.ExtractMinAndMax(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this._totalVertices);
+            var extend = BABYLON.Tools.ExtractMinAndMax(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this.getTotalVertices());
             result._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
 
             // Material
@@ -864,16 +875,8 @@ var BABYLON;
 
         // Dispose
         Mesh.prototype.dispose = function (doNotRecurse) {
-            if (this._vertexBuffers) {
-                for (var vbKind in this._vertexBuffers) {
-                    this._vertexBuffers[vbKind].dispose();
-                }
-                this._vertexBuffers = null;
-            }
-
-            if (this._indexBuffer) {
-                this.getScene().getEngine()._releaseBuffer(this._indexBuffer);
-                this._indexBuffer = null;
+            if (this._geometry) {
+                this._geometry.releaseForMesh(this);
             }
 
             // Physics
@@ -1010,15 +1013,16 @@ var BABYLON;
             var updatableNormals = false;
             for (var kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
                 var kind = kinds[kindIndex];
+                var vertexBuffer = this.getVertexBuffer(kind);
 
                 if (kind === BABYLON.VertexBuffer.NormalKind) {
-                    updatableNormals = this.getVertexBuffer(kind).isUpdatable();
+                    updatableNormals = vertexBuffer.isUpdatable();
                     kinds.splice(kindIndex, 1);
                     kindIndex--;
                     continue;
                 }
 
-                vbs[kind] = this.getVertexBuffer(kind);
+                vbs[kind] = vertexBuffer;
                 data[kind] = vbs[kind].getData();
                 newdata[kind] = [];
             }
@@ -1027,8 +1031,9 @@ var BABYLON;
             var previousSubmeshes = this.subMeshes.slice(0);
 
             var indices = this.getIndices();
+            var totalIndices = this.getTotalIndices();
 
-            for (index = 0; index < indices.length; index++) {
+            for (index = 0; index < totalIndices; index++) {
                 var vertexIndex = indices[index];
 
                 for (kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
@@ -1044,7 +1049,7 @@ var BABYLON;
             // Updating faces & normal
             var normals = [];
             var positions = newdata[BABYLON.VertexBuffer.PositionKind];
-            for (var index = 0; index < indices.length; index += 3) {
+            for (var index = 0; index < totalIndices; index += 3) {
                 indices[index] = index;
                 indices[index + 1] = index + 1;
                 indices[index + 2] = index + 2;

+ 127 - 118
Babylon/Mesh/babylon.mesh.ts

@@ -1,5 +1,5 @@
 module BABYLON {
-    export class Mesh extends Node {
+    export class Mesh extends Node implements IGetSetVerticesData {
         // Statics
         public static BILLBOARDMODE_NONE = 0;
         public static BILLBOARDMODE_X = 1;
@@ -12,7 +12,7 @@
         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 delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
         public material = null;
         public isVisible = true;
         public isPickable = true;
@@ -53,16 +53,13 @@
         public _physicRestitution: number;
 
         // Private
-        private _boundingInfo: BoundingInfo;
-        private _totalVertices = 0;
+        public _geometry: Geometry;
+        public _boundingInfo: BoundingInfo;
         private _pivotMatrix = BABYLON.Matrix.Identity();
-        private _indices = [];
         private _renderId = 0;
         private _onBeforeRenderCallbacks = [];
         private _delayInfo; //ANY
         private _animationStarted = false;
-        private _vertexBuffers;
-        private _indexBuffer;
         private _delayLoadingFunction: (any, Mesh) => void;
 
         constructor(name: string, scene: Scene) {
@@ -159,48 +156,61 @@
         }
 
         public getTotalVertices(): number {
-            return this._totalVertices;
+            if (!this._geometry) {
+                return 0;
+            }
+            return this._geometry.getTotalVertices();
         }
 
         public getVerticesData(kind): number[] {
-            return this._vertexBuffers[kind].getData();
+            if (!this._geometry) {
+                return null;
+            }
+            return this._geometry.getVerticesData(kind);
         }
 
         public getVertexBuffer(kind): VertexBuffer {
-            return this._vertexBuffers[kind];
+            if (!this._geometry) {
+                return undefined;
+            }
+            return this._geometry.getVertexBuffer(kind);
         }
 
         public isVerticesDataPresent(kind: string): boolean {
-            if (!this._vertexBuffers) {
+            if (!this._geometry) {
                 if (this._delayInfo) {
                     return this._delayInfo.indexOf(kind) !== -1;
                 }
                 return false;
             }
-            return this._vertexBuffers[kind] !== undefined;
+            return this._geometry.isVerticesDataPresent(kind);
         }
 
         public getVerticesDataKinds(): string[] {
-            var result = [];
-            if (!this._vertexBuffers && this._delayInfo) {
-                for (var kind in this._delayInfo) {
-                    result.push(kind);
-                }
-            } else {
-                for (kind in this._vertexBuffers) {
-                    result.push(kind);
+            if (!this._geometry) {
+                var result = [];
+                if (this._delayInfo) {
+                    for (var kind in this._delayInfo) {
+                        result.push(kind);
+                    }
                 }
+                return result;
             }
-
-            return result;
+            return this._geometry.getVerticesDataKinds();
         }
 
         public getTotalIndices(): number {
-            return this._indices.length;
+            if (!this._geometry) {
+                return 0;
+            }
+            return this._geometry.getTotalIndices();
         }
 
         public getIndices(): number[] {
-            return this._indices;
+            if (!this._geometry) {
+                return [];
+            }
+            return this._geometry.getIndices();
         }
 
         public setPivotMatrix(matrix: Matrix): void {
@@ -279,15 +289,15 @@
         public refreshBoundingInfo(): void {
             var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
 
-            if (!data) {
-                return;
+            if (data) {
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices());
+                this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
             }
 
-            var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
-            this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                this.subMeshes[index].refreshBoundingInfo();
+            if (this.subMeshes) {
+                for (var index = 0; index < this.subMeshes.length; index++) {
+                    this.subMeshes[index].refreshBoundingInfo();
+                }
             }
 
             this._updateBoundingInfo();
@@ -399,12 +409,13 @@
 
 
         public _createGlobalSubMesh(): SubMesh {
-            if (!this._totalVertices || !this._indices) {
+            var totalVertices = this.getTotalVertices();
+            if (!totalVertices || !this.getIndices()) {
                 return null;
             }
 
             this.subMeshes = [];
-            return new BABYLON.SubMesh(0, 0, this._totalVertices, 0, this._indices.length, this);
+            return new BABYLON.SubMesh(0, 0, totalVertices, 0, this.getTotalIndices(), this);
         }
 
         public subdivide(count: number): void {
@@ -412,85 +423,86 @@
                 return;
             }
 
-            var subdivisionSize = this._indices.length / count;
+            var totalIndices = this.getTotalIndices();
+            var subdivisionSize = totalIndices / count;
             var offset = 0;
 
             this.subMeshes = [];
             for (var index = 0; index < count; index++) {
-                BABYLON.SubMesh.CreateFromIndices(0, offset, Math.min(subdivisionSize, this._indices.length - offset), this);
+                BABYLON.SubMesh.CreateFromIndices(0, offset, Math.min(subdivisionSize, totalIndices - offset), this);
 
                 offset += subdivisionSize;
             }
         }
 
         public setVerticesData(data: number[], kind: string, updatable?: boolean): void {
-            if (!this._vertexBuffers) {
-                this._vertexBuffers = {};
-            }
-
-            if (this._vertexBuffers[kind]) {
-                this._vertexBuffers[kind].dispose();
-            }
-
-            this._vertexBuffers[kind] = new BABYLON.VertexBuffer(this, data, kind, updatable);
+            if (!this._geometry) {
+                var vertexData = new BABYLON.VertexData();
+                vertexData.set(data, kind);
 
-            if (kind === BABYLON.VertexBuffer.PositionKind) {
-                this._resetPointsArrayCache();
+                var scene = this.getScene();
 
-                var stride = this._vertexBuffers[kind].getStrideSize();
-                this._totalVertices = data.length / stride;
-
-                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
-                this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-
-                this._createGlobalSubMesh();
+                new BABYLON.Geometry(Geometry.RandomId(), scene.getEngine(), vertexData, updatable, this);
+            }
+            else {
+                this._geometry.setVerticesData(data, kind, updatable);
             }
         }
 
-        public updateVerticesData(kind: string, data: number[], updateExtends?: boolean): void {
-            if (this._vertexBuffers[kind]) {
-                this._vertexBuffers[kind].update(data);
-
-                if (kind === BABYLON.VertexBuffer.PositionKind) {
-                    this._resetPointsArrayCache();
-
-                    if (updateExtends) {
-                        var stride = this._vertexBuffers[kind].getStrideSize();
-                        this._totalVertices = data.length / stride;
+        public updateVerticesData(kind: string, data: number[], updateExtends?: boolean, makeItUnique?: boolean): void {
+            if (!this._geometry) {
+                return;
+            }
+            if (!makeItUnique) {
+                this._geometry.updateVerticesData(kind, data, updateExtends);
+            }
+            else {
+                this.makeGeometryUnique();
+                this.updateVerticesData(kind, data, updateExtends, false);
+            }
+        }
 
-                        var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
-                        this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-                    }
-                }
+        public makeGeometryUnique() {
+            if (!this._geometry) {
+                return;
             }
+            var geometry = this._geometry.copy(Geometry.RandomId());
+            geometry.applyToMesh(this);
         }
 
         public setIndices(indices: number[]): void {
-            if (this._indexBuffer) {
-                this.getScene().getEngine()._releaseBuffer(this._indexBuffer);
-            }
+            if (!this._geometry) {
+                var vertexData = new BABYLON.VertexData();
+                vertexData.indices = indices;
 
-            this._indexBuffer = this.getScene().getEngine().createIndexBuffer(indices);
-            this._indices = indices;
+                var scene = this.getScene();
 
-            this._createGlobalSubMesh();
+                new BABYLON.Geometry(BABYLON.Geometry.RandomId(), scene.getEngine(), vertexData, false, this);
+            }
+            else {
+                this._geometry.setIndices(indices);
+            }
         }
 
         // ANY
         public bindAndDraw(subMesh: SubMesh, effect, wireframe?: boolean): void {
+            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
+                return;
+            }
+
             var engine = this.getScene().getEngine();
 
             // Wireframe
-            var indexToBind = this._indexBuffer;
+            var indexToBind = this._geometry.getIndexBuffer();
             var useTriangles = true;
 
             if (wireframe) {
-                indexToBind = subMesh.getLinesIndexBuffer(this._indices, engine);
+                indexToBind = subMesh.getLinesIndexBuffer(this.getIndices(), engine);
                 useTriangles = false;
             }
 
             // VBOs
-            engine.bindMultiBuffers(this._vertexBuffers, indexToBind, effect);
+            engine.bindMultiBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
 
             // Draw order
             engine.draw(useTriangles, useTriangles ? subMesh.indexStart : 0, useTriangles ? subMesh.indexCount : subMesh.linesIndexCount);
@@ -509,7 +521,7 @@
         }
 
         public render(subMesh: SubMesh): void {
-            if (!this._vertexBuffers || !this._indexBuffer) {
+            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
                 return;
             }
 
@@ -582,20 +594,29 @@
                 return false;
             }
 
-            var result = this._boundingInfo.isInFrustum(frustumPlanes);
+            if (!this._boundingInfo.isInFrustum(frustumPlanes)) {
+                return false;
+            }
 
-            if (result && this.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) { 
-                this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADING; 
-                this.getScene()._addPendingData(this);
+            var that = this;
+            var scene = this.getScene();
 
-                Tools.LoadFile(this.delayLoadingFile, data => {
-                    this._delayLoadingFunction(JSON.parse(data), this);
-                    this.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADED; 
-                    this.getScene()._removePendingData(this);
-                }, () => { }, this.getScene().database);
+            if (this._geometry) {
+                this._geometry.load(scene);
             }
+            else if (that.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
+                that.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_LOADING;
 
-            return result;
+                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);
+            }
+
+            return true;
         }
 
         public setMaterialByID(id: string): void {
@@ -656,25 +677,25 @@
 
             this._resetPointsArrayCache();
 
-            var data = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].getData();
+            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             var temp = [];
             for (var index = 0; index < data.length; index += 3) {
                 BABYLON.Vector3.TransformCoordinates(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
             }
 
-            this.setVerticesData(temp, BABYLON.VertexBuffer.PositionKind, this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].isUpdatable());
+            this.setVerticesData(temp, BABYLON.VertexBuffer.PositionKind, this.getVertexBuffer(BABYLON.VertexBuffer.PositionKind).isUpdatable());
 
             // Normals
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
                 return;
             }
 
-            data = this._vertexBuffers[BABYLON.VertexBuffer.NormalKind].getData();
+            data = this.getVerticesData(BABYLON.VertexBuffer.NormalKind);
             for (index = 0; index < data.length; index += 3) {
                 BABYLON.Vector3.TransformNormal(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
             }
 
-            this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this._vertexBuffers[BABYLON.VertexBuffer.NormalKind].isUpdatable());
+            this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable());
         }
 
         public lookAt(targetPoint: Vector3, yawCor: number, pitchCor: number, rollCor: number): void {
@@ -707,7 +728,7 @@
 
             this._positions = [];
 
-            var data = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].getData();
+            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             for (var index = 0; index < data.length; index += 3) {
                 this._positions.push(BABYLON.Vector3.FromArray(data, index));
             }
@@ -728,7 +749,7 @@
                 }
             }
             // Collide
-            collider._collide(subMesh, subMesh._lastColliderWorldVertices, this._indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
+            collider._collide(subMesh, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
         }
 
         public _processCollisionsForSubModels(collider: Collider, transformMatrix: Matrix): void {
@@ -790,7 +811,7 @@
                 if (this.subMeshes.length > 1 && !subMesh.canIntersects(ray))
                     continue;
 
-                var currentIntersectInfo = subMesh.intersects(ray, this._positions, this._indices, fastCheck);
+                var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);
 
                 if (currentIntersectInfo) {
                     if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
@@ -832,20 +853,14 @@
         public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): Mesh {
             var result = new BABYLON.Mesh(name, this.getScene());
 
-            // Buffers
-            result._vertexBuffers = this._vertexBuffers;
-            for (var kind in result._vertexBuffers) {
-                result._vertexBuffers[kind]._buffer.references++;
-            }
-
-            result._indexBuffer = this._indexBuffer;
-            this._indexBuffer.references++;
+            // Geometry
+            this._geometry.applyToMesh(result);
 
             // Deep copy
-            BABYLON.Tools.DeepCopy(this, result, ["name", "material", "skeleton"], ["_indices", "_totalVertices"]);
+            BABYLON.Tools.DeepCopy(this, result, ["name", "material", "skeleton"], []);
 
             // Bounding info
-            var extend = BABYLON.Tools.ExtractMinAndMax(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this._totalVertices);
+            var extend = BABYLON.Tools.ExtractMinAndMax(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this.getTotalVertices());
             result._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
 
             // Material
@@ -883,16 +898,8 @@
 
         // Dispose
         public dispose(doNotRecurse?: boolean): void {
-            if (this._vertexBuffers) {
-                for (var vbKind in this._vertexBuffers) {
-                    this._vertexBuffers[vbKind].dispose();
-                }
-                this._vertexBuffers = null;
-            }
-
-            if (this._indexBuffer) {
-                this.getScene().getEngine()._releaseBuffer(this._indexBuffer);
-                this._indexBuffer = null;
+            if (this._geometry) {
+                this._geometry.releaseForMesh(this);
             }
 
             // Physics
@@ -1032,15 +1039,16 @@
             var updatableNormals = false;
             for (var kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
                 var kind = kinds[kindIndex];
+                var vertexBuffer = this.getVertexBuffer(kind);
 
                 if (kind === BABYLON.VertexBuffer.NormalKind) {
-                    updatableNormals = this.getVertexBuffer(kind).isUpdatable();
+                    updatableNormals = vertexBuffer.isUpdatable();
                     kinds.splice(kindIndex, 1);
                     kindIndex--;
                     continue;
                 }
 
-                vbs[kind] = this.getVertexBuffer(kind);
+                vbs[kind] = vertexBuffer;
                 data[kind] = vbs[kind].getData();
                 newdata[kind] = [];
             }
@@ -1049,9 +1057,10 @@
             var previousSubmeshes = this.subMeshes.slice(0);
 
             var indices = this.getIndices();
+            var totalIndices = this.getTotalIndices();
 
             // Generating unique vertices per face
-            for (index = 0; index < indices.length; index++) {
+            for (index = 0; index < totalIndices; index++) {
                 var vertexIndex = indices[index];
 
                 for (kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
@@ -1067,7 +1076,7 @@
             // Updating faces & normal
             var normals = [];
             var positions = newdata[BABYLON.VertexBuffer.PositionKind];
-            for (var index = 0; index < indices.length; index += 3) {
+            for (var index = 0; index < totalIndices; index += 3) {
                 indices[index] = index;
                 indices[index + 1] = index + 1;
                 indices[index + 2] = index + 2;

+ 65 - 23
Babylon/Mesh/babylon.mesh.vertexData.js

@@ -3,37 +3,71 @@
     var VertexData = (function () {
         function VertexData() {
         }
+        VertexData.prototype.set = function (data, kind) {
+            switch (kind) {
+                case BABYLON.VertexBuffer.PositionKind:
+                    this.positions = data;
+                    break;
+                case BABYLON.VertexBuffer.NormalKind:
+                    this.normals = data;
+                    break;
+                case BABYLON.VertexBuffer.UVKind:
+                    this.uvs = data;
+                    break;
+                case BABYLON.VertexBuffer.UV2Kind:
+                    this.uv2s = data;
+                    break;
+                case BABYLON.VertexBuffer.ColorKind:
+                    this.colors = data;
+                    break;
+                case BABYLON.VertexBuffer.MatricesIndicesKind:
+                    this.matricesIndices = data;
+                    break;
+                case BABYLON.VertexBuffer.MatricesWeightsKind:
+                    this.matricesWeights = data;
+                    break;
+            }
+        };
+
         VertexData.prototype.applyToMesh = function (mesh, updatable) {
+            this._applyTo(mesh, updatable);
+        };
+
+        VertexData.prototype.applyToGeometry = function (geometry, updatable) {
+            this._applyTo(geometry, updatable);
+        };
+
+        VertexData.prototype._applyTo = function (meshOrGeometry, updatable) {
             if (this.positions) {
-                mesh.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
+                meshOrGeometry.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
             }
 
             if (this.normals) {
-                mesh.setVerticesData(this.normals, BABYLON.VertexBuffer.NormalKind, updatable);
+                meshOrGeometry.setVerticesData(this.normals, BABYLON.VertexBuffer.NormalKind, updatable);
             }
 
             if (this.uvs) {
-                mesh.setVerticesData(this.uvs, BABYLON.VertexBuffer.UVKind, updatable);
+                meshOrGeometry.setVerticesData(this.uvs, BABYLON.VertexBuffer.UVKind, updatable);
             }
 
             if (this.uv2s) {
-                mesh.setVerticesData(this.uv2s, BABYLON.VertexBuffer.UV2Kind, updatable);
+                meshOrGeometry.setVerticesData(this.uv2s, BABYLON.VertexBuffer.UV2Kind, updatable);
             }
 
             if (this.colors) {
-                mesh.setVerticesData(this.colors, BABYLON.VertexBuffer.ColorKind, updatable);
+                meshOrGeometry.setVerticesData(this.colors, BABYLON.VertexBuffer.ColorKind, updatable);
             }
 
             if (this.matricesIndices) {
-                mesh.setVerticesData(this.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, updatable);
+                meshOrGeometry.setVerticesData(this.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, updatable);
             }
 
             if (this.matricesWeights) {
-                mesh.setVerticesData(this.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, updatable);
+                meshOrGeometry.setVerticesData(this.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, updatable);
             }
 
             if (this.indices) {
-                mesh.setIndices(this.indices);
+                meshOrGeometry.setIndices(this.indices);
             }
         };
 
@@ -146,37 +180,45 @@
 
         // Statics
         VertexData.ExtractFromMesh = function (mesh) {
+            return VertexData._ExtractFrom(mesh);
+        };
+
+        VertexData.ExtractFromGeometry = function (geometry) {
+            return VertexData._ExtractFrom(geometry);
+        };
+
+        VertexData._ExtractFrom = function (meshOrGeometry) {
             var result = new BABYLON.VertexData();
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
-                result.positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+                result.positions = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
-                result.normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                result.normals = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.NormalKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                result.uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                result.uvs = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.UVKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                result.uv2s = mesh.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                result.uv2s = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                result.colors = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                result.colors = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.ColorKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
-                result.matricesIndices = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
+                result.matricesIndices = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
-                result.matricesWeights = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+                result.matricesWeights = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
             }
 
-            result.indices = mesh.getIndices();
+            result.indices = meshOrGeometry.getIndices();
 
             return result;
         };

+ 73 - 23
Babylon/Mesh/babylon.mesh.vertexData.ts

@@ -1,4 +1,12 @@
 module BABYLON {
+    export interface IGetSetVerticesData {
+        isVerticesDataPresent(kind: string): boolean;
+        getVerticesData(kind: string): number[];
+        getIndices(): number[];
+        setVerticesData(data: number[], kind: string, updatable?: boolean): void;
+        setIndices(indices: number[]): void;
+    }
+
     export class VertexData {
         public positions: number[];
         public normals: number[];
@@ -9,37 +17,71 @@
         public matricesWeights: number[];
         public indices: number[];
 
+        public set(data: number[], kind: string) {
+            switch (kind) {
+                case BABYLON.VertexBuffer.PositionKind:
+                    this.positions = data;
+                    break;
+                case BABYLON.VertexBuffer.NormalKind:
+                    this.normals = data;
+                    break;
+                case BABYLON.VertexBuffer.UVKind:
+                    this.uvs = data;
+                    break;
+                case BABYLON.VertexBuffer.UV2Kind:
+                    this.uv2s = data;
+                    break;
+                case BABYLON.VertexBuffer.ColorKind:
+                    this.colors = data;
+                    break;
+                case BABYLON.VertexBuffer.MatricesIndicesKind:
+                    this.matricesIndices = data;
+                    break;
+                case BABYLON.VertexBuffer.MatricesWeightsKind:
+                    this.matricesWeights = data;
+                    break;
+            }
+        }
+
         public applyToMesh(mesh: Mesh, updatable?: boolean): void {
+            this._applyTo(mesh, updatable);
+        }
+
+        public applyToGeometry(geometry: Geometry, updatable?: boolean): void {
+            this._applyTo(geometry, updatable);
+        }
+
+        private _applyTo(meshOrGeometry: IGetSetVerticesData, updatable?: boolean) {
             if (this.positions) {
-                mesh.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
+                meshOrGeometry.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
             }
 
             if (this.normals) {
-                mesh.setVerticesData(this.normals, BABYLON.VertexBuffer.NormalKind, updatable);
+                meshOrGeometry.setVerticesData(this.normals, BABYLON.VertexBuffer.NormalKind, updatable);
             }
 
             if (this.uvs) {
-                mesh.setVerticesData(this.uvs, BABYLON.VertexBuffer.UVKind, updatable);
+                meshOrGeometry.setVerticesData(this.uvs, BABYLON.VertexBuffer.UVKind, updatable);
             }
 
             if (this.uv2s) {
-                mesh.setVerticesData(this.uv2s, BABYLON.VertexBuffer.UV2Kind, updatable);
+                meshOrGeometry.setVerticesData(this.uv2s, BABYLON.VertexBuffer.UV2Kind, updatable);
             }
 
             if (this.colors) {
-                mesh.setVerticesData(this.colors, BABYLON.VertexBuffer.ColorKind, updatable);
+                meshOrGeometry.setVerticesData(this.colors, BABYLON.VertexBuffer.ColorKind, updatable);
             }
 
             if (this.matricesIndices) {
-                mesh.setVerticesData(this.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, updatable);
+                meshOrGeometry.setVerticesData(this.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, updatable);
             }
 
             if (this.matricesWeights) {
-                mesh.setVerticesData(this.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, updatable);
+                meshOrGeometry.setVerticesData(this.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, updatable);
             }
 
             if (this.indices) {
-                mesh.setIndices(this.indices);
+                meshOrGeometry.setIndices(this.indices);
             }
         }
 
@@ -152,37 +194,45 @@
 
         // Statics
         public static ExtractFromMesh(mesh: Mesh): VertexData {
+            return VertexData._ExtractFrom(mesh);
+        }
+
+        public static ExtractFromGeometry(geometry: Geometry): VertexData {
+            return VertexData._ExtractFrom(geometry);
+        }
+
+        private static _ExtractFrom(meshOrGeometry: IGetSetVerticesData): VertexData {
             var result = new BABYLON.VertexData();
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
-                result.positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+                result.positions = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
-                result.normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                result.normals = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.NormalKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                result.uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                result.uvs = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.UVKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                result.uv2s = mesh.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                result.uv2s = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                result.colors = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                result.colors = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.ColorKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
-                result.matricesIndices = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
+                result.matricesIndices = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
-                result.matricesWeights = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+            if (meshOrGeometry.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+                result.matricesWeights = meshOrGeometry.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
             }
 
-            result.indices = mesh.getIndices();
+            result.indices = meshOrGeometry.getIndices();
 
             return result;
         }

+ 4 - 0
Babylon/Mesh/babylon.subMesh.js

@@ -39,6 +39,7 @@
             var data = this._mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
 
             if (!data) {
+                this._boundingInfo = this._mesh._boundingInfo;
                 return;
             }
 
@@ -51,6 +52,9 @@
         };
 
         SubMesh.prototype.updateBoundingInfo = function (world) {
+            if (!this._boundingInfo) {
+                this.refreshBoundingInfo();
+            }
             this._boundingInfo._update(world);
         };
 

+ 4 - 0
Babylon/Mesh/babylon.subMesh.ts

@@ -43,6 +43,7 @@
             var data = this._mesh.getVerticesData(VertexBuffer.PositionKind);
 
             if (!data) {
+                this._boundingInfo = this._mesh._boundingInfo;
                 return;
             }
 
@@ -55,6 +56,9 @@
         }
 
         public updateBoundingInfo(world: Matrix): void {
+            if (!this._boundingInfo) {
+                this.refreshBoundingInfo();
+            }
             this._boundingInfo._update(world);
         }
 

+ 35 - 20
Babylon/Mesh/babylon.vertexBuffer.js

@@ -1,27 +1,26 @@
 var BABYLON;
 (function (BABYLON) {
     var VertexBuffer = (function () {
-        function VertexBuffer(mesh, data, kind, updatable, engine) {
-            this._mesh = mesh;
-            this._engine = engine || mesh.getScene().getEngine();
-            this._updatable = updatable;
-
-            if (updatable) {
-                this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
-                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+        function VertexBuffer(engine, data, kind, updatable, postponeInternalCreation) {
+            if (engine instanceof BABYLON.Mesh) {
+                this._engine = engine.getScene().getEngine();
             } else {
-                this._buffer = this._engine.createVertexBuffer(data);
+                this._engine = engine;
             }
 
+            this._updatable = updatable;
+
             this._data = data;
+
+            if (!postponeInternalCreation) {
+                this.create();
+            }
+
             this._kind = kind;
 
             switch (kind) {
                 case VertexBuffer.PositionKind:
                     this._strideSize = 3;
-                    if (this._mesh) {
-                        this._mesh._resetPointsArrayCache();
-                    }
                     break;
                 case VertexBuffer.NormalKind:
                     this._strideSize = 3;
@@ -61,22 +60,38 @@
         };
 
         // Methods
-        VertexBuffer.prototype.update = function (data) {
-            if (!this._updatable) {
-                console.log("You cannot update a non-updatable vertex buffer");
+        VertexBuffer.prototype.create = function (data) {
+            if (!data && this._buffer) {
                 return;
             }
 
-            this._engine.updateDynamicVertexBuffer(this._buffer, data);
-            this._data = data;
+            data = data || this._data;
 
-            if (this._kind === BABYLON.VertexBuffer.PositionKind && this._mesh) {
-                this._mesh._resetPointsArrayCache();
+            if (!this._buffer) {
+                if (this._updatable) {
+                    this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
+                } else {
+                    this._buffer = this._engine.createVertexBuffer(data);
+                }
+            }
+
+            if (this._updatable) {
+                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+                this._data = data;
             }
         };
 
+        VertexBuffer.prototype.update = function (data) {
+            this.create(data);
+        };
+
         VertexBuffer.prototype.dispose = function () {
-            this._engine._releaseBuffer(this._buffer);
+            if (!this._buffer) {
+                return;
+            }
+            if (this._engine._releaseBuffer(this._buffer)) {
+                this._buffer = null;
+            }
         };
 
         VertexBuffer.PositionKind = "position";

+ 37 - 21
Babylon/Mesh/babylon.vertexBuffer.ts

@@ -8,27 +8,27 @@
         private _kind: string;
         private _strideSize: number;
 
-        constructor(mesh: Mesh, data: number[], kind: string, updatable: boolean, engine?: Engine) {
-            this._mesh = mesh;
-            this._engine = engine || mesh.getScene().getEngine();
+        constructor(engine: any, data: number[], kind: string, updatable: boolean, postponeInternalCreation?: boolean) {
+            if (engine instanceof Mesh) { // old versions of BABYLON.VertexBuffer accepted 'mesh' instead of 'engine'
+                this._engine = engine.getScene().getEngine();
+            }
+            else {
+                this._engine = engine;
+            }
+
             this._updatable = updatable;
 
-            if (updatable) {
-                this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
-                this._engine.updateDynamicVertexBuffer(this._buffer, data);
-            } else {
-                this._buffer = this._engine.createVertexBuffer(data);
+            this._data = data;
+
+            if (!postponeInternalCreation) { // by default
+                this.create();
             }
 
-            this._data = data;
             this._kind = kind;
 
             switch (kind) {
                 case VertexBuffer.PositionKind:
                     this._strideSize = 3;
-                    if (this._mesh) {
-                        this._mesh._resetPointsArrayCache();
-                    }
                     break;
                 case VertexBuffer.NormalKind:
                     this._strideSize = 3;
@@ -69,22 +69,38 @@
         }
 
         // Methods
-        public update(data: number[]): void {
-            if (!this._updatable) {
-                console.log("You cannot update a non-updatable vertex buffer");
-                return;
+        public create(data?: number[]): void {
+            if (!data && this._buffer) {
+                return; // nothing to do
             }
 
-            this._engine.updateDynamicVertexBuffer(this._buffer, data);
-            this._data = data;
+            data = data || this._data;
 
-            if (this._kind === BABYLON.VertexBuffer.PositionKind && this._mesh) {
-                this._mesh._resetPointsArrayCache();
+            if (!this._buffer) { // create buffer
+                if (this._updatable) {
+                    this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
+                } else {
+                    this._buffer = this._engine.createVertexBuffer(data);
+                }
+            }
+
+            if (this._updatable) { // update buffer
+                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+                this._data = data;
             }
         }
 
+        public update(data: number[]): void {
+            this.create(data);
+        }
+
         public dispose(): void {
-            this._engine._releaseBuffer(this._buffer);
+            if (!this._buffer) {
+                return;
+            }
+            if (this._engine._releaseBuffer(this._buffer)) {
+                this._buffer = null;
+            }
         }
 
         // Enums

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

@@ -14,7 +14,7 @@
 
             var engine = this._scene.getEngine();
             var boxdata = BABYLON.VertexData.CreateBox(1.0);
-            this._vb = new BABYLON.VertexBuffer(null, boxdata.positions, BABYLON.VertexBuffer.PositionKind, false, engine);
+            this._vb = new BABYLON.VertexBuffer(engine, boxdata.positions, BABYLON.VertexBuffer.PositionKind, false);
             this._ib = engine.createIndexBuffer([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 7, 1, 6, 2, 5, 3, 4]);
         }
         BoundingBoxRenderer.prototype.reset = function () {

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

@@ -22,7 +22,7 @@
 
             var engine = this._scene.getEngine();
             var boxdata = BABYLON.VertexData.CreateBox(1.0);
-            this._vb = new BABYLON.VertexBuffer(null, boxdata.positions, BABYLON.VertexBuffer.PositionKind, false, engine);
+            this._vb = new BABYLON.VertexBuffer(engine, boxdata.positions, BABYLON.VertexBuffer.PositionKind, false);
             this._ib = engine.createIndexBuffer([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 7, 1, 6, 2, 5, 3, 4]);
         }
 

+ 2 - 1
Babylon/Tools/babylon.filesInput.js

@@ -80,7 +80,8 @@ var BABYLON = BABYLON || {};
         if (filesToLoad && filesToLoad.length > 0) {
             for (var i = 0; i < filesToLoad.length; i++) {
                 if (filesToLoad[i].name.indexOf(".babylon") !== -1 && filesToLoad[i].name.indexOf(".manifest") === -1
-				 && filesToLoad[i].name.indexOf(".incremental") === -1 && filesToLoad[i].name.indexOf(".babylonmeshdata") === -1) {
+				 && filesToLoad[i].name.indexOf(".incremental") === -1 && filesToLoad[i].name.indexOf(".babylonmeshdata") === -1
+                 && filesToLoad[i].name.indexOf(".babylongeometrydata") === -1) {
                     sceneFileToLoad = filesToLoad[i];
                 }
                 else {

+ 190 - 28
Babylon/Tools/babylon.sceneSerializer.js

@@ -351,12 +351,169 @@
         return serializationObject;
     };
 
-    var serializeMesh = function (mesh) {
+    var serializedGeometries = [];
+    var serializeGeometry = function (geometry, serializationGeometries) {
+        if (serializedGeometries[geometry.id]) {
+            return;
+        }
+        if (geometry instanceof BABYLON.Geometry.Primitives.Box) {
+            serializationGeometries.boxes.push(serializeBox(geometry));
+        } else if (geometry instanceof BABYLON.Geometry.Primitives.Sphere) {
+            serializationGeometries.spheres.push(serializeSphere(geometry));
+        } else if (geometry instanceof BABYLON.Geometry.Primitives.Cylinder) {
+            serializationGeometries.cylinders.push(serializeCylinder(geometry));
+        } else if (geometry instanceof BABYLON.Geometry.Primitives.Torus) {
+            serializationGeometries.toruses.push(serializeTorus(geometry));
+        } else if (geometry instanceof BABYLON.Geometry.Primitives.Ground) {
+            serializationGeometries.grounds.push(serializeGround(geometry));
+        } else if (geometry instanceof BABYLON.Geometry.Primitives.Plane) {
+            serializationGeometries.planes.push(serializePlane(geometry));
+        } else if (geometry instanceof BABYLON.Geometry.Primitives.TorusKnot) {
+            serializationGeometries.torusKnots.push(serializeTorusKnot(geometry));
+        } else if (geometry instanceof BABYLON.Geometry.Primitives._Primitive) {
+            throw new Error("Unknow primitive type");
+        } else {
+            serializationGeometries.vertexData.push(serializeVertexData(geometry));
+        }
+
+        serializedGeometries[geometry.id] = true;
+    };
+
+    var serializeGeometryBase = function (geometry) {
+        var serializationObject = {};
+
+        serializationObject.id = geometry.id;
+
+        if (BABYLON.Tags.HasTags(geometry)) {
+            serializationObject.tags = BABYLON.Tags.GetTags(geometry);
+        }
+
+        return serializationObject;
+    };
+
+    var serializeVertexData = function (vertexData) {
+        var serializationObject = serializeGeometryBase(vertexData);
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+            serializationObject.positions = vertexData.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+            serializationObject.normals = vertexData.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+            serializationObject.uvs = vertexData.getVerticesData(BABYLON.VertexBuffer.UVKind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+            serializationObject.uvs2 = vertexData.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+            serializationObject.colors = vertexData.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
+            serializationObject.matricesIndices = vertexData.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+            serializationObject.matricesIndices._isExpanded = true;
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            serializationObject.matricesWeights = vertexData.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+        }
+
+        serializationObject.indices = vertexData.getIndices();
+
+        return serializationObject;
+    };
+
+    var serializePrimitive = function (primitive) {
+        var serializationObject = serializeGeometryBase(primitive);
+
+        serializationObject.canBeRegenerated = primitive.canBeRegenerated();
+
+        return serializationObject;
+    };
+
+    var serializeBox = function (box) {
+        var serializationObject = serializePrimitive(box);
+
+        serializationObject.size = box.size;
+
+        return serializationObject;
+    };
+
+    var serializeSphere = function (sphere) {
+        var serializationObject = serializePrimitive(sphere);
+
+        serializationObject.segments = sphere.segments;
+        serializationObject.diameter = sphere.diameter;
+
+        return serializationObject;
+    };
+
+    var serializeCylinder = function (cylinder) {
+        var serializationObject = serializePrimitive(cylinder);
+
+        serializationObject.height = cylinder.height;
+        serializationObject.diameterTop = cylinder.diameterTop;
+        serializationObject.diameterBottom = cylinder.diameterBottom;
+        serializationObject.tessellation = cylinder.tessellation;
+
+        return serializationObject;
+    };
+
+    var serializeTorus = function (torus) {
+        var serializationObject = serializePrimitive(torus);
+
+        serializationObject.diameter = torus.diameter;
+        serializationObject.thickness = torus.thickness;
+        serializationObject.tessellation = torus.tessellation;
+
+        return serializationObject;
+    };
+
+    var serializeGround = function (ground) {
+        var serializationObject = serializePrimitive(ground);
+
+        serializationObject.width = ground.width;
+        serializationObject.height = ground.height;
+        serializationObject.subdivisions = ground.subdivisions;
+
+        return serializationObject;
+    };
+
+    var serializePlane = function (plane) {
+        var serializationObject = serializePrimitive(plane);
+
+        serializationObject.size = plane.size;
+
+        return serializationObject;
+    };
+
+    var serializeTorusKnot = function (torusKnot) {
+        var serializationObject = serializePrimitive(torusKnot);
+
+        serializationObject.radius = torusKnot.radius;
+        serializationObject.tube = torusKnot.tube;
+        serializationObject.radialSegments = torusKnot.radialSegments;
+        serializationObject.tubularSegments = torusKnot.tubularSegments;
+        serializationObject.p = torusKnot.p;
+        serializationObject.q = torusKnot.q;
+
+        return serializationObject;
+    };
+
+    var serializeMesh = function (mesh, serializationScene) {
         var serializationObject = {};
 
         serializationObject.name = mesh.name;
         serializationObject.id = mesh.id;
-        serializationObject.tags = BABYLON.Tags.GetTags(mesh);
+
+        if (BABYLON.Tags.HasTags(mesh)) {
+            serializationObject.tags = BABYLON.Tags.GetTags(mesh);
+        }
 
         serializationObject.position = mesh.position.asArray();
 
@@ -387,33 +544,16 @@
         }
 
         // Geometry
-        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
-            serializationObject.positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            serializationObject.normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
-
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                serializationObject.uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
-            }
-
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                serializationObject.uvs2 = mesh.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
-            }
-
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                serializationObject.colors = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+        var geometry = mesh._geometry;
+        if (geometry) {
+            var geometryId = geometry.id;
+            serializationObject.geometryId = geometryId;
+
+            if (!mesh.getScene().getGeometryByID(geometryId)) {
+                // geometry was in the memory but not added to the scene, nevertheless it's better to serialize too be able to reload the mesh with its geometry
+                serializeGeometry(geometry, serializationScene.geometries);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
-                serializationObject.matricesWeights = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
-            }
-
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
-                serializationObject.matricesIndices = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
-                serializationObject.matricesIndices._isExpanded = true;
-            }
-
-            serializationObject.indices = mesh.getIndices();
-
             // SubMeshes
             serializationObject.subMeshes = [];
             for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
@@ -525,13 +665,35 @@
                 serializationObject.skeletons.push(serializeSkeleton(scene.skeletons[index]));
             }
 
+            // Geometries
+            serializationObject.geometries = {};
+
+            serializationObject.geometries.boxes = [];
+            serializationObject.geometries.spheres = [];
+            serializationObject.geometries.cylinders = [];
+            serializationObject.geometries.toruses = [];
+            serializationObject.geometries.grounds = [];
+            serializationObject.geometries.planes = [];
+            serializationObject.geometries.torusKnots = [];
+            serializationObject.geometries.vertexData = [];
+
+            serializedGeometries = [];
+            var geometries = scene.getGeometries();
+            for (var index = 0; index < geometries.length; index++) {
+                var geometry = geometries[index];
+
+                if (geometry.isReady()) {
+                    serializeGeometry(geometry, serializationObject.geometries);
+                }
+            }
+
             // Meshes
             serializationObject.meshes = [];
             for (index = 0; index < scene.meshes.length; index++) {
                 var mesh = scene.meshes[index];
 
                 if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) {
-                    serializationObject.meshes.push(serializeMesh(mesh));
+                    serializationObject.meshes.push(serializeMesh(mesh, serializationObject));
                 }
             }
 

+ 198 - 28
Babylon/Tools/babylon.sceneSerializer.ts

@@ -352,12 +352,177 @@
         return serializationObject;
     };
 
-    var serializeMesh = (mesh: Mesh):any => {
+    var serializedGeometries: Geometry[] = [];
+    var serializeGeometry = (geometry: Geometry, serializationGeometries: any): any => {
+        if (serializedGeometries[geometry.id]) {
+            return;
+        }
+        if (geometry instanceof Geometry.Primitives.Box) {
+            serializationGeometries.boxes.push(serializeBox(<Geometry.Primitives.Box>geometry));
+        }
+        else if (geometry instanceof Geometry.Primitives.Sphere) {
+            serializationGeometries.spheres.push(serializeSphere(<Geometry.Primitives.Sphere>geometry));
+        }
+        else if (geometry instanceof Geometry.Primitives.Cylinder) {
+            serializationGeometries.cylinders.push(serializeCylinder(<Geometry.Primitives.Cylinder>geometry));
+        }
+        else if (geometry instanceof Geometry.Primitives.Torus) {
+            serializationGeometries.toruses.push(serializeTorus(<Geometry.Primitives.Torus>geometry));
+        }
+        else if (geometry instanceof Geometry.Primitives.Ground) {
+            serializationGeometries.grounds.push(serializeGround(<Geometry.Primitives.Ground>geometry));
+        }
+        else if (geometry instanceof Geometry.Primitives.Plane) {
+            serializationGeometries.planes.push(serializePlane(<Geometry.Primitives.Plane>geometry));
+        }
+        else if (geometry instanceof Geometry.Primitives.TorusKnot) {
+            serializationGeometries.torusKnots.push(serializeTorusKnot(<Geometry.Primitives.TorusKnot>geometry));
+        }
+        else if (geometry instanceof Geometry.Primitives._Primitive) {
+            throw new Error("Unknow primitive type");
+        }
+        else {
+            serializationGeometries.vertexData.push(serializeVertexData(geometry));
+        }
+
+        serializedGeometries[geometry.id] = true;
+    };
+
+    var serializeGeometryBase = (geometry: Geometry): any => {
+        var serializationObject: any = {};
+
+        serializationObject.id = geometry.id;
+
+        if (Tags.HasTags(geometry)) {
+            serializationObject.tags = Tags.GetTags(geometry);
+        }
+
+        return serializationObject;
+    };
+
+    var serializeVertexData = (vertexData: Geometry): any => {
+        var serializationObject = serializeGeometryBase(vertexData);
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+            serializationObject.positions = vertexData.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+            serializationObject.normals = vertexData.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+            serializationObject.uvs = vertexData.getVerticesData(BABYLON.VertexBuffer.UVKind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+            serializationObject.uvs2 = vertexData.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+            serializationObject.colors = vertexData.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
+            serializationObject.matricesIndices = vertexData.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+            serializationObject.matricesIndices._isExpanded = true;
+        }
+
+        if (vertexData.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            serializationObject.matricesWeights = vertexData.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+        }
+
+        serializationObject.indices = vertexData.getIndices();
+
+        return serializationObject;
+    };
+
+    var serializePrimitive = (primitive: Geometry.Primitives._Primitive): any => {
+        var serializationObject = serializeGeometryBase(primitive);
+
+        serializationObject.canBeRegenerated = primitive.canBeRegenerated();
+
+        return serializationObject;
+    };
+
+    var serializeBox = (box: Geometry.Primitives.Box): any => {
+        var serializationObject = serializePrimitive(box);
+
+        serializationObject.size = box.size;
+
+        return serializationObject;
+    };
+
+    var serializeSphere = (sphere: Geometry.Primitives.Sphere): any => {
+        var serializationObject = serializePrimitive(sphere);
+
+        serializationObject.segments = sphere.segments;
+        serializationObject.diameter = sphere.diameter;
+
+        return serializationObject;
+    };
+
+    var serializeCylinder = (cylinder: Geometry.Primitives.Cylinder): any => {
+        var serializationObject = serializePrimitive(cylinder);
+
+        serializationObject.height = cylinder.height;
+        serializationObject.diameterTop = cylinder.diameterTop;
+        serializationObject.diameterBottom = cylinder.diameterBottom;
+        serializationObject.tessellation = cylinder.tessellation;
+
+        return serializationObject;
+    };
+
+    var serializeTorus = (torus: Geometry.Primitives.Torus): any => {
+        var serializationObject = serializePrimitive(torus);
+
+        serializationObject.diameter = torus.diameter;
+        serializationObject.thickness = torus.thickness;
+        serializationObject.tessellation = torus.tessellation;
+
+        return serializationObject;
+    };
+
+    var serializeGround = (ground: Geometry.Primitives.Ground): any => {
+        var serializationObject = serializePrimitive(ground);
+
+        serializationObject.width = ground.width;
+        serializationObject.height = ground.height;
+        serializationObject.subdivisions = ground.subdivisions;
+
+        return serializationObject;
+    };
+
+    var serializePlane = (plane: Geometry.Primitives.Plane): any => {
+        var serializationObject = serializePrimitive(plane);
+
+        serializationObject.size = plane.size;
+
+        return serializationObject;
+    };
+
+    var serializeTorusKnot = (torusKnot: Geometry.Primitives.TorusKnot): any => {
+        var serializationObject = serializePrimitive(torusKnot);
+
+        serializationObject.radius = torusKnot.radius;
+        serializationObject.tube = torusKnot.tube;
+        serializationObject.radialSegments = torusKnot.radialSegments;
+        serializationObject.tubularSegments = torusKnot.tubularSegments;
+        serializationObject.p = torusKnot.p;
+        serializationObject.q = torusKnot.q;
+
+        return serializationObject;
+    };
+
+    var serializeMesh = (mesh: Mesh, serializationScene: any):any => {
         var serializationObject:any = {};
 
         serializationObject.name = mesh.name;
         serializationObject.id = mesh.id;
-        serializationObject.tags = Tags.GetTags(mesh);
+
+        if (Tags.HasTags(mesh)) {
+            serializationObject.tags = Tags.GetTags(mesh);
+        }
 
         serializationObject.position = mesh.position.asArray();
 
@@ -388,33 +553,16 @@
         }
 
         // Geometry
-        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
-            serializationObject.positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            serializationObject.normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
-
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                serializationObject.uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+        var geometry = mesh._geometry;
+        if (geometry) {
+            var geometryId = geometry.id;
+            serializationObject.geometryId = geometryId;
+
+            if (!mesh.getScene().getGeometryByID(geometryId)) {
+                // geometry was in the memory but not added to the scene, nevertheless it's better to serialize too be able to reload the mesh with its geometry
+                serializeGeometry(geometry, serializationScene.geometries);
             }
 
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                serializationObject.uvs2 = mesh.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
-            }
-
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                serializationObject.colors = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
-            }
-
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
-                serializationObject.matricesWeights = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
-            }
-
-            if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
-                serializationObject.matricesIndices = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
-                serializationObject.matricesIndices._isExpanded = true;
-            }
-
-            serializationObject.indices = mesh.getIndices();
-
             // SubMeshes
             serializationObject.subMeshes = [];
             for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
@@ -525,13 +673,35 @@
                 serializationObject.skeletons.push(serializeSkeleton(scene.skeletons[index]));
             }
 
+            // Geometries
+            serializationObject.geometries = {};
+
+            serializationObject.geometries.boxes = [];
+            serializationObject.geometries.spheres = [];
+            serializationObject.geometries.cylinders = [];
+            serializationObject.geometries.toruses = [];
+            serializationObject.geometries.grounds = [];
+            serializationObject.geometries.planes = [];
+            serializationObject.geometries.torusKnots = [];
+            serializationObject.geometries.vertexData = [];
+
+            serializedGeometries = [];
+            var geometries = scene.getGeometries();
+            for (var index = 0; index < geometries.length; index++) {
+                var geometry = geometries[index];
+
+                if (geometry.isReady()) {
+                    serializeGeometry(geometry, serializationObject.geometries);
+                }
+            }
+
             // Meshes
             serializationObject.meshes = [];
             for (index = 0; index < scene.meshes.length; index++) {
                 var mesh = scene.meshes[index];
 
                 if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) {
-                    serializationObject.meshes.push(serializeMesh(mesh));
+                    serializationObject.meshes.push(serializeMesh(mesh, serializationObject));
                 }
             }
 

+ 31 - 15
Babylon/babylon.engine.js

@@ -104,7 +104,6 @@
             this._loadedTexturesCache = new Array();
             this._activeTexturesCache = new Array();
             this._compiledEffects = {};
-            this._lastVertexAttribIndex = 0;
             this._depthMask = false;
             this._renderingCanvas = canvas;
 
@@ -388,11 +387,16 @@
         };
 
         // VBOs
+        Engine.prototype._resetVertexBufferBinding = function () {
+            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this._cachedVertexBuffers = null;
+        };
+
         Engine.prototype.createVertexBuffer = function (vertices) {
             var vbo = this._gl.createBuffer();
             this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vbo);
             this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array(vertices), this._gl.STATIC_DRAW);
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this._resetVertexBufferBinding();
             vbo.references = 1;
             return vbo;
         };
@@ -401,7 +405,7 @@
             var vbo = this._gl.createBuffer();
             this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vbo);
             this._gl.bufferData(this._gl.ARRAY_BUFFER, capacity, this._gl.DYNAMIC_DRAW);
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this._resetVertexBufferBinding();
             vbo.references = 1;
             return vbo;
         };
@@ -418,14 +422,19 @@
                 }
             }
 
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this._resetVertexBufferBinding();
+        };
+
+        Engine.prototype._resetIndexBufferBinding = function () {
+            this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, null);
+            this._cachedIndexBuffer = null;
         };
 
         Engine.prototype.createIndexBuffer = function (indices) {
             var vbo = this._gl.createBuffer();
             this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, vbo);
             this._gl.bufferData(this._gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), this._gl.STATIC_DRAW);
-            this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, null);
+            this._resetIndexBufferBinding();
             vbo.references = 1;
             return vbo;
         };
@@ -484,7 +493,10 @@
 
             if (buffer.references === 0) {
                 this._gl.deleteBuffer(buffer);
+                return true;
             }
+
+            return false;
         };
 
         Engine.prototype.draw = function (useTriangles, indexStart, indexCount) {
@@ -568,26 +580,30 @@
                 return;
             }
 
+            this._vertexAttribArrays = this._vertexAttribArrays || [];
+
             // Use program
             this._gl.useProgram(effect.getProgram());
 
-            var currentCount = effect.getAttributesCount();
-            var maxIndex = 0;
-            for (var index = 0; index < currentCount; index++) {
+            for (var i in this._vertexAttribArrays) {
+                if (i > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[i]) {
+                    continue;
+                }
+                this._vertexAttribArrays[i] = false;
+                this._gl.disableVertexAttribArray(i);
+            }
+
+            var attributesCount = effect.getAttributesCount();
+            for (var index = 0; index < attributesCount; index++) {
                 // Attributes
                 var order = effect.getAttribute(index);
 
                 if (order >= 0) {
-                    this._gl.enableVertexAttribArray(effect.getAttribute(index));
-                    maxIndex = Math.max(maxIndex, order);
+                    this._vertexAttribArrays[order] = true;
+                    this._gl.enableVertexAttribArray(order);
                 }
             }
 
-            for (index = maxIndex + 1; index <= this._lastVertexAttribIndex; index++) {
-                this._gl.disableVertexAttribArray(index);
-            }
-
-            this._lastVertexAttribIndex = maxIndex;
             this._currentEffect = effect;
         };
 

+ 34 - 16
Babylon/babylon.engine.ts

@@ -142,7 +142,7 @@
         private _currentEffect: Effect;
         private _cullingState: boolean;
         private _compiledEffects = {};
-        private _lastVertexAttribIndex = 0;
+        private _vertexAttribArrays: boolean[];
         private _depthMask = false;
         private _cachedViewport: Viewport;
         private _cachedVertexBuffers: any;
@@ -445,11 +445,16 @@
         }
 
         // VBOs
+        private _resetVertexBufferBinding(): void {
+            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this._cachedVertexBuffers = null;
+        }
+
         public createVertexBuffer(vertices: number[]): WebGLBuffer {
             var vbo = this._gl.createBuffer();
             this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vbo);
             this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array(vertices), this._gl.STATIC_DRAW);
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this._resetVertexBufferBinding();
             vbo.references = 1;
             return vbo;
         }
@@ -458,7 +463,7 @@
             var vbo = this._gl.createBuffer();
             this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vbo);
             this._gl.bufferData(this._gl.ARRAY_BUFFER, capacity, this._gl.DYNAMIC_DRAW);
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this._resetVertexBufferBinding();
             vbo.references = 1;
             return vbo;
         }
@@ -475,14 +480,19 @@
                 }
             }
 
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this._resetVertexBufferBinding();
+        }
+
+        private _resetIndexBufferBinding(): void {
+            this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, null);
+            this._cachedIndexBuffer = null;
         }
 
         public createIndexBuffer(indices: number[]): WebGLBuffer {
             var vbo = this._gl.createBuffer();
             this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, vbo);
             this._gl.bufferData(this._gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), this._gl.STATIC_DRAW);
-            this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, null);
+            this._resetIndexBufferBinding();
             vbo.references = 1;
             return vbo;
         }
@@ -536,12 +546,15 @@
             }
         }
 
-        public _releaseBuffer(buffer: WebGLBuffer): void {
+        public _releaseBuffer(buffer: WebGLBuffer): boolean {
             buffer.references--;
 
             if (buffer.references === 0) {
                 this._gl.deleteBuffer(buffer);
+                return true;
             }
+
+            return false;
         }
 
         public draw(useTriangles: boolean, indexStart: number, indexCount: number): void {
@@ -625,26 +638,31 @@
             if (!effect || !effect.getAttributesCount() || this._currentEffect === effect) {
                 return;
             }
+
+            this._vertexAttribArrays = this._vertexAttribArrays || [];
+
             // Use program
             this._gl.useProgram(effect.getProgram());
 
-            var currentCount = effect.getAttributesCount();
-            var maxIndex = 0;
-            for (var index = 0; index < currentCount; index++) {
+            for (var i in this._vertexAttribArrays) {
+                if (i > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[i]) {
+                    continue;
+                }
+                this._vertexAttribArrays[i] = false;
+                this._gl.disableVertexAttribArray(i);
+            }
+
+            var attributesCount = effect.getAttributesCount();
+            for (var index = 0; index < attributesCount; index++) {
                 // Attributes
                 var order = effect.getAttribute(index);
 
                 if (order >= 0) {
-                    this._gl.enableVertexAttribArray(effect.getAttribute(index));
-                    maxIndex = Math.max(maxIndex, order);
+                    this._vertexAttribArrays[order] = true;
+                    this._gl.enableVertexAttribArray(order);
                 }
             }
 
-            for (index = maxIndex + 1; index <= this._lastVertexAttribIndex; index++) {
-                this._gl.disableVertexAttribArray(index);
-            }
-
-            this._lastVertexAttribIndex = maxIndex;
             this._currentEffect = effect;
         }
 

+ 34 - 0
Babylon/babylon.scene.js

@@ -38,6 +38,8 @@
             this.activeCameras = new Array();
             // Meshes
             this.meshes = new Array();
+            // Geometries
+            this._geometries = new Array();
             this.materials = new Array();
             this.multiMaterials = new Array();
             this.defaultMaterial = new BABYLON.StandardMaterial("default material", this);
@@ -209,6 +211,14 @@
                 return false;
             }
 
+            for (var index = 0; index < this._geometries.length; index++) {
+                var geometry = this._geometries[index];
+
+                if (geometry.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                    return false;
+                }
+            }
+
             for (var index = 0; index < this.meshes.length; index++) {
                 var mesh = this.meshes[index];
                 var mat = mesh.material;
@@ -459,6 +469,30 @@
             return null;
         };
 
+        Scene.prototype.getGeometryByID = function (id) {
+            for (var index = 0; index < this._geometries.length; index++) {
+                if (this._geometries[index].id === id) {
+                    return this._geometries[index];
+                }
+            }
+
+            return null;
+        };
+
+        Scene.prototype.pushGeometry = function (geometry, force) {
+            if (!force && this.getGeometryByID(geometry.id)) {
+                return false;
+            }
+
+            this._geometries.push(geometry);
+
+            return true;
+        };
+
+        Scene.prototype.getGeometries = function () {
+            return this._geometries;
+        };
+
         Scene.prototype.getMeshByID = function (id) {
             for (var index = 0; index < this.meshes.length; index++) {
                 if (this.meshes[index].id === id) {

+ 35 - 0
Babylon/babylon.scene.ts

@@ -55,6 +55,9 @@
         // Meshes
         public meshes = new Array<Mesh>();
 
+        // Geometries
+        private _geometries = new Array<Geometry>();
+
         public materials = new Array<Material>();
         public multiMaterials = new Array<MultiMaterial>();
         public defaultMaterial = new BABYLON.StandardMaterial("default material", this);
@@ -274,6 +277,14 @@
                 return false;
             }
 
+            for (var index = 0; index < this._geometries.length; index++) {
+                var geometry = this._geometries[index];
+
+                if (geometry.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
+                    return false;
+                }
+            }
+
             for (var index = 0; index < this.meshes.length; index++) {
                 var mesh = this.meshes[index];
                 var mat = mesh.material;
@@ -521,6 +532,30 @@
             return null;
         }
 
+        public getGeometryByID(id: string): Geometry {
+            for (var index = 0; index < this._geometries.length; index++) {
+                if (this._geometries[index].id === id) {
+                    return this._geometries[index];
+                }
+            }
+
+            return null;
+        }
+
+        public pushGeometry(geometry: Geometry, force?: boolean): boolean {
+            if (!force && this.getGeometryByID(geometry.id)) {
+                return false;
+            }
+
+            this._geometries.push(geometry);
+
+            return true;
+        }
+
+        public getGeometries(): Geometry[] {
+            return this._geometries;
+        }
+
         public getMeshByID(id: string): Mesh {
             for (var index = 0; index < this.meshes.length; index++) {
                 if (this.meshes[index].id === id) {

+ 8 - 7
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml

@@ -1,11 +1,5 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <files xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="babylonJS.xsd">
-  <script src="Babylon/Actions/babylon.condition.js"></script>
-  <script src="Babylon/Actions/babylon.action.js"></script>
-  <script src="Babylon/Actions/babylon.actionManager.js"></script>
-  <script src="Babylon/Actions/babylon.interpolateValueAction.js"></script>
-  <script src="Babylon/Actions/babylon.directActions.js"></script>
-  <script src="Babylon/Rendering/babylon.boundingBoxRenderer.js"></script>
   <script src="Babylon/Materials/babylon.shaderMaterial.js"></script>
   <script src="Babylon/Cameras/babylon.virtualJoysticksCamera.js"></script>
   <script src="Babylon/Tools/babylon.virtualJoystick.js"></script>
@@ -16,8 +10,8 @@
   <script src="Babylon/Cameras/Controllers/babylon.inputController.js"></script>
   <script src="Babylon/Mesh/babylon.csg.js"></script>
   <script src="Babylon/Tools/babylon.sceneSerializer.js"></script>
-  <script src="Babylon/Physics/Plugins/babylon.cannonJSPlugin.js"></script>
   <script src="Babylon/Physics/babylon.physicsEngine.js"></script>
+  <script src="Babylon/Physics/Plugins/babylon.cannonJSPlugin.js"></script>
   <script src="Babylon/Tools/babylon.filesInput.js"></script>
   <script src="Babylon/Collisions/babylon.pickingInfo.js"></script>
   <script src="Babylon/LensFlare/babylon.lensFlareSystem.js"></script>
@@ -66,9 +60,16 @@
   <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.geometry.js"></script>
   <script src="Babylon/Mesh/babylon.mesh.vertexData.js"></script>
   <script src="Babylon/Mesh/babylon.vertexBuffer.js"></script>
   <script src="Babylon/babylon.scene.js"></script>
+  <script src="Babylon/Rendering/babylon.boundingBoxRenderer.js"></script>
+  <script src="Babylon/Actions/babylon.condition.js"></script>
+  <script src="Babylon/Actions/babylon.actionManager.js"></script>
+  <script src="Babylon/Actions/babylon.interpolateValueAction.js"></script>
+  <script src="Babylon/Actions/babylon.directActions.js"></script>
+  <script src="Babylon/Actions/babylon.action.js"></script>
   <script src="Babylon/Cameras/babylon.anaglyphCamera.js"></script>
   <script src="Babylon/Cameras/babylon.arcRotateCamera.js"></script>
   <script src="Babylon/Cameras/babylon.deviceOrientationCamera.js"></script>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 4 - 4
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/ourOwnBabylon.js


+ 1 - 1
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJSServer/Controllers/BuildOurOwnBabylonJSController.cs

@@ -83,7 +83,7 @@ namespace BuildOurOwnBabylonJSServer.Controllers
 
                     foreach (var file in babylonFiles)
                     {
-                        var linkName = directory.Name + (file.Name.Contains(".incremental.babylon") ? " - Incremental" : "");
+                        var linkName = directory.Name + "/" + Path.GetFileNameWithoutExtension(file.Name);
                         files.Add(new JObject(
                             new JProperty("url", Url.Action("Index", "BabylonJSDemo", new { demoFolderName = directory.Name, demoFile = file.Name })),
                             new JProperty("linkName", linkName)

+ 136 - 104
Tools/MakeIncremental/Program.cs

@@ -4,6 +4,7 @@ using System.Linq;
 using System.Web;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
+using System.Collections.Generic;
 
 namespace MakeIncremental
 {
@@ -43,44 +44,143 @@ namespace MakeIncremental
             ProcessSourceFile(input);
         }
 
-        static string CreateDelayLoadingFile(dynamic mesh, string outputDir, string rootFilename)
+        static void Extract(dynamic meshOrGeometry, string outputDir, string rootFilename, bool mesh = true)
         {
-            var encodedMeshName = mesh.name.ToString().Replace("+", "_").Replace(" ", "_");
-            var outputPath = Path.Combine(outputDir, rootFilename + "." + encodedMeshName + ".babylonmeshdata");
+            Console.WriteLine("Extracting " + (mesh ? meshOrGeometry.name : meshOrGeometry.id));
+
+            if (meshOrGeometry.positions != null && meshOrGeometry.normals != null && meshOrGeometry.indices != null)
+            {
+                meshOrGeometry.delayLoadingFile = CreateDelayLoadingFile(meshOrGeometry, outputDir, rootFilename, mesh);
+                Console.WriteLine("Delay loading file: " + meshOrGeometry.delayLoadingFile);
+
+                // Compute bounding boxes
+                var positions = ((JArray)meshOrGeometry.positions).Select(v => v.Value<float>()).ToArray();
+                var minimum = new[] { float.MaxValue, float.MaxValue, float.MaxValue };
+                var maximum = new[] { float.MinValue, float.MinValue, float.MinValue };
+
+                for (var index = 0; index < positions.Length; index += 3)
+                {
+                    var x = positions[index];
+                    var y = positions[index + 1];
+                    var z = positions[index + 2];
+
+                    if (x < minimum[0])
+                    {
+                        minimum[0] = x;
+                    }
+                    if (x > maximum[0])
+                    {
+                        maximum[0] = x;
+                    }
+
+                    if (y < minimum[1])
+                    {
+                        minimum[1] = y;
+                    }
+                    if (y > maximum[1])
+                    {
+                        maximum[1] = y;
+                    }
+
+                    if (z < minimum[2])
+                    {
+                        minimum[2] = z;
+                    }
+                    if (z > maximum[2])
+                    {
+                        maximum[2] = z;
+                    }
+                }
+
+                meshOrGeometry["boundingBoxMinimum"] = new JArray(minimum);
+                meshOrGeometry["boundingBoxMaximum"] = new JArray(maximum);
+
+                // Erasing infos
+                meshOrGeometry.positions = null;
+                meshOrGeometry.normals = null;
+                meshOrGeometry.indices = null;
+
+                if (meshOrGeometry.uvs != null)
+                {
+                    meshOrGeometry["hasUVs"] = true;
+                    meshOrGeometry.uvs = null;
+                }
+
+                if (meshOrGeometry.uvs2 != null)
+                {
+                    meshOrGeometry["hasUVs2"] = true;
+                    meshOrGeometry.uvs2 = null;
+                }
+
+                if (meshOrGeometry.colors != null)
+                {
+                    meshOrGeometry["hasColors"] = true;
+                    meshOrGeometry.colors = null;
+                }
+
+                if (meshOrGeometry.matricesIndices != null)
+                {
+                    meshOrGeometry["hasMatricesIndices"] = true;
+                    meshOrGeometry.matricesIndices = null;
+                }
+
+                if (meshOrGeometry.matricesWeights != null)
+                {
+                    meshOrGeometry["hasMatricesWeights"] = true;
+                    meshOrGeometry.matricesWeights = null;
+                }
+
+                if (mesh && meshOrGeometry.subMeshes != null)
+                {
+                    meshOrGeometry.subMeshes = null;
+                }
+            }
+        }
+
+        static string CreateDelayLoadingFile(dynamic meshOrGeometry, string outputDir, string rootFilename, bool mesh = true)
+        {
+            string encodedName;
+            if(mesh)
+                encodedName = meshOrGeometry.name.ToString();
+            else
+                encodedName = meshOrGeometry.id.ToString();
+
+            encodedName = encodedName.Replace("+", "_").Replace(" ", "_");
+            var outputPath = Path.Combine(outputDir, rootFilename + "." + encodedName + (mesh ? ".babylonmeshdata" : ".babylongeometrydata"));
 
             var result = new JObject();
-            result["positions"] = mesh.positions;
-            result["indices"] = mesh.indices;
-            result["normals"] = mesh.normals;
+            result["positions"] = meshOrGeometry.positions;
+            result["indices"] = meshOrGeometry.indices;
+            result["normals"] = meshOrGeometry.normals;
 
-            if (mesh.uvs != null)
+            if (meshOrGeometry.uvs != null)
             {
-                result["uvs"] = mesh.uvs;
+                result["uvs"] = meshOrGeometry.uvs;
             }
 
-            if (mesh.uvs2 != null)
+            if (meshOrGeometry.uvs2 != null)
             {
-                result["uvs2"] = mesh.uvs2;
+                result["uvs2"] = meshOrGeometry.uvs2;
             }
 
-            if (mesh.colors != null)
+            if (meshOrGeometry.colors != null)
             {
-                result["colors"] = mesh.colors;
+                result["colors"] = meshOrGeometry.colors;
             }
 
-            if (mesh.matricesIndices != null)
+            if (meshOrGeometry.matricesIndices != null)
             {
-                result["matricesIndices"] = mesh.matricesIndices;
+                result["matricesIndices"] = meshOrGeometry.matricesIndices;
             }
 
-            if (mesh.matricesWeights != null)
+            if (meshOrGeometry.matricesWeights != null)
             {
-                result["matricesWeights"] = mesh.matricesWeights;
+                result["matricesWeights"] = meshOrGeometry.matricesWeights;
             }
 
-            if (mesh.subMeshes != null)
+            if (mesh && meshOrGeometry.subMeshes != null)
             {
-                result["subMeshes"] = mesh.subMeshes;
+                result["subMeshes"] = meshOrGeometry.subMeshes;
             }
 
             string json = result.ToString(Formatting.None);
@@ -118,103 +218,35 @@ namespace MakeIncremental
                 scene["autoClear"] = true;
                 scene["useDelayedTextureLoading"] = true;
 
+                var doNotDelayLoadingForGeometries = new List<string>();
+
                 // Parsing meshes
                 var meshes = (JArray)scene.meshes;
                 foreach (dynamic mesh in meshes)
                 {
                     if (mesh.checkCollisions.Value) // Do not delay load collisions object
                     {
+                        if (mesh.geometryId != null)
+                            doNotDelayLoadingForGeometries.Add(mesh.geometryId.Value);
                         continue;
                     }
 
-                    Console.WriteLine("Extracting " + mesh.name);
+                    Extract(mesh, outputDir, rootFilename);
+                }
 
-                    if (mesh.positions != null && mesh.normals != null && mesh.indices != null)
+                // Parsing vertexData
+                var geometries = scene.geometries;
+                if (geometries != null)
+                {
+                    var vertexData = (JArray)geometries.vertexData;
+                    foreach (dynamic geometry in vertexData)
                     {
-                        mesh.delayLoadingFile = CreateDelayLoadingFile(mesh, outputDir, rootFilename);
-                        Console.WriteLine("Delay loading file: " + mesh.delayLoadingFile);
-
-                        // Compute bounding boxes
-                        var positions = ((JArray) mesh.positions).Select(v=>v.Value<float>()).ToArray();
-                        var minimum = new[] {float.MaxValue, float.MaxValue, float.MaxValue};
-                        var maximum = new[] {float.MinValue, float.MinValue, float.MinValue};
-
-                        for (var index = 0; index < positions.Length; index += 3)
-                        {
-                            var x = positions[index];
-                            var y = positions[index + 1];
-                            var z = positions[index + 2];
-
-                            if (x < minimum[0])
-                            {
-                                minimum[0] = x;
-                            }
-                            if (x > maximum[0])
-                            {
-                                maximum[0] = x;
-                            }
-
-                            if (y < minimum[1])
-                            {
-                                minimum[1] = y;
-                            }
-                            if (y > maximum[1])
-                            {
-                                maximum[1] = y;
-                            }
-
-                            if (z < minimum[2])
-                            {
-                                minimum[2] = z;
-                            }
-                            if (z > maximum[2])
-                            {
-                                maximum[2] = z;
-                            }
-                        }
-
-                        mesh["boundingBoxMinimum"] = new JArray(minimum);
-                        mesh["boundingBoxMaximum"] = new JArray(maximum);
-
-                        // Erasing infos
-                        mesh.positions = null;
-                        mesh.normals = null;
-                        mesh.indices = null;
-
-                        if (mesh.uvs != null)
-                        {
-                            mesh["hasUVs"] = true;
-                            mesh.uvs = null;
-                        }
-
-                        if (mesh.uvs2 != null)
-                        {
-                            mesh["hasUVs2"] = true;
-                            mesh.uvs2 = null;
-                        }
-
-                        if (mesh.colors != null)
-                        {
-                            mesh["hasColors"] = true;
-                            mesh.colors = null;
-                        }
-
-                        if (mesh.matricesIndices != null)
-                        {
-                            mesh["hasMatricesIndices"] = true;
-                            mesh.matricesIndices = null;
-                        }
-
-                        if (mesh.matricesWeights != null)
-                        {
-                            mesh["hasMatricesWeights"] = true;
-                            mesh.matricesWeights = null;
-                        }
-
-                        if (mesh.subMeshes != null)
-                        {
-                            mesh.subMeshes = null;
-                        }
+                        var id = geometry.id.Value;
+
+                        if (doNotDelayLoadingForGeometries.Any(g => g == id))
+                            continue;
+
+                        Extract(geometry, outputDir, rootFilename, false);
                     }
                 }