Sfoglia il codice sorgente

more work on resource management

ncannasse 12 anni fa
parent
commit
94641ab12d

+ 18 - 0
hxd/res/EmbedFileSystem.hx

@@ -21,6 +21,18 @@ private class EmbedEntry extends FileEntry {
 		this.data = data;
 	}
 
+	override function getSign() : Int {
+		#if flash
+		var old = bytes == null ? 0 : bytes.position;
+		open();
+		var v = bytes.readUnsignedInt();
+		bytes.position = old;
+		return v;
+		#else
+		return 0;
+		#end
+	}
+	
 	override function getBytes() : haxe.io.Bytes {
 		#if flash
 		if( bytes == null )
@@ -39,6 +51,12 @@ private class EmbedEntry extends FileEntry {
 		#end
 	}
 	
+	override function skip( nbytes : Int ) {
+		#if flash
+		bytes.position += nbytes;
+		#end
+	}
+	
 	override function readByte() : Int {
 		#if flash
 		return bytes.readUnsignedByte();

+ 9 - 1
hxd/res/FileEntry.hx

@@ -4,13 +4,18 @@ class FileEntry {
 	
 	public var name(default, null) : String;
 	public var path(get, never) : String;
+	public var extension(get, never) : String;
 	public var size(get, never) : Int;
 	public var isDirectory(get, never) : Bool;
 	public var isAvailable(get, never) : Bool;
 	
+	// first four bytes of the file
+	public function getSign() : Int return 0;
+	
 	public function getBytes() : haxe.io.Bytes return null;
 	
 	public function open() { }
+	public function skip( nbytes : Int ) { }
 	public function readByte() : Int return 0;
 	public function read( out : haxe.io.Bytes, pos : Int, size : Int ) {}
 	public function close() {}
@@ -27,5 +32,8 @@ class FileEntry {
 	function get_isDirectory() return false;
 	function get_size() return 0;
 	function get_path() return name;
-	
+	function get_extension() {
+		var np = name.split(".");
+		return np.length == 1 ? "" : np.pop().toLowerCase();
+	}
 }

+ 4 - 0
hxd/res/FileInput.hx

@@ -9,6 +9,10 @@ class FileInput extends haxe.io.Input {
 		f.open();
 	}
 	
+	public function skip( nbytes : Int ) {
+		f.skip(nbytes);
+	}
+	
 	override function readByte() {
 		return f.readByte();
 	}

+ 1 - 1
hxd/res/FileTree.hx

@@ -170,7 +170,7 @@ class FileTree {
 	}
 	
 	function scanRec( relPath : String, fields : Array<Field>, dict : Map<String,String> ) {
-		var dir = this.path + relPath;
+		var dir = this.path + "/" + relPath;
 		// make sure to rescan if one of the directories content has changed (file added or deleted)
 		Context.registerModuleDependency(currentModule, dir);
 		for( f in sys.FileSystem.readDirectory(dir) ) {

+ 76 - 10
hxd/res/LocalFileSystem.hx

@@ -14,9 +14,49 @@ private class LocalEntry extends FileEntry {
 	#end
 
 	function new(fs, name, relPath, file) {
+		this.fs = fs;
 		this.name = name;
 		this.relPath = relPath;
 		this.file = file;
+		if( fs.createXBX && extension == "fbx" )
+			convertToXBX();
+	}
+	
+	static var INVALID_CHARS = ~/[^A-Za-z0-9_]/g;
+	
+	function convertToXBX() {
+		function getXBX() {
+			var fbx = h3d.fbx.Parser.parse(getBytes().toString());
+			fbx = fs.xbxFilter(this, fbx);
+			var out = new haxe.io.BytesOutput();
+			new h3d.fbx.XBXWriter(out).write(fbx);
+			return out.getBytes();
+		}
+		var target = fs.tmpDir + "R_" + INVALID_CHARS.replace(relPath,"_") + ".xbx";
+		#if air3
+		var target = new flash.filesystem.File(target);
+		if( !target.exists || target.modificationDate.getTime() < file.modificationDate.getTime() ) {
+			var fbx = getXBX();
+			var out = new flash.filesystem.FileStream();
+			out.open(target, flash.filesystem.FileMode.WRITE);
+			out.writeBytes(fbx.getData());
+			out.close();
+		}
+		file = target;
+		#end
+	}
+
+	override function getSign() : Int {
+		#if air3
+		var old = fread == null ? -1 : fread.position;
+		open();
+		fread.endian = flash.utils.Endian.LITTLE_ENDIAN;
+		var i = fread.readUnsignedInt();
+		if( old < 0 ) close() else fread.position = old;
+		return i;
+		#else
+		return 0;
+		#end
 	}
 
 	override function getBytes() : haxe.io.Bytes {
@@ -34,15 +74,31 @@ private class LocalEntry extends FileEntry {
 	
 	override function open() {
 		#if air3
-		if( fread != null ) fread.close();
-		fread = new flash.filesystem.FileStream();
-		fread.open(file, flash.filesystem.FileMode.READ);
+		if( fread != null )
+			fread.position = 0;
+		else {
+			fread = new flash.filesystem.FileStream();
+			fread.open(file, flash.filesystem.FileMode.READ);
+		}
+		#end
+	}
+	
+	override function skip(nbytes:Int) {
+		#if air3
+		fread.position += nbytes;
+		#end
+	}
+	
+	override function readByte() {
+		#if air3
+		return fread.readUnsignedByte();
+		#else
+		return 0;
 		#end
 	}
 	
 	override function read( out : haxe.io.Bytes, pos : Int, size : Int ) : Void {
 		#if air3
-		if( fread == null ) throw "File not opened";
 		fread.readBytes(out.getData(), pos, size);
 		#end
 	}
@@ -57,7 +113,9 @@ private class LocalEntry extends FileEntry {
 	}
 	
 	override function load( ?onReady : Void -> Void ) : Void {
+		#if air3
 		if( onReady != null ) haxe.Timer.delay(onReady, 1);
+		#end
 	}
 	
 	override function loadBitmap( onLoaded : hxd.BitmapData -> Void ) : Void {
@@ -108,6 +166,7 @@ private class LocalEntry extends FileEntry {
 			}
 		return new hxd.impl.ArrayIterator(arr);
 		#else
+		return null;
 		#end
 	}
 	
@@ -117,17 +176,24 @@ class LocalFileSystem implements FileSystem {
 	
 	var baseDir : String;
 	var root : FileEntry;
+	public var createXBX : Bool;
+	public var tmpDir : String;
 	
-	public function new( baseDir : String ) {
-		this.baseDir = baseDir;
+	public function new( dir : String ) {
+		baseDir = dir;
 		#if air3
 		var froot = new flash.filesystem.File(flash.filesystem.File.applicationDirectory.nativePath + "/" + baseDir);
-		if( !froot.exists ) throw "Could not find dir " + baseDir;
-		this.baseDir = froot.nativePath;
-		this.baseDir = this.baseDir.split("\\").join("/");
-		if( !StringTools.endsWith(this.baseDir, "/") ) this.baseDir += "/";
+		if( !froot.exists ) throw "Could not find dir " + dir;
+		baseDir = froot.nativePath;
+		baseDir = baseDir.split("\\").join("/");
+		if( !StringTools.endsWith(baseDir, "/") ) baseDir += "/";
 		root = new LocalEntry(this, "root", null, froot);
 		#end
+		tmpDir = baseDir + ".tmp/";
+	}
+	
+	public dynamic function xbxFilter( entry : FileEntry, fbx : h3d.fbx.Data.FbxNode ) : h3d.fbx.Data.FbxNode {
+		return fbx;
 	}
 	
 	public function getRoot() : FileEntry {

+ 16 - 1
hxd/res/Model.hx

@@ -2,8 +2,23 @@ package hxd.res;
 
 class Model extends Resource {
 	
+	public static var isLeftHanded = true;
+	
 	public function toFbx() : h3d.fbx.Library {
-		return null;
+		var lib = new h3d.fbx.Library();
+		switch( entry.getSign() & 0xFF ) {
+		case ';'.code: // FBX
+			lib.load(h3d.fbx.Parser.parse(entry.getBytes().toString()));
+		case 'X'.code: // XBX
+			var f = new haxe.io.BytesInput(entry.getBytes());
+			var xbx = new h3d.fbx.XBXReader(f).read();
+			lib.load(xbx);
+			f.close();
+		default:
+			throw "Unsupported model format " + entry.path;
+		}
+		if( isLeftHanded ) lib.leftHandConvert();
+		return lib;
 	}
 	
 }

+ 0 - 1
hxd/res/Sound.hx

@@ -23,7 +23,6 @@ class Sound extends Resource {
 		default:
 			throw "Unsupported sound format " + entry.path;
 		}
-		hxd.impl.Tmp.saveBytes(bytes);
 		snd.play();
 		#else
 		#end

+ 100 - 32
hxd/res/Texture.hx

@@ -2,19 +2,41 @@ package hxd.res;
 
 class Texture extends Resource {
 	
+	static var TMP = {
+		var b = haxe.io.Bytes.alloc(4);
+		b.set(0, 0xFF);
+		b.set(1, 0x80);
+		b.set(2, 0x80);
+		b.set(3, 0xFF);
+		b;
+	}
+	
+	var needResize : Bool;
 	var tex : h3d.mat.Texture;
-	var size : { width : Int, height : Int };
+	var inf : { width : Int, height : Int, isPNG : Bool };
 	
 	public function getSize() : { width : Int, height : Int } {
-		if( size != null )
-			return size;
+		if( inf != null )
+			return inf;
 		var f = new FileInput(entry);
-		var width = 0, height = 0;
+		var width = 0, height = 0, isPNG = false;
 		switch( f.readUInt16() ) {
 		case 0xD8FF: // JPG
 			f.bigEndian = true;
-			throw "TODO";
+			while( true ) {
+				switch( f.readUInt16() ) {
+				case 0xFFC2, 0xFFC0:
+					var len = f.readUInt16();
+					var prec = f.readByte();
+					height = f.readUInt16();
+					width = f.readUInt16();
+					break;
+				default:
+					f.skip(f.readUInt16() - 2);
+				}
+			}
 		case 0x5089: // PNG
+			isPNG = true;
 			var TMP = hxd.impl.Tmp.getBytes(256);
 			f.bigEndian = true;
 			f.readBytes(TMP, 0, 6);
@@ -35,55 +57,101 @@ class Texture extends Resource {
 			}
 			hxd.impl.Tmp.saveBytes(TMP);
 		default:
-			throw "Unsupported file format " + entry.name;
+			throw "Unsupported texture format " + entry.path;
 		}
 		f.close();
-		size = { width : width, height : height };
-		return size;
+		inf = { width : width, height : height, isPNG : isPNG };
+		return inf;
 	}
 	
 	function loadTexture() {
 		var tw = tex.width, th = tex.height;
-		var w =	size.width, h = size.height;
+		var w =	inf.width, h = inf.height;
 		var isSquare = w == tw && h == th;
-		entry.loadBitmap(function(bmp) {
-			if( isSquare )
-				tex.uploadBitmap(bmp);
-			else {
-				var out = hxd.impl.Tmp.getBytes(tw * th * 4);
-				var bmp = bmp.getBytes();
-				var p = 0, b = 0;
-				for( y in 0...h ) {
-					for( x in 0...w * 4 )
-						out.set(p++, bmp.get(b++));
-					for( i in 0...(tw - w) * 4 )
-						out.set(p++, 0);
+		if( inf.isPNG ) {
+			function load() {
+				if( needResize ) {
+					tex.resize(tw, th);
+					needResize = false;
+				}
+				// immediately loading the PNG is faster than going through loadBitmap
+				var png = new format.png.Reader(new haxe.io.BytesInput(entry.getBytes()));
+				png.checkCRC = false;
+				var bytes = hxd.impl.Tmp.getBytes(tw * th * 4);
+				format.png.Tools.extract32(png.read(), bytes);
+				if( !isSquare ) {
+					throw "TODO";
 				}
-				for( i in 0...(th - h) * tw )
-					out.set(p++, 0);
-				hxd.impl.Tmp.saveBytes(bmp);
-				tex.uploadBytes(out);
-				hxd.impl.Tmp.saveBytes(out);
+				tex.uploadBytes(bytes);
+				hxd.impl.Tmp.saveBytes(bytes);
+				trace(flash.Lib.getTimer());
 			}
-			bmp.dispose();
-		});
+			if( entry.isAvailable )
+				load();
+			else
+				entry.load(load);
+		} else {
+			// use native decoding
+			entry.loadBitmap(function(bmp) {
+				if( needResize ) {
+					tex.resize(tw, th);
+					needResize = false;
+				}
+				if( isSquare )
+					tex.uploadBitmap(bmp);
+				else {
+					var out = hxd.impl.Tmp.getBytes(tw * th * 4);
+					var bmp = bmp.getBytes();
+					var p = 0, b = 0;
+					for( y in 0...h ) {
+						for( x in 0...w * 4 )
+							out.set(p++, bmp.get(b++));
+						for( i in 0...(tw - w) * 4 )
+							out.set(p++, 0);
+					}
+					for( i in 0...(th - h) * tw )
+						out.set(p++, 0);
+					hxd.impl.Tmp.saveBytes(bmp);
+					tex.uploadBytes(out);
+					hxd.impl.Tmp.saveBytes(out);
+				}
+				bmp.dispose();
+				trace(flash.Lib.getTimer());
+			});
+		}
 	}
 	
-	public function toTexture( ?hasAlpha : Bool ) : h3d.mat.Texture {
+	public function toTexture() : h3d.mat.Texture {
 		if( tex != null && !tex.isDisposed() )
 			return tex;
 		if( tex != null ) {
 			tex.dispose();
 			tex = null;
 		}
-		var size = getSize();
-		var w = size.width, h = size.height;
+		getSize();
+		var w = inf.width, h = inf.height;
 		var tw = 1, th = 1;
 		while( tw < w ) tw <<= 1;
 		while( th < h ) th <<= 1;
-		tex = h3d.Engine.getCurrent().mem.allocTexture(tw, th, false);
+
+		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
+			needResize = true;
+			tex = h3d.Engine.getCurrent().mem.allocTexture(1, 1, false);
+			tex.uploadBytes(TMP);
+			@:privateAccess {
+				tex.width = tw;
+				tex.height = th;
+			}
+		}
+		
 		loadTexture();
 		tex.onContextLost = function() {
+			needResize = false;
 			loadTexture();
 			return true;
 		};