Selaa lähdekoodia

completed scn reader/writer, started working on replay (wip)

Nicolas Cannasse 10 vuotta sitten
vanhempi
commit
b5fbae59f7
7 muutettua tiedostoa jossa 317 lisäystä ja 11 poistoa
  1. 3 1
      h3d/impl/ManagedBuffer.hx
  2. 185 5
      h3d/impl/ScnDriver.hx
  3. 3 1
      h3d/mat/Texture.hx
  4. 1 0
      hxd/App.hx
  5. 6 1
      hxd/fmt/scn/Data.hx
  6. 91 0
      hxd/fmt/scn/Reader.hx
  7. 28 3
      hxd/fmt/scn/Writer.hx

+ 3 - 1
h3d/impl/ManagedBuffer.hx

@@ -29,11 +29,13 @@ class ManagedBuffer {
 		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);
+		#if !noEngine
+		this.mem = h3d.Engine.getCurrent().mem;
 		mem.allocManaged(this);
+		#end
 	}
 
 	public function uploadVertexBuffer( start : Int, vertices : Int, buf : hxd.FloatBuffer, bufPos = 0 ) {

+ 185 - 5
h3d/impl/ScnDriver.hx

@@ -6,19 +6,43 @@ class ScnDriver extends Driver {
 
 	var d : Driver;
 	var ops : Array<Operation>;
-	var savedShaders : Map<Int, Bool>;
+	var savedShaders : Map<Int, hxsl.RuntimeShader>;
+	var textureMap : Map<Int, h3d.mat.Texture>;
+	var vertexBuffers : Array<h3d.impl.ManagedBuffer>;
+	var indexBuffers : Array<IndexBuffer>;
 	#if !hxsdl
 	var UID = 0;
 	var indexMap : Map<IndexBuffer, Int>;
 	var vertexMap : Map<VertexBuffer, Int>;
 	#end
 	var vertexStride : Array<Int>;
+	var tmpShader : hxsl.RuntimeShader;
+	var tmpPass : h3d.mat.Pass;
+	var tmpBuf : h3d.shader.Buffers;
+	var tmpVBuf : h3d.Buffer;
+	var frame = 0;
 
 	public function new( driver : Driver ) {
 		this.d = driver;
 		ops = [];
+		tmpPass = new h3d.mat.Pass("");
+		tmpShader = new hxsl.RuntimeShader();
+		var s = tmpShader;
+		s.vertex = new hxsl.RuntimeShader.RuntimeShaderData();
+		s.fragment = new hxsl.RuntimeShader.RuntimeShaderData();
+		s.vertex.globalsSize = 0;
+		s.vertex.paramsSize = 0;
+		s.fragment.globalsSize = 0;
+		s.fragment.paramsSize = 0;
+		s.vertex.textures2DCount = s.vertex.texturesCubeCount = 0;
+		s.fragment.textures2DCount = s.fragment.texturesCubeCount = 0;
+		tmpBuf = new h3d.shader.Buffers(s);
+		tmpVBuf = new h3d.Buffer(0, 0, [NoAlloc]);
 		logEnable = true;
 		savedShaders = new Map();
+		textureMap = new Map();
+		vertexBuffers = [];
+		indexBuffers = [];
 		#if !hxsdl
 		indexMap = new Map();
 		vertexMap = new Map();
@@ -39,7 +63,6 @@ class ScnDriver extends Driver {
 	}
 
 	override function logImpl( str : String ) {
-		//d.logImpl(str);
 		ops.push(Log(str));
 	}
 
@@ -91,15 +114,15 @@ class ScnDriver extends Driver {
 
 
 	override function selectShader( shader : hxsl.RuntimeShader ) {
-		var hasData = savedShaders.get(shader.id);
-		if( hasData )
+		var s = savedShaders.get(shader.id);
+		if( s != null )
 			ops.push(SelectShader(shader.id, null));
 		else {
 			var s = new haxe.Serializer();
 			s.useCache = true;
 			s.serialize(shader);
 			ops.push(SelectShader(shader.id, haxe.io.Bytes.ofString(s.toString())));
-			savedShaders.set(shader.id, true);
+			savedShaders.set(shader.id, shader);
 		}
 		return d.selectShader(shader);
 	}
@@ -130,18 +153,28 @@ class ScnDriver extends Driver {
 	}
 
 	override function selectBuffer( buffer : Buffer ) {
+		ops.push(SelectBuffer(@:privateAccess vertexID(buffer.buffer.vbuf), buffer.flags.has(RawFormat)));
 		d.selectBuffer(buffer);
 	}
 
 	override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
+		var bufs = [];
+		var b = buffers;
+		while( b != null ) {
+			bufs.push( { vbuf : @:privateAccess vertexID(buffers.buffer.buffer.vbuf), offset : b.offset } );
+			b = b.next;
+		}
+		ops.push(SelectMultiBuffer(bufs));
 		d.selectMultiBuffers(buffers);
 	}
 
 	override function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
+		ops.push(Draw(indexID(ibuf), startIndex, ntriangles));
 		d.draw(ibuf, startIndex, ntriangles);
 	}
 
 	override function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
+		ops.push(RenderZone(x, y, width, height));
 		d.setRenderZone(x, y, width, height);
 	}
 
@@ -270,4 +303,151 @@ class ScnDriver extends Driver {
 		ops.push(UploadTexture(t.id, pixels, mipLevel, side));
 	}
 
+	var defTex : h3d.mat.Texture;
+	function defaultTexture() {
+		if( defTex == null || defTex.isDisposed() ) {
+			defTex = new h3d.mat.Texture(1, 1, [NoAlloc]);
+			defTex.t = d.allocTexture(defTex);
+			var pix = new hxd.Pixels(1, 1, haxe.io.Bytes.alloc(4), hxd.PixelFormat.ARGB);
+			pix.setPixel(0, 0, 0xFFFFFF00);
+			d.uploadTexturePixels(defTex, pix, 0, 0);
+		}
+		return defTex;
+	}
+
+	@:access(h3d.impl.ManagedBuffer)
+	public function replay( op : Operation ) {
+		switch( op ) {
+		case Log(str):
+			d.log(str);
+		case Begin:
+			d.begin(++frame);
+		case Clear(color, depth, stencil):
+			d.clear(color,depth,stencil);
+		case Reset:
+			d.reset();
+		case Resize(w, h):
+			d.resize(w,h);
+		case SelectShader(id, data):
+			if( data != null ) {
+				var s : hxsl.RuntimeShader = haxe.Unserializer.run(data.toString());
+				savedShaders.set(id, s);
+			}
+			d.selectShader(savedShaders.get(id));
+		case Material(bits):
+			@:privateAccess tmpPass.bits = bits;
+			d.selectMaterial(tmpPass);
+		case UploadShaderBuffers(globals, vertex, fragment):
+			var b = tmpBuf;
+			if( globals ) {
+				tmpShader.vertex.globalsSize = vertex.length>>2;
+				tmpShader.fragment.globalsSize = fragment.length >> 2;
+				b.grow(tmpShader);
+				for( i in 0...vertex.length )
+					b.vertex.globals[i] = vertex[i];
+				for( i in 0...fragment.length )
+					b.fragment.globals[i] = fragment[i];
+			} else {
+				tmpShader.vertex.paramsSize = vertex.length>>2;
+				tmpShader.fragment.paramsSize = fragment.length>>2;
+				b.grow(tmpShader);
+				for( i in 0...vertex.length )
+					b.vertex.params[i] = vertex[i];
+				for( i in 0...fragment.length )
+					b.fragment.params[i] = fragment[i];
+			}
+			d.uploadShaderBuffers(b, globals ? Globals : Params);
+		case UploadShaderTextures(vertex, fragment):
+			var b = tmpBuf;
+			tmpShader.vertex.textures2DCount = vertex.length;
+			tmpShader.fragment.textures2DCount = fragment.length;
+			b.grow(tmpShader);
+			for( i in 0...vertex.length ) {
+				var t = textureMap.get(vertex[i]);
+				b.vertex.tex[i] = t == null ? defaultTexture() : t;
+			}
+			for( i in 0...fragment.length ) {
+				var t = textureMap.get(fragment[i]);
+				b.fragment.tex[i] = t == null ? defaultTexture() : t;
+			}
+			d.uploadShaderBuffers(b, Textures);
+		case AllocTexture(id, name, width, height, flags):
+			var fl : Array<h3d.mat.Data.TextureFlags> = [NoAlloc];
+			var flbits = flags.toInt();
+			var flcount = 0;
+			while( flbits != 0 ) {
+				if( flbits & 1 != 0 )
+					fl.push(h3d.mat.Data.TextureFlags.createByIndex(flcount));
+				flbits >>>= 1;
+				flcount++;
+			}
+			var t = new h3d.mat.Texture(width, height, fl);
+			t.name = name;
+			t.t = d.allocTexture(t);
+			t.flags.unset(WasCleared);
+			textureMap.set(id, t);
+		case AllocIndexes(id, count):
+			var i = d.allocIndexes(count);
+			indexBuffers[id] = i;
+		case AllocVertexes(id, size, stride, flags):
+			var m = new ManagedBuffer(stride, size, [NoAlloc]);
+			m.flags = flags;
+			m.vbuf = d.allocVertexes(m);
+			vertexBuffers[id] = m;
+		case DisposeTexture(id):
+			var t = textureMap.get(id);
+			if( t != null ) {
+				textureMap.remove(id);
+				d.disposeTexture(t);
+			}
+		case DisposeIndexes(id):
+			var i = indexBuffers[id];
+			if( i != null ) {
+				indexBuffers[id] = null;
+				d.disposeIndexes(i);
+			}
+		case DisposeVertexes(id):
+			var v = vertexBuffers[id];
+			if( v != null ) {
+				vertexBuffers[id] = null;
+				d.disposeVertexes(v.vbuf);
+			}
+		case UploadTexture(id, pixels, mipMap, side):
+			d.uploadTexturePixels(textureMap.get(id), pixels, mipMap, side);
+		case UploadIndexes(id, start, count, data):
+			d.uploadIndexBytes(indexBuffers[id], start, count, data, 0);
+		case UploadVertexes(id, start, count, data):
+			d.uploadVertexBytes(vertexBuffers[id].vbuf, start, count, data, 0);
+		case SelectBuffer(id, raw):
+			var m = vertexBuffers[id];
+			var buf = new h3d.Buffer(0, 0, [NoAlloc]);
+			@:privateAccess buf.buffer = m;
+			if( raw ) buf.flags.set(RawFormat);
+			d.selectBuffer(buf);
+		case SelectMultiBuffer(bufs):
+			var head = null;
+			var cur : h3d.Buffer.BufferOffset = null;
+			for( b in bufs ) {
+				var buf = new h3d.Buffer(0, 0, [NoAlloc]);
+				@:privateAccess buf.buffer = vertexBuffers[b.vbuf];
+				var b = new h3d.Buffer.BufferOffset(buf, b.offset);
+				if( head == null )
+					head = b;
+				else
+					cur.next = b;
+				cur = b;
+			}
+			d.selectMultiBuffers(head);
+		case Draw(indexes, start, ntri):
+			d.draw(indexBuffers[indexes], start, ntri);
+		case RenderZone(x, y, w, h):
+			d.setRenderZone(x, y, w, h);
+		case RenderTarget(tid):
+			var t = textureMap.get(tid);
+			d.setRenderTarget(t);
+		case Present:
+			d.present();
+		}
+	}
+
 }

+ 3 - 1
h3d/mat/Texture.hx

@@ -44,8 +44,10 @@ class Texture {
 	public var realloc : Void -> Void;
 
 	public function new(w, h, ?flags : Array<TextureFlags>, ?allocPos : h3d.impl.AllocPos ) {
+		#if !noEngine
 		var engine = h3d.Engine.getCurrent();
 		this.mem = engine.mem;
+		#end
 		this.id = ++UID;
 		this.flags = new haxe.EnumFlags();
 		if( flags != null )
@@ -71,7 +73,7 @@ class Texture {
 		#if debug
 		this.allocPos = allocPos;
 		#end
-		alloc();
+		if( !this.flags.has(NoAlloc) ) alloc();
 	}
 
 	public function alloc() {

+ 1 - 0
hxd/App.hx

@@ -70,6 +70,7 @@ class App {
 					engine.mem.onContextLost();
 					engine.onContextLost();
 					engine.resize(engine.width, engine.height);
+					engine.render(s3d); // first render to perform allocations
 				}
 			} else if( scnDriver != null ) {
 				engine.setDriver(scnDriver.getDriver());

+ 6 - 1
hxd/fmt/scn/Data.hx

@@ -15,7 +15,7 @@ enum Operation {
 
 	AllocTexture( id : Int, name : String, width : Int, height : Int, flags : haxe.EnumFlags<h3d.mat.Data.TextureFlags> );
 	AllocIndexes( id : Int, count : Int );
-	AllocVertexes( id : Int, stride : Int, count : Int, flags : haxe.EnumFlags<h3d.Buffer.BufferFlag> );
+	AllocVertexes( id : Int, size : Int, stride : Int, flags : haxe.EnumFlags<h3d.Buffer.BufferFlag> );
 	DisposeTexture( id : Int );
 	DisposeIndexes( id : Int );
 	DisposeVertexes( id : Int );
@@ -24,6 +24,11 @@ enum Operation {
 	UploadIndexes( id : Int, start : Int, count : Int, data : haxe.io.Bytes );
 	UploadVertexes( id : Int, start : Int, count : Int, data : haxe.io.Bytes );
 
+	SelectBuffer( id : Int, raw : Bool );
+	SelectMultiBuffer( bufs : Array<{ vbuf:Int, offset : Int }> );
+	Draw( indexes : Int, start : Int, ntri : Int );
+
+	RenderZone( x : Int, y : Int, width : Int, height : Int );
 	RenderTarget( tid : Int );
 	Present;
 }

+ 91 - 0
hxd/fmt/scn/Reader.hx

@@ -0,0 +1,91 @@
+package hxd.fmt.scn;
+import hxd.fmt.scn.Data;
+
+class Reader {
+
+	var i : haxe.io.Input;
+
+	public function new( i : haxe.io.Input ) {
+		this.i = i;
+	}
+
+	public function read() : Data {
+		return {
+			version : i.readByte(),
+			ops : [for( i in 0...i.readInt32() ) readOp()]
+		};
+	}
+
+	function readOp() {
+		var tag = i.readByte();
+		return switch( tag ) {
+		case 0:
+			Log(i.readString(i.readInt32()));
+		case 1:
+			Begin;
+		case 2:
+			var bits = i.readByte();
+			Clear(
+				bits & 1 == 0 ? null : new h3d.Vector(i.readFloat(), i.readFloat(), i.readFloat(), i.readFloat()),
+				bits & 2 == 0 ? null : i.readFloat(),
+				bits & 4 == 0 ? null : i.readInt32()
+			);
+		case 3:
+			Reset;
+		case 4:
+			Resize(i.readInt32(), i.readInt32());
+		case 5:
+			var id = i.readInt32();
+			var len = i.readInt32();
+			SelectShader(id, len == 0 ? null : i.read(len));
+		case 6:
+			Material(i.readInt32());
+		case 7:
+			UploadShaderBuffers(i.readByte() == 1, [for( k in 0...i.readInt32() ) i.readFloat()], [for( k in 0...i.readInt32() ) i.readFloat()]);
+		case 8:
+			UploadShaderTextures([for( k in 0...i.readByte() ) i.readInt32()], [for( k in 0...i.readByte() ) i.readInt32()]);
+		case 9:
+			var id = i.readInt32();
+			var len = i.readInt32();
+			AllocTexture(id, len < 0 ? null : i.readString(len), i.readInt32(), i.readInt32(), haxe.EnumFlags.ofInt(i.readInt32()));
+		case 10:
+			AllocIndexes(i.readInt32(), i.readInt32());
+		case 11:
+			AllocVertexes(i.readInt32(), i.readInt32(), i.readInt32(), haxe.EnumFlags.ofInt(i.readInt32()) );
+		case 12:
+			DisposeTexture(i.readInt32());
+		case 13:
+			DisposeIndexes(i.readInt32());
+		case 14:
+			DisposeVertexes(i.readInt32());
+		case 15:
+			var id = i.readInt32();
+			var w = i.readInt32();
+			var h = i.readInt32();
+			var format = hxd.PixelFormat.createByIndex(i.readInt32());
+			var flags = haxe.EnumFlags.ofInt(i.readInt32());
+			var pixels = new hxd.Pixels(w, h, i.read(w * h * 4), format);
+			pixels.flags = flags;
+			UploadTexture(id, pixels, i.readInt32(), i.readByte());
+		case 16:
+			UploadIndexes(i.readInt32(), i.readInt32(), i.readInt32(), i.read(i.readInt32()) );
+		case 17:
+			UploadVertexes(i.readInt32(), i.readInt32(), i.readInt32(), i.read(i.readInt32()) );
+		case 18:
+			SelectBuffer(i.readInt32(), i.readByte() != 0 );
+		case 19:
+			SelectMultiBuffer([for( k in 0...i.readByte() ) { vbuf : i.readInt32(), offset : i.readByte() } ]);
+		case 20:
+			Draw(i.readInt32(), i.readInt32(), i.readInt32());
+		case 21:
+			RenderZone(i.readInt32(), i.readInt32(), i.readInt32(), i.readInt32());
+		case 22:
+			RenderTarget(i.readInt32());
+		case 23:
+			Present;
+		case x:
+			throw "Invalid SCN tag " + x;
+		}
+	}
+
+}

+ 28 - 3
hxd/fmt/scn/Writer.hx

@@ -11,6 +11,7 @@ class Writer {
 
 	public function write( d : Data ) {
 		out.addByte(d.version);
+		out.addInt32(d.ops.length);
 		for( op in d.ops ) {
 			out.addByte(op.getIndex());
 			switch( op ) {
@@ -35,7 +36,11 @@ class Writer {
 				out.addInt32(h);
 			case SelectShader(id, data):
 				out.addInt32(id);
-				if( data != null ) out.addBytes(data, 0, data.length);
+				if( data != null ) {
+					out.addInt32(data.length);
+					out.addBytes(data, 0, data.length);
+				} else
+					out.addInt32(0);
 			case Material(bits):
 				out.addInt32(bits);
 			case UploadShaderTextures(vertex, fragment):
@@ -67,10 +72,10 @@ class Writer {
 			case AllocIndexes(id, count):
 				out.addInt32(id);
 				out.addInt32(count);
-			case AllocVertexes(id, stride, count, flags):
+			case AllocVertexes(id, size, stride, flags):
 				out.addInt32(id);
+				out.addInt32(size);
 				out.addInt32(stride);
-				out.addInt32(count);
 				out.addInt32(flags.toInt());
 			case UploadTexture(id, pixels, mipMap, side):
 				out.addInt32(id);
@@ -79,6 +84,8 @@ class Writer {
 				out.addInt32(pixels.format.getIndex());
 				out.addInt32(pixels.flags.toInt());
 				out.add(pixels.bytes);
+				out.addInt32(mipMap);
+				out.addByte(side);
 			case UploadVertexes(id, start, count, data):
 				out.addInt32(id);
 				out.addInt32(start);
@@ -93,6 +100,24 @@ class Writer {
 				out.add(data);
 			case RenderTarget(id), DisposeIndexes(id), DisposeTexture(id), DisposeVertexes(id):
 				out.addInt32(id);
+			case SelectBuffer(id, raw):
+				out.addInt32(id);
+				out.addByte(raw?1:0);
+			case SelectMultiBuffer(bufs):
+				out.addByte(bufs.length);
+				for( b in bufs ) {
+					out.addInt32(b.vbuf);
+					out.addByte(b.offset);
+				}
+			case RenderZone(x, y, w, h):
+				out.addInt32(x);
+				out.addInt32(y);
+				out.addInt32(w);
+				out.addInt32(h);
+			case Draw(id, start, count):
+				out.addInt32(id);
+				out.addInt32(start);
+				out.addInt32(count);
 			}
 		}
 		return out.getBytes();