Refactor into Image and ImageBuffer

This commit is contained in:
Joshua Granick
2014-08-01 20:22:39 -07:00
parent 4a9716f4e7
commit 1749a18ab4
6 changed files with 349 additions and 227 deletions

View File

@@ -5,7 +5,7 @@ package lime;
import haxe.Unserializer;
import lime.graphics.Font;
import lime.media.AudioBuffer;
import lime.media.Image;
import lime.media.ImageBuffer;
import lime.utils.ByteArray;
@@ -189,7 +189,7 @@ class Assets {
* @param useCache (Optional) Whether to use BitmapData from the cache(Default: true)
* @return A new BitmapData object
*/
public static function getImage (id:String, useCache:Bool = true):Image {
public static function getImageBuffer (id:String, useCache:Bool = true):ImageBuffer {
initialize ();
@@ -217,7 +217,7 @@ class Assets {
if (library.isLocal (symbolName, cast AssetType.IMAGE)) {
var image = library.getImage (symbolName);
var image = library.getImageBuffer (symbolName);
if (useCache && cache.enabled) {
@@ -500,12 +500,12 @@ class Assets {
}
private static function isValidImage (image:Image):Bool {
private static function isValidImage (buffer:ImageBuffer):Bool {
#if (tools && !display)
#if (cpp || neko)
return true;
return (buffer != null);
//return (bitmapData.__handle != null);
#elseif flash
@@ -519,7 +519,7 @@ class Assets {
return false;
}*/
return true;
return (buffer != null);
#end
#end
@@ -651,7 +651,7 @@ class Assets {
}
public static function loadImage (id:String, handler:Image -> Void, useCache:Bool = true):Void {
public static function loadImageBuffer (id:String, handler:ImageBuffer -> Void, useCache:Bool = true):Void {
initialize ();
@@ -680,7 +680,7 @@ class Assets {
if (useCache && cache.enabled) {
library.loadImage (symbolName, function (image:Image):Void {
library.loadImageBuffer (symbolName, function (image:ImageBuffer):Void {
cache.image.set (id, image);
handler (image);
@@ -689,7 +689,7 @@ class Assets {
} else {
library.loadImage (symbolName, handler);
library.loadImageBuffer (symbolName, handler);
}
@@ -965,7 +965,7 @@ class AssetLibrary {
}
public function getImage (id:String):Image {
public function getImageBuffer (id:String):ImageBuffer {
return null;
@@ -1046,9 +1046,9 @@ class AssetLibrary {
}
public function loadImage (id:String, handler:Image -> Void):Void {
public function loadImageBuffer (id:String, handler:ImageBuffer -> Void):Void {
handler (getImage (id));
handler (getImageBuffer (id));
}
@@ -1097,7 +1097,7 @@ class AssetCache {
public var audio:Map<String, AudioBuffer>;
public var enabled:Bool = true;
public var image:Map<String, Image>;
public var image:Map<String, ImageBuffer>;
public var font:Map<String, Font>;
@@ -1105,7 +1105,7 @@ class AssetCache {
audio = new Map<String, AudioBuffer> ();
font = new Map<String, Font> ();
image = new Map<String, Image> ();
image = new Map<String, ImageBuffer> ();
}
@@ -1116,7 +1116,7 @@ class AssetCache {
audio = new Map<String, AudioBuffer> ();
font = new Map<String, Font> ();
image = new Map<String, Image> ();
image = new Map<String, ImageBuffer> ();
} else {

View File

@@ -2,6 +2,7 @@ package lime.graphics;
import haxe.ds.StringMap;
import lime.media.Image;
import lime.media.ImageBuffer;
import lime.utils.UInt8Array;
import lime.system.System;
#if js
@@ -20,7 +21,7 @@ typedef GlyphRect = {
}
typedef GlyphData = {
var image:Image;
var image:ImageBuffer;
var glyphs:StringMap<GlyphRect>;
};
@@ -134,7 +135,7 @@ class Font {
image.src = __canvas.toDataURL();
return {
glyphs: glyphRects,
image: new lime.media.Image (image, __canvas.width, __canvas.height)
image: ImageBuffer.fromImage (image)
}
#elseif flash
@@ -206,7 +207,7 @@ class Font {
return {
glyphs: glyphRects,
image: new Image (bd, bd.width, bd.height)
image: ImageBuffer.fromBitmapData (bd)
}
#elseif (cpp || neko)
@@ -235,7 +236,7 @@ class Font {
return {
glyphs: glyphRects,
image: new Image (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp)
image: new ImageBuffer (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp)
};
}

View File

@@ -1,6 +1,8 @@
package lime.media;
import lime.app.Application;
import lime.graphics.Renderer;
import lime.utils.ByteArray;
import lime.utils.UInt8Array;
import lime.system.System;
@@ -13,6 +15,8 @@ import js.Browser;
import flash.display.BitmapData;
#end
@:access(lime.app.Application)
class Image {
@@ -22,55 +26,42 @@ class Image {
private static var __context:CanvasRenderingContext2D;
#end
public var bpp:Int;
public var data (get, set):ImageBuffer;
public var buffer:ImageBuffer;
public var height:Int;
public var offsetX:Int;
public var offsetY:Int;
public var powerOfTwo (get, null):Bool;
public var premultiplied:Bool;
public var src:ImageSource;
public var textureHeight:Int;
public var textureWidth:Int;
public var powerOfTwo (get, set):Bool;
public var premultiplied (get, set):Bool;
public var width:Int;
private var __data:ImageBuffer;
private var __renderer:Renderer;
public function new (src:ImageSource = null, width:Int = 0, height:Int = 0, bpp:Int = 4) {
public function new (buffer:ImageBuffer, renderer:Renderer = null) {
this.src = src;
#if (!js && !flash)
this.__data = src;
#end
this.buffer = buffer;
this.width = textureWidth = width;
this.height = textureHeight = height;
this.bpp = bpp;
if (renderer == null) {
__renderer = Application.__instance.window.currentRenderer;
} else {
__renderer = renderer;
}
width = buffer.width;
height = buffer.height;
offsetX = 0;
offsetY = 0;
public function forcePowerOfTwo () {
switch (__renderer.context) {
if (powerOfTwo) return;
textureWidth = 1;
textureHeight = 1;
while (textureWidth < width) {
textureWidth <<= 1;
}
while (textureHeight < height) {
textureHeight <<= 1;
}
case OPENGL (_):
#if js
if (buffer.data == null && buffer.src != null && buffer.width > 0 && buffer.height > 0) {
if (__canvas == null) {
@@ -79,147 +70,243 @@ class Image {
}
__canvas.width = textureWidth;
__canvas.height = textureHeight;
__context.clearRect (0, 0, textureWidth, textureHeight);
__context.drawImage (src, 0, 0, width, height);
__canvas.width = buffer.width;
__canvas.height = buffer.height;
__context.drawImage (buffer.src, 0, 0);
var pixels = __context.getImageData (0, 0, textureWidth, textureHeight);
__data = new ImageBuffer (pixels.data);
var pixels = __context.getImageData (0, 0, buffer.width, buffer.height);
buffer.data = pixels.data;
#elseif flash
}
#end
var bitmapData = new BitmapData (textureWidth, textureHeight, true, 0x000000);
bitmapData.draw (src, null, null, null, true);
default:
var pixels = bitmapData.getPixels (bitmapData.rect);
__data = new ImageBuffer (pixels);
}
}
public function getPixel (x:Int, y:Int):Int {
// TODO: cache context type?
x += offsetX;
y += offsetY;
switch (__renderer.context) {
case OPENGL (_):
// TODO: handle premultiplied
var data = buffer.data;
var index = (y * buffer.width + x) * 4;
return ((data[index + 3] << 24) | (data[index] << 16 ) | (data[index + 1] << 8) | data[index + 2]);
case FLASH (_):
#if flash
return buffer.src.getPixel (x, y);
#else
var newData = new ImageBuffer (textureWidth * textureHeight * 4);
for (y in 0...height) {
for (x in 0...width) {
newData.setPixel (y * textureWidth + x, newData.getPixel (y * width + x));
}
}
__data = newData;
return 0;
#end
case DOM (_):
// TODO
return 0;
case CANVAS (_):
// TODO
return 0;
default:
return 0;
}
public static function fromBytes (bytes:ByteArray):Image {
}
#if (cpp || neko)
var imageData = lime_image_load (bytes);
return (imageData == null ? null : new Image (new ImageBuffer (imageData.data), imageData.width, imageData.height, imageData.bpp));
public function setPixel (x:Int, y:Int, value:Int):Void {
#else
x += offsetX;
y += offsetY;
throw "Image.loadFromFile not supported on this target";
switch (__renderer.context) {
case OPENGL (_):
// TODO: handle premultiplied
var data = buffer.data;
var index = (y * buffer.width + x) * 4;
data[index + 3] = (value >> 24) & 0xFF;
data[index] = (value >> 16) & 0xFF;
data[index + 1] = (value >> 8) & 0xFF;
data[index + 2] = value & 0xFF;
case FLASH (_):
#if flash
buffer.src.setPixel (x, y, value);
#end
case DOM (_):
// TODO
case CANVAS (_):
// TODO
default:
}
public static function fromFile (path:String) {
#if (cpp || neko)
var imageData = lime_image_load (path);
return (imageData == null ? null : new Image (new ImageBuffer (imageData.data), imageData.width, imageData.height, imageData.bpp));
#else
throw "Image.loadFromFile not supported on this target";
#end
}
public function premultiplyAlpha ():Void {
if (premultiplied) return;
var data = this.data;
data.premultiply ();
premultiplied = true;
}
private function get_data ():ImageBuffer {
if (__data == null && src != null && width > 0 && height > 0) {
#if js
if (__canvas == null) {
__canvas = cast Browser.document.createElement ("canvas");
__context = cast __canvas.getContext ("2d");
}
__canvas.width = width;
__canvas.height = height;
__context.drawImage (src, 0, 0);
var pixels = __context.getImageData (0, 0, width, height);
__data = new ImageBuffer (pixels.data);
#elseif flash
var pixels = src.getPixels (src.rect);
__data = new ImageBuffer (pixels);
#end
}
return __data;
}
// Get & Set Methods
private function set_data (value:ImageBuffer):ImageBuffer {
return __data = value;
}
private function get_powerOfTwo ():Bool {
return ((width != 0) && ((width & (~width + 1)) == width)) && ((height != 0) && ((height & (~height + 1)) == height));
return ((buffer.width != 0) && ((buffer.width & (~buffer.width + 1)) == buffer.width)) && ((buffer.height != 0) && ((buffer.height & (~buffer.height + 1)) == buffer.height));
}
#if (cpp || neko)
private static var lime_image_load:Dynamic = System.load ("lime", "lime_image_load", 1);
private function set_powerOfTwo (value:Bool):Bool {
if (value != powerOfTwo) {
var newWidth = 1;
var newHeight = 1;
while (newWidth < buffer.width) {
newWidth <<= 1;
}
while (newHeight < buffer.height) {
newHeight <<= 1;
}
switch (__renderer.context) {
case OPENGL (_):
var data = buffer.data;
var newData = new UInt8Array (newWidth * newHeight * 4);
var sourceIndex:Int, index:Int;
for (y in 0...buffer.height) {
for (x in 0...buffer.width) {
sourceIndex = y * buffer.width + x;
index = y * newWidth + x * 4;
newData[index] = data[sourceIndex];
newData[index + 1] = data[sourceIndex + 1];
newData[index + 2] = data[sourceIndex + 2];
newData[index + 3] = data[sourceIndex + 3];
}
}
buffer.data = newData;
buffer.width = newWidth;
buffer.height = newHeight;
case FLASH (_):
#if flash
var bitmapData = new BitmapData (newWidth, newHeight, true, 0x000000);
bitmapData.draw (buffer.src, null, null, null, true);
buffer.src = bitmapData;
buffer.width = newWidth;
buffer.height = newHeight;
#end
default:
// TODO
}
}
return value;
}
private function get_premultiplied ():Bool {
return buffer.premultiplied;
}
private function set_premultiplied (value:Bool):Bool {
if (value && !buffer.premultiplied) {
switch (__renderer.context) {
case OPENGL (_):
var data = buffer.data;
var index, a;
var length = Std.int (data.length / 4);
for (i in 0...length) {
index = i * 4;
a = data[index + 3];
data[index] = (data[index] * a) >> 8;
data[index + 1] = (data[index + 1] * a) >> 8;
data[index + 2] = (data[index + 2] * a) >> 8;
}
buffer.premultiplied = true;
default:
// TODO
}
} else {
// TODO, unmultiply
}
return value;
}
}
#if js
private typedef ImageSource = js.html.Image;
#elseif flash
private typedef ImageSource = flash.display.BitmapData;
#else
private typedef ImageSource = UInt8Array;
#end

View File

@@ -1,82 +1,120 @@
package lime.media;
import lime.system.System;
import lime.utils.ByteArray;
import lime.utils.UInt8Array;
abstract ImageBuffer(UInt8Array) from UInt8Array to UInt8Array {
#if js
import js.html.Image in HTMLImage;
#elseif flash
import flash.display.BitmapData;
#end
public var length (get, never):Int;
class ImageBuffer {
public function new (data:Dynamic = null) {
public var bitsPerPixel:Int;
public var data:UInt8Array;
public var height:Int;
public var premultiplied:Bool;
public var width:Int;
this = new UInt8Array (data);
#if js
public var src:HTMLImage;
#elseif flash
public var src:BitmapData;
#else
public var src:Dynamic;
#end
public function new (data:UInt8Array = null, width:Int = 0, height:Int = 0, bitsPerPixel:Int = 4) {
this.data = data;
this.width = width;
this.height = height;
this.bitsPerPixel = bitsPerPixel;
}
public function getComponent (pos:Int):Int {
#if flash
public static function fromBitmapData (bitmapData:BitmapData):ImageBuffer {
return this[pos];
var buffer = new ImageBuffer (null, bitmapData.width, bitmapData.height);
buffer.src = bitmapData;
return buffer;
}
#end
public static function fromBytes (bytes:ByteArray):ImageBuffer {
#if (cpp || neko)
var data = lime_image_load (bytes);
if (data != null) {
return new ImageBuffer (new UInt8Array (data.data), data.width, data.height, data.bpp);
} else {
return null;
}
#else
throw "ImageBuffer.loadFromFile not supported on this target";
#end
}
public function getPixel (pos:Int):Int {
public static function fromFile (path:String):ImageBuffer {
var index = pos * 4;
#if (cpp || neko)
return ((this[index + 3] << 24) | (this[index] << 16 ) | (this[index + 1] << 8) | this[index + 2]);
var data = lime_image_load (path);
if (data != null) {
return new ImageBuffer (new UInt8Array (data.data), data.width, data.height, data.bpp);
} else {
return null;
}
#else
throw "ImageBuffer.loadFromFile not supported on this target";
#end
}
public function premultiply ():Void {
#if js
public static function fromImage (image:HTMLImage):ImageBuffer {
var index, a;
var length = Std.int (this.length / 4);
for (i in 0...length) {
index = i * 4;
a = this[index + 3];
this[index] = (this[index] * a) >> 8;
this[index + 1] = (this[index + 1] * a) >> 8;
this[index + 2] = (this[index + 2] * a) >> 8;
}
var buffer = new ImageBuffer (null, image.width, image.height);
buffer.src = image;
return buffer;
}
#end
public function setComponent (pos:Int, value:Int):Void {
this[pos] = value;
}
public function setPixel (pos:Int, value:Int):Void {
var index = pos * 4;
this[index + 3] = (value >> 24) & 0xFF;
this[index] = (value >> 16) & 0xFF;
this[index + 1] = (value >> 8) & 0xFF;
this[index + 2] = value & 0xFF;
}
private function get_length ():Int {
return this.length;
}
#if (cpp || neko)
private static var lime_image_load:Dynamic = System.load ("lime", "lime_image_load", 1);
#end
}

View File

@@ -4,6 +4,7 @@ package;
import lime.app.Application;
import lime.graphics.opengl.*;
import lime.graphics.RenderContext;
import lime.media.ImageBuffer;
import lime.utils.Float32Array;
import lime.utils.GLUtils;
import lime.utils.Matrix4;
@@ -14,6 +15,7 @@ class Main extends Application {
private var buffer:GLBuffer;
private var image:ImageBuffer;
private var matrixUniform:GLUniformLocation;
private var program:GLProgram;
private var texture:GLTexture;
@@ -30,11 +32,12 @@ class Main extends Application {
public override function init (context:RenderContext):Void {
image = Assets.getImageBuffer ("assets/lime.png");
switch (context) {
case CANVAS (context):
var image = Assets.getImage ("assets/lime.png");
context.fillStyle = "#" + StringTools.hex (config.background, 6);
context.fillRect (0, 0, window.width, window.height);
context.drawImage (image.src, 0, 0, image.width, image.height);
@@ -42,16 +45,13 @@ class Main extends Application {
case DOM (element):
#if js
var image = new js.html.Image ();
image.src = Assets.getPath ("assets/lime.png");
element.style.backgroundColor = "#" + StringTools.hex (config.background, 6);
element.appendChild (image);
element.appendChild (image.src);
#end
case FLASH (sprite):
#if flash
var image = Assets.getImage ("assets/lime.png");
var bitmap = new flash.display.Bitmap (image.src);
sprite.addChild (bitmap);
#end
@@ -98,8 +98,6 @@ class Main extends Application {
gl.enableVertexAttribArray (textureAttribute);
gl.uniform1i (imageUniform, 0);
var image = Assets.getImage ("assets/lime.png");
var data = [
image.width, image.height, 0, 1, 1,
@@ -121,7 +119,7 @@ class Main extends Application {
#if js
gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image.src);
#else
gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA, image.textureWidth, image.textureHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, image.data);
gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, image.data);
#end
gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

View File

@@ -5,7 +5,7 @@ import haxe.Timer;
import haxe.Unserializer;
import lime.app.Preloader;
import lime.media.AudioBuffer;
import lime.media.Image;
import lime.media.ImageBuffer;
import lime.media.openal.AL;
import lime.utils.ByteArray;
import lime.utils.UInt8Array;
@@ -224,21 +224,19 @@ class DefaultAssetLibrary extends AssetLibrary {
}
public override function getImage (id:String):Image {
public override function getImageBuffer (id:String):ImageBuffer {
#if flash
var bitmapData = cast (Type.createInstance (className.get (id), []), BitmapData);
return new Image (bitmapData, bitmapData.width, bitmapData.height);
return ImageBuffer.fromBitmapData (cast (Type.createInstance (className.get (id), []), BitmapData));
#elseif js
var image = Preloader.images.get (path.get (id));
return new Image (image, image.width, image.height);
return ImageBuffer.fromImage (Preloader.images.get (path.get (id)));
#else
return Image.fromFile (path.get (id));
return ImageBuffer.fromFile (path.get (id));
#end
@@ -441,7 +439,7 @@ class DefaultAssetLibrary extends AssetLibrary {
}
public override function loadImage (id:String, handler:Image -> Void):Void {
public override function loadImageBuffer (id:String, handler:ImageBuffer -> Void):Void {
#if flash
@@ -451,20 +449,20 @@ class DefaultAssetLibrary extends AssetLibrary {
loader.contentLoaderInfo.addEventListener (Event.COMPLETE, function (event:Event) {
var bitmapData = cast (event.currentTarget.content, Bitmap).bitmapData;
handler (new Image (bitmapData, bitmapData.width, bitmapData.height));
handler (ImageBuffer.fromBitmapData (bitmapData));
});
loader.load (new URLRequest (path.get (id)));
} else {
handler (getImage (id));
handler (getImageBuffer (id));
}
#else
handler (getImage (id));
handler (getImageBuffer (id));
#end