diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ad8334ff..f4a3dd544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,72 @@ +2.5.2 (07/23/2015) +------------------ + +* Added support for automatic software fallback on native platforms +* Improved the behavior of image getPixel/setPixel +* Fixed native fillRect/floodFill when using certain color values +* Improved color conversion support for Flash +* Fixed issue preventing Neko from reading 32-bit integers correctly + + +2.5.1 (07/21/2015) +------------------ + +* Made Image properly support all PixelFormat/premultiplied types +* Updated PixelFormat names to be more descriptive +* Added prefix support for generated library class names +* Fixed an issue with Assets.loadImage on HTML5 +* Fixed support for OpenAL playback using a starting offset + + +2.5.0 (07/17/2015) +------------------ + +* Added guards against duplicate gamepad connect events +* Added guards against gamepad events after a disconnect +* Added dead zone and repeat value filtering for gamepad axis +* Added CairoImageSurface, properly separate from CairoSurface +* Improved HTML5 to use the project FPS setting +* Improved asset libraries to have an "unload" method +* Fixed repeated calls to Assets.load* with the same ID +* Fixed "lime build" to not progress without sources +* Fixed a regression in ByteArray.fromFile on Android +* Fixed a bug in arrayBufferView.set +* Quieted libpng "known incorrect profile" messages +* Added a patch to allow Wii Remote detection (legacy) + + +2.4.9 (07/13/2015) +------------------ + +* Added lime.system.ThreadPool +* Added lime.utils.Log +* Added image.scroll +* Added event.has +* Improved performance of Flash target logging +* Improved "lime upgrade" when Git is not in the PATH +* Improved image.clone when using canvas +* Updated for compatibility with newer lime-samples +* Updated to use a default icon when none is available +* Updated Assets to use a ThreadPool for asynchronous loads +* Updated to pass -verbose during "run" when in verbose mode +* Fixed an issue when tracing null typed arrays +* Fixed image.copyChannel when clipping is necessary +* Fixed use of cURL basic types as Int +* Improved support for asynchronous SSL requests (legacy) + + +2.4.8 (07/09/2015) +------------------ + +* Improved lime.system.BackgroundWorker onComplete +* Improved native bytes to guard against premature GC +* Fixed ENABLE_BITCODE when targeting older iOS versions +* Fixed possible double mouse events on iOS +* Fixed embedded font support on iOS +* Fixed "lime rebuild ios" with some versions of HXCPP +* Fixed mouse middle/right/wheel events on desktop (legacy) + + 2.4.7 (07/06/2015) ------------------ @@ -9,7 +78,7 @@ * Added lime.system.BackgroundWorker for easy threads * Made Assets loadImage/loadBytes asynchronous on native -* Removed the ByteArray __init__ and matching CFFI functions +* Removed the ByteArray \__init__ and matching CFFI functions * Improved the help documentation when using "lime create" * Fixed a crash that could occur when using Bytes * Fixed audioSource.play on native when there is no data diff --git a/haxelib.json b/haxelib.json index 4034cf160..d29e9c2fb 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,7 +4,7 @@ "license": "MIT", "tags": [], "description": "A flexible lightweight layer for Haxe cross-platform developers", - "version": "2.4.7", - "releasenote": "Fixed regression in HTML5 typed array support", + "version": "2.5.2", + "releasenote": "Software fallback support, image fixes", "contributors": [ "singmajesty" ] } diff --git a/include.xml b/include.xml index 610d21dc3..b01a1cddb 100644 --- a/include.xml +++ b/include.xml @@ -74,7 +74,7 @@ - +
diff --git a/legacy/project/src/sdl2/SDL2Stage.cpp b/legacy/project/src/sdl2/SDL2Stage.cpp index 5071ce712..46047009c 100644 --- a/legacy/project/src/sdl2/SDL2Stage.cpp +++ b/legacy/project/src/sdl2/SDL2Stage.cpp @@ -535,7 +535,7 @@ public: } #endif - #if defined(WEBOS) || defined(BLACKBERRY) || defined(HX_LINUX) || defined(HX_WINDOWS) + #if defined(WEBOS) || defined(BLACKBERRY) if (inEvent.type == etMouseMove || inEvent.type == etMouseDown || inEvent.type == etMouseUp) { if (mSingleTouchID == NO_TOUCH || inEvent.value == mSingleTouchID || !mMultiTouch) @@ -1210,8 +1210,8 @@ void ProcessEvent(SDL_Event &inEvent) //int inValue=0, int inID=0, int inFlags=0, float inScaleX=1,float inScaleY=1, int inDeltaX=0,int inDeltaY=0 Event mouse(etMouseMove, inEvent.motion.x, inEvent.motion.y, 0, 0, 0, 1.0f, 1.0f, deltaX, deltaY); - mouse.value = inEvent.motion.which; #if defined(WEBOS) || defined(BLACKBERRY) + mouse.value = inEvent.motion.which; mouse.flags |= efLeftDown; #else AddModStates(mouse.flags); @@ -1222,8 +1222,8 @@ void ProcessEvent(SDL_Event &inEvent) case SDL_MOUSEBUTTONDOWN: { Event mouse(etMouseDown, inEvent.button.x, inEvent.button.y, inEvent.button.button - 1); - mouse.value = inEvent.motion.which; #if defined(WEBOS) || defined(BLACKBERRY) + mouse.value = inEvent.motion.which; mouse.flags |= efLeftDown; #else AddModStates(mouse.flags); @@ -1234,8 +1234,9 @@ void ProcessEvent(SDL_Event &inEvent) case SDL_MOUSEBUTTONUP: { Event mouse(etMouseUp, inEvent.button.x, inEvent.button.y, inEvent.button.button - 1); + #if defined(WEBOS) || defined(BLACKBERRY) mouse.value = inEvent.motion.which; - #if !defined(WEBOS) && defined(BLACKBERRY) + #else AddModStates(mouse.flags); #endif sgSDLFrame->ProcessEvent(mouse); @@ -1408,6 +1409,18 @@ void ProcessEvent(SDL_Event &inEvent) { joystick.x = 3; } + else if (strcmp (gamepadstring, "Mayflash WIIMote PC Adapter") == 0) //MayFlash WIIMote PC Adapter + { + joystick.x = 4; + } + else if (strcmp (gamepadstring, "Nintendo RVL-CNT-01-TR") == 0) //Nintendo WIIMote MotionPlus, used directly + { + joystick.x = 5; + } + else if (strcmp (gamepadstring, "Nintendo RVL-CNT-01") == 0) //Nintendo WIIMote w/o MotionPlus attachment, used directly + { + joystick.x = 6; + } else //default (XBox 360, basically) { joystick.x = 0; diff --git a/lime/Assets.hx b/lime/Assets.hx index 6d7f62013..6dff318fb 100644 --- a/lime/Assets.hx +++ b/lime/Assets.hx @@ -935,6 +935,7 @@ class Assets { if (library != null) { cache.clear (name + ":"); + library.unload (); library.eventCallback = null; } @@ -1140,6 +1141,13 @@ class AssetLibrary { } + public function unload ():Void { + + + + } + + } diff --git a/lime/_backend/html5/HTML5Application.hx b/lime/_backend/html5/HTML5Application.hx index 2a7ef0547..fe2ac6eff 100644 --- a/lime/_backend/html5/HTML5Application.hx +++ b/lime/_backend/html5/HTML5Application.hx @@ -96,6 +96,7 @@ class HTML5Application { if (config != null) { + setFrameRate (config.fps); var window = new Window (config); var renderer = new Renderer (window); parent.addWindow (window); diff --git a/lime/_backend/native/NativeApplication.hx b/lime/_backend/native/NativeApplication.hx index fc8645d0e..1b62c0877 100644 --- a/lime/_backend/native/NativeApplication.hx +++ b/lime/_backend/native/NativeApplication.hx @@ -14,6 +14,7 @@ import lime.ui.Gamepad; import lime.ui.Window; @:access(haxe.Timer) +@:access(lime._backend.native.NativeRenderer) @:access(lime.app.Application) @:access(lime.graphics.Renderer) @:access(lime.ui.Gamepad) @@ -132,28 +133,35 @@ class NativeApplication { case AXIS_MOVE: - parent.window.onGamepadAxisMove.dispatch (Gamepad.devices.get (gamepadEventInfo.id), gamepadEventInfo.axis, gamepadEventInfo.value); + var gamepad = Gamepad.devices.get (gamepadEventInfo.id); + if (gamepad != null) parent.window.onGamepadAxisMove.dispatch (gamepad, gamepadEventInfo.axis, gamepadEventInfo.value); case BUTTON_DOWN: - parent.window.onGamepadButtonDown.dispatch (Gamepad.devices.get (gamepadEventInfo.id), gamepadEventInfo.button); + var gamepad = Gamepad.devices.get (gamepadEventInfo.id); + if (gamepad != null) parent.window.onGamepadButtonDown.dispatch (gamepad, gamepadEventInfo.button); case BUTTON_UP: - parent.window.onGamepadButtonUp.dispatch (Gamepad.devices.get (gamepadEventInfo.id), gamepadEventInfo.button); + var gamepad = Gamepad.devices.get (gamepadEventInfo.id); + if (gamepad != null) parent.window.onGamepadButtonUp.dispatch (gamepad, gamepadEventInfo.button); case CONNECT: - var gamepad = new Gamepad (gamepadEventInfo.id); - Gamepad.devices.set (gamepadEventInfo.id, gamepad); - parent.window.onGamepadConnect.dispatch (gamepad); + if (!Gamepad.devices.exists (gamepadEventInfo.id)) { + + var gamepad = new Gamepad (gamepadEventInfo.id); + Gamepad.devices.set (gamepadEventInfo.id, gamepad); + parent.window.onGamepadConnect.dispatch (gamepad); + + } case DISCONNECT: var gamepad = Gamepad.devices.get (gamepadEventInfo.id); if (gamepad != null) gamepad.connected = false; Gamepad.devices.remove (gamepadEventInfo.id); - parent.window.onGamepadDisconnect.dispatch (gamepad); + if (gamepad != null) parent.window.onGamepadDisconnect.dispatch (gamepad); } @@ -229,22 +237,26 @@ class NativeApplication { case RENDER_CONTEXT_LOST: - parent.renderer.context = null; - parent.renderer.onRenderContextLost.dispatch (); + if (parent.renderer.backend.useHardware) { + + parent.renderer.context = null; + parent.renderer.onRenderContextLost.dispatch (); + + } case RENDER_CONTEXT_RESTORED: - #if lime_console - parent.renderer.context = CONSOLE (new ConsoleRenderContext ()); - #else - if (parent.config.hardware) { + if (parent.renderer.backend.useHardware) { + #if lime_console + parent.renderer.context = CONSOLE (new ConsoleRenderContext ()); + #else parent.renderer.context = OPENGL (new GLRenderContext ()); + #end + + parent.renderer.onRenderContextRestored.dispatch (parent.renderer.context); } - #end - - parent.renderer.onRenderContextRestored.dispatch (parent.renderer.context); } @@ -753,4 +765,4 @@ private class WindowEventInfo { var WINDOW_RESIZE = 9; var WINDOW_RESTORE = 10; -} \ No newline at end of file +} diff --git a/lime/_backend/native/NativeRenderer.hx b/lime/_backend/native/NativeRenderer.hx index ace13fdf1..91b9234a3 100644 --- a/lime/_backend/native/NativeRenderer.hx +++ b/lime/_backend/native/NativeRenderer.hx @@ -3,6 +3,7 @@ package lime._backend.native; import lime.graphics.cairo.Cairo; import lime.graphics.cairo.CairoFormat; +import lime.graphics.cairo.CairoImageSurface; import lime.graphics.cairo.CairoSurface; import lime.graphics.CairoRenderContext; import lime.graphics.ConsoleRenderContext; @@ -39,23 +40,33 @@ class NativeRenderer { handle = lime_renderer_create (parent.window.backend.handle); - useHardware = parent.window.config.hardware; - #if lime_console + + useHardware = true; parent.context = CONSOLE (new ConsoleRenderContext ()); + #else - if (useHardware) { + + var type = lime_renderer_get_type (handle); + + switch (type) { - parent.context = OPENGL (new GLRenderContext ()); + case "opengl": + + useHardware = true; + parent.context = OPENGL (new GLRenderContext ()); - } else { - - #if lime_cairo - render (); - parent.context = CAIRO (cairo); - #end + default: + + useHardware = false; + + #if lime_cairo + render (); + parent.context = CAIRO (cairo); + #end } + #end } @@ -97,14 +108,17 @@ class NativeRenderer { if (cacheLock == null || cacheLock.pixels != lock.pixels || cacheLock.width != lock.width || cacheLock.height != lock.height) { - if ( primarySurface != null ) + if (primarySurface != null) { + primarySurface.destroy (); + + } - primarySurface = CairoSurface.createForData (lock.pixels, CairoFormat.ARGB32, lock.width, lock.height, lock.pitch); + primarySurface = CairoImageSurface.create (lock.pixels, CairoFormat.ARGB32, lock.width, lock.height, lock.pitch); if (cairo != null) { - cairo.recreate( primarySurface ); + cairo.recreate (primarySurface); } else { @@ -112,7 +126,6 @@ class NativeRenderer { } - } cacheLock = lock; @@ -134,6 +147,7 @@ class NativeRenderer { private static var lime_renderer_create = System.load ("lime", "lime_renderer_create", 1); private static var lime_renderer_flip = System.load ("lime", "lime_renderer_flip", 1); + private static var lime_renderer_get_type = System.load ("lime", "lime_renderer_get_type", 1); private static var lime_renderer_lock = System.load ("lime", "lime_renderer_lock", 1); private static var lime_renderer_unlock = System.load ("lime", "lime_renderer_unlock", 1); diff --git a/lime/app/Event.hx b/lime/app/Event.hx index 646d9d996..0b0ef6e6b 100644 --- a/lime/app/Event.hx +++ b/lime/app/Event.hx @@ -74,6 +74,14 @@ class Event { } + public function has (listener:T):Bool { + + var index = listeners.indexOf (listener); + return (index > -1); + + } + + public function remove (listener:T):Void { var index = listeners.indexOf (listener); diff --git a/lime/audio/AudioSource.hx b/lime/audio/AudioSource.hx index 682423932..ebe8cea3d 100644 --- a/lime/audio/AudioSource.hx +++ b/lime/audio/AudioSource.hx @@ -428,8 +428,8 @@ class AudioSource { if (buffer != null) { AL.sourceRewind (id); - AL.sourcef (id, AL.SEC_OFFSET, (value + offset) / 1000); if (playing) AL.sourcePlay (id); + AL.sourcef (id, AL.SEC_OFFSET, (value + offset) / 1000); } diff --git a/lime/graphics/Image.hx b/lime/graphics/Image.hx index da14b33eb..b036a7593 100644 --- a/lime/graphics/Image.hx +++ b/lime/graphics/Image.hx @@ -12,6 +12,9 @@ import lime.graphics.format.JPEG; import lime.graphics.format.PNG; import lime.graphics.utils.ImageCanvasUtil; import lime.graphics.utils.ImageDataUtil; +import lime.math.color.ARGB; +import lime.math.color.BGRA; +import lime.math.color.RGBA; import lime.math.ColorMatrix; import lime.math.Rectangle; import lime.math.Vector2; @@ -161,8 +164,26 @@ class Image { public function clone ():Image { - var image = new Image (buffer.clone (), offsetX, offsetY, width, height, null, type); - return image; + if (buffer != null) { + + if (type == CANVAS && buffer.__srcImage == null) { + + ImageCanvasUtil.convertToCanvas (this); + ImageCanvasUtil.sync (this); + buffer.data = null; + buffer.__srcImageData = null; + + } + + var image = new Image (buffer.clone (), offsetX, offsetY, width, height, null, type); + image.dirty = dirty; + return image; + + } else { + + return new Image (null, offsetX, offsetY, width, height, null, type); + + } } @@ -374,8 +395,16 @@ class Image { case FLASH: rect.offset (offsetX, offsetY); - if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8); - buffer.__srcBitmapData.fillRect (rect.__toFlashRectangle (), color); + + var argb:ARGB = switch (format) { + + case ARGB32: color; + case BGRA32: (color:BGRA); + default: (color:RGBA); + + } + + buffer.__srcBitmapData.fillRect (rect.__toFlashRectangle (), argb); default: @@ -404,8 +433,15 @@ class Image { case FLASH: - if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8); - buffer.__srcBitmapData.floodFill (x + offsetX, y + offsetY, color); + var argb:ARGB = switch (format) { + + case ARGB32: color; + case BGRA32: (color:BGRA); + default: (color:RGBA); + + } + + buffer.__srcBitmapData.floodFill (x + offsetX, y + offsetY, argb); default: @@ -522,15 +558,13 @@ class Image { case FLASH: - var color = buffer.__srcBitmapData.getPixel (x + offsetX, y + offsetY); + var color:ARGB = buffer.__srcBitmapData.getPixel (x + offsetX, y + offsetY); - if (format == null || format == RGBA) { + switch (format) { - return ((color & 0xFF) << 24) | (color >> 8); - - } else { - - return color; + case ARGB32: return color; + case BGRA32: var bgra:BGRA = color; return bgra; + default: var rgba:RGBA = color; return rgba; } @@ -563,15 +597,13 @@ class Image { case FLASH: - var color = buffer.__srcBitmapData.getPixel32 (x + offsetX, y + offsetY); + var color:ARGB = buffer.__srcBitmapData.getPixel32 (x + offsetX, y + offsetY); - if (format == null || format == RGBA) { + switch (format) { - return ((color & 0xFF) << 24) | (color >> 8); - - } else { - - return color; + case ARGB32: return color; + case BGRA32: var bgra:BGRA = color; return bgra; + default: var rgba:RGBA = color; return rgba; } @@ -607,20 +639,38 @@ class Image { rect.offset (offsetX, offsetY); var byteArray = buffer.__srcBitmapData.getPixels (rect.__toFlashRectangle ()); - if (format == null || format == RGBA) { + switch (format) { - var color; - var length = Std.int (byteArray.length / 4); - - for (i in 0...length) { + case ARGB32: // do nothing + case BGRA32: - color = byteArray.readUnsignedInt (); - byteArray.position -= 4; - byteArray.writeUnsignedInt (((color & 0xFF) << 24) | (color >> 8)); + var color:BGRA; + var length = Std.int (byteArray.length / 4); - } + for (i in 0...length) { + + color = (byteArray.readUnsignedInt ():ARGB); + byteArray.position -= 4; + byteArray.writeUnsignedInt (color); + + } + + byteArray.position = 0; - byteArray.position = 0; + default: + + var color:RGBA; + var length = Std.int (byteArray.length / 4); + + for (i in 0...length) { + + color = (byteArray.readUnsignedInt ():ARGB); + byteArray.position -= 4; + byteArray.writeUnsignedInt (color); + + } + + byteArray.position = 0; } @@ -706,6 +756,37 @@ class Image { } + public function scroll (x:Int, y:Int):Void { + + if (buffer == null) return; + + switch (type) { + + case CANVAS: + + ImageCanvasUtil.scroll (this, x, y); + + case DATA: + + //#if (js && html5) + //ImageCanvasUtil.convertToData (this); + //#end + + //ImageDataUtil.scroll (this, x, y); + + copyPixels (this, rect, new Vector2 (x, y)); + + case FLASH: + + buffer.__srcBitmapData.scroll (x + offsetX, y + offsetX); + + default: + + } + + } + + 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; @@ -726,8 +807,15 @@ class Image { case FLASH: - if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8); - buffer.__srcBitmapData.setPixel (x + offsetX, y + offsetX, color); + var argb:ARGB = switch (format) { + + case ARGB32: color; + case BGRA32: (color:BGRA); + default: (color:RGBA); + + } + + buffer.__srcBitmapData.setPixel (x + offsetX, y + offsetX, argb); default: @@ -756,8 +844,15 @@ class Image { case FLASH: - if (format == null || format == RGBA) color = ((color & 0xFF) << 24) | (color >> 8); - buffer.__srcBitmapData.setPixel32 (x + offsetX, y + offsetY, color); + var argb:ARGB = switch (format) { + + case ARGB32: color; + case BGRA32: (color:BGRA); + default: (color:RGBA); + + } + + buffer.__srcBitmapData.setPixel32 (x + offsetX, y + offsetY, argb); default: @@ -788,27 +883,54 @@ class Image { case FLASH: rect.offset (offsetX, offsetY); - if (format == null || format == RGBA) { + + switch (format) { - 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) { + case ARGB32: // do nothing + case BGRA32: - color = srcData.readUnsignedInt (); - byteArray.writeUnsignedInt (((color & 0xFF) << 24) | (color >> 8)); + var srcData = byteArray; + byteArray = new ByteArray (); + #if flash + byteArray.length = srcData.length; + #end - } + var color:BGRA; + var length = Std.int (byteArray.length / 4); + + for (i in 0...length) { + + color = srcData.readUnsignedInt (); + byteArray.writeUnsignedInt (cast (color, ARGB)); + + } + + srcData.position = 0; + byteArray.position = 0; + + default: + + var srcData = byteArray; + byteArray = new ByteArray (); + #if flash + byteArray.length = srcData.length; + #end + + var color:RGBA; + var length = Std.int (byteArray.length / 4); + + for (i in 0...length) { + + color = srcData.readUnsignedInt (); + byteArray.writeUnsignedInt (cast (color, ARGB)); + + } + + srcData.position = 0; + byteArray.position = 0; - srcData.position = 0; - byteArray.position = 0; } + buffer.__srcBitmapData.setPixels (rect.__toFlashRectangle (), byteArray); default: diff --git a/lime/graphics/ImageBuffer.hx b/lime/graphics/ImageBuffer.hx index ca1bb1368..c046e972c 100644 --- a/lime/graphics/ImageBuffer.hx +++ b/lime/graphics/ImageBuffer.hx @@ -47,7 +47,7 @@ class ImageBuffer { this.width = width; this.height = height; this.bitsPerPixel = bitsPerPixel; - this.format = (format == null ? RGBA : format); + this.format = (format == null ? RGBA32 : format); transparent = true; } @@ -108,6 +108,8 @@ class ImageBuffer { } #end + buffer.bitsPerPixel = bitsPerPixel; + buffer.format = format; buffer.premultiplied = premultiplied; buffer.transparent = transparent; return buffer; diff --git a/lime/graphics/PixelFormat.hx b/lime/graphics/PixelFormat.hx index 7b8106948..bcd901493 100644 --- a/lime/graphics/PixelFormat.hx +++ b/lime/graphics/PixelFormat.hx @@ -3,8 +3,8 @@ package lime.graphics; @:enum abstract PixelFormat(Int) from Int to Int { - public var RGBA = 0; - public var ARGB = 1; - public var BGRA = 2; + public var RGBA32 = 0; + public var ARGB32 = 1; + public var BGRA32 = 2; } \ No newline at end of file diff --git a/lime/graphics/cairo/CairoImageSurface.hx b/lime/graphics/cairo/CairoImageSurface.hx new file mode 100644 index 000000000..0f83305df --- /dev/null +++ b/lime/graphics/cairo/CairoImageSurface.hx @@ -0,0 +1,131 @@ +package lime.graphics.cairo; + + +import lime.system.System; + + +@:forward abstract CairoImageSurface(CairoSurface) from CairoSurface to CairoSurface { + + + public var data (get, never):Dynamic; + public var format (get, never):CairoFormat; + public var height (get, never):Int; + public var stride (get, never):Int; + public var width (get, never):Int; + + + public function new (format:CairoFormat, width:Int, height:Int):CairoSurface { + + #if lime_cairo + this = lime_cairo_image_surface_create (format, width, height); + #else + this = cast 0; + #end + + } + + + public static function create (data:Dynamic, format:CairoFormat, width:Int, height:Int, stride:Int):CairoSurface { + + #if lime_cairo + return lime_cairo_image_surface_create_for_data (data, format, width, height, stride); + #else + return cast 0; + #end + + } + + + public static function fromImage (image:Image):CairoSurface { + + #if lime_cairo + return create (lime_bytes_get_data_pointer (#if nodejs image.data #else image.data.buffer #end), CairoFormat.ARGB32, image.width, image.height, image.buffer.stride); + #else + return null; + #end + + } + + + + + // Get & Set Methods + + + + + @:noCompletion private function get_data ():Dynamic { + + #if lime_cairo + return lime_cairo_image_surface_get_data (this); + #else + return null; + #end + + } + + + @:noCompletion private function get_format ():CairoFormat { + + #if lime_cairo + return lime_cairo_image_surface_get_format (this); + #else + return 0; + #end + + } + + + @:noCompletion private function get_height ():Int { + + #if lime_cairo + return lime_cairo_image_surface_get_height (this); + #else + return 0; + #end + + } + + + @:noCompletion private function get_stride ():Int { + + #if lime_cairo + return lime_cairo_image_surface_get_stride (this); + #else + return 0; + #end + + } + + + @:noCompletion private function get_width ():Int { + + #if lime_cairo + return lime_cairo_image_surface_get_width (this); + #else + return 0; + #end + + } + + + + + // Native Methods + + + + + #if lime_cairo + private static var lime_bytes_get_data_pointer = System.load ("lime", "lime_bytes_get_data_pointer", 1); + private static var lime_cairo_image_surface_create = System.load ("lime", "lime_cairo_image_surface_create", 3); + private static var lime_cairo_image_surface_create_for_data = System.load ("lime", "lime_cairo_image_surface_create_for_data", 5); + private static var lime_cairo_image_surface_get_data = System.load ("lime", "lime_cairo_image_surface_get_data", 1); + private static var lime_cairo_image_surface_get_format = System.load ("lime", "lime_cairo_image_surface_get_format", 1); + private static var lime_cairo_image_surface_get_height = System.load ("lime", "lime_cairo_image_surface_get_height", 1); + private static var lime_cairo_image_surface_get_stride = System.load ("lime", "lime_cairo_image_surface_get_stride", 1); + private static var lime_cairo_image_surface_get_width = System.load ("lime", "lime_cairo_image_surface_get_width", 1); + #end + + +} \ No newline at end of file diff --git a/lime/graphics/cairo/CairoSurface.hx b/lime/graphics/cairo/CairoSurface.hx index 725ef20d1..5ef637b19 100644 --- a/lime/graphics/cairo/CairoSurface.hx +++ b/lime/graphics/cairo/CairoSurface.hx @@ -11,32 +11,6 @@ import lime.utils.ByteArray; abstract CairoSurface(Dynamic) { - public var height (get, never):Int; - public var width (get, never):Int; - - - public function new (format:CairoFormat, width:Int, height:Int):CairoSurface { - - #if lime_cairo - this = lime_cairo_image_surface_create (format, width, height); - #else - this = 0; - #end - - } - - - public static function createForData (data:Dynamic, format:CairoFormat, width:Int, height:Int, stride:Int):CairoSurface { - - #if lime_cairo - return lime_cairo_image_surface_create_for_data (data, format, width, height, stride); - #else - return cast 0; - #end - - } - - public function destroy ():Void { #if lime_cairo @@ -55,46 +29,6 @@ abstract CairoSurface(Dynamic) { } - public static function fromImage (image:Image):CairoSurface { - - #if lime_cairo - return createForData (lime_bytes_get_data_pointer (#if nodejs image.data #else image.data.buffer #end), CairoFormat.ARGB32, image.width, image.height, image.buffer.stride); - #else - return null; - #end - - } - - - - - // Get & Set Methods - - - - - @:noCompletion private function get_height ():Int { - - #if lime_cairo - return lime_cairo_image_surface_get_height (this); - #else - return 0; - #end - - } - - - @:noCompletion private function get_width ():Int { - - #if lime_cairo - return lime_cairo_image_surface_get_width (this); - #else - return 0; - #end - - } - - // Native Methods @@ -103,11 +37,6 @@ abstract CairoSurface(Dynamic) { #if lime_cairo - private static var lime_bytes_get_data_pointer = System.load ("lime", "lime_bytes_get_data_pointer", 1); - private static var lime_cairo_image_surface_create = System.load ("lime", "lime_cairo_image_surface_create", 3); - private static var lime_cairo_image_surface_create_for_data = System.load ("lime", "lime_cairo_image_surface_create_for_data", 5); - private static var lime_cairo_image_surface_get_height = System.load ("lime", "lime_cairo_image_surface_get_height", 1); - private static var lime_cairo_image_surface_get_width = System.load ("lime", "lime_cairo_image_surface_get_width", 1); private static var lime_cairo_surface_destroy = System.load ("lime", "lime_cairo_surface_destroy", 1); private static var lime_cairo_surface_flush = System.load ("lime", "lime_cairo_surface_flush", 1); #end diff --git a/lime/graphics/format/BMP.hx b/lime/graphics/format/BMP.hx index e3cf0d6d2..ffad8c901 100644 --- a/lime/graphics/format/BMP.hx +++ b/lime/graphics/format/BMP.hx @@ -94,7 +94,7 @@ class BMP { } - var pixels = image.getPixels (new Rectangle (0, 0, image.width, image.height), ARGB); + var pixels = image.getPixels (new Rectangle (0, 0, image.width, image.height), ARGB32); var a, r, g, b; switch (type) { diff --git a/lime/graphics/utils/ImageCanvasUtil.hx b/lime/graphics/utils/ImageCanvasUtil.hx index 7720ff945..73e1f46df 100644 --- a/lime/graphics/utils/ImageCanvasUtil.hx +++ b/lime/graphics/utils/ImageCanvasUtil.hx @@ -46,6 +46,11 @@ class ImageCanvasUtil { buffer.__srcImage = null; + } else if (buffer.data != null && buffer.__srcCanvas == null) { + + createCanvas (image, buffer.width, buffer.height); + createImageData (image); + } } @@ -83,6 +88,12 @@ class ImageCanvasUtil { public static function copyPixels (image:Image, sourceImage:Image, sourceRect:Rectangle, destPoint:Vector2, alphaImage:Image = null, alphaPoint:Vector2 = null, mergeAlpha:Bool = false):Void { + if (destPoint.x >= image.width || destPoint.y >= image.height) { + + return; + + } + if (alphaImage != null && alphaImage.transparent) { if (alphaPoint == null) alphaPoint = new Vector2 (); @@ -156,9 +167,19 @@ class ImageCanvasUtil { var buffer = image.buffer; - if (buffer.data == null) { + if (buffer.__srcImageData == null) { + + if (buffer.data == null) { + + buffer.__srcImageData = buffer.__srcContext.getImageData (0, 0, buffer.width, buffer.height); + + } else { + + buffer.__srcImageData = buffer.__srcContext.createImageData (buffer.width, buffer.height); + buffer.__srcImageData.data.set (cast buffer.data); + + } - buffer.__srcImageData = buffer.__srcContext.getImageData (0, 0, buffer.width, buffer.height); buffer.data = new UInt8Array (cast buffer.__srcImageData.data.buffer); } @@ -186,7 +207,7 @@ class ImageCanvasUtil { var r, g, b, a; - if (format == ARGB) { + if (format == ARGB32) { r = (color >> 16) & 0xFF; g = (color >> 8) & 0xFF; @@ -282,6 +303,19 @@ class ImageCanvasUtil { } + public static function scroll (image:Image, x:Int, y:Int):Void { + + if ((x % image.width == 0) && (y % image.height == 0)) return; + + convertToCanvas (image); + sync (image); + + image.buffer.__srcContext.clearRect (x, y, image.width, image.height); + image.buffer.__srcContext.drawImage (image.buffer.__srcCanvas, x, y); + + } + + public static function setPixel (image:Image, x:Int, y:Int, color:Int, format:PixelFormat):Void { convertToCanvas (image); @@ -315,7 +349,7 @@ class ImageCanvasUtil { public static function sync (image:Image):Void { #if (js && html5) - if (image.dirty && image.type != DATA) { + if (image.dirty && image.buffer.__srcImageData != null && image.type != DATA) { image.buffer.__srcContext.putImageData (image.buffer.__srcImageData, 0, 0); image.buffer.data = null; @@ -327,4 +361,4 @@ class ImageCanvasUtil { } -} \ No newline at end of file +} diff --git a/lime/graphics/utils/ImageDataUtil.hx b/lime/graphics/utils/ImageDataUtil.hx index 1d0d9892b..30951cf7a 100644 --- a/lime/graphics/utils/ImageDataUtil.hx +++ b/lime/graphics/utils/ImageDataUtil.hx @@ -2,10 +2,14 @@ package lime.graphics.utils; import haxe.ds.Vector; +import haxe.Int32; import haxe.io.Bytes; import lime.graphics.Image; import lime.graphics.ImageBuffer; import lime.graphics.PixelFormat; +import lime.math.color.ARGB; +import lime.math.color.BGRA; +import lime.math.color.RGBA; import lime.math.ColorMatrix; import lime.math.Rectangle; import lime.math.Vector2; @@ -13,41 +17,12 @@ import lime.system.System; import lime.utils.ByteArray; import lime.utils.UInt8Array; +@:access(lime.math.color.RGBA) + class ImageDataUtil { - private static var __alpha16:Vector; - private static var __clamp:Vector; - - - private static function __init__ ():Void { - - __alpha16 = new Vector (256); - - for (i in 0...256) { - - __alpha16[i] = Std.int (i * (1 << 16) / 255); - - } - - __clamp = new Vector (0xFF + 0xFF); - - for (i in 0...0xFF) { - - __clamp[i] = i; - - } - - for (i in 0xFF...(0xFF + 0xFF + 1)) { - - __clamp[i] = 0xFF; - - } - - } - - public static function colorTransform (image:Image, rect:Rectangle, colorMatrix:ColorMatrix):Void { var data = image.buffer.data; @@ -58,34 +33,29 @@ class ImageDataUtil { #end { - var stride = image.buffer.width * 4; - var offset:Int; + var format = image.buffer.format; + var premultiplied = image.buffer.premultiplied; - var rowStart = Std.int (rect.top + image.offsetY); - var rowEnd = Std.int (rect.bottom + image.offsetY); - var columnStart = Std.int (rect.left + image.offsetX); - var columnEnd = Std.int (rect.right + image.offsetX); + var dataView = new ImageDataView (image, rect); - var r, g, b, a, ex = 0; + var alphaTable = colorMatrix.getAlphaTable (); + var redTable = colorMatrix.getRedTable (); + var greenTable = colorMatrix.getGreenTable (); + var blueTable = colorMatrix.getBlueTable (); - for (row in rowStart...rowEnd) { + var row, offset, pixel:RGBA; + + for (y in 0...dataView.height) { - for (column in columnStart...columnEnd) { + row = dataView.row (y); + + for (x in 0...dataView.width) { - offset = (row * stride) + (column * 4); + offset = row + (x * 4); - a = Std.int ((data[offset + 3] * colorMatrix.alphaMultiplier) + colorMatrix.alphaOffset); - ex = a > 0xFF ? a - 0xFF : 0; - b = Std.int ((data[offset + 2] * colorMatrix.blueMultiplier) + colorMatrix.blueOffset + ex); - ex = b > 0xFF ? b - 0xFF : 0; - g = Std.int ((data[offset + 1] * colorMatrix.greenMultiplier) + colorMatrix.greenOffset + ex); - ex = g > 0xFF ? g - 0xFF : 0; - r = Std.int ((data[offset] * colorMatrix.redMultiplier) + colorMatrix.redOffset + ex); - - data[offset] = r > 0xFF ? 0xFF : r; - data[offset + 1] = g > 0xFF ? 0xFF : g; - data[offset + 2] = b > 0xFF ? 0xFF : b; - data[offset + 3] = a > 0xFF ? 0xFF : a; + pixel.readUInt8 (data, offset, format, premultiplied); + pixel.set (redTable[pixel.r], greenTable[pixel.g], blueTable[pixel.b], alphaTable[pixel.a]); + pixel.writeUInt8 (data, offset, format, premultiplied); } @@ -128,36 +98,48 @@ class ImageDataUtil { #end { - 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)); - var srcRowEnd = Std.int (4 * (sourceRect.x + sourceImage.offsetX + sourceRect.width)); - var srcData = sourceImage.buffer.data; + var srcView = new ImageDataView (sourceImage, sourceRect); + var destView = new ImageDataView (image, new Rectangle (destPoint.x, destPoint.y, srcView.width, srcView.height)); - var destStride = Std.int (image.buffer.width * 4); - var destPosition = Std.int (((destPoint.x + image.offsetX) * 4) + (destStride * (destPoint.y + image.offsetY)) + destIdx); - var destRowOffset = destStride - Std.int (4 * (sourceRect.width + image.offsetX)); - var destRowEnd = Std.int (4 * (destPoint.x + image.offsetX + sourceRect.width)); - var destData = image.buffer.data; + var srcFormat = sourceImage.buffer.format; + var destFormat = image.buffer.format; + var srcPremultiplied = sourceImage.buffer.premultiplied; + var destPremultiplied = image.buffer.premultiplied; - var length = Std.int (sourceRect.width * sourceRect.height); + var srcPosition, destPosition, srcPixel:RGBA, destPixel:RGBA, value = 0; - for (i in 0...length) { + for (y in 0...destView.height) { - destData[destPosition] = srcData[srcPosition]; + srcPosition = srcView.row (y); + destPosition = destView.row (y); - srcPosition += 4; - destPosition += 4; - - if ((srcPosition % srcStride) > srcRowEnd) { + for (x in 0...destView.width) { - srcPosition += srcRowOffset; + srcPixel.readUInt8 (srcData, srcPosition, srcFormat, srcPremultiplied); + destPixel.readUInt8 (destData, destPosition, destFormat, destPremultiplied); - } - - if ((destPosition % destStride) > destRowEnd) { + switch (srcIdx) { + + case 0: value = srcPixel.r; + case 1: value = srcPixel.g; + case 2: value = srcPixel.b; + case 3: value = srcPixel.a; + + } - destPosition += destRowOffset; + switch (destIdx) { + + case 0: destPixel.r = value; + case 1: destPixel.g = value; + case 2: destPixel.b = value; + case 3: destPixel.a = value; + + } + + destPixel.writeUInt8 (destData, destPosition, destFormat, destPremultiplied); + + srcPosition += 4; + destPosition += 4; } @@ -172,56 +154,40 @@ class ImageDataUtil { public static function copyPixels (image:Image, sourceImage:Image, sourceRect:Rectangle, destPoint:Vector2, alphaImage:Image = null, alphaPoint:Vector2 = null, mergeAlpha:Bool = false):Void { - if (alphaImage != null && alphaImage.transparent) { - - if (alphaPoint == null) alphaPoint = new Vector2 (); - - // TODO: use faster method - - var tempData = image.clone (); - tempData.copyChannel (alphaImage, new Rectangle (alphaPoint.x, alphaPoint.y, sourceRect.width, sourceRect.height), new Vector2 (sourceRect.x, sourceRect.y), ImageChannel.ALPHA, ImageChannel.ALPHA); - sourceImage = tempData; - - } - #if ((cpp || neko) && !disable_cffi) - if (!System.disableCFFI) lime_image_data_util_copy_pixels (image, sourceImage, sourceRect, destPoint, mergeAlpha); else + if (!System.disableCFFI) lime_image_data_util_copy_pixels (image, sourceImage, sourceRect, destPoint, alphaImage, alphaPoint, mergeAlpha); else #end { - var rowOffset = Std.int (destPoint.y + image.offsetY - sourceRect.y - sourceImage.offsetY); - var columnOffset = Std.int (destPoint.x + image.offsetX - sourceRect.x - sourceImage.offsetY); - var sourceData = sourceImage.buffer.data; - var sourceStride = sourceImage.buffer.width * 4; - var sourceOffset:Int = 0; + var destData = image.buffer.data; - var data = image.buffer.data; - var stride = image.buffer.width * 4; - var offset:Int = 0; + if (sourceData == null || destData == null) return; + + var sourceView = new ImageDataView (sourceImage, sourceRect); + var destView = new ImageDataView (image, new Rectangle (destPoint.x, destPoint.y, sourceView.width, sourceView.height)); + + var sourceFormat = sourceImage.buffer.format; + var destFormat = image.buffer.format; + var sourcePremultiplied = sourceImage.buffer.premultiplied; + var destPremultiplied = image.buffer.premultiplied; + + var sourcePosition, destPosition, sourcePixel:RGBA; if (!mergeAlpha || !sourceImage.transparent) { - //#if (!js && !flash) - //if (sourceRect.width == image.width && sourceRect.height == image.height && image.width == sourceImage.width && image.height == sourceImage.height && sourceRect.x == 0 && sourceRect.y == 0 && destPoint.x == 0 && destPoint.y == 0) { - // - //image.buffer.data.buffer.blit (0, sourceImage.buffer.data.buffer, 0, Std.int (sourceRect.width * sourceRect.height) * 4); - //return; - // - //} - //#end - - for (row in Std.int (sourceRect.top + sourceImage.offsetY)...Std.int (sourceRect.bottom + sourceImage.offsetY)) { + for (y in 0...destView.height) { - for (column in Std.int (sourceRect.left + sourceImage.offsetX)...Std.int (sourceRect.right + sourceImage.offsetX)) { + sourcePosition = sourceView.row (y); + destPosition = destView.row (y); + + for (x in 0...destView.width) { - sourceOffset = (row * sourceStride) + (column * 4); - offset = ((row + rowOffset) * stride) + ((column + columnOffset) * 4); + sourcePixel.readUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); + sourcePixel.writeUInt8 (destData, destPosition, destFormat, destPremultiplied); - data[offset] = sourceData[sourceOffset]; - data[offset + 1] = sourceData[sourceOffset + 1]; - data[offset + 2] = sourceData[sourceOffset + 2]; - data[offset + 3] = sourceData[sourceOffset + 3]; + sourcePosition += 4; + destPosition += 4; } @@ -229,28 +195,93 @@ class ImageDataUtil { } else { - var sourceAlpha:Float; - var destAlpha:Float; - var outA:Float; - var oneMinusSourceAlpha:Float; + var sourceAlpha, destAlpha, oneMinusSourceAlpha, blendAlpha; + var destPixel:RGBA; - for (row in Std.int (sourceRect.top + sourceImage.offsetY)...Std.int (sourceRect.bottom + sourceImage.offsetY)) { + if (alphaImage == null) { - for (column in Std.int (sourceRect.left + sourceImage.offsetX)...Std.int (sourceRect.right + sourceImage.offsetX)) { + for (y in 0...destView.height) { - sourceOffset = (row * sourceStride) + (column * 4); - offset = ((row + rowOffset) * stride) + ((column + columnOffset) * 4); + sourcePosition = sourceView.row (y); + destPosition = destView.row (y); - sourceAlpha = sourceData[sourceOffset + 3] / 255.0; - destAlpha = data[offset + 3] / 255.0; - oneMinusSourceAlpha = (1 - sourceAlpha); + for (x in 0...destView.width) { + + sourcePixel.readUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); + destPixel.readUInt8 (destData, destPosition, destFormat, destPremultiplied); + + sourceAlpha = sourcePixel.a / 255.0; + destAlpha = destPixel.a / 255.0; + oneMinusSourceAlpha = 1 - sourceAlpha; + blendAlpha = sourceAlpha + (destAlpha * oneMinusSourceAlpha); + + if (blendAlpha == 0) { + + destPixel = 0; + + } else { + + destPixel.r = RGBA.__clamp[Math.round ((sourcePixel.r * sourceAlpha + destPixel.r * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.g = RGBA.__clamp[Math.round ((sourcePixel.g * sourceAlpha + destPixel.g * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.b = RGBA.__clamp[Math.round ((sourcePixel.b * sourceAlpha + destPixel.b * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.a = RGBA.__clamp[Math.round (blendAlpha * 255.0)]; + + } + + destPixel.writeUInt8 (destData, destPosition, destFormat, destPremultiplied); + + sourcePosition += 4; + destPosition += 4; + + } - outA = sourceAlpha + destAlpha * oneMinusSourceAlpha; - data[offset + 0] = __clamp[Math.round ((sourceData[sourceOffset + 0] * sourceAlpha + data[offset + 0] * destAlpha * oneMinusSourceAlpha) / outA)]; - data[offset + 1] = __clamp[Math.round ((sourceData[sourceOffset + 1] * sourceAlpha + data[offset + 1] * destAlpha * oneMinusSourceAlpha) / outA)]; - data[offset + 2] = __clamp[Math.round ((sourceData[sourceOffset + 2] * sourceAlpha + data[offset + 2] * destAlpha * oneMinusSourceAlpha) / outA)]; - data[offset + 3] = __clamp[Math.round (outA * 255.0)]; + } + + } else { + + var alphaData = alphaImage.buffer.data; + var alphaFormat = alphaImage.buffer.format; + var alphaPremultiplied = alphaImage.buffer.premultiplied; + + var alphaView = new ImageDataView (alphaImage, new Rectangle (alphaPoint.x, alphaPoint.y, destView.width, destView.height)); + var alphaPosition, alphaPixel:RGBA; + + for (y in 0...alphaView.height) { + sourcePosition = sourceView.row (y); + destPosition = destView.row (y); + alphaPosition = alphaView.row (y); + + for (x in 0...alphaView.width) { + + sourcePixel.readUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); + destPixel.readUInt8 (destData, destPosition, destFormat, destPremultiplied); + alphaPixel.readUInt8 (alphaData, alphaPosition, alphaFormat, alphaPremultiplied); + + sourceAlpha = alphaPixel.a / 0xFF; + destAlpha = destPixel.a / 0xFF; + oneMinusSourceAlpha = 1 - sourceAlpha; + blendAlpha = sourceAlpha + (destAlpha * oneMinusSourceAlpha); + + if (blendAlpha == 0) { + + destPixel = 0; + + } else { + + destPixel.r = RGBA.__clamp[Math.round ((sourcePixel.r * sourceAlpha + destPixel.r * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.g = RGBA.__clamp[Math.round ((sourcePixel.g * sourceAlpha + destPixel.g * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.b = RGBA.__clamp[Math.round ((sourcePixel.b * sourceAlpha + destPixel.b * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.a = RGBA.__clamp[Math.round (blendAlpha * 255.0)]; + + } + + destPixel.writeUInt8 (destData, destPosition, destFormat, destPremultiplied); + + sourcePosition += 4; + destPosition += 4; + + } } @@ -267,80 +298,43 @@ class ImageDataUtil { public static function fillRect (image:Image, rect:Rectangle, color:Int, format:PixelFormat):Void { - var r, g, b, a; + var fillColor:RGBA; - if (format == ARGB) { + switch (format) { - 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; + case ARGB32: fillColor = (color:ARGB); + case BGRA32: fillColor = (color:BGRA); + default: fillColor = color; } - var rgba = (r | (g << 8) | (b << 16) | (a << 24)); + if (!image.transparent) { + + fillColor.a = 0xFF; + + } var data = image.buffer.data; if (data == null) return; #if ((cpp || neko) && !disable_cffi) - if (!System.disableCFFI) lime_image_data_util_fill_rect (image, rect, rgba); else + if (!System.disableCFFI) lime_image_data_util_fill_rect (image, rect, (fillColor >> 16) & 0xFFFF, (fillColor) & 0xFFFF); else // TODO: Better Int32 solution #end { - if (rect.width == image.buffer.width && rect.height == image.buffer.height && rect.x == 0 && rect.y == 0 && image.offsetX == 0 && image.offsetY == 0) { + var format = image.buffer.format; + var premultiplied = image.buffer.premultiplied; + + var dataView = new ImageDataView (image, rect); + var row; + + for (y in 0...dataView.height) { - var length = image.buffer.width * image.buffer.height; + row = dataView.row (y); - var j = 0; - for (i in 0...length) { + for (x in 0...dataView.width) { - j = i * 4; - - //#if js - data[j + 0] = r; - data[j + 1] = g; - data[j + 2] = b; - data[j + 3] = a; - //#else - //data.setUInt32 (j, rgba); - //#end - - } - - } else { - - var stride = image.buffer.width * 4; - var offset:Int; - - var rowStart = Std.int (rect.y + image.offsetY); - var rowEnd = Std.int (rect.bottom + image.offsetY); - var columnStart = Std.int (rect.x + image.offsetX); - var columnEnd = Std.int (rect.right + image.offsetX); - - for (row in rowStart...rowEnd) { - - for (column in columnStart...columnEnd) { - - offset = (row * stride) + (column * 4); - - //#if js - data[offset] = r; - data[offset + 1] = g; - data[offset + 2] = b; - data[offset + 3] = a; - //#else - //data.setUInt32 (offset, rgba); - //#end - - } + fillColor.writeUInt8 (data, row + (x * 4), format, premultiplied); } @@ -358,25 +352,29 @@ class ImageDataUtil { var data = image.buffer.data; if (data == null) return; - if (format == ARGB) color = ((color & 0xFFFFFF) << 8) | ((color >> 24) & 0xFF); + if (format == ARGB32) color = ((color & 0xFFFFFF) << 8) | ((color >> 24) & 0xFF); #if ((cpp || neko) && !disable_cffi) - if (!System.disableCFFI) lime_image_data_util_flood_fill (image, x, y, color); else + if (!System.disableCFFI) lime_image_data_util_flood_fill (image, x, y, (color >> 16) & 0xFFFF, (color) & 0xFFFF); else // TODO: Better Int32 solution #end { - var offset = (((y + image.offsetY) * (image.buffer.width * 4)) + ((x + image.offsetX) * 4)); - var hitColorR = data[offset + 0]; - var hitColorG = data[offset + 1]; - var hitColorB = data[offset + 2]; - var hitColorA = image.transparent ? data[offset + 3] : 0xFF; + var format = image.buffer.format; + var premultiplied = image.buffer.premultiplied; - var r = (color >> 24) & 0xFF; - var g = (color >> 16) & 0xFF; - var b = (color >> 8) & 0xFF; - var a = image.transparent ? color & 0xFF : 0xFF; + var fillColor:RGBA = color; - if (hitColorR == r && hitColorG == g && hitColorB == b && hitColorA == a) return; + var hitColor:RGBA; + hitColor.readUInt8 (data, ((y + image.offsetY) * (image.buffer.width * 4)) + ((x + image.offsetX) * 4), format, premultiplied); + + if (!image.transparent) { + + fillColor.a = 0xFF; + hitColor.a = 0xFF; + + } + + if (fillColor == hitColor) return; var dx = [ 0, -1, 1, 0 ]; var dy = [ -1, 0, 0, 1 ]; @@ -390,15 +388,17 @@ class ImageDataUtil { queue.push (x); queue.push (y); + var curPointX, curPointY, nextPointX, nextPointY, nextPointOffset, readColor:RGBA; + while (queue.length > 0) { - var curPointY = queue.pop (); - var curPointX = queue.pop (); + curPointY = queue.pop (); + curPointX = queue.pop (); for (i in 0...4) { - var nextPointX = curPointX + dx[i]; - var nextPointY = curPointY + dy[i]; + nextPointX = curPointX + dx[i]; + nextPointY = curPointY + dy[i]; if (nextPointX < minX || nextPointY < minY || nextPointX >= maxX || nextPointY >= maxY) { @@ -406,14 +406,12 @@ class ImageDataUtil { } - var nextPointOffset = (nextPointY * image.width + nextPointX) * 4; + nextPointOffset = (nextPointY * image.width + nextPointX) * 4; + readColor.readUInt8 (data, nextPointOffset, format, premultiplied); - if (data[nextPointOffset + 0] == hitColorR && data[nextPointOffset + 1] == hitColorG && data[nextPointOffset + 2] == hitColorB && data[nextPointOffset + 3] == hitColorA) { + if (readColor == hitColor) { - data[nextPointOffset + 0] = r; - data[nextPointOffset + 1] = g; - data[nextPointOffset + 2] = b; - data[nextPointOffset + 3] = a; + fillColor.writeUInt8 (data, nextPointOffset, format, premultiplied); queue.push (nextPointX); queue.push (nextPointY); @@ -441,7 +439,7 @@ class ImageDataUtil { var r, g, b, a; var mr, mg, mb, ma; - if (format == ARGB) { + if (format == ARGB32) { a = (image.transparent) ? (color >> 24) & 0xFF : 0xFF; r = (color >> 16) & 0xFF; @@ -600,28 +598,16 @@ class ImageDataUtil { 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; + var pixel:RGBA; - if (image.premultiplied) { - - var unmultiply = 255.0 / data[offset + 3]; - 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 { - - pixel = (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8); - - } + pixel.readUInt8 (image.buffer.data, (4 * (y + image.offsetY) * image.buffer.width + (x + image.offsetX) * 4), image.buffer.format, image.buffer.premultiplied); + pixel.a = 0; - if (format == ARGB) { + switch (format) { - return pixel >> 8 & 0xFFFFFF; - - } else { - - return pixel; + case ARGB32: return (pixel:ARGB); + case BGRA32: return (pixel:BGRA); + default: return pixel; } @@ -630,33 +616,15 @@ class ImageDataUtil { 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; + var pixel:RGBA; - if (image.premultiplied && a != 0) { - - var unmultiply = 255.0 / a; - r = __clamp[Math.round (data[offset] * unmultiply)]; - g = __clamp[Math.round (data[offset + 1] * unmultiply)]; - b = __clamp[Math.round (data[offset + 2] * unmultiply)]; - - } else { - - r = data[offset]; - g = data[offset + 1]; - b = data[offset + 2]; - - } + pixel.readUInt8 (image.buffer.data, (4 * (y + image.offsetY) * image.buffer.width + (x + image.offsetX) * 4), image.buffer.format, image.buffer.premultiplied); - if (format == ARGB) { + switch (format) { - return a << 24 | r << 16 | g << 8 | b; - - } else { - - return r << 24 | g << 16 | b << 8 | a; + case ARGB32: return (pixel:ARGB); + case BGRA32: return (pixel:BGRA); + default: return pixel; } @@ -681,73 +649,46 @@ class ImageDataUtil { #end { - //#if (!js && !flash) - //if (rect.width == image.width && rect.height == image.height && rect.x == 0 && rect.y == 0) { - // - //byteArray.blit (0, image.buffer.data.buffer, 0, length * 4); - //return byteArray; - // - //} - //#end + var data = image.buffer.data; + var sourceFormat = image.buffer.format; + var premultiplied = image.buffer.premultiplied; - // TODO: optimize if the rect is the same as the full buffer size + var dataView = new ImageDataView (image, rect); + var position, argb:ARGB, bgra:BGRA, pixel:RGBA; - var srcData = image.buffer.data; - var srcStride = Std.int (image.buffer.width * 4); - var srcPosition = Std.int ((rect.x * 4) + (srcStride * rect.y)); - var srcRowOffset = srcStride - Std.int (4 * rect.width); - var srcRowEnd = Std.int (4 * (rect.x + rect.width)); - - #if js - byteArray.length = length * 4; + #if !flash + var destPosition = 0; #end - if (format == ARGB) { + for (y in 0...dataView.height) { - for (i in 0...length) { + position = dataView.row (y); + + for (x in 0...dataView.width) { - #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 + pixel.readUInt8 (data, position, sourceFormat, premultiplied); - if ((srcPosition % srcStride) > srcRowEnd) { + switch (format) { - srcPosition += srcRowOffset; + case ARGB32: argb = pixel; pixel = cast argb; + case BGRA32: bgra = pixel; pixel = cast bgra; + default: } - } - - } 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++]); + byteArray.writeByte (pixel.r); + byteArray.writeByte (pixel.g); + byteArray.writeByte (pixel.b); + byteArray.writeByte (pixel.a); #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++]); + byteArray.__set (destPosition++, pixel.r); + byteArray.__set (destPosition++, pixel.g); + byteArray.__set (destPosition++, pixel.b); + byteArray.__set (destPosition++, pixel.a); #end - if ((srcPosition % srcStride) > srcRowEnd) { - - srcPosition += srcRowOffset; - - } + position += 4; } @@ -770,28 +711,37 @@ class ImageDataUtil { #end { - var rowOffset = Std.int (destPoint.y + image.offsetY - sourceRect.y - sourceImage.offsetY); - var columnOffset = Std.int (destPoint.x + image.offsetX - sourceRect.x - sourceImage.offsetY); + var sourceView = new ImageDataView (sourceImage, sourceRect); + var destView = new ImageDataView (image, new Rectangle (destPoint.x, destPoint.y, sourceView.width, sourceView.height)); var sourceData = sourceImage.buffer.data; - var sourceStride = sourceImage.buffer.width * 4; - var sourceOffset:Int = 0; + var destData = image.buffer.data; + var sourceFormat = sourceImage.buffer.format; + var destFormat = image.buffer.format; + var sourcePremultiplied = sourceImage.buffer.premultiplied; + var destPremultiplied = image.buffer.premultiplied; - var data = image.buffer.data; - var stride = image.buffer.width * 4; - var offset:Int = 0; + var sourcePosition, destPosition, sourcePixel:RGBA, destPixel:RGBA; - for (row in Std.int (sourceRect.top + sourceImage.offsetY)...Std.int (sourceRect.bottom + sourceImage.offsetY)) { + for (y in 0...destView.height) { - for (column in Std.int (sourceRect.left + sourceImage.offsetX)...Std.int (sourceRect.right + sourceImage.offsetX)) { + sourcePosition = sourceView.row (y); + destPosition = destView.row (y); + + for (x in 0...destView.width) { - sourceOffset = (row * sourceStride) + (column * 4); - offset = ((row + rowOffset) * stride) + ((column + columnOffset) * 4); + sourcePixel.readUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); + destPixel.readUInt8 (destData, destPosition, destFormat, destPremultiplied); - data[offset] = Std.int (((sourceData[offset] * redMultiplier) + (data[offset] * (256 - redMultiplier))) / 256); - data[offset + 1] = Std.int (((sourceData[offset + 1] * greenMultiplier) + (data[offset + 1] * (256 - greenMultiplier))) / 256); - data[offset + 2] = Std.int (((sourceData[offset + 2] * blueMultiplier) + (data[offset + 2] * (256 - blueMultiplier))) / 256); - data[offset + 3] = Std.int (((sourceData[offset + 3] * alphaMultiplier) + (data[offset + 3] * (256 - alphaMultiplier))) / 256); + destPixel.r = Std.int (((sourcePixel.r * redMultiplier) + (destPixel.r * (256 - redMultiplier))) / 256); + destPixel.g = Std.int (((sourcePixel.g * greenMultiplier) + (destPixel.g * (256 - greenMultiplier))) / 256); + destPixel.b = Std.int (((sourcePixel.b * blueMultiplier) + (destPixel.b * (256 - blueMultiplier))) / 256); + destPixel.a = Std.int (((sourcePixel.a * alphaMultiplier) + (destPixel.a * (256 - alphaMultiplier))) / 256); + + destPixel.writeUInt8 (destData, destPosition, destFormat, destPremultiplied); + + sourcePosition += 4; + destPosition += 4; } @@ -814,17 +764,14 @@ class ImageDataUtil { #end { - var index, a16; + var format = image.buffer.format; var length = Std.int (data.length / 4); + var pixel:RGBA; for (i in 0...length) { - index = i * 4; - - a16 = __alpha16[data[index + 3]]; - data[index] = (data[index] * a16) >> 16; - data[index + 1] = (data[index + 1] * a16) >> 16; - data[index + 2] = (data[index + 2] * a16) >> 16; + pixel.readUInt8 (data, i * 4, format, false); + pixel.writeUInt8 (data, i * 4, format, true); } @@ -860,6 +807,8 @@ class ImageDataUtil { for (x in 0...newWidth) { + // TODO: Handle more color formats + u = ((x + 0.5) / newWidth) * imageWidth - 0.5; v = ((y + 0.5) / newHeight) * imageHeight - 0.5; @@ -954,21 +903,21 @@ class ImageDataUtil { switch (image.format) { - case RGBA: + case RGBA32: r1 = 0; g1 = 1; b1 = 2; a1 = 3; - case ARGB: + case ARGB32: r1 = 1; g1 = 2; b1 = 3; a1 = 0; - case BGRA: + case BGRA32: r1 = 2; g1 = 1; @@ -979,21 +928,21 @@ class ImageDataUtil { switch (format) { - case RGBA: + case RGBA32: r2 = 0; g2 = 1; b2 = 2; a2 = 3; - case ARGB: + case ARGB32: r2 = 1; g2 = 2; b2 = 3; a2 = 0; - case BGRA: + case BGRA32: r2 = 2; g2 = 1; @@ -1028,14 +977,18 @@ class ImageDataUtil { 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 == RGBA) color = color >> 8; + var pixel:RGBA; - data[offset] = (color & 0xFF0000) >>> 16; - data[offset + 1] = (color & 0x00FF00) >>> 8; - data[offset + 2] = (color & 0x0000FF); - if (image.transparent) data[offset + 3] = (0xFF); + switch (format) { + + case ARGB32: pixel = (color:ARGB); + case BGRA32: pixel = (color:BGRA); + default: pixel = color; + + } + + pixel.a = 0xFF; + pixel.writeUInt8 (image.buffer.data, (4 * (y + image.offsetY) * image.buffer.width + (x + image.offsetX) * 4), image.buffer.format, image.buffer.premultiplied); image.dirty = true; @@ -1044,59 +997,18 @@ class ImageDataUtil { 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, r, g, b; + var pixel:RGBA; - if (format == ARGB) { + switch (format) { - 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; + case ARGB32: pixel = (color:ARGB); + case BGRA32: pixel = (color:BGRA); + default: pixel = color; } - // TODO(james4k): do a more sane endianness check, but this has changed - // in the latest lime anyways. - - if (image.transparent && image.premultiplied) { - - var a16 = __alpha16[a]; - #if !(ps3 || wiiu) - data[offset] = (r * a16) >> 16; - data[offset + 1] = (g * a16) >> 16; - data[offset + 2] = (b * a16) >> 16; - data[offset + 3] = a; - #else - data[offset + 0] = a; - data[offset + 1] = (b * a16) >> 16; - data[offset + 2] = (g * a16) >> 16; - data[offset + 3] = (r * a16) >> 16; - #end - - } else { - - #if !(ps3 || wiiu) - data[offset] = r; - data[offset + 1] = g; - data[offset + 2] = b; - data[offset + 3] = a; - #else - data[offset + 0] = a; - data[offset + 1] = b; - data[offset + 2] = g; - data[offset + 3] = r; - #end - - } + if (!image.transparent) pixel.a = 0xFF; + pixel.writeUInt8 (image.buffer.data, (4 * (y + image.offsetY) * image.buffer.width + (x + image.offsetX) * 4), image.buffer.format, image.buffer.premultiplied); image.dirty = true; @@ -1112,61 +1024,31 @@ class ImageDataUtil { #end { - var len = Math.round (rect.width * rect.height); - - //#if (!js && !flash) - //if (rect.width == image.width && rect.height == image.height && rect.x == 0 && rect.y == 0) { - // - //image.buffer.data.buffer.blit (0, byteArray, 0, len * 4); - //return; - // - //} - //#end - - // TODO: optimize when rect is the same as the buffer size - var data = image.buffer.data; - var offset = Math.round (image.buffer.width * (rect.y + image.offsetX) + (rect.x + image.offsetY)); - var pos = offset * 4; - var boundR = Math.round ((rect.x + rect.width + image.offsetX)); - var width = image.buffer.width; - var color; + var sourceFormat = image.buffer.format; + var premultiplied = image.buffer.premultiplied; + var dataView = new ImageDataView (image, rect); + var row, color, pixel:RGBA; + var transparent = image.transparent; - if (format == ARGB) { + for (y in 0...dataView.height) { - for (i in 0...len) { - - if (((pos) % (width * 4)) >= boundR * 4) { - - pos += (width - boundR) * 4; - - } + row = dataView.row (y); + + for (x in 0...dataView.width) { color = byteArray.readUnsignedInt (); - data[pos++] = (color & 0xFF0000) >>> 16; - data[pos++] = (color & 0x0000FF00) >>> 8; - data[pos++] = (color & 0x000000FF); - data[pos++] = (color & 0xFF000000) >>> 24; - - } - - } else { - - for (i in 0...len) { - - if (((pos) % (width * 4)) >= boundR * 4) { + switch (format) { - pos += (width - boundR) * 4; + case ARGB32: pixel = (color:ARGB); + case BGRA32: pixel = (color:BGRA); + default: pixel = color; } - color = byteArray.readUnsignedInt (); - - data[pos++] = (color & 0xFF000000) >>> 24; - data[pos++] = (color & 0xFF0000) >>> 16; - data[pos++] = (color & 0x0000FF00) >>> 8; - data[pos++] = (color & 0x000000FF); + if (!transparent) pixel.a = 0xFF; + pixel.writeUInt8 (data, row + (x * 4), sourceFormat, premultiplied); } @@ -1189,24 +1071,14 @@ class ImageDataUtil { #end { - var index, a, unmultiply; + var format = image.buffer.format; var length = Std.int (data.length / 4); + var pixel:RGBA; for (i in 0...length) { - index = i * 4; - - a = data[index + 3]; - - if (a != 0) { - - unmultiply = 255.0 / a; - - data[index] = __clamp[Std.int (data[index] * unmultiply)]; - data[index + 1] = __clamp[Std.int (data[index + 1] * unmultiply)]; - data[index + 2] = __clamp[Std.int (data[index + 2] * unmultiply)]; - - } + pixel.readUInt8 (data, i * 4, format, true); + pixel.writeUInt8 (data, i * 4, format, false); } @@ -1228,9 +1100,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_flood_fill = System.load ("lime", "lime_image_data_util_flood_fill", 4); + private static var lime_image_data_util_copy_pixels = System.load ("lime", "lime_image_data_util_copy_pixels", -1); + private static var lime_image_data_util_fill_rect = System.load ("lime", "lime_image_data_util_fill_rect", 4); + private static var lime_image_data_util_flood_fill = System.load ("lime", "lime_image_data_util_flood_fill", 5); private static var lime_image_data_util_get_pixels = System.load ("lime", "lime_image_data_util_get_pixels", 4); private static var lime_image_data_util_merge = System.load ("lime", "lime_image_data_util_merge", -1); private static var lime_image_data_util_multiply_alpha = System.load ("lime", "lime_image_data_util_multiply_alpha", 1); @@ -1242,3 +1114,71 @@ class ImageDataUtil { } + + +private class ImageDataView { + + + public var x (default, null):Int; + public var y (default, null):Int; + public var height (default, null):Int; + public var width (default, null):Int; + + private var image:Image; + private var offset:Int; + private var rect:Rectangle; + private var stride:Int; + + + public function new (image:Image, rect:Rectangle = null) { + + this.image = image; + + if (rect == null) { + + this.rect = image.rect; + + } else { + + if (rect.x < 0) rect.x = 0; + if (rect.y < 0) rect.y = 0; + if (rect.x + rect.width > image.width) rect.width = image.width - rect.x; + if (rect.y + rect.height > image.height) rect.height = image.height - rect.y; + if (rect.width < 0) rect.width = 0; + if (rect.height < 0) rect.height = 0; + this.rect = rect; + + } + + stride = image.buffer.stride; + + x = Math.ceil (this.rect.x); + y = Math.ceil (this.rect.y); + width = Math.floor (this.rect.width); + height = Math.floor (this.rect.height); + offset = (stride * (this.y + image.offsetY)) + ((this.x + image.offsetX) * 4); + + } + + + public function clip (x:Int, y:Int, width:Int, height:Int):Void { + + rect.__contract (x, y, width, height); + + this.x = Math.ceil (rect.x); + this.y = Math.ceil (rect.y); + this.width = Math.floor (rect.width); + this.height = Math.floor (rect.height); + offset = (stride * (this.y + image.offsetY)) + ((this.x + image.offsetX) * 4); + + } + + + public inline function row (y:Int):Int { + + return offset + stride * y; + + } + + +} diff --git a/lime/math/ColorMatrix.hx b/lime/math/ColorMatrix.hx index 1250b1c4b..d01becb4c 100644 --- a/lime/math/ColorMatrix.hx +++ b/lime/math/ColorMatrix.hx @@ -2,6 +2,7 @@ package lime.math; import lime.utils.Float32Array; +import lime.utils.UInt8Array; #if flash import flash.geom.ColorTransform; @@ -89,6 +90,90 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { } + public function getAlphaTable ():UInt8Array { + + var table = new UInt8Array (256); + var multiplier = alphaMultiplier; + var offset = alphaOffset; + var value:Int; + + for (i in 0...256) { + + value = Math.floor (i * multiplier + offset); + if (value > 0xFF) value = 0xFF; + if (value < 0) value = 0; + table[i] = value; + + } + + return table; + + } + + + public function getBlueTable ():UInt8Array { + + var table = new UInt8Array (256); + var multiplier = blueMultiplier; + var offset = blueOffset; + var value:Int; + + for (i in 0...256) { + + value = Math.floor (i * multiplier + offset); + if (value > 0xFF) value = 0xFF; + if (value < 0) value = 0; + table[i] = value; + + } + + return table; + + } + + + public function getGreenTable ():UInt8Array { + + var table = new UInt8Array (256); + var multiplier = greenMultiplier; + var offset = greenOffset; + var value:Int; + + for (i in 0...256) { + + value = Math.floor (i * multiplier + offset); + if (value > 0xFF) value = 0xFF; + if (value < 0) value = 0; + table[i] = value; + + } + + return table; + + } + + + public function getRedTable ():UInt8Array { + + var table = new UInt8Array (256); + var multiplier = redMultiplier; + var offset = redOffset; + var value:Int; + + for (i in 0...256) { + + value = Math.floor (i * multiplier + offset); + if (value > 0xFF) value = 0xFF; + if (value < 0) value = 0; + table[i] = value; + + } + + return table; + + } + + private function __toFlashColorTransform ():#if flash ColorTransform #else Dynamic #end { #if flash @@ -116,8 +201,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { private inline function set_alphaMultiplier (value:Float):Float { - this[18] = value; - return value; + return this[18] = value; } @@ -131,8 +215,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { private inline function set_alphaOffset (value:Float):Float { - this[19] = value / 255; - return value; + return this[19] = value / 255; } @@ -146,8 +229,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { private inline function set_blueMultiplier (value:Float):Float { - this[12] = value; - return value; + return this[12] = value; } @@ -161,8 +243,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { private inline function set_blueOffset (value:Float):Float { - this[14] = value / 255; - return value; + return this[14] = value / 255; } @@ -198,8 +279,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { private inline function set_greenMultiplier (value:Float):Float { - this[6] = value; - return value; + return this[6] = value; } @@ -213,8 +293,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { private inline function set_greenOffset (value:Float):Float { - this[9] = value / 255; - return value; + return this[9] = value / 255; } @@ -228,8 +307,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { private inline function set_redMultiplier (value:Float):Float { - this[0] = value; - return value; + return this[0] = value; } @@ -243,8 +321,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { private inline function set_redOffset (value:Float):Float { - this[4] = value / 255; - return value; + return this[4] = value / 255; } @@ -258,8 +335,7 @@ abstract ColorMatrix(Float32Array) from Float32Array to Float32Array { @:arrayAccess public function set (index:Int, value:Float):Float { - this[index] = value; - return value; + return this[index] = value; } diff --git a/lime/math/Rectangle.hx b/lime/math/Rectangle.hx index d6a39485d..365687837 100644 --- a/lime/math/Rectangle.hx +++ b/lime/math/Rectangle.hx @@ -250,8 +250,8 @@ class Rectangle { } - var cacheRight = right; - var cacheBottom = bottom; + //var cacheRight = right; + //var cacheBottom = bottom; if (this.x < x) this.x = x; if (this.y < y) this.y = y; diff --git a/lime/math/color/ARGB.hx b/lime/math/color/ARGB.hx new file mode 100644 index 000000000..dcbd16abd --- /dev/null +++ b/lime/math/color/ARGB.hx @@ -0,0 +1,217 @@ +package lime.math.color; + + +import lime.graphics.PixelFormat; +import lime.utils.UInt32Array; +import lime.utils.UInt8Array; + + +abstract ARGB(Int) from Int to Int { + + + private static var a16:Int; + private static var unmult:Float; + + public var a (get, set):Int; + public var b (get, set):Int; + public var g (get, set):Int; + public var r (get, set):Int; + + + public inline function new (argb:Int = 0) { + + this = argb; + + } + + + public static inline function create (a:Int, r:Int, g:Int, b:Int):ARGB { + + var argb = new ARGB (); + argb.set (a, r, g, b); + return argb; + + } + + + public inline function multiplyAlpha () { + + if (a == 0) { + + this = 0; + + } else if (a != 0xFF) { + + a16 = RGBA.__alpha16[a]; + set (a, (r * a16) >> 16, (g * a16) >> 16, (b * a16) >> 16); + + } + + } + + + public inline function readUInt8 (data:UInt8Array, offset:Int, format:PixelFormat = RGBA32, premultiplied:Bool = false):Void { + + switch (format) { + + case BGRA32: + + set (data[offset + 1], data[offset], data[offset + 3], data[offset + 2]); + + case RGBA32: + + set (data[offset + 1], data[offset + 2], data[offset + 3], data[offset]); + + case ARGB32: + + set (data[offset + 2], data[offset + 3], data[offset], data[offset + 1]); + + } + + if (premultiplied) { + + unmultiplyAlpha (); + + } + + } + + + public inline function set (a:Int, r:Int, g:Int, b:Int):Void { + + this = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF); + + } + + + public inline function unmultiplyAlpha () { + + if (a != 0 && a != 0xFF) { + + unmult = 255.0 / a; + set (a, RGBA.__clamp[Math.floor (r * unmult)], RGBA.__clamp[Math.floor (g * unmult)], RGBA.__clamp[Math.floor (b * unmult)]); + + } + + } + + + public inline function writeUInt8 (data:UInt8Array, offset:Int, format:PixelFormat = RGBA32, premultiplied:Bool = false):Void { + + if (premultiplied) { + + multiplyAlpha (); + + } + + switch (format) { + + case BGRA32: + + data[offset] = b; + data[offset + 1] = g; + data[offset + 2] = r; + data[offset + 3] = a; + + case RGBA32: + + data[offset] = r; + data[offset + 1] = g; + data[offset + 2] = b; + data[offset + 3] = a; + + case ARGB32: + + data[offset] = a; + data[offset + 1] = r; + data[offset + 2] = g; + data[offset + 3] = b; + + } + + } + + + @:from private static inline function __fromBGRA (bgra:BGRA):ARGB { + + return ARGB.create (bgra.a, bgra.r, bgra.g, bgra.b); + + } + + + @:from private static inline function __fromRGBA (rgba:RGBA):ARGB { + + return ARGB.create (rgba.a, rgba.r, rgba.g, rgba.b); + + } + + + + + // Get & Set Methods + + + + + private inline function get_a ():Int { + + return (this >> 24) & 0xFF; + + + } + + + private inline function set_a (value:Int):Int { + + set (value, r, g, b); + return value; + + } + + + private inline function get_b ():Int { + + return this & 0xFF; + + } + + + private inline function set_b (value:Int):Int { + + set (a, r, g, value); + return value; + + } + + + private inline function get_g ():Int { + + return (this >> 8) & 0xFF; + + } + + + private inline function set_g (value:Int):Int { + + set (a, r, value, b); + return value; + + } + + + private inline function get_r ():Int { + + return (this >> 16) & 0xFF; + + } + + + private inline function set_r (value:Int):Int { + + set (a, value, g, b); + return value; + + } + + +} \ No newline at end of file diff --git a/lime/math/color/BGRA.hx b/lime/math/color/BGRA.hx new file mode 100644 index 000000000..7bba30d32 --- /dev/null +++ b/lime/math/color/BGRA.hx @@ -0,0 +1,216 @@ +package lime.math.color; + + +import lime.graphics.PixelFormat; +import lime.utils.UInt32Array; +import lime.utils.UInt8Array; + + +abstract BGRA(Int) from Int to Int { + + + private static var a16:Int; + private static var unmult:Float; + + public var a (get, set):Int; + public var b (get, set):Int; + public var g (get, set):Int; + public var r (get, set):Int; + + + public inline function new (bgra:Int = 0) { + + this = bgra; + + } + + + public static inline function create (b:Int, g:Int, r:Int, a:Int):BGRA { + + var bgra = new BGRA (); + bgra.set (b, g, r, a); + return bgra; + + } + + + public inline function multiplyAlpha () { + + if (a == 0) { + + this = 0; + + } else if (a != 0xFF) { + + a16 = RGBA.__alpha16[a]; + set ((b * a16) >> 16, (g * a16) >> 16, (r * a16) >> 16, a); + + } + + } + + + public inline function readUInt8 (data:UInt8Array, offset:Int, format:PixelFormat = RGBA32, premultiplied:Bool = false):Void { + + switch (format) { + + case BGRA32: + + set (data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); + + case RGBA32: + + set (data[offset + 2], data[offset + 1], data[offset], data[offset + 3]); + + case ARGB32: + + set (data[offset + 3], data[offset + 2], data[offset + 1], data[offset]); + + } + + if (premultiplied) { + + unmultiplyAlpha (); + + } + + } + + + public inline function set (b:Int, g:Int, r:Int, a:Int):Void { + + this = ((b & 0xFF) << 24) | ((g & 0xFF) << 16) | ((r & 0xFF) << 8) | (a & 0xFF); + + } + + + public inline function unmultiplyAlpha () { + + if (a != 0 && a != 0xFF) { + + unmult = 255.0 / a; + set (RGBA.__clamp[Math.floor (b * unmult)], RGBA.__clamp[Math.floor (g * unmult)], RGBA.__clamp[Math.floor (r * unmult)], a); + + } + + } + + + public inline function writeUInt8 (data:UInt8Array, offset:Int, format:PixelFormat = RGBA32, premultiplied:Bool = false):Void { + + if (premultiplied) { + + multiplyAlpha (); + + } + + switch (format) { + + case BGRA32: + + data[offset] = b; + data[offset + 1] = g; + data[offset + 2] = r; + data[offset + 3] = a; + + case RGBA32: + + data[offset] = r; + data[offset + 1] = g; + data[offset + 2] = b; + data[offset + 3] = a; + + case ARGB32: + + data[offset] = a; + data[offset + 1] = r; + data[offset + 2] = g; + data[offset + 3] = b; + + } + + } + + + @:from private static inline function __fromARGB (argb:ARGB):BGRA { + + return BGRA.create (argb.b, argb.g, argb.r, argb.a); + + } + + + @:from private static inline function __fromRGBA (rgba:RGBA):BGRA { + + return BGRA.create (rgba.b, rgba.g, rgba.r, rgba.a); + + } + + + + + // Get & Set Methods + + + + + private inline function get_a ():Int { + + return this & 0xFF; + + } + + + private inline function set_a (value:Int):Int { + + set (b, g, r, value); + return value; + + } + + + private inline function get_b ():Int { + + return (this >> 24) & 0xFF; + + } + + + private inline function set_b (value:Int):Int { + + set (value, g, r, a); + return value; + + } + + + private inline function get_g ():Int { + + return (this >> 16) & 0xFF; + + } + + + private inline function set_g (value:Int):Int { + + set (b, value, r, a); + return value; + + } + + + private inline function get_r ():Int { + + return (this >> 8) & 0xFF; + + } + + + private inline function set_r (value:Int):Int { + + set (b, g, value, a); + return value; + + } + + +} \ No newline at end of file diff --git a/lime/math/color/RGBA.hx b/lime/math/color/RGBA.hx new file mode 100644 index 000000000..6f6753dec --- /dev/null +++ b/lime/math/color/RGBA.hx @@ -0,0 +1,251 @@ +package lime.math.color; + + +import lime.graphics.PixelFormat; +import lime.utils.UInt32Array; +import lime.utils.UInt8Array; + +@:allow(lime.math.color) + + +abstract RGBA(Int) from Int to Int { + + + private static var __alpha16:UInt32Array; + private static var __clamp:UInt8Array; + private static var a16:Int; + private static var unmult:Float; + + public var a (get, set):Int; + public var b (get, set):Int; + public var g (get, set):Int; + public var r (get, set):Int; + + + private static function __init__ ():Void { + + __alpha16 = new UInt32Array (256); + + for (i in 0...256) { + + __alpha16[i] = Math.ceil ((i) * ((1 << 16) / 0xFF)); + + } + + __clamp = new UInt8Array (0xFF + 0xFF); + + for (i in 0...0xFF) { + + __clamp[i] = i; + + } + + for (i in 0xFF...(0xFF + 0xFF + 1)) { + + __clamp[i] = 0xFF; + + } + + } + + + public inline function new (rgba:Int = 0) { + + this = rgba; + + } + + + public static inline function create (r:Int, g:Int, b:Int, a:Int):RGBA { + + var rgba = new RGBA (); + rgba.set (r, g, b, a); + return rgba; + + } + + + public inline function multiplyAlpha () { + + if (a == 0) { + + if (this != 0) { + + this = 0; + + } + + } else if (a != 0xFF) { + + a16 = __alpha16[a]; + set ((r * a16) >> 16, (g * a16) >> 16, (b * a16) >> 16, a); + + } + + } + + + public inline function readUInt8 (data:UInt8Array, offset:Int, format:PixelFormat = RGBA32, premultiplied:Bool = false):Void { + + switch (format) { + + case BGRA32: + + set (data[offset + 2], data[offset + 1], data[offset], data[offset + 3]); + + case RGBA32: + + set (data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); + + case ARGB32: + + set (data[offset + 1], data[offset + 2], data[offset + 3], data[offset]); + + } + + if (premultiplied) { + + unmultiplyAlpha (); + + } + + } + + + public inline function set (r:Int, g:Int, b:Int, a:Int):Void { + + this = ((r & 0xFF) << 24) | ((g & 0xFF) << 16) | ((b & 0xFF) << 8) | (a & 0xFF); + + } + + + public inline function unmultiplyAlpha () { + + if (a != 0 && a != 0xFF) { + + unmult = 255.0 / a; + set (__clamp[Math.round (r * unmult)], __clamp[Math.round (g * unmult)], __clamp[Math.round (b * unmult)], a); + + } + + } + + + public inline function writeUInt8 (data:UInt8Array, offset:Int, format:PixelFormat = RGBA32, premultiplied:Bool = false):Void { + + if (premultiplied) { + + multiplyAlpha (); + + } + + switch (format) { + + case BGRA32: + + data[offset] = b; + data[offset + 1] = g; + data[offset + 2] = r; + data[offset + 3] = a; + + case RGBA32: + + data[offset] = r; + data[offset + 1] = g; + data[offset + 2] = b; + data[offset + 3] = a; + + case ARGB32: + + data[offset] = a; + data[offset + 1] = r; + data[offset + 2] = g; + data[offset + 3] = b; + + } + + } + + + @:from private static inline function __fromARGB (argb:ARGB):RGBA { + + return RGBA.create (argb.r, argb.g, argb.b, argb.a); + + } + + + @:from private static inline function __fromBGRA (bgra:BGRA):RGBA { + + return RGBA.create (bgra.r, bgra.g, bgra.b, bgra.a); + + } + + + + + // Get & Set Methods + + + + + private inline function get_a ():Int { + + return this & 0xFF; + + } + + + private inline function set_a (value:Int):Int { + + set (r, g, b, value); + return value; + + } + + + private inline function get_b ():Int { + + return (this >> 8) & 0xFF; + + } + + + private inline function set_b (value:Int):Int { + + set (r, g, value, a); + return value; + + } + + + private inline function get_g ():Int { + + return (this >> 16) & 0xFF; + + } + + + private inline function set_g (value:Int):Int { + + set (r, value, b, a); + return value; + + } + + + private inline function get_r ():Int { + + return (this >> 24) & 0xFF; + + } + + + private inline function set_r (value:Int):Int { + + set (value, g, b, a); + return value; + + } + + +} \ No newline at end of file diff --git a/lime/net/curl/CURLCode.hx b/lime/net/curl/CURLCode.hx index 3e647ada5..0d0a5b9e8 100644 --- a/lime/net/curl/CURLCode.hx +++ b/lime/net/curl/CURLCode.hx @@ -1,7 +1,7 @@ package lime.net.curl; -@:enum abstract CURLCode(Int) { +@:enum abstract CURLCode(Int) from Int to Int { var OK = 0; var UNSUPPORTED_PROTOCOL = 1; diff --git a/lime/net/curl/CURLInfo.hx b/lime/net/curl/CURLInfo.hx index 238162c34..17a1ce8e2 100644 --- a/lime/net/curl/CURLInfo.hx +++ b/lime/net/curl/CURLInfo.hx @@ -1,7 +1,7 @@ package lime.net.curl; -@:enum abstract CURLInfo(Int) { +@:enum abstract CURLInfo(Int) from Int to Int { var NONE = 0; var EFFECTIVE_URL = 0x100000 + 1; diff --git a/lime/net/curl/CURLOption.hx b/lime/net/curl/CURLOption.hx index e3e3ecd3c..075e7d6ef 100644 --- a/lime/net/curl/CURLOption.hx +++ b/lime/net/curl/CURLOption.hx @@ -1,7 +1,7 @@ package lime.net.curl; -@:enum abstract CURLOption(Int) { +@:enum abstract CURLOption(Int) from Int to Int { //var FILE = 10001; //var WRITEDATA = 10001; diff --git a/lime/net/curl/CURLVersion.hx b/lime/net/curl/CURLVersion.hx index 008bc2a9f..052952b73 100644 --- a/lime/net/curl/CURLVersion.hx +++ b/lime/net/curl/CURLVersion.hx @@ -1,7 +1,7 @@ package lime.net.curl; -@:enum abstract CURLVersion(Int) { +@:enum abstract CURLVersion(Int) from Int to Int { var FIRST = 0; var SECOND = 1; diff --git a/lime/project/HXProject.hx b/lime/project/HXProject.hx index 1090ac437..46c11a312 100644 --- a/lime/project/HXProject.hx +++ b/lime/project/HXProject.hx @@ -136,7 +136,7 @@ class HXProject { defaultWindow.width = 0; defaultWindow.height = 0; - defaultWindow.fps = 0; + defaultWindow.fps = 60; case ANDROID, BLACKBERRY, IOS, TIZEN, WEBOS: diff --git a/lime/project/Library.hx b/lime/project/Library.hx index 06ccad052..d6d8597f6 100644 --- a/lime/project/Library.hx +++ b/lime/project/Library.hx @@ -10,12 +10,13 @@ class Library { public var embed:Null; public var generate:Bool; public var name:String; + public var prefix:String; public var preload:Bool; public var sourcePath:String; public var type:String; - public function new (sourcePath:String, name:String = "", type:String = null, embed:Null = null, preload:Bool = false, generate:Bool = false) { + public function new (sourcePath:String, name:String = "", type:String = null, embed:Null = null, preload:Bool = false, generate:Bool = false, prefix:String = "") { this.sourcePath = sourcePath; @@ -33,13 +34,14 @@ class Library { this.embed = embed; this.preload = preload; this.generate = generate; + this.prefix = prefix; } public function clone ():Library { - return new Library (sourcePath, name, type, embed, preload, generate); + return new Library (sourcePath, name, type, embed, preload, generate, prefix); } diff --git a/lime/project/ProjectXMLParser.hx b/lime/project/ProjectXMLParser.hx index 9692dda16..64fb29587 100644 --- a/lime/project/ProjectXMLParser.hx +++ b/lime/project/ProjectXMLParser.hx @@ -1214,6 +1214,7 @@ class ProjectXMLParser extends HXProject { var embed:Null = null; var preload = false; var generate = false; + var prefix = ""; if (element.has.name) { @@ -1251,7 +1252,13 @@ class ProjectXMLParser extends HXProject { } - libraries.push (new Library (path, name, type, embed, preload, generate)); + if (element.has.prefix) { + + prefix = substitute (element.att.prefix); + + } + + libraries.push (new Library (path, name, type, embed, preload, generate, prefix)); } diff --git a/lime/system/BackgroundWorker.hx b/lime/system/BackgroundWorker.hx index 5888067ab..d1ffe3643 100644 --- a/lime/system/BackgroundWorker.hx +++ b/lime/system/BackgroundWorker.hx @@ -74,7 +74,7 @@ class BackgroundWorker { } - public function sendComplete (message:Dynamic):Void { + public function sendComplete (message:Dynamic = null):Void { #if (cpp || neko) @@ -95,7 +95,7 @@ class BackgroundWorker { } - public function sendError (message:Dynamic):Void { + public function sendError (message:Dynamic = null):Void { #if (cpp || neko) @@ -116,7 +116,7 @@ class BackgroundWorker { } - public function sendProgress (message:Dynamic):Void { + public function sendProgress (message:Dynamic = null):Void { #if (cpp || neko) diff --git a/lime/system/ThreadPool.hx b/lime/system/ThreadPool.hx new file mode 100644 index 000000000..f60ee3c17 --- /dev/null +++ b/lime/system/ThreadPool.hx @@ -0,0 +1,240 @@ +package lime.system; + + +import lime.app.Application; +import lime.app.Event; + +#if cpp +import cpp.vm.Deque; +import cpp.vm.Thread; +#elseif neko +import neko.vm.Deque; +import neko.vm.Thread; +#end + + +class ThreadPool { + + + public var currentThreads (default, null):Int; + public var doWork = new EventDynamic->Void> (); + public var maxThreads:Int; + public var minThreads:Int; + public var onComplete = new EventDynamic->Void> (); + public var onError = new EventDynamic->Void> (); + public var onProgress = new EventDynamic->Void> (); + + #if (cpp || neko) + private var __workCompleted:Int; + private var __workIncoming = new Deque (); + private var __workQueued:Int; + private var __workResult = new Deque (); + #end + + + public function new (minThreads:Int = 0, maxThreads:Int = 1) { + + this.minThreads = minThreads; + this.maxThreads = maxThreads; + + currentThreads = 0; + + #if (cpp || neko) + __workQueued = 0; + __workCompleted = 0; + #end + + } + + + //public function cancel (id:String):Void { + // + // + // + //} + + + //public function isCanceled (id:String):Bool { + // + // + // + //} + + + public function queue (id:String, message:Dynamic = null):Void { + + #if (cpp || neko) + + __workIncoming.add (new ThreadPoolMessage (WORK, id, message)); + __workQueued++; + + if (currentThreads < maxThreads && currentThreads < (__workQueued - __workCompleted)) { + + currentThreads++; + Thread.create (__doWork); + + } + + if (!Application.current.onUpdate.has (__update)) { + + Application.current.onUpdate.add (__update); + + } + + #else + + doWork.dispatch (id, message); + + #end + + } + + + public function sendComplete (id:String, message:Dynamic = null):Void { + + #if (cpp || neko) + __workResult.add (new ThreadPoolMessage (COMPLETE, id, message)); + #else + onComplete.dispatch (id, message); + #end + + } + + + public function sendError (id:String, message:Dynamic = null):Void { + + #if (cpp || neko) + __workResult.add (new ThreadPoolMessage (ERROR, id, message)); + #else + onError.dispatch (id, message); + #end + + } + + + public function sendProgress (id:String, message:Dynamic = null):Void { + + #if (cpp || neko) + __workResult.add (new ThreadPoolMessage (PROGRESS, id, message)); + #else + onProgress.dispatch (id, message); + #end + + } + + + #if (cpp || neko) + + private function __doWork ():Void { + + while (true) { + + var message = __workIncoming.pop (true); + + if (message.type == WORK) { + + doWork.dispatch (message.id, message.message); + + } else if (message.type == EXIT) { + + break; + + } + + } + + } + + + private function __update (deltaTime:Int):Void { + + if (__workQueued > __workCompleted) { + + var message = __workResult.pop (false); + + while (message != null) { + + switch (message.type) { + + case PROGRESS: + + onProgress.dispatch (message.id, message.message); + + case COMPLETE, ERROR: + + __workCompleted++; + + if (currentThreads > (__workQueued - __workCompleted) || currentThreads > maxThreads) { + + currentThreads--; + __workIncoming.add (new ThreadPoolMessage (EXIT, null, null)); + + } + + if (message.type == COMPLETE) { + + onComplete.dispatch (message.id, message.message); + + } else { + + onError.dispatch (message.id, message.message); + + } + + default: + + } + + message = __workResult.pop (false); + + } + + } else { + + // TODO: Add sleep if keeping minThreads running with no work? + + if (currentThreads == 0 && minThreads <= 0) { + + Application.current.onUpdate.remove (__update); + + } + + } + + } + + #end + + +} + + +private enum ThreadPoolMessageType { + + COMPLETE; + ERROR; + EXIT; + PROGRESS; + WORK; + +} + + +private class ThreadPoolMessage { + + + public var id:String; + public var message:Dynamic; + public var type:ThreadPoolMessageType; + + + public function new (type:ThreadPoolMessageType, id:String, message:Dynamic) { + + this.type = type; + this.id = id; + this.message = message; + + } + + +} \ No newline at end of file diff --git a/lime/text/TextLayout.hx b/lime/text/TextLayout.hx index 71f552b06..f1efc1f08 100644 --- a/lime/text/TextLayout.hx +++ b/lime/text/TextLayout.hx @@ -100,15 +100,18 @@ class TextLayout { @:noCompletion private function get_positions ():Array { - if ( __dirty ) - { + if (__dirty) { + __dirty = false; - __position(); + __position (); + } return positions; + } + @:noCompletion private function get_direction ():TextDirection { return __direction; diff --git a/lime/tools/helpers/FlashHelper.hx b/lime/tools/helpers/FlashHelper.hx index 1c931733d..3e052431e 100644 --- a/lime/tools/helpers/FlashHelper.hx +++ b/lime/tools/helpers/FlashHelper.hx @@ -1012,7 +1012,7 @@ class FlashHelper { } - Sys.sleep (1); + Sys.sleep (0.3); } diff --git a/lime/tools/helpers/IconHelper.hx b/lime/tools/helpers/IconHelper.hx index af6f82972..1b4e5db4e 100644 --- a/lime/tools/helpers/IconHelper.hx +++ b/lime/tools/helpers/IconHelper.hx @@ -122,7 +122,7 @@ class IconHelper { for (c in 0...4) out.writeByte (code.charCodeAt(c)); var n = s * s; - var pixels = image.getPixels (new Rectangle (0, 0, s, s), ARGB); + var pixels = image.getPixels (new Rectangle (0, 0, s, s), ARGB32); var bytes_r = packBits (pixels, 1, s * s); var bytes_g = packBits (pixels, 2, s * s); diff --git a/lime/tools/platforms/AndroidPlatform.hx b/lime/tools/platforms/AndroidPlatform.hx index 3495b9e40..97de3b7d0 100644 --- a/lime/tools/platforms/AndroidPlatform.hx +++ b/lime/tools/platforms/AndroidPlatform.hx @@ -16,6 +16,7 @@ import lime.tools.helpers.ProcessHelper; import lime.project.Architecture; import lime.project.AssetType; import lime.project.HXProject; +import lime.project.Icon; import lime.project.PlatformTarget; import sys.io.File; import sys.FileSystem; @@ -322,10 +323,17 @@ class AndroidPlatform extends PlatformTarget { var iconTypes = [ "ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi" ]; var iconSizes = [ 36, 48, 72, 96, 144, 192 ]; + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } for (i in 0...iconTypes.length) { - if (IconHelper.createIcon (project.icons, iconSizes[i], iconSizes[i], destination + "/res/drawable-" + iconTypes[i] + "/icon.png")) { + if (IconHelper.createIcon (icons, iconSizes[i], iconSizes[i], destination + "/res/drawable-" + iconTypes[i] + "/icon.png")) { context.HAS_ICON = true; @@ -333,7 +341,7 @@ class AndroidPlatform extends PlatformTarget { } - IconHelper.createIcon (project.icons, 732, 412, destination + "/res/drawable-xhdpi/ouya_icon.png"); + IconHelper.createIcon (icons, 732, 412, destination + "/res/drawable-xhdpi/ouya_icon.png"); var packageDirectory = project.meta.packageName; packageDirectory = destination + "/src/" + packageDirectory.split (".").join ("/"); diff --git a/lime/tools/platforms/BlackBerryPlatform.hx b/lime/tools/platforms/BlackBerryPlatform.hx index c2c3fbaef..04387b3b1 100644 --- a/lime/tools/platforms/BlackBerryPlatform.hx +++ b/lime/tools/platforms/BlackBerryPlatform.hx @@ -16,6 +16,7 @@ import lime.tools.helpers.ProcessHelper; import lime.project.AssetType; import lime.project.Haxelib; import lime.project.HXProject; +import lime.project.Icon; import lime.project.NDLL; import lime.project.PlatformTarget; import sys.io.File; @@ -320,9 +321,17 @@ class BlackBerryPlatform extends PlatformTarget { context.ICONS = []; context.HAS_ICON = false; + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + for (size in [ 114, 86 ]) { - if (IconHelper.createIcon (project.icons, size, size, PathHelper.combine (destination, "icon-" + size + ".png"))) { + if (IconHelper.createIcon (icons, size, size, PathHelper.combine (destination, "icon-" + size + ".png"))) { context.ICONS.push ("icon-" + size + ".png"); context.HAS_ICON = true; diff --git a/lime/tools/platforms/FirefoxPlatform.hx b/lime/tools/platforms/FirefoxPlatform.hx index 4e2543024..597f180f3 100644 --- a/lime/tools/platforms/FirefoxPlatform.hx +++ b/lime/tools/platforms/FirefoxPlatform.hx @@ -8,6 +8,7 @@ import lime.tools.helpers.IconHelper; import lime.tools.helpers.PathHelper; import lime.tools.helpers.LogHelper; import lime.project.HXProject; +import lime.project.Icon; import sys.FileSystem; @@ -68,10 +69,17 @@ class FirefoxPlatform extends HTML5Platform { FileHelper.recursiveCopyTemplate (project.templatePaths, "firefox/template", destination, context); var sizes = [ 32, 48, 60, 64, 128, 512 ]; + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } for (size in sizes) { - IconHelper.createIcon (project.icons, size, size, PathHelper.combine (destination, "icon-" + size + ".png")); + IconHelper.createIcon (icons, size, size, PathHelper.combine (destination, "icon-" + size + ".png")); } diff --git a/lime/tools/platforms/FlashPlatform.hx b/lime/tools/platforms/FlashPlatform.hx index e10e5dffc..cdd9cf8ee 100644 --- a/lime/tools/platforms/FlashPlatform.hx +++ b/lime/tools/platforms/FlashPlatform.hx @@ -8,6 +8,7 @@ import lime.tools.helpers.CompatibilityHelper; import lime.tools.helpers.DeploymentHelper; import lime.tools.helpers.FileHelper; import lime.tools.helpers.FlashHelper; +import lime.tools.helpers.LogHelper; import lime.tools.helpers.PathHelper; import lime.tools.helpers.PlatformHelper; import lime.tools.helpers.ProcessHelper; @@ -172,6 +173,12 @@ class FlashPlatform extends PlatformTarget { } + if (LogHelper.verbose) { + + project.haxedefs.set ("verbose", 1); + + } + var context = project.templateContext; context.WIN_FLASHBACKGROUND = StringTools.hex (project.window.background, 6); var assets:Array = cast context.assets; diff --git a/lime/tools/platforms/HTML5Platform.hx b/lime/tools/platforms/HTML5Platform.hx index c204ddea8..caa00cd15 100644 --- a/lime/tools/platforms/HTML5Platform.hx +++ b/lime/tools/platforms/HTML5Platform.hx @@ -171,6 +171,12 @@ class HTML5Platform extends PlatformTarget { } + if (LogHelper.verbose) { + + project.haxedefs.set ("verbose", 1); + + } + var context = project.templateContext; context.WIN_FLASHBACKGROUND = StringTools.hex (project.window.background, 6); diff --git a/lime/tools/platforms/IOSPlatform.hx b/lime/tools/platforms/IOSPlatform.hx index 6c269f631..98fe8c4a6 100644 --- a/lime/tools/platforms/IOSPlatform.hx +++ b/lime/tools/platforms/IOSPlatform.hx @@ -23,6 +23,7 @@ import lime.project.Asset; import lime.project.AssetType; import lime.project.Haxelib; import lime.project.HXProject; +import lime.project.Icon; import lime.project.Keystore; import lime.project.NDLL; import lime.project.Platform; @@ -384,15 +385,23 @@ class IOSPlatform extends PlatformTarget { { name : "Icon-76@2x.png", size : 152 }, { name : "Icon-60@3x.png", size : 180 }, ]; - + context.HAS_ICON = true; var iconPath = PathHelper.combine (projectDirectory, "Images.xcassets/AppIcon.appiconset"); PathHelper.mkdir (iconPath); + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + for (iconSize in iconSizes) { - if (!IconHelper.createIcon (project.icons, iconSize.size, iconSize.size, PathHelper.combine (iconPath, iconSize.name))) { + if (!IconHelper.createIcon (icons, iconSize.size, iconSize.size, PathHelper.combine (iconPath, iconSize.name))) { context.HAS_ICON = false; diff --git a/lime/tools/platforms/LinuxPlatform.hx b/lime/tools/platforms/LinuxPlatform.hx index 87e2752ab..621c931e4 100644 --- a/lime/tools/platforms/LinuxPlatform.hx +++ b/lime/tools/platforms/LinuxPlatform.hx @@ -7,6 +7,7 @@ import lime.tools.helpers.AssetHelper; import lime.tools.helpers.CPPHelper; import lime.tools.helpers.DeploymentHelper; import lime.tools.helpers.FileHelper; +import lime.tools.helpers.LogHelper; import lime.tools.helpers.NekoHelper; import lime.tools.helpers.NodeJSHelper; import lime.tools.helpers.PathHelper; @@ -273,6 +274,12 @@ class LinuxPlatform extends PlatformTarget { var arguments = additionalArguments.copy (); + if (LogHelper.verbose) { + + arguments.push ("-verbose"); + + } + if (targetType == "nodejs") { NodeJSHelper.run (project, targetDirectory + "/bin/ApplicationMain.js", arguments); diff --git a/lime/tools/platforms/MacPlatform.hx b/lime/tools/platforms/MacPlatform.hx index d09faa683..8b7e8f916 100644 --- a/lime/tools/platforms/MacPlatform.hx +++ b/lime/tools/platforms/MacPlatform.hx @@ -9,6 +9,7 @@ import lime.tools.helpers.DeploymentHelper; import lime.tools.helpers.FileHelper; import lime.tools.helpers.IconHelper; import lime.tools.helpers.JavaHelper; +import lime.tools.helpers.LogHelper; import lime.tools.helpers.NekoHelper; import lime.tools.helpers.NodeJSHelper; import lime.tools.helpers.PathHelper; @@ -18,6 +19,7 @@ import lime.project.AssetType; import lime.project.Architecture; import lime.project.Haxelib; import lime.project.HXProject; +import lime.project.Icon; import lime.project.Platform; import lime.project.PlatformTarget; import sys.io.File; @@ -244,6 +246,12 @@ class MacPlatform extends PlatformTarget { var arguments = additionalArguments.copy (); + if (LogHelper.verbose) { + + arguments.push ("-verbose"); + + } + if (targetType == "nodejs") { NodeJSHelper.run (project, executableDirectory + "/ApplicationMain.js", arguments); @@ -310,7 +318,15 @@ class MacPlatform extends PlatformTarget { FileHelper.copyFileTemplate (project.templatePaths, "mac/Info.plist", targetDirectory + "/bin/" + project.app.file + ".app/Contents/Info.plist", context); FileHelper.copyFileTemplate (project.templatePaths, "mac/Entitlements.plist", targetDirectory + "/bin/" + project.app.file + ".app/Contents/Entitlements.plist", context); - context.HAS_ICON = IconHelper.createMacIcon (project.icons, PathHelper.combine (contentDirectory,"icon.icns")); + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + context.HAS_ICON = IconHelper.createMacIcon (icons, PathHelper.combine (contentDirectory, "icon.icns")); for (asset in project.assets) { diff --git a/lime/tools/platforms/TizenPlatform.hx b/lime/tools/platforms/TizenPlatform.hx index 8df063698..d51e47290 100644 --- a/lime/tools/platforms/TizenPlatform.hx +++ b/lime/tools/platforms/TizenPlatform.hx @@ -13,6 +13,7 @@ import lime.tools.helpers.ProcessHelper; import lime.tools.helpers.TizenHelper; import lime.project.AssetType; import lime.project.HXProject; +import lime.project.Icon; import lime.project.PlatformTarget; import sys.io.File; import sys.FileSystem; @@ -180,7 +181,15 @@ class TizenPlatform extends PlatformTarget { PathHelper.mkdir (destination + "shared/res/screen-density-xhigh"); - if (IconHelper.createIcon (project.icons, 117, 117, PathHelper.combine (destination + "shared/res/screen-density-xhigh", "mainmenu.png"))) { + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + if (IconHelper.createIcon (icons, 117, 117, PathHelper.combine (destination + "shared/res/screen-density-xhigh", "mainmenu.png"))) { context.APP_ICON = "mainmenu.png"; diff --git a/lime/tools/platforms/WebOSPlatform.hx b/lime/tools/platforms/WebOSPlatform.hx index 288b65829..7e857b496 100644 --- a/lime/tools/platforms/WebOSPlatform.hx +++ b/lime/tools/platforms/WebOSPlatform.hx @@ -13,6 +13,7 @@ import lime.tools.helpers.ProcessHelper; import lime.tools.helpers.WebOSHelper; import lime.project.AssetType; import lime.project.HXProject; +import lime.project.Icon; import lime.project.PlatformTarget; import sys.io.File; import sys.FileSystem; @@ -151,7 +152,15 @@ class WebOSPlatform extends PlatformTarget { var context = project.templateContext; context.CPP_DIR = targetDirectory + "/obj"; - if (IconHelper.createIcon (project.icons, 64, 64, PathHelper.combine (destination, "icon.png"))) { + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + if (IconHelper.createIcon (icons, 64, 64, PathHelper.combine (destination, "icon.png"))) { context.APP_ICON = "icon.png"; diff --git a/lime/tools/platforms/WindowsPlatform.hx b/lime/tools/platforms/WindowsPlatform.hx index 60d85a3d9..f6e11c1bc 100644 --- a/lime/tools/platforms/WindowsPlatform.hx +++ b/lime/tools/platforms/WindowsPlatform.hx @@ -3,11 +3,13 @@ package lime.tools.platforms; import haxe.io.Path; import haxe.Template; +import lime.project.Icon; import lime.tools.helpers.AssetHelper; import lime.tools.helpers.CPPHelper; import lime.tools.helpers.DeploymentHelper; import lime.tools.helpers.FileHelper; import lime.tools.helpers.IconHelper; +import lime.tools.helpers.LogHelper; import lime.tools.helpers.NekoHelper; import lime.tools.helpers.NodeJSHelper; import lime.tools.helpers.PathHelper; @@ -94,6 +96,14 @@ class WindowsPlatform extends PlatformTarget { } + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + //IconHelper.createIcon (project.icons, 32, 32, PathHelper.combine (applicationDirectory, "icon.png")); if (targetType == "neko") { @@ -102,7 +112,7 @@ class WindowsPlatform extends PlatformTarget { var iconPath = PathHelper.combine (applicationDirectory, "icon.ico"); - if (!IconHelper.createWindowsIcon (project.icons, iconPath)) { + if (!IconHelper.createWindowsIcon (icons, iconPath)) { iconPath = null; @@ -148,7 +158,7 @@ class WindowsPlatform extends PlatformTarget { var iconPath = PathHelper.combine (applicationDirectory, "icon.ico"); - if (IconHelper.createWindowsIcon (project.icons, iconPath) && PlatformHelper.hostPlatform == WINDOWS) { + if (IconHelper.createWindowsIcon (icons, iconPath) && PlatformHelper.hostPlatform == WINDOWS) { var templates = [ PathHelper.getHaxelib (new Haxelib ("lime")) + "/templates" ].concat (project.templatePaths); ProcessHelper.runCommand ("", PathHelper.findTemplate (templates, "bin/ReplaceVistaIcon.exe"), [ executablePath, iconPath, "1" ], true, true); @@ -231,6 +241,12 @@ class WindowsPlatform extends PlatformTarget { var arguments = additionalArguments.copy (); + if (LogHelper.verbose) { + + arguments.push ("-verbose"); + + } + if (targetType == "nodejs") { NodeJSHelper.run (project, targetDirectory + "/bin/ApplicationMain.js", arguments); diff --git a/lime/utils/ArrayBufferView.hx b/lime/utils/ArrayBufferView.hx index c3faa486a..117c90b1e 100644 --- a/lime/utils/ArrayBufferView.hx +++ b/lime/utils/ArrayBufferView.hx @@ -130,7 +130,7 @@ class ArrayBufferView { public function set( ?view:ArrayBufferView, ?array:Array, offset:Int = 0 ) : Void { if(view != null && array == null) { - buffer.blit( toByteLength(offset), view.buffer, view.byteOffset, view.buffer.length ); + buffer.blit( toByteLength(offset), view.buffer, view.byteOffset, view.byteLength ); } else if(array != null && view == null) { copyFromArray(cast array, offset); } else { @@ -241,7 +241,9 @@ class ArrayBufferView { #if !no_typedarray_inline inline #end function toString() { - + + if (this == null) return null; + var name = switch(type) { case Int8: 'Int8Array'; @@ -517,8 +519,8 @@ private abstract TypedArrayType(Int) from Int to Int { #if cpp untyped return __global__.__hxcpp_memory_get_i32(buffer.getData(), byteOffset); #else - #if (haxe_ver > 3103) - return buffer.getI32(byteOffset); + #if (haxe_ver >= 3.2) + return buffer.getInt32(byteOffset); #else var ch1 = getInt8(buffer, byteOffset ); @@ -542,8 +544,8 @@ private abstract TypedArrayType(Int) from Int to Int { #if cpp untyped __global__.__hxcpp_memory_set_i32(buffer.getData(), byteOffset, value); #else - #if (haxe_ver > 3103) - buffer.setI32(byteOffset,value); + #if ((haxe_ver >= 3.2) && !neko) // causes error on some int values? + buffer.setInt32(byteOffset,value); #else if (littleEndian) { setInt8(buffer, byteOffset , value ); diff --git a/lime/utils/ByteArray.hx b/lime/utils/ByteArray.hx index fd13fd40c..712f2b95c 100644 --- a/lime/utils/ByteArray.hx +++ b/lime/utils/ByteArray.hx @@ -328,11 +328,11 @@ class ByteArray #if !js extends Bytes implements ArrayAccess implements IDa public static function readFile (path:String):ByteArray { - #if html5 - return null; - #else - return ByteArray.fromBytes (File.getBytes (path)); + #if !html5 + var data = lime_bytes_read_file (path); + if (data != null) return ByteArray.fromBytes (@:privateAccess new Bytes (data.length, data.b)); #end + return null; } @@ -905,6 +905,16 @@ class ByteArray #if !js extends Bytes implements ArrayAccess implements IDa } + #if (cpp || neko || nodejs) + public static function __fromNativePointer (data:Dynamic, length:Int):ByteArray { + + var bytes = lime_bytes_from_data_pointer (data, length); + return ByteArray.fromBytes (@:privateAccess new Bytes (bytes.length, bytes.b)); + + } + #end + + @:keep public inline function __get (pos:Int):Int { #if js @@ -1092,7 +1102,9 @@ class ByteArray #if !js extends Bytes implements ArrayAccess implements IDa + private static var lime_bytes_from_data_pointer = System.load ("lime", "lime_bytes_from_data_pointer", 2); private static var lime_bytes_get_data_pointer = System.load ("lime", "lime_bytes_get_data_pointer", 1); + private static var lime_bytes_read_file = System.load ("lime", "lime_bytes_read_file", 1); } diff --git a/lime/utils/Float32Array.hx b/lime/utils/Float32Array.hx index 258a9e539..54963271a 100644 --- a/lime/utils/Float32Array.hx +++ b/lime/utils/Float32Array.hx @@ -53,7 +53,7 @@ package lime.utils; #end } - function toString() return 'Float32Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Float32Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } @@ -107,7 +107,7 @@ abstract Float32Array(ArrayBufferView) from ArrayBufferView to ArrayBufferView { //Internal - function toString() return 'Float32Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Float32Array [byteLength:${this.byteLength}, length:${this.length}]' : null; inline function get_length() return this.length; diff --git a/lime/utils/Float64Array.hx b/lime/utils/Float64Array.hx index 7046cfa77..d84329620 100644 --- a/lime/utils/Float64Array.hx +++ b/lime/utils/Float64Array.hx @@ -53,7 +53,7 @@ package lime.utils; #end } - function toString() return 'Float64Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Float64Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } @@ -121,7 +121,7 @@ abstract Float64Array(ArrayBufferView) from ArrayBufferView to ArrayBufferView { return ArrayBufferIO.setFloat64(this.buffer, this.byteOffset+(idx*BYTES_PER_ELEMENT), val); } - function toString() return 'Float64Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Float64Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } diff --git a/lime/utils/Int16Array.hx b/lime/utils/Int16Array.hx index 432ed36a6..517441fd8 100644 --- a/lime/utils/Int16Array.hx +++ b/lime/utils/Int16Array.hx @@ -53,7 +53,7 @@ package lime.utils; #end } - function toString() return 'Int16Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Int16Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } @@ -121,7 +121,7 @@ abstract Int16Array(ArrayBufferView) from ArrayBufferView to ArrayBufferView { return ArrayBufferIO.setInt16(this.buffer, this.byteOffset+(idx*BYTES_PER_ELEMENT), val); } - function toString() return 'Int16Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Int16Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } diff --git a/lime/utils/Int32Array.hx b/lime/utils/Int32Array.hx index 7baaeba09..c89b07b50 100644 --- a/lime/utils/Int32Array.hx +++ b/lime/utils/Int32Array.hx @@ -53,7 +53,7 @@ package lime.utils; #end } - function toString() return 'Int32Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Int32Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } @@ -121,7 +121,7 @@ abstract Int32Array(ArrayBufferView) from ArrayBufferView to ArrayBufferView { return ArrayBufferIO.setInt32(this.buffer, this.byteOffset+(idx*BYTES_PER_ELEMENT), val); } - function toString() return 'Int32Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Int32Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } diff --git a/lime/utils/Int8Array.hx b/lime/utils/Int8Array.hx index a56682848..2785966fb 100644 --- a/lime/utils/Int8Array.hx +++ b/lime/utils/Int8Array.hx @@ -51,7 +51,7 @@ package lime.utils; #end } - function toString() return 'Int8Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Int8Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } @@ -121,7 +121,7 @@ abstract Int8Array(ArrayBufferView) from ArrayBufferView to ArrayBufferView { return ArrayBufferIO.setInt8(this.buffer, this.byteOffset+idx, val); } - function toString() return 'Int8Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'Int8Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } diff --git a/lime/utils/Log.hx b/lime/utils/Log.hx new file mode 100644 index 000000000..e6c232dc0 --- /dev/null +++ b/lime/utils/Log.hx @@ -0,0 +1,148 @@ +package lime.utils; + + +import haxe.PosInfos; + + +class Log { + + + public static var level:LogLevel; + + + public static function debug (message:String, ?info:PosInfos):Void { + + if (level >= DEBUG) { + + println ("[" + info.className + "] " + message); + + } + + } + + + public static function error (message:String, ?info:PosInfos):Void { + + if (level >= ERROR) { + + println ("[" + info.className + "] ERROR: " + message); + + } + + } + + + public static function info (message:String, ?info:PosInfos):Void { + + if (level >= INFO) { + + println ("[" + info.className + "] " + message); + + } + + } + + + public static inline function print (message:String):Void { + + #if sys + Sys.print (message); + #elseif flash + untyped __global__["trace"] (message); + #elseif js + untyped __js__("console").log (message); + #else + trace (message); + #end + + } + + + public static inline function println (message:String):Void { + + #if sys + Sys.println (message); + #elseif flash + untyped __global__["trace"] (message); + #elseif js + untyped __js__("console").log (message); + #else + trace (message); + #end + + } + + + public static function verbose (message:String, ?info:PosInfos):Void { + + if (level >= VERBOSE) { + + println ("[" + info.className + "] " + message); + + } + + } + + + public static function warn (message:String, ?info:PosInfos):Void { + + if (level >= WARN) { + + println ("[" + info.className + "] WARNING: " + message); + + } + + } + + + private static function __init__ ():Void { + + #if no_traces + level = NONE; + #elseif verbose + level = VERBOSE; + #else + #if sys + var args = Sys.args (); + if (args.indexOf ("-v") > -1 || args.indexOf ("-verbose") > -1) { + level = VERBOSE; + return; + } + #end + #if debug + level = DEBUG; + #else + level = INFO; + #end + #end + + #if js + if (untyped __js__("typeof console") == "undefined") { + untyped __js__("console = {}"); + } + if (untyped __js__("console").log == null) { + untyped __js__("console").log = function () {}; + } + #end + + } + + +} + + +@:enum abstract LogLevel(Int) from Int to Int { + + var NONE = 0; + var ERROR = 1; + var WARN = 2; + var INFO = 3; + var DEBUG = 4; + var VERBOSE = 5; + + @:op(A > B) private static inline function gt (a:LogLevel, b:LogLevel):Bool { return (a:Int) > (b:Int); } + @:op(A >= B) private static inline function gte (a:LogLevel, b:LogLevel):Bool { return (a:Int) >= (b:Int); } + @:op(A < B) private static inline function lt (a:LogLevel, b:LogLevel):Bool { return (a:Int) < (b:Int); } + @:op(A <= B) private static inline function lte (a:LogLevel, b:LogLevel):Bool { return (a:Int) <= (b:Int); } + +} \ No newline at end of file diff --git a/lime/utils/UInt16Array.hx b/lime/utils/UInt16Array.hx index 3c3a5b249..69af7a87d 100644 --- a/lime/utils/UInt16Array.hx +++ b/lime/utils/UInt16Array.hx @@ -53,7 +53,7 @@ package lime.utils; #end } - function toString() return 'UInt16Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'UInt16Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } @@ -121,7 +121,7 @@ abstract UInt16Array(ArrayBufferView) from ArrayBufferView to ArrayBufferView { return ArrayBufferIO.setUint16(this.buffer, this.byteOffset+(idx*BYTES_PER_ELEMENT), val); } - function toString() return 'UInt16Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'UInt16Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } diff --git a/lime/utils/UInt32Array.hx b/lime/utils/UInt32Array.hx index 1dcb82f71..b8e0070bf 100644 --- a/lime/utils/UInt32Array.hx +++ b/lime/utils/UInt32Array.hx @@ -53,7 +53,7 @@ package lime.utils; #end } - function toString() return 'UInt32Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'UInt32Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } @@ -121,7 +121,7 @@ abstract UInt32Array(ArrayBufferView) from ArrayBufferView to ArrayBufferView { return ArrayBufferIO.setUint32(this.buffer, this.byteOffset+(idx*BYTES_PER_ELEMENT), val); } - function toString() return 'UInt32Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'UInt32Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } diff --git a/lime/utils/UInt8Array.hx b/lime/utils/UInt8Array.hx index f586bd7e5..4b1e18f65 100644 --- a/lime/utils/UInt8Array.hx +++ b/lime/utils/UInt8Array.hx @@ -53,7 +53,7 @@ package lime.utils; #end } - function toString() return 'UInt8Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'UInt8Array [byteLength:${this.byteLength}, length:${this.length}]' : null; } @@ -106,7 +106,7 @@ abstract UInt8Array(ArrayBufferView) from ArrayBufferView to ArrayBufferView { //Internal - function toString() return 'UInt8Array [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'UInt8Array [byteLength:${this.byteLength}, length:${this.length}]' : null; inline function get_length() return this.length; diff --git a/lime/utils/UInt8ClampedArray.hx b/lime/utils/UInt8ClampedArray.hx index 8d2cd8e4f..b78264790 100644 --- a/lime/utils/UInt8ClampedArray.hx +++ b/lime/utils/UInt8ClampedArray.hx @@ -53,7 +53,7 @@ package lime.utils; #end } - function toString() return 'UInt8ClampedArray [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'UInt8ClampedArray [byteLength:${this.byteLength}, length:${this.length}]' : null; //internal //clamp a Int to a 0-255 Uint8 @@ -129,7 +129,7 @@ abstract UInt8ClampedArray(ArrayBufferView) from ArrayBufferView to ArrayBufferV return ArrayBufferIO.setUint8Clamped(this.buffer, this.byteOffset+idx, val); } - function toString() return 'UInt8ClampedArray [byteLength:${this.byteLength}, length:${this.length}]'; + function toString() return this != null ? 'UInt8ClampedArray [byteLength:${this.byteLength}, length:${this.length}]' : null; } diff --git a/project/Build.xml b/project/Build.xml index 7f17042d6..1732717ec 100644 --- a/project/Build.xml +++ b/project/Build.xml @@ -29,6 +29,7 @@ + diff --git a/project/include/graphics/Image.h b/project/include/graphics/Image.h index 0fc3074fb..50e631aa1 100644 --- a/project/include/graphics/Image.h +++ b/project/include/graphics/Image.h @@ -23,7 +23,6 @@ namespace lime { int height; int offsetX; int offsetY; - bool transparent; int width; private: diff --git a/project/include/graphics/ImageBuffer.h b/project/include/graphics/ImageBuffer.h index 91f01489c..3dbf4fc52 100644 --- a/project/include/graphics/ImageBuffer.h +++ b/project/include/graphics/ImageBuffer.h @@ -28,8 +28,9 @@ namespace lime { Bytes *data; PixelFormat format; int height; - int width; + bool premultiplied; bool transparent; + int width; private: diff --git a/project/include/graphics/PixelFormat.h b/project/include/graphics/PixelFormat.h index fb35c7cb1..328f410bb 100644 --- a/project/include/graphics/PixelFormat.h +++ b/project/include/graphics/PixelFormat.h @@ -7,9 +7,9 @@ namespace lime { enum PixelFormat { - RGBA, - ARGB, - BGRA + RGBA32, + ARGB32, + BGRA32 }; diff --git a/project/include/graphics/Renderer.h b/project/include/graphics/Renderer.h index 2b9186067..5f1bb69ac 100644 --- a/project/include/graphics/Renderer.h +++ b/project/include/graphics/Renderer.h @@ -16,6 +16,7 @@ namespace lime { virtual void Flip () = 0; virtual value Lock () = 0; + virtual const char* Type () = 0; virtual void Unlock () = 0; Window* currentWindow; diff --git a/project/include/graphics/utils/ImageDataUtil.h b/project/include/graphics/utils/ImageDataUtil.h index 02e1e86fc..b411e7992 100644 --- a/project/include/graphics/utils/ImageDataUtil.h +++ b/project/include/graphics/utils/ImageDataUtil.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace lime { @@ -22,9 +23,9 @@ namespace lime { 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 FloodFill (Image* image, int x, int y, int color); + static void CopyPixels (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, Image* alphaImage, Vector2* alphaPoint, bool mergeAlpha); + static void FillRect (Image* image, Rectangle* rect, int32_t color); + static void FloodFill (Image* image, int x, int y, int32_t color); static void GetPixels (Image* image, Rectangle* rect, PixelFormat format, Bytes* pixels); static void Merge (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int redMultiplier, int greenMultiplier, int blueMultiplier, int alphaMultiplier); static void MultiplyAlpha (Image* image); @@ -37,6 +38,32 @@ namespace lime { }; + class ImageDataView { + + + public: + + ImageDataView (Image* image, Rectangle* rect); + + void Clip (int x, int y, int width, int height); + int Row (int y); + + int x; + int y; + int width; + int height; + + private: + + Image* image; + int offset; + Rectangle* rect; + int stride; + + + }; + + } diff --git a/project/include/math/ColorMatrix.h b/project/include/math/ColorMatrix.h index 8d3b80fc8..1de6c652b 100644 --- a/project/include/math/ColorMatrix.h +++ b/project/include/math/ColorMatrix.h @@ -4,6 +4,7 @@ #include #include +#include namespace lime { @@ -20,16 +21,24 @@ namespace lime { float GetAlphaMultiplier (); float GetAlphaOffset (); + void GetAlphaTable (unsigned char* table); float GetBlueMultiplier (); float GetBlueOffset (); - int GetColor (); + void GetBlueTable (unsigned char* table); + int32_t GetColor (); float GetGreenMultiplier (); float GetGreenOffset (); + void GetGreenTable (unsigned char* table); float GetRedMultiplier (); float GetRedOffset (); + void GetRedTable (unsigned char* table); float data[20]; + private: + + void GetDataTable (unsigned char* table, float multiplier, float offset); + }; diff --git a/project/include/math/Rectangle.h b/project/include/math/Rectangle.h index a6b94f9e2..5c3cbf84d 100644 --- a/project/include/math/Rectangle.h +++ b/project/include/math/Rectangle.h @@ -17,6 +17,8 @@ namespace lime { Rectangle (double x, double y, double width, double height); Rectangle (value rect); + void Contract (double x, double y, double width, double height); + double height; double width; double x; diff --git a/project/include/math/color/RGBA.h b/project/include/math/color/RGBA.h new file mode 100644 index 000000000..259126806 --- /dev/null +++ b/project/include/math/color/RGBA.h @@ -0,0 +1,211 @@ +#ifndef LIME_MATH_COLOR_RGBA_H +#define LIME_MATH_COLOR_RGBA_H + + +#include +#include +#include + + +namespace lime { + + + int __alpha16[0xFF + 1]; + int __clamp[0xFF + 0xFF + 1]; + static int a16; + static double unmult; + + int initValues () { + + for (int i = 0; i < 256; i++) { + + __alpha16[i] = ceil ((float)(i + 1) * ((1 << 16) / 0xFF)); + + } + + for (int i = 0; i < 0xFF; i++) { + + __clamp[i] = i; + + } + + for (int i = 0xFF; i < (0xFF + 0xFF + 1); i++) { + + __clamp[i] = 0xFF; + + } + + return 0; + + } + + static int initValues_ = initValues (); + + + struct RGBA { + + + public: + + inline RGBA () { + + r = 0; + g = 0; + b = 0; + a = 0; + + } + + + inline RGBA (int32_t rgba) { + + r = (rgba >> 24) & 0xFF; + g = (rgba >> 16) & 0xFF; + b = (rgba >> 8) & 0xFF; + a = rgba & 0xFF; + + } + + + inline RGBA (unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + + Set (r, g, b, a); + + } + + + inline int32_t Get () { + + int32_t value = ((r & 0xFF) << 24) | ((g & 0xFF) << 16) | ((b & 0xFF) << 8) | (a & 0xFF); + return value; + + } + + + inline void MultiplyAlpha () { + + if (a == 0) { + + Set (0, 0, 0, 0); + + } else if (a != 0xFF) { + + a16 = __alpha16[a]; + Set ((r * a16) >> 16, (g * a16) >> 16, (b * a16) >> 16, a); + + } + + } + + + inline void UnmultiplyAlpha () { + + if (a != 0 && a != 0xFF) { + + unmult = 255.0 / a; + Set (__clamp[(int)(r * unmult)], __clamp[(int)(g * unmult)], __clamp[(int)(b * unmult)], a); + + } + + } + + + inline void ReadUInt8 (const unsigned char* data, int offset, PixelFormat format, bool premultiplied) { + + switch (format) { + + case BGRA32: + + Set (data[offset + 2], data[offset + 1], data[offset], data[offset + 3]); + break; + + case RGBA32: + + Set (data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); + break; + + case ARGB32: + + Set (data[offset + 1], data[offset + 2], data[offset + 3], data[offset]); + break; + + } + + if (premultiplied) { + + UnmultiplyAlpha (); + + } + + } + + + inline void Set (unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + + this->r = r; + this->g = g; + this->b = b; + this->a = a; + + } + + + inline void WriteUInt8 (unsigned char* data, int offset, PixelFormat format, bool premultiplied) { + + if (premultiplied) { + + MultiplyAlpha (); + + } + + switch (format) { + + case BGRA32: + + data[offset] = b; + data[offset + 1] = g; + data[offset + 2] = r; + data[offset + 3] = a; + break; + + case RGBA32: + + data[offset] = r; + data[offset + 1] = g; + data[offset + 2] = b; + data[offset + 3] = a; + break; + + case ARGB32: + + data[offset] = a; + data[offset + 1] = r; + data[offset + 2] = g; + data[offset + 3] = b; + break; + + } + + } + + + inline bool operator == (RGBA& rgba) { + + return (a == rgba.a && r == rgba.r && g == rgba.g && b == rgba.b); + + } + + + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + + + }; + + +} + + +#endif diff --git a/project/lib/curl b/project/lib/curl index b5b913c01..7084474ab 160000 --- a/project/lib/curl +++ b/project/lib/curl @@ -1 +1 @@ -Subproject commit b5b913c01427297d87da69d34ddbbc06a6591697 +Subproject commit 7084474ab4eb76efa3ba1dc6eb4e407ae07a72ba diff --git a/project/lib/png b/project/lib/png index 95d51b67a..601ea3ce9 160000 --- a/project/lib/png +++ b/project/lib/png @@ -1 +1 @@ -Subproject commit 95d51b67a1be7b8112b411f0d7f8f0cb70e68b58 +Subproject commit 601ea3ce9b4af315bed7f371348305b28b3a231c diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index c3441a02b..e401d4590 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -127,6 +127,23 @@ namespace lime { } + value lime_bytes_from_data_pointer (value data, value length) { + + int size = val_int (length); + intptr_t ptr = (intptr_t)val_float (data); + Bytes bytes = Bytes (size); + + if (ptr) { + + memcpy (bytes.Data (), (const void*)ptr, size); + + } + + return bytes.Value (); + + } + + value lime_bytes_get_data_pointer (value bytes) { Bytes data = Bytes (bytes); @@ -135,6 +152,14 @@ namespace lime { } + value lime_bytes_read_file (value path) { + + Bytes data = Bytes (val_os_string (path)); + return data.Value (); + + } + + void lime_font_destroy (value handle) { #ifdef LIME_FREETYPE @@ -508,32 +533,49 @@ namespace lime { } - value lime_image_data_util_copy_pixels (value image, value sourceImage, value sourceRect, value destPoint, value mergeAlpha) { + value lime_image_data_util_copy_pixels (value *arg, int nargs) { + + enum { image, sourceImage, sourceRect, destPoint, alphaImage, alphaPoint, mergeAlpha }; + + Image _image = Image (arg[image]); + Image _sourceImage = Image (arg[sourceImage]); + Rectangle _sourceRect = Rectangle (arg[sourceRect]); + Vector2 _destPoint = Vector2 (arg[destPoint]); + + if (val_is_null (arg[alphaImage])) { + + ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, 0, 0, val_bool (arg[mergeAlpha])); + + } else { + + Image _alphaImage = Image (arg[alphaImage]); + Vector2 _alphaPoint = Vector2 (arg[alphaPoint]); + + ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, &_alphaImage, &_alphaPoint, val_bool (arg[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) { + value lime_image_data_util_fill_rect (value image, value rect, value rg, value ba) { Image _image = Image (image); Rectangle _rect = Rectangle (rect); - ImageDataUtil::FillRect (&_image, &_rect, val_number (color)); + int32_t color = (val_int (rg) << 16) | val_int (ba); + ImageDataUtil::FillRect (&_image, &_rect, color); return alloc_null (); } - value lime_image_data_util_flood_fill (value image, value x, value y, value color) { + value lime_image_data_util_flood_fill (value image, value x, value y, value rg, value ba) { Image _image = Image (image); - ImageDataUtil::FloodFill (&_image, val_number (x), val_number (y), val_number (color)); + int32_t color = (val_int (rg) << 16) | val_int (ba); + ImageDataUtil::FloodFill (&_image, val_number (x), val_number (y), color); return alloc_null (); } @@ -843,6 +885,14 @@ namespace lime { } + value lime_renderer_get_type (value renderer) { + + Renderer* targetRenderer = (Renderer*)(intptr_t)val_float (renderer); + return alloc_string (targetRenderer->Type ()); + + } + + value lime_renderer_lock (value renderer) { return ((Renderer*)(intptr_t)val_float (renderer))->Lock (); @@ -1120,7 +1170,9 @@ namespace lime { DEFINE_PRIM (lime_application_set_frame_rate, 2); DEFINE_PRIM (lime_application_update, 1); DEFINE_PRIM (lime_audio_load, 1); + DEFINE_PRIM (lime_bytes_from_data_pointer, 2); DEFINE_PRIM (lime_bytes_get_data_pointer, 1); + DEFINE_PRIM (lime_bytes_read_file, 1); DEFINE_PRIM (lime_font_get_ascender, 1); DEFINE_PRIM (lime_font_get_descender, 1); DEFINE_PRIM (lime_font_get_family_name, 1); @@ -1143,9 +1195,9 @@ namespace lime { 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_flood_fill, 4); + DEFINE_PRIM_MULT (lime_image_data_util_copy_pixels); + DEFINE_PRIM (lime_image_data_util_fill_rect, 4); + DEFINE_PRIM (lime_image_data_util_flood_fill, 5); DEFINE_PRIM (lime_image_data_util_get_pixels, 4); DEFINE_PRIM_MULT (lime_image_data_util_merge); DEFINE_PRIM (lime_image_data_util_multiply_alpha, 1); @@ -1172,6 +1224,7 @@ namespace lime { DEFINE_PRIM (lime_png_decode_file, 2); DEFINE_PRIM (lime_renderer_create, 1); DEFINE_PRIM (lime_renderer_flip, 1); + DEFINE_PRIM (lime_renderer_get_type, 1); DEFINE_PRIM (lime_renderer_lock, 1); DEFINE_PRIM (lime_renderer_unlock, 1); DEFINE_PRIM (lime_render_event_manager_register, 2); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index 94a6216d3..cfbc9461b 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -15,7 +15,8 @@ namespace lime { AutoGCRoot* Application::callback = 0; SDLApplication* SDLApplication::currentApplication = 0; - + std::map > gamepadsAxisMap; + const int analogAxisDeadZone = 1000; SDLApplication::SDLApplication () { @@ -239,9 +240,36 @@ namespace lime { case SDL_CONTROLLERAXISMOTION: + if (gamepadsAxisMap[event->caxis.which].empty()) { + + gamepadsAxisMap[event->caxis.which][event->caxis.axis] = event->caxis.value; + + } + else if (gamepadsAxisMap[event->caxis.which][event->caxis.axis] == event->caxis.value) { + + break; + + } + gamepadEvent.type = AXIS_MOVE; gamepadEvent.axis = event->caxis.axis; gamepadEvent.id = event->caxis.which; + + if (event->caxis.value > -analogAxisDeadZone && event->caxis.value < analogAxisDeadZone) { + + if (gamepadsAxisMap[event->caxis.which][event->caxis.axis] != 0) { + + gamepadsAxisMap[event->caxis.which][event->caxis.axis] = 0; + gamepadEvent.axisValue = 0; + GamepadEvent::Dispatch (&gamepadEvent); + + } + + break; + + } + + gamepadsAxisMap[event->caxis.which][event->caxis.axis] = event->caxis.value; gamepadEvent.axisValue = event->caxis.value / 32768.0; GamepadEvent::Dispatch (&gamepadEvent); diff --git a/project/src/backend/sdl/SDLRenderer.cpp b/project/src/backend/sdl/SDLRenderer.cpp index 659f13f87..b70085b5a 100644 --- a/project/src/backend/sdl/SDLRenderer.cpp +++ b/project/src/backend/sdl/SDLRenderer.cpp @@ -31,6 +31,15 @@ namespace lime { sdlRenderer = SDL_CreateRenderer (sdlWindow, -1, sdlFlags); + if (!sdlRenderer && (sdlFlags & SDL_RENDERER_ACCELERATED)) { + + sdlFlags &= ~SDL_RENDERER_ACCELERATED; + sdlFlags |= SDL_RENDERER_SOFTWARE; + + sdlRenderer = SDL_CreateRenderer (sdlWindow, -1, sdlFlags); + + } + if (!sdlRenderer) { printf ("Could not create SDL renderer: %s.\n", SDL_GetError ()); @@ -95,6 +104,30 @@ namespace lime { } + const char* SDLRenderer::Type () { + + if (sdlRenderer) { + + SDL_RendererInfo info; + SDL_GetRendererInfo (sdlRenderer, &info); + + if (info.flags & SDL_RENDERER_SOFTWARE) { + + return "software"; + + } else { + + return "opengl"; + + } + + } + + return "none"; + + } + + void SDLRenderer::Unlock () { if (sdlTexture) { diff --git a/project/src/backend/sdl/SDLRenderer.h b/project/src/backend/sdl/SDLRenderer.h index cc45e818d..f2c1d6c02 100644 --- a/project/src/backend/sdl/SDLRenderer.h +++ b/project/src/backend/sdl/SDLRenderer.h @@ -18,6 +18,7 @@ namespace lime { virtual void Flip (); virtual value Lock (); + virtual const char* Type (); virtual void Unlock (); SDL_Renderer* sdlRenderer; diff --git a/project/src/graphics/Image.cpp b/project/src/graphics/Image.cpp index 3ad8692db..d7d3f318f 100644 --- a/project/src/graphics/Image.cpp +++ b/project/src/graphics/Image.cpp @@ -8,7 +8,6 @@ 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; @@ -19,7 +18,6 @@ namespace lime { height = 0; offsetX = 0; offsetY = 0; - transparent = true; width = 0; } @@ -33,7 +31,6 @@ 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; @@ -44,7 +41,6 @@ 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)); } diff --git a/project/src/graphics/ImageBuffer.cpp b/project/src/graphics/ImageBuffer.cpp index d6c669c4b..4129d06fa 100644 --- a/project/src/graphics/ImageBuffer.cpp +++ b/project/src/graphics/ImageBuffer.cpp @@ -9,8 +9,9 @@ namespace lime { static int id_data; static int id_format; static int id_height; - static int id_width; + static int id_premultiplied; static int id_transparent; + static int id_width; static bool init = false; @@ -19,8 +20,9 @@ namespace lime { width = 0; height = 0; bitsPerPixel = 32; - format = RGBA; + format = RGBA32; data = 0; + premultiplied = false; transparent = false; } @@ -37,6 +39,7 @@ namespace lime { id_height = val_id ("height"); id_data = val_id ("data"); id_format = val_id ("format"); + id_premultiplied = val_id ("premultiplied"); init = true; } @@ -48,6 +51,7 @@ namespace lime { transparent = val_bool (val_field (imageBuffer, id_transparent)); value data_value = val_field (imageBuffer, id_data); value buffer_value = val_field (data_value, id_buffer); + premultiplied = val_bool (val_field (imageBuffer, id_premultiplied)); data = new Bytes (buffer_value); } @@ -119,6 +123,7 @@ namespace lime { id_height = val_id ("height"); id_data = val_id ("data"); id_format = val_id ("format"); + id_premultiplied = val_id ("premultiplied"); init = true; } @@ -130,6 +135,7 @@ namespace lime { alloc_field (mValue, id_data, data ? data->Value () : alloc_null ()); alloc_field (mValue, id_transparent, alloc_bool (transparent)); alloc_field (mValue, id_format, alloc_int (format)); + alloc_field (mValue, id_premultiplied, alloc_bool (premultiplied)); return mValue; } diff --git a/project/src/graphics/cairo/CairoBindings.cpp b/project/src/graphics/cairo/CairoBindings.cpp index 09b2d63ef..ec3ac8a79 100644 --- a/project/src/graphics/cairo/CairoBindings.cpp +++ b/project/src/graphics/cairo/CairoBindings.cpp @@ -368,16 +368,37 @@ namespace lime { } + value lime_cairo_image_surface_get_data (value handle) { + + return alloc_float ((intptr_t)cairo_image_surface_get_data ((cairo_surface_t*)(intptr_t)val_float (handle))); + + } + + + value lime_cairo_image_surface_get_format (value handle) { + + return alloc_int ((int)cairo_image_surface_get_format ((cairo_surface_t*)(intptr_t)val_float (handle))); + + } + + value lime_cairo_image_surface_get_height (value handle) { - return alloc_int ((intptr_t)cairo_image_surface_get_height ((cairo_surface_t*)(intptr_t)val_float (handle))); + return alloc_int (cairo_image_surface_get_height ((cairo_surface_t*)(intptr_t)val_float (handle))); + + } + + + value lime_cairo_image_surface_get_stride (value handle) { + + return alloc_int (cairo_image_surface_get_stride ((cairo_surface_t*)(intptr_t)val_float (handle))); } value lime_cairo_image_surface_get_width (value handle) { - return alloc_int ((intptr_t)cairo_image_surface_get_width ((cairo_surface_t*)(intptr_t)val_float (handle))); + return alloc_int (cairo_image_surface_get_width ((cairo_surface_t*)(intptr_t)val_float (handle))); } @@ -993,7 +1014,10 @@ namespace lime { DEFINE_PRIM (lime_cairo_identity_matrix, 1); DEFINE_PRIM (lime_cairo_image_surface_create, 3); DEFINE_PRIM (lime_cairo_image_surface_create_for_data, 5); + DEFINE_PRIM (lime_cairo_image_surface_get_data, 1); + DEFINE_PRIM (lime_cairo_image_surface_get_format, 1); DEFINE_PRIM (lime_cairo_image_surface_get_height, 1); + DEFINE_PRIM (lime_cairo_image_surface_get_stride, 1); DEFINE_PRIM (lime_cairo_image_surface_get_width, 1); DEFINE_PRIM (lime_cairo_in_clip, 3); DEFINE_PRIM (lime_cairo_in_fill, 3); diff --git a/project/src/graphics/utils/ImageDataUtil.cpp b/project/src/graphics/utils/ImageDataUtil.cpp index 20bfd4307..7ea828f85 100644 --- a/project/src/graphics/utils/ImageDataUtil.cpp +++ b/project/src/graphics/utils/ImageDataUtil.cpp @@ -1,82 +1,45 @@ #include +#include #include #include +#include namespace lime { - static int __alpha16[0xFF + 1]; - static int __clamp[0xFF + 0xFF + 1]; - - int initValues () { - - for (int i = 0; i < 256; i++) { - - // Seem to need +1 to get the same results as Haxe in multiplyAlpha - __alpha16[i] = (i + 1) * ((1 << 16) / 0xFF); - - } - - for (int i = 0; i < 0xFF; i++) { - - __clamp[i] = i; - - } - - for (int i = 0xFF; i < (0xFF + 0xFF + 1); i++) { - - __clamp[i] = 0xFF; - - } - - return 0; - - } - - static int initValues_ = initValues (); - - void ImageDataUtil::ColorTransform (Image* image, Rectangle* rect, ColorMatrix* colorMatrix) { - int stride = image->buffer->Stride (); - 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); - + PixelFormat format = image->buffer->format; + bool premultiplied = image->buffer->premultiplied; uint8_t* data = (uint8_t*)image->buffer->data->Data (); - int r, g, b, a, ex = 0; - float alphaMultiplier = colorMatrix->GetAlphaMultiplier (); - float redMultiplier = colorMatrix->GetRedMultiplier (); - float greenMultiplier = colorMatrix->GetGreenMultiplier (); - float blueMultiplier = colorMatrix->GetBlueMultiplier (); - int alphaOffset = colorMatrix->GetAlphaOffset (); - int redOffset = colorMatrix->GetRedOffset (); - int greenOffset = colorMatrix->GetGreenOffset (); - int blueOffset = colorMatrix->GetBlueOffset (); + ImageDataView dataView = ImageDataView (image, rect); - for (int row = rowStart; row < rowEnd; row++) { + unsigned char alphaTable[256]; + unsigned char redTable[256]; + unsigned char greenTable[256]; + unsigned char blueTable[256]; + + colorMatrix->GetAlphaTable (alphaTable); + colorMatrix->GetRedTable (redTable); + colorMatrix->GetGreenTable (greenTable); + colorMatrix->GetBlueTable (blueTable); + + int row, offset; + RGBA pixel; + + for (int y = 0; y < dataView.height; y++) { - for (int column = columnStart; column < columnEnd; column++) { + row = dataView.Row (y); + + for (int x = 0; x < dataView.width; x++) { - offset = (row * stride) + (column * 4); + offset = row + (x * 4); - a = (data[offset + 3] * alphaMultiplier) + alphaOffset; - ex = a > 0xFF ? a - 0xFF : 0; - b = (data[offset + 2] * blueMultiplier) + blueOffset + ex; - ex = b > 0xFF ? b - 0xFF : 0; - g = (data[offset + 1] * greenMultiplier) + greenOffset + ex; - ex = g > 0xFF ? g - 0xFF : 0; - r = (data[offset] * redMultiplier) + redOffset + ex; - - data[offset] = r > 0xFF ? 0xFF : r; - data[offset + 1] = g > 0xFF ? 0xFF : g; - data[offset + 2] = b > 0xFF ? 0xFF : b; - data[offset + 3] = a > 0xFF ? 0xFF : a; + pixel.ReadUInt8 (data, offset, format, premultiplied); + pixel.Set (redTable[pixel.r], greenTable[pixel.g], blueTable[pixel.b], alphaTable[pixel.a]); + pixel.WriteUInt8 (data, offset, format, premultiplied); } @@ -87,36 +50,54 @@ namespace lime { void ImageDataUtil::CopyChannel (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int srcChannel, int destChannel) { - int srcStride = sourceImage->buffer->Stride (); - 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->Data (); - - int destStride = image->buffer->Stride (); - 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->Data (); - int length = sourceRect->width * sourceRect->height; + ImageDataView srcView = ImageDataView (sourceImage, sourceRect); + Rectangle destRect = Rectangle (destPoint->x, destPoint->y, srcView.width, srcView.height); + ImageDataView destView = ImageDataView (image, &destRect); - for (int i = 0; i < length; i++) { + PixelFormat srcFormat = sourceImage->buffer->format; + PixelFormat destFormat = image->buffer->format; + bool srcPremultiplied = sourceImage->buffer->premultiplied; + bool destPremultiplied = image->buffer->premultiplied; + + int srcPosition, destPosition; + RGBA srcPixel, destPixel; + unsigned char value = 0; + + for (int y = 0; y < destView.height; y++) { - destData[destPosition] = srcData[srcPosition]; + srcPosition = srcView.Row (y); + destPosition = destView.Row (y); - srcPosition += 4; - destPosition += 4; - - if ((srcPosition % srcStride) > srcRowEnd) { + for (int x = 0; x < destView.width; x++) { - srcPosition += srcRowOffset; + srcPixel.ReadUInt8 (srcData, srcPosition, srcFormat, srcPremultiplied); + destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied); - } - - if ((destPosition % destStride) > destRowEnd) { + switch (srcChannel) { + + case 0: value = srcPixel.r; break; + case 1: value = srcPixel.g; break; + case 2: value = srcPixel.b; break; + case 3: value = srcPixel.a; break; + + } - destPosition += destRowOffset; + switch (destChannel) { + + case 0: destPixel.r = value; break; + case 1: destPixel.g = value; break; + case 2: destPixel.b = value; break; + case 3: destPixel.a = value; break; + + } + + destPixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied); + + srcPosition += 4; + destPosition += 4; } @@ -125,35 +106,37 @@ namespace lime { } - 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); + void ImageDataUtil::CopyPixels (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, Image* alphaImage, Vector2* alphaPoint, bool mergeAlpha) { uint8_t* sourceData = (uint8_t*)sourceImage->buffer->data->Data (); - int sourceStride = sourceImage->buffer->Stride (); - int sourceOffset = 0; + uint8_t* destData = (uint8_t*)image->buffer->data->Data (); - uint8_t* data = (uint8_t*)image->buffer->data->Data (); - int stride = image->buffer->Stride (); - int offset = 0; + ImageDataView sourceView = ImageDataView (sourceImage, sourceRect); + Rectangle destRect = Rectangle (destPoint->x, destPoint->y, sourceView.width, sourceView.height); + ImageDataView destView = ImageDataView (image, &destRect); - int rows = sourceRect->y + sourceRect->height + sourceImage->offsetY; - int columns = sourceRect->x + sourceRect->width + sourceImage->offsetX; + PixelFormat sourceFormat = sourceImage->buffer->format; + PixelFormat destFormat = image->buffer->format; + bool sourcePremultiplied = sourceImage->buffer->premultiplied; + bool destPremultiplied = image->buffer->premultiplied; + + int sourcePosition, destPosition; + RGBA sourcePixel; if (!mergeAlpha || !sourceImage->buffer->transparent) { - for (int row = sourceRect->y + sourceImage->offsetY; row < rows; row++) { + for (int y = 0; y < destView.height; y++) { - for (int column = sourceRect->x + sourceImage->offsetX; column < columns; column++) { + sourcePosition = sourceView.Row (y); + destPosition = destView.Row (y); + + for (int x = 0; x < destView.width; x++) { - sourceOffset = (row * sourceStride) + (column * 4); - offset = ((row + rowOffset) * stride) + ((column + columnOffset) * 4); + sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); + sourcePixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied); - data[offset] = sourceData[sourceOffset]; - data[offset + 1] = sourceData[sourceOffset + 1]; - data[offset + 2] = sourceData[sourceOffset + 2]; - data[offset + 3] = sourceData[sourceOffset + 3]; + sourcePosition += 4; + destPosition += 4; } @@ -161,75 +144,95 @@ namespace lime { } else { - float sourceAlpha; - float destAlpha; - float outA; - float oneMinusSourceAlpha; + float sourceAlpha, destAlpha, oneMinusSourceAlpha, blendAlpha; + RGBA destPixel; - for (int row = sourceRect->y + sourceImage->offsetY; row < rows; row++) { + if (alphaImage == 0) { - for (int column = sourceRect->x + sourceImage->offsetX; column < columns; column++) { + for (int y = 0; y < destView.height; y++) { - sourceOffset = (row * sourceStride) + (column * 4); - offset = ((row + rowOffset) * stride) + ((column + columnOffset) * 4); + sourcePosition = sourceView.Row (y); + destPosition = destView.Row (y); - sourceAlpha = sourceData[sourceOffset + 3] / 255.0; - destAlpha = data[offset + 3] / 255.0; - oneMinusSourceAlpha = (1 - sourceAlpha); - - outA = sourceAlpha + destAlpha * oneMinusSourceAlpha; - data[offset + 0] = __clamp[int (0.5 + ((sourceData[sourceOffset + 0] * sourceAlpha + data[offset + 0] * destAlpha * oneMinusSourceAlpha) / outA))]; - data[offset + 1] = __clamp[int (0.5 + ((sourceData[sourceOffset + 1] * sourceAlpha + data[offset + 1] * destAlpha * oneMinusSourceAlpha) / outA))]; - data[offset + 2] = __clamp[int (0.5 + ((sourceData[sourceOffset + 2] * sourceAlpha + data[offset + 2] * destAlpha * oneMinusSourceAlpha) / outA))]; - data[offset + 3] = __clamp[int (0.5 + (outA * 255.0))]; + for (int x = 0; x < destView.width; x++) { + + sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); + destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied); + + sourceAlpha = sourcePixel.a / 255.0; + destAlpha = destPixel.a / 255.0; + oneMinusSourceAlpha = 1 - sourceAlpha; + blendAlpha = sourceAlpha + (destAlpha * oneMinusSourceAlpha); + + if (blendAlpha == 0) { + + destPixel.Set (0, 0, 0, 0); + + } else { + + destPixel.r = __clamp[int (0.5 + (sourcePixel.r * sourceAlpha + destPixel.r * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.g = __clamp[int (0.5 + (sourcePixel.g * sourceAlpha + destPixel.g * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.b = __clamp[int (0.5 + (sourcePixel.b * sourceAlpha + destPixel.b * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.a = __clamp[int (0.5 + blendAlpha * 255.0)]; + + } + + destPixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied); + + sourcePosition += 4; + destPosition += 4; + + } } - } - - } - - } - - - void ImageDataUtil::FillRect (Image* image, Rectangle* rect, int color) { - - int* data = (int*)image->buffer->data->Data (); - - 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; - - if (color == 0 || color == 0xFFFFFFFF || (color & 0xFF == (color >> 8) & 0xFF && (color >> 8) & 0xFF == (color >> 16) & 0xFF && (color >> 16) & 0xFF == (color >> 24) & 0xFF)) { - - memset ((uint8_t*)data, color & 0xFF, length * 4); - } else { - for (int i = 0; i < length; i++) { - - data[i] = color; - - } + uint8_t* alphaData = (uint8_t*)alphaImage->buffer->data->Data (); + PixelFormat alphaFormat = alphaImage->buffer->format; + bool alphaPremultiplied = alphaImage->buffer->premultiplied; - } - - } 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++) { + Rectangle alphaRect = Rectangle (alphaPoint->x, alphaPoint->y, destView.width, destView.height); + ImageDataView alphaView = ImageDataView (alphaImage, &alphaRect); + int alphaPosition; + RGBA alphaPixel; - for (int column = columnStart; column < columnEnd; column++) { + for (int y = 0; y < alphaView.height; y++) { - offset = (row * stride) + (column); - data[offset] = color; + sourcePosition = sourceView.Row (y); + destPosition = destView.Row (y); + alphaPosition = alphaView.Row (y); + + for (int x = 0; x < alphaView.width; x++) { + + sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); + destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied); + alphaPixel.ReadUInt8 (alphaData, alphaPosition, alphaFormat, alphaPremultiplied); + + sourceAlpha = alphaPixel.a / 0xFF; + destAlpha = destPixel.a / 0xFF; + oneMinusSourceAlpha = 1 - sourceAlpha; + blendAlpha = sourceAlpha + (destAlpha * oneMinusSourceAlpha); + + if (blendAlpha == 0) { + + destPixel.Set (0, 0, 0, 0); + + } else { + + destPixel.r = __clamp[int (0.5 + (sourcePixel.r * sourceAlpha + destPixel.r * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.g = __clamp[int (0.5 + (sourcePixel.g * sourceAlpha + destPixel.g * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.b = __clamp[int (0.5 + (sourcePixel.b * sourceAlpha + destPixel.b * destAlpha * oneMinusSourceAlpha) / blendAlpha)]; + destPixel.a = __clamp[int (0.5 + blendAlpha * 255.0)]; + + } + + destPixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied); + + sourcePosition += 4; + destPosition += 4; + + } } @@ -240,22 +243,50 @@ namespace lime { } - void ImageDataUtil::FloodFill (Image* image, int x, int y, int color) { + void ImageDataUtil::FillRect (Image* image, Rectangle* rect, int32_t color) { uint8_t* data = (uint8_t*)image->buffer->data->Data (); + PixelFormat format = image->buffer->format; + bool premultiplied = image->buffer->premultiplied; - int offset = (((y + image->offsetY) * (image->buffer->width * 4)) + ((x + image->offsetX) * 4)); - uint8_t hitColorR = data[offset + 0]; - uint8_t hitColorG = data[offset + 1]; - uint8_t hitColorB = data[offset + 2]; - uint8_t hitColorA = image->transparent ? data[offset + 3] : 0xFF; + ImageDataView dataView = ImageDataView (image, rect); + int row; + RGBA fillColor (color); - uint8_t r = (color >> 24) & 0xFF; - uint8_t g = (color >> 16) & 0xFF; - uint8_t b = (color >> 8) & 0xFF; - uint8_t a = image->transparent ? color & 0xFF : 0xFF; + for (int y = 0; y < dataView.height; y++) { + + row = dataView.Row (y); + + for (int x = 0; x < dataView.width; x++) { + + fillColor.WriteUInt8 (data, row + (x * 4), format, premultiplied); + + } + + } - if (hitColorR == r && hitColorG == g && hitColorB == b && hitColorA == a) return; + } + + + void ImageDataUtil::FloodFill (Image* image, int x, int y, int32_t color) { + + uint8_t* data = (uint8_t*)image->buffer->data->Data (); + PixelFormat format = image->buffer->format; + bool premultiplied = image->buffer->premultiplied; + + RGBA fillColor (color); + + RGBA hitColor; + hitColor.ReadUInt8 (data, ((y + image->offsetY) * (image->buffer->width * 4)) + ((x + image->offsetX) * 4), format, premultiplied); + + if (!image->buffer->transparent) { + + fillColor.a = 0xFF; + hitColor.a = 0xFF; + + } + + if (fillColor == hitColor) return; int dx[4] = { 0, -1, 1, 0 }; int dy[4] = { -1, 0, 0, 1 }; @@ -270,6 +301,7 @@ namespace lime { queue.push_back (y); int curPointX, curPointY, i, nextPointX, nextPointY, nextPointOffset; + RGBA readColor; while (queue.size () > 0) { @@ -288,13 +320,11 @@ namespace lime { } nextPointOffset = (nextPointY * image->width + nextPointX) * 4; + readColor.ReadUInt8 (data, nextPointOffset, format, premultiplied); - if (data[nextPointOffset + 0] == hitColorR && data[nextPointOffset + 1] == hitColorG && data[nextPointOffset + 2] == hitColorB && data[nextPointOffset + 3] == hitColorA) { + if (readColor == hitColor) { - data[nextPointOffset + 0] = r; - data[nextPointOffset + 1] = g; - data[nextPointOffset + 2] = b; - data[nextPointOffset + 3] = a; + fillColor.WriteUInt8 (data, nextPointOffset, format, premultiplied); queue.push_back (nextPointX); queue.push_back (nextPointY); @@ -313,52 +343,27 @@ namespace lime { int length = int (rect->width * rect->height); pixels->Resize (length * 4); - if (format == RGBA && rect->width == image->buffer->width && rect->height == image->buffer->height && rect->x == 0 && rect->y == 0) { - - memcpy (pixels->Data (), image->buffer->data->Data (), image->buffer->data->Length ()); - return; - - } + uint8_t* data = (uint8_t*)image->buffer->data->Data (); + uint8_t* destData = (uint8_t*)pixels->Data (); - uint8_t* data = (uint8_t*)pixels->Data (); - uint8_t* srcData = (uint8_t*)image->buffer->data->Data (); + PixelFormat sourceFormat = image->buffer->format; + bool premultiplied = image->buffer->premultiplied; - int srcStride = image->buffer->Stride (); - int srcPosition = int ((rect->x * 4) + (srcStride * rect->y)); - int srcRowOffset = srcStride - int (4 * rect->width); - int srcRowEnd = int (4 * (rect->x + rect->width)); + ImageDataView dataView = ImageDataView (image, rect); + int position, destPosition = 0; + RGBA pixel; - if (format == ARGB) { + for (int y = 0; y < dataView.height; y++) { - for (int i = 0; i < length; i++) { - - data[i * 4 + 1] = srcData[srcPosition++]; - data[i * 4 + 2] = srcData[srcPosition++]; - data[i * 4 + 3] = srcData[srcPosition++]; - data[i * 4] = srcData[srcPosition++]; - - if ((srcPosition % srcStride) > srcRowEnd) { - - srcPosition += srcRowOffset; - - } - - } + position = dataView.Row (y); - } else { - - for (int i = 0; i < length; i++) { + for (int x = 0; x < dataView.width; x++) { - data[i * 4] = srcData[srcPosition++]; - data[i * 4 + 1] = srcData[srcPosition++]; - data[i * 4 + 2] = srcData[srcPosition++]; - data[i * 4 + 3] = srcData[srcPosition++]; + pixel.ReadUInt8 (data, position, sourceFormat, premultiplied); + pixel.WriteUInt8 (destData, destPosition, format, false); - if ((srcPosition % srcStride) > srcRowEnd) { - - srcPosition += srcRowOffset; - - } + position += 4; + destPosition += 4; } @@ -369,31 +374,39 @@ namespace lime { void ImageDataUtil::Merge (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int redMultiplier, int greenMultiplier, int blueMultiplier, int alphaMultiplier) { - int rowOffset = int (destPoint->y + image->offsetY - sourceRect->y - sourceImage->offsetY); - int columnOffset = int (destPoint->x + image->offsetX - sourceRect->x - sourceImage->offsetY); + ImageDataView sourceView = ImageDataView (sourceImage, sourceRect); + Rectangle destRect = Rectangle (destPoint->x, destPoint->y, sourceView.width, sourceView.height); + ImageDataView destView = ImageDataView (image, &destRect); uint8_t* sourceData = (uint8_t*)sourceImage->buffer->data->Data (); - int sourceStride = sourceImage->buffer->Stride (); - int sourceOffset = 0; + uint8_t* destData = (uint8_t*)image->buffer->data->Data (); + PixelFormat sourceFormat = sourceImage->buffer->format; + PixelFormat destFormat = image->buffer->format; + bool sourcePremultiplied = sourceImage->buffer->premultiplied; + bool destPremultiplied = image->buffer->premultiplied; - uint8_t* data = (uint8_t*)image->buffer->data->Data (); - int stride = image->buffer->Stride (); - int offset = 0; + int sourcePosition, destPosition; + RGBA sourcePixel, destPixel; - int rowEnd = int (sourceRect->y + sourceRect->height + sourceImage->offsetY); - int columnEnd = int (sourceRect->x + sourceRect->width + sourceImage->offsetX); - - for (int row = int (sourceRect->y + sourceImage->offsetY); row < rowEnd; row++) { + for (int y = 0; y < destView.height; y++) { - for (int column = int (sourceRect->x + sourceImage->offsetX); column < columnEnd; column++) { + sourcePosition = sourceView.Row (y); + destPosition = destView.Row (y); + + for (int x = 0; x < destView.width; x++) { - sourceOffset = (row * sourceStride) + (column * 4); - offset = ((row + rowOffset) * stride) + ((column + columnOffset) * 4); + sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); + destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied); - data[offset] = int (((sourceData[offset] * redMultiplier) + (data[offset] * (256 - redMultiplier))) / 256); - data[offset + 1] = int (((sourceData[offset + 1] * greenMultiplier) + (data[offset + 1] * (256 - greenMultiplier))) / 256); - data[offset + 2] = int (((sourceData[offset + 2] * blueMultiplier) + (data[offset + 2] * (256 - blueMultiplier))) / 256); - data[offset + 3] = int (((sourceData[offset + 3] * alphaMultiplier) + (data[offset + 3] * (256 - alphaMultiplier))) / 256); + destPixel.r = int (((sourcePixel.r * redMultiplier) + (destPixel.r * (256 - redMultiplier))) / 256); + destPixel.g = int (((sourcePixel.g * greenMultiplier) + (destPixel.g * (256 - greenMultiplier))) / 256); + destPixel.b = int (((sourcePixel.b * blueMultiplier) + (destPixel.b * (256 - blueMultiplier))) / 256); + destPixel.a = int (((sourcePixel.a * alphaMultiplier) + (destPixel.a * (256 - alphaMultiplier))) / 256); + + destPixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied); + + sourcePosition += 4; + destPosition += 4; } @@ -404,17 +417,15 @@ namespace lime { void ImageDataUtil::MultiplyAlpha (Image* image) { - int a16 = 0; - int length = image->buffer->data->Length () / 4; + PixelFormat format = image->buffer->format; uint8_t* data = (uint8_t*)image->buffer->data->Data (); + int length = int (image->buffer->data->Length () / 4); + RGBA pixel; for (int i = 0; i < length; i++) { - a16 = __alpha16[data[3]]; - data[0] = (data[0] * a16) >> 16; - data[1] = (data[1] * a16) >> 16; - data[2] = (data[2] * a16) >> 16; - data += 4; + pixel.ReadUInt8 (data, i * 4, format, false); + pixel.WriteUInt8 (data, i * 4, format, true); } @@ -487,7 +498,7 @@ namespace lime { switch (image->buffer->format) { - case RGBA: + case RGBA32: r1 = 0; g1 = 1; @@ -495,7 +506,7 @@ namespace lime { a1 = 3; break; - case ARGB: + case ARGB32: r1 = 1; g1 = 2; @@ -503,7 +514,7 @@ namespace lime { a1 = 0; break; - case BGRA: + case BGRA32: r1 = 2; g1 = 1; @@ -515,7 +526,7 @@ namespace lime { switch (format) { - case RGBA: + case RGBA32: r2 = 0; g2 = 1; @@ -523,7 +534,7 @@ namespace lime { a2 = 3; break; - case ARGB: + case ARGB32: r2 = 1; g2 = 2; @@ -531,7 +542,7 @@ namespace lime { a2 = 0; break; - case BGRA: + case BGRA32: r2 = 2; g2 = 1; @@ -564,61 +575,29 @@ namespace lime { void ImageDataUtil::SetPixels (Image* image, Rectangle* rect, Bytes* bytes, PixelFormat format) { - if (format == RGBA && rect->width == image->buffer->width && rect->height == image->buffer->height && rect->x == 0 && rect->y == 0) { - - memcpy (image->buffer->data->Data (), bytes->Data (), bytes->Length ()); - return; - - } + uint8_t* data = (uint8_t*)image->buffer->data->Data (); + PixelFormat sourceFormat = image->buffer->format; + bool premultiplied = image->buffer->premultiplied; + ImageDataView dataView = ImageDataView (image, rect); + int row; + RGBA pixel; - int offset = int (image->buffer->width * (rect->y + image->offsetX) + (rect->x + image->offsetY)); - int boundR = int ((rect->x + rect->width + image->offsetX)); - int width = image->buffer->width; - int color; + uint8_t* byteArray = (uint8_t*)bytes->Data (); + int srcPosition = 0; - if (format == ARGB) { + bool transparent = image->buffer->transparent; + + for (int y = 0; y < dataView.height; y++) { - int pos = offset * 4; - int len = int (rect->width * rect->height * 4); - uint8_t* data = (uint8_t*)image->buffer->data->Data (); - uint8_t* byteArray = (uint8_t*)bytes->Data (); + row = dataView.Row (y); - for (int i = 0; i < len; i += 4) { + for (int x = 0; x < dataView.width; x++) { + pixel.ReadUInt8 (byteArray, srcPosition, format, false); + if (!transparent) pixel.a = 0xFF; + pixel.WriteUInt8 (data, row + (x * 4), sourceFormat, premultiplied); - if (((pos) % (width * 4)) >= boundR * 4) { - - pos += (width - boundR) * 4; - - } - - data[pos] = byteArray[i + 1]; - data[pos + 1] = byteArray[i + 2]; - data[pos + 2] = byteArray[i + 3]; - data[pos + 3] = byteArray[i]; - pos += 4; - - } - - } else { - - int pos = offset; - int len = int (rect->width * rect->height); - int* data = (int*)image->buffer->data->Data (); - int* byteArray = (int*)bytes->Data (); - - // TODO: memcpy rows at once - - for (int i = 0; i < len; i++) { - - if (((pos) % (width)) >= boundR) { - - pos += (width - boundR); - - } - - data[pos] = byteArray[i]; - pos++; + srcPosition += 4; } @@ -629,28 +608,64 @@ namespace lime { void ImageDataUtil::UnmultiplyAlpha (Image* image) { - int length = image->buffer->data->Length () / 4; + PixelFormat format = image->buffer->format; uint8_t* data = (uint8_t*)image->buffer->data->Data (); - - int unmultiply; - uint8_t a; + int length = int (image->buffer->data->Length () / 4); + RGBA pixel; for (int i = 0; i < length; i++) { - a = data[3]; - - if (a != 0) { - - unmultiply = 255.0 / a; - data[0] = __clamp[data[0] * unmultiply]; - data[1] = __clamp[data[1] * unmultiply]; - data[2] = __clamp[data[2] * unmultiply]; - - } + pixel.ReadUInt8 (data, i * 4, format, true); + pixel.WriteUInt8 (data, i * 4, format, false); } } + ImageDataView::ImageDataView (Image* image, Rectangle* rect) { + + this->image = image; + + if (rect->x < 0) rect->x = 0; + if (rect->y < 0) rect->y = 0; + if (rect->x + rect->width > image->width) rect->width = image->width - rect->x; + if (rect->y + rect->height > image->height) rect->height = image->height - rect->y; + if (rect->width < 0) rect->width = 0; + if (rect->height < 0) rect->height = 0; + this->rect = rect; + + stride = image->buffer->Stride (); + + x = ceil (this->rect->x); + y = ceil (this->rect->y); + width = floor (this->rect->width); + height = floor (this->rect->height); + offset = (stride * (this->y + image->offsetY)) + ((this->x + image->offsetX) * 4); + + + } + + + void ImageDataView::Clip (int x, int y, int width, int height) { + + rect->Contract (x, y, width, height); + + this->x = ceil (rect->x); + this->y = ceil (rect->y); + this->width = floor (rect->width); + this->height = floor (rect->height); + offset = (stride * (this->y + image->offsetY)) + ((this->x + image->offsetX) * 4); + + + } + + + inline int ImageDataView::Row (int y) { + + return offset + stride * y; + + } + + } \ No newline at end of file diff --git a/project/src/math/ColorMatrix.cpp b/project/src/math/ColorMatrix.cpp index 34263b3ae..57f5a1531 100644 --- a/project/src/math/ColorMatrix.cpp +++ b/project/src/math/ColorMatrix.cpp @@ -57,67 +57,111 @@ namespace lime { } - float ColorMatrix::GetAlphaMultiplier () { + float inline ColorMatrix::GetAlphaMultiplier () { return data[18]; } - float ColorMatrix::GetAlphaOffset () { + float inline ColorMatrix::GetAlphaOffset () { return data[19] * 255; } - float ColorMatrix::GetBlueMultiplier () { + void ColorMatrix::GetAlphaTable (unsigned char* table) { + + GetDataTable (table, GetAlphaMultiplier (), GetAlphaOffset ()); + + } + + + float inline ColorMatrix::GetBlueMultiplier () { return data[12]; } - float ColorMatrix::GetBlueOffset () { + float inline ColorMatrix::GetBlueOffset () { return data[14] * 255; } - int ColorMatrix::GetColor () { + void ColorMatrix::GetBlueTable (unsigned char* table) { + + GetDataTable (table, GetBlueMultiplier (), GetBlueOffset ()); + + } + + + int32_t inline ColorMatrix::GetColor () { return ((int (GetRedOffset ()) << 16) | (int (GetGreenOffset ()) << 8) | int (GetBlueOffset ())); } - float ColorMatrix::GetGreenMultiplier () { + void inline ColorMatrix::GetDataTable (unsigned char* table, float multiplier, float offset) { + + int32_t value; + + for (int i = 0; i < 256; i++) { + + value = (int)(i * multiplier + offset); + if (value > 0xFF) value = 0xFF; + if (value < 0) value = 0; + table[i] = value; + + } + + } + + + float inline ColorMatrix::GetGreenMultiplier () { return data[6]; } - float ColorMatrix::GetGreenOffset () { + float inline ColorMatrix::GetGreenOffset () { return data[9] * 255; } - float ColorMatrix::GetRedMultiplier () { + void ColorMatrix::GetGreenTable (unsigned char* table) { + + GetDataTable (table, GetGreenMultiplier (), GetGreenOffset ()); + + } + + + float inline ColorMatrix::GetRedMultiplier () { return data[0]; } - float ColorMatrix::GetRedOffset () { + float inline ColorMatrix::GetRedOffset () { return data[4] * 255; } + void ColorMatrix::GetRedTable (unsigned char* table) { + + GetDataTable (table, GetRedMultiplier (), GetRedOffset ()); + + } + + } \ No newline at end of file diff --git a/project/src/math/Rectangle.cpp b/project/src/math/Rectangle.cpp index dcdc0c5bf..0ce21c467 100644 --- a/project/src/math/Rectangle.cpp +++ b/project/src/math/Rectangle.cpp @@ -51,4 +51,23 @@ namespace lime { } + void Rectangle::Contract (double x, double y, double width, double height) { + + if (this->width == 0 && this->height == 0) { + + return; + + } + + //double cacheRight = this->x + this->width; + //double cacheBottom = this->y + this->height; + + if (this->x < x) this->x = x; + if (this->y < y) this->y = y; + if (this->x + this->width > x + width) this->width = x + width - this->x; + if (this->y + this->height > y + height) this->height = y + height - this->y; + + } + + } \ No newline at end of file diff --git a/templates/project/Assets/lime.svg b/templates/default/icon.svg similarity index 98% rename from templates/project/Assets/lime.svg rename to templates/default/icon.svg index 0e20a1c77..98fa1766c 100644 --- a/templates/project/Assets/lime.svg +++ b/templates/default/icon.svg @@ -1,54 +1,54 @@ - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/haxe/DefaultAssetLibrary.hx b/templates/haxe/DefaultAssetLibrary.hx index a0ff0a1ae..dae62895f 100644 --- a/templates/haxe/DefaultAssetLibrary.hx +++ b/templates/haxe/DefaultAssetLibrary.hx @@ -8,7 +8,7 @@ import lime.audio.AudioSource; import lime.audio.openal.AL; import lime.audio.AudioBuffer; import lime.graphics.Image; -import lime.system.BackgroundWorker; +import lime.system.ThreadPool; import lime.text.Font; import lime.utils.ByteArray; import lime.utils.UInt8Array; @@ -40,6 +40,7 @@ class DefaultAssetLibrary extends AssetLibrary { public var type (default, null) = new Map (); private var lastModified:Float; + private var threadPool:ThreadPool; private var timer:Timer; @@ -132,6 +133,24 @@ class DefaultAssetLibrary extends AssetLibrary { } + private function createThreadPool ():Void { + + threadPool = new ThreadPool (0, 2); + threadPool.doWork.add (function (id, data) { + + data.result = data.getMethod (id); + threadPool.sendComplete (data.handler, data); + + }); + threadPool.onComplete.add (function (id, data) { + + data.handler (data.result); + + }); + + } + + public override function exists (id:String, type:String):Bool { var requestedType = type != null ? cast (type, AssetType) : null; @@ -548,16 +567,13 @@ class DefaultAssetLibrary extends AssetLibrary { #else - var worker = new BackgroundWorker (); - - worker.doWork.add (function (_) { + if (threadPool == null) { - worker.sendComplete (getBytes (id)); + createThreadPool (); - }); + } - worker.onComplete.add (handler); - worker.run (); + threadPool.queue (id, { handler: handler, getMethod: getBytes }); #end @@ -595,7 +611,7 @@ class DefaultAssetLibrary extends AssetLibrary { handler (Image.fromImageElement (image)); } - image.src = id; + image.src = path.get (id); } else { @@ -605,16 +621,13 @@ class DefaultAssetLibrary extends AssetLibrary { #else - var worker = new BackgroundWorker (); - - worker.doWork.add (function (_) { + if (threadPool == null) { - worker.sendComplete (getImage (id)); + createThreadPool (); - }); + } - worker.onComplete.add (handler); - worker.run (); + threadPool.queue (id, { handler: handler, getMethod: getImage }); #end diff --git a/templates/project/Assets/.gitignore b/templates/project/Assets/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/templates/project/project.xml b/templates/project/project.xml index 9f63eddf0..d65fddc13 100644 --- a/templates/project/project.xml +++ b/templates/project/project.xml @@ -8,7 +8,6 @@ - - + \ No newline at end of file diff --git a/tools/CommandLineTools.hx b/tools/CommandLineTools.hx index 05a36ee09..e436e62b1 100644 --- a/tools/CommandLineTools.hx +++ b/tools/CommandLineTools.hx @@ -1271,7 +1271,7 @@ class CommandLineTools { } - if (project == null) { + if (project == null || (command != "rebuild" && project.sources.length == 0)) { LogHelper.error ("You must have a \"project.xml\" file or specify another valid project file when using the '" + command + "' command"); return null; diff --git a/tools/utils/PlatformSetup.hx b/tools/utils/PlatformSetup.hx index 578017de6..335647dd8 100644 --- a/tools/utils/PlatformSetup.hx +++ b/tools/utils/PlatformSetup.hx @@ -2126,6 +2126,18 @@ class PlatformSetup { LogHelper.info ("\x1b[32;1mUpdating \"" + haxelib.name + "\"\x1b[0m"); + if (PlatformHelper.hostPlatform == Platform.WINDOWS) { + + var path = Sys.getEnv ("PATH"); + + if (path.indexOf ("Git") == -1) { + + Sys.putEnv ("PATH", "C:\\Program Files (x86)\\Git\\bin;" + path); + + } + + } + ProcessHelper.runCommand (lib, "git", [ "pull" ]); ProcessHelper.runCommand (lib, "git", [ "submodule", "init" ]); ProcessHelper.runCommand (lib, "git", [ "submodule", "update" ]);