Nicolas Cannasse 11 роки тому
батько
коміт
4587579013

+ 7 - 0
all.hxml

@@ -0,0 +1,7 @@
+-js heaps.js
+-lib heaps
+--macro include('h3d')
+--macro include('h2d')
+--macro include('hxsl',true,['hxsl.Macros'])
+--macro include('hxd',true,['hxd.res.FileTree','hxd.Res','hxd.impl.BitsBuilder'])
+--no-output

+ 15 - 25
h2d/CachedBitmap.hx

@@ -2,14 +2,11 @@ package h2d;
 
 class CachedBitmap extends Drawable {
 
-	var tex : h3d.mat.Texture;
 	public var width(default, set) : Int;
 	public var height(default, set) : Int;
 	public var freezed : Bool;
 	
 	var renderDone : Bool;
-	var realWidth : Int;
-	var realHeight : Int;
 	var tile : Tile;
 	
 	public function new( ?parent, width = -1, height = -1 ) {
@@ -19,11 +16,10 @@ class CachedBitmap extends Drawable {
 	}
 
 	function clean() {
-		if( tex != null ) {
-			tex.dispose();
-			tex = null;
+		if( tile != null ) {
+			tile.dispose();
+			tile = null;
 		}
-		tile = null;
 	}
 
 	override function onDelete() {
@@ -38,25 +34,20 @@ class CachedBitmap extends Drawable {
 	}
 
 	function set_height(h) {
-		if( tex != null ) {
-			tex.dispose();
-			tex = null;
-		}
+		clean();
 		height = h;
 		return h;
 	}
 	
 	public function getTile() {
 		if( tile == null ) {
-			var tw = 1, th = 1;
-			var engine = h3d.Engine.getCurrent();
-			realWidth = width < 0 ? engine.width : width;
-			realHeight = height < 0 ? engine.height : height;
-			while( tw < realWidth ) tw <<= 1;
-			while( th < realHeight ) th <<= 1;
-			tex = engine.mem.allocTargetTexture(tw, th);
+			var scene = getScene();
+			if( scene == null ) return null;
+			var tw = width < 0 ? scene.width : width;
+			var th = height < 0 ? scene.height : height;
+			var tex = new h3d.mat.Texture(tw, th, [Target]);
 			renderDone = false;
-			tile = new Tile(tex,0, 0, realWidth, realHeight);
+			tile = Tile.fromTexture(tex);
 		}
 		return tile;
 	}
@@ -72,7 +63,8 @@ class CachedBitmap extends Drawable {
 				c.posChanged = true;
 			posChanged = false;
 		}
-		if( tex != null && ((width < 0 && tex.width < ctx.engine.width) || (height < 0 && tex.height < ctx.engine.height)) )
+		var scene = getScene();
+		if( tile != null && ((width < 0 && scene.width != tile.width) || (height < 0 && scene.height != tile.height)) )
 			clean();
 		var tile = getTile();
 		if( !freezed || !renderDone ) {
@@ -87,8 +79,8 @@ class CachedBitmap extends Drawable {
 			absY = 0;
 			
 			// adds a pixels-to-viewport transform
-			var w = 2 / tex.width;
-			var h = -2 / tex.height;
+			var w = 2 / tile.width;
+			var h = -2 / tile.height;
 			absX = absX * w - 1;
 			absY = absY * h + 1;
 			matA *= w;
@@ -103,12 +95,10 @@ class CachedBitmap extends Drawable {
 			}
 
 			throw "Should not draw in sync!";
-			ctx.engine.setTarget(tex);
-			ctx.engine.setRenderZone(0, 0, realWidth, realHeight);
+			ctx.engine.setTarget(tile.getTexture());
 			for( c in childs )
 				c.drawRec(ctx);
 			ctx.engine.setTarget(null);
-			ctx.engine.setRenderZone();
 			
 			// restore
 			matA = oldA;

+ 8 - 2
h2d/Interactive.hx

@@ -6,7 +6,13 @@ class Interactive extends Drawable {
 	public var height : Float;
 	public var cursor(default,set) : hxd.System.Cursor;
 	public var isEllipse : Bool;
-	public var blockEvents : Bool = true;
+	/**
+		Set the default `cancel` mode (see `hxd.Event`), default to false.
+	**/
+	public var cancelEvents : Bool = false;
+	/**
+		Set the default `propagate` mode (see `hxd.Event`), default to false.
+	**/
 	public var propagateEvents : Bool = false;
 	public var backgroundColor : Null<Int>;
 	public var enableRightButton : Bool;
@@ -79,7 +85,7 @@ class Interactive extends Drawable {
 			}
 		}
 		if( propagateEvents ) e.propagate = true;
-		if( !blockEvents ) e.cancel = true;
+		if( cancelEvents ) e.cancel = true;
 		switch( e.kind ) {
 		case EMove:
 			onMove(e);

+ 19 - 0
h2d/Layers.hx

@@ -51,6 +51,25 @@ class Layers extends Sprite {
 		}
 	}
 	
+	public function under( s : Sprite ) {
+		for( i in 0...childs.length )
+			if( childs[i] == s ) {
+				var pos = 0;
+				for( l in layers )
+					if( l > i )
+						break;
+					else
+						pos = l;
+				var p = i;
+				while( p > pos ) {
+					childs[p] = childs[p - 1];
+					p--;
+				}
+				childs[pos] = s;
+				break;
+			}
+	}
+
 	public function over( s : Sprite ) {
 		for( i in 0...childs.length )
 			if( childs[i] == s ) {

+ 12 - 17
h2d/Scene.hx

@@ -99,24 +99,15 @@ class Scene extends Layers implements h3d.IDrawable {
 		case EPush: cancelFocus = true; checkPush = true;
 		case ERelease: checkPush = true;
 		case EKeyUp, EKeyDown, EWheel:
-			if( currentFocus != null )
+			if( currentFocus != null ) {
 				currentFocus.handleEvent(event);
-			else {
-				if( currentOver != null ) {
-					event.propagate = true;
-					currentOver.handleEvent(event);
-					if( !event.propagate ) return;
-				}
-				dispatchListeners(event);
+				if( !event.propagate )
+					return;
 			}
-			return;
 		default:
 		}
 		for( i in interactive ) {
 			
-
-			// TODO : we are not sure that the positions are correctly updated !
-			
 			// this is a bit tricky since we are not in the not-euclide viewport space
 			// (r = ratio correction)
 			var dx = rx - i.absX;
@@ -252,13 +243,20 @@ class Scene extends Layers implements h3d.IDrawable {
 					continue;
 			}
 			emitEvent(e);
+			/*
+				We want to make sure that after we have pushed, we send a release even if the mouse
+				has been outside of the Interactive (release outside). We will reset the mouse button
+				to prevent click to be generated
+			*/
 			if( e.kind == ERelease && pushList.length > 0 ) {
 				for( i in pushList ) {
 					// relX/relY is not correct here
 					if( i == null )
 						dispatchListeners(e);
-					else
+					else {
+						@:privateAccess i.isMouseDown = -1;
 						i.handleEvent(e);
+					}
 				}
 				pushList = new Array();
 			}
@@ -431,10 +429,7 @@ class Scene extends Layers implements h3d.IDrawable {
 	public function captureBitmap( ?target : Tile ) {
 		var engine = h3d.Engine.getCurrent();
 		if( target == null ) {
-			var tw = 1, th = 1;
-			while( tw < width ) tw <<= 1;
-			while( th < height ) th <<= 1;
-			var tex = engine.mem.allocTargetTexture(tw, th);
+			var tex = new h3d.mat.Texture(width, height, [Target]);
 			target = new Tile(tex,0, 0, width, height);
 		}
 		engine.begin();

+ 4 - 6
h2d/Tile.hx

@@ -32,9 +32,7 @@ class Tile {
 		if( tex != null ) setTexture(tex);
 	}
 	
-	public function getTexture() {
-		if( innerTex == null || innerTex.isDisposed() )
-			return h3d.mat.Texture.fromColor(0xFFFF00FF);
+	public inline function getTexture() {
 		return innerTex;
 	}
 	
@@ -153,7 +151,7 @@ class Tile {
 	
 
 	public static function fromColor( color : Int, ?width = 1, ?height = 1, ?allocPos : h3d.impl.AllocPos ) {
-		var t = new Tile(h3d.mat.Texture.fromColor(color), 0, 0, 1, 1);
+		var t = new Tile(h3d.mat.Texture.fromColor(color,allocPos),0,0,1,1);
 		// scale to size
 		t.width = width;
 		t.height = height;
@@ -166,7 +164,7 @@ class Tile {
 			w <<= 1;
 		while( h < bmp.height )
 			h <<= 1;
-		var tex = h3d.Engine.getCurrent().mem.allocTexture(w, h, false, allocPos);
+		var tex = new h3d.mat.Texture(w, h, allocPos);
 		var t = new Tile(tex, 0, 0, bmp.width, bmp.height);
 		t.upload(bmp);
 		return t;
@@ -184,7 +182,7 @@ class Tile {
 			w <<= 1;
 		while( h < bmp.height )
 			h <<= 1;
-		var tex = h3d.Engine.getCurrent().mem.allocTexture(w, h, false, allocPos);
+		var tex = new h3d.mat.Texture(w, h, allocPos);
 		for( y in 0...Std.int(bmp.height / height) ) {
 			var a = [];
 			tl[y] = a;

+ 4 - 0
h2d/col/Seg.hx

@@ -11,6 +11,10 @@ class Seg {
 	public var invLenSq : Float;
 	
 	public inline function new( p1 : Point, p2 : Point ) {
+		setPoints(p1, p2);
+	}
+	
+	public inline function setPoints( p1 : Point, p2 : Point ) {
 		x = p1.x;
 		y = p1.y;
 		dx = p2.x - x;

+ 1 - 1
h2d/comp/Slider.hx

@@ -12,7 +12,7 @@ class Slider extends Component {
 	public function new(?parent) {
 		super("slider", parent);
 		cursor = new Button("", this);
-		cursor.input.blockEvents = false;
+		cursor.input.cancelEvents = true;
 		cursor.onMouseDown = function() {
 			
 		};

+ 2 - 2
h2d/css/default.css

@@ -71,8 +71,8 @@ slider {
 }
 
 slider button, slider button:hover {
-	margin-top : -4px;
-	padding : 5px 2px;
+	margin-top : -5px;
+	padding : 0px 2px;
 }
 
 checkbox {

+ 8 - 19
h3d/Engine.hx

@@ -102,25 +102,13 @@ class Engine {
 	}
 
 	public inline function renderTriBuffer( b : h3d.impl.Buffer, start = 0, max = -1 ) {
-		return renderBuffer(b, mem.indexes, 3, start, max);
+		return renderBuffer(b, mem.triIndexes, 3, start, max);
 	}
 	
 	public inline function renderQuadBuffer( b : h3d.impl.Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.quadIndexes, 2, start, max);
 	}
 	
-	public function enableDriver( ?b : Bool ) {
-		if( b == null )
-			b = Std.is(driver, h3d.impl.NullDriver);
-		if( b ) {
-			var d = Std.instance(driver, h3d.impl.NullDriver);
-			if( d != null )
-				driver = d.driver;
-		} else if( !Std.is(driver,h3d.impl.NullDriver) ) {
-			driver = new h3d.impl.NullDriver(driver);
-		}
-	}
-
 	// we use preallocated indexes so all the triangles are stored inside our buffers
 	function renderBuffer( b : h3d.impl.Buffer, indexes : h3d.impl.Indexes, vertPerTri : Int, startTri = 0, drawTri = -1 ) {
 		if( indexes.isDisposed() )
@@ -258,7 +246,8 @@ class Engine {
 		shaderSwitches = 0;
 		drawCalls = 0;
 		curProjMatrix = null;
-		driver.reset();
+		currentTarget = null;
+		driver.begin(frameCount);
 		return true;
 	}
 
@@ -272,15 +261,15 @@ class Engine {
 		curProjMatrix = null;
 	}
 	
-	var currentTarget : Bool;
+	var currentTarget : h3d.mat.Texture;
 	
-	public function hasTarget() {
+	public function getTarget() {
 		return currentTarget;
 	}
 
-	public function setTarget( tex : h3d.mat.Texture, useDepth = false, clearColor = 0 ) {
-		currentTarget = tex != null;
-		driver.setRenderTarget(tex == null ? null : tex.t, useDepth, clearColor);
+	public function setTarget( tex : h3d.mat.Texture, clearColor = 0 ) {
+		currentTarget = tex;
+		driver.setRenderTarget(tex, clearColor);
 	}
 
 	public function setRenderZone( x = 0, y = 0, width = -1, height = -1 ) {

+ 11 - 0
h3d/col/Bounds.hx

@@ -280,5 +280,16 @@ class Bounds {
 		b.setMax(max);
 		return b;
 	}
+
+	public static inline function fromValues( x : Float, y : Float, z : Float, dx : Float, dy : Float, dz : Float ) {
+		var b = new Bounds();
+		b.xMin = x;
+		b.yMin = y;
+		b.zMin = z;
+		b.xMax = x + dx;
+		b.yMax = y + dy;
+		b.zMax = z + dz;
+		return b;
+	}
 	
 }

+ 0 - 68
h3d/impl/DebugGL.hx

@@ -1,68 +0,0 @@
-package h3d.impl;
-
-#if js
-private typedef GL = js.html.webgl.GL;
-#elseif cpp
-import openfl.gl.GL;
-#end
-
-#if (!macro && (js || cpp))
-@:build(h3d.impl.DebugGL.buildProxy())
-#end
-class DebugGL {
-	
-	
-	#if macro
-	static function buildProxy() {
-		var gl = haxe.macro.Context.getType("GL");
-		var fields = [];
-		var pos = haxe.macro.Context.currentPos();
-		switch( gl ) {
-		case TInst(cl, _):
-			for( f in cl.get().statics.get() ) {
-				var fname = f.name;
-				if( !f.isPublic ) continue;
-				switch( f.kind ) {
-				case FVar(_):
-					if( fname.toUpperCase() == fname )
-						fields.push((macro class { public static var $fname = GL.$fname; } ).fields[0] );
-				case FMethod(_):
-					switch( haxe.macro.Context.follow(f.type) ) {
-					case TFun(args, ret):
-						var eargs = [for( a in args ) macro $i { a.name } ];
-						var expr = if( haxe.macro.TypeTools.toString(haxe.macro.Context.follow(ret)) == "Void" )
-							macro {
-								GL.$fname($a{eargs});
-								haxe.Log.trace($v { fname } + ([$a { eargs } ] : Array<Dynamic>), _pos);
-							};
-						else
-							macro {
-								var r = GL.$fname($a { eargs } );
-								haxe.Log.trace($v{fname} + ([$a{eargs}] : Array<Dynamic>) + "=" + r, _pos);
-								return r;
-							};
-						var fargs = [for( a in args ) { name : a.name, opt : false, type : null, value : null } ];
-						fargs.push( { name : "_pos", opt : true, type : macro : haxe.PosInfos, value : null } );
-						fields.push({
-							name : fname,
-							access : [APublic, AStatic],
-							meta : [],
-							pos : pos,
-							kind : FFun( {
-								ret : null,
-								args : fargs,
-								params : [],
-								expr : expr,
-							}),
-						});
-					default:
-					}
-				}
-			}
-		default:
-		}
-		return fields;
-	}
-	#end
-	
-}

+ 4 - 1
h3d/impl/Driver.hx

@@ -27,6 +27,9 @@ class Driver {
 	public function dispose() {
 	}
 	
+	public function begin( frame : Int ) {
+	}
+	
 	public function clear( r : Float, g : Float, b : Float, a : Float ) {
 	}
 	
@@ -71,7 +74,7 @@ class Driver {
 	public function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
 	}
 	
-	public function setRenderTarget( tex : Null<Texture>, useDepth : Bool, clearColor : Int ) {
+	public function setRenderTarget( tex : Null<h3d.mat.Texture>, clearColor : Int ) {
 	}
 	
 	public function present() {

+ 26 - 18
h3d/impl/GlDriver.hx

@@ -55,7 +55,8 @@ class GlDriver extends Driver {
 	var curProgram : CompiledProgram;
 	var curMatBits : Int;
 	var programs : Map<Int, CompiledProgram>;
-	var hasTarget : Bool;
+	var hasTargetFlip : Bool;
+	var frame : Int;
 	
 	public function new() {
 		#if js
@@ -77,10 +78,15 @@ class GlDriver extends Driver {
 		selectMaterialBits(0);
 	}
 	
+	override function begin(frame) {
+		this.frame = frame;
+		reset();
+	}
+	
 	override function reset() {
 		gl.useProgram(null);
 		curProgram = null;
-		hasTarget = false;
+		hasTargetFlip = false;
 	}
 	
 	override function getShaderInputNames() {
@@ -190,14 +196,12 @@ class GlDriver extends Driver {
 	}
 	
 	function selectMaterialBits( bits : Int ) {
-		/*
-		if( hasTarget ) {
+		if( hasTargetFlip ) {
 			// switch culling font/back
 			var c = Pass.getCulling(bits);
 			if( c == 1 ) c = 2 else if( c == 2 ) c = 1;
 			bits = (bits & ~Pass.culling_mask) | (c << Pass.culling_offset);
 		}
-		*/
 		var diff = bits ^ curMatBits;
 		if( diff == 0 )
 			return;
@@ -277,14 +281,22 @@ class GlDriver extends Driver {
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
 		var tt = gl.createTexture();
 		var tt : Texture = { t : tt, width : t.width, height : t.height };
+		t.lastFrame = frame;
 		gl.bindTexture(GL.TEXTURE_2D, tt.t);
 		gl.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, tt.width, tt.height, 0, GL.RGBA, GL.UNSIGNED_BYTE, null);
-		if( t.isTarget ) {
+		if( t.flags.has(Target) ) {
 			var fb = gl.createFramebuffer();
 			gl.bindFramebuffer(GL.FRAMEBUFFER, fb);
 			gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, tt.t, 0);
-			gl.bindFramebuffer(GL.FRAMEBUFFER, null);
 			tt.fb = fb;
+			if( t.flags.has(TargetDepth) ) {
+				tt.rb = gl.createRenderbuffer();
+				gl.bindRenderbuffer(GL.RENDERBUFFER, tt.rb);
+				gl.renderbufferStorage(GL.RENDERBUFFER, GL.DEPTH_COMPONENT16, tt.width, tt.height);
+				gl.framebufferRenderbuffer(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, tt.rb);
+				gl.bindRenderbuffer(GL.RENDERBUFFER, null);
+			}
+			gl.bindFramebuffer(GL.FRAMEBUFFER, null);
 		}
 		gl.bindTexture(GL.TEXTURE_2D, null);
 		return tt;
@@ -425,23 +437,19 @@ class GlDriver extends Driver {
 		return gl.isContextLost();
 	}
 	
-	override function setRenderTarget( tex : h3d.impl.Texture, useDepth : Bool, clearColor : Int ) {
+	override function setRenderTarget( tex : h3d.mat.Texture, clearColor : Int ) {
 		if( tex == null ) {
 			gl.bindFramebuffer(GL.FRAMEBUFFER, null);
 			gl.viewport(0, 0, canvas.width, canvas.height);
-			hasTarget = false;
+			hasTargetFlip = false;
 			return;
 		}
-		hasTarget = true;
-		gl.bindFramebuffer(GL.FRAMEBUFFER, tex.fb);
+		if( tex.t == null )
+			tex.alloc();
+		tex.lastFrame = frame;
+		hasTargetFlip = !tex.flags.has(TargetNoFlipY);
+		gl.bindFramebuffer(GL.FRAMEBUFFER, tex.t.fb);
 		gl.viewport(0, 0, tex.width, tex.height);
-		if( useDepth && tex.rb == null ) {
-			tex.rb = gl.createRenderbuffer();
-			gl.bindRenderbuffer(GL.RENDERBUFFER, tex.rb);
-			gl.renderbufferStorage(GL.RENDERBUFFER, GL.DEPTH_COMPONENT16, tex.width, tex.height);
-			gl.framebufferRenderbuffer(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, tex.rb);
-			gl.bindRenderbuffer(GL.RENDERBUFFER, null);
-		}
 		clear(((clearColor >> 16) & 0xFF) / 255, ((clearColor >> 8) & 0xFF) / 255, (clearColor & 0xFF) / 255, (clearColor >>> 24) / 255);
 	}
 

+ 53 - 146
h3d/impl/MemoryManager.hx

@@ -89,23 +89,21 @@ class MemoryManager {
 	@:allow(h3d)
 	var driver : Driver;
 	var buffers : Array<BigBuffer>;
-	var idict : Map<Indexes,Bool>;
+	var indexes : Array<Indexes>;
+	var textures : Array<h3d.mat.Texture>;
 	
-	var tdict : WeakMap<h3d.mat.Texture,Driver.Texture>;
-	var textures : Array<Driver.Texture>;
-	
-	public var indexes(default,null) : Indexes;
+	public var triIndexes(default,null) : Indexes;
 	public var quadIndexes(default,null) : Indexes;
-	public var usedMemory(default,null) : Int;
-	public var bufferCount(default,null) : Int;
+	public var usedMemory(default, null) : Int = 0;
+	public var texMemory(default, null) : Int = 0;
+	public var bufferCount(default,null) : Int = 0;
 	public var allocSize(default,null) : Int;
 
 	public function new(driver,allocSize) {
 		this.driver = driver;
 		this.allocSize = allocSize;
 
-		idict = new Map();
-		tdict = new WeakMap();
+		indexes = new Array();
 		textures = new Array();
 		buffers = new Array();
 		
@@ -115,7 +113,7 @@ class MemoryManager {
 	function initIndexes() {
 		var indices = new hxd.IndexBuffer();
 		for( i in 0...allocSize ) indices.push(i);
-		indexes = allocIndex(indices);
+		triIndexes = allocIndex(indices);
 
 		var indices = new hxd.IndexBuffer();
 		var p = 0;
@@ -175,18 +173,12 @@ class MemoryManager {
 				b = b.next;
 			}
 		}
-		freeTextures();
-		var tcount = 0, tmem = 0;
-		for( t in tdict.keys() ) {
-			tcount++;
-			tmem += t.width * t.height * 4;
-		}
 		return {
 			bufferCount : count,
 			freeMemory : free,
 			totalMemory : total,
-			textureCount : tcount,
-			textureMemory : tmem,
+			textureCount : textures.length,
+			textureMemory : texMemory,
 		};
 	}
 
@@ -215,7 +207,7 @@ class MemoryManager {
 				buf = buf.next;
 			}
 		}
-		for( t in tdict.keys() ) {
+		for( t in textures ) {
 			var key = "$"+t.allocPos.fileName + ":" + t.allocPos.lineNumber;
 			var inf = h.get(key);
 			if( inf == null ) {
@@ -224,111 +216,68 @@ class MemoryManager {
 				all.push(inf);
 			}
 			inf.count++;
-			inf.size += t.width * t.height * 4;
+			inf.size += t.width * t.height * bpp(t);
 		}
 		all.sort(function(a, b) return a.size == b.size ? a.line - b.line : b.size - a.size);
 		return all;
 		#end
 	}
 	
-	function newTexture(fmt, w, h, cubic, target, mm, allocPos) {
-		var t = new h3d.mat.Texture(this, fmt, w, h, cubic, target, mm);
-		#if debug
-		t.allocPos = allocPos;
-		#end
-		initTexture(t);
-		return t;
-	}
-	
-	function initTexture( t : h3d.mat.Texture ) {
-		t.t = driver.allocTexture(t);
-		tdict.set(t, t.t);
-		textures.push(t.t);
-	}
-
 	@:allow(h3d.impl.Indexes.dispose)
 	function deleteIndexes( i : Indexes ) {
-		idict.remove(i);
+		indexes.remove(i);
 		driver.disposeIndexes(i.ibuf);
 		i.ibuf = null;
 		usedMemory -= i.count * 2;
 	}
 	
-	@:allow(h3d.mat.Texture.dispose)
-	function deleteTexture( t : h3d.mat.Texture ) {
-		textures.remove(t.t);
-		tdict.remove(t);
-		driver.disposeTexture(t.t);
-		t.t = null;
-	}
-
-	@:allow(h3d.mat.Texture.resize)
-	function resizeTexture( t : h3d.mat.Texture, width, height ) {
-		t.dispose();
-		t.width = width;
-		t.height = height;
-		initTexture(t);
+	function bpp( t : h3d.mat.Texture ) {
+		return 4;
 	}
 	
-	public function readAtfHeader( data : haxe.io.Bytes ) {
-		var cubic = (data.get(6) & 0x80) != 0;
-		var alpha = false, compress = false;
-		switch( data.get(6) & 0x7F ) {
-		case 0:
-		case 1: alpha = true;
-		case 2: compress = true;
-		case 3, 4: alpha = true; compress = true;
-		case f: throw "Invalid ATF format " + f;
+	public function cleanTextures( force = true ) {
+		textures.sort(sortByLRU);
+		for( t in textures ) {
+			if( t.realloc == null ) continue;
+			if( force || t.lastFrame < h3d.Engine.getCurrent().frameCount - 3600 ) {
+				t.dispose();
+				return true;
+			}
 		}
-		var width = 1 << data.get(7);
-		var height = 1 << data.get(8);
-		var mips = data.get(9) - 1;
-		return {
-			width : width,
-			height : height,
-			cubic : cubic,
-			alpha : alpha,
-			compress : compress,
-			mips : mips,
-		};
-	}
-
-	public function allocCustomTexture( fmt : h3d.mat.Data.TextureFormat, width : Int, height : Int, mipLevels : Int = 0, cubic : Bool = false, target : Bool = false, ?allocPos : AllocPos ) {
-		freeTextures();
-		return newTexture(fmt, width, height, cubic, target, mipLevels, allocPos);
+		return false;
 	}
 	
-	public function allocTexture( width : Int, height : Int, ?mipMap = false, ?allocPos : AllocPos ) {
-		freeTextures();
-		var levels = 0;
-		if( mipMap ) {
-			while( width > (1 << levels) && height > (1 << levels) )
-				levels++;
-		}
-		return newTexture(Rgba, width, height, false, false, levels, allocPos);
+	function sortByLRU( t1 : h3d.mat.Texture, t2 : h3d.mat.Texture ) {
+		return t1.lastFrame - t2.lastFrame;
 	}
 	
-	public function allocTargetTexture( width : Int, height : Int, ?allocPos : AllocPos ) {
-		freeTextures();
-		return newTexture(Rgba, width, height, false, true, 0, allocPos);
+	@:allow(h3d.mat.Texture.dispose)
+	function deleteTexture( t : h3d.mat.Texture ) {
+		textures.remove(t);
+		driver.disposeTexture(t.t);
+		t.t = null;
+		texMemory -= t.width * t.height * bpp(t);
 	}
 
-	public function allocCubeTexture( size : Int, ?mipMap = false, ?allocPos : AllocPos ) {
-		freeTextures();
-		var levels = 0;
-		if( mipMap ) {
-			while( size > (1 << levels) )
-				levels++;
+	@:allow(h3d.mat.Texture.alloc)
+	function allocTexture( t : h3d.mat.Texture ) {
+		var free = cleanTextures(false);
+		t.t = driver.allocTexture(t);
+		if( t.t == null ) {
+			if( !cleanTextures(true) ) throw "Maximum texture memory reached";
+			allocTexture(t);
+			return;
 		}
-		return newTexture(Rgba, size, size, true, false, levels, allocPos);
+		textures.push(t);
+		texMemory += t.width * t.height * bpp(t);
 	}
-
+	
 	public function allocIndex( indices : hxd.IndexBuffer, pos = 0, count = -1 ) {
 		if( count < 0 ) count = indices.length;
 		var ibuf = driver.allocIndexes(count);
 		var idx = new Indexes(this, ibuf, count);
 		idx.upload(indices, 0, count);
-		idict.set(idx, true);
+		indexes.push(idx);
 		usedMemory += idx.count * 2;
 		return idx;
 	}
@@ -346,26 +295,6 @@ class MemoryManager {
 		b.uploadVector(v, 0, nvert);
 		return b;
 	}
-	
-	/**
-		This will automatically free all textures which are no longer referenced / have been GC'ed.
-		This is called before each texture allocation as well.
-		Returns the number of textures freed that way.
-	 **/
-	public function freeTextures() {
-		var tall = new Map();
-		for( t in textures )
-			tall.set(t, true);
-		for( t in tdict )
-			tall.remove(t);
-		var count = 0;
-		for( t in tall.keys() ) {
-			driver.disposeTexture(t);
-			textures.remove(t);
-			count++;
-		}
-		return count;
-	}
 
 	/**
 		The amount of free buffers memory
@@ -513,54 +442,32 @@ class MemoryManager {
 	}
 
 	public function onContextLost() {
-		indexes.dispose();
-		quadIndexes.dispose();
-		var tkeys = Lambda.array({ iterator : tdict.keys });
-		for( t in tkeys ) {
-			if( !tdict.exists(t) )
-				continue;
-			if( t.onContextLost == null )
-				t.dispose();
-			else {
-				textures.remove(t.t);
-				initTexture(t);
-				t.onContextLost();
-			}
-		}
-		for( b in buffers ) {
-			var b = b;
-			while( b != null ) {
-				b.dispose();
-				b = b.next;
-			}
-		}
-		for( i in idict.keys() )
-			i.dispose();
-		buffers = [];
-		bufferCount = 0;
-		usedMemory = 0;
+		dispose();
 		initIndexes();
 	}
 
 	public function dispose() {
-		indexes.dispose();
-		indexes = null;
+		triIndexes.dispose();
 		quadIndexes.dispose();
+		triIndexes = null;
 		quadIndexes = null;
-		for( t in tdict.keys() )
+		for( t in textures.copy() )
 			t.dispose();
-		for( b in buffers ) {
+		for( b in buffers.copy() ) {
 			var b = b;
 			while( b != null ) {
 				b.dispose();
 				b = b.next;
 			}
 		}
-		for( i in idict.keys() )
+		for( i in indexes.copy() )
 			i.dispose();
 		buffers = [];
+		indexes = [];
+		textures = [];
 		bufferCount = 0;
 		usedMemory = 0;
+		texMemory = 0;
 	}
 
 }

+ 0 - 112
h3d/impl/NullDriver.hx

@@ -1,112 +0,0 @@
-package h3d.impl;
-import h3d.impl.Driver;
-
-class NullDriver extends Driver {
-
-	public var driver : Driver;
-	
-	public function new( driver ) {
-		this.driver = driver;
-	}
-	
-	override function isDisposed() {
-		return driver.isDisposed();
-	}
-	
-	override function dispose() {
-		driver.dispose();
-	}
-
-	override function reset() {
-		driver.reset();
-	}
-
-	override function present() {
-		driver.present();
-	}
-
-	override function clear( r : Float, g : Float, b : Float, a : Float ) {
-		driver.clear(r, g, b, a);
-	}
-	
-	override function getDriverName( details : Bool ) {
-		return "Null Driver - " + driver.getDriverName(details);
-	}
-	
-	override function init( onCreate : Bool -> Void, forceSoftware = false ) {
-		driver.init(onCreate, forceSoftware);
-	}
-
-	override function resize( width : Int, height : Int ) {
-		driver.resize(width, height);
-	}
-
-	override function getShaderInputNames() : Array<String> {
-		return driver.getShaderInputNames();
-	}
-	
-	override function isHardware() {
-		return driver.isHardware();
-	}
-	
-	override function setDebug( b : Bool ) {
-		driver.setDebug(b);
-	}
-	
-	override function allocTexture( t : h3d.mat.Texture ) : Texture {
-		return driver.allocTexture(t);
-	}
-
-	override function allocIndexes( count : Int ) : IndexBuffer {
-		return driver.allocIndexes(count);
-	}
-
-	override function allocVertex( count : Int, stride : Int ) : VertexBuffer {
-		return driver.allocVertex(count,stride);
-	}
-	
-	override function disposeTexture( t : Texture ) {
-		driver.disposeTexture(t);
-	}
-	
-	override function disposeIndexes( i : IndexBuffer ) {
-		driver.disposeIndexes(i);
-	}
-	
-	override function disposeVertex( v : VertexBuffer ) {
-		driver.disposeVertex(v);
-	}
-	
-	override function uploadIndexesBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
-		driver.uploadIndexesBuffer(i, startIndice, indiceCount, buf, bufPos);
-	}
-
-	override function uploadIndexesBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes , bufPos : Int ) {
-		driver.uploadIndexesBytes(i, startIndice, indiceCount, buf, bufPos);
-	}
-	
-	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
-		driver.uploadVertexBuffer(v, startVertex, vertexCount, buf, bufPos);
-	}
-
-	override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
-		driver.uploadVertexBytes(v, startVertex, vertexCount, buf, bufPos);
-	}
-	
-	override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
-		driver.uploadTextureBitmap(t, bmp, mipLevel, side);
-	}
-
-	override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
-		driver.uploadTexturePixels(t, pixels, mipLevel, side);
-	}
-
-	/*
-	public function selectBuffer( buffer : VertexBuffer )
-	public function selectMultiBuffers( buffers : Array<Buffer.BufferOffset> )
-	public function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int )
-	public function setRenderZone( x : Int, y : Int, width : Int, height : Int )
-	public function setRenderTarget( tex : Null<Texture>, useDepth : Bool, clearColor : Int )
-	*/
-	
-}

+ 67 - 52
h3d/impl/Stage3dDriver.hx

@@ -45,12 +45,13 @@ class Stage3dDriver extends Driver {
 	var curAttributes : Int;
 	var curTextures : Array<h3d.mat.Texture>;
 	var curSamplerBits : Array<Int>;
-	var inTarget : Texture;
+	var inTarget : h3d.mat.Texture;
 	var antiAlias : Int;
 	var width : Int;
 	var height : Int;
 	var enableDraw : Bool;
 	var capture : { bmp : hxd.BitmapData, callb : Void -> Void };
+	var frame : Int;
 
 	@:allow(h3d.impl.VertexWrapper)
 	var empty : flash.utils.ByteArray;
@@ -66,6 +67,11 @@ class Stage3dDriver extends Driver {
 		return ctx == null ? "None" : (details ? ctx.driverInfo : ctx.driverInfo.split(" ")[0]);
 	}
 	
+	override function begin( frame : Int ) {
+		reset();
+		this.frame = frame;
+	}
+
 	override function reset() {
 		enableDraw = true;
 		curMatBits = -1;
@@ -162,40 +168,49 @@ class Stage3dDriver extends Driver {
 		return ctx.createIndexBuffer(count);
 	}
 	
+	function getMipLevels( t : h3d.mat.Texture ) {
+		if( !t.flags.has(MipMapped) )
+			return 0;
+		var levels = 0;
+		while( t.width > (1 << levels) || t.height > (1 << levels) )
+			levels++;
+		return levels;
+	}
+	
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
-		var fmt = switch( t.format ) {
-		case Rgba, Atf:
-			flash.display3D.Context3DTextureFormat.BGRA;
-		case AtfCompressed(alpha):
-			alpha ? flash.display3D.Context3DTextureFormat.COMPRESSED_ALPHA : flash.display3D.Context3DTextureFormat.COMPRESSED;
-		}
-		var rect = false;
-		if( t.isTarget && !t.isCubic && t.mipLevels == 0 ) {
-			var tw = 1, th = 1;
-			while( tw < t.width ) tw <<= 1;
-			while( th < t.height) th <<= 1;
-			if( tw != t.width || th != t.height )
-				rect = true;
-		}
-		return if( t.isCubic )
-			ctx.createCubeTexture(t.width, fmt, t.isTarget, t.mipLevels);
-		else if( rect ) {
-			#if !flash11_8
-			throw "Support for rectangle texture requires Flash 11.8+ compilation";
-			#else
-			ctx.createRectangleTexture(t.width, t.height, fmt, t.isTarget);
-			#end
+		var fmt = flash.display3D.Context3DTextureFormat.BGRA;
+		if( t.flags.has(TargetDepth) )
+			throw "Unsupported texture flag";
+		try {
+			if( t.flags.has(IsRectangle) ) {
+				if( t.flags.has(Cubic) || t.flags.has(MipMapped) || t.flags.has(Target) )
+					throw "Not power of two texture is not supported with these flags";
+				#if !flash11_8
+				throw "Support for rectangle texture requires Flash 11.8+ compilation";
+				#else
+				return ctx.createRectangleTexture(t.width, t.height, fmt, t.flags.has(Target));
+				#end
+			}
+			if( t.flags.has(Cubic) )
+				return ctx.createCubeTexture(t.width, fmt, t.flags.has(Target), getMipLevels(t));
+			return ctx.createTexture(t.width, t.height, fmt, t.flags.has(Target), getMipLevels(t));
+		} catch( e : flash.errors.Error ) {
+			if( e.errorID == 3691 )
+				return null;
+			throw e;
 		}
-		else
-			ctx.createTexture(t.width, t.height, fmt, t.isTarget, t.mipLevels);
 	}
 
 	override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
-		if( t.isCubic ) {
+		if( t.flags.has(Cubic) ) {
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			t.uploadFromBitmapData(bmp.toNative(), side, mipLevel);
-		}
-		else {
+		} else if( t.flags.has(IsRectangle) ) {
+			#if flash11_8
+			var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
+			t.uploadFromBitmapData(bmp.toNative());
+			#end
+		} else {
 			var t = flash.Lib.as(t.t, flash.display3D.textures.Texture);
 			t.uploadFromBitmapData(bmp.toNative(), mipLevel);
 		}
@@ -204,25 +219,17 @@ class Stage3dDriver extends Driver {
 	override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
 		pixels.convert(BGRA);
 		var data = pixels.bytes.getData();
-		switch( t.format ) {
-		case Atf, AtfCompressed(_):
-			if( t.isCubic ) {
-				var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
-				t.uploadCompressedTextureFromByteArray(data, 0);
-			}
-			else {
-				var t = flash.Lib.as(t.t,  flash.display3D.textures.Texture);
-				t.uploadCompressedTextureFromByteArray(data, 0);
-			}
-		default:
-			if( t.isCubic ) {
-				var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
-				t.uploadFromByteArray(data, 0, side, mipLevel);
-			}
-			else {
-				var t = flash.Lib.as(t.t,  flash.display3D.textures.Texture);
-				t.uploadFromByteArray(data, 0, mipLevel);
-			}
+		if( t.flags.has(Cubic) ) {
+			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
+			t.uploadFromByteArray(data, 0, side, mipLevel);
+		} else if( t.flags.has(IsRectangle) ) {
+			#if flash11_8
+			var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
+			t.uploadFromByteArray(data, 0);
+			#end
+		} else {
+			var t = flash.Lib.as(t.t,  flash.display3D.textures.Texture);
+			t.uploadFromByteArray(data, 0, mipLevel);
 		}
 	}
 	
@@ -306,12 +313,17 @@ class Stage3dDriver extends Driver {
 			for( i in 0...s.textures.length ) {
 				var t = s.textures[i];
 				if( t == null || t.isDisposed() )
-					t = h2d.Tile.fromColor(0xFFFF00FF).getTexture();
+					t = h3d.mat.Texture.fromColor(0xFFFF00FF);
+				if( t != null && t.t == null && t.realloc != null ) {
+					t.alloc();
+					t.realloc();
+				}
 				var cur = curTextures[i];
 				if( t != cur ) {
 					ctx.setTextureAt(i, t.t);
 					curTextures[i] = t;
 				}
+				t.lastFrame = frame;
 				// if we have set one of the texture flag manually or if the shader does not configure the texture flags
 				if( !t.hasDefaultFlags() || !s.texHasConfig[s.textureMap[i]] ) {
 					if( cur == null || t.bits != curSamplerBits[i] ) {
@@ -417,15 +429,18 @@ class Stage3dDriver extends Driver {
 		}
 	}
 
-	override function setRenderTarget( tex : Null<Texture>, useDepth : Bool, clearColor : Int ) {
-		if( tex == null ) {
+	override function setRenderTarget( t : Null<h3d.mat.Texture>, clearColor : Int ) {
+		if( t == null ) {
 			ctx.setRenderToBackBuffer();
 			inTarget = null;
 		} else {
+			if( t.t == null )
+				t.alloc();
 			if( inTarget != null )
 				throw "Calling setTarget() while already set";
-			ctx.setRenderToTexture(tex, useDepth);
-			inTarget = tex;
+			ctx.setRenderToTexture(t.t, t.flags.has(TargetUseDefaultDepth));
+			inTarget = t;
+			t.lastFrame = frame;
 			reset();
 			ctx.clear( ((clearColor>>16)&0xFF)/255 , ((clearColor>>8)&0xFF)/255, (clearColor&0xFF)/255, ((clearColor>>>24)&0xFF)/255);
 		}

+ 39 - 4
h3d/mat/Data.hx

@@ -54,12 +54,47 @@ enum Wrap {
 	//Mirrored;
 }
 
-enum TextureFormat {
-	Rgba;
-}
-
 enum Operation {
 	Add;
 	Sub;
 	ReverseSub;
 }
+
+enum TextureFlags {
+	/**
+		Allocate a texture that will be used as render target.
+	**/
+	Target;
+	/**
+		Add depth buffer on target texture
+	**/
+	TargetDepth;
+	/**
+		Use depth depth buffer when rendering to target texture
+	**/
+	TargetUseDefaultDepth;
+	/**
+		Allocate a cubic texture. Might be restricted to power of two textures only.
+	**/
+	Cubic;
+	/**
+		Used to prevent culling inversion on target textures in GL.
+	**/
+	TargetNoFlipY;
+	/**
+		Activates Mip Mapping for this texture. Might not be available for target textures.
+	**/
+	MipMapped;
+	/**
+		This is a not power of two texture. Automatically set when having width or height being not power of two.
+	**/
+	IsRectangle;
+	/**
+		Don't initialy allocate the texture memory.
+	**/
+	NoAlloc;
+	/**
+		Inform that we will often perform upload operations on this texture
+	**/
+	Dynamic;
+}

+ 55 - 60
h3d/mat/Texture.hx

@@ -1,5 +1,4 @@
 package h3d.mat;
-
 import h3d.mat.Data;
 
 @:allow(h3d)
@@ -16,35 +15,54 @@ class Texture {
 	public var name(default, null) : String;
 	public var width(default, null) : Int;
 	public var height(default, null) : Int;
-	public var isCubic(default, null) : Bool;
-	public var isTarget(default, null) : Bool;
-	public var mipLevels(default, null) : Int;
-	public var format(default, null) : TextureFormat;
-	
+	public var flags(default, null) : haxe.EnumFlags<TextureFlags>;
+
+	var lastFrame : Int;
 	var bits : Int;
 	public var mipMap(default,set) : MipMap;
 	public var filter(default,set) : Filter;
 	public var wrap(default,set) : Wrap;
 
 	/**
-		If this callback is set, the texture is re-allocated when the 3D context has been lost and the callback is called
-		so it can perform the necessary operations to restore the texture in its initial state
+		If this callback is set, the texture can be re-allocated when the 3D context has been lost or when
+		it's been free because of lack of memory.
 	**/
-	public var onContextLost : Void -> Void;
+	public var realloc : Void -> Void;
 	
-	function new(m, fmt, w, h, c, ta, mm) {
+	public function new(w, h, ?flags : Array<TextureFlags>, ?allocPos : h3d.impl.AllocPos ) {
+		var engine = h3d.Engine.getCurrent();
+		this.mem = engine.mem;
 		this.id = ++UID;
-		this.format = fmt;
-		this.mem = m;
-		this.isTarget = ta;
+		this.flags = new haxe.EnumFlags();
+		if( flags != null )
+			for( f in flags )
+				this.flags.set(f);
+
+		var tw = 1, th = 1;
+		while( tw < w ) tw <<= 1;
+		while( th < h) th <<= 1;
+		if( tw != w || th != h )
+			this.flags.set(IsRectangle);
+			
+		// make the texture disposable if we're out of memory
+		// this can be disabled after allocation by reseting realloc
+		if( this.flags.has(Target) ) realloc = function() { };
+
 		this.width = w;
 		this.height = h;
-		this.isCubic = c;
-		this.mipLevels = mm;
-		this.mipMap = mm > 0 ? Nearest : None;
+		this.mipMap = this.flags.has(MipMapped) ? Nearest : None;
 		this.filter = Linear;
 		this.wrap = Clamp;
 		bits &= 0x7FFF;
+		#if debug
+		this.allocPos = allocPos;
+		#end
+		alloc();
+	}
+	
+	public function alloc() {
+		if( t == null )
+			mem.allocTexture(this);
 	}
 	
 	function toString() {
@@ -77,35 +95,26 @@ class Texture {
 		return bits & 0x80000 == 0;
 	}
 
-	public function isDisposed() {
-		return t == null;
+	public inline function isDisposed() {
+		return t == null && realloc == null;
 	}
 	
 	public function resize(width, height) {
-		mem.resizeTexture(this, width, height);
-	}
+		dispose();
+		
+		var tw = 1, th = 1;
+		while( tw < width ) tw <<= 1;
+		while( th < height ) th <<= 1;
+		if( tw != width || th != height )
+			this.flags.set(IsRectangle);
+		else
+			this.flags.unset(IsRectangle);
 
-	/*
-	public function uploadMipMap( bmp : hxd.BitmapData, smoothing = false, side = 0 ) {
-		upload(bmp, 0, side);
-		var w = bmp.width >> 1, h = bmp.height >> 1, mip = 1;
-		var m = new flash.geom.Matrix();
-		var draw : flash.display.IBitmapDrawable = bmp;
-		if( smoothing ) draw = new flash.display.Bitmap(bmp, flash.display.PixelSnapping.ALWAYS, true);
-		while( w > 0 && h > 0 ) {
-			var tmp = new flash.display.BitmapData(w, h, true, 0);
-			m.identity();
-			m.scale(w / bmp.width, h / bmp.height);
-			tmp.draw(draw, m);
-			upload(tmp,mip,side);
-			tmp.dispose();
-			mip++;
-			w >>= 1;
-			h >>= 1;
-		}
+		this.width = width;
+		this.height = height;
+		alloc();
 	}
-	*/
-	
+
 	public function clear( color : Int ) {
 		var p = hxd.Pixels.alloc(width, height, BGRA);
 		var k = 0;
@@ -134,44 +143,30 @@ class Texture {
 	}
 	
 	public static function fromBitmap( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {
-		var mem = h3d.Engine.getCurrent().mem;
-		var t = mem.allocTexture(bmp.width, bmp.height, false, allocPos);
+		var t = new Texture(bmp.width, bmp.height, allocPos);
 		t.uploadBitmap(bmp);
 		return t;
 	}
 	
 	public static function fromPixels( pixels : hxd.Pixels, ?allocPos : h3d.impl.AllocPos ) {
-		var mem = h3d.Engine.getCurrent().mem;
-		var t = mem.allocTexture(pixels.width, pixels.height, false, allocPos);
+		var t = new Texture(pixels.width, pixels.height, allocPos);
 		t.uploadPixels(pixels);
 		return t;
 	}
 	
-	static var tmpPixels : hxd.Pixels = null;
 	static var COLOR_CACHE = new Map<Int,h3d.mat.Texture>();
 	/**
 		Creates a 1x1 texture using the ARGB color passed as parameter.
 	**/
 	public static function fromColor( color : Int, ?allocPos : h3d.impl.AllocPos ) {
 		var t = COLOR_CACHE.get(color);
-		if( t != null && !t.isDisposed() )
+		if( t != null )
 			return t;
-		var mem = h3d.Engine.getCurrent().mem;
-		var t = mem.allocTexture(1, 1, false, allocPos);
-		if( tmpPixels == null ) tmpPixels = new hxd.Pixels(1, 1, haxe.io.Bytes.alloc(4), BGRA);
-		tmpPixels.format = BGRA;
-		tmpPixels.bytes.set(0, color & 0xFF);
-		tmpPixels.bytes.set(1, (color>>8) & 0xFF);
-		tmpPixels.bytes.set(2, (color>>16) & 0xFF);
-		tmpPixels.bytes.set(3, color>>>24);
-		t.uploadPixels(tmpPixels);
+		var t = new Texture(1, 1, null, allocPos);
+		t.clear(color);
+		t.realloc = function() t.clear(color);
 		COLOR_CACHE.set(color, t);
 		return t;
 	}
-	
-	public static function alloc( width : Int, height : Int, isTarget = false, ?allocPos : h3d.impl.AllocPos ) {
-		var engine = h3d.Engine.getCurrent();
-		return isTarget ? engine.mem.allocTargetTexture(width, height, allocPos) : engine.mem.allocTexture(width, height, null, allocPos);
-	}
 
 }

+ 1 - 1
h3d/parts/Editor.hx

@@ -751,7 +751,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		curveBG = h2d.Tile.fromBitmap(bg);
 		bg.dispose();
-		curveTexture = 	h2d.Tile.fromTexture(h3d.Engine.getCurrent().mem.allocTexture(512, 512)).sub(0, 0, curveBG.width, curveBG.height);
+		curveTexture = h2d.Tile.fromTexture(new h3d.mat.Texture(512, 512)).sub(0, 0, curveBG.width, curveBG.height);
 	}
 	
 	function rebuildCurve() {

+ 3 - 3
h3d/pass/Distance.hx

@@ -15,11 +15,11 @@ class Distance extends Base {
 	}
 	
 	override function draw(ctx : h3d.scene.RenderContext, passes) {
-		if( texture == null || texture.isDisposed() || texture.width != ctx.engine.width || texture.height != ctx.engine.height ) {
+		if( texture == null || texture.width != ctx.engine.width || texture.height != ctx.engine.height ) {
 			if( texture != null ) texture.dispose();
-			texture = h3d.mat.Texture.alloc(ctx.engine.width, ctx.engine.height, true);
+			texture = new h3d.mat.Texture(ctx.engine.width, ctx.engine.height, [Target, TargetDepth, TargetNoFlipY]);
 		}
-		ctx.engine.setTarget(texture, true);
+		ctx.engine.setTarget(texture);
 		super.draw(ctx, passes);
 		ctx.engine.setTarget(null);
 	}

+ 3 - 3
h3d/pass/ShadowMap.hx

@@ -53,14 +53,14 @@ class ShadowMap extends Base {
 	}
 	
 	override function draw( ctx : h3d.scene.RenderContext, passes) {
-		if( texture == null || texture.isDisposed() || texture.width != size ) {
+		if( texture == null || texture.width != size ) {
 			if( texture != null ) texture.dispose();
-			texture = h3d.mat.Texture.alloc(size, size, true);
+			texture = new h3d.mat.Texture(size, size, [Target, TargetDepth, TargetNoFlipY]);
 		}
 		var ct = ctx.camera.target;
 		lightCamera.target.set(ct.x, ct.y, ct.z);
 		lightCamera.pos.set(ct.x - lightDirection.x, ct.y - lightDirection.y, ct.z - lightDirection.z);
-		ctx.engine.setTarget(texture, true, 0xFFFFFFFF);
+		ctx.engine.setTarget(texture, 0xFFFFFFFF);
 		super.draw(ctx, passes);
 		ctx.engine.setTarget(null);
 		ctx.sharedGlobals.set(shadowMapId, texture);

+ 6 - 0
hxd/Event.hx

@@ -18,7 +18,13 @@ class Event {
 	public var kind : EventKind;
 	public var relX : Float;
 	public var relY : Float;
+	/**
+		Will propagate the event to other interactives that are below the current one.
+	**/
 	public var propagate : Bool;
+	/**
+		Will cancel the default behavior for this event as if it had happen outside of the interactive zone.
+	**/
 	public var cancel : Bool;
 	public var button : Int = 0;
 	public var touchId : Int;

+ 22 - 4
hxd/Stage.hx

@@ -24,6 +24,7 @@ class Stage {
 	public var height(get, null) : Int;
 	public var mouseX(get, null) : Int;
 	public var mouseY(get, null) : Int;
+	public var mouseLock(get, set) : Bool;
 	
 	function new() {
 		eventTargets = new List();
@@ -164,6 +165,14 @@ class Stage {
 		return stage.stageHeight;
 	}
 	
+	inline function get_mouseLock() {
+		return stage.mouseLock;
+	}
+
+	inline function set_mouseLock(v) {
+		return stage.mouseLock = v;
+	}
+	
 	function onResize(_) {
 		for( e in resizeEvents )
 			e();
@@ -200,14 +209,14 @@ class Stage {
 	}
 	
 	function onKeyUp(e:flash.events.KeyboardEvent) {
-		var ev = new Event(EKeyUp);
+		var ev = new Event(EKeyUp, mouseX, mouseY);
 		ev.keyCode = e.keyCode;
 		ev.charCode = getCharCode(e);
 		event(ev);
 	}
 
 	function onKeyDown(e:flash.events.KeyboardEvent) {
-		var ev = new Event(EKeyDown);
+		var ev = new Event(EKeyDown, mouseX, mouseY);
 		ev.keyCode = e.keyCode;
 		ev.charCode = getCharCode(e);
 		event(ev);
@@ -299,6 +308,15 @@ class Stage {
 	function get_mouseY() {
 		return Math.round(curMouseY - canvasPos.top);
 	}
+	
+	function get_mouseLock() {
+		return false;
+	}
+	
+	function set_mouseLock(b) {
+		throw "Mouse lock not supported";
+		return false;
+	}
 
 	function onMouseDown(e:js.html.MouseEvent) {
 		event(new Event(EPush, mouseX, mouseY));
@@ -321,14 +339,14 @@ class Stage {
 	}
 	
 	function onKeyUp(e:js.html.KeyboardEvent) {
-		var ev = new Event(EKeyUp);
+		var ev = new Event(EKeyUp, mouseX, mouseY);
 		ev.keyCode = e.keyCode;
 		ev.charCode = e.charCode;
 		event(ev);
 	}
 
 	function onKeyDown(e:js.html.KeyboardEvent) {
-		var ev = new Event(EKeyDown);
+		var ev = new Event(EKeyDown, mouseX, mouseY);
 		ev.keyCode = e.keyCode;
 		ev.charCode = e.charCode;
 		event(ev);

+ 3 - 6
hxd/res/BitmapFont.hx

@@ -12,18 +12,15 @@ class BitmapFont extends Resource {
 	
 	@:access(h2d.Font)
 	public function toFont() : h2d.Font {
-		if( font != null && !font.tile.isDisposed() )
+		if( font != null )
 			return font;
 		var tile = loader.load(entry.path.substr(0, -3) + "png").toTile();
-		if( font != null ) {
-			font.tile = tile;
-			return font;
-		}
 		var name = entry.path, size = 0, lineHeight = 0, glyphs = new Map();
 		switch( entry.getSign() ) {
 		case 0x6D783F3C: // <?xm : XML file
 			var xml = Xml.parse(entry.getBytes().toString());
 			// support only the FontBuilder/Divo format
+			// export with FontBuilder https://github.com/andryblack/fontbuilder/downloads
 			var xml = new haxe.xml.Fast(xml.firstElement());
 			size = Std.parseInt(xml.att.size);
 			lineHeight = Std.parseInt(xml.att.height);
@@ -32,7 +29,7 @@ class BitmapFont extends Resource {
 				var r = c.att.rect.split(" ");
 				var o = c.att.offset.split(" ");
 				var t = tile.sub(Std.parseInt(r[0]), Std.parseInt(r[1]), Std.parseInt(r[2]), Std.parseInt(r[3]), Std.parseInt(o[0]), Std.parseInt(o[1]));
-				var fc = new h2d.Font.FontChar(t, Std.parseInt(c.att.width));
+				var fc = new h2d.Font.FontChar(t, Std.parseInt(c.att.width) - 1);
 				for( k in c.elements )
 					fc.addKerning(k.att.id.charCodeAt(0), Std.parseInt(k.att.advance));
 				glyphs.set(c.att.code.charCodeAt(0), fc);

+ 2 - 1
hxd/res/DynamicText.hx

@@ -112,7 +112,8 @@ class DynamicText {
 
 	public static function build( file : String, ?withDict : Bool ) {
 		var path = FileTree.resolvePath();
-		var x = Xml.parse(sys.io.File.getContent("res/" + file));
+		var x = Xml.parse(sys.io.File.getContent(path + "/" + file));
+		Context.registerModuleDependency(Context.getLocalModule(), path + "/" + file);
 		var fields = Context.getBuildFields();
 		var pos = Context.currentPos();
 		var tdict = new Map();

+ 5 - 5
hxd/res/FontBuilder.hx

@@ -92,7 +92,7 @@ class FontBuilder {
 				tf.text = options.chars.charAt(i);
 				bmp.fillRect(new flash.geom.Rectangle(x, y, w, h), 0);
 				bmp.draw(tf, m);
-				var t = new h2d.Tile(null, x, y, w - 1, h - 1);
+				var t = new h2d.Tile(innerTex, x, y, w - 1, h - 1);
 				all.push(t);
 				font.glyphs.set(options.chars.charCodeAt(i), new h2d.Font.FontChar(t,w-1));
 				// next element
@@ -124,7 +124,7 @@ class FontBuilder {
 			font.tile = h2d.Tile.fromTexture(innerTex);
 			for( t in all )
 				t.setTexture(innerTex);
-			innerTex.onContextLost = build;
+			innerTex.realloc = build;
 		} else
 			innerTex.uploadPixels(pixels);
 		pixels.dispose();
@@ -195,7 +195,7 @@ class FontBuilder {
 				ctx.globalAlpha = 1.0;
 				ctx.fillStyle = 'white';
 				ctx.fillText(options.chars.charAt(i), x, y);
-				var t = new h2d.Tile(null, x, y, w - 1, h - 1);
+				var t = new h2d.Tile(innerTex, x, y, w - 1, h - 1);
 				all.push(t);
 				font.glyphs.set(options.chars.charCodeAt(i), new h2d.Font.FontChar(t,w-1));
 				// next element
@@ -210,7 +210,7 @@ class FontBuilder {
 			font.tile = h2d.Tile.fromTexture(innerTex);
 			for( t in all )
 				t.setTexture(innerTex);
-			innerTex.onContextLost = build;
+			innerTex.realloc = build;
 		} else {
 			innerTex.uploadBitmap(rbmp);
 		}
@@ -230,7 +230,7 @@ class FontBuilder {
 	public static function getFont( name : String, size : Int, ?options : FontBuildOptions ) {
 		var key = name + "#" + size;
 		var f = FONTS.get(key);
-		if( f != null && f.tile.innerTex != null && !f.tile.innerTex.isDisposed() )
+		if( f != null && f.tile.innerTex != null )
 			return f;
 		f = new FontBuilder(name, size, options).build();
 		FONTS.set(key, f);

+ 10 - 57
hxd/res/Image.hx

@@ -2,7 +2,6 @@ package hxd.res;
 
 class Image extends Resource {
 	
-	var needResize : Bool;
 	var tex : h3d.mat.Texture;
 	var inf : { width : Int, height : Int, isPNG : Bool };
 	
@@ -11,16 +10,6 @@ class Image extends Resource {
 		return inf.isPNG;
 	}
 
-	function checkResize() {
-		if( !needResize ) return;
-		var tw = tex.width, th = tex.height;
-		@:privateAccess {
-			tex.width = 1;
-			tex.height = 1;
-		}
-		tex.resize(tw,th);
-	}
-	
 	public function getSize() : { width : Int, height : Int } {
 		if( inf != null )
 			return inf;
@@ -95,18 +84,14 @@ class Image extends Resource {
 	}
 	
 	function loadTexture() {
-		var tw = tex.width, th = tex.height;
-		var w =	inf.width, h = inf.height;
-		var isSquare = w == tw && h == th;
 		if( inf.isPNG ) {
 			function load() {
-				checkResize();
-
 				// immediately loading the PNG is faster than going through loadBitmap
+				tex.alloc();
 				var pixels = getPixels();
-				pixels.makeSquare();
 				tex.uploadPixels(pixels);
 				pixels.dispose();
+				tex.realloc = loadTexture;
 			}
 			if( entry.isAvailable )
 				load();
@@ -114,55 +99,23 @@ class Image extends Resource {
 				entry.load(load);
 		} else {
 			// use native decoding
-			entry.loadBitmap(function(loaded) {
-				checkResize();
-				var bmp = loaded.toBitmap();
-				if( isSquare )
-					tex.uploadBitmap(bmp);
-				else {
-					var pixels = bmp.getPixels();
-					pixels.makeSquare();
-					tex.uploadPixels(pixels);
-					pixels.dispose();
-				}
+			entry.loadBitmap(function(bmp) {
+				var bmp = bmp.toBitmap();
+				tex.alloc();
+				tex.uploadBitmap(bmp);
 				bmp.dispose();
+				tex.realloc = loadTexture;
 			});
 		}
 	}
 	
 	public function toTexture() : h3d.mat.Texture {
-		if( tex != null && !tex.isDisposed() )
+		if( tex != null )
 			return tex;
-		if( tex != null ) {
-			tex.dispose();
-			tex = null;
-		}
 		getSize();
-		var w = inf.width, h = inf.height;
-		var tw = 1, th = 1;
-		while( tw < w ) tw <<= 1;
-		while( th < h ) th <<= 1;
-
-		if( inf.isPNG && entry.isAvailable ) {
-			// direct upload
-			needResize = false;
-			tex = h3d.Engine.getCurrent().mem.allocTexture(tw, th, false);
-		} else {
-			// create a temp 1x1 texture while we're loading
-			tex = h3d.mat.Texture.fromColor(0xFF0000FF);
-			needResize = true;
-			@:privateAccess {
-				tex.width = tw;
-				tex.height = th;
-			}
-		}
-		loadTexture();
+		tex = new h3d.mat.Texture(inf.width, inf.height, [NoAlloc]);
 		tex.setName(entry.path);
-		tex.onContextLost = function() {
-			needResize = false;
-			loadTexture();
-			return true;
-		};
+		loadTexture();
 		return tex;
 	}
 	

+ 2 - 1
hxsl/Checker.hx

@@ -228,7 +228,7 @@ class Checker {
 	}
 
 	function typeExpr( e : Expr, with : WithType ) : TExpr {
-		var type;
+		var type = null;
 		var ed = switch( e.expr ) {
 		case EConst(c):
 			type = switch( c ) {
@@ -473,6 +473,7 @@ class Checker {
 			type = TArray(t, SConst(el.length));
 			TArrayDecl(el);
 		}
+		if( type == null ) throw "assert";
 		return { e : ed, t : type, p : e.pos };
 	}
 	

+ 1 - 1
tools/fbx/Viewer.hx

@@ -267,7 +267,7 @@ class Viewer {
 	}
 	
 	function textureLoader( textureName : String, matData : h3d.fbx.Data.FbxNode ) {
-		var t = engine.mem.allocTexture(1024, 1024);
+		var t = new h3d.mat.Texture(1024, 1024);
 		var bmp = new flash.display.BitmapData(1024, 1024, true, 0xFFFF0000);
 		var mat = new h3d.mat.MeshMaterial(t);
 		t.uploadBitmap(hxd.BitmapData.fromNative(bmp));

+ 1 - 1
tools/perlin/PerlinView.hx

@@ -1,4 +1,4 @@
-@:enum abstract Mode {
+@:enum abstract Mode(Int) {
 	var Perlin = 0;
 	var Ridged = 1;
 }