Pārlūkot izejas kodu

renamed Sprite.filters to filter (not an array - use h2d.filter.Group for multifilters)
renamed Drawable.filter to smooth (more accurate)

ncannasse 8 gadi atpakaļ
vecāks
revīzija
5f1437eb97

+ 1 - 1
all.hxml

@@ -5,7 +5,7 @@
 --macro include('h3d')
 --macro include('h3d')
 --macro include('h2d')
 --macro include('h2d')
 --macro include('hxsl',true,['hxsl.Macros'])
 --macro include('hxsl',true,['hxsl.Macros'])
---macro include('hxd',true,['hxd.res.FileTree','hxd.Res','hxd.impl.BitsBuilder','hxd.impl.Air3File','hxd.fmt.pak.Build','hxd.fmt.hmd.MakeAll','hxd.impl.LimeStage','hxd.fs.LimeFileSystem'])
+--macro include('hxd',true,['hxd.res.FileTree','hxd.Res','hxd.impl.BitsBuilder','hxd.impl.Air3File','hxd.fmt.pak.Build','hxd.fmt.hmd.MakeAll','hxd.impl.LimeStage','hxd.fs.LimeFileSystem','hxd.net.SteamHost'])
 --no-output
 --no-output
 --each
 --each
 
 

+ 1 - 1
h2d/Drawable.hx

@@ -4,7 +4,7 @@ class Drawable extends Sprite {
 
 
 	public var color(default,null) : h3d.Vector;
 	public var color(default,null) : h3d.Vector;
 	public var blendMode : BlendMode;
 	public var blendMode : BlendMode;
-	public var filter : Null<Bool>;
+	public var smooth : Null<Bool>;
 	public var tileWrap(default, set) : Bool;
 	public var tileWrap(default, set) : Bool;
 	public var colorKey(default, set) : Null<Int>;
 	public var colorKey(default, set) : Null<Int>;
 	public var colorMatrix(get, set) : Null<h3d.Matrix>;
 	public var colorMatrix(get, set) : Null<h3d.Matrix>;

+ 8 - 3
h2d/Dropdown.hx

@@ -35,7 +35,7 @@ class Dropdown extends Flow {
 	var fake : Fake;
 	var fake : Fake;
 	var cursor : h2d.Bitmap;
 	var cursor : h2d.Bitmap;
 
 
-	public var canEdit : Bool = true;
+	public var canEdit(default,set) : Bool = true;
 	public var dropdownCursor(get,set) : h2d.Tile;
 	public var dropdownCursor(get,set) : h2d.Tile;
 	public var dropdownList : Flow;
 	public var dropdownList : Flow;
 	public var dropdownLayer : Int = -1;
 	public var dropdownLayer : Int = -1;
@@ -59,13 +59,13 @@ class Dropdown extends Flow {
 		enableInteractive = true;
 		enableInteractive = true;
 
 
 		interactive.onPush = function(e:hxd.Event) {
 		interactive.onPush = function(e:hxd.Event) {
-			if( e.button == 0 )
+			if( e.button == 0 && canEdit )
 				interactive.focus();
 				interactive.focus();
 		}
 		}
 		interactive.onClick = function(e) {
 		interactive.onClick = function(e) {
 			if (dropdownList.allocated) {
 			if (dropdownList.allocated) {
 				close();
 				close();
-			} else {
+			} else if( canEdit ) {
 				var bds = this.getBounds();
 				var bds = this.getBounds();
 				dropdownList.y = bds.yMax;
 				dropdownList.y = bds.yMax;
 				dropdownList.x = bds.xMin;
 				dropdownList.x = bds.xMin;
@@ -126,6 +126,11 @@ class Dropdown extends Flow {
 		minWidth = width;
 		minWidth = width;
 	}
 	}
 
 
+	function set_canEdit(b) {
+		if( !b ) close();
+		return canEdit = b;
+	}
+
 	function set_selectedItem(s) {
 	function set_selectedItem(s) {
 		if (s < 0) {
 		if (s < 0) {
 			return selectedItem = -1;
 			return selectedItem = -1;

+ 2 - 2
h2d/RenderContext.hx

@@ -9,7 +9,7 @@ class RenderContext extends h3d.impl.RenderContext {
 	public var bufPos : Int;
 	public var bufPos : Int;
 	public var textures : h3d.impl.TextureCache;
 	public var textures : h3d.impl.TextureCache;
 	public var scene : h2d.Scene;
 	public var scene : h2d.Scene;
-	public var defaultFilter : Bool = false;
+	public var defaultSmooth : Bool = false;
 	public var killAlpha : Bool;
 	public var killAlpha : Bool;
 	public var front2back : Bool;
 	public var front2back : Bool;
 
 
@@ -239,7 +239,7 @@ class RenderContext extends h3d.impl.RenderContext {
 		if( texture == null ) texture = h3d.mat.Texture.fromColor(0xFF00FF);
 		if( texture == null ) texture = h3d.mat.Texture.fromColor(0xFF00FF);
 		baseShader.texture = texture;
 		baseShader.texture = texture;
 		var f = currentObj.filter;
 		var f = currentObj.filter;
-		texture.filter = (currentObj.filter == null ? defaultFilter : currentObj.filter) ? Linear : Nearest;
+		texture.filter = (currentObj.filter == null ? defaultSmooth : currentObj.smooth) ? Linear : Nearest;
 		texture.wrap = currentObj.tileWrap ? Repeat : Clamp;
 		texture.wrap = currentObj.tileWrap ? Repeat : Clamp;
 		var blend = currentObj.blendMode;
 		var blend = currentObj.blendMode;
 		if( inFilter == currentObj  && blend == Erase ) blend = Add; // add THEN erase
 		if( inFilter == currentObj  && blend == Erase ) blend = Add; // add THEN erase

+ 3 - 3
h2d/Scene.hx

@@ -10,7 +10,7 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 	public var mouseY(get, null) : Float;
 	public var mouseY(get, null) : Float;
 
 
 	public var zoom(get, set) : Int;
 	public var zoom(get, set) : Int;
-	public var defaultFilter(get, set) : Bool;
+	public var defaultSmooth(get, set) : Bool;
 	public var renderer(get, set) : RenderContext;
 	public var renderer(get, set) : RenderContext;
 
 
 	var fixedSize : Bool;
 	var fixedSize : Bool;
@@ -33,8 +33,8 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 		posChanged = true;
 		posChanged = true;
 	}
 	}
 
 
-	inline function get_defaultFilter() return ctx.defaultFilter;
-	inline function set_defaultFilter(v) return ctx.defaultFilter = v;
+	inline function get_defaultSmooth() return ctx.defaultSmooth;
+	inline function set_defaultSmooth(v) return ctx.defaultSmooth = v;
 
 
 	public function setEvents(events) {
 	public function setEvents(events) {
 		this.events = events;
 		this.events = events;

+ 29 - 22
h2d/Sprite.hx

@@ -20,7 +20,7 @@ class Sprite {
 	public var name : String;
 	public var name : String;
 	public var alpha : Float = 1.;
 	public var alpha : Float = 1.;
 
 
-	public var filters : Array<h2d.filter.Filter>;
+	public var filter(default,set) : h2d.filter.Filter;
 
 
 	var matA : Float;
 	var matA : Float;
 	var matB : Float;
 	var matB : Float;
@@ -39,7 +39,6 @@ class Sprite {
 		posChanged = parent != null;
 		posChanged = parent != null;
 		visible = true;
 		visible = true;
 		childs = [];
 		childs = [];
-		filters = [];
 		if( parent != null )
 		if( parent != null )
 			parent.addChild(this);
 			parent.addChild(this);
 	}
 	}
@@ -83,6 +82,13 @@ class Sprite {
 		return out;
 		return out;
 	}
 	}
 
 
+	function set_filter(f) {
+		if( filter != null && allocated ) filter.unbind(this);
+		filter = f;
+		if( f != null && allocated ) f.bind(this);
+		return f;
+	}
+
 	function getBoundsRec( relativeTo : Sprite, out : h2d.col.Bounds, forSize : Bool ) {
 	function getBoundsRec( relativeTo : Sprite, out : h2d.col.Bounds, forSize : Bool ) {
 		if( posChanged ) {
 		if( posChanged ) {
 			calcAbsPos();
 			calcAbsPos();
@@ -259,6 +265,8 @@ class Sprite {
 	// kept for internal init
 	// kept for internal init
 	function onAdd() {
 	function onAdd() {
 		allocated = true;
 		allocated = true;
+		if( filter != null )
+			filter.bind(this);
 		for( c in childs )
 		for( c in childs )
 			c.onAdd();
 			c.onAdd();
 	}
 	}
@@ -266,6 +274,8 @@ class Sprite {
 	// kept for internal cleanup
 	// kept for internal cleanup
 	function onRemove() {
 	function onRemove() {
 		allocated = false;
 		allocated = false;
+		if( filter != null )
+			filter.unbind(this);
 		for( c in childs )
 		for( c in childs )
 			c.onRemove();
 			c.onRemove();
 	}
 	}
@@ -541,14 +551,12 @@ class Sprite {
 		var bounds = ctx.tmpBounds;
 		var bounds = ctx.tmpBounds;
 		var total = new h2d.col.Bounds();
 		var total = new h2d.col.Bounds();
 		var maxExtent = -1.;
 		var maxExtent = -1.;
-		for( f in filters ) {
-			f.sync(ctx, this);
-			if( f.autoBounds ) {
-				if( f.boundsExtend > maxExtent ) maxExtent = f.boundsExtend;
-			} else {
-				f.getBounds(this, bounds);
-				total.addBounds(bounds);
-			}
+		filter.sync(ctx, this);
+		if( filter.autoBounds ) {
+			maxExtent = filter.boundsExtend;
+		} else {
+			filter.getBounds(this, bounds);
+			total.addBounds(bounds);
 		}
 		}
 		if( maxExtent >= 0 ) {
 		if( maxExtent >= 0 ) {
 			getBounds(this, bounds);
 			getBounds(this, bounds);
@@ -599,17 +607,16 @@ class Sprite {
 		var final = h2d.Tile.fromTexture(t);
 		var final = h2d.Tile.fromTexture(t);
 		final.dx = xMin;
 		final.dx = xMin;
 		final.dy = yMin;
 		final.dy = yMin;
-		for( f in filters ) {
-			var prev = final;
-			final = f.draw(ctx, final);
-			if( final == null ) {
-				ctx.popTarget();
-				return;
-			}
-			if( final != prev ) {
-				final.dx += xMin;
-				final.dy += yMin;
-			}
+
+		var prev = final;
+		final = filter.draw(ctx, final);
+		if( final == null ) {
+			ctx.popTarget();
+			return;
+		}
+		if( final != prev ) {
+			final.dx += xMin;
+			final.dy += yMin;
 		}
 		}
 
 
 		shader.filterMatrixA.load(oldA);
 		shader.filterMatrixA.load(oldA);
@@ -635,7 +642,7 @@ class Sprite {
 				c.posChanged = true;
 				c.posChanged = true;
 			posChanged = false;
 			posChanged = false;
 		}
 		}
-		if( filters.length > 0 ) {
+		if( filter != null ) {
 			drawFilters(ctx);
 			drawFilters(ctx);
 		} else {
 		} else {
 			var old = ctx.globalAlpha;
 			var old = ctx.globalAlpha;

+ 1 - 1
h2d/Video.hx

@@ -44,7 +44,7 @@ class Video extends Drawable {
 	public function new(?parent) {
 	public function new(?parent) {
 		super(parent);
 		super(parent);
 		blendMode = None;
 		blendMode = None;
-		filter = true;
+		smooth = true;
 	}
 	}
 
 
 	public dynamic function onError( msg : String ) {
 	public dynamic function onError( msg : String ) {

+ 1 - 1
h2d/comp/Button.hx

@@ -26,7 +26,7 @@ class Button extends Interactive {
 			tf.font = getFont();
 			tf.font = getFont();
 			tf.textColor = style.color;
 			tf.textColor = style.color;
 			tf.text = text;
 			tf.text = text;
-			tf.filter = true;
+			tf.smooth = true;
 			contentWidth = tf.textWidth;
 			contentWidth = tf.textWidth;
 			contentHeight = tf.textHeight;
 			contentHeight = tf.textHeight;
 		}
 		}

+ 2 - 2
h2d/comp/Input.hx

@@ -7,7 +7,7 @@ class Input extends Interactive {
 	var tf : h2d.Text;
 	var tf : h2d.Text;
 	var cursor : h2d.Bitmap;
 	var cursor : h2d.Bitmap;
 	var cursorPos(default, set) : Int;
 	var cursorPos(default, set) : Int;
-	public var filter = true;
+	public var smooth = true;
 	public var value(default, set) : String;
 	public var value(default, set) : String;
 
 
 	public function new(?parent) {
 	public function new(?parent) {
@@ -116,7 +116,7 @@ class Input extends Interactive {
 			tf.font = getFont();
 			tf.font = getFont();
 			tf.textColor = style.color;
 			tf.textColor = style.color;
 			tf.text = value;
 			tf.text = value;
-			tf.filter = filter;
+			tf.smooth = smooth;
 			textAlign(tf);
 			textAlign(tf);
 			contentWidth = tf.textWidth;
 			contentWidth = tf.textWidth;
 			contentHeight = tf.textHeight;
 			contentHeight = tf.textHeight;

+ 1 - 1
h2d/comp/Label.hx

@@ -27,7 +27,7 @@ class Label extends Component {
 			tf.font = getFont();
 			tf.font = getFont();
 			tf.textColor = style.color;
 			tf.textColor = style.color;
 			tf.text = text;
 			tf.text = text;
-			tf.filter = true;
+			tf.smooth = true;
 			contentWidth = tf.textWidth;
 			contentWidth = tf.textWidth;
 			contentHeight = tf.textHeight;
 			contentHeight = tf.textHeight;
 		}
 		}

+ 1 - 1
h2d/comp/Select.hx

@@ -132,7 +132,7 @@ class Select extends Interactive {
 			tf.font = getFont();
 			tf.font = getFont();
 			tf.textColor = style.color;
 			tf.textColor = style.color;
 			tf.text = options[selectedIndex] == null ? "" : options[selectedIndex].label;
 			tf.text = options[selectedIndex] == null ? "" : options[selectedIndex].label;
-			tf.filter = true;
+			tf.smooth = true;
 			contentWidth = tf.textWidth;
 			contentWidth = tf.textWidth;
 			contentHeight = tf.textHeight;
 			contentHeight = tf.textHeight;
 		}
 		}

+ 29 - 4
h2d/filter/AbstractMask.hx

@@ -5,6 +5,11 @@ class Hide extends Filter {
 	public var frame : Int;
 	public var frame : Int;
 	public var input : h2d.Tile;
 	public var input : h2d.Tile;
 
 
+	public function new() {
+		super();
+		this.boundsExtend = 1;
+	}
+
 	override function draw( ctx : RenderContext, input : h2d.Tile ) {
 	override function draw( ctx : RenderContext, input : h2d.Tile ) {
 		this.frame = ctx.frame;
 		this.frame = ctx.frame;
 		this.input = input;
 		this.input = input;
@@ -19,6 +24,7 @@ class AbstractMask extends Filter {
 	var maskMatrix : h2d.col.Matrix;
 	var maskMatrix : h2d.col.Matrix;
 	var tmpMatrix : h2d.col.Matrix;
 	var tmpMatrix : h2d.col.Matrix;
 	var obj : h2d.Sprite;
 	var obj : h2d.Sprite;
+	var bindCount : Int;
 	public var mask(default, set) : h2d.Sprite;
 	public var mask(default, set) : h2d.Sprite;
 
 
 	function new(mask) {
 	function new(mask) {
@@ -29,12 +35,31 @@ class AbstractMask extends Filter {
 		tmpMatrix = new h2d.col.Matrix();
 		tmpMatrix = new h2d.col.Matrix();
 	}
 	}
 
 
+	override function bind(s:Sprite) {
+		bindCount++;
+		if( bindCount == 1 )
+			this.mask = mask;
+	}
+
+	override function unbind(s:Sprite) {
+		bindCount--;
+		if( bindCount == 0 )
+			this.mask = mask;
+	}
+
 	function set_mask(m:h2d.Sprite) {
 	function set_mask(m:h2d.Sprite) {
-		if( mask != null )
-			mask.filters.remove(hide);
+		if( mask != null ) {
+			if( mask.filter == hide )
+				mask.filter = null;
+		}
 		mask = m;
 		mask = m;
-		if( m != null )
-			m.filters.push(hide);
+		if( m != null && bindCount > 0 ) {
+			if( m.filter != null ) {
+				if( Std.is(m.filter,Hide) ) throw "Same mask can't be part of several filters";
+				throw "Can't set mask with filter "+m.filter;
+			}
+			m.filter = hide;
+		}
 		hide.input = null;
 		hide.input = null;
 		return m;
 		return m;
 	}
 	}

+ 1 - 0
h2d/filter/ColorMatrix.hx

@@ -9,6 +9,7 @@ class ColorMatrix extends Filter {
 	public function new( ?m : h3d.Matrix ) {
 	public function new( ?m : h3d.Matrix ) {
 		super();
 		super();
 		pass = new h3d.pass.ColorMatrix(m);
 		pass = new h3d.pass.ColorMatrix(m);
+		pass.shader.useAlpha = true;
 	}
 	}
 
 
 	inline function get_matrix() return pass.matrix;
 	inline function get_matrix() return pass.matrix;

+ 6 - 0
h2d/filter/Filter.hx

@@ -12,6 +12,12 @@ class Filter {
 	public function sync( ctx : RenderContext, s : Sprite ) {
 	public function sync( ctx : RenderContext, s : Sprite ) {
 	}
 	}
 
 
+	public function bind( s : Sprite ) {
+	}
+
+	public function unbind( s : Sprite ) {
+	}
+
 	public function getBounds( s : Sprite, bounds : h2d.col.Bounds ) {
 	public function getBounds( s : Sprite, bounds : h2d.col.Bounds ) {
 		s.getBounds(s, bounds);
 		s.getBounds(s, bounds);
 		bounds.xMin -= boundsExtend;
 		bounds.xMin -= boundsExtend;

+ 60 - 0
h2d/filter/Group.hx

@@ -0,0 +1,60 @@
+package h2d.filter;
+
+class Group extends Filter {
+
+	var filters : Array<Filter>;
+
+	public function new( filters : Array<Filter> ) {
+		super();
+		this.filters = filters.copy();
+	}
+
+	override function bind(s:Sprite) {
+		for( f in filters )
+			f.bind(s);
+	}
+
+	override function unbind(s:Sprite) {
+		for( f in filters )
+			f.unbind(s);
+	}
+
+	override function sync( ctx:RenderContext, s : Sprite ) {
+		this.autoBounds = true;
+		this.boundsExtend = 0;
+		for( f in filters ) {
+			f.sync(ctx, s);
+			if( f.boundsExtend > boundsExtend ) boundsExtend = f.boundsExtend;
+			if( !f.autoBounds ) autoBounds = false;
+		}
+	}
+
+	override function getBounds(s:Sprite, bounds:h2d.col.Bounds) {
+		for( f in filters )
+			if( !f.autoBounds )
+				f.getBounds(s, bounds);
+	}
+
+	override function draw( ctx : RenderContext, input : h2d.Tile ) {
+		var xMin = input.dx;
+		var yMin = input.dy;
+		var start = input;
+		for( f in filters ) {
+			var prev = input;
+			input = f.draw(ctx, input);
+			if( input == null )
+				return null;
+			if( input != prev ) {
+				input.dx += xMin;
+				input.dy += yMin;
+			}
+		}
+		if( start != input ) {
+			input.dx -= xMin;
+			input.dy -= yMin;
+		}
+		return input;
+	}
+
+
+}

+ 46 - 0
h2d/filter/Mask.hx

@@ -0,0 +1,46 @@
+package h2d.filter;
+
+private class MaskShader extends h3d.shader.ScreenShader {
+
+	static var SRC = {
+
+		@param var texture : Sampler2D;
+		@param var mask : Sampler2D;
+		@param var maskMatA : Vec3;
+		@param var maskMatB : Vec3;
+
+		function fragment() {
+			var color = texture.get(input.uv);
+			var uv = vec3(input.uv, 1);
+			var k = mask.get( vec2(uv.dot(maskMatA), uv.dot(maskMatB)) );
+			output.color = vec4(color.rgb, color.a * k.a);
+		}
+
+	};
+
+}
+
+
+class Mask extends AbstractMask {
+
+	var pass : h3d.pass.ScreenFx<MaskShader>;
+
+	public function new(mask) {
+		super(mask);
+		pass = new h3d.pass.ScreenFx(new MaskShader());
+	}
+
+	override function draw( ctx : RenderContext, t : h2d.Tile ) {
+		var out = ctx.textures.allocTarget("maskTmp", ctx, t.width, t.height, false);
+		ctx.engine.pushTarget(out);
+		pass.shader.texture = t.getTexture();
+		pass.shader.mask = getMaskTexture(t);
+		pass.shader.maskMatA.set(maskMatrix.a, maskMatrix.c, maskMatrix.x);
+		pass.shader.maskMatB.set(maskMatrix.b, maskMatrix.d, maskMatrix.y);
+		pass.render();
+		ctx.engine.popTarget();
+		return h2d.Tile.fromTexture(out);
+	}
+
+
+}

+ 3 - 3
h3d/impl/Benchmark.hx

@@ -63,7 +63,7 @@ class Benchmark extends h2d.Graphics {
 	public var font : h2d.Font;
 	public var font : h2d.Font;
 
 
 	public var recalTime = 1e9;
 	public var recalTime = 1e9;
-	public var smooth = 0.95;
+	public var smoothTime = 0.95;
 
 
 	public var measureCpu = true;
 	public var measureCpu = true;
 
 
@@ -169,7 +169,7 @@ class Benchmark extends h2d.Graphics {
 		if( hxd.Math.abs(ft - frameTime) > recalTime )
 		if( hxd.Math.abs(ft - frameTime) > recalTime )
 			frameTime = ft;
 			frameTime = ft;
 		else
 		else
-			frameTime = frameTime * smooth + ft * (1 - smooth);
+			frameTime = frameTime * smoothTime + ft * (1 - smoothTime);
 		prevFrame = t0;
 		prevFrame = t0;
 
 
 		// end was not called...
 		// end was not called...
@@ -348,7 +348,7 @@ class Benchmark extends h2d.Graphics {
 			if( et > recalTime )
 			if( et > recalTime )
 				s.time = time;
 				s.time = time;
 			else
 			else
-				s.time = s.time * smooth + time * (1 - smooth);
+				s.time = s.time * smoothTime + time * (1 - smoothTime);
 		} else {
 		} else {
 			s.name = name;
 			s.name = name;
 			s.time = time;
 			s.time = time;

+ 6 - 1
hxd/SceneEvents.hx

@@ -246,11 +246,16 @@ class SceneEvents {
 				}
 				}
 
 
 				if( currentDrag != null && (currentDrag.ref == null || currentDrag.ref == e.touchId) ) {
 				if( currentDrag != null && (currentDrag.ref == null || currentDrag.ref == e.touchId) ) {
+					e.propagate = false;
+					e.cancel = false;
 					currentDrag.f(e);
 					currentDrag.f(e);
 					e.relX = ox;
 					e.relX = ox;
 					e.relY = oy;
 					e.relY = oy;
-					if( !e.cancel )
+					if( e.cancel || e.propagate ) {
+						e.cancel = false;
+						e.propagate = false;
 						continue;
 						continue;
+					}
 				}
 				}
 
 
 				emitEvent(e);
 				emitEvent(e);

+ 18 - 10
samples/Filters.hx

@@ -4,6 +4,7 @@ class Filters extends hxd.App {
 
 
 	var spr : h2d.Sprite;
 	var spr : h2d.Sprite;
 	var bmp : h2d.Bitmap;
 	var bmp : h2d.Bitmap;
+	var mask : h2d.Graphics;
 	var disp : h2d.Tile;
 	var disp : h2d.Tile;
 
 
 	override function init() {
 	override function init() {
@@ -16,17 +17,22 @@ class Filters extends hxd.App {
 		bmp = new h2d.Bitmap(hxd.Res.hxlogo.toTile(), spr);
 		bmp = new h2d.Bitmap(hxd.Res.hxlogo.toTile(), spr);
 		bmp.colorKey = 0xFFFFFF;
 		bmp.colorKey = 0xFFFFFF;
 
 
+		mask = new h2d.Graphics(spr);
+		mask.beginFill(0xFF0000, 0.5);
+		mask.drawCircle(0, 0, 60);
+		mask.x = -20;
+		mask.y = -50;
 
 
 		disp = hxd.Res.normalmap.toTile();
 		disp = hxd.Res.normalmap.toTile();
 		setFilters(6);
 		setFilters(6);
 
 
 		var help = new h2d.Text(hxd.Res.customFont.toFont(), s2d);
 		var help = new h2d.Text(hxd.Res.customFont.toFont(), s2d);
 		help.x = help.y = 5;
 		help.x = help.y = 5;
-		help.text = "0:Disable 1:Blur 2:Glow 3:DropShadow 4:Displacement 5:Glow(Knockout) 6:Mix 7:ColorMatrix +/-:Scale";
+		help.text = "0:Disable 1:Blur 2:Glow 3:DropShadow 4:Displacement 5:Glow(Knockout) 6:Mix 7:ColorMatrix 8:Mask +/-:Scale";
 	}
 	}
 
 
 	override function update(dt:Float) {
 	override function update(dt:Float) {
-		for( i in 0...8 )
+		for( i in 0...10 )
 			if( K.isPressed(K.NUMBER_0 + i) || K.isPressed(K.NUMPAD_0+i) )
 			if( K.isPressed(K.NUMBER_0 + i) || K.isPressed(K.NUMPAD_0+i) )
 				setFilters(i);
 				setFilters(i);
 		if( K.isPressed(K.NUMPAD_ADD) ) {
 		if( K.isPressed(K.NUMPAD_ADD) ) {
@@ -49,30 +55,32 @@ class Filters extends hxd.App {
 	function setFilters(i) {
 	function setFilters(i) {
 		switch( i ) {
 		switch( i ) {
 		case 0:
 		case 0:
-			spr.filters = [];
+			spr.filter = null;
 		case 1:
 		case 1:
-			spr.filters = [new h2d.filter.Blur(2, 1, 100)];
+			spr.filter = new h2d.filter.Blur(2, 1, 100);
 		case 2:
 		case 2:
-			spr.filters = [new h2d.filter.Glow(0xFFFFFF, 100, 2)];
+			spr.filter = new h2d.filter.Glow(0xFFFFFF, 100, 2);
 		case 3:
 		case 3:
-			spr.filters = [new h2d.filter.DropShadow(8,Math.PI/4,0,1,2,2)];
+			spr.filter = new h2d.filter.DropShadow(8,Math.PI/4,0,1,2,2);
 		case 4:
 		case 4:
-			spr.filters = [new h2d.filter.Displacement(disp,4,4)];
+			spr.filter = new h2d.filter.Displacement(disp,4,4);
 		case 5:
 		case 5:
 			var g = new h2d.filter.Glow(0xFFFFFF, 100, 2);
 			var g = new h2d.filter.Glow(0xFFFFFF, 100, 2);
 			g.knockout = true;
 			g.knockout = true;
-			spr.filters = [g];
+			spr.filter = g;
 		case 6:
 		case 6:
 			var g = new h2d.filter.Glow(0xFFA500, 50, 2, 2);
 			var g = new h2d.filter.Glow(0xFFA500, 50, 2, 2);
 			g.knockout = true;
 			g.knockout = true;
-			spr.filters = [g, new h2d.filter.Displacement(disp, 3, 3), new h2d.filter.Blur(3, 2, 0.8), new h2d.filter.DropShadow(8, Math.PI / 4, 0, 1, 3, 3, 0.5)];
+			spr.filter = new h2d.filter.Group([g, new h2d.filter.Displacement(disp, 3, 3), new h2d.filter.Blur(3, 2, 0.8), new h2d.filter.DropShadow(8, Math.PI / 4, 0, 1, 3, 3, 0.5)]);
 		case 7:
 		case 7:
 			var m = new h3d.Matrix();
 			var m = new h3d.Matrix();
 			m.identity();
 			m.identity();
 			m.colorContrast(0.5);
 			m.colorContrast(0.5);
 			m.colorHue(Math.PI / 4);
 			m.colorHue(Math.PI / 4);
 			m.colorSaturation(-0.5);
 			m.colorSaturation(-0.5);
-			spr.filters = [new h2d.filter.ColorMatrix(m)];
+			spr.filter = new h2d.filter.ColorMatrix(m);
+		case 8:
+			spr.filter = new h2d.filter.Mask(mask);
 		}
 		}
 	}
 	}