Explorar o código

added correct texture format support
added Driver.isSupportedFormat

Nicolas Cannasse %!s(int64=9) %!d(string=hai) anos
pai
achega
abbf0c9dc1

+ 8 - 4
h3d/impl/Driver.hx

@@ -7,19 +7,19 @@ 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 = { t : js.html.webgl.Texture, width : Int, height : Int, fmt : Int, ?fb : js.html.webgl.Framebuffer, ?rb : js.html.webgl.Renderbuffer };
+typedef Texture = { t : js.html.webgl.Texture, width : Int, height : Int, internalFmt : Int, pixelFmt : Int, ?fb : js.html.webgl.Framebuffer, ?rb : js.html.webgl.Renderbuffer };
 #elseif nme
 typedef IndexBuffer = nme.gl.GLBuffer;
 typedef VertexBuffer = { b : nme.gl.GLBuffer, stride : Int };
-typedef Texture = { t : nme.gl.GLTexture, width : Int, height : Int, fmt : Int, ?fb : nme.gl.GLFramebuffer, ?rb : nme.gl.GLRenderbuffer };
+typedef Texture = { t : nme.gl.GLTexture, width : Int, height : Int, internalFmt : Int, pixelFmt : Int, ?fb : nme.gl.GLFramebuffer, ?rb : nme.gl.GLRenderbuffer };
 #elseif lime
 typedef IndexBuffer = lime.graphics.opengl.GLBuffer;
 typedef VertexBuffer = { b : lime.graphics.opengl.GLBuffer, stride : Int };
-typedef Texture = { t : lime.graphics.opengl.GLTexture, width : Int, height : Int, fmt : Int, ?fb : lime.graphics.opengl.GLFramebuffer, ?rb : lime.graphics.opengl.GLRenderbuffer };
+typedef Texture = { t : lime.graphics.opengl.GLTexture, width : Int, height : Int, internalFmt : Int, pixelFmt : Int, ?fb : lime.graphics.opengl.GLFramebuffer, ?rb : lime.graphics.opengl.GLRenderbuffer };
 #elseif hxsdl
 typedef IndexBuffer = sdl.GL.Buffer;
 typedef VertexBuffer = { b : sdl.GL.Buffer, stride : Int };
-typedef Texture = { t : sdl.GL.Texture, width : Int, height : Int, fmt : Int, ?fb : sdl.GL.Framebuffer, ?rb : sdl.GL.Renderbuffer };
+typedef Texture = { t : sdl.GL.Texture, width : Int, height : Int, internalFmt : Int, pixelFmt : Int, ?fb : sdl.GL.Framebuffer, ?rb : sdl.GL.Renderbuffer };
 #else
 typedef IndexBuffer = Int;
 typedef VertexBuffer = Int;
@@ -66,6 +66,10 @@ class Driver {
 		return false;
 	}
 
+	public function isSupportedFormat( fmt : h3d.mat.Data.TextureFormat ) {
+		return false;
+	}
+
 	public function isDisposed() {
 		return true;
 	}

+ 45 - 29
h3d/impl/GlDriver.hx

@@ -371,26 +371,41 @@ class GlDriver extends Driver {
 		gl.viewport(0, 0, width, height);
 	}
 
+	function getChannels( t : Texture ) {
+		return switch( t.internalFmt ) {
+		case GL.RGBA: GL.RGBA;
+		default: throw "Invalid format " + t.internalFmt;
+		}
+	}
+
+	override function isSupportedFormat( fmt : h3d.mat.Data.TextureFormat ) {
+		return switch( fmt ) {
+		case RGBA: true;
+		case RGBA32F: hasFeature(FloatTextures);
+		default: false;
+		}
+	}
+
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
 		if( t.flags.has(TargetUseDefaultDepth) )
 			throw "TargetUseDefaultDepth not supported in GL";
 		var tt = gl.createTexture();
-		var tt : Texture = { t : tt, width : t.width, height : t.height, fmt : GL.UNSIGNED_BYTE };
-		if( t.flags.has(FmtFloat) )
-			tt.fmt = GL.FLOAT;
-		else if( t.flags.has(Fmt5_5_5_1) )
-			tt.fmt = GL.UNSIGNED_SHORT_5_5_5_1;
-		else if( t.flags.has(Fmt5_6_5) )
-			tt.fmt = GL.UNSIGNED_SHORT_5_6_5;
-		else if( t.flags.has(Fmt4_4_4_4) )
-			tt.fmt = GL.UNSIGNED_SHORT_4_4_4_4;
+		var tt : Texture = { t : tt, width : t.width, height : t.height, internalFmt : GL.RGBA, pixelFmt : GL.UNSIGNED_BYTE };
+		switch( t.format ) {
+		case RGBA:
+			// default
+		case RGBA32F if( hasFeature(FloatTextures) ):
+			tt.pixelFmt = GL.FLOAT;
+		default:
+			throw "Unsupported texture format "+t.format;
+		}
 		t.lastFrame = frame;
 		t.flags.unset(WasCleared);
 		gl.bindTexture(GL.TEXTURE_2D, tt.t);
 		var mipMap = t.flags.has(MipMapped) ? GL.LINEAR_MIPMAP_NEAREST : GL.LINEAR;
 		gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, mipMap);
 		gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, mipMap);
-		gl.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, tt.width, tt.height, 0, GL.RGBA, tt.fmt, null);
+		gl.texImage2D(GL.TEXTURE_2D, 0, tt.internalFmt, tt.width, tt.height, 0, getChannels(tt), tt.pixelFmt, null);
 		if( t.flags.has(Target) ) {
 			var fb = gl.createFramebuffer();
 			gl.bindFramebuffer(GL.FRAMEBUFFER, fb);
@@ -458,38 +473,39 @@ class GlDriver extends Driver {
 	}
 
 	override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
-		#if nme
+		#if (nme || hxsdl)
 		var pixels = bmp.getPixels();
 		uploadTexturePixels(t, pixels, mipLevel, side);
 		pixels.dispose();
 		#else
-		var img = bmp.toNative();
-		gl.bindTexture(GL.TEXTURE_2D, t.t.t);
-		#if hxsdl
-		var pixels = bmp.getPixels();
-		pixels.setFlip(true);
-		gl.texImage2D(GL.TEXTURE_2D, mipLevel, GL.RGBA, bmp.width, bmp.height, 0, GL.RGBA, GL.UNSIGNED_BYTE, pixels.bytes.getData());
-		pixels.dispose();
-		#elseif lime
-		gl.texImage2D(GL.TEXTURE_2D, mipLevel, GL.RGBA, bmp.width, bmp.height, 0, GL.RGBA, GL.UNSIGNED_BYTE, img.image.data);
-		#else
-		gl.texImage2D(GL.TEXTURE_2D, mipLevel, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, img.getImageData(0, 0, bmp.width, bmp.height));
-		#end
-		if( t.flags.has(MipMapped) ) gl.generateMipmap(GL.TEXTURE_2D);
-		gl.bindTexture(GL.TEXTURE_2D, null);
+		if( t.format != RGBA ) {
+			var pixels = bmp.getPixels();
+			uploadTexturePixels(t, pixels, mipLevel, side);
+			pixels.dispose();
+		} else {
+			var img = bmp.toNative();
+			gl.bindTexture(GL.TEXTURE_2D, t.t.t);
+			#if lime
+			gl.texImage2D(GL.TEXTURE_2D, mipLevel, t.t.internalFmt, bmp.width, bmp.height, 0, getChannels(t.t), t.pixelFmt, img.image.data);
+			#else
+			gl.texImage2D(GL.TEXTURE_2D, mipLevel, t.t.internalFmt, getChannels(t.t), t.t.pixelFmt, img.getImageData(0, 0, bmp.width, bmp.height));
+			#end
+			if( t.flags.has(MipMapped) ) gl.generateMipmap(GL.TEXTURE_2D);
+			gl.bindTexture(GL.TEXTURE_2D, null);
+			t.flags.set(WasCleared);
+		}
 		#end
-		t.flags.set(WasCleared);
 	}
 
 	override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
 		gl.bindTexture(GL.TEXTURE_2D, t.t.t);
-		pixels.convert(RGBA);
+		pixels.convert(t.format);
 		#if hxsdl
 		pixels.setFlip(true);
-		gl.texImage2D(GL.TEXTURE_2D, mipLevel, GL.RGBA, t.width, t.height, 0, GL.RGBA, GL.UNSIGNED_BYTE, pixels.bytes.getData());
+		gl.texImage2D(GL.TEXTURE_2D, mipLevel, t.t.internalFmt, t.width, t.height, 0, getChannels(t.t), t.t.pixelFmt, pixels.bytes.getData());
 		#else
 		var pixels = new Uint8Array(pixels.bytes.getData());
-		gl.texImage2D(GL.TEXTURE_2D, mipLevel, GL.RGBA, t.width, t.height, 0, GL.RGBA, GL.UNSIGNED_BYTE, pixels);
+		gl.texImage2D(GL.TEXTURE_2D, mipLevel, t.t.internalFmt, t.width, t.height, 0, getChannels(t.t), t.t.pixelFmt, pixels);
 		#end
 		if( t.flags.has(MipMapped) ) gl.generateMipmap(GL.TEXTURE_2D);
 		gl.bindTexture(GL.TEXTURE_2D, null);

+ 4 - 0
h3d/impl/LogDriver.hx

@@ -25,6 +25,10 @@ class LogDriver extends Driver {
 		return d.hasFeature(f);
 	}
 
+	override function isSupportedFormat( fmt : h3d.mat.Data.TextureFormat ) {
+		return d.isSupportedFormat(fmt);
+	}
+
 	override function isDisposed() {
 		return d.isDisposed();
 	}

+ 4 - 0
h3d/impl/ScnDriver.hx

@@ -72,6 +72,10 @@ class ScnDriver extends Driver {
 		return d.hasFeature(f);
 	}
 
+	override function isSupportedFormat( fmt ) {
+		return d.isSupportedFormat(fmt);
+	}
+
 	override function isDisposed() {
 		return d.isDisposed();
 	}

+ 13 - 1
h3d/impl/Stage3dDriver.hx

@@ -254,10 +254,22 @@ class Stage3dDriver extends Driver {
 		return levels;
 	}
 
+	override function isSupportedFormat( fmt : h3d.mat.Data.TextureFormat ) {
+		return switch( fmt ) {
+		case BGRA: true;
+		case RGBA16F: true;
+		default: false;
+		}
+	}
+
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
 		if( t.flags.has(TargetDepth) )
 			throw "TargetDepth not supported in Stage3D";
-		var fmt = flash.display3D.Context3DTextureFormat.BGRA;
+		var fmt = switch( t.format ) {
+		case BGRA: flash.display3D.Context3DTextureFormat.BGRA;
+		case RGBA16F: flash.display3D.Context3DTextureFormat.RGBA_HALF_FLOAT;
+		default: throw "Unsupported texture format " + t.format;
+		}
 		t.lastFrame = frame;
 		t.flags.unset(WasCleared);
 		try {

+ 1 - 16
h3d/mat/Data.hx

@@ -93,22 +93,6 @@ enum TextureFlags {
 		Inform that we will often perform upload operations on this texture
 	**/
 	Dynamic;
-	/**
-		The texture format will contain Float values
-	**/
-	FmtFloat;
-	/**
-		16-bit RGB format
-	**/
-	Fmt5_6_5;
-	/**
-		16-bit RGBA format
-	**/
-	Fmt4_4_4_4;
-	/**
-		16-bit RGBA format (1 bit of alpha)
-	**/
-	Fmt5_5_5_1;
 	/**
 		Assumes that the color value of the texture is premultiplied by the alpha component.
 	**/
@@ -119,4 +103,5 @@ enum TextureFlags {
 	WasCleared;
 }
 
+typedef TextureFormat = hxd.PixelFormat;
 

+ 10 - 6
h3d/mat/Texture.hx

@@ -7,14 +7,15 @@ class Texture {
 	static var UID = 0;
 
 	/**
-		The preferred native format that the Driver will process faster.
+		The default texture color format
 	**/
-	public static var nativeFormat(default,never) : hxd.PixelFormat =
+	public static var nativeFormat(default,never) : TextureFormat =
 		#if flash
-			BGRA;
+			BGRA
 		#else
-			RGBA; // OpenGL
-		#end
+			RGBA // OpenGL, WebGL
+		#end;
+
 	/**
 		Tells if the Driver requires y-flipping the texture pixels before uploading.
 	**/
@@ -30,6 +31,7 @@ class Texture {
 	public var width(default, null) : Int;
 	public var height(default, null) : Int;
 	public var flags(default, null) : haxe.EnumFlags<TextureFlags>;
+	public var format(default, null) : TextureFormat;
 
 	var lastFrame : Int;
 	var bits : Int;
@@ -43,12 +45,14 @@ class Texture {
 	**/
 	public var realloc : Void -> Void;
 
-	public function new(w, h, ?flags : Array<TextureFlags>, ?allocPos : h3d.impl.AllocPos ) {
+	public function new(w, h, ?flags : Array<TextureFlags>, ?format : TextureFormat, ?allocPos : h3d.impl.AllocPos ) {
 		#if !noEngine
 		var engine = h3d.Engine.getCurrent();
 		this.mem = engine.mem;
 		#end
+		if( format == null ) format = nativeFormat;
 		this.id = ++UID;
+		this.format = format;
 		this.flags = new haxe.EnumFlags();
 		if( flags != null )
 			for( f in flags )

+ 1 - 1
hxd/BitmapData.hx

@@ -379,7 +379,7 @@ class BitmapData {
 			bytes.endian = flash.utils.Endian.LITTLE_ENDIAN;
 		case ARGB:
 			bytes.endian = flash.utils.Endian.BIG_ENDIAN;
-		case RGBA:
+		default:
 			pixels.convert(BGRA);
 			bytes.endian = flash.utils.Endian.LITTLE_ENDIAN;
 		}

+ 2 - 0
hxd/PixelFormat.hx

@@ -4,4 +4,6 @@ enum PixelFormat {
 	ARGB;
 	BGRA;
 	RGBA;
+	RGBA16F;
+	RGBA32F;
 }

+ 25 - 5
hxd/Pixels.hx

@@ -8,11 +8,12 @@ enum Flags {
 
 class Pixels {
 	public var bytes : haxe.io.Bytes;
-	public var format : PixelFormat;
+	public var format(default,set) : PixelFormat;
 	public var width : Int;
 	public var height : Int;
 	public var offset : Int;
 	public var flags: haxe.EnumFlags<Flags>;
+	var bpp : Int;
 
 	public function new(width : Int, height : Int, bytes : haxe.io.Bytes, format : hxd.PixelFormat, offset = 0) {
 		this.width = width;
@@ -22,6 +23,16 @@ class Pixels {
 		this.offset = offset;
 	}
 
+	function set_format(fmt) {
+		this.format = fmt;
+		bpp = bytesPerPixel(fmt);
+		return fmt;
+	}
+
+	function invalidFormat() {
+		throw "Unsupported format for this operation : " + format;
+	}
+
 	public function clear( color : Int ) {
 		var a, b, c, d;
 		switch( format ) {
@@ -40,6 +51,8 @@ class Pixels {
 			b = color >> 8;
 			c = color >> 16;
 			d = color >>> 24;
+		default:
+			invalidFormat();
 		}
 		a &= 0xFF;
 		b &= 0xFF;
@@ -93,7 +106,7 @@ class Pixels {
 		if( flags.has(FlipY) == b ) return;
 		if( flags.has(ReadOnly) ) copyInner();
 		if( b ) flags.set(FlipY) else flags.unset(FlipY);
-		var stride = width * bytesPerPixel(format);
+		var stride = width * bpp;
 		for( y in 0...height >> 1 ) {
 			var p1 = y * stride;
 			var p2 = (height - 1 - y) * stride;
@@ -161,20 +174,23 @@ class Pixels {
 
 	public function getPixel(x, y) : Int {
 		if( flags.has(FlipY) ) y = height - 1 - y;
-		var p = ((x + y * width) << 2) + offset;
+		var p = ((x + y * width) * bpp) + offset;
 		switch(format) {
 		case BGRA:
 			return bytes.get(p) | (bytes.get( p+1 )<<8) | (bytes.get( p+2 )<<16) | (bytes.get( p+3 )<<24);
 		case RGBA:
 			return (bytes.get(p)<<16) | (bytes.get( p+1 )<<8) | bytes.get( p+2 ) | (bytes.get( p+3 )<<24);
 		case ARGB:
-			return (bytes.get(p)<<24) | (bytes.get( p+1 )<<16) | (bytes.get( p+2 )<<8) | bytes.get( p+3 );
+			return (bytes.get(p) << 24) | (bytes.get( p + 1 ) << 16) | (bytes.get( p + 2 ) << 8) | bytes.get( p + 3 );
+		default:
+			invalidFormat();
+			return 0;
 		}
 	}
 
 	public function setPixel(x, y, color) : Void {
 		if( flags.has(FlipY) ) y = height - 1 - y;
-		var p = ((x + y * width) << 2) + offset;
+		var p = ((x + y * width) * bpp) + offset;
 		var a = color >>> 24;
 		var r = (color >> 16) & 0xFF;
 		var g = (color >> 8) & 0xFF;
@@ -195,6 +211,8 @@ class Pixels {
 			bytes.set(p++, r);
 			bytes.set(p++, g);
 			bytes.set(p++, b);
+		default:
+			invalidFormat();
 		}
 	}
 
@@ -234,6 +252,8 @@ class Pixels {
 	public static function bytesPerPixel( format : PixelFormat ) {
 		return switch( format ) {
 		case ARGB, BGRA, RGBA: 4;
+		case RGBA16F: 8;
+		case RGBA32F: 16;
 		}
 	}