Add support for PixelFormat (RGBA, ARGB) in Image, add more CFFI methods

This commit is contained in:
Joshua Granick
2015-04-14 13:49:58 -07:00
parent a6cb988d72
commit 560a78db62
14 changed files with 574 additions and 102 deletions

View File

@@ -134,6 +134,7 @@ class Image {
#if flash
this.buffer = new ImageBuffer (null, width, height);
if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8);
this.buffer.src = new BitmapData (width, height, true, color);
#end
@@ -196,7 +197,7 @@ class Image {
sourceRect = __clipRect (sourceRect);
if (buffer == null || sourceRect == null) return;
if (destChannel == ImageChannel.ALPHA && !transparent) return;
if (destChannel == ALPHA && !transparent) return;
if (sourceRect.width <= 0 || sourceRect.height <= 0) return;
if (sourceRect.x + sourceRect.width > sourceImage.width) sourceRect.width = sourceImage.width - sourceRect.x;
if (sourceRect.y + sourceRect.height > sourceImage.height) sourceRect.height = sourceImage.height - sourceRect.y;
@@ -316,7 +317,7 @@ class Image {
}
public function fillRect (rect:Rectangle, color:Int):Void {
public function fillRect (rect:Rectangle, color:Int, format:PixelFormat = null):Void {
rect = __clipRect (rect);
if (buffer == null || rect == null) return;
@@ -325,7 +326,7 @@ class Image {
case CANVAS:
ImageCanvasUtil.fillRect (this, rect, color);
ImageCanvasUtil.fillRect (this, rect, color, format);
case DATA:
@@ -333,11 +334,12 @@ class Image {
ImageCanvasUtil.convertToData (this);
#end
ImageDataUtil.fillRect (this, rect, color);
ImageDataUtil.fillRect (this, rect, color, format);
case FLASH:
rect.offset (offsetX, offsetY);
if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8);
buffer.__srcBitmapData.fillRect (rect.__toFlashRectangle (), color);
default:
@@ -347,7 +349,7 @@ class Image {
}
public function floodFill (x:Int, y:Int, color:Int):Void {
public function floodFill (x:Int, y:Int, color:Int, format:PixelFormat = null):Void {
if (buffer == null) return;
@@ -355,7 +357,7 @@ class Image {
case CANVAS:
ImageCanvasUtil.floodFill (this, x, y, color);
ImageCanvasUtil.floodFill (this, x, y, color, format);
case DATA:
@@ -363,10 +365,11 @@ class Image {
ImageCanvasUtil.convertToData (this);
#end
ImageDataUtil.floodFill (this, x, y, color);
ImageDataUtil.floodFill (this, x, y, color, format);
case FLASH:
if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8);
buffer.__srcBitmapData.floodFill (x + offsetX, y + offsetY, color);
default:
@@ -430,7 +433,7 @@ class Image {
}
public function getPixel (x:Int, y:Int):Int {
public function getPixel (x:Int, y:Int, format:PixelFormat = null):Int {
if (buffer == null || x < 0 || y < 0 || x >= width || y >= height) return 0;
@@ -438,7 +441,7 @@ class Image {
case CANVAS:
return ImageCanvasUtil.getPixel (this, x, y);
return ImageCanvasUtil.getPixel (this, x, y, format);
case DATA:
@@ -446,11 +449,21 @@ class Image {
ImageCanvasUtil.convertToData (this);
#end
return ImageDataUtil.getPixel (this, x, y);
return ImageDataUtil.getPixel (this, x, y, format);
case FLASH:
return buffer.__srcBitmapData.getPixel (x + offsetX, y + offsetY);
var color = buffer.__srcBitmapData.getPixel (x + offsetX, y + offsetY);
if (format == null || format == RGBA) {
return ((color & 0xFF) << 24) | (color >> 8);
} else {
return color;
}
default:
@@ -461,7 +474,7 @@ class Image {
}
public function getPixel32 (x:Int, y:Int):Int {
public function getPixel32 (x:Int, y:Int, format:PixelFormat = null):Int {
if (buffer == null || x < 0 || y < 0 || x >= width || y >= height) return 0;
@@ -469,7 +482,7 @@ class Image {
case CANVAS:
return ImageCanvasUtil.getPixel32 (this, x, y);
return ImageCanvasUtil.getPixel32 (this, x, y, format);
case DATA:
@@ -477,11 +490,21 @@ class Image {
ImageCanvasUtil.convertToData (this);
#end
return ImageDataUtil.getPixel32 (this, x, y);
return ImageDataUtil.getPixel32 (this, x, y, format);
case FLASH:
return buffer.__srcBitmapData.getPixel32 (x + offsetX, y + offsetY);
var color = buffer.__srcBitmapData.getPixel32 (x + offsetX, y + offsetY);
if (format == null || format == RGBA) {
return ((color & 0xFF) << 24) | (color >> 8);
} else {
return color;
}
default:
@@ -492,7 +515,7 @@ class Image {
}
public function getPixels (rect:Rectangle):ByteArray {
public function getPixels (rect:Rectangle, format:PixelFormat = null):ByteArray {
if (buffer == null) return null;
@@ -500,7 +523,7 @@ class Image {
case CANVAS:
return ImageCanvasUtil.getPixels (this, rect);
return ImageCanvasUtil.getPixels (this, rect, format);
case DATA:
@@ -508,12 +531,31 @@ class Image {
ImageCanvasUtil.convertToData (this);
#end
return ImageDataUtil.getPixels (this, rect);
return ImageDataUtil.getPixels (this, rect, format);
case FLASH:
rect.offset (offsetX, offsetY);
return buffer.__srcBitmapData.getPixels (rect.__toFlashRectangle ());
var byteArray = buffer.__srcBitmapData.getPixels (rect.__toFlashRectangle ());
if (format == null || format == RGBA) {
var color;
var length = Std.int (byteArray.length / 4);
for (i in 0...length) {
color = byteArray.readUnsignedInt ();
byteArray.position -= 4;
byteArray.writeUnsignedInt (((color & 0xFF) << 24) | (color >> 8));
}
byteArray.position = 0;
}
return cast byteArray;
default:
@@ -595,7 +637,7 @@ class Image {
}
public function setPixel (x:Int, y:Int, color:Int):Void {
public function setPixel (x:Int, y:Int, color:Int, format:PixelFormat = null):Void {
if (buffer == null || x < 0 || y < 0 || x >= width || y >= height) return;
@@ -603,7 +645,7 @@ class Image {
case CANVAS:
ImageCanvasUtil.setPixel (this, x, y, color);
ImageCanvasUtil.setPixel (this, x, y, color, format);
case DATA:
@@ -611,10 +653,11 @@ class Image {
ImageCanvasUtil.convertToData (this);
#end
ImageDataUtil.setPixel (this, x, y, color);
ImageDataUtil.setPixel (this, x, y, color, format);
case FLASH:
if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8);
buffer.__srcBitmapData.setPixel (x + offsetX, y + offsetX, color);
default:
@@ -624,7 +667,7 @@ class Image {
}
public function setPixel32 (x:Int, y:Int, color:Int):Void {
public function setPixel32 (x:Int, y:Int, color:Int, format:PixelFormat = null):Void {
if (buffer == null || x < 0 || y < 0 || x >= width || y >= height) return;
@@ -632,7 +675,7 @@ class Image {
case CANVAS:
ImageCanvasUtil.setPixel32 (this, x, y, color);
ImageCanvasUtil.setPixel32 (this, x, y, color, format);
case DATA:
@@ -640,10 +683,11 @@ class Image {
ImageCanvasUtil.convertToData (this);
#end
ImageDataUtil.setPixel32 (this, x, y, color);
ImageDataUtil.setPixel32 (this, x, y, color, format);
case FLASH:
if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8);
buffer.__srcBitmapData.setPixel32 (x + offsetX, y + offsetY, color);
default:
@@ -653,7 +697,7 @@ class Image {
}
public function setPixels (rect:Rectangle, byteArray:ByteArray):Void {
public function setPixels (rect:Rectangle, byteArray:ByteArray, format:PixelFormat = null):Void {
rect = __clipRect (rect);
if (buffer == null || rect == null) return;
@@ -662,7 +706,7 @@ class Image {
case CANVAS:
ImageCanvasUtil.setPixels (this, rect, byteArray);
ImageCanvasUtil.setPixels (this, rect, byteArray, format);
case DATA:
@@ -670,11 +714,32 @@ class Image {
ImageCanvasUtil.convertToData (this);
#end
ImageDataUtil.setPixels (this, rect, byteArray);
ImageDataUtil.setPixels (this, rect, byteArray, format);
case FLASH:
rect.offset (offsetX, offsetY);
if (format == null || format == RGBA) {
var srcData = byteArray;
byteArray = new ByteArray ();
#if flash
byteArray.length = srcData.length;
#end
var color;
var length = Std.int (byteArray.length / 4);
for (i in 0...length) {
color = srcData.readUnsignedInt ();
byteArray.writeUnsignedInt (((color & 0xFF) << 24) | (color >> 8));
}
srcData.position = 0;
byteArray.position = 0;
}
buffer.__srcBitmapData.setPixels (rect.__toFlashRectangle (), byteArray);
default:
@@ -1205,13 +1270,3 @@ class Image {
}
enum ImageChannel {
RED;
GREEN;
BLUE;
ALPHA;
}

View File

@@ -0,0 +1,11 @@
package lime.graphics;
enum ImageChannel {
RED;
GREEN;
BLUE;
ALPHA;
}

View File

@@ -0,0 +1,9 @@
package lime.graphics;
enum PixelFormat {
RGBA;
ARGB;
}

View File

@@ -4,6 +4,7 @@ package lime.graphics.utils;
import haxe.format.JsonParser;
import lime.graphics.Image;
import lime.graphics.ImageBuffer;
import lime.graphics.PixelFormat;
import lime.math.ColorMatrix;
import lime.math.Rectangle;
import lime.math.Vector2;
@@ -163,7 +164,7 @@ class ImageCanvasUtil {
}
public static function fillRect (image:Image, rect:Rectangle, color:Int):Void {
public static function fillRect (image:Image, rect:Rectangle, color:Int, format:PixelFormat):Void {
convertToCanvas (image);
sync (image);
@@ -190,42 +191,42 @@ class ImageCanvasUtil {
}
public static function floodFill (image:Image, x:Int, y:Int, color:Int):Void {
public static function floodFill (image:Image, x:Int, y:Int, color:Int, format:PixelFormat):Void {
convertToCanvas (image);
createImageData (image);
ImageDataUtil.floodFill (image, x, y, color);
ImageDataUtil.floodFill (image, x, y, color, format);
}
public static function getPixel (image:Image, x:Int, y:Int):Int {
public static function getPixel (image:Image, x:Int, y:Int, format:PixelFormat):Int {
convertToCanvas (image);
createImageData (image);
return ImageDataUtil.getPixel (image, x, y);
return ImageDataUtil.getPixel (image, x, y, format);
}
public static function getPixel32 (image:Image, x:Int, y:Int):Int {
public static function getPixel32 (image:Image, x:Int, y:Int, format:PixelFormat):Int {
convertToCanvas (image);
createImageData (image);
return ImageDataUtil.getPixel32 (image, x, y);
return ImageDataUtil.getPixel32 (image, x, y, format);
}
public static function getPixels (image:Image, rect:Rectangle):ByteArray {
public static function getPixels (image:Image, rect:Rectangle, format:PixelFormat):ByteArray {
convertToCanvas (image);
createImageData (image);
return ImageDataUtil.getPixels (image, rect);
return ImageDataUtil.getPixels (image, rect, format);
}
@@ -264,32 +265,32 @@ class ImageCanvasUtil {
}
public static function setPixel (image:Image, x:Int, y:Int, color:Int):Void {
public static function setPixel (image:Image, x:Int, y:Int, color:Int, format:PixelFormat):Void {
convertToCanvas (image);
createImageData (image);
ImageDataUtil.setPixel (image, x, y, color);
ImageDataUtil.setPixel (image, x, y, color, format);
}
public static function setPixel32 (image:Image, x:Int, y:Int, color:Int):Void {
public static function setPixel32 (image:Image, x:Int, y:Int, color:Int, format:PixelFormat):Void {
convertToCanvas (image);
createImageData (image);
ImageDataUtil.setPixel32 (image, x, y, color);
ImageDataUtil.setPixel32 (image, x, y, color, format);
}
public static function setPixels (image:Image, rect:Rectangle, byteArray:ByteArray):Void {
public static function setPixels (image:Image, rect:Rectangle, byteArray:ByteArray, format:PixelFormat):Void {
convertToCanvas (image);
createImageData (image);
ImageDataUtil.setPixels (image, rect, byteArray);
ImageDataUtil.setPixels (image, rect, byteArray, format);
}

View File

@@ -115,6 +115,15 @@ class ImageDataUtil {
}
var srcData = sourceImage.buffer.data;
var destData = image.buffer.data;
if (srcData == null || destData == null) return;
#if ((cpp || neko) && !disable_cffi)
lime_image_data_util_copy_channel (image, sourceImage, sourceRect, destPoint, srcIdx, destIdx);
#else
var srcStride = Std.int (sourceImage.buffer.width * 4);
var srcPosition = Std.int (((sourceRect.x + sourceImage.offsetX) * 4) + (srcStride * (sourceRect.y + sourceImage.offsetY)) + srcIdx);
var srcRowOffset = srcStride - Std.int (4 * (sourceRect.width + sourceImage.offsetX));
@@ -150,6 +159,8 @@ class ImageDataUtil {
}
#end
image.dirty = true;
}
@@ -169,6 +180,10 @@ class ImageDataUtil {
}
#if ((cpp || neko) && !disable_cffi)
lime_image_data_util_copy_pixels (image, sourceImage, sourceRect, destPoint, mergeAlpha);
#else
var rowOffset = Std.int (destPoint.y + image.offsetY - sourceRect.y - sourceImage.offsetY);
var columnOffset = Std.int (destPoint.x + image.offsetX - sourceRect.x - sourceImage.offsetY);
@@ -233,20 +248,41 @@ class ImageDataUtil {
}
#end
image.dirty = true;
}
public static function fillRect (image:Image, rect:Rectangle, color:Int):Void {
public static function fillRect (image:Image, rect:Rectangle, color:Int, format:PixelFormat):Void {
var a = (image.transparent) ? ((color & 0xFF000000) >>> 24) : 0xFF;
var r = (color & 0x00FF0000) >>> 16;
var g = (color & 0x0000FF00) >>> 8;
var b = (color & 0x000000FF);
var r, g, b, a;
if (format == ARGB) {
a = (image.transparent) ? (color >> 24) & 0xFF : 0xFF;
r = (color >> 16) & 0xFF;
g = (color >> 8) & 0xFF;
b = color & 0xFF;
} else {
r = (color >> 24) & 0xFF;
g = (color >> 16) & 0xFF;
b = (color >> 8) & 0xFF;
a = (image.transparent) ? color & 0xFF : 0xFF;
}
var rgba = (r | (g << 8) | (b << 16) | (a << 24));
var data = image.buffer.data;
if (data == null) return;
#if ((cpp || neko) && !disable_cffi)
lime_image_data_util_fill_rect (image, rect, rgba);
#else
if (rect.width == image.buffer.width && rect.height == image.buffer.height && rect.x == 0 && rect.y == 0 && image.offsetX == 0 && image.offsetY == 0) {
@@ -299,14 +335,18 @@ class ImageDataUtil {
}
#end
image.dirty = true;
}
public static function floodFill (image:Image, x:Int, y:Int, color:Int):Void {
public static function floodFill (image:Image, x:Int, y:Int, color:Int, format:PixelFormat):Void {
var data = image.buffer.data;
if (data == null) return;
var offset = (((y + image.offsetY) * (image.buffer.width * 4)) + ((x + image.offsetX) * 4));
var hitColorR = data[offset + 0];
var hitColorG = data[offset + 1];
@@ -371,46 +411,72 @@ class ImageDataUtil {
}
public static function getPixel (image:Image, x:Int, y:Int):Int {
public static function getPixel (image:Image, x:Int, y:Int, format:PixelFormat):Int {
var data = image.buffer.data;
var offset = (4 * (y + image.offsetY) * image.buffer.width + (x + image.offsetX) * 4);
var pixel;
if (image.premultiplied) {
var unmultiply = 255.0 / data[offset + 3];
return __clamp[Std.int (data[offset] * unmultiply)] << 16 | __clamp[Std.int (data[offset + 1] * unmultiply)] << 8 | __clamp[Std.int (data[offset + 2] * unmultiply)];
pixel = __clamp[Std.int (data[offset] * unmultiply)] << 24 | __clamp[Std.int (data[offset + 1] * unmultiply)] << 16 | __clamp[Std.int (data[offset + 2] * unmultiply)] << 8;
} else {
return (data[offset] << 16) | (data[offset + 1] << 8) | (data[offset + 2]);
pixel = (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8);
}
if (format == ARGB) {
return pixel >> 8 & 0xFFFFFF;
} else {
return pixel;
}
}
public static function getPixel32 (image:Image, x:Int, y:Int):Int {
public static function getPixel32 (image:Image, x:Int, y:Int, format:PixelFormat):Int {
var data = image.buffer.data;
var offset = (4 * (y + image.offsetY) * image.buffer.width + (x + image.offsetX) * 4);
var a = (image.transparent ? data[offset + 3] : 0xFF);
var r, g, b;
if (image.premultiplied && a != 0) {
var unmultiply = 255.0 / a;
return a << 24 | __clamp[Math.round (data[offset] * unmultiply)] << 16 | __clamp[Std.int (data[offset + 1] * unmultiply)] << 8 | __clamp[Std.int (data[offset + 2] * unmultiply)];
r = __clamp[Math.round (data[offset] * unmultiply)];
g = __clamp[Math.round (data[offset + 1] * unmultiply)];
b = __clamp[Math.round (data[offset + 2] * unmultiply)];
} else {
return a << 24 | data[offset] << 16 | data[offset + 1] << 8 | data[offset + 2];
r = data[offset];
g = data[offset + 1];
b = data[offset + 2];
}
if (format == ARGB) {
return a << 24 | r << 16 | g << 8 | b;
} else {
return r << 24 | g << 16 | b << 8 | a;
}
}
public static function getPixels (image:Image, rect:Rectangle):ByteArray {
public static function getPixels (image:Image, rect:Rectangle, format:PixelFormat):ByteArray {
var length = Std.int (rect.width * rect.height);
@@ -442,23 +508,52 @@ class ImageDataUtil {
byteArray.length = length * 4;
#end
for (i in 0...length) {
if (format == ARGB) {
#if flash
byteArray.writeUnsignedInt (srcData[srcPosition++]);
byteArray.writeUnsignedInt (srcData[srcPosition++]);
byteArray.writeUnsignedInt (srcData[srcPosition++]);
byteArray.writeUnsignedInt (srcData[srcPosition++]);
#else
byteArray.__set (i * 4 + 1, srcData[srcPosition++]);
byteArray.__set (i * 4 + 2, srcData[srcPosition++]);
byteArray.__set (i * 4 + 3, srcData[srcPosition++]);
byteArray.__set (i * 4, srcData[srcPosition++]);
#end
for (i in 0...length) {
if ((srcPosition % srcStride) > srcRowEnd) {
#if flash
byteArray.writeByte (srcData[srcPosition++]);
byteArray.writeByte (srcData[srcPosition++]);
byteArray.writeByte (srcData[srcPosition++]);
byteArray.writeByte (srcData[srcPosition++]);
#else
byteArray.__set (i * 4 + 1, srcData[srcPosition++]);
byteArray.__set (i * 4 + 2, srcData[srcPosition++]);
byteArray.__set (i * 4 + 3, srcData[srcPosition++]);
byteArray.__set (i * 4, srcData[srcPosition++]);
#end
srcPosition += srcRowOffset;
if ((srcPosition % srcStride) > srcRowEnd) {
srcPosition += srcRowOffset;
}
}
} else {
for (i in 0...length) {
#if flash
// TODO
byteArray.writeByte (srcData[srcPosition++]);
byteArray.writeByte (srcData[srcPosition++]);
byteArray.writeByte (srcData[srcPosition++]);
byteArray.writeByte (srcData[srcPosition++]);
#else
byteArray.__set (i * 4, srcData[srcPosition++]);
byteArray.__set (i * 4 + 1, srcData[srcPosition++]);
byteArray.__set (i * 4 + 2, srcData[srcPosition++]);
byteArray.__set (i * 4 + 3, srcData[srcPosition++]);
#end
if ((srcPosition % srcStride) > srcRowEnd) {
srcPosition += srcRowOffset;
}
}
@@ -628,10 +723,11 @@ class ImageDataUtil {
}
public static function setPixel (image:Image, x:Int, y:Int, color:Int):Void {
public static function setPixel (image:Image, x:Int, y:Int, color:Int, format:PixelFormat):Void {
var data = image.buffer.data;
var offset = (4 * (y + image.offsetY) * image.buffer.width + (x + image.offsetX) * 4);
if (format == null || format == RGBA) color = color >> 8;
data[offset] = (color & 0xFF0000) >>> 16;
data[offset + 1] = (color & 0x00FF00) >>> 8;
@@ -643,25 +739,41 @@ class ImageDataUtil {
}
public static function setPixel32 (image:Image, x:Int, y:Int, color:Int):Void {
public static function setPixel32 (image:Image, x:Int, y:Int, color:Int, format:PixelFormat):Void {
var data = image.buffer.data;
var offset = (4 * (y + image.offsetY) * image.buffer.width + (x + image.offsetX) * 4);
var a = (image.transparent ? (color & 0xFF000000) >>> 24 : 0xFF);
var a, r, g, b;
if (format == ARGB) {
a = image.transparent ? (color >> 24) & 0xFF : 0xFF;
r = (color >> 16) & 0xFF;
g = (color >> 8) & 0xFF;
b = color & 0xFF;
} else {
r = (color >> 24) & 0xFF;
g = (color >> 16) & 0xFF;
b = (color >> 8) & 0xFF;
a = image.transparent ? color & 0xFF : 0xFF;
}
if (image.transparent && image.premultiplied) {
var a16 = __alpha16[a];
data[offset] = (((color & 0x00FF0000) >>> 16) * a16) >> 16;
data[offset + 1] = (((color & 0x0000FF00) >>> 8) * a16) >> 16;
data[offset + 2] = ((color & 0x000000FF) * a16) >> 16;
data[offset] = (r * a16) >> 16;
data[offset + 1] = (g * a16) >> 16;
data[offset + 2] = (b * a16) >> 16;
data[offset + 3] = a;
} else {
data[offset] = (color & 0x00FF0000) >>> 16;
data[offset + 1] = (color & 0x0000FF00) >>> 8;
data[offset + 2] = (color & 0x000000FF);
data[offset] = r;
data[offset + 1] = g;
data[offset + 2] = b;
data[offset + 3] = a;
}
@@ -671,7 +783,7 @@ class ImageDataUtil {
}
public static function setPixels (image:Image, rect:Rectangle, byteArray:ByteArray):Void {
public static function setPixels (image:Image, rect:Rectangle, byteArray:ByteArray, format:PixelFormat):Void {
var len = Math.round (rect.width * rect.height);
@@ -693,20 +805,43 @@ class ImageDataUtil {
var width = image.buffer.width;
var color;
for (i in 0...len) {
if (format == ARGB) {
if (((pos) % (width * 4)) >= boundR * 4) {
for (i in 0...len) {
pos += (width - boundR) * 4;
if (((pos) % (width * 4)) >= boundR * 4) {
pos += (width - boundR) * 4;
}
color = byteArray.readUnsignedInt ();
data[pos++] = (color & 0xFF0000) >>> 16;
data[pos++] = (color & 0x0000FF00) >>> 8;
data[pos++] = (color & 0x000000FF);
data[pos++] = (color & 0xFF000000) >>> 24;
}
color = byteArray.readUnsignedInt ();
} else {
data[pos++] = (color & 0xFF0000) >>> 16;
data[pos++] = (color & 0x0000FF00) >>> 8;
data[pos++] = (color & 0x000000FF);
data[pos++] = (color & 0xFF000000) >>> 24;
for (i in 0...len) {
if (((pos) % (width * 4)) >= boundR * 4) {
pos += (width - boundR) * 4;
}
color = byteArray.readUnsignedInt ();
data[pos++] = (color & 0xFF000000) >>> 24;
data[pos++] = (color & 0xFF0000) >>> 16;
data[pos++] = (color & 0x0000FF00) >>> 8;
data[pos++] = (color & 0x000000FF);
}
}
@@ -762,6 +897,9 @@ class ImageDataUtil {
#if (cpp || neko || nodejs)
private static var lime_image_data_util_color_transform = System.load ("lime", "lime_image_data_util_color_transform", 3);
private static var lime_image_data_util_copy_channel = System.load ("lime", "lime_image_data_util_copy_channel", -1);
private static var lime_image_data_util_copy_pixels = System.load ("lime", "lime_image_data_util_copy_pixels", 5);
private static var lime_image_data_util_fill_rect = System.load ("lime", "lime_image_data_util_fill_rect", 3);
private static var lime_image_data_util_multiply_alpha = System.load ("lime", "lime_image_data_util_multiply_alpha", 1);
private static var lime_image_data_util_unmultiply_alpha = System.load ("lime", "lime_image_data_util_unmultiply_alpha", 1);
#end

View File

@@ -170,6 +170,7 @@
<file name="src/graphics/RenderEvent.cpp" />
<file name="src/math/ColorMatrix.cpp" />
<file name="src/math/Rectangle.cpp" />
<file name="src/math/Vector2.cpp" />
<file name="src/ui/GamepadEvent.cpp" />
<file name="src/ui/KeyEvent.cpp" />
<file name="src/ui/MouseEvent.cpp" />

View File

@@ -23,6 +23,7 @@ namespace lime {
int height;
int offsetX;
int offsetY;
bool transparent;
int width;
private:

View File

@@ -6,6 +6,8 @@
#include <graphics/Image.h>
#include <math/ColorMatrix.h>
#include <math/Rectangle.h>
#include <math/Vector2.h>
#include <system/System.h>
namespace lime {
@@ -17,6 +19,9 @@ namespace lime {
public:
static void ColorTransform (Image *image, Rectangle *rect, ColorMatrix *ColorMatrix);
static void CopyChannel (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int srcChannel, int destChannel);
static void CopyPixels (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, bool mergeAlpha);
static void FillRect (Image* image, Rectangle* rect, int color);
static void MultiplyAlpha (Image *image);
static void UnmultiplyAlpha (Image *image);

View File

@@ -14,7 +14,7 @@ namespace lime {
public:
Rectangle ();
Rectangle (value _rect);
Rectangle (value rect);
double height;
double width;

View File

@@ -0,0 +1,29 @@
#ifndef LIME_MATH_VECTOR2_H
#define LIME_MATH_VECTOR2_H
#include <hx/CFFI.h>
namespace lime {
class Vector2 {
public:
Vector2 ();
Vector2 (value vec);
double x;
double y;
};
}
#endif

View File

@@ -459,6 +459,42 @@ namespace lime {
}
value lime_image_data_util_copy_channel (value *arg, int nargs) {
enum { image, sourceImage, sourceRect, destPoint, srcChannel, destChannel };
Image _image = Image (arg[image]);
Image _sourceImage = Image (arg[sourceImage]);
Rectangle _sourceRect = Rectangle (arg[sourceRect]);
Vector2 _destPoint = Vector2 (arg[destPoint]);
ImageDataUtil::CopyChannel (&_image, &_sourceImage, &_sourceRect, &_destPoint, val_int (arg[srcChannel]), val_int (arg[destChannel]));
return alloc_null ();
}
value lime_image_data_util_copy_pixels (value image, value sourceImage, value sourceRect, value destPoint, value mergeAlpha) {
Image _image = Image (image);
Image _sourceImage = Image (sourceImage);
Rectangle _sourceRect = Rectangle (sourceRect);
Vector2 _destPoint = Vector2 (destPoint);
ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, val_bool (mergeAlpha));
return alloc_null ();
}
value lime_image_data_util_fill_rect (value image, value rect, value color) {
Image _image = Image (image);
Rectangle _rect = Rectangle (rect);
ImageDataUtil::FillRect (&_image, &_rect, val_number (color));
return alloc_null ();
}
value lime_image_data_util_multiply_alpha (value image) {
Image _image = Image (image);
@@ -869,6 +905,9 @@ namespace lime {
DEFINE_PRIM (lime_gamepad_get_device_guid, 1);
DEFINE_PRIM (lime_gamepad_get_device_name, 1);
DEFINE_PRIM (lime_image_data_util_color_transform, 3);
DEFINE_PRIM_MULT (lime_image_data_util_copy_channel);
DEFINE_PRIM (lime_image_data_util_copy_pixels, 5);
DEFINE_PRIM (lime_image_data_util_fill_rect, 3);
DEFINE_PRIM (lime_image_data_util_multiply_alpha, 1);
DEFINE_PRIM (lime_image_data_util_unmultiply_alpha, 1);
DEFINE_PRIM (lime_image_encode, 3);

View File

@@ -8,6 +8,7 @@ namespace lime {
static int id_height;
static int id_offsetX;
static int id_offsetY;
static int id_transparent;
static int id_width;
static bool init = false;
@@ -18,6 +19,7 @@ namespace lime {
height = 0;
offsetX = 0;
offsetY = 0;
transparent = true;
width = 0;
}
@@ -31,6 +33,7 @@ namespace lime {
id_height = val_id ("height");
id_offsetX = val_id ("offsetX");
id_offsetY = val_id ("offsetY");
id_transparent = val_id ("transparent");
id_width = val_id ("width");
init = true;
@@ -41,6 +44,7 @@ namespace lime {
buffer = new ImageBuffer (val_field (image, id_buffer));
offsetX = val_int (val_field (image, id_offsetX));
offsetY = val_int (val_field (image, id_offsetY));
transparent = val_bool (val_field (image, id_transparent));
}

View File

@@ -84,6 +84,149 @@ namespace lime {
}
void ImageDataUtil::CopyChannel (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int srcChannel, int destChannel) {
int srcStride = sourceImage->buffer->width * 4;
int srcPosition = ((sourceRect->x + sourceImage->offsetX) * 4) + (srcStride * (sourceRect->y + sourceImage->offsetY)) + srcChannel;
int srcRowOffset = srcStride - int (4 * (sourceRect->width + sourceImage->offsetX));
int srcRowEnd = 4 * (sourceRect->x + sourceImage->offsetX + sourceRect->width);
uint8_t* srcData = (uint8_t*)sourceImage->buffer->data->Bytes ();
int destStride = image->buffer->width * 4;
int destPosition = ((destPoint->x + image->offsetX) * 4) + (destStride * (destPoint->y + image->offsetY)) + destChannel;
int destRowOffset = destStride - int (4 * (sourceRect->width + image->offsetX));
int destRowEnd = 4 * (destPoint->x + image->offsetX + sourceRect->width);
uint8_t* destData = (uint8_t*)image->buffer->data->Bytes ();
int length = sourceRect->width * sourceRect->height;
for (int i = 0; i < length; i++) {
destData[destPosition] = srcData[srcPosition];
srcPosition += 4;
destPosition += 4;
if ((srcPosition % srcStride) > srcRowEnd) {
srcPosition += srcRowOffset;
}
if ((destPosition % destStride) > destRowEnd) {
destPosition += destRowOffset;
}
}
}
void ImageDataUtil::CopyPixels (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, bool mergeAlpha) {
int rowOffset = int (destPoint->y + image->offsetY - sourceRect->y - sourceImage->offsetY);
int columnOffset = int (destPoint->x + image->offsetX - sourceRect->x - sourceImage->offsetY);
uint8_t* sourceData = (uint8_t*)sourceImage->buffer->data->Bytes ();
int sourceStride = sourceImage->buffer->width * 4;
int sourceOffset = 0;
uint8_t* data = (uint8_t*)image->buffer->data->Bytes ();
int stride = image->buffer->width * 4;
int offset = 0;
int rows = sourceRect->y + sourceRect->height + sourceImage->offsetY;
int columns = sourceRect->x + sourceRect->width + sourceImage->offsetX;
if (!mergeAlpha || !sourceImage->transparent) {
for (int row = sourceRect->y + sourceImage->offsetY; row < rows; row++) {
for (int column = sourceRect->x + sourceImage->offsetX; column < columns; column++) {
sourceOffset = (row * sourceStride) + (column * 4);
offset = ((row + rowOffset) * stride) + ((column + columnOffset) * 4);
data[offset] = sourceData[sourceOffset];
data[offset + 1] = sourceData[sourceOffset + 1];
data[offset + 2] = sourceData[sourceOffset + 2];
data[offset + 3] = sourceData[sourceOffset + 3];
}
}
} else {
float sourceAlpha;
float oneMinusSourceAlpha;
for (int row = sourceRect->y + sourceImage->offsetY; row < rows; row++) {
for (int column = sourceRect->x + sourceImage->offsetX; column < columns; column++) {
sourceOffset = (row * sourceStride) + (column * 4);
offset = ((row + rowOffset) * stride) + ((column + columnOffset) * 4);
sourceAlpha = sourceData[sourceOffset + 3] / 255;
oneMinusSourceAlpha = (1 - sourceAlpha);
data[offset] = __clamp[int (sourceData[sourceOffset] + (data[offset] * oneMinusSourceAlpha))];
data[offset + 1] = __clamp[int (sourceData[sourceOffset + 1] + (data[offset + 1] * oneMinusSourceAlpha))];
data[offset + 2] = __clamp[int (sourceData[sourceOffset + 2] + (data[offset + 2] * oneMinusSourceAlpha))];
data[offset + 3] = __clamp[int (sourceData[sourceOffset + 3] + (data[offset + 3] * oneMinusSourceAlpha))];
}
}
}
}
void ImageDataUtil::FillRect (Image* image, Rectangle* rect, int color) {
int* data = (int*)image->buffer->data->Bytes ();
if (rect->width == image->buffer->width && rect->height == image->buffer->height && rect->x == 0 && rect->y == 0 && image->offsetX == 0 && image->offsetY == 0) {
int length = image->buffer->width * image->buffer->height;
for (int i = 0; i < length; i++) {
data[i] = color;
}
} else {
int stride = image->buffer->width;
int offset;
int rowStart = int (rect->y + image->offsetY);
int rowEnd = int (rect->y + rect->height + image->offsetY);
int columnStart = int (rect->x + image->offsetX);
int columnEnd = int (rect->x + rect->width + image->offsetX);
for (int row = rowStart; row < rowEnd; row++) {
for (int column = columnStart; column < columnEnd; column++) {
offset = (row * stride) + (column);
data[offset] = color;
}
}
}
}
void ImageDataUtil::MultiplyAlpha (Image* image) {
int a16 = 0;

View File

@@ -0,0 +1,36 @@
#include <math/Vector2.h>
namespace lime {
static int id_x;
static int id_y;
static bool init = false;
Vector2::Vector2 () {
x = 0;
y = 0;
}
Vector2::Vector2 (value vec) {
if (!init) {
id_x = val_id ("x");
id_y = val_id ("y");
init = true;
}
x = val_number (val_field (vec, id_x));
y = val_number (val_field (vec, id_y));
}
}