diff --git a/src/openfl/display/BitmapData.hx b/src/openfl/display/BitmapData.hx index a6dcb8d66f..cdc8b2b339 100644 --- a/src/openfl/display/BitmapData.hx +++ b/src/openfl/display/BitmapData.hx @@ -10,6 +10,7 @@ import openfl.display3D.Context3DClearMask; import openfl.display3D.Context3D; import openfl.display3D.IndexBuffer3D; import openfl.display3D.VertexBuffer3D; +import openfl.display.Graphics; import openfl.errors.Error; import openfl.filters.BitmapFilter; import openfl.geom.ColorTransform; @@ -123,7 +124,6 @@ import openfl.display._internal.stats.DrawCallContext; @:access(openfl.display3D.textures.TextureBase) @:access(openfl.display3D.Context3D) @:access(openfl.display.DisplayObject) -@:access(openfl.display.DisplayObjectShader) @:access(openfl.display.Graphics) @:access(openfl.display.Shader) @:access(openfl.filters.BitmapFilter) @@ -141,6 +141,9 @@ class BitmapData implements IBitmapDrawable #if lime @:noCompletion private static var __tempVector:Vector2 = new Vector2(); @:noCompletion private static var __fillRectRectangle:Rectangle = new Rectangle(); + #if (cpp && lime_cffi && !macro && sys) + @:noCompletion private static var __imageAssetCache:Image = new Image(new ImageBuffer(new UInt8Array(haxe.io.Bytes.alloc(0)))); + #end #end /** @@ -217,7 +220,7 @@ class BitmapData implements IBitmapDrawable @:noCompletion private var __textureHeight:Int; @:noCompletion private var __textureVersion:Int; @:noCompletion private var __textureWidth:Int; - @:noCompletion private var __textureShared:Bool = true; + @:noCompletion private var __textureShared:Bool; @:noCompletion private var __transform:Matrix; @:noCompletion private var __uvRect:Rectangle; @:noCompletion private var __vertexBuffer:VertexBuffer3D; @@ -1270,21 +1273,24 @@ class BitmapData implements IBitmapDrawable format, such as PNG or JPG. To use raw ARGB pixel data, call `setPixels` or `setVector` instead. + When creating BitmapData asynchronously with this method with true in `hardware` + parameter, it will always return `null`. + HTML5 and Flash do not support creating BitmapData synchronously, so these targets always return `null`. Other targets will return `null` if decoding was unsuccessful. @param base64 Base64-encoded data @param type The MIME-type for the encoded data ("image/jpeg", etc) + @param hardware Should it be a hardware-only BItmapData object. @returns A new BitmapData if successful, or `null` if unsuccessful **/ - public static function fromBase64(base64:String, type:String):BitmapData + public static function fromBase64(base64:String, type:String, hardware:Bool = false):BitmapData { #if (js && html5) return null; #else var bitmapData = new BitmapData(0, 0, true, 0); - bitmapData.__fromBase64(base64, type); - return bitmapData; + return bitmapData.__fromBase64(base64, type, hardware) ? bitmapData : null; #end } #end @@ -1297,6 +1303,9 @@ class BitmapData implements IBitmapDrawable supported bitmap file format, such as PNG or JPG. To use raw ARGB pixel data, call `setPixels` or `setVector` instead. + When creating BitmapData asynchronously with this method with true in `hardware` + parameter, it will always return `null`. + HTML5 and Flash do not support creating BitmapData synchronously, so these targets always return `null`. Other targets will return `null` if decoding was unsuccessful. @@ -1305,16 +1314,16 @@ class BitmapData implements IBitmapDrawable @param bytes A haxe.io.Bytes or openfl.utils.ByteArray instance @param rawAlpha An optional byte array with alpha data + @param hardware Should it be a hardware-only BItmapData object. @returns A new BitmapData if successful, or `null` if unsuccessful **/ - public static function fromBytes(bytes:ByteArray, rawAlpha:ByteArray = null):BitmapData + public static function fromBytes(bytes:ByteArray, rawAlpha:ByteArray = null, hardware:Bool = false):BitmapData { #if (js && html5) return null; #else var bitmapData = new BitmapData(0, 0, true, 0); - bitmapData.__fromBytes(bytes, rawAlpha); - return bitmapData; + return bitmapData.__fromBytes(bytes, rawAlpha, hardware) ? bitmapData : null; #end } #end @@ -1346,23 +1355,26 @@ class BitmapData implements IBitmapDrawable Creates a new BitmapData from a file path synchronously. This means that the BitmapData will be returned immediately (if supported). + When creating BitmapData asynchronously with this method with true in `hardware` + parameter, it will always return `null`. + HTML5 and Flash do not support creating BitmapData synchronously, so these targets always return `null`. In order to load files from a remote web address, use the `loadFromFile` method, which supports asynchronous loading. - @param path A local file path containing an image + @param path A local file path containing an image + @param hardware Should it be a hardware-only BItmapData object. @returns A new BitmapData if successful, or `null` if unsuccessful **/ - public static function fromFile(path:String):BitmapData + public static function fromFile(path:String, hardware:Bool = false):BitmapData { #if (js && html5) return null; #else var bitmapData = new BitmapData(0, 0, true, 0); - bitmapData.__fromFile(path); - return bitmapData.image != null ? bitmapData : null; + return bitmapData.__fromFile(path, hardware) ? bitmapData : null; #end } #end @@ -1407,13 +1419,49 @@ class BitmapData implements IBitmapDrawable { if (texture == null) return null; - var bitmapData = new BitmapData(texture.__width, texture.__height, true, 0); - bitmapData.readable = false; + var bitmapData = new BitmapData(0, 0, true, 0); bitmapData.__texture = texture; bitmapData.__textureContext = texture.__textureContext; bitmapData.__textureShared = shared; - bitmapData.__surface = null; - bitmapData.image = null; + bitmapData.__resize(texture.__width, texture.__height); + bitmapData.__isValid = true; + return bitmapData; + } + + /** + **BETA** + + Creates a new hardware-only BitmapData instance from a Stage3D context. + Only purpose is to be only rendered and not be readable. + + This method is not supported by the Flash target. + + @param context A Stage3D context + @param width The width of the bitmap image in pixels. + @param height The height of the bitmap image in pixels. + @param fillColor A 32-bit ARGB color value that you use to fill + the bitmap image area. The default value is + 0x00000000 (full transparency). + @returns A new BitmapData if successful, or `null` if unsuccessful + + @see `BitmapData.readable` + @since FunkinCrew's OpenFL + **/ + public static function fromContext(context:Context3D, width:Int, height:Int, fillColor:UInt = 0):BitmapData + { + if (context == null || context.gl == null) return null; + + if (width > Graphics.maxTextureWidth) width = Graphics.maxTextureWidth; + if (height > Graphics.maxTextureHeight) height = Graphics.maxTextureHeight; + + var bitmapData = new BitmapData(0, 0, true, 0); + bitmapData.__texture = context.createRectangleTexture(width, height, BGRA, false); + bitmapData.__textureContext = bitmapData.__texture.__textureContext; + bitmapData.__resize(bitmapData.__texture.__width, bitmapData.__texture.__height); + bitmapData.__texture.__getGLFramebuffer(true, 0, 0); + bitmapData.__isValid = true; + bitmapData.__fillRect(bitmapData.rect, fillColor, true); + bitmapData.readable = false; return bitmapData; } @@ -2245,13 +2293,7 @@ class BitmapData implements IBitmapDrawable @:dox(hide) public function getSurface():#if lime CairoImageSurface #else Dynamic #end { #if lime - if (!readable) return null; - - if (__surface == null) - { - __surface = CairoImageSurface.fromImage(image); - } - + if (__surface == null && image != null) __surface = CairoImageSurface.fromImage(image); return __surface; #else return null; @@ -2326,7 +2368,7 @@ class BitmapData implements IBitmapDrawable __textureHeight = textureImage.buffer.height; } - if (!readable && image != null) + if (!readable && (image != null || __surface != null)) { __surface = null; image = null; @@ -3134,6 +3176,176 @@ class BitmapData implements IBitmapDrawable **/ public function unlock(changeRect:Rectangle = null):Void {} + /** + **BETA** + + Resize this BitmapData object to a desired width and height. This will stretch this + BitmapData object to the new dimension. + + @param width The width of the bitmap image in pixels. + @param height The height of the bitmap image in pixels. + + @since FunkinCrew's OpenFL + **/ + public function resize(width:Int, height:Int):Void + { + if (this.width != width || this.height != height) + { + __resize(width, height); + + if (__surface != null) __surface.flush(); + if (image != null) image.resize(width, height); + + if (__texture != null) + { + __texture.resize(width, height); + + __framebufferContext = __textureContext; + __indexBufferContext = __textureContext; + __framebuffer = __texture.__glFramebuffer; + __stencilBuffer = __texture.__glStencilRenderbuffer; + __vertexBuffer = null; + + getVertexBuffer(__texture.__context); + } + } + } + + /** + **BETA** + + Convert this BitmapData object to be hardware-only, that is only accessible for + graphics to render and making it unreadable. + + This method is not supported by the Flash target. + + @param context Optional; A Context3D instance + + @since FunkinCrew's OpenFL + **/ + public function toHardware(?context:Context3D):Void + { + if (image != null) + { + if (context == null) + { + if (Lib.current.stage == null || Lib.current.stage.context3D == null) return; + context = Lib.current.stage.context3D; + } + + if (__texture == null || __textureContext != context.__context) + { + __textureContext = context.__context; + __texture = context.createRectangleTexture(width, height, BGRA, false); + } + + #if (js && html5) + ImageCanvasUtil.sync(image, false); + #end + + if (__surface != null) __surface.flush(); + + #if (js && html5) + if (#if openfl_power_of_two true || #end (!TextureBase.__supportsBGRA && image.format != RGBA32)) + { + image.format = RGBA32; + // image.buffer.premultiplied = true; + #if openfl_power_of_two + image.powerOfTwo = true; + #end + } + #else + if (#if openfl_power_of_two !image.powerOfTwo || #end (!image.premultiplied && image.transparent)) + { + image.premultiplied = true; + #if openfl_power_of_two + image.powerOfTwo = true; + #end + } + #end + + __texture.__uploadFromImage(image); + __textureVersion = image.version; + __textureWidth = image.buffer.width; + __textureHeight = image.buffer.height; + __surface = null; + + readable = false; + image = null; + } + } + + /** + **BETA** + + Convert this BitmapData object from hardware-only to be be readable and modifiable. + + This method is not supported by the Flash target. + + @since FunkinCrew's OpenFL + **/ + public function toReadable():Void + { + if (__texture == null || __texture.__glFramebuffer == null) return; + + var context = __texture.__context; + if (context == null) return; + + var gl = context.gl; + if (gl == null) return; + + readable = true; + __textureContext = __texture.__textureContext; + __resize(__texture.__width, __texture.__height); + + var buffer:ImageBuffer = image.buffer; + if (buffer == null || buffer.width != width || buffer.height != height || buffer.bitsPerPixel != 32) + { + buffer = new ImageBuffer(new UInt8Array(width * height * 4), width, height, 32); + #if (js && html5) + Reflect.setField(buffer, "format", lime.graphics.PixelFormat.RGBA32); + #elseif sys + Reflect.setField(buffer, "format", lime.graphics.PixelFormat.BGRA32); + Reflect.setField(buffer, "premultiplied", true); + #end + } + + if (image == null) + { + image = new Image(buffer, 0, 0, width, height); + } + else + { + image.offsetX = 0; + image.offsetY = 0; + image.width = width; + image.height = height; + image.type = DATA; + image.buffer = buffer; + image.version = __textureVersion; + } + + var cacheRTT = context.__state.renderToTexture; + var cacheRTTDepthStencil = context.__state.renderToTextureDepthStencil; + var cacheRTTAntiAlias = context.__state.renderToTextureAntiAlias; + var cacheRTTSurfaceSelector = context.__state.renderToTextureSurfaceSelector; + + context.setRenderToTexture(__texture); + context.__flushGLFramebuffer(); + context.__flushGLViewport(); + + gl.readPixels(0, 0, width, height, __texture.__format, gl.UNSIGNED_BYTE, buffer.data); + + if (cacheRTT != null) + { + context.setRenderToTexture(cacheRTT, cacheRTTDepthStencil, cacheRTTAntiAlias, cacheRTTSurfaceSelector); + } + else + { + context.setRenderToBackBuffer(); + } + } + @:noCompletion private function __applyAlpha(alpha:ByteArray):Void { #if (js && html5) @@ -3284,35 +3496,113 @@ class BitmapData implements IBitmapDrawable #end } - @:noCompletion private inline function __fromBase64(base64:String, type:String):Void + @:noCompletion private inline function __fromBase64(base64:String, type:String, hardware:Bool = false):Bool { #if lime - var image = Image.fromBase64(base64, type); - __fromImage(image); + return __fromBytes(lime._internal.format.Base64.decode(base64), null, hardware); + #else + return false; #end } - @:noCompletion private inline function __fromBytes(bytes:ByteArray, rawAlpha:ByteArray = null):Void + @:noCompletion private function __fromBytes(bytes:ByteArray, rawAlpha:ByteArray = null, hardware:Bool = false):Bool + @:privateAccess { #if lime - var image = Image.fromBytes(bytes); - __fromImage(image); - if (rawAlpha != null) + #if (cpp && lime_cffi && !macro && sys) + if (hardware && Lib.current.stage != null && Lib.current.stage.context3D != null) { - __applyAlpha(rawAlpha); + if (lime._internal.backend.native.NativeCFFI.lime_image_load_bytes(bytes, __imageAssetCache.buffer) != null) + { + var data = __imageAssetCache.buffer.data; + for (i in 0...rawAlpha.length) data[i * 4 + 3] = rawAlpha.readUnsignedByte(); + __fromImageAssetCache(Lib.current.stage.context3D); + return true; + } + + return false; + } + else + { + __fromImage(Image.fromBytes(bytes)); + if (image == null) return false; + else if (rawAlpha != null) __applyAlpha(rawAlpha); + + return true; } + #else + __fromImage(Image.fromBytes(bytes)); + if (image == null) return false; + else if (rawAlpha != null) __applyAlpha(rawAlpha); + + if (hardware) toHardware(); + return true; + #end + + #else + return false; #end } - @:noCompletion private function __fromFile(path:String):Void + @:noCompletion private function __fromFile(path:String, hardware:Bool = false):Bool + @:privateAccess { #if lime - var image = Image.fromFile(path); - __fromImage(image); + + #if (cpp && lime_cffi && !macro && sys) + if (hardware && Lib.current.stage != null && Lib.current.stage.context3D != null) + { + if (lime._internal.backend.native.NativeCFFI.lime_image_load_file(path, __imageAssetCache.buffer) != null) + { + __fromImageAssetCache(Lib.current.stage.context3D); + return true; + } + + return false; + } + else + { + __fromImage(Image.fromFile(path)); + return image != null; + } + #else + __fromImage(Image.fromFile(path)); + if (image == null) return false; + else if (hardware) toHardware(); + + return true; + #end + + #else + return false; #end } + #if (cpp && lime_cffi && !macro && sys) + @:noCompletion private inline function __fromImageAssetCache(context:Context3D):Void + @:privateAccess + { + Reflect.setField(__imageAssetCache.buffer, "format", lime.graphics.PixelFormat.RGBA32); + lime._internal.graphics.ImageDataUtil.setFormat(__imageAssetCache, BGRA32); + lime._internal.graphics.ImageDataUtil.multiplyAlpha(__imageAssetCache); + Reflect.setField(__imageAssetCache.buffer, "premultiplied", true); + __imageAssetCache.__fromImageBuffer(__imageAssetCache.buffer); + + __resize(__imageAssetCache.buffer.width, __imageAssetCache.buffer.height); + __isValid = true; + + __texture = context.createRectangleTexture(width, height, BGRA, false); + __textureContext = context.__context; + __textureVersion = 0; + __texture.__uploadFromImage(__imageAssetCache); + + image = null; + __surface = null; + readable = false; + } + #end + @SuppressWarnings("checkstyle:Dynamic") @:noCompletion private function __fromImage(image:#if lime Image #else Dynamic #end):Void { @@ -3321,12 +3611,7 @@ class BitmapData implements IBitmapDrawable { this.image = image; - width = image.width; - height = image.height; - rect = new Rectangle(0, 0, image.width, image.height); - - __textureWidth = width; - __textureHeight = height; + __resize(image.width, image.height); #if sys image.format = BGRA32; @@ -3423,8 +3708,16 @@ class BitmapData implements IBitmapDrawable { this.width = width; this.height = height; - this.rect.width = width; - this.rect.height = height; + + if (rect == null) + { + rect = new Rectangle(0, 0, width, height); + } + else + { + rect.width = width; + rect.height = height; + } __textureWidth = width; __textureHeight = height; diff --git a/src/openfl/display/DisplayObjectRenderer.hx b/src/openfl/display/DisplayObjectRenderer.hx index eb1780edb8..d73c1b0caa 100644 --- a/src/openfl/display/DisplayObjectRenderer.hx +++ b/src/openfl/display/DisplayObjectRenderer.hx @@ -216,6 +216,7 @@ class DisplayObjectRenderer extends EventDispatcher { if (displayObject == null) return false; var renderer = this; + var allowFramebuffer = renderer.__type == OPENGL; switch (displayObject.__drawableType) { @@ -223,19 +224,19 @@ class DisplayObjectRenderer extends EventDispatcher var bitmap:Bitmap = cast displayObject; // TODO: Handle filters without an intermediate draw if (bitmap.__bitmapData == null - || (bitmap.__filters == null #if lime && renderer.__type == OPENGL #end && bitmap.__cacheBitmap == null)) return false; + || (bitmap.__filters == null #if lime && allowFramebuffer #end && bitmap.__cacheBitmap == null)) return false; force = (bitmap.__bitmapData.image != null && bitmap.__bitmapData.image.version != bitmap.__imageVersion); case TEXT_FIELD: var textField:TextField = cast displayObject; - if (textField.__filters == null #if lime && renderer.__type == OPENGL #end && textField.__cacheBitmap == null + if (textField.__filters == null #if lime && allowFramebuffer #end && textField.__cacheBitmap == null && !textField.__domRender) return false; if (force) textField.__renderDirty = true; force = force || textField.__dirty; case TILEMAP: var tilemap:Tilemap = cast displayObject; - if (tilemap.__filters == null #if lime && renderer.__type == OPENGL #end && tilemap.__cacheBitmap == null) return false; + if (tilemap.__filters == null #if lime && allowFramebuffer #end && tilemap.__cacheBitmap == null) return false; default: } @@ -252,9 +253,8 @@ class DisplayObjectRenderer extends EventDispatcher var updated = false; if (displayObject.cacheAsBitmap - || (renderer.__type != OPENGL - && !colorTransform.__isDefault(true) #if (openfl_legacy_scale9grid && openfl_force_gl_cacheasbitmap_for_scale9grid) - || (renderer.__type == OPENGL && displayObject.scale9Grid != null) #end)) + || (!allowFramebuffer && !colorTransform.__isDefault(true) #if (openfl_legacy_scale9grid && openfl_force_gl_cacheasbitmap_for_scale9grid) + || (allowFramebuffer && displayObject.scale9Grid != null) #end)) { var rect:Rectangle = null; @@ -271,7 +271,7 @@ class DisplayObjectRenderer extends EventDispatcher if (softwareDirty || hardwareDirty) { #if !openfl_force_gl_cacheasbitmap - if (renderType == OPENGL) + if (allowFramebuffer) { if (#if !openfl_disable_gl_cacheasbitmap __shouldCacheHardware(displayObject, null) == false #else true #end) { @@ -280,12 +280,22 @@ class DisplayObjectRenderer extends EventDispatcher #else renderType = CAIRO; #end + allowFramebuffer = false; } } #end - if (softwareDirty && (renderType == CANVAS || renderType == CAIRO)) needRender = true; - if (hardwareDirty && renderType == OPENGL) needRender = true; + if (!allowFramebuffer) + { + if (softwareDirty) + { + needRender = true; + } + } + else if (hardwareDirty) + { + needRender = true; + } } var updateTransform = (needRender || !displayObject.__cacheBitmap.__worldTransform.equals(displayObject.__worldTransform)); @@ -336,7 +346,7 @@ class DisplayObjectRenderer extends EventDispatcher } if (!needRender - && renderer.__type != OPENGL + && !allowFramebuffer && displayObject.__cacheBitmapData != null && displayObject.__cacheBitmapData.image != null && displayObject.__cacheBitmapData.image.version < displayObject.__cacheBitmapData.__textureVersion) @@ -382,12 +392,19 @@ class DisplayObjectRenderer extends EventDispatcher displayObject.__getFilterBounds(rect, displayObject.__cacheBitmapMatrix); - filterWidth = rect.width > 0 ? Math.ceil(rect.width * pixelRatio) : 0; - filterHeight = rect.height > 0 ? Math.ceil(rect.height * pixelRatio) : 0; + filterWidth = rect.width > 0 ? Math.floor(rect.width * pixelRatio) : 0; + filterHeight = rect.height > 0 ? Math.floor(rect.height * pixelRatio) : 0; offsetX = rect.x > 0 ? Math.ceil(rect.x) : Math.floor(rect.x); offsetY = rect.y > 0 ? Math.ceil(rect.y) : Math.floor(rect.y); + #if lime + bitmapWidth = filterWidth; + bitmapHeight = filterHeight; + + if (!needRender) needRender = displayObject.__cacheBitmapData == null || + displayObject.__cacheBitmapData.width != filterWidth || displayObject.__cacheBitmapData.height != filterHeight; + #else if (displayObject.__cacheBitmapData != null) { if (filterWidth > displayObject.__cacheBitmapData.width || filterHeight > displayObject.__cacheBitmapData.height) @@ -407,6 +424,7 @@ class DisplayObjectRenderer extends EventDispatcher bitmapWidth = filterWidth; bitmapHeight = filterHeight; } + #end } if (needRender) @@ -416,39 +434,57 @@ class DisplayObjectRenderer extends EventDispatcher if (filterWidth >= 0.5 && filterHeight >= 0.5) { - var needsFill = (displayObject.opaqueBackground != null - && (bitmapWidth != filterWidth || bitmapHeight != filterHeight)); - var fillColor = displayObject.opaqueBackground != null ? (0xFF << 24) | displayObject.opaqueBackground : 0; - var bitmapColor = needsFill ? 0 : fillColor; - var allowFramebuffer = (renderer.__type == OPENGL); - - if (displayObject.__cacheBitmapData == null - || bitmapWidth > displayObject.__cacheBitmapData.width - || bitmapHeight > displayObject.__cacheBitmapData.height) - { - displayObject.__cacheBitmapData = new BitmapData(bitmapWidth, bitmapHeight, true, bitmapColor); + var fillColor = displayObject.opaqueBackground != null ? 0xFF000000 | displayObject.opaqueBackground : 0; + #if lime + if (allowFramebuffer) + { if (displayObject.__cacheBitmap == null) displayObject.__cacheBitmap = new Bitmap(); - displayObject.__cacheBitmap.__bitmapData = displayObject.__cacheBitmapData; - displayObject.__cacheBitmapRenderer = null; + if (displayObject.__cacheBitmapData == null) + { + displayObject.__cacheBitmapData = BitmapData.fromContext(cast(renderer, OpenGLRenderer).__context3D, + bitmapWidth, bitmapHeight); + + displayObject.__cacheBitmap.__bitmapData = displayObject.__cacheBitmapData; + //displayObject.__cacheBitmapRenderer = null; + } + else if (bitmapWidth != displayObject.__cacheBitmapData.width || bitmapHeight != displayObject.__cacheBitmapData.height) + { + displayObject.__cacheBitmapData.resize(bitmapWidth, bitmapHeight); + + displayObject.__cacheBitmap.__bitmapData = displayObject.__cacheBitmapData; + //displayObject.__cacheBitmapRenderer = null; + } + + displayObject.__cacheBitmapData.__fillRect(displayObject.__cacheBitmapData.rect, fillColor, true); } else + #end { - displayObject.__cacheBitmapData.__fillRect(displayObject.__cacheBitmapData.rect, bitmapColor, allowFramebuffer); - } + if (displayObject.__cacheBitmapData == null + || bitmapWidth > displayObject.__cacheBitmapData.width + || bitmapHeight > displayObject.__cacheBitmapData.height) + { + displayObject.__cacheBitmapData = new BitmapData(bitmapWidth, bitmapHeight, true, fillColor); - if (renderer.__type == OPENGL - && displayObject.__cacheBitmapData.__texture != null - && __hasMaskedDescendant(displayObject) - && __isOnMouseOverPath(displayObject)) - { - displayObject.__cacheBitmapData.__texture = null; - } + if (displayObject.__cacheBitmap == null) displayObject.__cacheBitmap = new Bitmap(); + displayObject.__cacheBitmap.__bitmapData = displayObject.__cacheBitmapData; + displayObject.__cacheBitmapRenderer = null; + } + else + { + rect.setTo(0, 0, filterWidth, filterHeight); + displayObject.__cacheBitmapData.__fillRect(rect, fillColor, allowFramebuffer); + } - if (needsFill) - { - rect.setTo(0, 0, filterWidth, filterHeight); - displayObject.__cacheBitmapData.__fillRect(rect, fillColor, allowFramebuffer); + if (renderer.__type == OPENGL + && displayObject.__cacheBitmapData.__texture != null + && __hasMaskedDescendant(displayObject) + && __isOnMouseOverPath(displayObject)) + { + displayObject.__cacheBitmapData.__texture.dispose(); + displayObject.__cacheBitmapData.__texture = null; + } } } else @@ -536,7 +572,7 @@ class DisplayObjectRenderer extends EventDispatcher #if lime if (displayObject.__cacheBitmapRenderer == null || renderType != displayObject.__cacheBitmapRenderer.__type) { - if (renderType == OPENGL) + if (allowFramebuffer) { displayObject.__cacheBitmapRenderer = new OpenGLRenderer(cast(renderer, OpenGLRenderer).__context3D, displayObject.__cacheBitmapData); } @@ -634,20 +670,15 @@ class DisplayObjectRenderer extends EventDispatcher var bitmap3:BitmapData = null; // if (needSecondBitmapData) { - if (displayObject.__cacheBitmapData2 == null - || bitmapWidth > displayObject.__cacheBitmapData2.width - || bitmapHeight > displayObject.__cacheBitmapData2.height) + if (displayObject.__cacheBitmapData2 == null) { - displayObject.__cacheBitmapData2 = new BitmapData(bitmapWidth, bitmapHeight, true, 0); + displayObject.__cacheBitmapData2 = BitmapData.fromContext(context, bitmapWidth, bitmapHeight); } - else + else if (bitmapWidth != displayObject.__cacheBitmapData2.width || bitmapHeight != displayObject.__cacheBitmapData2.height) { - displayObject.__cacheBitmapData2.fillRect(displayObject.__cacheBitmapData2.rect, 0); - if (displayObject.__cacheBitmapData2.image != null) - { - displayObject.__cacheBitmapData2.__textureVersion = displayObject.__cacheBitmapData2.image.version + 1; - } + displayObject.__cacheBitmapData2.resize(bitmapWidth, bitmapHeight); } + displayObject.__cacheBitmapData2.__fillRect(displayObject.__cacheBitmapData2.rect, 0, true); displayObject.__cacheBitmapData2.__setUVRect(context, 0, 0, filterWidth, filterHeight); bitmap2 = displayObject.__cacheBitmapData2; // } else { @@ -656,20 +687,15 @@ class DisplayObjectRenderer extends EventDispatcher if (needCopyOfOriginal) { - if (displayObject.__cacheBitmapData3 == null - || bitmapWidth > displayObject.__cacheBitmapData3.width - || bitmapHeight > displayObject.__cacheBitmapData3.height) + if (displayObject.__cacheBitmapData3 == null) { - displayObject.__cacheBitmapData3 = new BitmapData(bitmapWidth, bitmapHeight, true, 0); + displayObject.__cacheBitmapData3 = BitmapData.fromContext(context, bitmapWidth, bitmapHeight); } - else + else if (bitmapWidth != displayObject.__cacheBitmapData3.width || bitmapHeight != displayObject.__cacheBitmapData3.height) { - displayObject.__cacheBitmapData3.fillRect(displayObject.__cacheBitmapData3.rect, 0); - if (displayObject.__cacheBitmapData3.image != null) - { - displayObject.__cacheBitmapData3.__textureVersion = displayObject.__cacheBitmapData3.image.version + 1; - } + displayObject.__cacheBitmapData3.resize(bitmapWidth, bitmapHeight); } + displayObject.__cacheBitmapData3.__fillRect(displayObject.__cacheBitmapData3.rect, 0, true); displayObject.__cacheBitmapData3.__setUVRect(context, 0, 0, filterWidth, filterHeight); bitmap3 = displayObject.__cacheBitmapData3; } diff --git a/src/openfl/display/Graphics.hx b/src/openfl/display/Graphics.hx index 6fdd6f73bb..7a3877605e 100644 --- a/src/openfl/display/Graphics.hx +++ b/src/openfl/display/Graphics.hx @@ -61,9 +61,11 @@ import js.html.CanvasRenderingContext2D; { @:noCompletion private static var maxTextureHeight:Null = null; @:noCompletion private static var maxTextureWidth:Null = null; + @:noCompletion private static var shaderBufferPool:ObjectPool = new ObjectPool(function() return new ShaderBuffer()); @:noCompletion private var __bounds:Rectangle; @:noCompletion private var __commands:DrawCommandBuffer; + @:noCompletion private var __reader:DrawCommandReader; @:noCompletion private var __dirty(default, set):Bool = true; @:noCompletion private var __hardwareDirty:Bool; @:noCompletion private var __height:Int; @@ -72,7 +74,6 @@ import js.html.CanvasRenderingContext2D; @:noCompletion private var __positionY:Float; @:noCompletion private var __quadBuffer:Context3DBuffer; @:noCompletion private var __renderTransform:Matrix; - @:noCompletion private var __shaderBufferPool:ObjectPool; @:noCompletion private var __softwareDirty:Bool; @:noCompletion private var __strokePadding:Float; @:noCompletion private var __transformDirty:Bool; @@ -118,8 +119,6 @@ import js.html.CanvasRenderingContext2D; __bitmapScaleX = 1; __bitmapScaleY = 1; - __shaderBufferPool = new ObjectPool(function() return new ShaderBuffer()); - #if (js && html5) moveTo(0, 0); #end @@ -393,7 +392,7 @@ import js.html.CanvasRenderingContext2D; if (shader != null) { #if lime - var shaderBuffer = __shaderBufferPool.get(); + var shaderBuffer = shaderBufferPool.get(); __usedShaderBuffers.add(shaderBuffer); shaderBuffer.update(cast shader); @@ -412,7 +411,7 @@ import js.html.CanvasRenderingContext2D; #if lime for (shaderBuffer in __usedShaderBuffers) { - __shaderBufferPool.release(shaderBuffer); + shaderBufferPool.release(shaderBuffer); } #end @@ -931,8 +930,8 @@ import js.html.CanvasRenderingContext2D; if (maxY < tileRect.bottom) maxY = tileRect.bottom; } - __inflateBounds(minX, minY); - __inflateBounds(maxX, maxY); + __inflateBounds(minX - __strokePadding, minY - __strokePadding); + __inflateBounds(maxX + __strokePadding, maxY + __strokePadding); __commands.drawQuads(rects, indices, transforms); @@ -1800,7 +1799,16 @@ import js.html.CanvasRenderingContext2D; @:noCompletion private function __readGraphicsData(graphicsData:Vector):Void { - var data = new DrawCommandReader(__commands); + if (__reader == null) + { + __reader = new DrawCommandReader(__commands); + } + else + { + __reader.reset(); + __reader.buffer = __commands; + } + var path:GraphicsPath = null; var stroke:GraphicsStroke; @@ -1825,41 +1833,41 @@ import js.html.CanvasRenderingContext2D; switch (type) { case CUBIC_CURVE_TO: - var c = data.readCubicCurveTo(); + var c = __reader.readCubicCurveTo(); path.cubicCurveTo(c.controlX1, c.controlY1, c.controlX2, c.controlY2, c.anchorX, c.anchorY); case CURVE_TO: - var c = data.readCurveTo(); + var c = __reader.readCurveTo(); path.curveTo(c.controlX, c.controlY, c.anchorX, c.anchorY); case LINE_TO: - var c = data.readLineTo(); + var c = __reader.readLineTo(); path.lineTo(c.x, c.y); case MOVE_TO: - var c = data.readMoveTo(); + var c = __reader.readMoveTo(); path.moveTo(c.x, c.y); case DRAW_CIRCLE: - var c = data.readDrawCircle(); + var c = __reader.readDrawCircle(); path.__drawCircle(c.x, c.y, c.radius); case DRAW_ELLIPSE: - var c = data.readDrawEllipse(); + var c = __reader.readDrawEllipse(); path.__drawEllipse(c.x, c.y, c.width, c.height); case DRAW_RECT: - var c = data.readDrawRect(); + var c = __reader.readDrawRect(); path.__drawRect(c.x, c.y, c.width, c.height); case DRAW_ROUND_RECT: - var c = data.readDrawRoundRect(); + var c = __reader.readDrawRoundRect(); path.__drawRoundRect(c.x, c.y, c.width, c.height, c.ellipseWidth, c.ellipseHeight != null ? c.ellipseHeight : c.ellipseWidth); case LINE_GRADIENT_STYLE: // TODO - var c = data.readLineGradientStyle(); + var c = __reader.readLineGradientStyle(); // stroke = new GraphicsStroke (c.thickness, c.pixelHinting, c.scaleMode, c.caps, c.joints, c.miterLimit); // stroke.fill = new GraphicsGradientFill (c.type, c.colors, c.alphas, c.ratios, c.matrix, c.spreadMethod, c.interpolationMethod, c.focalPointRatio); // graphicsData.push (stroke); @@ -1867,39 +1875,39 @@ import js.html.CanvasRenderingContext2D; case LINE_BITMAP_STYLE: // TODO - var c = data.readLineBitmapStyle(); + var c = __reader.readLineBitmapStyle(); path = null; // stroke = new GraphicsStroke (c.thickness, c.pixelHinting, c.scaleMode, c.caps, c.joints, c.miterLimit); // stroke.fill = new GraphicsBitmapFill (c.bitmap, c.matrix, c.repeat, c.smooth); // graphicsData.push (stroke); case LINE_STYLE: - var c = data.readLineStyle(); + var c = __reader.readLineStyle(); stroke = new GraphicsStroke(c.thickness, c.pixelHinting, c.scaleMode, c.caps, c.joints, c.miterLimit); stroke.fill = new GraphicsSolidFill(c.color, c.alpha); graphicsData.push(stroke); case END_FILL: - data.readEndFill(); + __reader.readEndFill(); graphicsData.push(new GraphicsEndFill()); case BEGIN_BITMAP_FILL: - var c = data.readBeginBitmapFill(); + var c = __reader.readBeginBitmapFill(); graphicsData.push(new GraphicsBitmapFill(c.bitmap, c.matrix, c.repeat, c.smooth)); case BEGIN_FILL: - var c = data.readBeginFill(); + var c = __reader.readBeginFill(); graphicsData.push(new GraphicsSolidFill(c.color, c.alpha)); case BEGIN_GRADIENT_FILL: - var c = data.readBeginGradientFill(); + var c = __reader.readBeginGradientFill(); graphicsData.push(new GraphicsGradientFill(c.type, c.colors, c.alphas, c.ratios, c.matrix, c.spreadMethod, c.interpolationMethod, c.focalPointRatio)); case BEGIN_SHADER_FILL: default: - data.skip(type); + __reader.skip(type); } } @@ -2033,10 +2041,10 @@ import js.html.CanvasRenderingContext2D; var tx = x * parentTransform.a + y * parentTransform.c + parentTransform.tx; var ty = x * parentTransform.b + y * parentTransform.d + parentTransform.ty; - #if openfl_disable_graphics_pixel_snapping + //#if openfl_disable_graphics_pixel_snapping __worldTransform.tx = tx; __worldTransform.ty = ty; - #else + /*#else // round the world position for crisp graphics rendering if (pixelRatio > 1.0) { @@ -2057,7 +2065,7 @@ import js.html.CanvasRenderingContext2D; // Offset the rendering with the subpixel offset removed by Math.round above __renderTransform.tx = __worldTransform.__transformInverseX(tx, ty); __renderTransform.ty = __worldTransform.__transformInverseY(tx, ty); - #end + #end*/ // Calculate the size to contain the graphics and an extra subpixel // We used to add tx and ty from __renderTransform instead of 1.0 diff --git a/src/openfl/display/_internal/CairoGraphics.hx b/src/openfl/display/_internal/CairoGraphics.hx index 19eb5bfb88..3d360b947b 100644 --- a/src/openfl/display/_internal/CairoGraphics.hx +++ b/src/openfl/display/_internal/CairoGraphics.hx @@ -125,7 +125,10 @@ class CairoGraphics private static function createImagePattern(bitmapFill:BitmapData, bitmapRepeat:Bool, smooth:Bool):CairoPattern { - var pattern = CairoPattern.createForSurface(bitmapFill.getSurface()); + var surface = bitmapFill.getSurface(); + if (surface == null) return null; + + var pattern = CairoPattern.createForSurface(surface); pattern.filter = (smooth && allowSmoothing) ? CairoFilter.GOOD : CairoFilter.NEAREST; if (bitmapRepeat) @@ -1162,9 +1165,9 @@ class CairoGraphics cairo.moveTo(positionX - offsetX, positionY - offsetY); - if (c.bitmap.readable) + strokePattern = createImagePattern(c.bitmap, c.repeat, c.smooth); + if (strokePattern != null) { - strokePattern = createImagePattern(c.bitmap, c.repeat, c.smooth); bitmapStroke = c.bitmap; bitmapStrokeMatrix = c.matrix; } @@ -1192,9 +1195,9 @@ class CairoGraphics case BEGIN_BITMAP_FILL: var c = data.readBeginBitmapFill(); - if (c.bitmap.readable) + fillPattern = createImagePattern(c.bitmap, c.repeat, c.smooth); + if (fillPattern != null) { - fillPattern = createImagePattern(c.bitmap, c.repeat, c.smooth); bitmapFill = c.bitmap; bitmapFillMatrix = c.matrix; } @@ -1264,11 +1267,8 @@ class CairoGraphics if (shaderBuffer.inputCount > 0) { bitmapFill = shaderBuffer.inputs[0]; - if (bitmapFill.readable) - { - fillPattern = createImagePattern(bitmapFill, shaderBuffer.inputWrap[0] != CLAMP, shaderBuffer.inputFilter[0] != NEAREST); - } - else + fillPattern = createImagePattern(bitmapFill, shaderBuffer.inputWrap[0] != CLAMP, shaderBuffer.inputFilter[0] != NEAREST); + if (fillPattern == null) { // if it's hardware-only BitmapData, fall back to // drawing solid black because we have no software diff --git a/src/openfl/display3D/textures/ASTCTexture.hx b/src/openfl/display3D/textures/ASTCTexture.hx index 51a14ffcf2..b5393f3afe 100644 --- a/src/openfl/display3D/textures/ASTCTexture.hx +++ b/src/openfl/display3D/textures/ASTCTexture.hx @@ -1,6 +1,7 @@ package openfl.display3D.textures; #if !flash +import openfl.display._internal.SamplerState; import openfl.display3D.Context3D; import openfl.display3D._internal.ASTCReader; import openfl.errors.IllegalOperationError; @@ -65,41 +66,29 @@ using StringTools; reader = null; } - @:noCompletion - private override function __setSamplerState(state:openfl.display._internal.SamplerState):Bool + @:noCompletion private override function __setSamplerState(state:SamplerState):Bool { if (super.__setSamplerState(state)) { - if (state.mipfilter != MIPNONE && !__samplerState.mipmapGenerated) - { - __context.gl.generateMipmap(__textureTarget); - __samplerState.mipmapGenerated = true; - } + var gl = __context.gl; if (Context3D.__glMaxTextureMaxAnisotropy != 0) { - var aniso:Int = -1; - - if (state != null && state.filter != null) + var aniso = switch (state.filter) { - switch (state.filter) - { - case ANISOTROPIC2X: - aniso = 2; - case ANISOTROPIC4X: - aniso = 4; - case ANISOTROPIC8X: - aniso = 8; - case ANISOTROPIC16X: - aniso = 16; - default: - aniso = 1; - } + case ANISOTROPIC2X: 2; + case ANISOTROPIC4X: 4; + case ANISOTROPIC8X: 8; + case ANISOTROPIC16X: 16; + default: 1; } - if (aniso > Context3D.__glMaxTextureMaxAnisotropy) aniso = Context3D.__glMaxTextureMaxAnisotropy; + if (aniso > Context3D.__glMaxTextureMaxAnisotropy) + { + aniso = Context3D.__glMaxTextureMaxAnisotropy; + } - __context.gl.texParameterf(__context.gl.TEXTURE_2D, Context3D.__glTextureMaxAnisotropy, aniso); + gl.texParameterf(gl.TEXTURE_2D, Context3D.__glTextureMaxAnisotropy, aniso); } return true; diff --git a/src/openfl/display3D/textures/Texture.hx b/src/openfl/display3D/textures/Texture.hx index f02b95966e..a39643e2c1 100644 --- a/src/openfl/display3D/textures/Texture.hx +++ b/src/openfl/display3D/textures/Texture.hx @@ -265,12 +265,6 @@ import openfl.utils.ByteArray; { var gl = __context.gl; - if (state.mipfilter != MIPNONE && !__samplerState.mipmapGenerated) - { - gl.generateMipmap(gl.TEXTURE_2D); - __samplerState.mipmapGenerated = true; - } - if (Context3D.__glMaxTextureMaxAnisotropy != 0) { var aniso = switch (state.filter) diff --git a/src/openfl/display3D/textures/TextureBase.hx b/src/openfl/display3D/textures/TextureBase.hx index 2fe9f6b7ba..ebd07da08d 100644 --- a/src/openfl/display3D/textures/TextureBase.hx +++ b/src/openfl/display3D/textures/TextureBase.hx @@ -1,15 +1,16 @@ package openfl.display3D.textures; #if !flash +import openfl.display._internal.SamplerState; import openfl.display3D._internal.GLFramebuffer; import openfl.display3D._internal.GLRenderbuffer; import openfl.display3D._internal.GLTexture; import openfl.display3D._internal.ATFGPUFormat; -import openfl.display._internal.SamplerState; +import openfl.utils._internal.Log; import openfl.display.BitmapData; +import openfl.display.Graphics; import openfl.events.EventDispatcher; import openfl.errors.Error; -import openfl.utils._internal.Log; #if lime import lime._internal.graphics.ImageCanvasUtil; import lime.graphics.Image; @@ -29,6 +30,7 @@ import lime.graphics.RenderContext; @:access(openfl.display._internal.SamplerState) @:access(openfl.display3D.Context3D) @:access(openfl.display.BitmapData) +@:access(openfl.display.Graphics) @:access(openfl.display.Stage) class TextureBase extends EventDispatcher { @@ -204,6 +206,41 @@ class TextureBase extends EventDispatcher } } + /** + **BETA** + + Resizes and stretches this Texture object to desired width and height. + + @param width The width of the bitmap image in pixels. + @param height The height of the bitmap image in pixels. + + @since FunkinCrew's OpenFL + + @see `BitmapData.resize` + **/ + public function resize(width:Int, height:Int):Void + { + if (__alphaTexture != null) __alphaTexture.resize(width, height); + + if (width > Graphics.maxTextureWidth) width = Graphics.maxTextureWidth; + if (height > Graphics.maxTextureHeight) height = Graphics.maxTextureHeight; + + var gl = __context.gl; + + if (gl != null && width > 0 && height > 0 && (__width != width || __height != height)) + { + __width = width; + __height = height; + + gl.bindTexture(gl.TEXTURE_2D, __textureID); + gl.texImage2D(__textureTarget, 0, __internalFormat, width, height, 0, __format, gl.UNSIGNED_BYTE, null); + __updateGLFramebuffer(false, 0, 0); + + @:privateAccess + gl.bindTexture(gl.TEXTURE_2D, __context.__contextState.__currentGLTexture2D); + } + } + @SuppressWarnings("checkstyle:Dynamic") @:noCompletion private function __getGLFramebuffer(enableDepthAndStencil:Bool, antiAlias:Int, surfaceSelector:Int):GLFramebuffer { @@ -269,6 +306,36 @@ class TextureBase extends EventDispatcher return __glFramebuffer; } + @:noCompletion private function __updateGLFramebuffer(enableDepthAndStencil:Bool, antiAlias:Int, surfaceSelector:Int):GLFramebuffer + { + if (__glFramebuffer == null) + { + return __getGLFramebuffer(false, 0, 0); + } + else + { + var gl = __context.gl; + + gl.bindFramebuffer(gl.FRAMEBUFFER, __glFramebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, __textureID, 0); + + var seperate = __glDepthRenderbuffer != __glStencilRenderbuffer; + + gl.bindRenderbuffer(gl.RENDERBUFFER, __glDepthRenderbuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, seperate ? gl.DEPTH_COMPONENT16 : Context3D.__glDepthStencil, __width, __height); + + if (seperate) + { + gl.bindRenderbuffer(gl.RENDERBUFFER, __glStencilRenderbuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, __width, __height); + } + + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + + return __glFramebuffer; + } + } + #if lime @:noCompletion private function __getImage(bitmapData:BitmapData):Image { @@ -330,14 +397,15 @@ class TextureBase extends EventDispatcher @:noCompletion private function __setSamplerState(state:SamplerState):Bool { - if (!state.equals(__samplerState)) + var gl = __context.gl; + if (__textureTarget != __context.gl.TEXTURE_CUBE_MAP && state.mipfilter != MIPNONE) { - var gl = __context.gl; - - if (__textureTarget == __context.gl.TEXTURE_CUBE_MAP) __context.__bindGLTextureCubeMap(__textureID); - else - __context.__bindGLTexture2D(__textureID); + gl.generateMipmap(__textureTarget); + state.mipmapGenerated = true; + } + if (!state.equals(__samplerState)) + { var wrapModeS = 0, wrapModeT = 0; switch (state.wrap) @@ -385,14 +453,15 @@ class TextureBase extends EventDispatcher gl.texParameteri(__textureTarget, gl.TEXTURE_WRAP_S, wrapModeS); gl.texParameteri(__textureTarget, gl.TEXTURE_WRAP_T, wrapModeT); - if (state.lodBias != 0.0) + #if lime + if (__context.__context.type == OPENGL) { - // TODO - // throw new IllegalOperationError("Lod bias setting not supported yet"); + gl.texParameterf(__textureTarget, 0x8501, state.lodBias); // GL_TEXTURE_LOD_BIAS } + #end if (__samplerState == null) __samplerState = state.clone(); - __samplerState.copyFrom(state); + else __samplerState.copyFrom(state); return true; } diff --git a/src/openfl/utils/Assets.hx b/src/openfl/utils/Assets.hx index febda9e67b..6eaae06445 100644 --- a/src/openfl/utils/Assets.hx +++ b/src/openfl/utils/Assets.hx @@ -50,6 +50,9 @@ import lime.media.vorbis.VorbisFile; @:access(openfl.utils.AssetLibrary) class Assets { + public static var allowCompressedTextures:Bool = true; + public static var allowHardwareTextures:Bool = true; + public static var cache:IAssetCache = new AssetCache(); @:noCompletion private static var dispatcher:EventDispatcher #if !macro = new EventDispatcher() #end; @@ -79,8 +82,10 @@ class Assets @param allowCompressedTextures Whether to check for compressed texture formats (e.g., ASTC) when the asset is a PNG. Defaults to true. @return Whether the requested asset ID and type exists **/ - public static function exists(id:String, type:AssetType = null, allowCompressedTextures:Bool = true):Bool + public static function exists(id:String, type:AssetType = null, ?allowCompressedTextures:Null):Bool { + if (allowCompressedTextures == null) allowCompressedTextures = Assets.allowCompressedTextures; + #if lime #if !flash if (allowCompressedTextures) @@ -137,8 +142,11 @@ class Assets @see [Working with bitmap assets](https://books.openfl.org/openfl-developers-guide/working-with-bitmaps/working-with-bitmap-assets.html) **/ - public static function getBitmapData(id:String, useCache:Bool = true, allowCompressedTextures:Bool = true):BitmapData + public static function getBitmapData(id:String, useCache:Bool = true, ?allowCompressedTextures:Null, ?allowHardwareTextures:Null):BitmapData { + if (allowCompressedTextures == null) allowCompressedTextures = Assets.allowCompressedTextures; + if (allowHardwareTextures == null) allowHardwareTextures = Assets.allowHardwareTextures; + #if (lime && tools && !display) if (useCache && cache.enabled && cache.hasBitmapData(id)) { @@ -174,6 +182,40 @@ class Assets } #end + #if (cpp && lime_cffi && !macro && sys) + // HTML5 does not like synchronously loads bitmap, and it already caches all of the images initially. + // So the methods to get hardware textures with cached bytes will be cpp only. + // The reason why this exists so it doesn't have to make gc in under pressure for allocating temporary bytes + // just for to make it not readable later. + if (allowHardwareTextures) + { + var bitmapData = BitmapData.fromFile(LimeAssets.getPath(id), true); + if (bitmapData == null) + { + try + { + bitmapData = BitmapData.fromBytes(LimeAssets.getBytes(id), null, true); + } + catch (e) + { + // Causes crash for some reason for casting some weird stuff in lime getBytes AssetLibrary? + } + } + + if (bitmapData != null) + { + bitmapData.__asset = true; + + if (useCache && cache.enabled) + { + cache.setBitmapData(id, bitmapData); + } + + return bitmapData; + } + } + #end + var image = LimeAssets.getImage(id, false); if (image != null) @@ -182,6 +224,8 @@ class Assets var bitmapData = image.src; #else var bitmapData = BitmapData.fromImage(image); + if (allowHardwareTextures) bitmapData.toHardware(); + bitmapData.__asset = true; #end @@ -579,8 +623,11 @@ class Assets @see [Working with bitmap assets](https://books.openfl.org/openfl-developers-guide/working-with-bitmaps/working-with-bitmap-assets.html) **/ - public static function loadBitmapData(id:String, useCache:Null = true):Future + public static function loadBitmapData(id:String, useCache:Null = true, ?allowCompressedTextures:Null, ?allowHardwareTextures:Null):Future { + if (allowCompressedTextures == null) allowCompressedTextures = Assets.allowCompressedTextures; + if (allowHardwareTextures == null) allowHardwareTextures = Assets.allowHardwareTextures; + if (useCache == null) useCache = true; #if (lime && tools && !display) @@ -597,6 +644,44 @@ class Assets } } + #if !flash + if ((allowCompressedTextures || haxe.io.Path.extension(id) == "astc") && openfl.Lib.current.stage.context3D.isASTCSupported()) + { + final astcTexture:String = haxe.io.Path.withExtension(id, "astc"); + + if (LimeAssets.exists(astcTexture, BINARY)) + { + LimeAssets.loadBytes(astcTexture).onComplete(function(bytes) + { + if (bytes != null) + { + var bitmapData = BitmapData.fromTexture(openfl.Lib.current.stage.context3D.createASTCTexture(bytes), false); + bitmapData.__asset = true; + + if (useCache && cache.enabled) + { + cache.setBitmapData(id, bitmapData); + } + + promise.complete(bitmapData); + } + else + { + promise.error("[Assets] Could not load Image \"" + id + "\""); + } + }).onError(promise.error).onProgress(promise.progress); + + return promise.future; + } + + if (haxe.io.Path.extension(id) == "astc") + { + promise.error("[Assets] Could not load Image \"" + id + "\""); + return promise.future; + } + } + #end + LimeAssets.loadImage(id, false).onComplete(function(image) { if (image != null) @@ -605,6 +690,8 @@ class Assets var bitmapData = image.src; #else var bitmapData = BitmapData.fromImage(image); + if (allowHardwareTextures) bitmapData.toHardware(); + bitmapData.__asset = true; #end