소스 검색

entirely reviewed vertex buffer handling

ncannasse 11 년 전
부모
커밋
91785f8214

+ 3 - 3
h2d/Graphics.hx

@@ -25,7 +25,7 @@ private class GraphicsContent extends h3d.prim.Primitive {
 	var tmp : hxd.FloatBuffer;
 	var index : hxd.IndexBuffer;
 	
-	var buffers : Array<{ buf : hxd.FloatBuffer, vbuf : h3d.impl.Buffer, idx : hxd.IndexBuffer, ibuf : h3d.impl.Indexes }>;
+	var buffers : Array<{ buf : hxd.FloatBuffer, vbuf : h3d.Buffer, idx : hxd.IndexBuffer, ibuf : h3d.Indexes }>;
 	
 	public function new() {
 		buffers = [];
@@ -59,10 +59,10 @@ private class GraphicsContent extends h3d.prim.Primitive {
 	
 	override function alloc( engine : h3d.Engine ) {
 		if (index.length <= 0) return ;
-		buffer = engine.mem.allocVector(tmp, 8, 0);
+		buffer = h3d.Buffer.ofFloats(tmp, 8);
 		indexes = engine.mem.allocIndex(index);
 		for( b in buffers ) {
-			if( b.vbuf == null || b.vbuf.isDisposed() ) b.vbuf = engine.mem.allocVector(b.buf, 8, 0);
+			if( b.vbuf == null || b.vbuf.isDisposed() ) b.vbuf = h3d.Buffer.ofFloats(b.buf, 8);
 			if( b.ibuf == null || b.ibuf.isDisposed() ) b.ibuf = engine.mem.allocIndex(b.idx);
 		}
 	}

+ 1 - 4
h2d/SpriteBatch.hx

@@ -149,10 +149,7 @@ class SpriteBatch extends Drawable {
 			}
 			e = e.next;
 		}
-		var stride = 5;
-		var nverts = Std.int(pos / stride);
-		var buffer = ctx.engine.mem.alloc(nverts, stride, 4);
-		buffer.uploadVector(tmpBuf, 0, nverts);
+		var buffer = h3d.Buffer.ofFloats(tmpBuf, 5, [Dynamic, Quads]);
 		setupShader(ctx.engine, tile, 0);
 		ctx.engine.renderQuadBuffer(buffer);
 		buffer.dispose();

+ 2 - 2
h2d/TileColorGroup.hx

@@ -20,7 +20,7 @@ private class TileLayerContent extends h3d.prim.Primitive {
 		var v = 0;
 		var b = buffer;
 		while( b != null ) {
-			v += b.nvert;
+			v += b.vertices;
 			b = b.next;
 		}
 		return v >> 1;
@@ -126,7 +126,7 @@ private class TileLayerContent extends h3d.prim.Primitive {
 
 	override public function alloc(engine:h3d.Engine) {
 		if( tmp == null ) reset();
-		buffer = engine.mem.allocVector(tmp, 8, 4);
+		buffer = h3d.Buffer.ofFloats(tmp, 8, [Quads]);
 	}
 
 	public function doRender(engine, min, len) {

+ 2 - 10
h2d/TileGroup.hx

@@ -42,20 +42,12 @@ private class TileLayerContent extends h3d.prim.Primitive {
 	}
 	
 	override public function triCount() {
-		if( buffer == null )
-			return tmp.length >> 3;
-		var v = 0;
-		var b = buffer;
-		while( b != null ) {
-			v += b.nvert;
-			b = b.next;
-		}
-		return v >> 1;
+		return if( buffer == null ) tmp.length >> 3 else buffer.totalVertices() >> 1;
 	}
 	
 	override public function alloc(engine:h3d.Engine) {
 		if( tmp == null ) reset();
-		buffer = engine.mem.allocVector(tmp, 4, 4);
+		buffer = h3d.Buffer.ofFloats(tmp, 4, [Quads]);
 	}
 
 	public function doRender(engine, min, len) {

+ 4 - 3
h2d/Tools.hx

@@ -10,7 +10,7 @@ private class CoreObjects  {
 	public var tmpColor : h3d.Vector;
 	public var tmpMatrix : h3d.Matrix;
 	public var tmpMaterial : h3d.mat.Material;
-	public var planBuffer : h3d.impl.Buffer;
+	public var planBuffer : h3d.Buffer;
 	public var nullTile : Tile;
 	
 	var emptyTexture : h3d.mat.Texture;
@@ -35,7 +35,8 @@ private class CoreObjects  {
 			vector.push(pt[1]);
 		}
 		
-		planBuffer = h3d.Engine.getCurrent().mem.allocVector(vector, 4, 4);
+		planBuffer = new h3d.Buffer(4, 4, [Quads]);
+		planBuffer.uploadVector(vector, 0, 4);
 		nullTile = new Tile(null, 0, 0, 5, 5);
 	}
 	
@@ -61,7 +62,7 @@ class Tools {
 		var c = CORE;
 		if( c == null ) return;
 		// if we have lost our context
-		if( c.planBuffer.b.isDisposed() )
+		if( c.planBuffer.isDisposed() )
 			CORE = null;
 	}
 	

+ 128 - 0
h3d/Buffer.hx

@@ -0,0 +1,128 @@
+package h3d;
+
+enum BufferFlag {
+	/**
+		Indicate that the buffer content will be often modified.
+	**/
+	Dynamic;
+	/**
+		The buffer contains only triangles. Imply Managed. Make sure the position is aligned on 3 vertices multiples.
+	**/
+	Triangles;
+	/**
+		The buffer contains only quads. Imply Managed. Make sure the position is aligned on 4 vertices multiples.
+	**/
+	Quads;
+	/**
+		Will allocate the memory as part of an shared buffer pool, preventing a lot of small GPU buffers to be allocated.
+	**/
+	Managed;
+	/**
+		Used internaly
+	**/
+	NoAlloc;
+}
+
+class Buffer {
+
+	public var buffer(default,null) : h3d.impl.ManagedBuffer;
+	public var position(default,null) : Int;
+	public var vertices(default,null) : Int;
+	public var next(default,null) : Buffer;
+	public var flags(default, null) : haxe.EnumFlags<BufferFlag>;
+	
+	public function new(vertices, stride, ?flags : Array<BufferFlag>) {
+		this.vertices = vertices;
+		this.flags = new haxe.EnumFlags();
+		if( flags != null )
+			for( f in flags )
+				this.flags.set(f);
+		if( this.flags.has(Quads) || this.flags.has(Triangles) )
+			this.flags.set(Managed);
+		if( !this.flags.has(NoAlloc) )
+			h3d.Engine.getCurrent().mem.allocBuffer(this, stride);
+	}
+
+	public function isDisposed() {
+		return buffer == null || buffer.isDisposed();
+	}
+	
+	public function dispose() {
+		if( buffer != null ) {
+			buffer.freeBuffer(this);
+			buffer = null;
+			if( next != null ) next.dispose();
+		}
+	}
+	
+	/**
+		Returns the total number of vertices including the potential next buffers if it is split.
+	**/
+	public function totalVertices() {
+		var count = 0;
+		var b = this;
+		while( b != null ) {
+			count += b.vertices;
+			b = b.next;
+		}
+		return count;
+	}
+	
+	public function uploadVector( buf : hxd.FloatBuffer, bufPos : Int, vertices : Int ) {
+		var cur = this;
+		while( vertices > 0 ) {
+			if( cur == null ) throw "Too many vertices";
+			var count = vertices > cur.vertices ? cur.vertices : vertices;
+			cur.buffer.uploadVertexBuffer(cur.position, count, buf, bufPos);
+			bufPos += count * buffer.stride;
+			vertices -= count;
+			cur = cur.next;
+		}
+	}
+	
+	public function uploadBytes( data : haxe.io.Bytes, dataPos : Int, vertices : Int ) {
+		var cur = this;
+		while( vertices > 0 ) {
+			if( cur == null ) throw "Too many vertices";
+			var count = vertices > cur.vertices ? cur.vertices : vertices;
+			cur.buffer.uploadVertexBytes(cur.position, count, data, dataPos);
+			dataPos += count * buffer.stride * 4;
+			vertices -= count;
+			cur = cur.next;
+		}
+	}
+	
+	public static function ofFloats( v : hxd.FloatBuffer, stride : Int, ?flags ) {
+		var nvert = Std.int(v.length / stride);
+		var b = new Buffer(nvert, stride, flags);
+		b.uploadVector(v, 0, nvert);
+		return b;
+	}
+	
+}
+
+class BufferOffset {
+	public var id : Int;
+	public var buffer : Buffer;
+	public var offset : Int;
+	
+	/*
+		This is used to return a list of BufferOffset without allocating an array
+	*/
+	public var next : BufferOffset;
+	
+	static var UID = 0;
+	
+	public function new(buffer, offset) {
+		this.id = UID++;
+		this.buffer = buffer;
+		this.offset = offset;
+	}
+	public function dispose() {
+		if( buffer != null ) {
+			buffer.dispose();
+			buffer = null;
+		}
+		next = null;
+	}
+}

+ 12 - 12
h3d/Engine.hx

@@ -99,28 +99,28 @@ class Engine {
 		selectShader(m.shader);
 	}
 
-	function selectBuffer( buf : h3d.impl.MemoryManager.BigBuffer ) {
+	function selectBuffer( buf : h3d.impl.ManagedBuffer ) {
 		if( buf.isDisposed() )
 			return false;
-		driver.selectBuffer(buf.vbuf);
+		driver.selectBuffer(@:privateAccess buf.vbuf);
 		return true;
 	}
 
-	public inline function renderTriBuffer( b : h3d.impl.Buffer, start = 0, max = -1 ) {
+	public inline function renderTriBuffer( b : Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.triIndexes, 3, start, max);
 	}
 	
-	public inline function renderQuadBuffer( b : h3d.impl.Buffer, start = 0, max = -1 ) {
+	public inline function renderQuadBuffer( b : Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.quadIndexes, 2, start, max);
 	}
 	
 	// we use preallocated indexes so all the triangles are stored inside our buffers
-	function renderBuffer( b : h3d.impl.Buffer, indexes : h3d.impl.Indexes, vertPerTri : Int, startTri = 0, drawTri = -1 ) {
+	function renderBuffer( b : Buffer, indexes : Indexes, vertPerTri : Int, startTri = 0, drawTri = -1 ) {
 		if( indexes.isDisposed() )
 			return;
 		do {
-			var ntri = Std.int(b.nvert / vertPerTri);
-			var pos = Std.int(b.pos / vertPerTri);
+			var ntri = Std.int(b.vertices / vertPerTri);
+			var pos = Std.int(b.position / vertPerTri);
 			if( startTri > 0 ) {
 				if( startTri >= ntri ) {
 					startTri -= ntri;
@@ -139,7 +139,7 @@ class Engine {
 					drawTri = 0;
 				}
 			}
-			if( ntri > 0 && selectBuffer(b.b) ) {
+			if( ntri > 0 && selectBuffer(b.buffer) ) {
 				// *3 because it's the position in indexes which are always by 3
 				driver.draw(indexes.ibuf, pos * 3, ntri);
 				drawTriangles += ntri;
@@ -150,14 +150,14 @@ class Engine {
 	}
 	
 	// we use custom indexes, so the number of triangles is the number of indexes/3
-	public function renderIndexed( b : h3d.impl.Buffer, indexes : h3d.impl.Indexes, startTri = 0, drawTri = -1 ) {
+	public function renderIndexed( b : Buffer, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 		if( b.next != null )
 			throw "Buffer is split";
 		if( indexes.isDisposed() )
 			return;
 		var maxTri = Std.int(indexes.count / 3);
 		if( drawTri < 0 ) drawTri = maxTri - startTri;
-		if( drawTri > 0 && selectBuffer(b.b) ) {
+		if( drawTri > 0 && selectBuffer(b.buffer) ) {
 			// *3 because it's the position in indexes which are always by 3
 			driver.draw(indexes.ibuf, startTri * 3, drawTri);
 			drawTriangles += drawTri;
@@ -165,7 +165,7 @@ class Engine {
 		}
 	}
 	
-	public function renderMultiBuffers( buffers : h3d.impl.Buffer.BufferOffset, indexes : h3d.impl.Indexes, startTri = 0, drawTri = -1 ) {
+	public function renderMultiBuffers( buffers : Buffer.BufferOffset, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 		var maxTri = Std.int(indexes.count / 3);
 		if( maxTri <= 0 ) return;
 		driver.selectMultiBuffers(buffers);
@@ -194,7 +194,7 @@ class Engine {
 		if( disposed )
 			mem.onContextLost();
 		else
-			mem = new h3d.impl.MemoryManager(driver, 65400);
+			mem = new h3d.impl.MemoryManager(driver);
 		hardware = driver.isHardware();
 		set_debug(debug);
 		set_fullScreen(fullScreen);

+ 3 - 3
h3d/impl/Indexes.hx → h3d/Indexes.hx

@@ -1,11 +1,11 @@
-package h3d.impl;
+package h3d;
 
 @:allow(h3d.impl.MemoryManager)
 @:allow(h3d.Engine)
 class Indexes {
 
-	var mem : MemoryManager;
-	var ibuf : Driver.IndexBuffer;
+	var mem : h3d.impl.MemoryManager;
+	var ibuf : h3d.impl.Driver.IndexBuffer;
 	public var count(default,null) : Int;
 	
 	function new(mem, ibuf, count) {

+ 1 - 1
h3d/fbx/Geometry.hx

@@ -101,7 +101,7 @@ class Geometry {
 	}
 
 	/**
-		Decode polygon informations into triangle indexes and vertexes indexes.
+		Decode polygon informations into triangle indexes and vertices indexes.
 		Returns vidx, which is the list of vertices indexes and iout which is the index buffer for the full vertex model
 	**/
 	public function getIndexes() {

+ 0 - 91
h3d/impl/Buffer.hx

@@ -1,91 +0,0 @@
-package h3d.impl;
-
-class Buffer {
-
-	public var b : MemoryManager.BigBuffer;
-	public var pos : Int;
-	public var nvert : Int;
-	public var next : Buffer;
-	#if debug
-	public var allocPos : AllocPos;
-	public var allocNext : Buffer;
-	public var allocPrev : Buffer;
-	#end
-	
-	public function new(b, pos, nvert) {
-		this.b = b;
-		this.pos = pos;
-		this.nvert = nvert;
-	}
-
-	public function isDisposed() {
-		return b == null || b.isDisposed();
-	}
-	
-	public function dispose() {
-		if( b != null ) {
-			b.freeCursor(pos, nvert);
-			#if debug
-			if( allocNext != null )
-				allocNext.allocPrev = allocPrev;
-			if( allocPrev != null )
-				allocPrev.allocNext = allocNext;
-			if( b.allocHead == this )
-				b.allocHead = allocNext;
-			#end
-			b = null;
-			if( next != null ) next.dispose();
-		}
-	}
-	
-	public function uploadVector( data : hxd.FloatBuffer, dataPos : Int, nverts : Int ) {
-		var cur = this;
-		while( nverts > 0 ) {
-			if( cur == null ) throw "Too many vertexes";
-			var count = nverts > cur.nvert ? cur.nvert : nverts;
-			cur.b.mem.driver.uploadVertexBuffer(cur.b.vbuf, cur.pos, count, data, dataPos);
-			dataPos += count * b.stride;
-			nverts -= count;
-			cur = cur.next;
-		}
-	}
-	
-	public function uploadBytes( data : haxe.io.Bytes, dataPos : Int, nverts : Int ) {
-		var cur = this;
-		while( nverts > 0 ) {
-			if( cur == null ) throw "Too many vertexes";
-			var count = nverts > cur.nvert ? cur.nvert : nverts;
-			cur.b.mem.driver.uploadVertexBytes(cur.b.vbuf, cur.pos, count, data, dataPos);
-			dataPos += count * b.stride * 4;
-			nverts -= count;
-			cur = cur.next;
-		}
-	}
-	
-}
-
-class BufferOffset {
-	public var id : Int;
-	public var b : Buffer;
-	public var offset : Int;
-	
-	/*
-		This is used to return a list of BufferOffset without allocating an array
-	*/
-	public var next : BufferOffset;
-	
-	static var UID = 0;
-	
-	public function new(b, offset) {
-		this.id = UID++;
-		this.b = b;
-		this.offset = offset;
-	}
-	public function dispose() {
-		if( b != null ) {
-			b.dispose();
-			b = null;
-		}
-		next = null;
-	}
-}

+ 1 - 15
h3d/impl/Driver.hx

@@ -1,22 +1,8 @@
 package h3d.impl;
 
-#if flash
 typedef IndexBuffer = flash.display3D.IndexBuffer3D;
 typedef VertexBuffer = Stage3dDriver.VertexWrapper;
 typedef Texture = flash.display3D.textures.TextureBase;
-#elseif js
-typedef IndexBuffer = js.html.webgl.Buffer;
-typedef VertexBuffer = { b : js.html.webgl.Buffer, stride : Int };
-typedef Texture = js.html.webgl.Texture;
-#elseif cpp
-typedef IndexBuffer = openfl.gl.GLBuffer;
-typedef VertexBuffer = { b : openfl.gl.GLBuffer, stride : Int };
-typedef Texture = openfl.gl.GLTexture;
-#else
-typedef IndexBuffer = Int;
-typedef VertexBuffer = Int;
-typedef Texture = Int;
-#end
 
 class Driver {
 	
@@ -94,7 +80,7 @@ class Driver {
 		return null;
 	}
 
-	public function allocVertex( count : Int, stride : Int ) : VertexBuffer {
+	public function allocVertex( m : ManagedBuffer ) : VertexBuffer {
 		return null;
 	}
 	

+ 139 - 0
h3d/impl/ManagedBuffer.hx

@@ -0,0 +1,139 @@
+package h3d.impl;
+
+@:allow(h3d)
+private class FreeCell {
+	var pos : Int;
+	var count : Int;
+	var next : FreeCell;
+	function new(pos,count,next) {
+		this.pos = pos;
+		this.count = count;
+		this.next = next;
+	}
+}
+
+@:allow(h3d.impl.MemoryManager)
+class ManagedBuffer {
+
+	var mem : MemoryManager;
+	public var stride(default,null) : Int;
+	public var size(default,null) : Int;
+	public var flags(default, null) : haxe.EnumFlags<Buffer.BufferFlag>;
+	
+	var vbuf : Driver.VertexBuffer;
+	var freeList : FreeCell;
+	var next : ManagedBuffer;
+	
+	public function new( stride, size, ?flags : Array<Buffer.BufferFlag> ) {
+		this.flags = new haxe.EnumFlags();
+		if( flags != null )
+			for( f in flags )
+				this.flags.set(f);
+		this.mem = h3d.Engine.getCurrent().mem;
+		this.size = size;
+		this.stride = stride;
+		this.freeList = new FreeCell(0, size, null);
+		mem.allocManaged(this);
+	}
+
+	public function uploadVertexBuffer( start : Int, vertices : Int, buf : hxd.FloatBuffer, bufPos = 0 ) {
+		mem.driver.uploadVertexBuffer(vbuf, start, vertices, buf, bufPos);
+	}
+
+	public function uploadVertexBytes( start : Int, vertices : Int, data : haxe.io.Bytes, dataPos = 0 ) {
+		mem.driver.uploadVertexBytes(vbuf, start, vertices, data, dataPos);
+	}
+	
+	public function alloc(vertices,align) {
+		var p = allocPosition(vertices, align);
+		if( p < 0 )
+			return null;
+		var b = new Buffer(vertices, stride, [NoAlloc]);
+		@:privateAccess {
+			b.position = p;
+			b.buffer = this;
+		};
+		return b;
+	}
+	
+	function allocPosition( nvert : Int, align : Int ) {
+		var free = freeList;
+		while( free != null ) {
+			if( free.count >= nvert ) {
+				var d = (align - (free.pos % align)) % align;
+				if( d == 0 )
+					break;
+				// insert some padding
+				if( free.count >= nvert + d ) {
+					free.next = new FreeCell(free.pos + d, free.count - d, free.next);
+					free.count = d;
+					free = free.next;
+					break;
+				}
+			}
+			free = free.next;
+		}
+		if( free == null )
+			return -1;
+		var pos = free.pos;
+		free.pos += nvert;
+		free.count -= nvert;
+		return pos;
+	}
+	
+	function allocBuffer( b : Buffer ) {
+		var align = b.flags.has(Quads) ? 4 : (b.flags.has(Triangles) ? 3 : 1);
+		var p = allocPosition(b.vertices, align);
+		if( p < 0 ) return false;
+		@:privateAccess {
+			b.position = p;
+			b.buffer = this;
+		};
+		return true;
+	}
+	
+	@:allow(h3d.Buffer.dispose)
+	function freeBuffer( b : Buffer ) {
+		var prev : FreeCell = null;
+		var f = freeList;
+		var nvert = b.vertices;
+		var end = b.position + nvert;
+		while( f != null ) {
+			if( f.pos == end ) {
+				f.pos -= nvert;
+				f.count += nvert;
+				if( prev != null && prev.pos + prev.count == f.pos ) {
+					prev.count += f.count;
+					prev.next = f.next;
+				}
+				nvert = 0;
+				break;
+			}
+			if( f.pos > end ) {
+				if( prev != null && prev.pos + prev.count == b.position )
+					prev.count += nvert;
+				else {
+					var n = new FreeCell(b.position, nvert, f);
+					if( prev == null ) freeList = n else prev.next = n;
+				}
+				nvert = 0;
+				break;
+			}
+			prev = f;
+			f = f.next;
+		}
+		if( nvert != 0 )
+			throw "assert";
+		if( freeList.count == size && !flags.has(Managed) )
+			dispose();
+	}
+
+	public function dispose() {
+		mem.freeManaged(this);
+	}
+	
+	public inline function isDisposed() {
+		return vbuf == null;
+	}
+
+}

+ 203 - 317
h3d/impl/MemoryManager.hx

@@ -1,94 +1,15 @@
 package h3d.impl;
 
-#if flash
-private typedef WeakMap<K,T> = haxe.ds.WeakMap<K,T>;
-#else
-private typedef WeakMap<K,T> = haxe.ds.ObjectMap<K,T>;
-#end
-
-@:allow(h3d)
-class FreeCell {
-	var pos : Int;
-	var count : Int;
-	var next : FreeCell;
-	function new(pos,count,next) {
-		this.pos = pos;
-		this.count = count;
-		this.next = next;
-	}
-}
-
-@:allow(h3d)
-class BigBuffer {
-
-	var mem : MemoryManager;
-	var stride : Int;
-	var size : Int;
-	
-	var vbuf : Driver.VertexBuffer;
-	var free : FreeCell;
-	var next : BigBuffer;
-	#if debug
-	public var allocHead : Buffer;
-	#end
-	
-	function new(mem, v, stride, size) {
-		this.mem = mem;
-		this.size = size;
-		this.stride = stride;
-		this.vbuf = v;
-		this.free = new FreeCell(0,size,null);
-	}
-
-	function freeCursor( pos:Int, nvect:Int ) {
-		var prev : FreeCell = null;
-		var f = free;
-		var end = pos + nvect;
-		while( f != null ) {
-			if( f.pos == end ) {
-				f.pos -= nvect;
-				f.count += nvect;
-				if( prev != null && prev.pos + prev.count == f.pos ) {
-					prev.count += f.count;
-					prev.next = f.next;
-				}
-				return;
-			}
-			if( f.pos > end ) {
-				if( prev != null && prev.pos + prev.count == pos )
-					prev.count += nvect;
-				else {
-					var n = new FreeCell(pos, nvect, f);
-					if( prev == null ) free = n else prev.next = n;
-				}
-				return;
-			}
-			prev = f;
-			f = f.next;
-		}
-		if( nvect != 0 )
-			throw "assert";
-	}
-
-	function dispose() {
-		mem.driver.disposeVertex(vbuf);
-		vbuf = null;
-	}
-	
-	inline function isDisposed() {
-		return vbuf == null;
-	}
-
-}
-
 class MemoryManager {
 
 	static inline var MAX_MEMORY = 250 << 20; // MB
 	static inline var MAX_BUFFERS = 4096;
+	static inline var SIZE = 65533;
+	static var ALL_FLAGS = Type.allEnums(Buffer.BufferFlag);
 
 	@:allow(h3d)
 	var driver : Driver;
-	var buffers : Array<BigBuffer>;
+	var buffers : Array<ManagedBuffer>;
 	var indexes : Array<Indexes>;
 	var textures : Array<h3d.mat.Texture>;
 	
@@ -97,27 +18,23 @@ class MemoryManager {
 	public var usedMemory(default, null) : Int = 0;
 	public var texMemory(default, null) : Int = 0;
 	public var bufferCount(default,null) : Int = 0;
-	public var allocSize(default,null) : Int;
 
-	public function new(driver,allocSize) {
+	public function new(driver) {
 		this.driver = driver;
-		this.allocSize = allocSize;
-
 		indexes = new Array();
 		textures = new Array();
 		buffers = new Array();
-		
 		initIndexes();
 	}
 	
 	function initIndexes() {
 		var indices = new hxd.IndexBuffer();
-		for( i in 0...allocSize ) indices.push(i);
+		for( i in 0...SIZE ) indices.push(i);
 		triIndexes = allocIndex(indices);
 
 		var indices = new hxd.IndexBuffer();
 		var p = 0;
-		for( i in 0...allocSize >> 2 ) {
+		for( i in 0...SIZE >> 2 ) {
 			var k = i << 2;
 			indices.push(k);
 			indices.push(k + 1);
@@ -126,6 +43,7 @@ class MemoryManager {
 			indices.push(k + 1);
 			indices.push(k + 3);
 		}
+		indices.push(SIZE);
 		quadIndexes = allocIndex(indices);
 	}
 
@@ -136,17 +54,17 @@ class MemoryManager {
 	public dynamic function garbage() {
 	}
 
+	// ------------------------------------- BUFFERS ------------------------------------------
+	
 	/**
 		Clean empty (unused) buffers
 	**/
-	public function cleanBuffers() {
+	public function cleanManagedBuffers() {
 		for( i in 0...buffers.length ) {
-			var b = buffers[i], prev : BigBuffer = null;
+			var b = buffers[i], prev : ManagedBuffer = null;
 			while( b != null ) {
-				if( b.free.count == b.size ) {
+				if( b.freeList.count == b.size ) {
 					b.dispose();
-					bufferCount--;
-					usedMemory -= b.size * b.stride * 4;
 					if( prev == null )
 						buffers[i] = b.next;
 					else
@@ -157,73 +75,108 @@ class MemoryManager {
 			}
 		}
 	}
+	
+	@:allow(h3d.impl.ManagedBuffer)
+	function allocManaged( m : ManagedBuffer ) {
+		if( m.vbuf != null ) return;
 
-	public function stats() {
-		var total = 0, free = 0, count = 0;
-		for( b in buffers ) {
-			var b = b;
-			while( b != null ) {
-				total += b.stride * b.size * 4;
-				var f = b.free;
-				while( f != null ) {
-					free += f.count * b.stride * 4;
-					f = f.next;
-				}
-				count++;
-				b = b.next;
+		var mem = m.size * m.stride * 4;
+		while( usedMemory + mem > MAX_MEMORY || bufferCount >= MAX_BUFFERS || (m.vbuf = driver.allocVertex(m)) == null ) {
+			var size = usedMemory - freeMemorySize();
+			garbage();
+			cleanManagedBuffers();
+			if( usedMemory - freeMemorySize() == size ) {
+				if( bufferCount >= MAX_BUFFERS )
+					throw "Too many buffer";
+				throw "Memory full";
 			}
 		}
-		return {
-			bufferCount : count,
-			freeMemory : free,
-			totalMemory : total,
-			textureCount : textures.length,
-			textureMemory : texMemory,
-		};
+		usedMemory += mem;
+		bufferCount++;
 	}
 
-	public function allocStats() : Array<{ file : String, line : Int, count : Int, tex : Bool, size : Int }> {
-		#if !debug
-		return [];
-		#else
-		var h = new Map();
-		var all = [];
-		for( buf in buffers ) {
-			var buf = buf;
-			while( buf != null ) {
-				var b = buf.allocHead;
-				while( b != null ) {
-					var key = b.allocPos.fileName + ":" + b.allocPos.lineNumber;
-					var inf = h.get(key);
-					if( inf == null ) {
-						inf = { file : b.allocPos.fileName, line : b.allocPos.lineNumber, count : 0, size : 0, tex : false };
-						h.set(key, inf);
-						all.push(inf);
+	@:allow(h3d.impl.ManagedBuffer)
+	function freeManaged( m : ManagedBuffer ) {
+		if( m.vbuf == null ) return;
+		driver.disposeVertex(m.vbuf);
+		m.vbuf = null;
+		usedMemory -= m.size * m.stride * 4;
+		bufferCount--;
+	}
+	
+	@:allow(h3d.Buffer)
+	@:access(h3d.Buffer)
+	function allocBuffer( b : Buffer, stride : Int ) {
+		// split big buffers
+		var max = b.flags.has(Quads) ? 65532 : b.flags.has(Triangles) ? 65533 : 65534;
+		if( b.vertices > max ) {
+			if( max == 65534 )
+				throw "Cannot split buffer with "+b.vertices+" vertices if it's not Quads/Triangles";
+			var rem = b.vertices - max;
+			b.vertices = max;
+			// make sure to alloc in order
+			allocBuffer(b, stride);
+			var flags = [];
+			for( f in ALL_FLAGS )
+				if( b.flags.has(f) )
+					flags.push(f);
+			b.next = new Buffer(rem, stride, flags);
+			return;
+		}
+		
+		if( !b.flags.has(Managed) ) {
+			var m = new ManagedBuffer(stride, b.vertices);
+			m.allocBuffer(b);
+			return;
+		}
+		
+		// look into one of the managed buffers
+		var m = buffers[stride], prev = null;
+		while( m != null ) {
+			if( m.allocBuffer(b) )
+				return;
+			prev = m;
+			m = m.next;
+		}
+
+		// if quad/triangles, we are allowed to split it
+		var align = b.flags.has(Triangles) ? 3 : b.flags.has(Quads) ? 4 : 0;
+		if( m == null && align > 0 ) {
+			var total = b.vertices;
+			var size = total;
+			while( size > 2048 ) {
+				m = buffers[stride];
+				size >>= 1;
+				size -= size % align;
+				b.vertices = size;
+				while( m != null ) {
+					if( m.allocBuffer(b) ) {
+						var flags = [];
+						for( f in ALL_FLAGS )
+							if( b.flags.has(f) )
+								flags.push(f);
+						b.next = new Buffer(total - size, stride, flags);
+						return;
 					}
-					inf.count++;
-					inf.size += b.nvert * b.b.stride * 4;
-					b = b.allocNext;
+					m = m.next;
 				}
-				buf = buf.next;
-			}
-		}
-		for( t in textures ) {
-			var key = "$"+t.allocPos.fileName + ":" + t.allocPos.lineNumber;
-			var inf = h.get(key);
-			if( inf == null ) {
-				inf = { file : t.allocPos.fileName, line : t.allocPos.lineNumber, count : 0, size : 0, tex : true };
-				h.set(key, inf);
-				all.push(inf);
 			}
-			inf.count++;
-			inf.size += t.width * t.height * bpp(t);
+			b.vertices = total;
 		}
-		all.sort(function(a, b) return a.size == b.size ? a.line - b.line : b.size - a.size);
-		return all;
-		#end
+		
+		// alloc a new managed buffer
+		m = new ManagedBuffer(stride, SIZE, [Managed]);
+		if( prev == null )
+			buffers[stride] = m;
+		else
+			prev.next = m;
+	
+		if( !m.allocBuffer(b) ) throw "assert";
 	}
+
+	// ------------------------------------- INDEXES ------------------------------------------
 	
-	@:allow(h3d.impl.Indexes.dispose)
+	@:allow(h3d.Indexes.dispose)
 	function deleteIndexes( i : Indexes ) {
 		indexes.remove(i);
 		driver.disposeIndexes(i.ibuf);
@@ -231,6 +184,19 @@ class MemoryManager {
 		usedMemory -= i.count * 2;
 	}
 	
+	public function allocIndex( indices : hxd.IndexBuffer, pos = 0, count = -1 ) {
+		if( count < 0 ) count = indices.length;
+		var ibuf = driver.allocIndexes(count);
+		var idx = new Indexes(this, ibuf, count);
+		idx.upload(indices, 0, count);
+		indexes.push(idx);
+		usedMemory += idx.count * 2;
+		return idx;
+	}
+
+	
+	// ------------------------------------- TEXTURES ------------------------------------------
+	
 	function bpp( t : h3d.mat.Texture ) {
 		return 4;
 	}
@@ -272,39 +238,45 @@ class MemoryManager {
 		texMemory += t.width * t.height * bpp(t);
 	}
 	
-	public function allocIndex( indices : hxd.IndexBuffer, pos = 0, count = -1 ) {
-		if( count < 0 ) count = indices.length;
-		var ibuf = driver.allocIndexes(count);
-		var idx = new Indexes(this, ibuf, count);
-		idx.upload(indices, 0, count);
-		indexes.push(idx);
-		usedMemory += idx.count * 2;
-		return idx;
-	}
-
-	public function allocBytes( bytes : haxe.io.Bytes, stride : Int, align, ?allocPos : AllocPos ) {
-		var count = Std.int(bytes.length / (stride * 4));
-		var b = alloc(count, stride, align, allocPos);
-		b.uploadBytes(bytes, 0, count);
-		return b;
+	// ------------------------------------- DISPOSE ------------------------------------------
+	
+	public function onContextLost() {
+		dispose();
+		initIndexes();
 	}
 
-	public function allocVector( v : hxd.FloatBuffer, stride, align, ?allocPos : AllocPos ) {
-		var nvert = Std.int(v.length / stride);
-		var b = alloc(nvert, stride, align, allocPos);
-		b.uploadVector(v, 0, nvert);
-		return b;
+	public function dispose() {
+		triIndexes.dispose();
+		quadIndexes.dispose();
+		triIndexes = null;
+		quadIndexes = null;
+		for( t in textures.copy() )
+			t.dispose();
+		for( b in buffers.copy() ) {
+			var b = b;
+			while( b != null ) {
+				b.dispose();
+				b = b.next;
+			}
+		}
+		for( i in indexes.copy() )
+			i.dispose();
+		buffers = [];
+		indexes = [];
+		textures = [];
+		bufferCount = 0;
+		usedMemory = 0;
+		texMemory = 0;
 	}
+	
+	// ------------------------------------- STATS ------------------------------------------
 
-	/**
-		The amount of free buffers memory
-	 **/
-	function freeMemory() {
+	function freeMemorySize() {
 		var size = 0;
 		for( b in buffers ) {
 			var b = b;
 			while( b != null ) {
-				var free = b.free;
+				var free = b.freeList;
 				while( free != null ) {
 					size += free.count * b.stride * 4;
 					free = free.next;
@@ -314,160 +286,74 @@ class MemoryManager {
 		}
 		return size;
 	}
-
-	/**
-		Allocate a vertex buffer.
-		Align represent the number of vertex that represent a single primitive : 3 for triangles, 4 for quads
-		You can use 0 to allocate your own buffer but in that case you can't use pre-allocated indexes/quadIndexes
-	 **/
-	public function alloc( nvect : Int, stride, align, ?allocPos : AllocPos ) {
-		var b = buffers[stride], free = null;
-		if( nvect == 0 && align == 0 )
-			align = 3;
-		while( b != null ) {
-			free = b.free;
-			while( free != null ) {
-				if( free.count >= nvect ) {
-					// align 0 must be on first index
-					if( align == 0 ) {
-						if( free.pos != 0 )
-							free = null;
-						break;
-					} else {
-						// we can't alloc into a smaller buffer because we might use preallocated indexes
-						if( b.size != allocSize ) {
-							free = null;
-							break;
-						}
-						var d = (align - (free.pos % align)) % align;
-						if( d == 0 )
-							break;
-							
-						// insert some padding
-						if( free.count >= nvect + d ) {
-							free.next = new FreeCell(free.pos + d, free.count - d, free.next);
-							free.count = d;
-							free = free.next;
-							break;
-						}
-					}
-					break;
+	
+	public function stats() {
+		var total = 0, free = 0, count = 0;
+		for( b in buffers ) {
+			var b = b;
+			while( b != null ) {
+				total += b.stride * b.size * 4;
+				var f = b.freeList;
+				while( f != null ) {
+					free += f.count * b.stride * 4;
+					f = f.next;
 				}
-				free = free.next;
+				count++;
+				b = b.next;
 			}
-			if( free != null ) break;
-			b = b.next;
 		}
-		// try splitting big groups
-		if( b == null && align > 0 ) {
-			var size = nvect;
-			while( size > 1000 ) {
-				b = buffers[stride];
-				size >>= 1;
-				size -= size % align;
+		return {
+			bufferCount : bufferCount,
+			freeManagedMemory : free,
+			managedMemory : total,
+			totalVertexMemory : usedMemory,
+			textureCount : textures.length,
+			textureMemory : texMemory,
+		};
+	}
+
+	public function allocStats() : Array<{ file : String, line : Int, count : Int, tex : Bool, size : Int }> {
+		#if !debug
+		return [];
+		#else
+		var h = new Map();
+		var all = [];
+		/*
+		for( buf in buffers ) {
+			var buf = buf;
+			while( buf != null ) {
+				var b = buf.allocHead;
 				while( b != null ) {
-					free = b.free;
-					// skip not aligned buffers
-					if( b.size != allocSize )
-						free = null;
-					while( free != null ) {
-						if( free.count >= size ) {
-							// check alignment
-							var d = (align - (free.pos % align)) % align;
-							if( d == 0 )
-								break;
-							// insert some padding
-							if( free.count >= size + d ) {
-								free.next = new FreeCell(free.pos + d, free.count - d, free.next);
-								free.count = d;
-								free = free.next;
-								break;
-							}
-						}
-						free = free.next;
+					var key = b.allocPos.fileName + ":" + b.allocPos.lineNumber;
+					var inf = h.get(key);
+					if( inf == null ) {
+						inf = { file : b.allocPos.fileName, line : b.allocPos.lineNumber, count : 0, size : 0, tex : false };
+						h.set(key, inf);
+						all.push(inf);
 					}
-					if( free != null ) break;
-					b = b.next;
+					inf.count++;
+					inf.size += b.nvert * b.b.stride * 4;
+					b = b.allocNext;
 				}
-				if( b != null ) break;
+				buf = buf.next;
 			}
 		}
-		// buffer not found : allocate a new one
-		if( b == null ) {
-			var size;
-			if( align == 0 ) {
-				size = nvect;
-				if( size > 0xFFFF ) throw "Too many vertex to allocate "+size;
-			} else
-				size = allocSize; // group allocations together to minimize buffer count
-			var mem = size * stride * 4, v = null;
-			if( usedMemory + mem > MAX_MEMORY || bufferCount >= MAX_BUFFERS || (v = driver.allocVertex(size,stride)) == null ) {
-				var size = usedMemory - freeMemory();
-				garbage();
-				cleanBuffers();
-				if( usedMemory - freeMemory() == size ) {
-					if( bufferCount >= MAX_BUFFERS )
-						throw "Too many buffer";
-					throw "Memory full";
-				}
-				return alloc(nvect, stride, align, allocPos);
+		*/
+		for( t in textures ) {
+			var key = "$"+t.allocPos.fileName + ":" + t.allocPos.lineNumber;
+			var inf = h.get(key);
+			if( inf == null ) {
+				inf = { file : t.allocPos.fileName, line : t.allocPos.lineNumber, count : 0, size : 0, tex : true };
+				h.set(key, inf);
+				all.push(inf);
 			}
-			usedMemory += mem;
-			bufferCount++;
-			b = new BigBuffer(this, v, stride, size);
-			#if flash
-			untyped v.b = b;
-			#end
-			b.next = buffers[stride];
-			buffers[stride] = b;
-			free = b.free;
+			inf.count++;
+			inf.size += t.width * t.height * bpp(t);
 		}
-		// always alloc multiples of 4 (prevent quad split)
-		var alloc = nvect > free.count ? free.count - (free.count%align) : nvect;
-		var fpos = free.pos;
-		free.pos += alloc;
-		free.count -= alloc;
-		var b = new Buffer(b, fpos, alloc);
-		nvect -= alloc;
-		#if debug
-		var head = b.b.allocHead;
-		b.allocPos = allocPos;
-		b.allocNext = head;
-		if( head != null ) head.allocPrev = b;
-		b.b.allocHead = b;
+		all.sort(function(a, b) return a.size == b.size ? a.line - b.line : b.size - a.size);
+		return all;
 		#end
-		if( nvect > 0 )
-			b.next = this.alloc(nvect, stride, align #if debug, allocPos #end);
-		return b;
 	}
 
-	public function onContextLost() {
-		dispose();
-		initIndexes();
-	}
-
-	public function dispose() {
-		triIndexes.dispose();
-		quadIndexes.dispose();
-		triIndexes = null;
-		quadIndexes = null;
-		for( t in textures.copy() )
-			t.dispose();
-		for( b in buffers.copy() ) {
-			var b = b;
-			while( b != null ) {
-				b.dispose();
-				b = b.next;
-			}
-		}
-		for( i in indexes.copy() )
-			i.dispose();
-		buffers = [];
-		indexes = [];
-		textures = [];
-		bufferCount = 0;
-		usedMemory = 0;
-		texMemory = 0;
-	}
 
 }

+ 16 - 17
h3d/impl/Stage3dDriver.hx

@@ -6,25 +6,24 @@ import h3d.impl.Driver;
 @:allow(h3d.impl.Stage3dDriver)
 class VertexWrapper {
 	var vbuf : flash.display3D.VertexBuffer3D;
-	var stride : Int;
 	var written : Bool;
-	var b : MemoryManager.BigBuffer;
+	var b : ManagedBuffer;
 	
-	function new(vbuf, stride) {
+	function new(vbuf, b) {
 		this.vbuf = vbuf;
-		this.stride = stride;
+		this.b = b;
 	}
-	
+		
 	function finalize( driver : Stage3dDriver ) {
 		if( written ) return;
 		written = true;
 		// fill all the free positions that were unwritten with zeroes (necessary for flash)
-		var f = b.free;
+		var f = @:privateAccess b.freeList;
 		while( f != null ) {
 			if( f.count > 0 ) {
 				var mem : UInt = f.count * b.stride * 4;
 				if( driver.empty.length < mem ) driver.empty.length = mem;
-				driver.uploadVertexBytes(b.vbuf, f.pos, f.count, haxe.io.Bytes.ofData(driver.empty), 0);
+				driver.uploadVertexBytes(@:privateAccess b.vbuf, f.pos, f.count, haxe.io.Bytes.ofData(driver.empty), 0);
 			}
 			f = f.next;
 		}
@@ -151,17 +150,17 @@ class Stage3dDriver extends Driver {
 		t.dispose();
 	}
 	
-	override function allocVertex( count : Int, stride : Int ) : VertexBuffer {
+	override function allocVertex( buf : ManagedBuffer ) : VertexBuffer {
 		var v;
 		try {
-			v = ctx.createVertexBuffer(count, stride);
+			v = ctx.createVertexBuffer(buf.size, buf.stride);
 		} catch( e : flash.errors.Error ) {
 			// too many resources / out of memory
 			if( e.errorID == 3691 )
 				return null;
 			throw e;
 		}
-		return new VertexWrapper(v, stride);
+		return new VertexWrapper(v, buf);
 	}
 
 	override function allocIndexes( count : Int ) : IndexBuffer {
@@ -249,7 +248,7 @@ class Stage3dDriver extends Driver {
 	
 	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
 		var data = buf.getNative();
-		v.vbuf.uploadFromVector( bufPos == 0 ? data : data.slice(bufPos, vertexCount * v.stride + bufPos), startVertex, vertexCount );
+		v.vbuf.uploadFromVector( bufPos == 0 ? data : data.slice(bufPos, vertexCount * v.b.stride + bufPos), startVertex, vertexCount );
 	}
 
 	override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, bytes : haxe.io.Bytes, bufPos : Int ) {
@@ -345,8 +344,8 @@ class Stage3dDriver extends Driver {
 			return;
 		curBuffer = v;
 		curMultiBuffer[0] = -1;
-		if( v.stride < curShader.stride )
-			throw "Buffer stride (" + v.stride + ") and shader stride (" + curShader.stride + ") mismatch";
+		if( v.b.stride < curShader.stride )
+			throw "Buffer stride (" + v.b.stride + ") and shader stride (" + curShader.stride + ") mismatch";
 		if( !v.written )
 			v.finalize(this);
 		var pos = 0, offset = 0;
@@ -385,11 +384,11 @@ class Stage3dDriver extends Driver {
 			var b = buffers;
 			while( offset < curShader.stride ) {
 				var size = bits & 7;
-				if( b.b.next != null )
+				if( b.buffer.next != null )
 					throw "Buffer is split";
-				if( !b.b.b.vbuf.written )
-					b.b.b.vbuf.finalize(this);
-				ctx.setVertexBufferAt(pos, b.b.b.vbuf.vbuf, b.offset, FORMAT[size]);
+				var vbuf = @:privateAccess b.buffer.buffer.vbuf;
+				if( !vbuf.written ) vbuf.finalize(this);
+				ctx.setVertexBufferAt(pos, vbuf.vbuf, b.offset, FORMAT[size]);
 				curMultiBuffer[pos] = b.id;
 				offset += size == 0 ? 1 : size;
 				bits >>= 3;

+ 1 - 3
h3d/parts/Emitter.hx

@@ -558,9 +558,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		var stride = 10;
 		if( hasColor ) stride += 4;
-		var nverts = Std.int(pos / stride);
-		var buffer = ctx.engine.mem.alloc(nverts, stride, 4);
-		buffer.uploadVector(tmpBuf, 0, nverts);
+		var buffer = h3d.Buffer.ofFloats(tmpBuf, stride, [Quads, Dynamic]);
 		var size = eval(state.globalSize);
 		
 		material.pshader.mpos = state.emitLocal ? this.absPos : h3d.Matrix.I();

+ 7 - 7
h3d/prim/FBXModel.hx

@@ -1,6 +1,6 @@
 package h3d.prim;
 using h3d.fbx.Data;
-import h3d.impl.Buffer.BufferOffset;
+import h3d.Buffer.BufferOffset;
 import h3d.col.Point;
 
 class FBXModel extends MeshPrimitive {
@@ -10,7 +10,7 @@ class FBXModel extends MeshPrimitive {
 	public var multiMaterial : Bool;
 	var bounds : h3d.col.Bounds;
 	var curMaterial : Int;
-	var groupIndexes : Array<h3d.impl.Indexes>;
+	var groupIndexes : Array<Indexes>;
 
 	public function new(g) {
 		this.geom = g;
@@ -183,17 +183,17 @@ class FBXModel extends MeshPrimitive {
 			pos++;
 		}
 		
-		addBuffer("pos", engine.mem.allocVector(pbuf, 3, 0));
-		if( nbuf != null ) addBuffer("normal", engine.mem.allocVector(nbuf, 3, 0));
-		if( tbuf != null ) addBuffer("uv", engine.mem.allocVector(tbuf, 2, 0));
+		addBuffer("pos", h3d.Buffer.ofFloats(pbuf, 3));
+		if( nbuf != null ) addBuffer("normal", h3d.Buffer.ofFloats(nbuf, 3));
+		if( tbuf != null ) addBuffer("uv", h3d.Buffer.ofFloats(tbuf, 2));
 		if( sbuf != null ) {
 			var nverts = Std.int(sbuf.length / ((skin.bonesPerVertex + 1) * 4));
-			var skinBuf = engine.mem.alloc(nverts, skin.bonesPerVertex + 1, 0);
+			var skinBuf = new h3d.Buffer(nverts, skin.bonesPerVertex + 1);
 			skinBuf.uploadBytes(sbuf.getBytes(), 0, nverts);
 			addBuffer("weights", skinBuf, 0);
 			addBuffer("indexes", skinBuf, skin.bonesPerVertex);
 		}
-		if( cbuf != null ) addBuffer("color", engine.mem.allocVector(cbuf, 3, 0));
+		if( cbuf != null ) addBuffer("color", h3d.Buffer.ofFloats(cbuf, 3));
 		
 		indexes = engine.mem.allocIndex(idx);
 		if( mats != null ) {

+ 2 - 2
h3d/prim/MeshPrimitive.hx

@@ -2,7 +2,7 @@ package h3d.prim;
 
 class MeshPrimitive extends Primitive {
 		
-	var bufferCache : Map<Int,h3d.impl.Buffer.BufferOffset>;
+	var bufferCache : Map<Int,h3d.Buffer.BufferOffset>;
 	
 	function allocBuffer( engine : h3d.Engine, name : String ) {
 		return null;
@@ -22,7 +22,7 @@ class MeshPrimitive extends Primitive {
 		var id = hash(name);
 		var old = bufferCache.get(id);
 		if( old != null ) old.dispose();
-		bufferCache.set(id, new h3d.impl.Buffer.BufferOffset(buf, offset));
+		bufferCache.set(id, new h3d.Buffer.BufferOffset(buf, offset));
 	}
 
 	override public function dispose() {

+ 1 - 1
h3d/prim/Plan2D.hx

@@ -27,7 +27,7 @@ class Plan2D extends Primitive {
 		v.push( 1);
 		v.push( 0);
 		
-		buffer = engine.mem.allocVector(v, 4, 4);
+		buffer = h3d.Buffer.ofFloats(v, 4, [Quads]);
 	}
 	
 	override function render(engine:h3d.Engine) {

+ 1 - 1
h3d/prim/Plan3D.hx

@@ -73,7 +73,7 @@ class Plan3D extends Primitive {
 		v.push( 0);
 		v.push( 1);
 		
-		buffer = engine.mem.allocVector(v, 8, 4);
+		buffer = h3d.Buffer.ofFloats(v, 8, [Quads]);
 	}
 	
 	override function render(engine:h3d.Engine) {

+ 1 - 1
h3d/prim/Polygon.hx

@@ -56,7 +56,7 @@ class Polygon extends Primitive {
 				buf.push(c.z);
 			}
 		}
-		buffer = engine.mem.allocVector(buf, size, idx == null ? 3 : 0);
+		buffer = h3d.Buffer.ofFloats(buf, size, idx == null ? [Triangles] : null);
 		
 		if( idx != null )
 			indexes = engine.mem.allocIndex(idx);

+ 3 - 11
h3d/prim/Primitive.hx

@@ -2,19 +2,11 @@ package h3d.prim;
 
 class Primitive {
 	
-	public var buffer : h3d.impl.Buffer;
-	public var indexes : h3d.impl.Indexes;
+	public var buffer : Buffer;
+	public var indexes : Indexes;
 	
 	public function triCount() {
-		if( indexes != null )
-			return Std.int(indexes.count / 3);
-		var count = 0;
-		var b = buffer;
-		while( b != null ) {
-			count += Std.int(b.nvert / 3);
-			b = b.next;
-		}
-		return count;
+		return if( indexes != null ) Std.int(indexes.count / 3) else if( buffer == null ) 0 else Std.int(buffer.totalVertices() / 3);
 	}
 	
 	public function getBounds() : h3d.col.Bounds {

+ 1 - 1
h3d/prim/Quads.hx

@@ -62,7 +62,7 @@ class Quads extends Primitive {
 		var size = 3;
 		if( normals != null ) size += 3;
 		if( uvs != null ) size += 2;
-		buffer = engine.mem.allocVector(v,size, 4);
+		buffer = h3d.Buffer.ofFloats(v, size, [Quads]);
 	}
 	
 	public function getPoints() {

+ 1 - 1
h3d/prim/RawPrimitive.hx

@@ -3,7 +3,7 @@ package h3d.prim;
 class RawPrimitive extends Primitive {
 
 	public function new( engine : h3d.Engine, vbuf : hxd.FloatBuffer, stride : Int, ?ibuf : hxd.IndexBuffer ) {
-		buffer = engine.mem.allocVector(vbuf, stride, ibuf == null ? 3 : 0);
+		buffer = h3d.Buffer.ofFloats(vbuf, stride, ibuf == null ? [Triangles] : null);
 		if( ibuf != null )
 			indexes = engine.mem.allocIndex(ibuf);
 	}

+ 1 - 1
h3d/scene/Image.hx

@@ -64,7 +64,7 @@ class Image extends Object {
 		tmp.push(tile.v2);
 		
 		cast(material.shader,ImageShader).tex = tile.getTexture();
-		var b = ctx.engine.mem.allocVector(tmp, 4, 4);
+		var b = h3d.Buffer.ofFloats(tmp,4,[Quads,Dynamic]);
 		ctx.engine.selectMaterial(material);
 		ctx.engine.renderQuadBuffer(b);
 		b.dispose();

+ 1 - 3
h3d/scene/Particles.hx

@@ -142,9 +142,7 @@ class Particles extends Object {
 		if( hasFrame ) stride++;
 		if( hasRotation ) stride++;
 		if( hasSize ) stride++;
-		var nverts = Std.int(pos / stride);
-		var buffer = ctx.engine.mem.alloc(nverts, stride, 4);
-		buffer.uploadVector(tmpBuf, 0, nverts);
+		var buffer = h3d.Buffer.ofFloats(tmpBuf, stride, [Quads, Dynamic]);
 		var size = partSize;
 		ctx.localPos = this.absPos;
 		material.setup(ctx);