浏览代码

texture and sound resources loading working in flash

Nicolas Cannasse 12 年之前
父节点
当前提交
463c265a4c
共有 9 个文件被更改,包括 253 次插入9 次删除
  1. 28 0
      hxd/BitmapData.hx
  2. 41 0
      hxd/impl/Memory.hx
  3. 33 0
      hxd/impl/Tmp.hx
  4. 10 2
      hxd/res/EmbedFileSystem.hx
  5. 2 1
      hxd/res/FileEntry.hx
  6. 25 0
      hxd/res/FileInput.hx
  7. 3 3
      hxd/res/FileTree.hx
  8. 24 1
      hxd/res/Sound.hx
  9. 87 2
      hxd/res/Texture.hx

+ 28 - 0
hxd/BitmapData.hx

@@ -53,6 +53,10 @@ abstract BitmapData(InnerData) {
 	inline function get_height() {
 		return this.height;
 	}
+	
+	public inline function getBytes() {
+		return nativeGetBytes(this);
+	}
 
 	public inline function toNative() : InnerData {
 		return this;
@@ -62,4 +66,28 @@ abstract BitmapData(InnerData) {
 		return cast bmp;
 	}
 	
+	static function nativeGetBytes( b : InnerData ) {
+		#if flash
+		var bytes = haxe.io.Bytes.ofData(b.getPixels(b.rect));
+		// it is necessary to swap the bytes from BE to LE
+		var mem = hxd.impl.Memory.select(bytes);
+		for( i in 0...b.width*b.height ) {
+			var p = i << 2;
+			var a = mem.b(p);
+			var r = mem.b(p+1);
+			var g = mem.b(p+2);
+			var b = mem.b(p+3);
+			mem.wb(p, b);
+			mem.wb(p+1, g);
+			mem.wb(p+2, r);
+			mem.wb(p+3, a);
+		}
+		mem.end();
+		return bytes;
+		#else
+		throw "TODO";
+		return null;
+		#end
+	}
+	
 }

+ 41 - 0
hxd/impl/Memory.hx

@@ -0,0 +1,41 @@
+package hxd.impl;
+
+class MemoryReader {
+
+	public function new() {
+	}
+	
+	public inline function b( addr : Int ) {
+		return flash.Memory.getByte(addr);
+	}
+	
+	public inline function wb( addr : Int, v : Int ) {
+		flash.Memory.setByte(addr, v);
+	}
+	
+	public inline function end() {
+		@:privateAccess Memory.end();
+	}
+
+}
+
+class Memory {
+
+	static var stack = new Array<haxe.io.Bytes>();
+	static var current : haxe.io.Bytes = null;
+	static var inst = new MemoryReader();
+	
+	public static function select( b : haxe.io.Bytes ) {
+		flash.Memory.select(b.getData());
+		if( current != null ) stack.push(current);
+		current = b;
+		return inst;
+	}
+	
+	static function end() {
+		current = stack.pop();
+		if( current != null )
+			flash.Memory.select(current.getData());
+	}
+
+}

+ 33 - 0
hxd/impl/Tmp.hx

@@ -0,0 +1,33 @@
+package hxd.impl;
+
+class Tmp {
+
+	static var bytes = new Array<haxe.io.Bytes>();
+	
+	public static function getBytes( size : Int ) {
+		for( i in 0...bytes.length ) {
+			var b = bytes[i];
+			if( b.length >= size ) {
+				bytes.splice(i, 1);
+				return b;
+			}
+		}
+		var sz = 1024;
+		while( sz < size )
+			sz = (sz * 3) >> 1;
+		return haxe.io.Bytes.alloc(sz);
+	}
+	
+	public static function saveBytes( b : haxe.io.Bytes ) {
+		for( i in 0...bytes.length ) {
+			if( bytes[i].length <= b.length ) {
+				bytes.insert(i, b);
+				if( bytes.length > 8 )
+					bytes.pop();
+				return;
+			}
+		}
+		bytes.push(b);
+	}
+	
+}

+ 10 - 2
hxd/res/EmbedFileSystem.hx

@@ -35,12 +35,20 @@ private class EmbedEntry extends FileEntry {
 		#if flash
 		if( bytes == null )
 			bytes = Type.createInstance(data, []);
+		bytes.position = 0;
+		#end
+	}
+	
+	override function readByte() : Int {
+		#if flash
+		return bytes.readUnsignedByte();
+		#else
+		return 0;
 		#end
 	}
 	
 	override function read( out : haxe.io.Bytes, pos : Int, size : Int ) : Void {
 		#if flash
-		if( bytes == null ) throw "File not opened";
 		bytes.readBytes(out.getData(), pos, size);
 		#end
 	}
@@ -132,7 +140,7 @@ class EmbedFileSystem #if !macro implements FileSystem #end {
 	#if flash
 	static var invalidChars = ~/[^A-Za-z0-9_]/g;
 	static function resolve( path : String ) {
-		return "hxd._res.R"+invalidChars.replace(path,"_");
+		return "hxd._res.R_"+invalidChars.replace(path,"_");
 	}
 	#end
 	

+ 2 - 1
hxd/res/FileEntry.hx

@@ -10,7 +10,8 @@ class FileEntry {
 	
 	public function getBytes() : haxe.io.Bytes return null;
 	
-	public function open() {}
+	public function open() { }
+	public function readByte() : Int return 0;
 	public function read( out : haxe.io.Bytes, pos : Int, size : Int ) {}
 	public function close() {}
 	

+ 25 - 0
hxd/res/FileInput.hx

@@ -0,0 +1,25 @@
+package hxd.res;
+
+class FileInput extends haxe.io.Input {
+	
+	var f : FileEntry;
+	
+	public function new(f) {
+		this.f = f;
+		f.open();
+	}
+	
+	override function readByte() {
+		return f.readByte();
+	}
+	
+	override function readBytes( b : haxe.io.Bytes, pos : Int, len : Int ) {
+		f.read(b, pos, len);
+		return len;
+	}
+	
+	override function close() {
+		f.close();
+	}
+
+}

+ 3 - 3
hxd/res/FileTree.hx

@@ -73,7 +73,7 @@ class FileTree {
 				if( ignoredExt.exists(ext.toLowerCase()) )
 					continue;
 				if( embedFile(f, ext, relPath + "/" + f, path) )
-					Reflect.setField(data, f, null);
+					Reflect.setField(data, f, true);
 			}
 		}
 		return data;
@@ -181,14 +181,14 @@ class FileTree {
 			if( sys.FileSystem.isDirectory(path) ) {
 				if( ignoredDir.exists(f.toLowerCase()) )
 					continue;
-				field = handleDir(f, relPath+"/"+f, path);
+				field = handleDir(f, relPath.length == 0 ? f : relPath+"/"+f, path);
 			} else {
 				var extParts = f.split(".");
 				var noExt = extParts.shift();
 				ext = extParts.join(".");
 				if( ignoredExt.exists(ext.toLowerCase()) )
 					continue;
-				field = handleFile(f, ext, relPath + "/" + f, path);
+				field = handleFile(f, ext, relPath.length == 0 ? f : relPath + "/" + f, path);
 				f = noExt;
 			}
 			if( field != null ) {

+ 24 - 1
hxd/res/Sound.hx

@@ -2,8 +2,31 @@ package hxd.res;
 
 class Sound extends Resource {
 	
+	#if flash
+	var snd : flash.media.Sound;
+	#end
+	
 	public function play() {
-		trace("TODO");
+		#if flash
+		if( snd != null ) {
+			snd.play();
+			return;
+		}
+		snd = new flash.media.Sound();
+		var bytes = entry.getBytes();
+		switch( bytes.get(0) ) {
+		case 'R'.code: // RIFF (wav)
+			// TODO : use snd.loadPCMFromByteArray
+			throw "WAV not supported ATM";
+		case 255: // MP3
+			snd.loadCompressedDataFromByteArray(bytes.getData(), bytes.length);
+		default:
+			throw "Unsupported sound format " + entry.path;
+		}
+		hxd.impl.Tmp.saveBytes(bytes);
+		snd.play();
+		#else
+		#end
 	}
 
 }

+ 87 - 2
hxd/res/Texture.hx

@@ -2,12 +2,97 @@ package hxd.res;
 
 class Texture extends Resource {
 	
+	var tex : h3d.mat.Texture;
+	var size : { width : Int, height : Int };
+	
+	public function getSize() : { width : Int, height : Int } {
+		if( size != null )
+			return size;
+		var f = new FileInput(entry);
+		var width = 0, height = 0;
+		switch( f.readUInt16() ) {
+		case 0xD8FF: // JPG
+			f.bigEndian = true;
+			throw "TODO";
+		case 0x5089: // PNG
+			var TMP = hxd.impl.Tmp.getBytes(256);
+			f.bigEndian = true;
+			f.readBytes(TMP, 0, 6);
+			while( true ) {
+				var dataLen = f.readInt32();
+				if( f.readInt32() == ('I'.code << 24) | ('H'.code << 16) | ('D'.code << 8) | 'R'.code ) {
+					width = f.readInt32();
+					height = f.readInt32();
+					break;
+				}
+				// skip data
+				while( dataLen > 0 ) {
+					var k = dataLen > TMP.length ? TMP.length : dataLen;
+					f.readBytes(TMP, 0, k);
+					dataLen -= k;
+				}
+				var crc = f.readInt32();
+			}
+			hxd.impl.Tmp.saveBytes(TMP);
+		default:
+			throw "Unsupported file format " + entry.name;
+		}
+		f.close();
+		size = { width : width, height : height };
+		return size;
+	}
+	
+	function loadTexture() {
+		var tw = tex.width, th = tex.height;
+		var w =	size.width, h = size.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);
+				}
+				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();
+		});
+	}
+	
 	public function toTexture( ?hasAlpha : Bool ) : h3d.mat.Texture {
-		return null;
+		if( tex != null && !tex.isDisposed() )
+			return tex;
+		if( tex != null ) {
+			tex.dispose();
+			tex = null;
+		}
+		var size = getSize();
+		var w = size.width, h = size.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);
+		loadTexture();
+		tex.onContextLost = function() {
+			loadTexture();
+			return true;
+		};
+		return tex;
 	}
 	
 	public function toTile() : h2d.Tile {
-		return null;
+		var size = getSize();
+		return h2d.Tile.fromTexture(toTexture()).sub(0, 0, size.width, size.height);
 	}
 	
 }