Bläddra i källkod

moved capturePixels from Texture to Driver (allow capture in directX even if not render target)

ncannasse 7 år sedan
förälder
incheckning
96420f0d15
5 ändrade filer med 110 tillägg och 100 borttagningar
  1. 33 24
      h3d/impl/DirectXDriver.hx
  2. 5 0
      h3d/impl/Driver.hx
  3. 40 15
      h3d/impl/GlDriver.hx
  4. 31 60
      h3d/mat/Texture.hx
  5. 1 1
      samples/GraphicsDraw.hx

+ 33 - 24
h3d/impl/DirectXDriver.hx

@@ -251,30 +251,7 @@ class DirectXDriver extends h3d.impl.Driver {
 		var rt = curTexture;
 		if( rt == null )
 			throw "Can't capture main render buffer in DirectX";
-
-		var desc = new Texture2dDesc();
-		desc.width = rt.width;
-		desc.height = rt.height;
-		desc.access = CpuRead | CpuWrite;
-		desc.usage = Staging;
-		desc.format = getTextureFormat(rt);
-		var tmp = dx.Driver.createTexture2d(desc);
-		if( tmp == null )
-			throw "Capture failed: can't create tmp texture";
-
-		tmp.copyResource(rt.t.res);
-
-		var pitch = 0;
-		var ptr = tmp.map(0, Read, true, pitch);
-		if( pitch == desc.width * 4 )
-			@:privateAccess pixels.bytes.b.blit(0, ptr, 0, desc.width * desc.height * 4);
-		else {
-			for( i in 0...desc.height )
-				@:privateAccess pixels.bytes.b.blit(i * desc.width * 4, ptr, i * pitch, desc.width * 4);
-		}
-
-		tmp.unmap(0);
-		tmp.release();
+		captureTexPixels(pixels, rt, 0, 0);
 	}
 
 	function getTextureFormat( t : h3d.mat.Texture ) : dx.Format {
@@ -413,6 +390,38 @@ class DirectXDriver extends h3d.impl.Driver {
 		tmp.release();
 	}
 
+	override function capturePixels(tex:h3d.mat.Texture, face:Int, mipLevel:Int) : hxd.Pixels {
+		var pixels = hxd.Pixels.alloc(tex.width >> mipLevel, tex.height >> mipLevel, tex.format);
+		captureTexPixels(pixels, tex, face, mipLevel);
+		return pixels;
+	}
+
+	function captureTexPixels( pixels: hxd.Pixels, tex:h3d.mat.Texture, face:Int, mipLevel:Int)  {
+		var desc = new Texture2dDesc();
+		desc.width = pixels.width;
+		desc.height = pixels.height;
+		desc.access = CpuRead | CpuWrite;
+		desc.usage = Staging;
+		desc.format = getTextureFormat(tex);
+		var tmp = dx.Driver.createTexture2d(desc);
+		if( tmp == null )
+			throw "Capture failed: can't create tmp texture";
+
+		tmp.copySubresourceRegion(0,0,0,0,tex.t.res,tex.t.mips * face + mipLevel, null);
+
+		var pitch = 0;
+		var ptr = tmp.map(0, Read, true, pitch);
+		if( pitch == desc.width * 4 )
+			@:privateAccess pixels.bytes.b.blit(0, ptr, 0, desc.width * desc.height * 4);
+		else {
+			for( i in 0...desc.height )
+				@:privateAccess pixels.bytes.b.blit(i * desc.width * 4, ptr, i * pitch, desc.width * 4);
+		}
+		tmp.unmap(0);
+		tmp.release();
+		return pixels;
+	}
+
 	override function uploadTextureBitmap(t:h3d.mat.Texture, bmp:hxd.BitmapData, mipLevel:Int, side:Int) {
 		var pixels = bmp.getPixels();
 		uploadTexturePixels(t, pixels, mipLevel, side);

+ 5 - 0
h3d/impl/Driver.hx

@@ -135,6 +135,11 @@ class Driver {
 	public function captureRenderBuffer( pixels : hxd.Pixels ) {
 	}
 
+	public function capturePixels( tex : h3d.mat.Texture, face : Int, mipLevel : Int ) : hxd.Pixels {
+		throw "Can't capture pixels on this platform";
+		return null;
+	}
+
 	public function getDriverName( details : Bool ) {
 		return "Not available";
 	}

+ 40 - 15
h3d/impl/GlDriver.hx

@@ -132,6 +132,8 @@ class GlDriver extends Driver {
 	var bufferHeight : Int;
 	var curTarget : h3d.mat.Texture;
 	var numTargets : Int;
+	var curTargetFace : Int;
+	var curTargetMip : Int;
 
 	var debug : Bool;
 	var boundTextures : Array<Texture> = [];
@@ -1025,19 +1027,40 @@ class GlDriver extends Driver {
 		}
 	}
 
+	function setDrawBuffers( k : Int ) {
+		#if js
+		if( mrtExt != null )
+			mrtExt.drawBuffersWEBGL(CBUFFERS[k]);
+		#elseif (hlsdl || usegl)
+		gl.drawBuffers(k, CBUFFERS);
+		#end
+	}
+
 	inline function unbindTargets() {
 		if( curTarget != null && numTargets > 1 ) {
 			while( numTargets > 1 )
 				gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0 + (--numTargets), GL.TEXTURE_2D, null, 0);
-			#if js
-			if( mrtExt != null )
-				mrtExt.drawBuffersWEBGL([GL.COLOR_ATTACHMENT0]);
-			#elseif (hlsdl || usegl)
-			gl.drawBuffers(1, CBUFFERS);
-			#end
+			setDrawBuffers(1);
 		}
 	}
 
+	override function capturePixels(tex:h3d.mat.Texture, face:Int, mipLevel:Int) {
+		var old = curTarget;
+		var oldCount = numTargets;
+		var oldFace = curTargetFace;
+		var oldMip = curTargetMip;
+		numTargets = 1;
+		setRenderTarget(tex, face, mipLevel);
+		var pixels = hxd.Pixels.alloc(tex.width >> mipLevel, tex.height >> mipLevel, RGBA);
+		captureRenderBuffer(pixels);
+		setRenderTarget(old, oldFace, oldMip);
+		if( oldCount > 1 ) {
+			setDrawBuffers(oldCount);
+			numTargets = oldCount;
+		}
+		return pixels;
+	}
+
 	override function setRenderTarget( tex : h3d.mat.Texture, face = 0, mipLevel = 0 ) {
 		unbindTargets();
 		curTarget = tex;
@@ -1061,6 +1084,8 @@ class GlDriver extends Driver {
 
 		tex.flags.set(WasCleared); // once we draw to, do not clear again
 		tex.lastFrame = frame;
+		curTargetFace = face;
+		curTargetMip = mipLevel;
 		gl.bindFramebuffer(GL.FRAMEBUFFER, commonFB);
 		gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, tex.flags.has(Cube) ? CUBE_FACES[face] : GL.TEXTURE_2D, tex.t.t, mipLevel);
 		if( tex.depthBuffer != null )
@@ -1086,12 +1111,7 @@ class GlDriver extends Driver {
 			tex.lastFrame = frame;
 			tex.flags.set(WasCleared); // once we draw to, do not clear again
 		}
-		#if js
-		if( mrtExt != null )
-			mrtExt.drawBuffersWEBGL([for( i in 0...textures.length ) GL.COLOR_ATTACHMENT0 + i]);
-		#elseif (hlsdl || usegl)
-			gl.drawBuffers(textures.length, CBUFFERS);
-		#end
+		setDrawBuffers(textures.length);
 	}
 
 	override function init( onCreate : Bool -> Void, forceSoftware = false ) {
@@ -1260,9 +1280,14 @@ class GlDriver extends Driver {
 		GL.TEXTURE_CUBE_MAP_NEGATIVE_Z,
 	];
 
-	#if (hlsdl || usegl)
-	static var CBUFFERS = hl.Bytes.getArray([for( i in 0...32 ) GL.COLOR_ATTACHMENT0 + i]);
-	#end
+	static var CBUFFERS =
+		#if (hlsdl || usegl)
+			hl.Bytes.getArray([for( i in 0...32 ) GL.COLOR_ATTACHMENT0 + i]);
+		#elseif js
+			[for( i in 0...32 ) [for( k in 0...i ) GL.COLOR_ATTACHMENT0 + k]];
+		#else
+			null;
+		#end
 
 }
 

+ 31 - 60
h3d/mat/Texture.hx

@@ -257,14 +257,22 @@ class Texture {
 		Downloads the current texture data from the GPU.
 		Beware, this is a very slow operation that shouldn't be done during rendering.
 	**/
-	public function capturePixels( face = 0, mipLevel = 0 ) {
+	public function capturePixels( face = 0, mipLevel = 0 ) : hxd.Pixels {
 		#if flash
+		if( flags.has(Cube) ) throw "Can't capture cube texture on this platform";
+		if( face != 0 || mipLevel != 0 ) throw "Can't capture face/mipLevel on this platform";
+		return capturePixelsFlash();
+		#else
+		var old = lastFrame;
+		preventAutoDispose();
+		var pix = mem.driver.capturePixels(this, face, mipLevel);
+		lastFrame = old;
+		return pix;
+		#end
+	}
 
-		if( face != 0 || mipLevel != 0 )
-			throw "Can't capture face/mipLevel";
-
-		var twoPassCapture = true;
-
+	#if flash
+	function capturePixelsFlash() {
 		var e = h3d.Engine.getCurrent();
 		var oldW = e.width, oldH = e.height;
 		var oldF = filter, oldM = mipMap, oldWrap = wrap;
@@ -273,11 +281,8 @@ class Texture {
 		e.driver.clear(new h3d.Vector(0, 0, 0, 0),1,0);
 		var s2d = new h2d.Scene();
 		var b = new h2d.Bitmap(h2d.Tile.fromTexture(this), s2d);
-		var shader = null;
-		if( twoPassCapture ) {
-			shader = new h3d.shader.AlphaChannel();
-			b.addShader(shader); // erase alpha
-		}
+		var shader = new h3d.shader.AlphaChannel();
+		b.addShader(shader); // erase alpha
 		b.blendMode = None;
 
 		mipMap = None;
@@ -287,24 +292,22 @@ class Texture {
 		var pixels = hxd.Pixels.alloc(width, height, ARGB);
 		e.driver.captureRenderBuffer(pixels);
 
-		if( twoPassCapture ) {
-			shader.showAlpha = true;
-			s2d.render(e); // render only alpha channel
-			var alpha = hxd.Pixels.alloc(width, height, ARGB);
-			e.driver.captureRenderBuffer(alpha);
-			var alphaPos = hxd.Pixels.getChannelOffset(alpha.format, A);
-			var redPos = hxd.Pixels.getChannelOffset(alpha.format, R);
-			var bpp = hxd.Pixels.bytesPerPixel(alpha.format);
-			for( y in 0...height ) {
-				var p = y * width * bpp;
-				for( x in 0...width ) {
-					pixels.bytes.set(p + alphaPos, alpha.bytes.get(p + redPos)); // copy alpha value only
-					p += bpp;
-				}
+		shader.showAlpha = true;
+		s2d.render(e); // render only alpha channel
+		var alpha = hxd.Pixels.alloc(width, height, ARGB);
+		e.driver.captureRenderBuffer(alpha);
+		var alphaPos = hxd.Pixels.getChannelOffset(alpha.format, A);
+		var redPos = hxd.Pixels.getChannelOffset(alpha.format, R);
+		var bpp = hxd.Pixels.bytesPerPixel(alpha.format);
+		for( y in 0...height ) {
+			var p = y * width * bpp;
+			for( x in 0...width ) {
+				pixels.bytes.set(p + alphaPos, alpha.bytes.get(p + redPos)); // copy alpha value only
+				p += bpp;
 			}
-			alpha.dispose();
-			pixels.flags.unset(AlphaPremultiplied);
 		}
+		alpha.dispose();
+		pixels.flags.unset(AlphaPremultiplied);
 
 		if( e.width != oldW || e.height != oldH )
 			e.resize(oldW, oldH);
@@ -314,41 +317,9 @@ class Texture {
 		filter = oldF;
 		mipMap = oldM;
 		wrap = oldWrap;
-
-		#else
-
-		var e = h3d.Engine.getCurrent();
-		e.pushTarget(this, face, mipLevel);
-		@:privateAccess e.flushTarget();
-		var pixels = hxd.Pixels.alloc(width, height, RGBA);
-		e.driver.captureRenderBuffer(pixels);
-		e.popTarget();
-
-		#end
 		return pixels;
 	}
-
-	/*
-
-		// Seems unreliable on flash, not sure why...
-		// eg :
-		//    var t = hxd.Res.tex1.toTexture();
-		//	  t.onLoaded = function() { var s = hxd.Res.tex2.toTexture(); s.onLoaded = function() t.setChannel(A,s,R); }
-		// using setChannel here will clear the texture, for no known reason
-
-	public function setChannel( c : hxd.Pixels.Channel, with : h3d.mat.Texture, ?srcChannel : hxd.Pixels.Channel ) {
-		if( t == null || with.t == null )
-			throw "Can't set disposed or loading texture";
-		var pass = new h3d.mat.Pass("");
-		pass.colorMask = 1 << c.toInt();
-		pass.depth(false, Always);
-		pass.culling = None;
-		if( srcChannel != null && srcChannel != c )
-			pass.addShader(new h3d.shader.ChannelSelect(srcChannel.toInt()));
-		h3d.pass.Copy.run(with, this, null, pass);
-	}
-
-	*/
+	#end
 
 	public static function fromBitmap( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {
 		var t = new Texture(bmp.width, bmp.height, allocPos);

+ 1 - 1
samples/GraphicsDraw.hx

@@ -86,7 +86,7 @@ class GraphicsDraw extends hxd.App {
 		}
 		pg.drawTo(t);
 
-		var pix = t.capturePixels(true);
+		var pix = t.capturePixels();
 		bclone.tile.getTexture().uploadPixels(pix);
 		pix.dispose();
 	}