From e95e1d3dfa0c63519d6b1d3a5c6f4f572fbfbe5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=8D=9A=7ENex?= <87421482+NexIsDumb@users.noreply.github.com> Date: Tue, 19 Mar 2024 02:31:27 +0100 Subject: [PATCH] bugfix for +1 pixel when shaders (openfl objs) NO MORE THAT GODDAMN +1 PIXEL ON CAMERAS WITH SHADERS --- .../openfl/display/DisplayObjectRenderer.hx | 864 ++++++++++++++++++ 1 file changed, 864 insertions(+) create mode 100644 source/openfl/display/DisplayObjectRenderer.hx diff --git a/source/openfl/display/DisplayObjectRenderer.hx b/source/openfl/display/DisplayObjectRenderer.hx new file mode 100644 index 00000000..f25e330d --- /dev/null +++ b/source/openfl/display/DisplayObjectRenderer.hx @@ -0,0 +1,864 @@ +package openfl.display; + +#if !flash +import openfl.display._internal.Context3DGraphics; +import openfl.display.Bitmap; +import openfl.display.DisplayObject; +import openfl.display.Tilemap; +import openfl.events.EventDispatcher; +import openfl.events.RenderEvent; +import openfl.geom.ColorTransform; +import openfl.geom.Matrix; +import openfl.geom.Point; +import openfl.geom.Rectangle; +import openfl.text.TextField; +#if lime +import lime._internal.graphics.ImageCanvasUtil; // TODO +import lime.graphics.cairo.Cairo; +import lime.graphics.RenderContext; +import lime.graphics.RenderContextType; +#end + +#if !openfl_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(openfl.display._internal.Context3DGraphics) +@:access(lime.graphics.ImageBuffer) +@:access(openfl.display.Bitmap) +@:access(openfl.display.BitmapData) +@:access(openfl.display.DisplayObject) +@:access(openfl.display.Graphics) +@:access(openfl.display.Tilemap) +@:access(openfl.display3D.Context3D) +@:access(openfl.events.RenderEvent) +@:access(openfl.filters.BitmapFilter) +@:access(openfl.geom.ColorTransform) +@:access(openfl.geom.Rectangle) +@:access(openfl.geom.Transform) +@:access(openfl.text.TextField) +@:allow(openfl.display._internal) +@:allow(openfl.display) +@:allow(openfl.text) +class DisplayObjectRenderer extends EventDispatcher +{ + @:noCompletion private var __allowSmoothing:Bool; + @:noCompletion private var __blendMode:BlendMode; + @:noCompletion private var __cleared:Bool; + @SuppressWarnings("checkstyle:Dynamic") @:noCompletion private var __context:#if lime RenderContext #else Dynamic #end; + @:noCompletion private var __overrideBlendMode:BlendMode; + @:noCompletion private var __pixelRatio:Float; + @:noCompletion private var __roundPixels:Bool; + @:noCompletion private var __stage:Stage; + @:noCompletion private var __tempColorTransform:ColorTransform; + @:noCompletion private var __transparent:Bool; + @SuppressWarnings("checkstyle:Dynamic") @:noCompletion private var __type:#if lime RenderContextType #else Dynamic #end; + @:noCompletion private var __worldAlpha:Float; + @:noCompletion private var __worldColorTransform:ColorTransform; + @:noCompletion private var __worldTransform:Matrix; + + @:noCompletion private function new() + { + super(); + + __allowSmoothing = true; + __pixelRatio = 1; + __tempColorTransform = new ColorTransform(); + __worldAlpha = 1; + } + + @:noCompletion private function __clear():Void {} + + @:noCompletion private function __getAlpha(value:Float):Float + { + return value * __worldAlpha; + } + + @:noCompletion private function __getColorTransform(value:ColorTransform):ColorTransform + { + if (__worldColorTransform != null) + { + __tempColorTransform.__copyFrom(__worldColorTransform); + __tempColorTransform.__combine(value); + return __tempColorTransform; + } + else + { + return value; + } + } + + @:noCompletion private function __popMask():Void {} + + @:noCompletion private function __popMaskObject(object:DisplayObject, handleScrollRect:Bool = true):Void {} + + @:noCompletion private function __popMaskRect():Void {} + + @:noCompletion private function __pushMask(mask:DisplayObject):Void {} + + @:noCompletion private function __pushMaskObject(object:DisplayObject, handleScrollRect:Bool = true):Void {} + + @:noCompletion private function __pushMaskRect(rect:Rectangle, transform:Matrix):Void {} + + @:noCompletion private function __render(object:IBitmapDrawable):Void {} + + @:noCompletion private function __renderEvent(displayObject:DisplayObject):Void + { + var renderer = this; + #if lime + if (displayObject.__customRenderEvent != null && displayObject.__renderable) + { + displayObject.__customRenderEvent.allowSmoothing = renderer.__allowSmoothing; + displayObject.__customRenderEvent.objectMatrix.copyFrom(displayObject.__renderTransform); + displayObject.__customRenderEvent.objectColorTransform.__copyFrom(displayObject.__worldColorTransform); + displayObject.__customRenderEvent.renderer = renderer; + + switch (renderer.__type) + { + case OPENGL: + if (!renderer.__cleared) renderer.__clear(); + + var renderer:OpenGLRenderer = cast renderer; + renderer.setShader(displayObject.__worldShader); + renderer.__context3D.__flushGL(); + + displayObject.__customRenderEvent.type = RenderEvent.RENDER_OPENGL; + + case CAIRO: + displayObject.__customRenderEvent.type = RenderEvent.RENDER_CAIRO; + + case DOM: + if (displayObject.stage != null && displayObject.__worldVisible) + { + displayObject.__customRenderEvent.type = RenderEvent.RENDER_DOM; + } + else + { + displayObject.__customRenderEvent.type = RenderEvent.CLEAR_DOM; + } + + case CANVAS: + displayObject.__customRenderEvent.type = RenderEvent.RENDER_CANVAS; + + default: + return; + } + + renderer.__setBlendMode(displayObject.__worldBlendMode); + renderer.__pushMaskObject(displayObject); + + displayObject.dispatchEvent(displayObject.__customRenderEvent); + + renderer.__popMaskObject(displayObject); + + if (renderer.__type == OPENGL) + { + var renderer:OpenGLRenderer = cast renderer; + renderer.setViewport(); + } + } + #end + } + + @:noCompletion private function __resize(width:Int, height:Int):Void {} + + @:noCompletion private function __setBlendMode(value:BlendMode):Void {} + + @:noCompletion private function __shouldCacheHardware(displayObject:DisplayObject, value:Null):Null + { + if (displayObject == null) return null; + + switch (displayObject.__drawableType) + { + case SPRITE, STAGE: + if (value == true) return true; + value = __shouldCacheHardware_DisplayObject(displayObject, value); + if (value == true) return true; + + if (displayObject.__children != null) + { + for (child in displayObject.__children) + { + value = __shouldCacheHardware_DisplayObject(child, value); + if (value == true) return true; + } + } + + return value; + + case TEXT_FIELD: + return value == true ? true : false; + + case TILEMAP: + return true; + + default: + return __shouldCacheHardware_DisplayObject(displayObject, value); + } + } + + @:noCompletion private function __shouldCacheHardware_DisplayObject(displayObject:DisplayObject, value:Null):Null + { + if (value == true || displayObject.__filters != null) return true; + + if (value == false || (displayObject.__graphics != null && !Context3DGraphics.isCompatible(displayObject.__graphics))) + { + return false; + } + + return null; + } + + @:noCompletion private function __updateCacheBitmap(displayObject:DisplayObject, force:Bool):Bool + { + if (displayObject == null) return false; + var renderer = this; + + switch (displayObject.__drawableType) + { + case BITMAP: + 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; + 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 + && !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; + + default: + } + + #if lime + if (displayObject.__isCacheBitmapRender) return false; + #if openfl_disable_cacheasbitmap + return false; + #end + + var colorTransform = ColorTransform.__pool.get(); + colorTransform.__copyFrom(displayObject.__worldColorTransform); + if (renderer.__worldColorTransform != null) colorTransform.__combine(renderer.__worldColorTransform); + var updated = false; + + // TODO: Do not force cacheAsBitmap on OpenGL once Scale-9 is properly supported in Context3DShape + if (displayObject.cacheAsBitmap + || (renderer.__type != OPENGL && !colorTransform.__isDefault(true)) + || (renderer.__type == OPENGL && displayObject.scale9Grid != null)) + { + var rect = null; + + var needRender = (displayObject.__cacheBitmap == null + || (displayObject.__renderDirty && (force || (displayObject.__children != null && displayObject.__children.length > 0))) + || displayObject.opaqueBackground != displayObject.__cacheBitmapBackground); + var softwareDirty = needRender + || (displayObject.__graphics != null && displayObject.__graphics.__softwareDirty) + || !displayObject.__cacheBitmapColorTransform.__equals(colorTransform, true); + var hardwareDirty = needRender || (displayObject.__graphics != null && displayObject.__graphics.__hardwareDirty); + + var renderType = renderer.__type; + + if (softwareDirty || hardwareDirty) + { + #if !openfl_force_gl_cacheasbitmap + if (renderType == OPENGL) + { + if (#if !openfl_disable_gl_cacheasbitmap __shouldCacheHardware(displayObject, null) == false #else true #end) + { + #if (js && html5) + renderType = CANVAS; + #else + renderType = CAIRO; + #end + } + } + #end + + if (softwareDirty && (renderType == CANVAS || renderType == CAIRO)) needRender = true; + if (hardwareDirty && renderType == OPENGL) needRender = true; + } + + var updateTransform = (needRender || !displayObject.__cacheBitmap.__worldTransform.equals(displayObject.__worldTransform)); + var hasFilters = #if !openfl_disable_filters displayObject.__filters != null #else false #end; + + #if !openfl_enable_cacheasbitmap + if (renderer.__type == DOM && !hasFilters) + { + return false; + } + #end + + if (hasFilters && !needRender) + { + for (filter in displayObject.__filters) + { + if (filter.__renderDirty) + { + needRender = true; + break; + } + } + } + + if (displayObject.__cacheBitmapMatrix == null) + { + displayObject.__cacheBitmapMatrix = new Matrix(); + } + + var bitmapMatrix = (displayObject.__cacheAsBitmapMatrix != null ? displayObject.__cacheAsBitmapMatrix : displayObject.__renderTransform); + + if (!needRender + && (bitmapMatrix.a != displayObject.__cacheBitmapMatrix.a + || bitmapMatrix.b != displayObject.__cacheBitmapMatrix.b + || bitmapMatrix.c != displayObject.__cacheBitmapMatrix.c + || bitmapMatrix.d != displayObject.__cacheBitmapMatrix.d)) + { + needRender = true; + } + + if (!needRender + && renderer.__type != OPENGL + && displayObject.__cacheBitmapData != null + && displayObject.__cacheBitmapData.image != null + && displayObject.__cacheBitmapData.image.version < displayObject.__cacheBitmapData.__textureVersion) + { + needRender = true; + } + + // Ensure that cached bitmap is updated after changes to scrollRect + if (!needRender) + { + var current = displayObject; + while (current != null) + { + if (current.scrollRect != null) + { + // TODO: do we need to update transform if scroll rects haven't changed? + updateTransform = true; + break; + } + current = current.parent; + } + } + + displayObject.__cacheBitmapMatrix.copyFrom(bitmapMatrix); + displayObject.__cacheBitmapMatrix.tx = 0; + displayObject.__cacheBitmapMatrix.ty = 0; + + // TODO: Handle dimensions better if object has a scrollRect? + + var bitmapWidth = 0, bitmapHeight = 0; + var filterWidth = 0, filterHeight = 0; + var offsetX = 0., offsetY = 0.; + + #if (openfl_disable_hdpi || openfl_disable_hdpi_cacheasbitmap) + var pixelRatio = 1; + #else + var pixelRatio = __pixelRatio; + #end + + if (updateTransform || needRender) + { + rect = Rectangle.__pool.get(); + + 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; + + 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 (displayObject.__cacheBitmapData != null) + { + if (filterWidth > displayObject.__cacheBitmapData.width || filterHeight > displayObject.__cacheBitmapData.height) + { + bitmapWidth = Math.ceil(Math.max(filterWidth * 1.25, displayObject.__cacheBitmapData.width)); + bitmapHeight = Math.ceil(Math.max(filterHeight * 1.25, displayObject.__cacheBitmapData.height)); + needRender = true; + } + else + { + bitmapWidth = displayObject.__cacheBitmapData.width; + bitmapHeight = displayObject.__cacheBitmapData.height; + } + } + else + { + bitmapWidth = filterWidth; + bitmapHeight = filterHeight; + } + } + + if (needRender) + { + updateTransform = true; + displayObject.__cacheBitmapBackground = displayObject.opaqueBackground; + + 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); + + if (displayObject.__cacheBitmap == null) displayObject.__cacheBitmap = new Bitmap(); + displayObject.__cacheBitmap.__bitmapData = displayObject.__cacheBitmapData; + displayObject.__cacheBitmapRenderer = null; + } + else + { + displayObject.__cacheBitmapData.__fillRect(displayObject.__cacheBitmapData.rect, bitmapColor, allowFramebuffer); + } + + if (needsFill) + { + rect.setTo(0, 0, filterWidth, filterHeight); + displayObject.__cacheBitmapData.__fillRect(rect, fillColor, allowFramebuffer); + } + } + else + { + ColorTransform.__pool.release(colorTransform); + + displayObject.__cacheBitmap = null; + displayObject.__cacheBitmapData = null; + displayObject.__cacheBitmapData2 = null; + displayObject.__cacheBitmapData3 = null; + displayObject.__cacheBitmapRenderer = null; + + if (displayObject.__drawableType == TEXT_FIELD) + { + var textField:TextField = cast displayObject; + if (textField.__cacheBitmap != null) + { + textField.__cacheBitmap.__renderTransform.tx -= textField.__offsetX * pixelRatio; + textField.__cacheBitmap.__renderTransform.ty -= textField.__offsetY * pixelRatio; + } + } + + return true; + } + } + else + { + // Should we retain these longer? + + displayObject.__cacheBitmapData = displayObject.__cacheBitmap.bitmapData; + displayObject.__cacheBitmapData2 = null; + displayObject.__cacheBitmapData3 = null; + } + + if (updateTransform || needRender) + { + displayObject.__cacheBitmap.__worldTransform.copyFrom(displayObject.__worldTransform); + + if (bitmapMatrix == displayObject.__renderTransform) + { + displayObject.__cacheBitmap.__renderTransform.identity(); + displayObject.__cacheBitmap.__renderTransform.scale(1 / pixelRatio, 1 / pixelRatio); + displayObject.__cacheBitmap.__renderTransform.tx = displayObject.__renderTransform.tx + offsetX; + displayObject.__cacheBitmap.__renderTransform.ty = displayObject.__renderTransform.ty + offsetY; + } + else + { + displayObject.__cacheBitmap.__renderTransform.copyFrom(displayObject.__cacheBitmapMatrix); + displayObject.__cacheBitmap.__renderTransform.invert(); + displayObject.__cacheBitmap.__renderTransform.concat(displayObject.__renderTransform); + displayObject.__cacheBitmap.__renderTransform.a *= 1 / pixelRatio; + displayObject.__cacheBitmap.__renderTransform.d *= 1 / pixelRatio; + displayObject.__cacheBitmap.__renderTransform.tx += offsetX; + displayObject.__cacheBitmap.__renderTransform.ty += offsetY; + } + } + + displayObject.__cacheBitmap.smoothing = renderer.__allowSmoothing; + displayObject.__cacheBitmap.__renderable = displayObject.__renderable; + displayObject.__cacheBitmap.__worldAlpha = displayObject.__worldAlpha; + displayObject.__cacheBitmap.__worldBlendMode = displayObject.__worldBlendMode; + displayObject.__cacheBitmap.__worldShader = displayObject.__worldShader; + // displayObject.__cacheBitmap.__scrollRect = displayObject.__scrollRect; + // displayObject.__cacheBitmap.filters = displayObject.filters; + displayObject.__cacheBitmap.mask = displayObject.__mask; + + if (needRender) + { + #if lime + if (displayObject.__cacheBitmapRenderer == null || renderType != displayObject.__cacheBitmapRenderer.__type) + { + if (renderType == OPENGL) + { + displayObject.__cacheBitmapRenderer = new OpenGLRenderer(cast(renderer, OpenGLRenderer).__context3D, displayObject.__cacheBitmapData); + } + else + { + if (displayObject.__cacheBitmapData.image == null) + { + var color = displayObject.opaqueBackground != null ? (0xFF << 24) | displayObject.opaqueBackground : 0; + displayObject.__cacheBitmapData = new BitmapData(bitmapWidth, bitmapHeight, true, color); + displayObject.__cacheBitmap.__bitmapData = displayObject.__cacheBitmapData; + } + + #if (js && html5) + ImageCanvasUtil.convertToCanvas(displayObject.__cacheBitmapData.image); + displayObject.__cacheBitmapRenderer = new CanvasRenderer(displayObject.__cacheBitmapData.image.buffer.__srcContext); + #else + displayObject.__cacheBitmapRenderer = new CairoRenderer(new Cairo(displayObject.__cacheBitmapData.getSurface())); + #end + } + + displayObject.__cacheBitmapRenderer.__worldTransform = new Matrix(); + displayObject.__cacheBitmapRenderer.__worldColorTransform = new ColorTransform(); + } + #else + return false; + #end + + if (displayObject.__cacheBitmapColorTransform == null) displayObject.__cacheBitmapColorTransform = new ColorTransform(); + + displayObject.__cacheBitmapRenderer.__stage = displayObject.stage; + + displayObject.__cacheBitmapRenderer.__allowSmoothing = renderer.__allowSmoothing; + displayObject.__cacheBitmapRenderer.__setBlendMode(NORMAL); + displayObject.__cacheBitmapRenderer.__worldAlpha = 1 / displayObject.__worldAlpha; + + displayObject.__cacheBitmapRenderer.__worldTransform.copyFrom(displayObject.__renderTransform); + displayObject.__cacheBitmapRenderer.__worldTransform.invert(); + displayObject.__cacheBitmapRenderer.__worldTransform.concat(displayObject.__cacheBitmapMatrix); + displayObject.__cacheBitmapRenderer.__worldTransform.tx -= offsetX; + displayObject.__cacheBitmapRenderer.__worldTransform.ty -= offsetY; + displayObject.__cacheBitmapRenderer.__worldTransform.scale(pixelRatio, pixelRatio); + + displayObject.__cacheBitmapRenderer.__pixelRatio = pixelRatio; + + displayObject.__cacheBitmapRenderer.__worldColorTransform.__copyFrom(colorTransform); + displayObject.__cacheBitmapRenderer.__worldColorTransform.__invert(); + + displayObject.__isCacheBitmapRender = true; + + if (displayObject.__cacheBitmapRenderer.__type == OPENGL) + { + var parentRenderer:OpenGLRenderer = cast renderer; + var childRenderer:OpenGLRenderer = cast displayObject.__cacheBitmapRenderer; + + var context = childRenderer.__context3D; + + var cacheRTT = context.__state.renderToTexture; + var cacheRTTDepthStencil = context.__state.renderToTextureDepthStencil; + var cacheRTTAntiAlias = context.__state.renderToTextureAntiAlias; + var cacheRTTSurfaceSelector = context.__state.renderToTextureSurfaceSelector; + + // var cacheFramebuffer = context.__contextState.__currentGLFramebuffer; + + var cacheBlendMode = parentRenderer.__blendMode; + parentRenderer.__suspendClipAndMask(); + childRenderer.__copyShader(parentRenderer); + // childRenderer.__copyState (parentRenderer); + + displayObject.__cacheBitmapData.__setUVRect(context, 0, 0, filterWidth, filterHeight); + childRenderer.__setRenderTarget(displayObject.__cacheBitmapData); + if (displayObject.__cacheBitmapData.image != null) + displayObject.__cacheBitmapData.__textureVersion = displayObject.__cacheBitmapData.image.version + + 1; + + displayObject.__cacheBitmapData.__drawGL(displayObject, childRenderer); + + if (hasFilters) + { + var needSecondBitmapData = true; + var needCopyOfOriginal = false; + + for (filter in displayObject.__filters) + { + // if (filter.__needSecondBitmapData) { + // needSecondBitmapData = true; + // } + if (filter.__preserveObject) + { + needCopyOfOriginal = true; + } + } + + var bitmap = displayObject.__cacheBitmapData; + var bitmap2 = null; + var bitmap3 = null; + + // if (needSecondBitmapData) { + if (displayObject.__cacheBitmapData2 == null + || bitmapWidth > displayObject.__cacheBitmapData2.width + || bitmapHeight > displayObject.__cacheBitmapData2.height) + { + displayObject.__cacheBitmapData2 = new BitmapData(bitmapWidth, bitmapHeight, true, 0); + } + else + { + displayObject.__cacheBitmapData2.fillRect(displayObject.__cacheBitmapData2.rect, 0); + if (displayObject.__cacheBitmapData2.image != null) + { + displayObject.__cacheBitmapData2.__textureVersion = displayObject.__cacheBitmapData2.image.version + 1; + } + } + displayObject.__cacheBitmapData2.__setUVRect(context, 0, 0, filterWidth, filterHeight); + bitmap2 = displayObject.__cacheBitmapData2; + // } else { + // bitmap2 = bitmapData; + // } + + if (needCopyOfOriginal) + { + if (displayObject.__cacheBitmapData3 == null + || bitmapWidth > displayObject.__cacheBitmapData3.width + || bitmapHeight > displayObject.__cacheBitmapData3.height) + { + displayObject.__cacheBitmapData3 = new BitmapData(bitmapWidth, bitmapHeight, true, 0); + } + else + { + displayObject.__cacheBitmapData3.fillRect(displayObject.__cacheBitmapData3.rect, 0); + if (displayObject.__cacheBitmapData3.image != null) + { + displayObject.__cacheBitmapData3.__textureVersion = displayObject.__cacheBitmapData3.image.version + 1; + } + } + displayObject.__cacheBitmapData3.__setUVRect(context, 0, 0, filterWidth, filterHeight); + bitmap3 = displayObject.__cacheBitmapData3; + } + + childRenderer.__setBlendMode(NORMAL); + childRenderer.__worldAlpha = 1; + childRenderer.__worldTransform.identity(); + childRenderer.__worldColorTransform.__identity(); + + // var sourceRect = bitmap.rect; + // if (__tempPoint == null) __tempPoint = new Point (); + // var destPoint = __tempPoint; + var shader, cacheBitmap; + + for (filter in displayObject.__filters) + { + if (filter.__preserveObject) + { + childRenderer.__setRenderTarget(bitmap3); + childRenderer.__renderFilterPass(bitmap, childRenderer.__defaultDisplayShader, filter.__smooth); + } + + for (i in 0...filter.__numShaderPasses) + { + shader = filter.__initShader(childRenderer, i, filter.__preserveObject ? bitmap3 : null); + childRenderer.__setBlendMode(filter.__shaderBlendMode); + childRenderer.__setRenderTarget(bitmap2); + childRenderer.__renderFilterPass(bitmap, shader, filter.__smooth); + + cacheBitmap = bitmap; + bitmap = bitmap2; + bitmap2 = cacheBitmap; + } + + filter.__renderDirty = false; + } + + displayObject.__cacheBitmap.__bitmapData = bitmap; + } + + parentRenderer.__blendMode = NORMAL; + parentRenderer.__setBlendMode(cacheBlendMode); + parentRenderer.__copyShader(childRenderer); + + if (cacheRTT != null) + { + context.setRenderToTexture(cacheRTT, cacheRTTDepthStencil, cacheRTTAntiAlias, cacheRTTSurfaceSelector); + } + else + { + context.setRenderToBackBuffer(); + } + + // context.__bindGLFramebuffer (cacheFramebuffer); + + // parentRenderer.__restoreState (childRenderer); + parentRenderer.__resumeClipAndMask(childRenderer); + parentRenderer.setViewport(); + + displayObject.__cacheBitmapColorTransform.__copyFrom(colorTransform); + } + else + { + #if (js && html5) + displayObject.__cacheBitmapData.__drawCanvas(displayObject, cast displayObject.__cacheBitmapRenderer); + #else + displayObject.__cacheBitmapData.__drawCairo(displayObject, cast displayObject.__cacheBitmapRenderer); + #end + + if (hasFilters) + { + var needSecondBitmapData = false; + var needCopyOfOriginal = false; + + for (filter in displayObject.__filters) + { + if (filter.__needSecondBitmapData) + { + needSecondBitmapData = true; + } + if (filter.__preserveObject) + { + needCopyOfOriginal = true; + } + } + + var bitmap = displayObject.__cacheBitmapData; + var bitmap2 = null; + var bitmap3 = null; + + if (needSecondBitmapData) + { + if (displayObject.__cacheBitmapData2 == null + || displayObject.__cacheBitmapData2.image == null + || bitmapWidth > displayObject.__cacheBitmapData2.width + || bitmapHeight > displayObject.__cacheBitmapData2.height) + { + displayObject.__cacheBitmapData2 = new BitmapData(bitmapWidth, bitmapHeight, true, 0); + } + else + { + displayObject.__cacheBitmapData2.fillRect(displayObject.__cacheBitmapData2.rect, 0); + } + bitmap2 = displayObject.__cacheBitmapData2; + } + else + { + bitmap2 = bitmap; + } + + if (needCopyOfOriginal) + { + if (displayObject.__cacheBitmapData3 == null + || displayObject.__cacheBitmapData3.image == null + || bitmapWidth > displayObject.__cacheBitmapData3.width + || bitmapHeight > displayObject.__cacheBitmapData3.height) + { + displayObject.__cacheBitmapData3 = new BitmapData(bitmapWidth, bitmapHeight, true, 0); + } + else + { + displayObject.__cacheBitmapData3.fillRect(displayObject.__cacheBitmapData3.rect, 0); + } + bitmap3 = displayObject.__cacheBitmapData3; + } + + if (displayObject.__tempPoint == null) displayObject.__tempPoint = new Point(); + var destPoint = displayObject.__tempPoint; + var cacheBitmap, lastBitmap; + + for (filter in displayObject.__filters) + { + if (filter.__preserveObject) + { + bitmap3.copyPixels(bitmap, bitmap.rect, destPoint); + } + + lastBitmap = filter.__applyFilter(bitmap2, bitmap, bitmap.rect, destPoint); + + if (filter.__preserveObject) + { + lastBitmap.draw(bitmap3, null, + displayObject.__objectTransform != null ? displayObject.__objectTransform.__colorTransform : null); + } + filter.__renderDirty = false; + + if (needSecondBitmapData && lastBitmap == bitmap2) + { + cacheBitmap = bitmap; + bitmap = bitmap2; + bitmap2 = cacheBitmap; + } + } + + if (displayObject.__cacheBitmapData != bitmap) + { + // TODO: Fix issue with swapping __cacheBitmap.__bitmapData + // __cacheBitmapData.copyPixels (bitmap, bitmap.rect, destPoint); + + // Adding __cacheBitmapRenderer = null; makes this work + cacheBitmap = displayObject.__cacheBitmapData; + displayObject.__cacheBitmapData = bitmap; + displayObject.__cacheBitmapData2 = cacheBitmap; + displayObject.__cacheBitmap.__bitmapData = displayObject.__cacheBitmapData; + displayObject.__cacheBitmapRenderer = null; + } + + displayObject.__cacheBitmap.__imageVersion = displayObject.__cacheBitmapData.__textureVersion; + } + + displayObject.__cacheBitmapColorTransform.__copyFrom(colorTransform); + + if (!displayObject.__cacheBitmapColorTransform.__isDefault(true)) + { + displayObject.__cacheBitmapColorTransform.alphaMultiplier = 1; + displayObject.__cacheBitmapData.colorTransform(displayObject.__cacheBitmapData.rect, displayObject.__cacheBitmapColorTransform); + } + } + + displayObject.__isCacheBitmapRender = false; + } + + if (updateTransform || needRender) + { + Rectangle.__pool.release(rect); + } + + updated = updateTransform; + } + else if (displayObject.__cacheBitmap != null) + { + if (renderer.__type == DOM) + { + var domRenderer:DOMRenderer = cast renderer; + domRenderer.__renderDrawableClear(displayObject.__cacheBitmap); + } + + displayObject.__cacheBitmap = null; + displayObject.__cacheBitmapData = null; + displayObject.__cacheBitmapData2 = null; + displayObject.__cacheBitmapData3 = null; + displayObject.__cacheBitmapColorTransform = null; + displayObject.__cacheBitmapRenderer = null; + + updated = true; + } + + ColorTransform.__pool.release(colorTransform); + + if (updated && displayObject.__drawableType == TEXT_FIELD) + { + var textField:TextField = cast displayObject; + if (textField.__cacheBitmap != null) + { + textField.__cacheBitmap.__renderTransform.tx -= textField.__offsetX; + textField.__cacheBitmap.__renderTransform.ty -= textField.__offsetY; + } + } + + return updated; + #else + return false; + #end + } +} +#else +typedef DisplayObjectRenderer = Dynamic; +#end