瀏覽代碼

h2d.Sprite -> h2d.Object

Nicolas Cannasse 7 年之前
父節點
當前提交
6f709692c5

+ 2 - 2
h2d/Anim.hx

@@ -16,7 +16,7 @@ class Anim extends Drawable {
 	public var fading : Bool = false;
 	var curFrame : Float;
 
-	public function new( ?frames : Array<Tile>, ?speed : Float, ?parent : h2d.Sprite ) {
+	public function new( ?frames : Array<Tile>, ?speed : Float, ?parent : h2d.Object ) {
 		super(parent);
 		this.frames = frames == null ? [] : frames;
 		this.curFrame = 0;
@@ -42,7 +42,7 @@ class Anim extends Drawable {
 		return curFrame;
 	}
 
-	override function getBoundsRec( relativeTo : Sprite, out : h2d.col.Bounds, forSize : Bool ) {
+	override function getBoundsRec( relativeTo : Object, out : h2d.col.Bounds, forSize : Bool ) {
 		super.getBoundsRec(relativeTo, out, forSize);
 		var tile = getFrame();
 		if( tile != null ) addBounds(relativeTo, out, tile.dx, tile.dy, tile.width, tile.height);

+ 2 - 2
h2d/Bitmap.hx

@@ -4,7 +4,7 @@ class Bitmap extends Drawable {
 
 	public var tile : Tile;
 
-	public function new( ?tile : Tile, ?parent : h2d.Sprite ) {
+	public function new( ?tile : Tile, ?parent : h2d.Object ) {
 		super(parent);
 		this.tile = tile;
 	}
@@ -15,7 +15,7 @@ class Bitmap extends Drawable {
 		return tileWrap = b;
 	}
 
-	override function getBoundsRec( relativeTo : Sprite, out : h2d.col.Bounds, forSize : Bool ) {
+	override function getBoundsRec( relativeTo : Object, out : h2d.col.Bounds, forSize : Bool ) {
 		super.getBoundsRec(relativeTo, out, forSize);
 		if( tile != null ) addBounds(relativeTo, out, tile.dx, tile.dy, tile.width, tile.height);
 	}

+ 1 - 1
h2d/Console.hx

@@ -16,7 +16,7 @@ typedef ConsoleArgDesc = {
 	?opt : Bool,
 }
 
-class Console extends h2d.Sprite {
+class Console extends h2d.Object {
 
 	public static var HIDE_LOG_TIMEOUT = 3.;
 

+ 2 - 2
h2d/Drawable.hx

@@ -8,7 +8,7 @@ typedef ColorAdjust = {
 	?gain : { color : Int, alpha : Float },
 };
 
-class Drawable extends Sprite {
+class Drawable extends Object {
 
 	public var color(default,default) : h3d.Vector;
 	public var blendMode : BlendMode;
@@ -20,7 +20,7 @@ class Drawable extends Sprite {
 
 	var shaders : hxsl.ShaderList;
 
-	function new(parent : h2d.Sprite) {
+	function new(parent : h2d.Object) {
 		super(parent);
 		blendMode = Alpha;
 		color = new h3d.Vector(1, 1, 1, 1);

+ 6 - 6
h2d/Dropdown.hx

@@ -1,13 +1,13 @@
 package h2d;
 
-private class Fake extends Sprite {
+private class Fake extends Object {
 	var dd : Dropdown;
 	public function new(dd : Dropdown) {
 		super(dd);
 		this.dd = dd;
 	}
 
-	override function getBoundsRec(relativeTo:Sprite, out:h2d.col.Bounds, forSize:Bool) {
+	override function getBoundsRec(relativeTo:Object, out:h2d.col.Bounds, forSize:Bool) {
 		super.getBoundsRec(relativeTo, out, forSize);
 		if (dd.selectedItem >= 0) {
 			var item = @:privateAccess dd.items[dd.selectedItem];
@@ -31,7 +31,7 @@ private class Fake extends Sprite {
 }
 
 class Dropdown extends Flow {
-	var items : Array<h2d.Sprite>;
+	var items : Array<h2d.Object>;
 	var fake : Fake;
 	var cursor : h2d.Bitmap;
 	var arrow : h2d.Bitmap;
@@ -154,7 +154,7 @@ class Dropdown extends Flow {
 		return tileOverItem = t;
 	}
 
-	public function addItem(s : Sprite) {
+	public function addItem(s : Object) {
 		items.push(s);
 		dropdownList.addChild(s);
 		var width = Std.int(dropdownList.getSize().width);
@@ -209,9 +209,9 @@ class Dropdown extends Flow {
 	public dynamic function onClose() {
 	}
 
-	public dynamic function onOverItem(item : Sprite) {
+	public dynamic function onOverItem(item : Object) {
 	}
 
-	public dynamic function onOutItem(item : Sprite) {
+	public dynamic function onOutItem(item : Object) {
 	}
 }

+ 5 - 5
h2d/Flow.hx

@@ -11,7 +11,7 @@ enum FlowAlign {
 @:allow(h2d.Flow)
 class FlowProperties {
 
-	var elt : Sprite;
+	var elt : Object;
 
 	public var paddingLeft = 0;
 	public var paddingTop = 0;
@@ -54,7 +54,7 @@ class FlowProperties {
 
 }
 
-class Flow extends Sprite {
+class Flow extends Object {
 
 	static var tmpBounds = new h2d.col.Bounds();
 
@@ -189,7 +189,7 @@ class Flow extends Sprite {
 	/**
 		Get the per-element properties. Returns null if the element is not currently part of the flow.
 	**/
-	public function getProperties( e : h2d.Sprite ) {
+	public function getProperties( e : h2d.Object ) {
 		needReflow = true; // properties might be changed
 		return properties[getChildIndex(e)];
 	}
@@ -335,7 +335,7 @@ class Flow extends Sprite {
 		updateConstraint();
 	}
 
-	override function contentChanged( s : Sprite ) {
+	override function contentChanged( s : Object ) {
 		while( s.parent != this )
 			s = s.parent;
 		if( getProperties(s).isAbsolute )
@@ -392,7 +392,7 @@ class Flow extends Sprite {
 		s.setParentContainer(this);
 	}
 
-	override public function removeChild(s:Sprite) {
+	override public function removeChild(s:Object) {
 		var index = getChildIndex(s);
 		super.removeChild(s);
 		if( index >= 0 ) {

+ 10 - 10
h2d/HtmlText.hx

@@ -4,7 +4,7 @@ import h2d.Text;
 
 class HtmlText extends Text {
 
-	var elements : Array<Sprite> = [];
+	var elements : Array<Object> = [];
 	var xPos : Int;
 	var yPos : Int;
 	var xMax : Int;
@@ -51,10 +51,10 @@ class HtmlText extends Text {
 			elements = [];
 		}
 		glyphs.setDefaultColor(textColor);
-		
+
 		xPos = 0;
 		xMin = 0;
-		
+
 		var align = handleAlign ? textAlign : Left;
 		switch( align ) {
 			case Center, Right, MultilineCenter, MultilineRight:
@@ -68,23 +68,23 @@ class HtmlText extends Text {
 				xMin = xPos;
 			default:
 		}
-		
+
 		yPos = 0;
 		xMax = 0;
 		sizePos = 0;
 		calcYMin = 0;
-		
+
 		var doc = try Xml.parse(text) catch( e : Dynamic ) throw "Could not parse " + text + " (" + e +")";
-		
+
 		var sizes = [];
 		prevChar = -1;
 		for( e in doc )
 			buildSizes(e, sizes);
-		
+
 		prevChar = -1;
 		for( e in doc )
 			addNode(e, font, rebuild, handleAlign, sizes, lines);
-		
+
 		if (!handleAlign && !rebuild && lines != null) lines.push(xPos);
 		if( xPos > xMax ) xMax = xPos;
 
@@ -239,7 +239,7 @@ class HtmlText extends Text {
 			for( i in 0...t.length ) {
 				var cc = t.charCodeAt(i);
 				var e = font.getChar(cc);
-				
+
 				if( cc == "\n".code ) {
 					if( xPos > xMax ) xMax = xPos;
 					if( calcLines ) lines.push(xPos);
@@ -274,7 +274,7 @@ class HtmlText extends Text {
 		return c;
 	}
 
-	override function getBoundsRec( relativeTo : Sprite, out : h2d.col.Bounds, forSize : Bool ) {
+	override function getBoundsRec( relativeTo : Object, out : h2d.col.Bounds, forSize : Bool ) {
 		if( forSize )
 			for( i in elements )
 				if( Std.is(i,h2d.Bitmap) )

+ 3 - 3
h2d/KeyFrames.hx

@@ -4,7 +4,7 @@ import hxd.fmt.kframes.Data;
 typedef KeyframesLayer = {
 	var id : Int;
 	var name : String;
-	var spr : Sprite;
+	var spr : Object;
 	var tiles : Array<h2d.Tile>;
 	var animations : Array<KFAnimation>;
 	var from : Int;
@@ -46,7 +46,7 @@ class KeyFrames extends Mask {
 		for( f in file.features ) {
 			var spr, tiles = null;
 			if( f.backed_image == null ) {
-				spr = new h2d.Sprite(this);
+				spr = new h2d.Object(this);
 			} else {
 				var reg = ~/(.*?)\[([0-9]+)-([0-9]+)\](.*)/;
 				if( reg.match(f.backed_image) ){
@@ -57,7 +57,7 @@ class KeyFrames extends Mask {
 				}else{
 					tiles = [loadTile(f.backed_image)];
 				}
-				
+
 				for( t in tiles ) t.scaleToSize(f.size.x, f.size.y);
 				var bmp = new h2d.Bitmap(tiles[0], this);
 				bmp.smooth = smooth;

+ 6 - 6
h2d/Layers.hx

@@ -1,6 +1,6 @@
 package h2d;
 
-class Layers extends Sprite {
+class Layers extends Object {
 
 	// the per-layer insert position
 	var layersIndexes : Array<Int>;
@@ -20,7 +20,7 @@ class Layers extends Sprite {
 		return addChildAt(s, layer);
 	}
 
-	override function addChildAt( s : Sprite, layer : Int ) {
+	override function addChildAt( s : Object, layer : Int ) {
 		if( s.parent == this ) {
 			var old = s.allocated;
 			s.allocated = false;
@@ -35,7 +35,7 @@ class Layers extends Sprite {
 			layersIndexes[i]++;
 	}
 
-	override function removeChild( s : Sprite ) {
+	override function removeChild( s : Object ) {
 		for( i in 0...children.length ) {
 			if( children[i] == s ) {
 				children.splice(i, 1);
@@ -51,7 +51,7 @@ class Layers extends Sprite {
 		}
 	}
 
-	public function under( s : Sprite ) {
+	public function under( s : Object ) {
 		for( i in 0...children.length )
 			if( children[i] == s ) {
 				var pos = 0;
@@ -70,7 +70,7 @@ class Layers extends Sprite {
 			}
 	}
 
-	public function over( s : Sprite ) {
+	public function over( s : Object ) {
 		for( i in 0...children.length )
 			if( children[i] == s ) {
 				for( l in layersIndexes )
@@ -84,7 +84,7 @@ class Layers extends Sprite {
 			}
 	}
 
-	public function getLayer( layer : Int ) : Iterator<Sprite> {
+	public function getLayer( layer : Int ) : Iterator<Object> {
 		var a;
 		if( layer >= layerCount )
 			a = [];

+ 1 - 1
h2d/Mask.hx

@@ -1,6 +1,6 @@
 package h2d;
 
-class Mask extends Sprite {
+class Mask extends Object {
 
 	public var width : Int;
 	public var height : Int;

+ 788 - 0
h2d/Object.hx

@@ -0,0 +1,788 @@
+package h2d;
+import hxd.Math;
+
+@:allow(h2d.Tools)
+class Object {
+
+	static var nullDrawable : h2d.Drawable;
+
+	var children : Array<Object>;
+	var parentContainer : Object;
+
+	/**
+		The parent `Sprite` in the scene tree.
+	**/
+	public var parent(default, null) : Object;
+	/**
+		How many immediate children this sprite has.
+	**/
+	public var numChildren(get, never) : Int;
+
+	public var x(default,set) : Float;
+	public var y(default, set) : Float;
+	public var scaleX(default,set) : Float;
+	public var scaleY(default,set) : Float;
+	public var rotation(default, set) : Float;
+	public var visible(default, set) : Bool;
+	public var name : String;
+	public var alpha : Float = 1.;
+
+	public var filter(default,set) : h2d.filter.Filter;
+
+	var matA : Float;
+	var matB : Float;
+	var matC : Float;
+	var matD : Float;
+	var absX : Float;
+	var absY : Float;
+
+	var posChanged : Bool;
+	var allocated : Bool;
+	var lastFrame : Int;
+
+	public function new( ?parent : Object ) {
+		matA = 1; matB = 0; matC = 0; matD = 1; absX = 0; absY = 0;
+		x = 0; y = 0; scaleX = 1; scaleY = 1; rotation = 0;
+		posChanged = parent != null;
+		visible = true;
+		children = [];
+		if( parent != null )
+			parent.addChild(this);
+	}
+
+	/**
+		Returns the bounds of the sprite for its whole content, recursively.
+		If relativeTo is null, it will return the bounds in the absolute coordinates.
+		If not, it will return the bounds relative to the specified sprite coordinates.
+		You can pass an already allocated bounds or getBounds will allocate one for you and return it.
+	**/
+	public function getBounds( ?relativeTo : Object, ?out : h2d.col.Bounds ) : h2d.col.Bounds {
+		if( out == null ) out = new h2d.col.Bounds() else out.empty();
+		if( relativeTo != null )
+			relativeTo.syncPos();
+		if( relativeTo != this )
+			syncPos();
+		getBoundsRec(relativeTo, out, false);
+		if( out.isEmpty() ) {
+			addBounds(relativeTo, out, -1, -1, 2, 2);
+			out.xMax = out.xMin = (out.xMax + out.xMin) * 0.5;
+			out.yMax = out.yMin = (out.yMax + out.yMin) * 0.5;
+		}
+		return out;
+	}
+
+	/**
+		This is similar to getBounds(parent), but instead of the full content, it will return
+		the size based on the alignement of the Sprite. For instance for a text, getBounds will return
+		the full glyphs size whereas getSize() will ignore the pixels under the baseline.
+	**/
+	public function getSize( ?out : h2d.col.Bounds ) : h2d.col.Bounds {
+		if( out == null ) out = new h2d.col.Bounds() else out.empty();
+		syncPos();
+		getBoundsRec(parent, out, true);
+		if( out.isEmpty() ) {
+			addBounds(parent, out, -1, -1, 2, 2);
+			out.xMax = out.xMin = (out.xMax + out.xMin) * 0.5;
+			out.yMax = out.yMin = (out.yMax + out.yMin) * 0.5;
+		}
+		out.offset( -x, -y);
+		return out;
+	}
+
+	public function find<T>( f : Object -> Null<T> ) : Null<T> {
+		var v = f(this);
+		if( v != null )
+			return v;
+		for( o in children ) {
+			var v = o.find(f);
+			if( v != null ) return v;
+		}
+		return null;
+	}
+
+	public function findAll<T>( f : Object -> Null<T>, ?arr : Array<T> ) : Array<T> {
+		if( arr == null ) arr = [];
+		var v = f(this);
+		if( v != null )
+			arr.push(v);
+		for( o in children )
+			o.findAll(f,arr);
+		return arr;
+	}
+
+	function set_filter(f : h2d.filter.Filter) {
+		if( filter != null && allocated ) filter.unbind(this);
+		filter = f;
+		if( f != null && allocated ) f.bind(this);
+		return f;
+	}
+
+	function getBoundsRec( relativeTo : Object, out : h2d.col.Bounds, forSize : Bool ) : Void {
+		if( posChanged ) {
+			calcAbsPos();
+			for( c in children )
+				c.posChanged = true;
+			posChanged = false;
+		}
+		var n = children.length;
+		if( n == 0 ) {
+			out.empty();
+			return;
+		}
+		if( n == 1 ) {
+			var c = children[0];
+			if( c.visible ) c.getBoundsRec(relativeTo, out,forSize) else out.empty();
+			return;
+		}
+		var xmin = hxd.Math.POSITIVE_INFINITY, ymin = hxd.Math.POSITIVE_INFINITY;
+		var xmax = hxd.Math.NEGATIVE_INFINITY, ymax = hxd.Math.NEGATIVE_INFINITY;
+		for( c in children ) {
+			if( !c.visible ) continue;
+			c.getBoundsRec(relativeTo, out, forSize);
+			if( out.xMin < xmin ) xmin = out.xMin;
+			if( out.yMin < ymin ) ymin = out.yMin;
+			if( out.xMax > xmax ) xmax = out.xMax;
+			if( out.yMax > ymax ) ymax = out.yMax;
+		}
+		out.xMin = xmin;
+		out.yMin = ymin;
+		out.xMax = xmax;
+		out.yMax = ymax;
+	}
+
+	function addBounds( relativeTo : Object, out : h2d.col.Bounds, dx : Float, dy : Float, width : Float, height : Float ) {
+
+		if( width <= 0 || height <= 0 ) return;
+
+		if( relativeTo == null  ) {
+			var x, y;
+			out.addPos(dx * matA + dy * matC + absX, dx * matB + dy * matD + absY);
+			out.addPos((dx + width) * matA + dy * matC + absX, (dx + width) * matB + dy * matD + absY);
+			out.addPos(dx * matA + (dy + height) * matC + absX, dx * matB + (dy + height) * matD + absY);
+			out.addPos((dx + width) * matA + (dy + height) * matC + absX, (dx + width) * matB + (dy + height) * matD + absY);
+			return;
+		}
+
+		if( relativeTo == this ) {
+			if( out.xMin > dx ) out.xMin = dx;
+			if( out.yMin > dy ) out.yMin = dy;
+			if( out.xMax < dx + width ) out.xMax = dx + width;
+			if( out.yMax < dy + height ) out.yMax = dy + height;
+			return;
+		}
+
+		var r = relativeTo.matA * relativeTo.matD - relativeTo.matB * relativeTo.matC;
+		if( r == 0 )
+			return;
+
+		var det = 1 / r;
+		var rA = relativeTo.matD * det;
+		var rB = -relativeTo.matB * det;
+		var rC = -relativeTo.matC * det;
+		var rD = relativeTo.matA * det;
+		var rX = absX - relativeTo.absX;
+		var rY = absY - relativeTo.absY;
+
+		var x, y;
+
+		x = dx * matA + dy * matC + rX;
+		y = dx * matB + dy * matD + rY;
+		out.addPos(x * rA + y * rC, x * rB + y * rD);
+
+		x = (dx + width) * matA + dy * matC + rX;
+		y = (dx + width) * matB + dy * matD + rY;
+		out.addPos(x * rA + y * rC, x * rB + y * rD);
+
+		x = dx * matA + (dy + height) * matC + rX;
+		y = dx * matB + (dy + height) * matD + rY;
+		out.addPos(x * rA + y * rC, x * rB + y * rD);
+
+		x = (dx + width) * matA + (dy + height) * matC + rX;
+		y = (dx + width) * matB + (dy + height) * matD + rY;
+		out.addPos(x * rA + y * rC, x * rB + y * rD);
+	}
+
+	public function getSpritesCount() : Int {
+		var k = 0;
+		for( c in children )
+			k += c.getSpritesCount() + 1;
+		return k;
+	}
+
+	public function localToGlobal( ?pt : h2d.col.Point ) : h2d.col.Point {
+		syncPos();
+		if( pt == null ) pt = new h2d.col.Point();
+		var px = pt.x * matA + pt.y * matC + absX;
+		var py = pt.x * matB + pt.y * matD + absY;
+		pt.x = px;
+		pt.y = py;
+		return pt;
+	}
+
+	public function globalToLocal( pt : h2d.col.Point ) : h2d.col.Point {
+		syncPos();
+		pt.x -= absX;
+		pt.y -= absY;
+		var invDet = 1 / (matA * matD - matB * matC);
+		var px = (pt.x * matD - pt.y * matC) * invDet;
+		var py = (-pt.x * matB + pt.y * matA) * invDet;
+		pt.x = px;
+		pt.y = py;
+		return pt;
+	}
+
+	function getScene() : Scene {
+		var p = this;
+		while( p.parent != null ) p = p.parent;
+		return Std.instance(p, Scene);
+	}
+
+	function set_visible(b) {
+		if( visible == b )
+			return b;
+		visible = b;
+		onContentChanged();
+		return b;
+	}
+
+	public function addChild( s : Object ) : Void {
+		addChildAt(s, children.length);
+	}
+
+	public function addChildAt( s : Object, pos : Int ) : Void {
+		if( pos < 0 ) pos = 0;
+		if( pos > children.length ) pos = children.length;
+		var p = this;
+		while( p != null ) {
+			if( p == s ) throw "Recursive addChild";
+			p = p.parent;
+		}
+		if( s.parent != null ) {
+			// prevent calling onRemove
+			var old = s.allocated;
+			s.allocated = false;
+			s.parent.removeChild(s);
+			s.allocated = old;
+		}
+		children.insert(pos, s);
+		if( !allocated && s.allocated )
+			s.onRemove();
+		s.parent = this;
+		s.parentContainer = parentContainer;
+		s.posChanged = true;
+		// ensure that proper alloc/delete is done if we change parent
+		if( allocated ) {
+			if( !s.allocated )
+				s.onAdd();
+			else
+				s.onParentChanged();
+		}
+		onContentChanged();
+	}
+
+	inline function onContentChanged() {
+		if( parentContainer != null ) parentContainer.contentChanged(this);
+	}
+
+	// called when we're allocated already but moved in hierarchy
+	function onParentChanged() {
+		for( c in children )
+			c.onParentChanged();
+	}
+
+	// kept for internal init
+	function onAdd() {
+		allocated = true;
+		if( filter != null )
+			filter.bind(this);
+		for( c in children )
+			c.onAdd();
+	}
+
+	// kept for internal cleanup
+	function onRemove() {
+		allocated = false;
+		if( filter != null )
+			filter.unbind(this);
+		for( c in children )
+			c.onRemove();
+	}
+
+	function getMatrix( m : h2d.col.Matrix ) {
+		m.a = matA;
+		m.b = matB;
+		m.c = matC;
+		m.d = matD;
+		m.x = absX;
+		m.y = absY;
+	}
+
+	public function removeChild( s : Object ) {
+		if( children.remove(s) ) {
+			if( s.allocated ) s.onRemove();
+			s.parent = null;
+			if( s.parentContainer != null ) s.setParentContainer(null);
+			s.posChanged = true;
+			onContentChanged();
+		}
+	}
+
+	function setParentContainer( c : Object ) {
+		parentContainer = c;
+		for( s in children )
+			s.setParentContainer(c);
+	}
+
+	public function removeChildren() {
+		while( numChildren>0 )
+			removeChild( getChildAt(0) );
+	}
+
+	/**
+		Same as parent.removeChild(this), but does nothing if parent is null.
+		In order to capture add/removal from scene, you can override onAdd/onRemove/onParentChanged
+	**/
+	public inline function remove() {
+		if( this != null && parent != null ) parent.removeChild(this);
+	}
+
+	public function drawTo( t : h3d.mat.Texture ) {
+		var s = getScene();
+		var needDispose = s == null;
+		if( s == null ) s = new h2d.Scene();
+		@:privateAccess s.drawImplTo(this, t);
+		if( needDispose ) s.dispose();
+	}
+
+	function draw( ctx : RenderContext ) {
+	}
+
+	function sync( ctx : RenderContext ) {
+		var changed = posChanged;
+		if( changed ) {
+			calcAbsPos();
+			posChanged = false;
+		}
+
+		lastFrame = ctx.frame;
+		var p = 0, len = children.length;
+		while( p < len ) {
+			var c = children[p];
+			if( c == null )
+				break;
+			if( c.lastFrame != ctx.frame ) {
+				if( changed ) c.posChanged = true;
+				c.sync(ctx);
+			}
+			// if the object was removed, let's restart again.
+			// our lastFrame ensure that no object will get synched twice
+			if( children[p] != c ) {
+				p = 0;
+				len = children.length;
+			} else
+				p++;
+		}
+	}
+
+	function syncPos() {
+		if( parent != null ) parent.syncPos();
+		if( posChanged ) {
+			calcAbsPos();
+			for( c in children )
+				c.posChanged = true;
+			posChanged = false;
+		}
+	}
+
+	function calcAbsPos() {
+		if( parent == null ) {
+			var cr, sr;
+			if( rotation == 0 ) {
+				cr = 1.; sr = 0.;
+				matA = scaleX;
+				matB = 0;
+				matC = 0;
+				matD = scaleY;
+			} else {
+				cr = Math.cos(rotation);
+				sr = Math.sin(rotation);
+				matA = scaleX * cr;
+				matB = scaleX * sr;
+				matC = scaleY * -sr;
+				matD = scaleY * cr;
+			}
+			absX = x;
+			absY = y;
+		} else {
+			// M(rel) = S . R . T
+			// M(abs) = M(rel) . P(abs)
+			if( rotation == 0 ) {
+				matA = scaleX * parent.matA;
+				matB = scaleX * parent.matB;
+				matC = scaleY * parent.matC;
+				matD = scaleY * parent.matD;
+			} else {
+				var cr = Math.cos(rotation);
+				var sr = Math.sin(rotation);
+				var tmpA = scaleX * cr;
+				var tmpB = scaleX * sr;
+				var tmpC = scaleY * -sr;
+				var tmpD = scaleY * cr;
+				matA = tmpA * parent.matA + tmpB * parent.matC;
+				matB = tmpA * parent.matB + tmpB * parent.matD;
+				matC = tmpC * parent.matA + tmpD * parent.matC;
+				matD = tmpC * parent.matB + tmpD * parent.matD;
+			}
+			absX = x * parent.matA + y * parent.matC + parent.absX;
+			absY = x * parent.matB + y * parent.matD + parent.absY;
+		}
+	}
+
+	function emitTile( ctx : RenderContext, tile : h2d.Tile ) {
+		if( nullDrawable == null )
+			nullDrawable = @:privateAccess new h2d.Drawable(null);
+		if( !ctx.hasBuffering() ) {
+			nullDrawable.absX = absX;
+			nullDrawable.absY = absY;
+			nullDrawable.matA = matA;
+			nullDrawable.matB = matB;
+			nullDrawable.matC = matC;
+			nullDrawable.matD = matD;
+			ctx.drawTile(nullDrawable, tile);
+			return;
+		}
+		if( !ctx.beginDrawBatch(nullDrawable, tile.getTexture()) ) return;
+
+		var ax = absX + tile.dx * matA + tile.dy * matC;
+		var ay = absY + tile.dx * matB + tile.dy * matD;
+		var buf = ctx.buffer;
+		var pos = ctx.bufPos;
+		buf.grow(pos + 4 * 8);
+
+		inline function emit(v:Float) buf[pos++] = v;
+
+		emit(ax);
+		emit(ay);
+		emit(tile.u);
+		emit(tile.v);
+		emit(1.);
+		emit(1.);
+		emit(1.);
+		emit(ctx.globalAlpha);
+
+
+		var tw = tile.width;
+		var th = tile.height;
+		var dx1 = tw * matA;
+		var dy1 = tw * matB;
+		var dx2 = th * matC;
+		var dy2 = th * matD;
+
+		emit(ax + dx1);
+		emit(ay + dy1);
+		emit(tile.u2);
+		emit(tile.v);
+		emit(1.);
+		emit(1.);
+		emit(1.);
+		emit(ctx.globalAlpha);
+
+		emit(ax + dx2);
+		emit(ay + dy2);
+		emit(tile.u);
+		emit(tile.v2);
+		emit(1.);
+		emit(1.);
+		emit(1.);
+		emit(ctx.globalAlpha);
+
+		emit(ax + dx1 + dx2);
+		emit(ay + dy1 + dy2);
+		emit(tile.u2);
+		emit(tile.v2);
+		emit(1.);
+		emit(1.);
+		emit(1.);
+		emit(ctx.globalAlpha);
+
+		ctx.bufPos = pos;
+	}
+
+	/**
+		Will clip a local bounds with our global viewport
+	**/
+	function clipBounds( ctx : RenderContext, bounds : h2d.col.Bounds ) {
+		var view = ctx.tmpBounds;
+		var matA, matB, matC, matD, absX, absY;
+		@:privateAccess if( ctx.inFilter != null ) {
+			var f1 = ctx.baseShader.filterMatrixA;
+			var f2 = ctx.baseShader.filterMatrixB;
+			matA = this.matA * f1.x + this.matB * f1.y;
+			matB = this.matA * f2.x + this.matB * f2.y;
+			matC = this.matC * f1.x + this.matD * f1.y;
+			matD = this.matC * f2.x + this.matD * f2.y;
+			absX = this.absX * f1.x + this.absY * f1.y + f1.z;
+			absY = this.absX * f2.x + this.absY * f2.y + f2.z;
+		} else {
+			matA = this.matA;
+			matB = this.matB;
+			matC = this.matC;
+			matD = this.matD;
+			absX = this.absX;
+			absY = this.absY;
+		}
+
+		// intersect our transformed local view with our viewport in global space
+		view.empty();
+		inline function add(x:Float, y:Float) {
+			view.addPos(x * matA + y * matC + absX, x * matB + y * matD + absY);
+		}
+		add(bounds.xMin, bounds.yMin);
+		add(bounds.xMax, bounds.yMin);
+		add(bounds.xMin, bounds.yMax);
+		add(bounds.xMax, bounds.yMax);
+
+		// clip with our scene
+		@:privateAccess {
+			if( view.xMin < ctx.curX ) view.xMin = ctx.curX;
+			if( view.yMin < ctx.curY ) view.yMin = ctx.curY;
+			if( view.xMax > ctx.curX + ctx.curWidth ) view.xMax = ctx.curX + ctx.curWidth;
+			if( view.yMax > ctx.curY + ctx.curHeight ) view.yMax = ctx.curY + ctx.curHeight;
+		}
+
+		// inverse our matrix
+		var invDet = 1 / (matA * matD - matB * matC);
+		inline function add(x:Float, y:Float) {
+			x -= absX;
+			y -= absY;
+			view.addPos((x * matD - y * matC) * invDet, ( -x * matB + y * matA) * invDet);
+		}
+
+		// intersect our resulting viewport with our calculated local space
+		var sxMin = view.xMin;
+		var syMin = view.yMin;
+		var sxMax = view.xMax;
+		var syMax = view.yMax;
+		view.empty();
+		add(sxMin, syMin);
+		add(sxMax, syMin);
+		add(sxMin, syMax);
+		add(sxMax, syMax);
+
+		// intersects
+		bounds.doIntersect(view);
+	}
+
+	function drawFilters( ctx : RenderContext ) {
+		if( !ctx.pushFilter(this) ) return;
+
+		var bounds = ctx.tmpBounds;
+		var total = new h2d.col.Bounds();
+		var maxExtent = -1.;
+		filter.sync(ctx, this);
+		if( filter.autoBounds ) {
+			maxExtent = filter.boundsExtend;
+		} else {
+			filter.getBounds(this, bounds);
+			total.addBounds(bounds);
+		}
+		if( maxExtent >= 0 ) {
+			getBounds(this, bounds);
+			bounds.xMin -= maxExtent;
+			bounds.yMin -= maxExtent;
+			bounds.xMax += maxExtent;
+			bounds.yMax += maxExtent;
+			total.addBounds(bounds);
+		}
+
+		clipBounds(ctx, total);
+
+		var xMin = Math.floor(total.xMin + 1e-10);
+		var yMin = Math.floor(total.yMin + 1e-10);
+		var width = Math.ceil(total.xMax - xMin - 1e-10);
+		var height = Math.ceil(total.yMax - yMin - 1e-10);
+
+		if( width <= 0 || height <= 0 || total.xMax < total.xMin ) return;
+
+		var t = ctx.textures.allocTarget("filterTemp", width, height, false);
+		ctx.pushTarget(t, xMin, yMin, width, height);
+		ctx.engine.clear(0);
+
+		// reset transform and update children
+		var oldAlpha = ctx.globalAlpha;
+		var shader = @:privateAccess ctx.baseShader;
+		var oldA = shader.filterMatrixA.clone();
+		var oldB = shader.filterMatrixB.clone();
+		var oldF = @:privateAccess ctx.inFilter;
+
+		// 2x3 inverse matrix
+		var invDet = 1 / (matA * matD - matB * matC);
+		var invA = matD * invDet;
+		var invB = -matB * invDet;
+		var invC = -matC * invDet;
+		var invD = matA * invDet;
+		var invX = -(absX * invA + absY * invC);
+		var invY = -(absX * invB + absY * invD);
+
+		shader.filterMatrixA.set(invA, invC, invX);
+		shader.filterMatrixB.set(invB, invD, invY);
+		ctx.globalAlpha = 1;
+		draw(ctx);
+		for( c in children )
+			c.drawRec(ctx);
+		ctx.flush();
+
+		var finalTile = h2d.Tile.fromTexture(t);
+		finalTile.dx = xMin;
+		finalTile.dy = yMin;
+
+		var prev = finalTile;
+		finalTile = filter.draw(ctx, finalTile);
+		if( finalTile != prev && finalTile != null ) {
+			finalTile.dx += xMin;
+			finalTile.dy += yMin;
+		}
+
+		shader.filterMatrixA.load(oldA);
+		shader.filterMatrixB.load(oldB);
+
+		ctx.popTarget();
+		ctx.popFilter();
+
+		if( finalTile == null )
+			return;
+
+		ctx.globalAlpha = oldAlpha * alpha;
+		emitTile(ctx, finalTile);
+		ctx.globalAlpha = oldAlpha;
+		ctx.flush();
+	}
+
+	function drawRec( ctx : RenderContext ) {
+		if( !visible ) return;
+		// fallback in case the object was added during a sync() event and we somehow didn't update it
+		if( posChanged ) {
+			// only sync anim, don't update() (prevent any event from occuring during draw())
+			// if( currentAnimation != null ) currentAnimation.sync();
+			calcAbsPos();
+			for( c in children )
+				c.posChanged = true;
+			posChanged = false;
+		}
+		if( filter != null ) {
+			drawFilters(ctx);
+		} else {
+			var old = ctx.globalAlpha;
+			ctx.globalAlpha *= alpha;
+			if( ctx.front2back ) {
+				var nchilds = children.length;
+				for (i in 0...nchilds) children[nchilds - 1 - i].drawRec(ctx);
+				draw(ctx);
+			} else {
+				draw(ctx);
+				for( c in children ) c.drawRec(ctx);
+			}
+			ctx.globalAlpha = old;
+		}
+	}
+
+	inline function set_x(v) {
+		posChanged = true;
+		return x = v;
+	}
+
+	inline function set_y(v) {
+		posChanged = true;
+		return y = v;
+	}
+
+	inline function set_scaleX(v) {
+		posChanged = true;
+		return scaleX = v;
+	}
+
+	inline function set_scaleY(v) {
+		posChanged = true;
+		return scaleY = v;
+	}
+
+	inline function set_rotation(v) {
+		posChanged = true;
+		return rotation = v;
+	}
+
+	public function move( dx : Float, dy : Float ) {
+		x += dx * Math.cos(rotation);
+		y += dy * Math.sin(rotation);
+	}
+
+	public inline function setPosition( x : Float, y : Float ) {
+		this.x = x;
+		this.y = y;
+	}
+
+	public inline function rotate( v : Float ) {
+		rotation += v;
+	}
+
+	public inline function scale( v : Float ) {
+		scaleX *= v;
+		scaleY *= v;
+	}
+
+	public inline function setScale( v : Float ) {
+		scaleX = v;
+		scaleY = v;
+	}
+
+	public inline function getChildAt( n ) {
+		return children[n];
+	}
+
+	public function getChildIndex( s ) {
+		for( i in 0...children.length )
+			if( children[i] == s )
+				return i;
+		return -1;
+	}
+
+	public function getSpriteByName( name : String ) {
+		if( this.name == name )
+			return this;
+		for( c in children ) {
+			var o = c.getSpriteByName(name);
+			if( o != null ) return o;
+		}
+		return null;
+	}
+
+	inline function get_numChildren() {
+		return children.length;
+	}
+
+	public inline function iterator() {
+		return new hxd.impl.ArrayIterator(children);
+	}
+
+	function toString() {
+		var c = Type.getClassName(Type.getClass(this));
+		return name == null ? c : name + "(" + c + ")";
+	}
+
+	// ---- additional methods for containers (h2d.Flow)
+
+	/**
+		This is called by our children if we have defined their parentContainer when they get resized
+	**/
+	function contentChanged( s : Object ) {
+	}
+
+	/**
+		This can be called by a parent container to constraint the size of its children.
+		Negative value mean that constraint is to be disable.
+	**/
+	function constraintSize( maxWidth : Float, maxHeight : Float ) {
+	}
+
+}
+

+ 1 - 1
h2d/ObjectFollower.hx

@@ -3,7 +3,7 @@ package h2d;
 /**
 	Allows a 2D sprite position to follow a 3D object using the current camera.
 **/
-class ObjectFollower extends Sprite {
+class ObjectFollower extends Object {
 
 	public var follow : h3d.scene.Object;
 	public var pixelSnap = true;

+ 5 - 5
h2d/RenderContext.hx

@@ -13,8 +13,8 @@ class RenderContext extends h3d.impl.RenderContext {
 	public var front2back : Bool;
 
 	public var onBeginDraw : h2d.Drawable->Bool; // return false to cancel drawing
-	public var onEnterFilter : h2d.Sprite->Bool;
-	public var onLeaveFilter : h2d.Sprite->Void;
+	public var onEnterFilter : h2d.Object->Bool;
+	public var onLeaveFilter : h2d.Object->Void;
 
 	public var tmpBounds = new h2d.col.Bounds();
 	var texture : h3d.mat.Texture;
@@ -31,8 +31,8 @@ class RenderContext extends h3d.impl.RenderContext {
 	var targetsStack : Array<{ t : h3d.mat.Texture, x : Int, y : Int, w : Int, h : Int, hasRZ : Bool, rzX:Float, rzY:Float, rzW:Float, rzH:Float }>;
 	var targetsStackIndex : Int;
 	var hasUVPos : Bool;
-	var filterStack : Array<h2d.Sprite>;
-	var inFilter : Sprite;
+	var filterStack : Array<h2d.Object>;
+	var inFilter : Object;
 
 	var curX : Int;
 	var curY : Int;
@@ -133,7 +133,7 @@ class RenderContext extends h3d.impl.RenderContext {
 		if( targetsStackIndex != 0 ) throw "Missing popTarget()";
 	}
 
-	public function pushFilter( spr : h2d.Sprite ) {
+	public function pushFilter( spr : h2d.Object ) {
 		if( filterStack.length == 0 && onEnterFilter != null )
 			if( !onEnterFilter(spr) ) return false;
 		filterStack.push(spr);

+ 10 - 10
h2d/Scene.hx

@@ -102,7 +102,7 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 	}
 
 	public function isInteractiveVisible( i : hxd.SceneEvents.Interactive ) : Bool {
-		var s : Sprite = cast i;
+		var s : Object = cast i;
 		while( s != null ) {
 			if( !s.visible ) return false;
 			s = s.parent;
@@ -142,7 +142,7 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 
 			// check visibility
 			var visible = true;
-			var p : Sprite = i;
+			var p : Object = i;
 			while( p != null ) {
 				if( !p.visible ) {
 					visible = false;
@@ -228,7 +228,7 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 
 			// check visibility
 			var visible = true;
-			var p : Sprite = i;
+			var p : Object = i;
 			while( p != null ) {
 				if( !p.visible ) {
 					visible = false;
@@ -292,7 +292,7 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 	@:allow(h2d)
 	function addEventTarget(i:Interactive) {
 		// sort by which is over the other in the scene hierarchy
-		inline function getLevel(i:Sprite) {
+		inline function getLevel(i:Object) {
 			var lv = 0;
 			while( i != null ) {
 				i = i.parent;
@@ -300,7 +300,7 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 			}
 			return lv;
 		}
-		inline function indexOf(p:Sprite, i:Sprite) {
+		inline function indexOf(p:Object, i:Object) {
 			var id = -1;
 			for( k in 0...p.children.length )
 				if( p.children[k] == i ) {
@@ -311,12 +311,12 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 		}
 		var level = getLevel(i);
 		for( index in 0...interactive.length ) {
-			var i1 : Sprite = i;
-			var i2 : Sprite = interactive[index];
+			var i1 : Object = i;
+			var i2 : Object = interactive[index];
 			var lv1 = level;
 			var lv2 = getLevel(i2);
-			var p1 : Sprite = i1;
-			var p2 : Sprite = i2;
+			var p1 : Object = i1;
+			var p2 : Object = i2;
 			while( lv1 > lv2 ) {
 				i1 = p1;
 				p1 = p1.parent;
@@ -358,7 +358,7 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 		ctx.elapsedTime = v;
 	}
 
-	function drawImplTo( s : Sprite, t : h3d.mat.Texture ) {
+	function drawImplTo( s : Object, t : h3d.mat.Texture ) {
 
 		if( !t.flags.has(Target) ) throw "Can only draw to texture created with Target flag";
 		var needClear = !t.flags.has(WasCleared);

+ 4 - 779
h2d/Sprite.hx

@@ -1,781 +1,6 @@
 package h2d;
-import hxd.Math;
-
-@:allow(h2d.Tools)
-class Sprite {
-
-	static var nullDrawable : h2d.Drawable;
-
-	var children : Array<Sprite>;
-	var parentContainer : Sprite;
-	public var parent(default, null) : Sprite;
-	public var numChildren(get, never) : Int;
-
-	public var x(default,set) : Float;
-	public var y(default, set) : Float;
-	public var scaleX(default,set) : Float;
-	public var scaleY(default,set) : Float;
-	public var rotation(default, set) : Float;
-	public var visible(default, set) : Bool;
-	public var name : String;
-	public var alpha : Float = 1.;
-
-	public var filter(default,set) : h2d.filter.Filter;
-
-	var matA : Float;
-	var matB : Float;
-	var matC : Float;
-	var matD : Float;
-	var absX : Float;
-	var absY : Float;
-
-	var posChanged : Bool;
-	var allocated : Bool;
-	var lastFrame : Int;
-
-	public function new( ?parent : Sprite ) {
-		matA = 1; matB = 0; matC = 0; matD = 1; absX = 0; absY = 0;
-		x = 0; y = 0; scaleX = 1; scaleY = 1; rotation = 0;
-		posChanged = parent != null;
-		visible = true;
-		children = [];
-		if( parent != null )
-			parent.addChild(this);
-	}
-
-	/**
-		Returns the bounds of the sprite for its whole content, recursively.
-		If relativeTo is null, it will return the bounds in the absolute coordinates.
-		If not, it will return the bounds relative to the specified sprite coordinates.
-		You can pass an already allocated bounds or getBounds will allocate one for you and return it.
-	**/
-	public function getBounds( ?relativeTo : Sprite, ?out : h2d.col.Bounds ) : h2d.col.Bounds {
-		if( out == null ) out = new h2d.col.Bounds() else out.empty();
-		if( relativeTo != null )
-			relativeTo.syncPos();
-		if( relativeTo != this )
-			syncPos();
-		getBoundsRec(relativeTo, out, false);
-		if( out.isEmpty() ) {
-			addBounds(relativeTo, out, -1, -1, 2, 2);
-			out.xMax = out.xMin = (out.xMax + out.xMin) * 0.5;
-			out.yMax = out.yMin = (out.yMax + out.yMin) * 0.5;
-		}
-		return out;
-	}
-
-	/**
-		This is similar to getBounds(parent), but instead of the full content, it will return
-		the size based on the alignement of the Sprite. For instance for a text, getBounds will return
-		the full glyphs size whereas getSize() will ignore the pixels under the baseline.
-	**/
-	public function getSize( ?out : h2d.col.Bounds ) : h2d.col.Bounds {
-		if( out == null ) out = new h2d.col.Bounds() else out.empty();
-		syncPos();
-		getBoundsRec(parent, out, true);
-		if( out.isEmpty() ) {
-			addBounds(parent, out, -1, -1, 2, 2);
-			out.xMax = out.xMin = (out.xMax + out.xMin) * 0.5;
-			out.yMax = out.yMin = (out.yMax + out.yMin) * 0.5;
-		}
-		out.offset( -x, -y);
-		return out;
-	}
-
-	public function find<T>( f : Sprite -> Null<T> ) : Null<T> {
-		var v = f(this);
-		if( v != null )
-			return v;
-		for( o in children ) {
-			var v = o.find(f);
-			if( v != null ) return v;
-		}
-		return null;
-	}
-
-	public function findAll<T>( f : Sprite -> Null<T>, ?arr : Array<T> ) : Array<T> {
-		if( arr == null ) arr = [];
-		var v = f(this);
-		if( v != null )
-			arr.push(v);
-		for( o in children )
-			o.findAll(f,arr);
-		return arr;
-	}
-
-	function set_filter(f : h2d.filter.Filter) {
-		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 ) : Void {
-		if( posChanged ) {
-			calcAbsPos();
-			for( c in children )
-				c.posChanged = true;
-			posChanged = false;
-		}
-		var n = children.length;
-		if( n == 0 ) {
-			out.empty();
-			return;
-		}
-		if( n == 1 ) {
-			var c = children[0];
-			if( c.visible ) c.getBoundsRec(relativeTo, out,forSize) else out.empty();
-			return;
-		}
-		var xmin = hxd.Math.POSITIVE_INFINITY, ymin = hxd.Math.POSITIVE_INFINITY;
-		var xmax = hxd.Math.NEGATIVE_INFINITY, ymax = hxd.Math.NEGATIVE_INFINITY;
-		for( c in children ) {
-			if( !c.visible ) continue;
-			c.getBoundsRec(relativeTo, out, forSize);
-			if( out.xMin < xmin ) xmin = out.xMin;
-			if( out.yMin < ymin ) ymin = out.yMin;
-			if( out.xMax > xmax ) xmax = out.xMax;
-			if( out.yMax > ymax ) ymax = out.yMax;
-		}
-		out.xMin = xmin;
-		out.yMin = ymin;
-		out.xMax = xmax;
-		out.yMax = ymax;
-	}
-
-	function addBounds( relativeTo : Sprite, out : h2d.col.Bounds, dx : Float, dy : Float, width : Float, height : Float ) {
-
-		if( width <= 0 || height <= 0 ) return;
-
-		if( relativeTo == null  ) {
-			var x, y;
-			out.addPos(dx * matA + dy * matC + absX, dx * matB + dy * matD + absY);
-			out.addPos((dx + width) * matA + dy * matC + absX, (dx + width) * matB + dy * matD + absY);
-			out.addPos(dx * matA + (dy + height) * matC + absX, dx * matB + (dy + height) * matD + absY);
-			out.addPos((dx + width) * matA + (dy + height) * matC + absX, (dx + width) * matB + (dy + height) * matD + absY);
-			return;
-		}
-
-		if( relativeTo == this ) {
-			if( out.xMin > dx ) out.xMin = dx;
-			if( out.yMin > dy ) out.yMin = dy;
-			if( out.xMax < dx + width ) out.xMax = dx + width;
-			if( out.yMax < dy + height ) out.yMax = dy + height;
-			return;
-		}
-
-		var r = relativeTo.matA * relativeTo.matD - relativeTo.matB * relativeTo.matC;
-		if( r == 0 )
-			return;
-
-		var det = 1 / r;
-		var rA = relativeTo.matD * det;
-		var rB = -relativeTo.matB * det;
-		var rC = -relativeTo.matC * det;
-		var rD = relativeTo.matA * det;
-		var rX = absX - relativeTo.absX;
-		var rY = absY - relativeTo.absY;
-
-		var x, y;
-
-		x = dx * matA + dy * matC + rX;
-		y = dx * matB + dy * matD + rY;
-		out.addPos(x * rA + y * rC, x * rB + y * rD);
-
-		x = (dx + width) * matA + dy * matC + rX;
-		y = (dx + width) * matB + dy * matD + rY;
-		out.addPos(x * rA + y * rC, x * rB + y * rD);
-
-		x = dx * matA + (dy + height) * matC + rX;
-		y = dx * matB + (dy + height) * matD + rY;
-		out.addPos(x * rA + y * rC, x * rB + y * rD);
-
-		x = (dx + width) * matA + (dy + height) * matC + rX;
-		y = (dx + width) * matB + (dy + height) * matD + rY;
-		out.addPos(x * rA + y * rC, x * rB + y * rD);
-	}
-
-	public function getSpritesCount() : Int {
-		var k = 0;
-		for( c in children )
-			k += c.getSpritesCount() + 1;
-		return k;
-	}
-
-	public function localToGlobal( ?pt : h2d.col.Point ) : h2d.col.Point {
-		syncPos();
-		if( pt == null ) pt = new h2d.col.Point();
-		var px = pt.x * matA + pt.y * matC + absX;
-		var py = pt.x * matB + pt.y * matD + absY;
-		pt.x = px;
-		pt.y = py;
-		return pt;
-	}
-
-	public function globalToLocal( pt : h2d.col.Point ) : h2d.col.Point {
-		syncPos();
-		pt.x -= absX;
-		pt.y -= absY;
-		var invDet = 1 / (matA * matD - matB * matC);
-		var px = (pt.x * matD - pt.y * matC) * invDet;
-		var py = (-pt.x * matB + pt.y * matA) * invDet;
-		pt.x = px;
-		pt.y = py;
-		return pt;
-	}
-
-	function getScene() : Scene {
-		var p = this;
-		while( p.parent != null ) p = p.parent;
-		return Std.instance(p, Scene);
-	}
-
-	function set_visible(b) {
-		if( visible == b )
-			return b;
-		visible = b;
-		onContentChanged();
-		return b;
-	}
-
-	public function addChild( s : Sprite ) : Void {
-		addChildAt(s, children.length);
-	}
-
-	public function addChildAt( s : Sprite, pos : Int ) : Void {
-		if( pos < 0 ) pos = 0;
-		if( pos > children.length ) pos = children.length;
-		var p = this;
-		while( p != null ) {
-			if( p == s ) throw "Recursive addChild";
-			p = p.parent;
-		}
-		if( s.parent != null ) {
-			// prevent calling onRemove
-			var old = s.allocated;
-			s.allocated = false;
-			s.parent.removeChild(s);
-			s.allocated = old;
-		}
-		children.insert(pos, s);
-		if( !allocated && s.allocated )
-			s.onRemove();
-		s.parent = this;
-		s.parentContainer = parentContainer;
-		s.posChanged = true;
-		// ensure that proper alloc/delete is done if we change parent
-		if( allocated ) {
-			if( !s.allocated )
-				s.onAdd();
-			else
-				s.onParentChanged();
-		}
-		onContentChanged();
-	}
-
-	inline function onContentChanged() {
-		if( parentContainer != null ) parentContainer.contentChanged(this);
-	}
-
-	// called when we're allocated already but moved in hierarchy
-	function onParentChanged() {
-		for( c in children )
-			c.onParentChanged();
-	}
-
-	// kept for internal init
-	function onAdd() {
-		allocated = true;
-		if( filter != null )
-			filter.bind(this);
-		for( c in children )
-			c.onAdd();
-	}
-
-	// kept for internal cleanup
-	function onRemove() {
-		allocated = false;
-		if( filter != null )
-			filter.unbind(this);
-		for( c in children )
-			c.onRemove();
-	}
-
-	function getMatrix( m : h2d.col.Matrix ) {
-		m.a = matA;
-		m.b = matB;
-		m.c = matC;
-		m.d = matD;
-		m.x = absX;
-		m.y = absY;
-	}
-
-	public function removeChild( s : Sprite ) {
-		if( children.remove(s) ) {
-			if( s.allocated ) s.onRemove();
-			s.parent = null;
-			if( s.parentContainer != null ) s.setParentContainer(null);
-			s.posChanged = true;
-			onContentChanged();
-		}
-	}
-
-	function setParentContainer( c : Sprite ) {
-		parentContainer = c;
-		for( s in children )
-			s.setParentContainer(c);
-	}
-
-	public function removeChildren() {
-		while( numChildren>0 )
-			removeChild( getChildAt(0) );
-	}
-
-	/**
-		Same as parent.removeChild(this), but does nothing if parent is null.
-		In order to capture add/removal from scene, you can override onAdd/onRemove/onParentChanged
-	**/
-	public inline function remove() {
-		if( this != null && parent != null ) parent.removeChild(this);
-	}
-
-	public function drawTo( t : h3d.mat.Texture ) {
-		var s = getScene();
-		var needDispose = s == null;
-		if( s == null ) s = new h2d.Scene();
-		@:privateAccess s.drawImplTo(this, t);
-		if( needDispose ) s.dispose();
-	}
-
-	function draw( ctx : RenderContext ) {
-	}
-
-	function sync( ctx : RenderContext ) {
-		var changed = posChanged;
-		if( changed ) {
-			calcAbsPos();
-			posChanged = false;
-		}
-
-		lastFrame = ctx.frame;
-		var p = 0, len = children.length;
-		while( p < len ) {
-			var c = children[p];
-			if( c == null )
-				break;
-			if( c.lastFrame != ctx.frame ) {
-				if( changed ) c.posChanged = true;
-				c.sync(ctx);
-			}
-			// if the object was removed, let's restart again.
-			// our lastFrame ensure that no object will get synched twice
-			if( children[p] != c ) {
-				p = 0;
-				len = children.length;
-			} else
-				p++;
-		}
-	}
-
-	function syncPos() {
-		if( parent != null ) parent.syncPos();
-		if( posChanged ) {
-			calcAbsPos();
-			for( c in children )
-				c.posChanged = true;
-			posChanged = false;
-		}
-	}
-
-	function calcAbsPos() {
-		if( parent == null ) {
-			var cr, sr;
-			if( rotation == 0 ) {
-				cr = 1.; sr = 0.;
-				matA = scaleX;
-				matB = 0;
-				matC = 0;
-				matD = scaleY;
-			} else {
-				cr = Math.cos(rotation);
-				sr = Math.sin(rotation);
-				matA = scaleX * cr;
-				matB = scaleX * sr;
-				matC = scaleY * -sr;
-				matD = scaleY * cr;
-			}
-			absX = x;
-			absY = y;
-		} else {
-			// M(rel) = S . R . T
-			// M(abs) = M(rel) . P(abs)
-			if( rotation == 0 ) {
-				matA = scaleX * parent.matA;
-				matB = scaleX * parent.matB;
-				matC = scaleY * parent.matC;
-				matD = scaleY * parent.matD;
-			} else {
-				var cr = Math.cos(rotation);
-				var sr = Math.sin(rotation);
-				var tmpA = scaleX * cr;
-				var tmpB = scaleX * sr;
-				var tmpC = scaleY * -sr;
-				var tmpD = scaleY * cr;
-				matA = tmpA * parent.matA + tmpB * parent.matC;
-				matB = tmpA * parent.matB + tmpB * parent.matD;
-				matC = tmpC * parent.matA + tmpD * parent.matC;
-				matD = tmpC * parent.matB + tmpD * parent.matD;
-			}
-			absX = x * parent.matA + y * parent.matC + parent.absX;
-			absY = x * parent.matB + y * parent.matD + parent.absY;
-		}
-	}
-
-	function emitTile( ctx : RenderContext, tile : h2d.Tile ) {
-		if( nullDrawable == null )
-			nullDrawable = @:privateAccess new h2d.Drawable(null);
-		if( !ctx.hasBuffering() ) {
-			nullDrawable.absX = absX;
-			nullDrawable.absY = absY;
-			nullDrawable.matA = matA;
-			nullDrawable.matB = matB;
-			nullDrawable.matC = matC;
-			nullDrawable.matD = matD;
-			ctx.drawTile(nullDrawable, tile);
-			return;
-		}
-		if( !ctx.beginDrawBatch(nullDrawable, tile.getTexture()) ) return;
-
-		var ax = absX + tile.dx * matA + tile.dy * matC;
-		var ay = absY + tile.dx * matB + tile.dy * matD;
-		var buf = ctx.buffer;
-		var pos = ctx.bufPos;
-		buf.grow(pos + 4 * 8);
-
-		inline function emit(v:Float) buf[pos++] = v;
-
-		emit(ax);
-		emit(ay);
-		emit(tile.u);
-		emit(tile.v);
-		emit(1.);
-		emit(1.);
-		emit(1.);
-		emit(ctx.globalAlpha);
-
-
-		var tw = tile.width;
-		var th = tile.height;
-		var dx1 = tw * matA;
-		var dy1 = tw * matB;
-		var dx2 = th * matC;
-		var dy2 = th * matD;
-
-		emit(ax + dx1);
-		emit(ay + dy1);
-		emit(tile.u2);
-		emit(tile.v);
-		emit(1.);
-		emit(1.);
-		emit(1.);
-		emit(ctx.globalAlpha);
-
-		emit(ax + dx2);
-		emit(ay + dy2);
-		emit(tile.u);
-		emit(tile.v2);
-		emit(1.);
-		emit(1.);
-		emit(1.);
-		emit(ctx.globalAlpha);
-
-		emit(ax + dx1 + dx2);
-		emit(ay + dy1 + dy2);
-		emit(tile.u2);
-		emit(tile.v2);
-		emit(1.);
-		emit(1.);
-		emit(1.);
-		emit(ctx.globalAlpha);
-
-		ctx.bufPos = pos;
-	}
-
-	/**
-		Will clip a local bounds with our global viewport
-	**/
-	function clipBounds( ctx : RenderContext, bounds : h2d.col.Bounds ) {
-		var view = ctx.tmpBounds;
-		var matA, matB, matC, matD, absX, absY;
-		@:privateAccess if( ctx.inFilter != null ) {
-			var f1 = ctx.baseShader.filterMatrixA;
-			var f2 = ctx.baseShader.filterMatrixB;
-			matA = this.matA * f1.x + this.matB * f1.y;
-			matB = this.matA * f2.x + this.matB * f2.y;
-			matC = this.matC * f1.x + this.matD * f1.y;
-			matD = this.matC * f2.x + this.matD * f2.y;
-			absX = this.absX * f1.x + this.absY * f1.y + f1.z;
-			absY = this.absX * f2.x + this.absY * f2.y + f2.z;
-		} else {
-			matA = this.matA;
-			matB = this.matB;
-			matC = this.matC;
-			matD = this.matD;
-			absX = this.absX;
-			absY = this.absY;
-		}
-
-		// intersect our transformed local view with our viewport in global space
-		view.empty();
-		inline function add(x:Float, y:Float) {
-			view.addPos(x * matA + y * matC + absX, x * matB + y * matD + absY);
-		}
-		add(bounds.xMin, bounds.yMin);
-		add(bounds.xMax, bounds.yMin);
-		add(bounds.xMin, bounds.yMax);
-		add(bounds.xMax, bounds.yMax);
-
-		// clip with our scene
-		@:privateAccess {
-			if( view.xMin < ctx.curX ) view.xMin = ctx.curX;
-			if( view.yMin < ctx.curY ) view.yMin = ctx.curY;
-			if( view.xMax > ctx.curX + ctx.curWidth ) view.xMax = ctx.curX + ctx.curWidth;
-			if( view.yMax > ctx.curY + ctx.curHeight ) view.yMax = ctx.curY + ctx.curHeight;
-		}
-
-		// inverse our matrix
-		var invDet = 1 / (matA * matD - matB * matC);
-		inline function add(x:Float, y:Float) {
-			x -= absX;
-			y -= absY;
-			view.addPos((x * matD - y * matC) * invDet, ( -x * matB + y * matA) * invDet);
-		}
-
-		// intersect our resulting viewport with our calculated local space
-		var sxMin = view.xMin;
-		var syMin = view.yMin;
-		var sxMax = view.xMax;
-		var syMax = view.yMax;
-		view.empty();
-		add(sxMin, syMin);
-		add(sxMax, syMin);
-		add(sxMin, syMax);
-		add(sxMax, syMax);
-
-		// intersects
-		bounds.doIntersect(view);
-	}
-
-	function drawFilters( ctx : RenderContext ) {
-		if( !ctx.pushFilter(this) ) return;
-
-		var bounds = ctx.tmpBounds;
-		var total = new h2d.col.Bounds();
-		var maxExtent = -1.;
-		filter.sync(ctx, this);
-		if( filter.autoBounds ) {
-			maxExtent = filter.boundsExtend;
-		} else {
-			filter.getBounds(this, bounds);
-			total.addBounds(bounds);
-		}
-		if( maxExtent >= 0 ) {
-			getBounds(this, bounds);
-			bounds.xMin -= maxExtent;
-			bounds.yMin -= maxExtent;
-			bounds.xMax += maxExtent;
-			bounds.yMax += maxExtent;
-			total.addBounds(bounds);
-		}
-
-		clipBounds(ctx, total);
-
-		var xMin = Math.floor(total.xMin + 1e-10);
-		var yMin = Math.floor(total.yMin + 1e-10);
-		var width = Math.ceil(total.xMax - xMin - 1e-10);
-		var height = Math.ceil(total.yMax - yMin - 1e-10);
-
-		if( width <= 0 || height <= 0 || total.xMax < total.xMin ) return;
-
-		var t = ctx.textures.allocTarget("filterTemp", width, height, false);
-		ctx.pushTarget(t, xMin, yMin, width, height);
-		ctx.engine.clear(0);
-
-		// reset transform and update children
-		var oldAlpha = ctx.globalAlpha;
-		var shader = @:privateAccess ctx.baseShader;
-		var oldA = shader.filterMatrixA.clone();
-		var oldB = shader.filterMatrixB.clone();
-		var oldF = @:privateAccess ctx.inFilter;
-
-		// 2x3 inverse matrix
-		var invDet = 1 / (matA * matD - matB * matC);
-		var invA = matD * invDet;
-		var invB = -matB * invDet;
-		var invC = -matC * invDet;
-		var invD = matA * invDet;
-		var invX = -(absX * invA + absY * invC);
-		var invY = -(absX * invB + absY * invD);
-
-		shader.filterMatrixA.set(invA, invC, invX);
-		shader.filterMatrixB.set(invB, invD, invY);
-		ctx.globalAlpha = 1;
-		draw(ctx);
-		for( c in children )
-			c.drawRec(ctx);
-		ctx.flush();
-
-		var finalTile = h2d.Tile.fromTexture(t);
-		finalTile.dx = xMin;
-		finalTile.dy = yMin;
-
-		var prev = finalTile;
-		finalTile = filter.draw(ctx, finalTile);
-		if( finalTile != prev && finalTile != null ) {
-			finalTile.dx += xMin;
-			finalTile.dy += yMin;
-		}
-
-		shader.filterMatrixA.load(oldA);
-		shader.filterMatrixB.load(oldB);
-
-		ctx.popTarget();
-		ctx.popFilter();
-
-		if( finalTile == null )
-			return;
-
-		ctx.globalAlpha = oldAlpha * alpha;
-		emitTile(ctx, finalTile);
-		ctx.globalAlpha = oldAlpha;
-		ctx.flush();
-	}
-
-	function drawRec( ctx : RenderContext ) {
-		if( !visible ) return;
-		// fallback in case the object was added during a sync() event and we somehow didn't update it
-		if( posChanged ) {
-			// only sync anim, don't update() (prevent any event from occuring during draw())
-			// if( currentAnimation != null ) currentAnimation.sync();
-			calcAbsPos();
-			for( c in children )
-				c.posChanged = true;
-			posChanged = false;
-		}
-		if( filter != null ) {
-			drawFilters(ctx);
-		} else {
-			var old = ctx.globalAlpha;
-			ctx.globalAlpha *= alpha;
-			if( ctx.front2back ) {
-				var nchilds = children.length;
-				for (i in 0...nchilds) children[nchilds - 1 - i].drawRec(ctx);
-				draw(ctx);
-			} else {
-				draw(ctx);
-				for( c in children ) c.drawRec(ctx);
-			}
-			ctx.globalAlpha = old;
-		}
-	}
-
-	inline function set_x(v) {
-		posChanged = true;
-		return x = v;
-	}
-
-	inline function set_y(v) {
-		posChanged = true;
-		return y = v;
-	}
-
-	inline function set_scaleX(v) {
-		posChanged = true;
-		return scaleX = v;
-	}
-
-	inline function set_scaleY(v) {
-		posChanged = true;
-		return scaleY = v;
-	}
-
-	inline function set_rotation(v) {
-		posChanged = true;
-		return rotation = v;
-	}
-
-	public function move( dx : Float, dy : Float ) {
-		x += dx * Math.cos(rotation);
-		y += dy * Math.sin(rotation);
-	}
-
-	public inline function setPosition( x : Float, y : Float ) {
-		this.x = x;
-		this.y = y;
-	}
-
-	public inline function rotate( v : Float ) {
-		rotation += v;
-	}
-
-	public inline function scale( v : Float ) {
-		scaleX *= v;
-		scaleY *= v;
-	}
-
-	public inline function setScale( v : Float ) {
-		scaleX = v;
-		scaleY = v;
-	}
-
-	public inline function getChildAt( n ) {
-		return children[n];
-	}
-
-	public function getChildIndex( s ) {
-		for( i in 0...children.length )
-			if( children[i] == s )
-				return i;
-		return -1;
-	}
-
-	public function getSpriteByName( name : String ) {
-		if( this.name == name )
-			return this;
-		for( c in children ) {
-			var o = c.getSpriteByName(name);
-			if( o != null ) return o;
-		}
-		return null;
-	}
-
-	inline function get_numChildren() {
-		return children.length;
-	}
-
-	public inline function iterator() {
-		return new hxd.impl.ArrayIterator(children);
-	}
-
-	function toString() {
-		var c = Type.getClassName(Type.getClass(this));
-		return name == null ? c : name + "(" + c + ")";
-	}
-
-	// ---- additional methods for containers (h2d.Flow)
-
-	/**
-		This is called by our children if we have defined their parentContainer when they get resized
-	**/
-	function contentChanged( s : Sprite ) {
-	}
-
-	/**
-		This can be called by a parent container to constraint the size of its children.
-		Negative value mean that constraint is to be disable.
-	**/
-	function constraintSize( maxWidth : Float, maxHeight : Float ) {
-	}
-
-}
 
+#if !heaps_sprite
+@:deprecated("h2d.Sprite is now h2d.Object, rename or use -D heaps-sprite") 
+#end 
+typedef Sprite = Object;

+ 3 - 3
h2d/Text.hx

@@ -37,7 +37,7 @@ class Text extends Drawable {
 	var waShader : h3d.shader.WhiteAlpha;
 	#end
 
-	public function new( font : Font, ?parent : h2d.Sprite ) {
+	public function new( font : Font, ?parent : h2d.Object ) {
 		super(parent);
 		this.font = font;
 		textAlign = Left;
@@ -233,7 +233,7 @@ class Text extends Drawable {
 			var offs = e.getKerningOffset(prevChar);
 			var esize = e.width + offs;
 			// if the next word goes past the max width, change it into a newline
-			
+
 			if( cc == '\n'.code ) {
 				if( x > xMax ) xMax = x;
 				if( calcLines ) lines.push(x);
@@ -308,7 +308,7 @@ class Text extends Drawable {
 		return c;
 	}
 
-	override function getBoundsRec( relativeTo : Sprite, out : h2d.col.Bounds, forSize : Bool ) {
+	override function getBoundsRec( relativeTo : Object, out : h2d.col.Bounds, forSize : Bool ) {
 		super.getBoundsRec(relativeTo, out, forSize);
 		updateSize();
 		var x, y, w : Float, h;

+ 2 - 2
h2d/TileGroup.hx

@@ -393,7 +393,7 @@ class TileGroup extends Drawable {
 	public var rangeMin : Int;
 	public var rangeMax : Int;
 
-	public function new(t : Tile, ?parent : h2d.Sprite) {
+	public function new(t : Tile, ?parent : h2d.Object) {
 		super(parent);
 		tile = t;
 		rangeMin = rangeMax = -1;
@@ -401,7 +401,7 @@ class TileGroup extends Drawable {
 		content = new TileLayerContent();
 	}
 
-	override function getBoundsRec( relativeTo : Sprite, out : h2d.col.Bounds, forSize : Bool ) {
+	override function getBoundsRec( relativeTo : Object, out : h2d.col.Bounds, forSize : Bool ) {
 		super.getBoundsRec(relativeTo, out, forSize);
 		addBounds(relativeTo, out, content.xMin, content.yMin, content.xMax - content.xMin, content.yMax - content.yMin);
 	}

+ 10 - 10
h2d/ZGroup.hx

@@ -28,7 +28,7 @@ private class State {
 }
 
 private class DepthEntry {
-	public var spr   : Sprite;
+	public var spr   : Object;
 	public var depth : Float;
 	public var keep  : Bool;
 	public var next  : DepthEntry;
@@ -36,7 +36,7 @@ private class DepthEntry {
 }
 
 class DepthMap {
-	var map      : Map<Sprite, DepthEntry>;
+	var map      : Map<Object, DepthEntry>;
 	var curIndex : Int;
 	var free     : DepthEntry;
 	var first    : DepthEntry;
@@ -45,7 +45,7 @@ class DepthMap {
 		map = new Map();
 	}
 
-	function push(spr : Sprite) {
+	function push(spr : Object) {
 		var e = map.get(spr);
 		if (e == null) {
 			if (free != null) {
@@ -64,7 +64,7 @@ class DepthMap {
 		e.depth = curIndex++;
 	}
 
-	function populate(spr : Sprite) {
+	function populate(spr : Object) {
 		for (c in spr) {
 			if (!c.visible) continue;
 			push(c);
@@ -72,7 +72,7 @@ class DepthMap {
 		}
 	}
 
-	public function build(spr : Sprite) {
+	public function build(spr : Object) {
 		curIndex = 0;
 
 		var e = first;
@@ -105,7 +105,7 @@ class DepthMap {
 		}
 	}
 
-	inline public function getDepth(spr : Sprite) {
+	inline public function getDepth(spr : Object) {
 		return map.get(spr).depth;
 	}
 
@@ -125,8 +125,8 @@ class ZGroup extends Layers
 	var normalState : State;
 	var transpState : State;
 	var opaqueState : State;
-	var onEnterFilterCached : Sprite -> Bool;
-	var onLeaveFilterCached : Sprite -> Void;
+	var onEnterFilterCached : Object -> Bool;
+	var onLeaveFilterCached : Object -> Void;
 
 	public function new(?p) {
 		super(p);
@@ -190,13 +190,13 @@ class ZGroup extends Layers
 		return true;
 	}
 
-	function onEnterFilter(spr : Sprite) {
+	function onEnterFilter(spr : Object) {
 		if (ctx.front2back) return false; // opaque pass : do not render the filter
 		normalState.applyTo(ctx);
 		return true;
 	}
 
-	function onLeaveFilter(spr : Sprite) {
+	function onLeaveFilter(spr : Object) {
 		transpState.applyTo(ctx);
 	}
 }

+ 6 - 6
h2d/filter/AbstractMask.hx

@@ -24,9 +24,9 @@ class AbstractMask extends Filter {
 	var hide : Hide;
 	var maskMatrix : h2d.col.Matrix;
 	var tmpMatrix : h2d.col.Matrix;
-	var obj : h2d.Sprite;
+	var obj : h2d.Object;
 	var bindCount : Int;
-	public var mask(default, set) : h2d.Sprite;
+	public var mask(default, set) : h2d.Object;
 	public var maskVisible(default, set) : Bool;
 
 	function new(mask) {
@@ -42,19 +42,19 @@ class AbstractMask extends Filter {
 		return maskVisible = b;
 	}
 
-	override function bind(s:Sprite) {
+	override function bind(s:Object) {
 		bindCount++;
 		if( bindCount == 1 )
 			this.mask = mask;
 	}
 
-	override function unbind(s:Sprite) {
+	override function unbind(s:Object) {
 		bindCount--;
 		if( bindCount == 0 )
 			this.mask = mask;
 	}
 
-	function set_mask(m:h2d.Sprite) {
+	function set_mask(m:h2d.Object) {
 		if( mask != null ) {
 			if( mask.filter == hide )
 				mask.filter = null;
@@ -95,7 +95,7 @@ class AbstractMask extends Filter {
 		return t;
 	}
 
-	override function sync( ctx : RenderContext, obj : h2d.Sprite ) {
+	override function sync( ctx : RenderContext, obj : h2d.Object ) {
 		this.obj = obj;
 		if( mask == null || hide.frame != ctx.frame ) {
 			var p = obj;

+ 1 - 1
h2d/filter/Blur.hx

@@ -39,7 +39,7 @@ class Blur extends Filter {
 	inline function get_linear() return pass.linear;
 	inline function set_linear(v) return pass.linear = v;
 
-	override function sync( ctx : RenderContext, s : Sprite ) {
+	override function sync( ctx : RenderContext, s : Object ) {
 		boundsExtend = radius * 2;
 	}
 

+ 4 - 4
h2d/filter/Filter.hx

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

+ 4 - 4
h2d/filter/Group.hx

@@ -9,17 +9,17 @@ class Group extends Filter {
 		this.filters = filters.copy();
 	}
 
-	override function bind(s:Sprite) {
+	override function bind(s:Object) {
 		for( f in filters )
 			f.bind(s);
 	}
 
-	override function unbind(s:Sprite) {
+	override function unbind(s:Object) {
 		for( f in filters )
 			f.unbind(s);
 	}
 
-	override function sync( ctx:RenderContext, s : Sprite ) {
+	override function sync( ctx:RenderContext, s : Object ) {
 		this.autoBounds = true;
 		this.boundsExtend = 0;
 		for( f in filters ) {
@@ -31,7 +31,7 @@ class Group extends Filter {
 		}
 	}
 
-	override function getBounds(s:Sprite, bounds:h2d.col.Bounds) {
+	override function getBounds(s:Object, bounds:h2d.col.Bounds) {
 		for( f in filters )
 			if( !f.autoBounds )
 				f.getBounds(s, bounds);

+ 2 - 2
hxd/fmt/pak/Loader.hx

@@ -1,6 +1,6 @@
 package hxd.fmt.pak;
 
-class Loader extends h2d.Sprite {
+class Loader extends h2d.Object {
 
 	var onDone : Void -> Void;
 	var cur : hxd.net.BinaryLoader;
@@ -52,7 +52,7 @@ class Loader extends h2d.Sprite {
 					onDone();
 				}
 				return;
-			} 
+			}
 			fs.addPak(f);
 			resCount++;
 			f.close();

+ 1 - 1
hxd/prefab/Context.hx

@@ -2,7 +2,7 @@ package hxd.prefab;
 
 @:final class Context {
 
-	public var local2d : h2d.Sprite;
+	public var local2d : h2d.Object;
 	public var local3d : h3d.scene.Object;
 	public var shared : ContextShared;
 	public var cleanup : Void -> Void;

+ 2 - 2
hxd/prefab/ContextShared.hx

@@ -8,7 +8,7 @@ typedef ShaderDef = {
 typedef ShaderDefCache = Map<String, ShaderDef>;
 
 class ContextShared {
-	public var root2d : h2d.Sprite;
+	public var root2d : h2d.Object;
 	public var root3d : h3d.scene.Object;
 	public var contexts : Map<Prefab,Context>;
 	public var references : Map<Prefab,Array<Context>>;
@@ -20,7 +20,7 @@ class ContextShared {
 	var bakedData : Map<String, haxe.io.Bytes>;
 
 	public function new() {
-		root2d = new h2d.Sprite();
+		root2d = new h2d.Object();
 		root3d = new h3d.scene.Object();
 		contexts = new Map();
 		references = new Map();