Ver código fonte

Fixing small issues with latest PR

David Catuhe 9 anos atrás
pai
commit
2680a5cf7e

Diferenças do arquivo suprimidas por serem muito extensas
+ 25 - 25
dist/preview release/babylon.core.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 610 - 580
dist/preview release/babylon.d.ts


Diferenças do arquivo suprimidas por serem muito extensas
+ 33 - 33
dist/preview release/babylon.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 433 - 254
dist/preview release/babylon.max.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 35 - 35
dist/preview release/babylon.noworker.js


+ 4 - 4
src/Canvas2d/babylon.ellipse2d.js

@@ -35,7 +35,7 @@ var BABYLON;
             if (this.effectFill) {
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
                 engine.enableEffect(this.effectFill);
-                engine.bindBuffers(this.fillVB, this.fillIB, [1], 4, this.effectFill);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, this.effectFill);
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingFillAttributes) {
@@ -44,7 +44,7 @@ var BABYLON;
                     }
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
                     engine.draw(true, 0, this.fillIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingFillAttributes);
+                    engine.unbindInstanceAttributes();
                 }
                 else {
                     for (var i = 0; i < count; i++) {
@@ -56,7 +56,7 @@ var BABYLON;
             if (this.effectBorder) {
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
                 engine.enableEffect(this.effectBorder);
-                engine.bindBuffers(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingBorderAttributes) {
@@ -64,7 +64,7 @@ var BABYLON;
                     }
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
                     engine.draw(true, 0, this.borderIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingBorderAttributes);
+                    engine.unbindInstanceAttributes();
                 }
                 else {
                     for (var i = 0; i < count; i++) {

+ 4 - 4
src/Canvas2d/babylon.lines2d.js

@@ -35,7 +35,7 @@ var BABYLON;
             if (this.effectFill) {
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
                 engine.enableEffect(this.effectFill);
-                engine.bindBuffers(this.fillVB, this.fillIB, [2], 2 * 4, this.effectFill);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [2], 2 * 4, this.effectFill);
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingFillAttributes) {
@@ -44,7 +44,7 @@ var BABYLON;
                     }
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
                     engine.draw(true, 0, this.fillIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingFillAttributes);
+                    engine.unbindInstanceAttributes();
                 }
                 else {
                     for (var i = 0; i < count; i++) {
@@ -56,7 +56,7 @@ var BABYLON;
             if (this.effectBorder) {
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
                 engine.enableEffect(this.effectBorder);
-                engine.bindBuffers(this.borderVB, this.borderIB, [2], 2 * 4, this.effectBorder);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [2], 2 * 4, this.effectBorder);
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingBorderAttributes) {
@@ -64,7 +64,7 @@ var BABYLON;
                     }
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
                     engine.draw(true, 0, this.borderIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingBorderAttributes);
+                    engine.unbindInstanceAttributes();
                 }
                 else {
                     for (var i = 0; i < count; i++) {

+ 4 - 4
src/Canvas2d/babylon.rectangle2d.js

@@ -35,7 +35,7 @@ var BABYLON;
             if (this.effectFill) {
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
                 engine.enableEffect(this.effectFill);
-                engine.bindBuffers(this.fillVB, this.fillIB, [1], 4, this.effectFill);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, this.effectFill);
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingFillAttributes) {
@@ -44,7 +44,7 @@ var BABYLON;
                     }
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
                     engine.draw(true, 0, this.fillIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingFillAttributes);
+                    engine.unbindInstanceAttributes();
                 }
                 else {
                     for (var i = 0; i < count; i++) {
@@ -56,7 +56,7 @@ var BABYLON;
             if (this.effectBorder) {
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
                 engine.enableEffect(this.effectBorder);
-                engine.bindBuffers(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingBorderAttributes) {
@@ -64,7 +64,7 @@ var BABYLON;
                     }
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
                     engine.draw(true, 0, this.borderIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingBorderAttributes);
+                    engine.unbindInstanceAttributes();
                 }
                 else {
                     for (var i = 0; i < count; i++) {

+ 2 - 2
src/Canvas2d/babylon.sprite2d.js

@@ -25,7 +25,7 @@ var BABYLON;
             var engine = instanceInfo._owner.owner.engine;
             engine.enableEffect(this.effect);
             this.effect.setTexture("diffuseSampler", this.texture);
-            engine.bindBuffers(this.vb, this.ib, [1], 4, this.effect);
+            engine.bindBuffersDirectly(this.vb, this.ib, [1], 4, this.effect);
             var cur = engine.getAlphaMode();
             engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
             var count = instanceInfo._instancesPartsData[0].usedElementCount;
@@ -35,7 +35,7 @@ var BABYLON;
                 }
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
                 engine.draw(true, 0, 6, count);
-                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
+                engine.unbindInstanceAttributes();
             }
             else {
                 for (var i = 0; i < count; i++) {

+ 2 - 2
src/Canvas2d/babylon.text2d.js

@@ -29,14 +29,14 @@ var BABYLON;
             this.fontTexture.update();
             engine.enableEffect(this.effect);
             this.effect.setTexture("diffuseSampler", this.fontTexture);
-            engine.bindBuffers(this.vb, this.ib, [1], 4, this.effect);
+            engine.bindBuffersDirectly(this.vb, this.ib, [1], 4, this.effect);
             var cur = engine.getAlphaMode();
             engine.setAlphaMode(BABYLON.Engine.ALPHA_ADD);
             var count = instanceInfo._instancesPartsData[0].usedElementCount;
             if (instanceInfo._owner.owner.supportInstancedArray) {
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
                 engine.draw(true, 0, 6, count);
-                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
+                engine.unbindInstanceAttributes();
             }
             else {
                 for (var i = 0; i < count; i++) {

+ 12 - 10
src/Layer/babylon.layer.js

@@ -6,8 +6,7 @@ var BABYLON;
             this.scale = new BABYLON.Vector2(1, 1);
             this.offset = new BABYLON.Vector2(0, 0);
             this.alphaBlendingMode = BABYLON.Engine.ALPHA_COMBINE;
-            this._vertexDeclaration = [2];
-            this._vertexStrideSize = 2 * 4;
+            this._vertexBuffers = {};
             // Events
             /**
             * An event triggered when the layer is disposed.
@@ -29,13 +28,15 @@ var BABYLON;
             this.color = color === undefined ? new BABYLON.Color4(1, 1, 1, 1) : color;
             this._scene = scene;
             this._scene.layers.push(this);
+            var engine = scene.getEngine();
             // VBO
             var vertices = [];
             vertices.push(1, 1);
             vertices.push(-1, 1);
             vertices.push(-1, -1);
             vertices.push(1, -1);
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+            var vertexBuffer = new BABYLON.VertexBuffer(engine, vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2);
+            this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = vertexBuffer;
             // Indices
             var indices = [];
             indices.push(0);
@@ -44,10 +45,10 @@ var BABYLON;
             indices.push(0);
             indices.push(2);
             indices.push(3);
-            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
+            this._indexBuffer = engine.createIndexBuffer(indices);
             // Effects
-            this._effect = this._scene.getEngine().createEffect("layer", ["position"], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "");
-            this._alphaTestEffect = this._scene.getEngine().createEffect("layer", ["position"], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "#define ALPHATEST");
+            this._effect = engine.createEffect("layer", [BABYLON.VertexBuffer.PositionKind], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "");
+            this._alphaTestEffect = engine.createEffect("layer", [BABYLON.VertexBuffer.PositionKind], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "#define ALPHATEST");
         }
         Object.defineProperty(Layer.prototype, "onDispose", {
             set: function (callback) {
@@ -98,7 +99,7 @@ var BABYLON;
             currentEffect.setVector2("offset", this.offset);
             currentEffect.setVector2("scale", this.scale);
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, currentEffect);
+            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect);
             // Draw order
             if (!this._alphaTestEffect) {
                 engine.setAlphaMode(this.alphaBlendingMode);
@@ -111,9 +112,10 @@ var BABYLON;
             this.onAfterRenderObservable.notifyObservers(this);
         };
         Layer.prototype.dispose = function () {
-            if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
-                this._vertexBuffer = null;
+            var vertexBuffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
+            if (vertexBuffer) {
+                vertexBuffer.dispose();
+                this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null;
             }
             if (this._indexBuffer) {
                 this._scene.getEngine()._releaseBuffer(this._indexBuffer);

+ 10 - 9
src/LensFlare/babylon.lensFlareSystem.js

@@ -6,21 +6,21 @@ var BABYLON;
             this.lensFlares = new Array();
             this.borderLimit = 300;
             this.layerMask = 0x0FFFFFFF;
-            this._vertexDeclaration = [2];
-            this._vertexStrideSize = 2 * 4;
+            this._vertexBuffers = {};
             this._isEnabled = true;
             this._scene = scene;
             this._emitter = emitter;
             this.id = name;
             scene.lensFlareSystems.push(this);
             this.meshesSelectionPredicate = function (m) { return m.material && m.isVisible && m.isEnabled() && m.isBlocker && ((m.layerMask & scene.activeCamera.layerMask) != 0); };
+            var engine = scene.getEngine();
             // VBO
             var vertices = [];
             vertices.push(1, 1);
             vertices.push(-1, 1);
             vertices.push(-1, -1);
             vertices.push(1, -1);
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+            this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = new BABYLON.VertexBuffer(engine, vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2);
             // Indices
             var indices = [];
             indices.push(0);
@@ -29,9 +29,9 @@ var BABYLON;
             indices.push(0);
             indices.push(2);
             indices.push(3);
-            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
+            this._indexBuffer = engine.createIndexBuffer(indices);
             // Effects
-            this._effect = this._scene.getEngine().createEffect("lensFlare", ["position"], ["color", "viewportMatrix"], ["textureSampler"], "");
+            this._effect = engine.createEffect("lensFlare", [BABYLON.VertexBuffer.PositionKind], ["color", "viewportMatrix"], ["textureSampler"], "");
         }
         Object.defineProperty(LensFlareSystem.prototype, "isEnabled", {
             get: function () {
@@ -138,7 +138,7 @@ var BABYLON;
             engine.setDepthBuffer(false);
             engine.setAlphaMode(BABYLON.Engine.ALPHA_ONEONE);
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
+            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, this._effect);
             // Flares
             for (var index = 0; index < this.lensFlares.length; index++) {
                 var flare = this.lensFlares[index];
@@ -162,9 +162,10 @@ var BABYLON;
             return true;
         };
         LensFlareSystem.prototype.dispose = function () {
-            if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
-                this._vertexBuffer = null;
+            var vertexBuffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
+            if (vertexBuffer) {
+                vertexBuffer.dispose();
+                this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null;
             }
             if (this._indexBuffer) {
                 this._scene.getEngine()._releaseBuffer(this._indexBuffer);

+ 16 - 8
src/Materials/Textures/Procedurals/babylon.proceduralTexture.js

@@ -15,8 +15,7 @@ var BABYLON;
             this.isEnabled = true;
             this._currentRefreshId = -1;
             this._refreshRate = 1;
-            this._vertexDeclaration = [2];
-            this._vertexStrideSize = 2 * 4;
+            this._vertexBuffers = {};
             this._uniforms = new Array();
             this._samplers = new Array();
             this._textures = new Array();
@@ -35,12 +34,13 @@ var BABYLON;
             this._generateMipMaps = generateMipMaps;
             this.setFragment(fragment);
             this._fallbackTexture = fallbackTexture;
+            var engine = scene.getEngine();
             if (isCube) {
-                this._texture = scene.getEngine().createRenderTargetCubeTexture(size, { generateMipMaps: generateMipMaps });
+                this._texture = engine.createRenderTargetCubeTexture(size, { generateMipMaps: generateMipMaps });
                 this.setFloat("face", 0);
             }
             else {
-                this._texture = scene.getEngine().createRenderTargetTexture(size, generateMipMaps);
+                this._texture = engine.createRenderTargetTexture(size, generateMipMaps);
             }
             // VBO
             var vertices = [];
@@ -48,7 +48,7 @@ var BABYLON;
             vertices.push(-1, 1);
             vertices.push(-1, -1);
             vertices.push(1, -1);
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+            this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = new BABYLON.VertexBuffer(engine, vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2);
             // Indices
             var indices = [];
             indices.push(0);
@@ -57,7 +57,7 @@ var BABYLON;
             indices.push(0);
             indices.push(2);
             indices.push(3);
-            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
+            this._indexBuffer = engine.createIndexBuffer(indices);
         }
         ProceduralTexture.prototype.reset = function () {
             if (this._effect === undefined) {
@@ -82,7 +82,7 @@ var BABYLON;
             else {
                 shaders = { vertex: "procedural", fragment: this._fragment };
             }
-            this._effect = engine.createEffect(shaders, ["position"], this._uniforms, this._samplers, "", null, null, function () {
+            this._effect = engine.createEffect(shaders, [BABYLON.VertexBuffer.PositionKind], this._uniforms, this._samplers, "", null, null, function () {
                 _this.releaseInternalTexture();
                 if (_this._fallbackTexture) {
                     _this._texture = _this._fallbackTexture._texture;
@@ -225,7 +225,7 @@ var BABYLON;
                 this._effect.setMatrix(name, this._matrices[name]);
             }
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
+            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, this._effect);
             if (this.isCube) {
                 for (var face = 0; face < 6; face++) {
                     engine.bindFramebuffer(this._texture, face);
@@ -268,6 +268,14 @@ var BABYLON;
             if (index >= 0) {
                 this.getScene()._proceduralTextures.splice(index, 1);
             }
+            var vertexBuffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
+            if (vertexBuffer) {
+                vertexBuffer.dispose();
+                this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null;
+            }
+            if (this._indexBuffer && this.getScene().getEngine()._releaseBuffer(this._indexBuffer)) {
+                this._indexBuffer = null;
+            }
             _super.prototype.dispose.call(this);
         };
         return ProceduralTexture;

+ 82 - 0
src/Mesh/babylon.buffer.js

@@ -0,0 +1,82 @@
+var BABYLON;
+(function (BABYLON) {
+    var Buffer = (function () {
+        function Buffer(engine, data, updatable, stride, postponeInternalCreation, instanced) {
+            if (engine instanceof BABYLON.Mesh) {
+                this._engine = engine.getScene().getEngine();
+            }
+            else {
+                this._engine = engine;
+            }
+            this._updatable = updatable;
+            this._data = data;
+            this._strideSize = stride;
+            if (!postponeInternalCreation) {
+                this.create();
+            }
+            this._instanced = instanced;
+        }
+        Buffer.prototype.createVertexBuffer = function (kind, offset, size, stride) {
+            // a lot of these parameters are ignored as they are overriden by the buffer
+            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, this._instanced, offset, size);
+        };
+        // Properties
+        Buffer.prototype.isUpdatable = function () {
+            return this._updatable;
+        };
+        Buffer.prototype.getData = function () {
+            return this._data;
+        };
+        Buffer.prototype.getBuffer = function () {
+            return this._buffer;
+        };
+        Buffer.prototype.getStrideSize = function () {
+            return this._strideSize;
+        };
+        Buffer.prototype.getIsInstanced = function () {
+            return this._instanced;
+        };
+        // Methods
+        Buffer.prototype.create = function (data) {
+            if (!data && this._buffer) {
+                return; // nothing to do
+            }
+            data = data || this._data;
+            if (!this._buffer) {
+                if (this._updatable) {
+                    this._buffer = this._engine.createDynamicVertexBuffer(data);
+                    this._data = data;
+                }
+                else {
+                    this._buffer = this._engine.createVertexBuffer(data);
+                }
+            }
+            else if (this._updatable) {
+                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+                this._data = data;
+            }
+        };
+        Buffer.prototype.update = function (data) {
+            this.create(data);
+        };
+        Buffer.prototype.updateDirectly = function (data, offset, vertexCount) {
+            if (!this._buffer) {
+                return;
+            }
+            if (this._updatable) {
+                this._engine.updateDynamicVertexBuffer(this._buffer, data, offset, (vertexCount ? vertexCount * this.getStrideSize() : undefined));
+                this._data = null;
+            }
+        };
+        Buffer.prototype.dispose = function () {
+            if (!this._buffer) {
+                return;
+            }
+            if (this._engine._releaseBuffer(this._buffer)) {
+                this._buffer = null;
+            }
+        };
+        return Buffer;
+    }());
+    BABYLON.Buffer = Buffer;
+})(BABYLON || (BABYLON = {}));

+ 14 - 8
src/Mesh/babylon.geometry.js

@@ -74,14 +74,20 @@ var BABYLON;
             this.notifyUpdate();
         };
         Geometry.prototype.setVerticesData = function (kind, data, updatable, stride) {
+            var buffer = new BABYLON.VertexBuffer(this._engine, data, kind, updatable, this._meshes.length === 0, stride);
+            this.setVerticesBuffer(buffer);
+        };
+        Geometry.prototype.setVerticesBuffer = function (buffer) {
+            var kind = buffer.getKind();
             if (this._vertexBuffers[kind]) {
                 this._vertexBuffers[kind].dispose();
             }
-            this._vertexBuffers[kind] = new BABYLON.VertexBuffer(this._engine, data, kind, updatable, this._meshes.length === 0, stride);
+            this._vertexBuffers[kind] = buffer;
             if (kind === BABYLON.VertexBuffer.PositionKind) {
-                stride = this._vertexBuffers[kind].getStrideSize();
+                var data = buffer.getData();
+                var stride = buffer.getStrideSize();
                 this._totalVertices = data.length / stride;
-                this.updateExtend(data);
+                this.updateExtend(data, stride);
                 var meshes = this._meshes;
                 var numOfMeshes = meshes.length;
                 for (var index = 0; index < numOfMeshes; index++) {
@@ -278,12 +284,12 @@ var BABYLON;
                 mesh._boundingInfo = this._boundingInfo;
             }
         };
-        Geometry.prototype.updateExtend = function (data) {
+        Geometry.prototype.updateExtend = function (data, stride) {
             if (data === void 0) { data = null; }
             if (!data) {
                 data = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].getData();
             }
-            this._extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices, this.boundingBias);
+            this._extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices, this.boundingBias, stride);
         };
         Geometry.prototype._applyToMesh = function (mesh) {
             var numOfMeshes = this._meshes.length;
@@ -292,7 +298,7 @@ var BABYLON;
                 if (numOfMeshes === 1) {
                     this._vertexBuffers[kind].create();
                 }
-                this._vertexBuffers[kind]._buffer.references = numOfMeshes;
+                this._vertexBuffers[kind].getBuffer().references = numOfMeshes;
                 if (kind === BABYLON.VertexBuffer.PositionKind) {
                     mesh._resetPointsArrayCache();
                     if (!this._extend) {
@@ -305,7 +311,7 @@ var BABYLON;
                 }
             }
             // indexBuffer
-            if (numOfMeshes === 1 && this._indices) {
+            if (numOfMeshes === 1 && this._indices && this._indices.length > 0) {
                 this._indexBuffer = this._engine.createIndexBuffer(this._indices);
             }
             if (this._indexBuffer) {
@@ -390,7 +396,7 @@ var BABYLON;
             for (var kind in this._vertexBuffers) {
                 this._vertexBuffers[kind].dispose();
             }
-            this._vertexBuffers = [];
+            this._vertexBuffers = {};
             this._totalVertices = 0;
             if (this._indexBuffer) {
                 this._engine._releaseBuffer(this._indexBuffer);

+ 5 - 3
src/Mesh/babylon.linesMesh.js

@@ -12,16 +12,18 @@ var BABYLON;
             _super.call(this, name, scene, parent, source, doNotCloneChildren);
             this.color = new BABYLON.Color3(1, 1, 1);
             this.alpha = 1;
+            this._positionBuffer = {};
             if (source) {
                 this.color = source.color.clone();
                 this.alpha = source.alpha;
             }
             this._intersectionThreshold = 0.1;
             this._colorShader = new BABYLON.ShaderMaterial("colorShader", scene, "color", {
-                attributes: ["position"],
+                attributes: [BABYLON.VertexBuffer.PositionKind],
                 uniforms: ["worldViewProjection", "color"],
                 needAlphaBlending: true
             });
+            this._positionBuffer[BABYLON.VertexBuffer.PositionKind] = null;
         }
         Object.defineProperty(LinesMesh.prototype, "intersectionThreshold", {
             /**
@@ -70,9 +72,9 @@ var BABYLON;
         };
         LinesMesh.prototype._bind = function (subMesh, effect, fillMode) {
             var engine = this.getScene().getEngine();
-            var indexToBind = this._geometry.getIndexBuffer();
+            this._positionBuffer[BABYLON.VertexBuffer.PositionKind] = this._geometry.getVertexBuffer(BABYLON.VertexBuffer.PositionKind);
             // VBOs
-            engine.bindBuffers(this._geometry.getVertexBuffer(BABYLON.VertexBuffer.PositionKind).getBuffer(), indexToBind, [3], 3 * 4, this._colorShader.getEffect());
+            engine.bindBuffers(this._positionBuffer, this._geometry.getIndexBuffer(), this._colorShader.getEffect());
             // Color
             this._colorShader.setColor4("color", this.color.toColor4(this.alpha));
         };

+ 44 - 20
src/Mesh/babylon.mesh.js

@@ -515,6 +515,16 @@ var BABYLON;
         Mesh.prototype.unfreezeNormals = function () {
             this._areNormalsFrozen = false;
         };
+        Object.defineProperty(Mesh.prototype, "overridenInstanceCount", {
+            /**
+             * Overrides instance count. Only applicable when custom instanced InterleavedVertexBuffer are used rather than InstancedMeshs
+             */
+            set: function (count) {
+                this._overridenInstanceCount = count;
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         Mesh.prototype._preActivate = function () {
             var sceneRenderId = this.getScene().getRenderId();
@@ -623,6 +633,13 @@ var BABYLON;
                 this._geometry.setVerticesData(kind, data, updatable, stride);
             }
         };
+        Mesh.prototype.setVerticesBuffer = function (buffer) {
+            if (!this._geometry) {
+                var scene = this.getScene();
+                new BABYLON.Geometry(BABYLON.Geometry.RandomId(), scene).applyToMesh(this);
+            }
+            this._geometry.setVerticesBuffer(buffer);
+        };
         /**
          * Updates the existing vertex data of the mesh geometry for the requested `kind`.
          * If the mesh has no geometry, it is simply returned as it is.
@@ -746,7 +763,7 @@ var BABYLON;
                 }
             }
             // VBOs
-            engine.bindMultiBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
+            engine.bindBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
         };
         Mesh.prototype._draw = function (subMesh, fillMode, instancesCount) {
             if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
@@ -836,40 +853,47 @@ var BABYLON;
             var visibleInstances = batch.visibleInstances[subMesh._id];
             var matricesCount = visibleInstances.length + 1;
             var bufferSize = matricesCount * 16 * 4;
+            var currentInstancesBufferSize = this._instancesBufferSize;
+            var instancesBuffer = this._instancesBuffer;
             while (this._instancesBufferSize < bufferSize) {
                 this._instancesBufferSize *= 2;
             }
-            if (!this._worldMatricesInstancesBuffer || this._worldMatricesInstancesBuffer.capacity < this._instancesBufferSize) {
-                if (this._worldMatricesInstancesBuffer) {
-                    engine.deleteInstancesBuffer(this._worldMatricesInstancesBuffer);
-                }
-                this._worldMatricesInstancesBuffer = engine.createInstancesBuffer(this._instancesBufferSize);
-                this._worldMatricesInstancesArray = new Float32Array(this._instancesBufferSize / 4);
+            if (!this._instancesData || currentInstancesBufferSize != this._instancesBufferSize) {
+                this._instancesData = new Float32Array(this._instancesBufferSize / 4);
             }
             var offset = 0;
             var instancesCount = 0;
             var world = this.getWorldMatrix();
             if (batch.renderSelf[subMesh._id]) {
-                world.copyToArray(this._worldMatricesInstancesArray, offset);
+                world.copyToArray(this._instancesData, offset);
                 offset += 16;
                 instancesCount++;
             }
             if (visibleInstances) {
                 for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
                     var instance = visibleInstances[instanceIndex];
-                    instance.getWorldMatrix().copyToArray(this._worldMatricesInstancesArray, offset);
+                    instance.getWorldMatrix().copyToArray(this._instancesData, offset);
                     offset += 16;
                     instancesCount++;
                 }
             }
-            var offsetLocation0 = effect.getAttributeLocationByName("world0");
-            var offsetLocation1 = effect.getAttributeLocationByName("world1");
-            var offsetLocation2 = effect.getAttributeLocationByName("world2");
-            var offsetLocation3 = effect.getAttributeLocationByName("world3");
-            var offsetLocations = [offsetLocation0, offsetLocation1, offsetLocation2, offsetLocation3];
-            engine.updateAndBindInstancesBuffer(this._worldMatricesInstancesBuffer, this._worldMatricesInstancesArray, offsetLocations);
+            if (!instancesBuffer || currentInstancesBufferSize != this._instancesBufferSize) {
+                if (instancesBuffer) {
+                    instancesBuffer.dispose();
+                }
+                instancesBuffer = new BABYLON.Buffer(engine, this._instancesData, true, 16, false, true);
+                this._instancesBuffer = instancesBuffer;
+                this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world0", 0, 4));
+                this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world1", 4, 4));
+                this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world2", 8, 4));
+                this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world3", 12, 4));
+                engine.bindBuffers(this.geometry.getVertexBuffers(), this.geometry.getIndexBuffer(), effect);
+            }
+            else {
+                instancesBuffer.updateDirectly(this._instancesData, 0, instancesCount);
+            }
             this._draw(subMesh, fillMode, instancesCount);
-            engine.unBindInstancesBuffer(this._worldMatricesInstancesBuffer, offsetLocations);
+            engine.unbindInstanceAttributes();
         };
         Mesh.prototype._processRendering = function (subMesh, effect, fillMode, batch, hardwareInstancedRendering, onBeforeDraw) {
             var scene = this.getScene();
@@ -883,7 +907,7 @@ var BABYLON;
                     if (onBeforeDraw) {
                         onBeforeDraw(false, this.getWorldMatrix());
                     }
-                    this._draw(subMesh, fillMode);
+                    this._draw(subMesh, fillMode, this._overridenInstanceCount);
                 }
                 if (batch.visibleInstances[subMesh._id]) {
                     for (var instanceIndex = 0; instanceIndex < batch.visibleInstances[subMesh._id].length; instanceIndex++) {
@@ -1160,9 +1184,9 @@ var BABYLON;
                 this._geometry.releaseForMesh(this, true);
             }
             // Instances
-            if (this._worldMatricesInstancesBuffer) {
-                this.getEngine().deleteInstancesBuffer(this._worldMatricesInstancesBuffer);
-                this._worldMatricesInstancesBuffer = null;
+            if (this._instancesBuffer) {
+                this._instancesBuffer.dispose();
+                this._instancesBuffer = null;
             }
             while (this.instances.length) {
                 this.instances[0].dispose();

+ 63 - 74
src/Mesh/babylon.vertexBuffer.js

@@ -1,102 +1,91 @@
 var BABYLON;
 (function (BABYLON) {
     var VertexBuffer = (function () {
-        function VertexBuffer(engine, data, kind, updatable, postponeInternalCreation, stride) {
-            if (engine instanceof BABYLON.Mesh) {
-                this._engine = engine.getScene().getEngine();
+        function VertexBuffer(engine, data, kind, updatable, postponeInternalCreation, stride, instanced, offset, size) {
+            if (!stride) {
+                // Deduce stride from kind
+                switch (kind) {
+                    case VertexBuffer.PositionKind:
+                        stride = 3;
+                        break;
+                    case VertexBuffer.NormalKind:
+                        stride = 3;
+                        break;
+                    case VertexBuffer.UVKind:
+                    case VertexBuffer.UV2Kind:
+                    case VertexBuffer.UV3Kind:
+                    case VertexBuffer.UV4Kind:
+                    case VertexBuffer.UV5Kind:
+                    case VertexBuffer.UV6Kind:
+                        stride = 2;
+                        break;
+                    case VertexBuffer.ColorKind:
+                        stride = 4;
+                        break;
+                    case VertexBuffer.MatricesIndicesKind:
+                    case VertexBuffer.MatricesIndicesExtraKind:
+                        stride = 4;
+                        break;
+                    case VertexBuffer.MatricesWeightsKind:
+                    case VertexBuffer.MatricesWeightsExtraKind:
+                        stride = 4;
+                        break;
+                }
             }
-            else {
-                this._engine = engine;
+            if (data instanceof BABYLON.Buffer) {
+                if (!stride) {
+                    stride = data.getStrideSize();
+                }
+                this._buffer = data;
+                this._ownsBuffer = false;
             }
-            this._updatable = updatable;
-            this._data = data;
-            if (!postponeInternalCreation) {
-                this.create();
+            else {
+                this._buffer = new BABYLON.Buffer(engine, data, updatable, stride, postponeInternalCreation, instanced);
+                this._ownsBuffer = true;
             }
+            this._stride = stride;
+            this._offset = offset ? offset : 0;
+            this._size = size ? size : stride;
             this._kind = kind;
-            if (stride) {
-                this._strideSize = stride;
-                return;
-            }
-            // Deduce stride from kind
-            switch (kind) {
-                case VertexBuffer.PositionKind:
-                    this._strideSize = 3;
-                    break;
-                case VertexBuffer.NormalKind:
-                    this._strideSize = 3;
-                    break;
-                case VertexBuffer.UVKind:
-                case VertexBuffer.UV2Kind:
-                case VertexBuffer.UV3Kind:
-                case VertexBuffer.UV4Kind:
-                case VertexBuffer.UV5Kind:
-                case VertexBuffer.UV6Kind:
-                    this._strideSize = 2;
-                    break;
-                case VertexBuffer.ColorKind:
-                    this._strideSize = 4;
-                    break;
-                case VertexBuffer.MatricesIndicesKind:
-                case VertexBuffer.MatricesIndicesExtraKind:
-                    this._strideSize = 4;
-                    break;
-                case VertexBuffer.MatricesWeightsKind:
-                case VertexBuffer.MatricesWeightsExtraKind:
-                    this._strideSize = 4;
-                    break;
-            }
         }
+        VertexBuffer.prototype.getKind = function () {
+            return this._kind;
+        };
         // Properties
         VertexBuffer.prototype.isUpdatable = function () {
-            return this._updatable;
+            return this._buffer.isUpdatable();
         };
         VertexBuffer.prototype.getData = function () {
-            return this._data;
+            return this._buffer.getData();
         };
         VertexBuffer.prototype.getBuffer = function () {
-            return this._buffer;
+            return this._buffer.getBuffer();
         };
         VertexBuffer.prototype.getStrideSize = function () {
-            return this._strideSize;
+            return this._stride;
+        };
+        VertexBuffer.prototype.getOffset = function () {
+            return this._offset;
+        };
+        VertexBuffer.prototype.getSize = function () {
+            return this._size;
+        };
+        VertexBuffer.prototype.getIsInstanced = function () {
+            return this._buffer.getIsInstanced();
         };
         // Methods
         VertexBuffer.prototype.create = function (data) {
-            if (!data && this._buffer) {
-                return; // nothing to do
-            }
-            data = data || this._data;
-            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;
-            }
+            return this._buffer.create(data);
         };
         VertexBuffer.prototype.update = function (data) {
-            this.create(data);
+            return this._buffer.update(data);
         };
         VertexBuffer.prototype.updateDirectly = function (data, offset) {
-            if (!this._buffer) {
-                return;
-            }
-            if (this._updatable) {
-                this._engine.updateDynamicVertexBuffer(this._buffer, data, offset);
-                this._data = null;
-            }
+            return this._buffer.updateDirectly(data, offset);
         };
         VertexBuffer.prototype.dispose = function () {
-            if (!this._buffer) {
-                return;
-            }
-            if (this._engine._releaseBuffer(this._buffer)) {
-                this._buffer = null;
+            if (this._ownsBuffer) {
+                this._buffer.dispose();
             }
         };
         Object.defineProperty(VertexBuffer, "PositionKind", {

+ 26 - 22
src/Particles/babylon.particleSystem.js

@@ -46,10 +46,9 @@ var BABYLON;
             this.colorDead = new BABYLON.Color4(0, 0, 0, 1.0);
             this.textureMask = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);
             this.particles = new Array();
-            this._vertexDeclaration = [3, 4, 4];
-            this._vertexStrideSize = 11 * 4; // 11 floats per particle (x, y, z, r, g, b, a, angle, size, offsetX, offsetY)
             this._stockParticles = new Array();
             this._newPartsExcess = 0;
+            this._vertexBuffers = {};
             this._scaledColorStep = new BABYLON.Color4(0, 0, 0, 0);
             this._colorDiff = new BABYLON.Color4(0, 0, 0, 0);
             this._scaledDirection = BABYLON.Vector3.Zero();
@@ -63,8 +62,6 @@ var BABYLON;
             this._scene = scene;
             this._customEffect = customEffect;
             scene.particleSystems.push(this);
-            // VBO
-            this._vertexBuffer = scene.getEngine().createDynamicVertexBuffer(capacity * this._vertexStrideSize * 4);
             var indices = [];
             var index = 0;
             for (var count = 0; count < capacity; count++) {
@@ -77,7 +74,15 @@ var BABYLON;
                 index += 4;
             }
             this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
-            this._vertices = new Float32Array(capacity * this._vertexStrideSize);
+            // 11 floats per particle (x, y, z, r, g, b, a, angle, size, offsetX, offsetY) + 1 filler
+            this._vertexData = new Float32Array(capacity * 11 * 4);
+            this._vertexBuffer = new BABYLON.Buffer(scene.getEngine(), this._vertexData, true, 11);
+            var positions = this._vertexBuffer.createVertexBuffer(BABYLON.VertexBuffer.PositionKind, 0, 3);
+            var colors = this._vertexBuffer.createVertexBuffer(BABYLON.VertexBuffer.ColorKind, 3, 4);
+            var options = this._vertexBuffer.createVertexBuffer("options", 7, 4);
+            this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = positions;
+            this._vertexBuffers[BABYLON.VertexBuffer.ColorKind] = colors;
+            this._vertexBuffers["options"] = options;
             // Default behaviors
             this.startDirectionFunction = function (emitPower, worldMatrix, directionToUpdate, particle) {
                 var randX = randomNumber(_this.direction1.x, _this.direction2.x);
@@ -150,17 +155,17 @@ var BABYLON;
         };
         ParticleSystem.prototype._appendParticleVertex = function (index, particle, offsetX, offsetY) {
             var offset = index * 11;
-            this._vertices[offset] = particle.position.x;
-            this._vertices[offset + 1] = particle.position.y;
-            this._vertices[offset + 2] = particle.position.z;
-            this._vertices[offset + 3] = particle.color.r;
-            this._vertices[offset + 4] = particle.color.g;
-            this._vertices[offset + 5] = particle.color.b;
-            this._vertices[offset + 6] = particle.color.a;
-            this._vertices[offset + 7] = particle.angle;
-            this._vertices[offset + 8] = particle.size;
-            this._vertices[offset + 9] = offsetX;
-            this._vertices[offset + 10] = offsetY;
+            this._vertexData[offset] = particle.position.x;
+            this._vertexData[offset + 1] = particle.position.y;
+            this._vertexData[offset + 2] = particle.position.z;
+            this._vertexData[offset + 3] = particle.color.r;
+            this._vertexData[offset + 4] = particle.color.g;
+            this._vertexData[offset + 5] = particle.color.b;
+            this._vertexData[offset + 6] = particle.color.a;
+            this._vertexData[offset + 7] = particle.angle;
+            this._vertexData[offset + 8] = particle.size;
+            this._vertexData[offset + 9] = offsetX;
+            this._vertexData[offset + 10] = offsetY;
         };
         ParticleSystem.prototype._update = function (newParticles) {
             // Update current
@@ -212,7 +217,7 @@ var BABYLON;
             var join = defines.join("\n");
             if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
-                this._effect = this._scene.getEngine().createEffect("particles", ["position", "color", "options"], ["invView", "view", "projection", "vClipPlane", "textureMask"], ["diffuseSampler"], join);
+                this._effect = this._scene.getEngine().createEffect("particles", [BABYLON.VertexBuffer.PositionKind, BABYLON.VertexBuffer.ColorKind, "options"], ["invView", "view", "projection", "vClipPlane", "textureMask"], ["diffuseSampler"], join);
             }
             return this._effect;
         };
@@ -271,8 +276,7 @@ var BABYLON;
                 this._appendParticleVertex(offset++, particle, 1, 1);
                 this._appendParticleVertex(offset++, particle, 0, 1);
             }
-            var engine = this._scene.getEngine();
-            engine.updateDynamicVertexBuffer(this._vertexBuffer, this._vertices);
+            this._vertexBuffer.update(this._vertexData);
         };
         ParticleSystem.prototype.render = function () {
             var effect = this._getEffect();
@@ -296,7 +300,7 @@ var BABYLON;
                 effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
             }
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
             // Draw order
             if (this.blendMode === ParticleSystem.BLENDMODE_ONEONE) {
                 engine.setAlphaMode(BABYLON.Engine.ALPHA_ONEONE);
@@ -313,7 +317,7 @@ var BABYLON;
         };
         ParticleSystem.prototype.dispose = function () {
             if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+                this._vertexBuffer.dispose();
                 this._vertexBuffer = null;
             }
             if (this._indexBuffer) {
@@ -334,7 +338,7 @@ var BABYLON;
         // Clone
         ParticleSystem.prototype.clone = function (name, newEmitter) {
             var result = new ParticleSystem(name, this._capacity, this._scene);
-            BABYLON.Tools.DeepCopy(this, result, ["particles"], ["_vertexDeclaration", "_vertexStrideSize"]);
+            BABYLON.Tools.DeepCopy(this, result, ["particles"]);
             if (newEmitter === undefined) {
                 newEmitter = this.emitter;
             }

+ 3 - 3
src/Particles/babylon.particleSystem.ts

@@ -124,8 +124,8 @@
             this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
 
             // 11 floats per particle (x, y, z, r, g, b, a, angle, size, offsetX, offsetY) + 1 filler
-            this._vertexData = new Float32Array(capacity * 12);
-            this._vertexBuffer = new Buffer(scene.getEngine(), this._vertexData, true, 12);
+            this._vertexData = new Float32Array(capacity * 11 * 4);
+            this._vertexBuffer = new Buffer(scene.getEngine(), this._vertexData, true, 11);
 
             var positions = this._vertexBuffer.createVertexBuffer(VertexBuffer.PositionKind, 0, 3);
             var colors = this._vertexBuffer.createVertexBuffer(VertexBuffer.ColorKind, 3, 4);
@@ -213,7 +213,7 @@
         }
 
         public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {
-            var offset = index * 12;
+            var offset = index * 11;
             this._vertexData[offset] = particle.position.x;
             this._vertexData[offset + 1] = particle.position.y;
             this._vertexData[offset + 2] = particle.position.z;

+ 9 - 9
src/PostProcess/babylon.postProcessManager.js

@@ -2,12 +2,11 @@ var BABYLON;
 (function (BABYLON) {
     var PostProcessManager = (function () {
         function PostProcessManager(scene) {
-            this._vertexDeclaration = [2];
-            this._vertexStrideSize = 2 * 4;
+            this._vertexBuffers = {};
             this._scene = scene;
         }
         PostProcessManager.prototype._prepareBuffers = function () {
-            if (this._vertexBuffer) {
+            if (this._vertexBuffers[BABYLON.VertexBuffer.PositionKind]) {
                 return;
             }
             // VBO
@@ -16,7 +15,7 @@ var BABYLON;
             vertices.push(-1, 1);
             vertices.push(-1, -1);
             vertices.push(1, -1);
-            this._vertexBuffer = this._scene.getEngine().createVertexBuffer(vertices);
+            this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = new BABYLON.VertexBuffer(this._scene.getEngine(), vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2);
             // Indices
             var indices = [];
             indices.push(0);
@@ -56,7 +55,7 @@ var BABYLON;
                     pp.onBeforeRenderObservable.notifyObservers(effect);
                     // VBOs
                     this._prepareBuffers();
-                    engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+                    engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
                     // Draw order
                     engine.draw(true, 0, 6);
                     pp.onAfterRenderObservable.notifyObservers(effect);
@@ -93,7 +92,7 @@ var BABYLON;
                     pp.onBeforeRenderObservable.notifyObservers(effect);
                     // VBOs
                     this._prepareBuffers();
-                    engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+                    engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
                     // Draw order
                     engine.draw(true, 0, 6);
                     pp.onAfterRenderObservable.notifyObservers(effect);
@@ -104,9 +103,10 @@ var BABYLON;
             engine.setDepthWrite(true);
         };
         PostProcessManager.prototype.dispose = function () {
-            if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
-                this._vertexBuffer = null;
+            var buffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
+            if (buffer) {
+                buffer.dispose();
+                this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null;
             }
             if (this._indexBuffer) {
                 this._scene.getEngine()._releaseBuffer(this._indexBuffer);

+ 11 - 6
src/Rendering/babylon.boundingBoxRenderer.js

@@ -6,6 +6,7 @@ var BABYLON;
             this.backColor = new BABYLON.Color3(0.1, 0.1, 0.1);
             this.showBackLines = true;
             this.renderList = new BABYLON.SmartArray(32);
+            this._vertexBuffers = {};
             this._scene = scene;
         }
         BoundingBoxRenderer.prototype._prepareRessources = function () {
@@ -13,13 +14,13 @@ var BABYLON;
                 return;
             }
             this._colorShader = new BABYLON.ShaderMaterial("colorShader", this._scene, "color", {
-                attributes: ["position"],
+                attributes: [BABYLON.VertexBuffer.PositionKind],
                 uniforms: ["worldViewProjection", "color"]
             });
             var engine = this._scene.getEngine();
             var boxdata = BABYLON.VertexData.CreateBox(1.0);
-            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]);
+            this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = new BABYLON.VertexBuffer(engine, boxdata.positions, BABYLON.VertexBuffer.PositionKind, false);
+            this._indexBuffer = 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 () {
             this.renderList.reset();
@@ -45,7 +46,7 @@ var BABYLON;
                     .multiply(BABYLON.Matrix.Translation(median.x, median.y, median.z))
                     .multiply(boundingBox.getWorldMatrix());
                 // VBOs
-                engine.bindBuffers(this._vb.getBuffer(), this._ib, [3], 3 * 4, this._colorShader.getEffect());
+                engine.bindBuffers(this._vertexBuffers, this._indexBuffer, this._colorShader.getEffect());
                 if (this.showBackLines) {
                     // Back
                     engine.setDepthFunctionToGreaterOrEqual();
@@ -72,8 +73,12 @@ var BABYLON;
                 return;
             }
             this._colorShader.dispose();
-            this._vb.dispose();
-            this._scene.getEngine()._releaseBuffer(this._ib);
+            var buffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
+            if (buffer) {
+                buffer.dispose();
+                this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null;
+            }
+            this._scene.getEngine()._releaseBuffer(this._indexBuffer);
         };
         return BoundingBoxRenderer;
     }());

+ 14 - 8
src/Rendering/babylon.edgesRenderer.js

@@ -17,7 +17,7 @@ var BABYLON;
             this._linesPositions = new Array();
             this._linesNormals = new Array();
             this._linesIndices = new Array();
-            this._buffers = new Array();
+            this._buffers = {};
             this._checkVerticesInsteadOfIndices = false;
             this._source = source;
             this._checkVerticesInsteadOfIndices = checkVerticesInsteadOfIndices;
@@ -37,8 +37,16 @@ var BABYLON;
             this._lineShader.backFaceCulling = false;
         };
         EdgesRenderer.prototype.dispose = function () {
-            this._vb0.dispose();
-            this._vb1.dispose();
+            var buffer = this._buffers[BABYLON.VertexBuffer.PositionKind];
+            if (buffer) {
+                buffer.dispose();
+                this._buffers[BABYLON.VertexBuffer.PositionKind] = null;
+            }
+            buffer = this._buffers[BABYLON.VertexBuffer.NormalKind];
+            if (buffer) {
+                buffer.dispose();
+                this._buffers[BABYLON.VertexBuffer.NormalKind] = null;
+            }
             this._source.getScene().getEngine()._releaseBuffer(this._ib);
             this._lineShader.dispose();
         };
@@ -208,10 +216,8 @@ var BABYLON;
             }
             // Merge into a single mesh
             var engine = this._source.getScene().getEngine();
-            this._vb0 = new BABYLON.VertexBuffer(engine, this._linesPositions, BABYLON.VertexBuffer.PositionKind, false);
-            this._vb1 = new BABYLON.VertexBuffer(engine, this._linesNormals, BABYLON.VertexBuffer.NormalKind, false, false, 4);
-            this._buffers[BABYLON.VertexBuffer.PositionKind] = this._vb0;
-            this._buffers[BABYLON.VertexBuffer.NormalKind] = this._vb1;
+            this._buffers[BABYLON.VertexBuffer.PositionKind] = new BABYLON.VertexBuffer(engine, this._linesPositions, BABYLON.VertexBuffer.PositionKind, false);
+            this._buffers[BABYLON.VertexBuffer.NormalKind] = new BABYLON.VertexBuffer(engine, this._linesNormals, BABYLON.VertexBuffer.NormalKind, false, false, 4);
             this._ib = engine.createIndexBuffer(this._linesIndices);
             this._indicesCount = this._linesIndices.length;
         };
@@ -223,7 +229,7 @@ var BABYLON;
             var engine = scene.getEngine();
             this._lineShader._preBind();
             // VBOs
-            engine.bindMultiBuffers(this._buffers, this._ib, this._lineShader.getEffect());
+            engine.bindBuffers(this._buffers, this._ib, this._lineShader.getEffect());
             scene.resetCachedMaterial();
             this._lineShader.setColor4("color", this._source.edgesColor);
             if (scene.activeCamera.mode === BABYLON.Camera.ORTHOGRAPHIC_CAMERA) {

+ 36 - 28
src/Sprites/babylon.spriteManager.js

@@ -15,8 +15,7 @@ var BABYLON;
             * @type {BABYLON.Observable}
             */
             this.onDisposeObservable = new BABYLON.Observable();
-            this._vertexDeclaration = [4, 4, 4, 4];
-            this._vertexStrideSize = 16 * 4; // 15 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color)
+            this._vertexBuffers = {};
             this._capacity = capacity;
             this._spriteTexture = new BABYLON.Texture(imgUrl, scene, true, false, samplingMode);
             this._spriteTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
@@ -24,8 +23,6 @@ var BABYLON;
             this._epsilon = epsilon === undefined ? 0.01 : epsilon;
             this._scene = scene;
             this._scene.spriteManagers.push(this);
-            // VBO
-            this._vertexBuffer = scene.getEngine().createDynamicVertexBuffer(capacity * this._vertexStrideSize * 4);
             var indices = [];
             var index = 0;
             for (var count = 0; count < capacity; count++) {
@@ -38,10 +35,21 @@ var BABYLON;
                 index += 4;
             }
             this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
-            this._vertices = new Float32Array(capacity * this._vertexStrideSize);
+            // VBO
+            // 16 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color r, color g, color b, color a)
+            this._vertexData = new Float32Array(capacity * 16 * 4);
+            this._buffer = new BABYLON.Buffer(scene.getEngine(), this._vertexData, true, 16);
+            var positions = this._buffer.createVertexBuffer(BABYLON.VertexBuffer.PositionKind, 0, 4);
+            var options = this._buffer.createVertexBuffer("options", 4, 4);
+            var cellInfo = this._buffer.createVertexBuffer("cellInfo", 8, 4);
+            var colors = this._buffer.createVertexBuffer(BABYLON.VertexBuffer.ColorKind, 12, 4);
+            this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = positions;
+            this._vertexBuffers["options"] = options;
+            this._vertexBuffers["cellInfo"] = cellInfo;
+            this._vertexBuffers[BABYLON.VertexBuffer.ColorKind] = colors;
             // Effects
-            this._effectBase = this._scene.getEngine().createEffect("sprites", ["position", "options", "cellInfo", "color"], ["view", "projection", "textureInfos", "alphaTest"], ["diffuseSampler"], "");
-            this._effectFog = this._scene.getEngine().createEffect("sprites", ["position", "options", "cellInfo", "color"], ["view", "projection", "textureInfos", "alphaTest", "vFogInfos", "vFogColor"], ["diffuseSampler"], "#define FOG");
+            this._effectBase = this._scene.getEngine().createEffect("sprites", [BABYLON.VertexBuffer.PositionKind, "options", "cellInfo", BABYLON.VertexBuffer.ColorKind], ["view", "projection", "textureInfos", "alphaTest"], ["diffuseSampler"], "");
+            this._effectFog = this._scene.getEngine().createEffect("sprites", [BABYLON.VertexBuffer.PositionKind, "options", "cellInfo", BABYLON.VertexBuffer.ColorKind], ["view", "projection", "textureInfos", "alphaTest", "vFogInfos", "vFogColor"], ["diffuseSampler"], "#define FOG");
         }
         Object.defineProperty(SpriteManager.prototype, "onDispose", {
             set: function (callback) {
@@ -73,24 +81,24 @@ var BABYLON;
                 offsetY = this._epsilon;
             else if (offsetY === 1)
                 offsetY = 1 - this._epsilon;
-            this._vertices[arrayOffset] = sprite.position.x;
-            this._vertices[arrayOffset + 1] = sprite.position.y;
-            this._vertices[arrayOffset + 2] = sprite.position.z;
-            this._vertices[arrayOffset + 3] = sprite.angle;
-            this._vertices[arrayOffset + 4] = sprite.width;
-            this._vertices[arrayOffset + 5] = sprite.height;
-            this._vertices[arrayOffset + 6] = offsetX;
-            this._vertices[arrayOffset + 7] = offsetY;
-            this._vertices[arrayOffset + 8] = sprite.invertU ? 1 : 0;
-            this._vertices[arrayOffset + 9] = sprite.invertV ? 1 : 0;
+            this._vertexData[arrayOffset] = sprite.position.x;
+            this._vertexData[arrayOffset + 1] = sprite.position.y;
+            this._vertexData[arrayOffset + 2] = sprite.position.z;
+            this._vertexData[arrayOffset + 3] = sprite.angle;
+            this._vertexData[arrayOffset + 4] = sprite.width;
+            this._vertexData[arrayOffset + 5] = sprite.height;
+            this._vertexData[arrayOffset + 6] = offsetX;
+            this._vertexData[arrayOffset + 7] = offsetY;
+            this._vertexData[arrayOffset + 8] = sprite.invertU ? 1 : 0;
+            this._vertexData[arrayOffset + 9] = sprite.invertV ? 1 : 0;
             var offset = (sprite.cellIndex / rowSize) >> 0;
-            this._vertices[arrayOffset + 10] = sprite.cellIndex - offset * rowSize;
-            this._vertices[arrayOffset + 11] = offset;
+            this._vertexData[arrayOffset + 10] = sprite.cellIndex - offset * rowSize;
+            this._vertexData[arrayOffset + 11] = offset;
             // Color
-            this._vertices[arrayOffset + 12] = sprite.color.r;
-            this._vertices[arrayOffset + 13] = sprite.color.g;
-            this._vertices[arrayOffset + 14] = sprite.color.b;
-            this._vertices[arrayOffset + 15] = sprite.color.a;
+            this._vertexData[arrayOffset + 12] = sprite.color.r;
+            this._vertexData[arrayOffset + 13] = sprite.color.g;
+            this._vertexData[arrayOffset + 14] = sprite.color.b;
+            this._vertexData[arrayOffset + 15] = sprite.color.a;
         };
         SpriteManager.prototype.intersects = function (ray, camera, predicate, fastCheck) {
             var count = Math.min(this._capacity, this.sprites.length);
@@ -158,7 +166,7 @@ var BABYLON;
                 this._appendSpriteVertex(offset++, sprite, 1, 1, rowSize);
                 this._appendSpriteVertex(offset++, sprite, 0, 1, rowSize);
             }
-            engine.updateDynamicVertexBuffer(this._vertexBuffer, this._vertices);
+            this._buffer.update(this._vertexData);
             // Render
             var effect = this._effectBase;
             if (this._scene.fogEnabled && this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
@@ -176,7 +184,7 @@ var BABYLON;
                 effect.setColor3("vFogColor", this._scene.fogColor);
             }
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
             // Draw order
             engine.setDepthFunctionToLessOrEqual();
             effect.setBool("alphaTest", true);
@@ -189,9 +197,9 @@ var BABYLON;
             engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
         };
         SpriteManager.prototype.dispose = function () {
-            if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
-                this._vertexBuffer = null;
+            if (this._buffer) {
+                this._buffer.dispose();
+                this._buffer = null;
             }
             if (this._indexBuffer) {
                 this._scene.getEngine()._releaseBuffer(this._indexBuffer);

+ 1 - 1
src/Sprites/babylon.spriteManager.ts

@@ -68,7 +68,7 @@
 
             // VBO
             // 16 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color r, color g, color b, color a)
-            this._vertexData = new Float32Array(capacity * 16);
+            this._vertexData = new Float32Array(capacity * 16 * 4);
             this._buffer = new Buffer(scene.getEngine(), this._vertexData, true, 16);
 
             var positions = this._buffer.createVertexBuffer(VertexBuffer.PositionKind, 0, 4);

+ 5 - 2
src/Tools/babylon.tools.js

@@ -124,12 +124,15 @@ var BABYLON;
                 maximum: maximum
             };
         };
-        Tools.ExtractMinAndMax = function (positions, start, count, bias) {
+        Tools.ExtractMinAndMax = function (positions, start, count, bias, stride) {
             if (bias === void 0) { bias = null; }
             var minimum = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var maximum = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+            if (!stride) {
+                stride = 3;
+            }
             for (var index = start; index < start + count; index++) {
-                var current = new BABYLON.Vector3(positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2]);
+                var current = new BABYLON.Vector3(positions[index * stride], positions[index * stride + 1], positions[index * stride + 2]);
                 minimum = BABYLON.Vector3.Minimize(current, minimum);
                 maximum = BABYLON.Vector3.Maximize(current, maximum);
             }

+ 96 - 58
src/babylon.engine.js

@@ -152,6 +152,9 @@ var BABYLON;
             this._activeTexturesCache = new Array(this._maxTextureChannels);
             this._compiledEffects = {};
             this._uintIndicesCurrentlySet = false;
+            this._currentBoundBuffer = new Array();
+            this._currentInstanceLocations = new Array();
+            this._currentInstanceBuffers = new Array();
             this._renderingCanvas = canvas;
             this._externalData = new BABYLON.StringDictionary();
             options = options || {};
@@ -699,12 +702,12 @@ var BABYLON;
         };
         // VBOs
         Engine.prototype._resetVertexBufferBinding = function () {
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this.bindBuffer(null, this._gl.ARRAY_BUFFER);
             this._cachedVertexBuffers = null;
         };
         Engine.prototype.createVertexBuffer = function (vertices) {
             var vbo = this._gl.createBuffer();
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vbo);
+            this.bindBuffer(vbo, this._gl.ARRAY_BUFFER);
             if (vertices instanceof Float32Array) {
                 this._gl.bufferData(this._gl.ARRAY_BUFFER, vertices, this._gl.STATIC_DRAW);
             }
@@ -715,34 +718,49 @@ var BABYLON;
             vbo.references = 1;
             return vbo;
         };
-        Engine.prototype.createDynamicVertexBuffer = function (capacity) {
+        Engine.prototype.createDynamicVertexBuffer = function (vertices) {
             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.bindBuffer(vbo, this._gl.ARRAY_BUFFER);
+            if (vertices instanceof Float32Array) {
+                this._gl.bufferData(this._gl.ARRAY_BUFFER, vertices, this._gl.DYNAMIC_DRAW);
+            }
+            else {
+                this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array(vertices), this._gl.DYNAMIC_DRAW);
+            }
             this._resetVertexBufferBinding();
             vbo.references = 1;
             return vbo;
         };
-        Engine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices, offset) {
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
+        Engine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices, offset, count) {
+            this.bindBuffer(vertexBuffer, this._gl.ARRAY_BUFFER);
             if (offset === undefined) {
                 offset = 0;
             }
-            if (vertices instanceof Float32Array) {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, vertices);
+            if (count === undefined) {
+                if (vertices instanceof Float32Array) {
+                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, vertices);
+                }
+                else {
+                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, new Float32Array(vertices));
+                }
             }
             else {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, new Float32Array(vertices));
+                if (vertices instanceof Float32Array) {
+                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, vertices.subarray(offset, offset + count));
+                }
+                else {
+                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices).subarray(offset, offset + count));
+                }
             }
             this._resetVertexBufferBinding();
         };
         Engine.prototype._resetIndexBufferBinding = function () {
-            this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, null);
+            this.bindBuffer(null, this._gl.ELEMENT_ARRAY_BUFFER);
             this._cachedIndexBuffer = null;
         };
         Engine.prototype.createIndexBuffer = function (indices) {
             var vbo = this._gl.createBuffer();
-            this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, vbo);
+            this.bindBuffer(vbo, this._gl.ELEMENT_ARRAY_BUFFER);
             // Check for 32 bits indices
             var arrayBuffer;
             var need32Bits = false;
@@ -764,11 +782,17 @@ var BABYLON;
             vbo.is32Bits = need32Bits;
             return vbo;
         };
-        Engine.prototype.bindBuffers = function (vertexBuffer, indexBuffer, vertexDeclaration, vertexStrideSize, effect) {
+        Engine.prototype.bindBuffer = function (buffer, target) {
+            if (this._currentBoundBuffer[target] !== buffer) {
+                this._gl.bindBuffer(target, buffer);
+                this._currentBoundBuffer[target] = buffer;
+            }
+        };
+        Engine.prototype.bindBuffersDirectly = function (vertexBuffer, indexBuffer, vertexDeclaration, vertexStrideSize, effect) {
             if (this._cachedVertexBuffers !== vertexBuffer || this._cachedEffectForVertexBuffers !== effect) {
                 this._cachedVertexBuffers = vertexBuffer;
                 this._cachedEffectForVertexBuffers = effect;
-                this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
+                this.bindBuffer(vertexBuffer, this._gl.ARRAY_BUFFER);
                 var offset = 0;
                 for (var index = 0; index < vertexDeclaration.length; index++) {
                     var order = effect.getAttributeLocation(index);
@@ -780,11 +804,11 @@ var BABYLON;
             }
             if (this._cachedIndexBuffer !== indexBuffer) {
                 this._cachedIndexBuffer = indexBuffer;
-                this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+                this.bindBuffer(indexBuffer, this._gl.ELEMENT_ARRAY_BUFFER);
                 this._uintIndicesCurrentlySet = indexBuffer.is32Bits;
             }
         };
-        Engine.prototype.bindMultiBuffers = function (vertexBuffers, indexBuffer, effect) {
+        Engine.prototype.bindBuffers = function (vertexBuffers, indexBuffer, effect) {
             if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
                 this._cachedVertexBuffers = vertexBuffers;
                 this._cachedEffectForVertexBuffers = effect;
@@ -796,18 +820,37 @@ var BABYLON;
                         if (!vertexBuffer) {
                             continue;
                         }
-                        var stride = vertexBuffer.getStrideSize();
-                        this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer.getBuffer());
-                        this._gl.vertexAttribPointer(order, stride, this._gl.FLOAT, false, stride * 4, 0);
+                        var buffer = vertexBuffer.getBuffer();
+                        this.bindBuffer(buffer, this._gl.ARRAY_BUFFER);
+                        this._gl.vertexAttribPointer(order, vertexBuffer.getSize(), this._gl.FLOAT, false, vertexBuffer.getStrideSize() * 4, vertexBuffer.getOffset() * 4);
+                        if (vertexBuffer.getIsInstanced()) {
+                            this._caps.instancedArrays.vertexAttribDivisorANGLE(order, 1);
+                            this._currentInstanceLocations.push(order);
+                            this._currentInstanceBuffers.push(buffer);
+                        }
                     }
                 }
             }
             if (indexBuffer != null && this._cachedIndexBuffer !== indexBuffer) {
                 this._cachedIndexBuffer = indexBuffer;
-                this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+                this.bindBuffer(indexBuffer, this._gl.ELEMENT_ARRAY_BUFFER);
                 this._uintIndicesCurrentlySet = indexBuffer.is32Bits;
             }
         };
+        Engine.prototype.unbindInstanceAttributes = function () {
+            var boundBuffer;
+            for (var i = 0, ul = this._currentInstanceLocations.length; i < ul; i++) {
+                var instancesBuffer = this._currentInstanceBuffers[i];
+                if (boundBuffer != instancesBuffer) {
+                    boundBuffer = instancesBuffer;
+                    this.bindBuffer(instancesBuffer, this._gl.ARRAY_BUFFER);
+                }
+                var offsetLocation = this._currentInstanceLocations[i];
+                this._caps.instancedArrays.vertexAttribDivisorANGLE(offsetLocation, 0);
+            }
+            this._currentInstanceBuffers.length = 0;
+            this._currentInstanceLocations.length = 0;
+        };
         Engine.prototype._releaseBuffer = function (buffer) {
             buffer.references--;
             if (buffer.references === 0) {
@@ -819,7 +862,7 @@ var BABYLON;
         Engine.prototype.createInstancesBuffer = function (capacity) {
             var buffer = this._gl.createBuffer();
             buffer.capacity = capacity;
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, buffer);
+            this.bindBuffer(buffer, this._gl.ARRAY_BUFFER);
             this._gl.bufferData(this._gl.ARRAY_BUFFER, capacity, this._gl.DYNAMIC_DRAW);
             return buffer;
         };
@@ -827,7 +870,7 @@ var BABYLON;
             this._gl.deleteBuffer(buffer);
         };
         Engine.prototype.updateAndBindInstancesBuffer = function (instancesBuffer, data, offsetLocations) {
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, instancesBuffer);
+            this.bindBuffer(instancesBuffer, this._gl.ARRAY_BUFFER);
             if (data) {
                 this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, data);
             }
@@ -842,6 +885,8 @@ var BABYLON;
                     this._gl.enableVertexAttribArray(ai.index);
                     this._gl.vertexAttribPointer(ai.index, ai.attributeSize, ai.attribyteType || this._gl.FLOAT, ai.normalized || false, stride, ai.offset);
                     this._caps.instancedArrays.vertexAttribDivisorANGLE(ai.index, 1);
+                    this._currentInstanceLocations.push(ai.index);
+                    this._currentInstanceBuffers.push(instancesBuffer);
                 }
             }
             else {
@@ -850,23 +895,8 @@ var BABYLON;
                     this._gl.enableVertexAttribArray(offsetLocation);
                     this._gl.vertexAttribPointer(offsetLocation, 4, this._gl.FLOAT, false, 64, index * 16);
                     this._caps.instancedArrays.vertexAttribDivisorANGLE(offsetLocation, 1);
-                }
-            }
-        };
-        Engine.prototype.unBindInstancesBuffer = function (instancesBuffer, offsetLocations) {
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, instancesBuffer);
-            if (offsetLocations[0].index !== undefined) {
-                for (var i = 0; i < offsetLocations.length; i++) {
-                    var ai = offsetLocations[i];
-                    this._gl.disableVertexAttribArray(ai.index);
-                    this._caps.instancedArrays.vertexAttribDivisorANGLE(ai.index, 0);
-                }
-            }
-            else {
-                for (var index = 0; index < 4; index++) {
-                    var offsetLocation = offsetLocations[index];
-                    this._gl.disableVertexAttribArray(offsetLocation);
-                    this._caps.instancedArrays.vertexAttribDivisorANGLE(offsetLocation, 0);
+                    this._currentInstanceLocations.push(offsetLocation);
+                    this._currentInstanceBuffers.push(instancesBuffer);
                 }
             }
         };
@@ -981,25 +1011,33 @@ var BABYLON;
                 }
                 return;
             }
-            this._vertexAttribArrays = this._vertexAttribArrays || [];
+            this._vertexAttribArraysToUse = this._vertexAttribArraysToUse || [];
+            this._vertexAttribArraysEnabled = this._vertexAttribArraysEnabled || [];
             // Use program
             this._gl.useProgram(effect.getProgram());
-            for (var i in this._vertexAttribArrays) {
-                //make sure this is a number)
-                var iAsNumber = +i;
-                if (iAsNumber > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[iAsNumber]) {
-                    continue;
-                }
-                this._vertexAttribArrays[iAsNumber] = false;
-                this._gl.disableVertexAttribArray(iAsNumber);
+            var i, ul;
+            for (i = 0, ul = this._vertexAttribArraysToUse.length; i < ul; i++) {
+                this._vertexAttribArraysToUse[i] = false;
             }
             var attributesCount = effect.getAttributesCount();
-            for (var index = 0; index < attributesCount; index++) {
+            for (i = 0; i < attributesCount; i++) {
                 // Attributes
-                var order = effect.getAttributeLocation(index);
+                var order = effect.getAttributeLocation(i);
                 if (order >= 0) {
-                    this._vertexAttribArrays[order] = true;
-                    this._gl.enableVertexAttribArray(order);
+                    this._vertexAttribArraysToUse[order] = true;
+                }
+            }
+            for (i = 0, ul = this._vertexAttribArraysEnabled.length; i < ul; i++) {
+                if (i > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArraysEnabled[i] || this._vertexAttribArraysToUse[i]) {
+                    continue;
+                }
+                this._vertexAttribArraysEnabled[i] = false;
+                this._gl.disableVertexAttribArray(i);
+            }
+            for (i = 0, ul = this._vertexAttribArraysToUse.length; i < ul; i++) {
+                if (this._vertexAttribArraysToUse[i] && !this._vertexAttribArraysEnabled[i]) {
+                    this._vertexAttribArraysEnabled[i] = true;
+                    this._gl.enableVertexAttribArray(i);
                 }
             }
             this._currentEffect = effect;
@@ -1930,13 +1968,13 @@ var BABYLON;
                 this._gl.deleteProgram(this._compiledEffects[name]._program);
             }
             // Unbind
-            for (var i in this._vertexAttribArrays) {
-                //making sure this is a string
-                var iAsNumber = +i;
-                if (iAsNumber > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArrays[iAsNumber]) {
-                    continue;
+            if (this._vertexAttribArraysEnabled) {
+                for (var i = 0, ul = this._vertexAttribArraysEnabled.length; i < ul; i++) {
+                    if (i > this._gl.VERTEX_ATTRIB_ARRAY_ENABLED || !this._vertexAttribArraysEnabled[i]) {
+                        continue;
+                    }
+                    this._gl.disableVertexAttribArray(i);
                 }
-                this._gl.disableVertexAttribArray(iAsNumber);
             }
             this._gl = null;
             // Events

+ 3 - 3
src/babylon.engine.ts

@@ -348,7 +348,7 @@
         private _cachedEffectForVertexBuffers: Effect;
         private _currentRenderTarget: WebGLTexture;
         private _uintIndicesCurrentlySet = false;
-        private _currentBoundBuffer: WebGLBuffer;
+        private _currentBoundBuffer = new Array<WebGLBuffer>();
         private _currentInstanceLocations = new Array<number>();
         private _currentInstanceBuffers = new Array<WebGLBuffer>();
 
@@ -952,9 +952,9 @@
         }
 
         private bindBuffer(buffer: WebGLBuffer, target: number): void {
-            if (this._currentBoundBuffer != buffer) {
+            if (this._currentBoundBuffer[target] !== buffer) {
                 this._gl.bindBuffer(target, buffer);
-                this._currentBoundBuffer = buffer;
+                this._currentBoundBuffer[target] = buffer;
             }
         }