浏览代码

interleaved buffers+custom instancing

Ben Adams 9 年之前
父节点
当前提交
f4879db779

+ 3 - 1
Tools/Gulp/config.json

@@ -14,7 +14,7 @@
       "!../../src/**/*.d.ts",
       "../../external references/**/*.d.ts"
     ],
-   "files": [
+    "files": [
       "../../src/Math/babylon.math.js",
       "../../src/Tools/babylon.decorators.js",
       "../../src/Tools/babylon.observable.js",
@@ -66,6 +66,8 @@
       "../../src/Rendering/babylon.renderingGroup.js",
       "../../src/babylon.scene.js",
       "../../src/Mesh/babylon.vertexBuffer.js",
+      "../../src/Mesh/babylon.interleavedBuffer.js",
+      "../../src/Mesh/babylon.interleavedVertexBuffer.js",
       "../../src/Mesh/babylon.instancedMesh.js",
       "../../src/Mesh/babylon.mesh.js",
       "../../src/Mesh/babylon.subMesh.js",

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

@@ -40,7 +40,7 @@
                 let partIndex = instanceInfo._partIndexFromId.get(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);
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingFillAttributes) {
@@ -50,7 +50,7 @@
 
                     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 (let i = 0; i < count; i++) {
                         this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
@@ -63,7 +63,7 @@
                 let partIndex = instanceInfo._partIndexFromId.get(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);
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingBorderAttributes) {
@@ -72,7 +72,7 @@
 
                     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 (let i = 0; i < count; i++) {
                         this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);

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

@@ -40,7 +40,7 @@
                 let partIndex = instanceInfo._partIndexFromId.get(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);
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingFillAttributes) {
@@ -50,7 +50,7 @@
 
                     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 (let i = 0; i < count; i++) {
                         this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
@@ -63,7 +63,7 @@
                 let partIndex = instanceInfo._partIndexFromId.get(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);
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingBorderAttributes) {
@@ -72,7 +72,7 @@
 
                     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 (let i = 0; i < count; i++) {
                         this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);

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

@@ -40,7 +40,7 @@
                 let partIndex = instanceInfo._partIndexFromId.get(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);
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingFillAttributes) {
@@ -50,7 +50,7 @@
 
                     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 (let i = 0; i < count; i++) {
                         this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
@@ -63,7 +63,7 @@
                 let partIndex = instanceInfo._partIndexFromId.get(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);
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingBorderAttributes) {
@@ -72,7 +72,7 @@
 
                     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 (let i = 0; i < count; i++) {
                         this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);

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

@@ -18,7 +18,7 @@
 
             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(Engine.ALPHA_COMBINE);
@@ -29,7 +29,7 @@
                 }
                 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 (let i = 0; i < count; i++) {
                     this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);

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

@@ -22,7 +22,7 @@
 
             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(Engine.ALPHA_ADD);
@@ -30,7 +30,7 @@
             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 (let i = 0; i < count; i++) {
                     this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);

+ 13 - 11
src/Layer/babylon.layer.ts

@@ -9,9 +9,8 @@
         public alphaTest: boolean;
 
         private _scene: Scene;
-        private _vertexDeclaration = [2];
-        private _vertexStrideSize = 2 * 4;
-        private _vertexBuffer: WebGLBuffer;
+        private _vertexBuffer: VertexBuffer;
+        private _vertexBuffers: { [key: string]: IVertexBuffer } = {};
         private _indexBuffer: WebGLBuffer;
         private _effect: Effect;
         private _alphaTestEffect: Effect;
@@ -69,6 +68,8 @@
             this._scene = scene;
             this._scene.layers.push(this);
 
+            var engine = scene.getEngine();
+
             // VBO
             var vertices = [];
             vertices.push(1, 1);
@@ -76,7 +77,8 @@
             vertices.push(-1, -1);
             vertices.push(1, -1);
 
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+            this._vertexBuffer = new VertexBuffer(engine, vertices, VertexBuffer.PositionKind, false, false, 2);
+            this._vertexBuffers[VertexBuffer.PositionKind] = this._vertexBuffer;
 
             // Indices
             var indices = [];
@@ -88,16 +90,16 @@
             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"],
+            this._effect = engine.createEffect("layer",
+                [VertexBuffer.PositionKind],
                 ["textureMatrix", "color", "scale", "offset"],
                 ["textureSampler"], "");
 
-            this._alphaTestEffect = this._scene.getEngine().createEffect("layer",
-                ["position"],
+            this._alphaTestEffect = engine.createEffect("layer",
+                [VertexBuffer.PositionKind],
                 ["textureMatrix", "color", "scale", "offset"],
                 ["textureSampler"], "#define ALPHATEST");
         }
@@ -130,7 +132,7 @@
             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) {
@@ -147,7 +149,7 @@
 
         public dispose(): void {
             if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+                this._vertexBuffer.dispose();
                 this._vertexBuffer = null;
             }
 

+ 11 - 9
src/LensFlare/babylon.lensFlareSystem.ts

@@ -8,9 +8,8 @@
 
         private _scene: Scene;
         private _emitter: any;
-        private _vertexDeclaration = [2];
-        private _vertexStrideSize = 2 * 4;
-        private _vertexBuffer: WebGLBuffer;
+        private _vertexBuffer: VertexBuffer;
+        private _vertexBuffers: { [key: string]: IVertexBuffer } = {};
         private _indexBuffer: WebGLBuffer;
         private _effect: Effect;
         private _positionX: number;
@@ -26,6 +25,8 @@
 
             this.meshesSelectionPredicate = m => 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);
@@ -33,7 +34,8 @@
             vertices.push(-1, -1);
             vertices.push(1, -1);
 
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+            this._vertexBuffer = new VertexBuffer(engine, vertices, VertexBuffer.PositionKind, false, false, 2);
+            this._vertexBuffers[VertexBuffer.PositionKind] = this._vertexBuffer;
 
             // Indices
             var indices = [];
@@ -45,11 +47,11 @@
             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"],
+            this._effect = engine.createEffect("lensFlare",
+                [VertexBuffer.PositionKind],
                 ["color", "viewportMatrix"],
                 ["textureSampler"], "");
         }
@@ -179,7 +181,7 @@
             engine.setAlphaMode(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++) {
@@ -218,7 +220,7 @@
 
         public dispose(): void {
             if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+                this._vertexBuffer.dispose();
                 this._vertexBuffer = null;
             }
 

+ 11 - 10
src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts

@@ -9,13 +9,11 @@
 
         public onGenerated: () => void;
 
-        private _vertexBuffer: WebGLBuffer;
+        private _vertexBuffer: VertexBuffer;
+        private _vertexBuffers: { [key: string]: IVertexBuffer } = {};
         private _indexBuffer: WebGLBuffer;
         private _effect: Effect;
 
-        private _vertexDeclaration = [2];
-        private _vertexStrideSize = 2 * 4;
-
         private _uniforms = new Array<string>();
         private _samplers = new Array<string>();
         private _fragment: any;
@@ -47,12 +45,14 @@
 
             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
@@ -62,7 +62,8 @@
             vertices.push(-1, -1);
             vertices.push(1, -1);
 
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+            this._vertexBuffer = new VertexBuffer(engine, vertices, VertexBuffer.PositionKind, false, false, 2);
+            this._vertexBuffers[VertexBuffer.PositionKind] = this._vertexBuffer;
 
             // Indices
             var indices = [];
@@ -74,7 +75,7 @@
             indices.push(2);
             indices.push(3);
 
-            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
+            this._indexBuffer = engine.createIndexBuffer(indices);
         }
 
         public reset(): void {
@@ -106,7 +107,7 @@
             }
 
             this._effect = engine.createEffect(shaders,
-                ["position"],
+                [VertexBuffer.PositionKind],
                 this._uniforms,
                 this._samplers,
                 "", null, null, () => {
@@ -291,7 +292,7 @@
             }            
 
             // 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++) {

+ 22 - 13
src/Mesh/babylon.geometry.ts

@@ -12,12 +12,12 @@
         private _meshes: Mesh[];
         private _totalVertices = 0;
         private _indices: number[] | Int32Array;
-        private _vertexBuffers;
+        private _vertexBuffers: { [key: string]: IVertexBuffer; };
         private _isDisposed = false;
         private _extend: { minimum: Vector3, maximum: Vector3 };
         private _boundingBias: Vector2;
         public _delayInfo; //ANY
-        private _indexBuffer;
+        private _indexBuffer: WebGLBuffer;
         public _boundingInfo: BoundingInfo;
         public _delayLoadingFunction: (any: any, geometry: Geometry) => void;
         public _softwareSkinningRenderId: number;
@@ -92,18 +92,26 @@
         }
 
         public setVerticesData(kind: string, data: number[] | Float32Array, updatable?: boolean, stride?: number): void {
+            var buffer = new VertexBuffer(this._engine, data, kind, updatable, this._meshes.length === 0, stride);
+
+            this.setVerticesBuffer(buffer);
+        }
+
+        public setVerticesBuffer(buffer: IVertexBuffer): void {
+            var kind = buffer.getKind();
             if (this._vertexBuffers[kind]) {
                 this._vertexBuffers[kind].dispose();
             }
 
-            this._vertexBuffers[kind] = new VertexBuffer(this._engine, data, kind, updatable, this._meshes.length === 0, stride);
+            this._vertexBuffers[kind] = buffer;
 
             if (kind === 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;
@@ -116,6 +124,7 @@
                     mesh.computeWorldMatrix(true);
                 }
             }
+
             this.notifyUpdate(kind);
         }
 
@@ -198,14 +207,14 @@
             }
         }
 
-        public getVertexBuffer(kind: string): VertexBuffer {
+        public getVertexBuffer(kind: string): IVertexBuffer {
             if (!this.isReady()) {
                 return null;
             }
             return this._vertexBuffers[kind];
         }
 
-        public getVertexBuffers(): VertexBuffer[] {
+        public getVertexBuffers(): { [key: string]: IVertexBuffer; } {
             if (!this.isReady()) {
                 return null;
             }
@@ -285,7 +294,7 @@
             }
         }
 
-        public getIndexBuffer(): any {
+        public getIndexBuffer(): WebGLBuffer {
             if (!this.isReady()) {
                 return null;
             }
@@ -344,12 +353,12 @@
             }
         }
 
-        private updateExtend(data = null) {
+        private updateExtend(data = null, stride? : number) {
             if (!data) {
                 data = this._vertexBuffers[VertexBuffer.PositionKind].getData();
             }
 
-            this._extend = Tools.ExtractMinAndMax(data, 0, this._totalVertices, this.boundingBias);
+            this._extend = Tools.ExtractMinAndMax(data, 0, this._totalVertices, this.boundingBias, stride);
         }
 
         private _applyToMesh(mesh: Mesh): void {
@@ -360,7 +369,7 @@
                 if (numOfMeshes === 1) {
                     this._vertexBuffers[kind].create();
                 }
-                this._vertexBuffers[kind]._buffer.references = numOfMeshes;
+                this._vertexBuffers[kind].getBuffer().references = numOfMeshes;
 
                 if (kind === VertexBuffer.PositionKind) {
                     mesh._resetPointsArrayCache();
@@ -378,7 +387,7 @@
             }
 
             // 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) {
@@ -478,7 +487,7 @@
             for (var kind in this._vertexBuffers) {
                 this._vertexBuffers[kind].dispose();
             }
-            this._vertexBuffers = [];
+            this._vertexBuffers = {};
             this._totalVertices = 0;
 
             if (this._indexBuffer) {

+ 99 - 0
src/Mesh/babylon.interleavedBuffer.ts

@@ -0,0 +1,99 @@
+module BABYLON {
+    export class InterleavedBuffer {
+        private _engine: Engine;
+        private _buffer: WebGLBuffer;
+        private _data: number[] | Float32Array;
+        private _updatable: boolean;
+        private _strideSize: number;
+        private _instanced: boolean;
+
+        constructor(engine: any, data: number[] | Float32Array, updatable: boolean, stride: number, postponeInternalCreation?: boolean, instanced?: 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;
+
+            this._data = data;
+
+            this._strideSize = stride;
+
+            if (!postponeInternalCreation) { // by default
+                this.create();
+            }
+
+            this._instanced = instanced;
+        }
+
+        // Properties
+        public isUpdatable(): boolean {
+            return this._updatable;
+        }
+
+        public getData(): number[] | Float32Array {
+            return this._data;
+        }
+
+        public getBuffer(): WebGLBuffer {
+            return this._buffer;
+        }
+
+        public getStrideSize(): number {
+            return this._strideSize;
+        }
+
+        public getIsInstanced(): boolean {
+            return this._instanced;
+        }
+
+        // Methods
+        public create(data?: number[] | Float32Array): void {
+            if (!data && this._buffer) {
+                return; // nothing to do
+            }
+
+            data = data || this._data;
+
+            if (!this._buffer) { // create buffer
+                if (this._updatable) {
+                    this._buffer = this._engine.createDynamicVertexBuffer(data);
+                } else {
+                    this._buffer = this._engine.createVertexBuffer(data);
+                    this._data = null;
+                }
+            }
+
+            if (this._updatable) { // update buffer
+                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+                this._data = data;
+            }
+        }
+
+        public update(data: number[] | Float32Array): void {
+            this.create(data);
+        }
+
+        public updateDirectly(data: Float32Array, offset: number, vertexCount?: number): void {
+            if (!this._buffer) {
+                return;
+            }
+
+            if (this._updatable) { // update buffer
+                this._engine.updateDynamicVertexBuffer(this._buffer, data, offset, (vertexCount ? vertexCount * this.getStrideSize() : undefined));
+                this._data = data;
+            }
+        }
+
+        public dispose(): void {
+            if (!this._buffer) {
+                return;
+            }
+            if (this._engine._releaseBuffer(this._buffer)) {
+                this._buffer = null;
+            }
+        }
+    }
+} 

+ 66 - 0
src/Mesh/babylon.interleavedVertexBuffer.ts

@@ -0,0 +1,66 @@
+module BABYLON {
+    export class InterleavedVertexBuffer implements IVertexBuffer {
+        private _buffer: InterleavedBuffer;
+        private _offset: number;
+        private _size: number;
+        private _kind: string;
+
+        constructor(buffer: InterleavedBuffer, kind: string, size: number, offset: number) {
+            this._kind = kind;
+
+            this._buffer = buffer;
+            this._offset = offset;
+            this._size = size;
+        }
+
+        public getKind(): string {
+            return this._kind;
+        }
+
+        public getStrideSize(): number {
+            return this._buffer.getStrideSize();
+        }
+
+        public getOffset(): number {
+            return this._offset;
+        }
+
+        public getSize(): number {
+            return this._size;
+        }
+
+        public getIsInstanced(): boolean {
+            return this._buffer.getIsInstanced();
+        }
+
+        public getBuffer(): WebGLBuffer {
+            return this._buffer.getBuffer();
+        }
+
+        public getData(): number[] | Float32Array {
+            return this._buffer.getData();
+        }
+
+        public isUpdatable(): boolean {
+            return this._buffer.isUpdatable();
+        }
+
+        public create(data?: number[] | Float32Array): void
+        {
+            return this._buffer.create(data);
+        }
+
+        public update(data: number[] | Float32Array): void
+        {
+            return this._buffer.update(data);
+        }
+
+        public updateDirectly(data: Float32Array, offset: number): void
+        {
+            return this._buffer.updateDirectly(data, offset);
+        }
+
+        public dispose(): void {
+        }
+    }
+} 

+ 7 - 3
src/Mesh/babylon.linesMesh.ts

@@ -3,6 +3,8 @@
         public color = new Color3(1, 1, 1);
         public alpha = 1;
 
+        private _positionBuffer: { [key: string]: IVertexBuffer } = {};
+
         /**
          * The intersection Threshold is the margin applied when intersection a segment of the LinesMesh with a Ray.
          * This margin is expressed in world space coordinates, so its value may vary.
@@ -43,10 +45,12 @@
             this._intersectionThreshold = 0.1;
             this._colorShader = new ShaderMaterial("colorShader", scene, "color",
                 {
-                    attributes: ["position"],
+                    attributes: [VertexBuffer.PositionKind],
                     uniforms: ["worldViewProjection", "color"],
                     needAlphaBlending: true
                 });
+
+            this._positionBuffer[VertexBuffer.PositionKind] = null;
         }
 
         public get material(): Material {
@@ -65,10 +69,10 @@
         public _bind(subMesh: SubMesh, effect: Effect, fillMode: number): void {
             var engine = this.getScene().getEngine();
 
-            var indexToBind = this._geometry.getIndexBuffer();
+            this._positionBuffer[VertexBuffer.PositionKind] = this._geometry.getVertexBuffer(VertexBuffer.PositionKind);
 
             // VBOs
-            engine.bindBuffers(this._geometry.getVertexBuffer(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));

+ 51 - 25
src/Mesh/babylon.mesh.ts

@@ -104,12 +104,15 @@
         public _geometry: Geometry;
         public _delayInfo; //ANY
         public _delayLoadingFunction: (any: any, mesh: Mesh) => void;
+
         public _visibleInstances: any = {};
         private _renderIdForInstances = new Array<number>();
         private _batchCache = new _InstancesBatch();
-        private _worldMatricesInstancesBuffer: WebGLBuffer;
-        private _worldMatricesInstancesArray: Float32Array;
         private _instancesBufferSize = 32 * 16 * 4; // let's start with a maximum of 32 instances
+        private _instancesBuffer: InterleavedBuffer;
+        private _instancesData: Float32Array;
+        private _overridenInstanceCount: number;
+
         public _shouldGenerateFlatShading: boolean;
         private _preActivateId: number;
         private _sideOrientation: number = Mesh._DEFAULTSIDE;
@@ -384,7 +387,7 @@
          * - BABYLON.VertexBuffer.MatricesWeightsKind
          * - BABYLON.VertexBuffer.MatricesWeightsExtraKind 
          */
-        public getVertexBuffer(kind): VertexBuffer {
+        public getVertexBuffer(kind): IVertexBuffer {
             if (!this._geometry) {
                 return undefined;
             }
@@ -529,6 +532,13 @@
             this._areNormalsFrozen = false;
         }
 
+        /**
+         * Overrides instance count. Only applicable when custom instanced InterleavedVertexBuffer are used rather than InstancedMeshs
+         */
+        public set OverridenInstanceCount(count: number) {
+            this._overridenInstanceCount = count;
+        }
+
         // Methods
         public _preActivate(): void {
             var sceneRenderId = this.getScene().getRenderId();
@@ -659,6 +669,16 @@
             }
         }
 
+        public setVerticesBuffer(buffer: IVertexBuffer): void {
+            if (!this._geometry) {
+                var scene = this.getScene();
+
+                new Geometry(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.  
@@ -794,7 +814,7 @@
             }
 
             // VBOs
-            engine.bindMultiBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
+            engine.bindBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
         }
 
         public _draw(subMesh: SubMesh, fillMode: number, instancesCount?: number): void {
@@ -900,17 +920,15 @@
             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;
@@ -918,33 +936,41 @@
 
             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");
+            if (!instancesBuffer || currentInstancesBufferSize != this._instancesBufferSize) {
+                if (instancesBuffer) {
+                    instancesBuffer.dispose();
+                }
+
+                instancesBuffer = new BABYLON.InterleavedBuffer(engine, this._instancesData, true, 16, false, true);
+                this._instancesBuffer = instancesBuffer;
 
-            var offsetLocations = [offsetLocation0, offsetLocation1, offsetLocation2, offsetLocation3];
+                this.setVerticesBuffer(new BABYLON.InterleavedVertexBuffer(instancesBuffer, "world0", 4, 0));
+                this.setVerticesBuffer(new BABYLON.InterleavedVertexBuffer(instancesBuffer, "world1", 4, 4));
+                this.setVerticesBuffer(new BABYLON.InterleavedVertexBuffer(instancesBuffer, "world2", 4, 8));
+                this.setVerticesBuffer(new BABYLON.InterleavedVertexBuffer(instancesBuffer, "world3", 4, 12));
 
-            engine.updateAndBindInstancesBuffer(this._worldMatricesInstancesBuffer, this._worldMatricesInstancesArray, offsetLocations);
+                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();
         }
 
         public _processRendering(subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean,
@@ -961,7 +987,7 @@
                         onBeforeDraw(false, this.getWorldMatrix());
                     }
 
-                    this._draw(subMesh, fillMode);
+                    this._draw(subMesh, fillMode, this._overridenInstanceCount);
                 }
 
                 if (batch.visibleInstances[subMesh._id]) {
@@ -1298,9 +1324,9 @@
             }
 
             // 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) {

+ 36 - 4
src/Mesh/babylon.vertexBuffer.ts

@@ -1,14 +1,28 @@
 module BABYLON {
-    export class VertexBuffer {
-        private _mesh: Mesh;
+    export interface IVertexBuffer extends IDisposable {
+        getKind(): string;
+        getStrideSize(): number;
+        getData(): number[] | Float32Array;
+        getBuffer(): WebGLBuffer;
+        getOffset(): number;
+        getSize(): number;
+        getIsInstanced(): boolean;
+        isUpdatable(): boolean;
+        create(data?: number[] | Float32Array): void;
+        update(data: number[] | Float32Array): void;
+        updateDirectly(data: Float32Array, offset: number): void;
+    }
+
+    export class VertexBuffer implements IVertexBuffer {
         private _engine: Engine;
         private _buffer: WebGLBuffer;
         private _data: number[] | Float32Array;
         private _updatable: boolean;
         private _kind: string;
         private _strideSize: number;
+        private _instanced: boolean;
 
-        constructor(engine: any, data: number[] | Float32Array, kind: string, updatable: boolean, postponeInternalCreation?: boolean, stride?: number) {
+        constructor(engine: any, data: number[] | Float32Array, kind: string, updatable: boolean, postponeInternalCreation?: boolean, stride?: number, instanced?: boolean) {
             if (engine instanceof Mesh) { // old versions of BABYLON.VertexBuffer accepted 'mesh' instead of 'engine'
                 this._engine = engine.getScene().getEngine();
             }
@@ -20,6 +34,8 @@
 
             this._data = data;
 
+            this._instanced = instanced;
+
             if (!postponeInternalCreation) { // by default
                 this.create();
             }
@@ -66,6 +82,10 @@
             return this._updatable;
         }
 
+        public getKind(): string {
+            return this._kind;
+        }
+
         public getData(): number[] | Float32Array {
             return this._data;
         }
@@ -78,6 +98,18 @@
             return this._strideSize;
         }
 
+        public getOffset(): number {
+            return 0;
+        }
+
+        public getSize(): number {
+            return this._strideSize;
+        }
+
+        public getIsInstanced(): boolean {
+            return this._instanced;
+        }
+
         // Methods
         public create(data?: number[] | Float32Array): void {
             if (!data && this._buffer) {
@@ -88,7 +120,7 @@
 
             if (!this._buffer) { // create buffer
                 if (this._updatable) {
-                    this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
+                    this._buffer = this._engine.createDynamicVertexBuffer(data);
                 } else {
                     this._buffer = this._engine.createVertexBuffer(data);
                 }

+ 32 - 25
src/Particles/babylon.particleSystem.ts

@@ -77,13 +77,12 @@
 
         private _capacity: number;
         private _scene: Scene;
-        private _vertexDeclaration = [3, 4, 4];
-        private _vertexStrideSize = 11 * 4; // 11 floats per particle (x, y, z, r, g, b, a, angle, size, offsetX, offsetY)
         private _stockParticles = new Array<Particle>();
         private _newPartsExcess = 0;
-        private _vertexBuffer: WebGLBuffer;
+        private _vertexData: Float32Array;
+        private _vertexBuffer: InterleavedBuffer;
+        private _vertexBuffers: { [key: string]: IVertexBuffer } = {};
         private _indexBuffer: WebGLBuffer;
-        private _vertices: Float32Array;
         private _effect: Effect;
         private _customEffect: Effect;
         private _cachedDefines: string;
@@ -110,9 +109,6 @@
 
             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++) {
@@ -127,7 +123,17 @@
 
             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)
+            this._vertexData = new Float32Array(capacity * 11);
+            this._vertexBuffer = new InterleavedBuffer(scene.getEngine(), this._vertexData, true, 11);
+
+            var positions = new InterleavedVertexBuffer(this._vertexBuffer, VertexBuffer.PositionKind, 3, 0);
+            var colors = new InterleavedVertexBuffer(this._vertexBuffer, VertexBuffer.ColorKind, 4, 3);
+            var options = new InterleavedVertexBuffer(this._vertexBuffer, "options", 4, 7);
+
+            this._vertexBuffers[VertexBuffer.PositionKind] = positions;
+            this._vertexBuffers[VertexBuffer.ColorKind] = colors;
+            this._vertexBuffers["options"] = options;
 
             // Default behaviors
             this.startDirectionFunction = (emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void => {
@@ -208,17 +214,17 @@
 
         public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {
             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;
         }
 
         private _update(newParticles: number): void {
@@ -287,7 +293,7 @@
 
                 this._effect = this._scene.getEngine().createEffect(
                     "particles",
-                    ["position", "color", "options"],
+                    [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "options"],
                     ["invView", "view", "projection", "vClipPlane", "textureMask"],
                     ["diffuseSampler"], join);
             }
@@ -363,8 +369,8 @@
                 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);
         }
 
         public render(): number {
@@ -395,7 +401,7 @@
             }
 
             // 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) {
@@ -416,7 +422,7 @@
 
         public dispose(): void {
             if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+                this._vertexBuffer.dispose();
                 this._vertexBuffer = null;
             }
 
@@ -443,7 +449,8 @@
         public clone(name: string, newEmitter: any): ParticleSystem {
             var result = new ParticleSystem(name, this._capacity, this._scene);
 
-            Tools.DeepCopy(this, result, ["particles"], ["_vertexDeclaration", "_vertexStrideSize"]);
+            // TODO
+            Tools.DeepCopy(this, result, ["particles"]);
 
             if (newEmitter === undefined) {
                 newEmitter = this.emitter;

+ 9 - 8
src/PostProcess/babylon.postProcessManager.ts

@@ -2,9 +2,8 @@
     export class PostProcessManager {
         private _scene: Scene;
         private _indexBuffer: WebGLBuffer;
-        private _vertexDeclaration = [2];
-        private _vertexStrideSize = 2 * 4;
-        private _vertexBuffer: WebGLBuffer;
+        private _vertexBuffer: VertexBuffer;
+        private _vertexBuffers: { [key: string]: IVertexBuffer } = {};
 
         constructor(scene: Scene) {
             this._scene = scene;
@@ -21,7 +20,9 @@
             vertices.push(-1, 1);
             vertices.push(-1, -1);
             vertices.push(1, -1);
-            this._vertexBuffer = this._scene.getEngine().createVertexBuffer(vertices);
+
+            this._vertexBuffer = new VertexBuffer(this._scene.getEngine(), vertices, VertexBuffer.PositionKind, false, false, 2);
+            this._vertexBuffers[VertexBuffer.PositionKind] = this._vertexBuffer;
 
             // Indices
             var indices = [];
@@ -70,12 +71,12 @@
 
                     // 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);                    
+                    pp.onAfterRenderObservable.notifyObservers(effect);
                 }
             }
 
@@ -114,7 +115,7 @@
 
                     // 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);
@@ -130,7 +131,7 @@
 
         public dispose(): void {
             if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+                this._vertexBuffer.dispose();
                 this._vertexBuffer = null;
             }
 

+ 10 - 8
src/Rendering/babylon.boundingBoxRenderer.ts

@@ -7,8 +7,9 @@
 
         private _scene: Scene;
         private _colorShader: ShaderMaterial;
-        private _vb: VertexBuffer;
-        private _ib: WebGLBuffer;
+        private _vertexBuffer: VertexBuffer;
+        private _vertexBuffers: { [key: string]: IVertexBuffer } = {};
+        private _indexBuffer: WebGLBuffer;
 
         constructor(scene: Scene) {
             this._scene = scene;
@@ -21,15 +22,16 @@
 
             this._colorShader = new ShaderMaterial("colorShader", this._scene, "color",
                 {
-                    attributes: ["position"],
+                    attributes: [VertexBuffer.PositionKind],
                     uniforms: ["worldViewProjection", "color"]
                 });
 
 
             var engine = this._scene.getEngine();
             var boxdata = VertexData.CreateBox(1.0);
-            this._vb = new VertexBuffer(engine, boxdata.positions, 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._vertexBuffer = new VertexBuffer(engine, boxdata.positions, VertexBuffer.PositionKind, false);
+            this._vertexBuffers[VertexBuffer.PositionKind] = this._vertexBuffer;
+            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]);
         }
 
         public reset(): void {
@@ -62,7 +64,7 @@
                     .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
@@ -95,8 +97,8 @@
             }
 
             this._colorShader.dispose();
-            this._vb.dispose();
-            this._scene.getEngine()._releaseBuffer(this._ib);
+            this._vertexBuffer.dispose();
+            this._scene.getEngine()._releaseBuffer(this._indexBuffer);
         }
     }
 } 

+ 2 - 2
src/Rendering/babylon.edgesRenderer.ts

@@ -22,7 +22,7 @@
         private _vb0: VertexBuffer;
         private _vb1: VertexBuffer;
         private _ib: WebGLBuffer;
-        private _buffers = new Array<VertexBuffer>();
+        private _buffers: { [key: string]: IVertexBuffer; } = {};
         private _checkVerticesInsteadOfIndices = false;
 
         // Beware when you use this class with complex objects as the adjacencies computation can be really long
@@ -282,7 +282,7 @@
             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);

+ 39 - 29
src/Sprites/babylon.spriteManager.ts

@@ -26,11 +26,10 @@
 
         private _scene: Scene;
 
-        private _vertexDeclaration = [4, 4, 4, 4];
-        private _vertexStrideSize = 16 * 4; // 15 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV, cellIndexX, cellIndexY, color)
-        private _vertexBuffer: WebGLBuffer;
+        private _vertexData: Float32Array;
+        private _vertexBuffer: InterleavedBuffer;
+        private _vertexBuffers: { [key: string]: IVertexBuffer } = {};
         private _indexBuffer: WebGLBuffer;
-        private _vertices: Float32Array;
         private _effectBase: Effect;
         private _effectFog: Effect;
 
@@ -53,9 +52,6 @@
             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++) {
@@ -69,16 +65,30 @@
             }
 
             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);
+            this._vertexBuffer = new InterleavedBuffer(scene.getEngine(), this._vertexData, true, 16);
+
+            var positions = new InterleavedVertexBuffer(this._vertexBuffer, VertexBuffer.PositionKind, 4, 0);
+            var options = new InterleavedVertexBuffer(this._vertexBuffer, "options", 4, 4);
+            var cellInfo = new InterleavedVertexBuffer(this._vertexBuffer, "cellInfo", 4, 8);
+            var colors = new InterleavedVertexBuffer(this._vertexBuffer, VertexBuffer.ColorKind, 4, 12);
+
+            this._vertexBuffers[VertexBuffer.PositionKind] = positions;
+            this._vertexBuffers["options"] = options;
+            this._vertexBuffers["cellInfo"] = cellInfo;
+            this._vertexBuffers[VertexBuffer.ColorKind] = colors;
 
             // Effects
             this._effectBase = this._scene.getEngine().createEffect("sprites",
-                ["position", "options", "cellInfo", "color"],
+                [VertexBuffer.PositionKind, "options", "cellInfo", VertexBuffer.ColorKind],
                 ["view", "projection", "textureInfos", "alphaTest"],
                 ["diffuseSampler"], "");
 
             this._effectFog = this._scene.getEngine().createEffect("sprites",
-                ["position", "options", "cellInfo", "color"],
+                [VertexBuffer.PositionKind, "options", "cellInfo", VertexBuffer.ColorKind],
                 ["view", "projection", "textureInfos", "alphaTest", "vFogInfos", "vFogColor"],
                 ["diffuseSampler"], "#define FOG");
         }
@@ -96,24 +106,24 @@
             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;
         }
 
         public intersects(ray: Ray, camera:Camera, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean): PickingInfo {
@@ -198,7 +208,7 @@
                 this._appendSpriteVertex(offset++, sprite, 1, 1, rowSize);
                 this._appendSpriteVertex(offset++, sprite, 0, 1, rowSize);
             }
-            engine.updateDynamicVertexBuffer(this._vertexBuffer, this._vertices);
+            this._vertexBuffer.update(this._vertexData);
 
             // Render
             var effect = this._effectBase;
@@ -223,7 +233,7 @@
             }
 
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
 
             // Draw order
             engine.setDepthFunctionToLessOrEqual();
@@ -240,7 +250,7 @@
 
         public dispose(): void {
             if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+                this._vertexBuffer.dispose();
                 this._vertexBuffer = null;
             }
 

+ 6 - 2
src/Tools/babylon.tools.ts

@@ -158,12 +158,16 @@
             };
         }
 
-        public static ExtractMinAndMax(positions: number[] | Float32Array, start: number, count: number, bias: Vector2 = null): { minimum: Vector3; maximum: Vector3 } {
+        public static ExtractMinAndMax(positions: number[] | Float32Array, start: number, count: number, bias: Vector2 = null, stride?: number): { minimum: Vector3; maximum: Vector3 } {
             var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var maximum = new 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 Vector3(positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2]);
+                var current = new Vector3(positions[index * stride], positions[index * stride + 1], positions[index * stride + 2]);
 
                 minimum = Vector3.Minimize(current, minimum);
                 maximum = Vector3.Maximize(current, maximum);

+ 73 - 42
src/babylon.engine.ts

@@ -162,11 +162,11 @@
         public maxCubemapTextureSize: number;
         public maxRenderTextureSize: number;
         public standardDerivatives: boolean;
-        public s3tc;
+        public s3tc : WEBGL_compressed_texture_s3tc;
         public textureFloat: boolean;
-        public textureAnisotropicFilterExtension;
+        public textureAnisotropicFilterExtension: EXT_texture_filter_anisotropic;
         public maxAnisotropy: number;
-        public instancedArrays;
+        public instancedArrays: ANGLE_instanced_arrays;
         public uintIndices: boolean;
         public highPrecisionShaderSupported: boolean;
         public fragmentDepthSupported: boolean;
@@ -347,6 +347,9 @@
         private _cachedEffectForVertexBuffers: Effect;
         private _currentRenderTarget: WebGLTexture;
         private _uintIndicesCurrentlySet = false;
+        private _currentBoundBuffer: WebGLBuffer;
+        private _currentInstanceLocations = new Array<number>();
+        private _currentInstanceBuffers = new Array<WebGLBuffer>();
 
         private _workingCanvas: HTMLCanvasElement;
         private _workingContext: CanvasRenderingContext2D;
@@ -856,13 +859,13 @@
 
         // VBOs
         private _resetVertexBufferBinding(): void {
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
+            this.bindBuffer(null, this._gl.ARRAY_BUFFER);
             this._cachedVertexBuffers = null;
         }
 
         public createVertexBuffer(vertices: number[] | Float32Array): WebGLBuffer {
             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, <Float32Array>vertices, this._gl.STATIC_DRAW);
@@ -875,39 +878,52 @@
             return vbo;
         }
 
-        public createDynamicVertexBuffer(capacity: number): WebGLBuffer {
+        public createDynamicVertexBuffer(vertices: number[] | Float32Array): WebGLBuffer {
             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, <Float32Array>vertices, this._gl.DYNAMIC_DRAW);
+            } else {
+                this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array(<number[]>vertices), this._gl.DYNAMIC_DRAW);
+            }
             this._resetVertexBufferBinding();
             vbo.references = 1;
             return vbo;
         }
 
-        public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, vertices: number[] | Float32Array, offset?: number): void {
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
+        public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, vertices: number[] | Float32Array, offset?: number, count?: number): void {
+            this.bindBuffer(vertexBuffer, this._gl.ARRAY_BUFFER);
 
             if (offset === undefined) {
                 offset = 0;
             }
 
-            if (vertices instanceof Float32Array) {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, <Float32Array>vertices);
+            if (count === undefined) {
+                if (vertices instanceof Float32Array) {
+                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, <Float32Array>vertices);
+                } else {
+                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, new Float32Array(<number[]>vertices));
+                }
             } else {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, new Float32Array(<number[]>vertices));
+                if (vertices instanceof Float32Array) {
+                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, <Float32Array>vertices.subarray(offset, offset + count));
+                } else {
+                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(<number[]>vertices).subarray(offset, offset + count));
+                }
             }
 
             this._resetVertexBufferBinding();
         }
 
         private _resetIndexBufferBinding(): void {
-            this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, null);
+            this.bindBuffer(null, this._gl.ELEMENT_ARRAY_BUFFER);
             this._cachedIndexBuffer = null;
         }
 
         public createIndexBuffer(indices: number[] | Int32Array): WebGLBuffer {
             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;
@@ -934,12 +950,19 @@
             return vbo;
         }
 
-        public bindBuffers(vertexBuffer: WebGLBuffer, indexBuffer: WebGLBuffer, vertexDeclaration: number[], vertexStrideSize: number, effect: Effect): void {
+        private bindBuffer(buffer: WebGLBuffer, target: number): void {
+            if (this._currentBoundBuffer != buffer) {
+                this._gl.bindBuffer(target, buffer);
+                this._currentBoundBuffer = buffer;
+            }
+        }
+
+        public bindBuffersDirectly(vertexBuffer: WebGLBuffer, indexBuffer: WebGLBuffer, vertexDeclaration: number[], vertexStrideSize: number, effect: Effect): void {
             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++) {
@@ -954,12 +977,12 @@
 
             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;
             }
         }
 
-        public bindMultiBuffers(vertexBuffers: VertexBuffer[], indexBuffer: WebGLBuffer, effect: Effect): void {
+        public bindBuffers(vertexBuffers: { [key: string]: IVertexBuffer; }, indexBuffer: WebGLBuffer, effect: Effect): void {
             if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
                 this._cachedVertexBuffers = vertexBuffers;
                 this._cachedEffectForVertexBuffers = effect;
@@ -974,20 +997,41 @@
                         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;
             }
         }
 
+        public unbindInstanceAttributes() {
+            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;
+        }
+
         public _releaseBuffer(buffer: WebGLBuffer): boolean {
             buffer.references--;
 
@@ -1004,7 +1048,7 @@
 
             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;
         }
@@ -1014,7 +1058,7 @@
         }
 
         public updateAndBindInstancesBuffer(instancesBuffer: WebGLBuffer, data: Float32Array, offsetLocations: number[] | InstancingAttributeInfo[]): void {
-            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);
             }
@@ -1030,6 +1074,8 @@
                     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 {
                 for (let index = 0; index < 4; index++) {
@@ -1037,23 +1083,8 @@
                     this._gl.enableVertexAttribArray(offsetLocation);
                     this._gl.vertexAttribPointer(offsetLocation, 4, this._gl.FLOAT, false, 64, index * 16);
                     this._caps.instancedArrays.vertexAttribDivisorANGLE(offsetLocation, 1);
-                }
-            }
-        }
-
-        public unBindInstancesBuffer(instancesBuffer: WebGLBuffer, offsetLocations: number[] | InstancingAttributeInfo[]): void {
-            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, instancesBuffer);
-            if ((<any>offsetLocations[0]).index !== undefined) {
-                for (let i = 0; i < offsetLocations.length; i++) {
-                    let ai = <InstancingAttributeInfo>offsetLocations[i];
-                    this._gl.disableVertexAttribArray(ai.index);
-                    this._caps.instancedArrays.vertexAttribDivisorANGLE(ai.index, 0);
-                }
-            } else {
-                for (let index = 0; index < 4; index++) {
-                    let offsetLocation = <number>offsetLocations[index];
-                    this._gl.disableVertexAttribArray(offsetLocation);
-                    this._caps.instancedArrays.vertexAttribDivisorANGLE(offsetLocation, 0);
+                    this._currentInstanceLocations.push(offsetLocation);
+                    this._currentInstanceBuffers.push(instancesBuffer);
                 }
             }
         }