diff --git a/flixel/FlxCamera.hx b/flixel/FlxCamera.hx index c2c92ca4e7..c45ebb893d 100644 --- a/flixel/FlxCamera.hx +++ b/flixel/FlxCamera.hx @@ -10,10 +10,13 @@ import flixel.math.FlxMatrix; import flixel.math.FlxPoint; import flixel.math.FlxRect; import flixel.system.FlxAssets.FlxShader; +import flixel.system.render.FlxCameraView; +import flixel.system.render.quad.FlxQuadView; +import flixel.system.render.blit.FlxBlitView; +import flixel.system.render.blit.FlxBlitRenderer; import flixel.util.FlxAxes; import flixel.util.FlxColor; import flixel.util.FlxDestroyUtil; -import flixel.util.FlxSpriteUtil; import openfl.Vector; import openfl.display.Bitmap; import openfl.display.BitmapData; @@ -21,6 +24,7 @@ import openfl.display.BlendMode; import openfl.display.DisplayObject; import openfl.display.Graphics; import openfl.display.Sprite; +import openfl.display.DisplayObjectContainer; import openfl.filters.BitmapFilter; import openfl.geom.ColorTransform; import openfl.geom.Point; @@ -32,15 +36,9 @@ using flixel.util.FlxColorTransformUtil; * The camera class is used to display the game's visuals. * By default one camera is created automatically, that is the same size as window. * You can add more cameras or even replace the main camera using utilities in `FlxG.cameras`. - * - * Every camera has following display list: - * `flashSprite:Sprite` (which is a container for everything else in the camera, it's added to FlxG.game sprite) - * |-> `_scrollRect:Sprite` (which is used for cropping camera's graphic, mostly in tile render mode) - * |-> `_flashBitmap:Bitmap` (its bitmapData property is buffer BitmapData, this var is used in blit render mode. - * Everything is rendered on buffer in blit render mode) - * |-> `canvas:Sprite` (its graphics is used for rendering objects in tile render mode) - * |-> `debugLayer:Sprite` (this sprite is used in tile render mode for rendering debug info, like bounding boxes) */ +@:allow(flixel.system.render) +@:access(flixel.system.render) class FlxCamera extends FlxBasic { /** @@ -97,6 +95,25 @@ class FlxCamera extends FlxBasic */ public var totalScaleY(default, null):Float; + /** + * Holds various rendering related objects + */ + public var view(default, null):FlxCameraView; + + /** + * This camera's `view`, typed as a `FlxQuadView`. + * + * **NOTE**: May be null depending on the render implementation used. + */ + public var viewQuad(default, null):Null; + + /** + * This camera's `view`, typed as a `FlxBlitView`. + * + * **NOTE**: May be null depending on the render implementation used. + */ + public var viewBlit(default, null):Null; + /** * Tells the camera to use this following style. */ @@ -160,7 +177,10 @@ class FlxCamera extends FlxBasic * The actual `BitmapData` of the camera display itself. * Used in blit render mode, where you can manipulate its pixels for achieving some visual effects. */ - public var buffer:BitmapData; + @:deprecated("buffer is deprecated, use camera.viewBlit.buffer, instead") + public var buffer(get, set):BitmapData; + inline function set_buffer(value:BitmapData):BitmapData return viewBlit.buffer = value; + inline function get_buffer():BitmapData return viewBlit.buffer; /** * The natural background color of the camera, in `AARRGGBB` format. Defaults to `FlxG.cameras.bgColor`. @@ -175,7 +195,10 @@ class FlxCamera extends FlxBasic * * **NOTE:** This field is only used in blit render mode. */ - public var screen:FlxSprite; + @:deprecated("screen is deprecated, use camera.viewBlit.screen, instead") + public var screen(get, set):FlxSprite; + inline function set_screen(value:FlxSprite):FlxSprite return viewBlit.screen = value; + inline function get_screen():FlxSprite return viewBlit.screen; /** * Whether to use alpha blending for the camera's background fill or not. @@ -196,12 +219,20 @@ class FlxCamera extends FlxBasic * * Its position is modified by `updateFlashSpritePosition()` which is called every frame. */ - public var flashSprite:Sprite = new Sprite(); + @:deprecated("flashSprite is deprecated, use camera.display, instead") + public var flashSprite(get, set):Sprite; + inline function set_flashSprite(value:Sprite):Sprite + { + var sprite = FlxG.renderer.method != BLITTING ? viewQuad.flashSprite : viewBlit.flashSprite; + return sprite = value; + } + + inline function get_flashSprite():Sprite return cast view.display; /** * Whether the positions of the objects rendered on this camera are rounded. * If set on individual objects, they ignore the global camera setting. - * Defaults to `false` with `FlxG.renderTile` and to `true` with `FlxG.renderBlit`. + * Defaults to `true` with the blitting renderer and `false` elsewhere. * WARNING: setting this to `false` on blitting targets is very expensive. */ public var pixelPerfectRender:Bool; @@ -317,16 +348,27 @@ class FlxCamera extends FlxBasic */ public var viewBottom(get, never):Float; + /** + * Reference to camera's `view.display`. + */ + public var display(get, never):DisplayObjectContainer; + /** * Helper matrix object. Used in blit render mode when camera's zoom is less than initialZoom * (it is applied to all objects rendered on the camera at such circumstances). */ - var _blitMatrix:FlxMatrix = new FlxMatrix(); + @:deprecated("_blitMatrix is deprecated, use camera.viewBlit.blitMatrix, instead") + var _blitMatrix(get, set):FlxMatrix; + inline function get__blitMatrix():FlxMatrix return viewBlit._blitMatrix; + inline function set__blitMatrix(value:FlxMatrix) return viewBlit._blitMatrix = value; /** * Logical flag for tracking whether to apply _blitMatrix transformation to objects or not. */ - var _useBlitMatrix:Bool = false; + @:deprecated("_useBlitMatrix is deprecated, use camera.viewBlit._useBlitMatrix, instead") + var _useBlitMatrix(get, set):Bool; + inline function get__useBlitMatrix():Bool return viewBlit._useBlitMatrix; + inline function set__useBlitMatrix(value:Bool) return viewBlit._useBlitMatrix = value; /** * The alpha value of this camera display (a number between `0.0` and `1.0`). @@ -365,14 +407,20 @@ class FlxCamera extends FlxBasic * (the area of camera's buffer which should be filled with `bgColor`). * Do not modify it unless you know what are you doing. */ + @:deprecated("_flashRect is deprecated, use camera.viewBlit._flashRect, instead") var _flashRect:Rectangle; + inline function get__flashRect():Rectangle return viewBlit._flashRect; + inline function set__flashRect(value:Rectangle) return viewBlit._flashRect = value; /** * Internal, used in blit render mode in camera's `fill()` method for less garbage creation: * Its coordinates are always `(0,0)`, where camera's buffer filling should start. * Do not modify it unless you know what are you doing. */ + @:deprecated("_flashPoint is deprecated, use FlxBlitRenderer._flashPoint, instead") var _flashPoint:Point = new Point(); + inline function get__flashPoint():Point return cast (FlxG.renderer, FlxBlitRenderer)._flashPoint; + inline function set__flashPoint(value:Point) return cast (FlxG.renderer, FlxBlitRenderer)._flashPoint = value; /** * Internal, used for positioning camera's `flashSprite` on screen. @@ -381,7 +429,10 @@ class FlxCamera extends FlxBasic * Its value depends on camera's size (`width` and `height`), game's `scale` and camera's initial zoom factor. * Do not modify it unless you know what are you doing. */ - var _flashOffset:FlxPoint = FlxPoint.get(); + @:deprecated("_flashOffset is deprecated, use camera.view._flashOffset, instead") + var _flashOffset(get, set):FlxPoint; + inline function get__flashOffset():FlxPoint return view._flashOffset; + inline function set__flashOffset(value:FlxPoint) return view._flashOffset = value; /** * Internal, represents the color of `flash()` special effect. @@ -479,7 +530,10 @@ class FlxCamera extends FlxBasic * Internal helper variable for doing better wipes/fills between renders. * Used it blit render mode only (in `fill()` method). */ - var _fill:BitmapData; + @:deprecated("_fill is deprecated, use camera.viewBlit._fill, instead") + var _fill(get, set):BitmapData; + inline function get__fill():BitmapData return viewBlit._fill; + inline function set__fill(value:BitmapData):BitmapData return viewBlit._fill = value; /** * Internal, used to render buffer to screen space. Used it blit render mode only. @@ -487,19 +541,41 @@ class FlxCamera extends FlxBasic * Its position is modified by `updateInternalSpritePositions()`, which is called on camera's resize and scale events. * It is a child of the `_scrollRect` `Sprite`. */ - var _flashBitmap:Bitmap; + @:deprecated("_flashBitmap is deprecated, use camera.viewBlit._flashBitmap, instead") + var _flashBitmap(get, set):Bitmap; + inline function get__flashBitmap():Bitmap return viewBlit._flashBitmap; + inline function set__flashBitmap(value:Bitmap):Bitmap return viewBlit._flashBitmap = value; /** * Internal sprite, used for correct trimming of camera viewport. * It is a child of `flashSprite`. * Its position is modified by `updateScrollRect()` method, which is called on camera's resize and scale events. */ - var _scrollRect:Sprite = new Sprite(); + @:deprecated("_scrollRect is deprecated, use camera.viewQuad._scrollRect/camera.viewBlit._scrollRect, instead") + var _scrollRect(get, set):Sprite; + inline function get__scrollRect():Sprite + { + return FlxG.renderer.method != BLITTING ? viewQuad._scrollRect : viewBlit._scrollRect; + } + inline function set__scrollRect(value:Sprite):Sprite + { + var scrollRect = FlxG.renderer.method != BLITTING ? viewQuad._scrollRect : viewBlit._scrollRect; + return scrollRect = value; + } /** * Helper rect for `drawTriangles()` visibility checks */ - var _bounds:FlxRect = FlxRect.get(); + @:deprecated("_bounds is deprecated, use FlxBlitRenderer/FlxQuadRender._bounds, instead") + var _bounds(get, set):FlxRect; + inline function get__bounds():FlxRect + { + return untyped FlxG.renderer._bounds; + } + inline function set__bounds(value:FlxRect):FlxRect + { + return untyped FlxG.renderer._bounds = value; + } /** * Sprite used for actual rendering in tile render mode (instead of `_flashBitmap` for blitting). @@ -507,7 +583,10 @@ class FlxCamera extends FlxBasic * It is a child of `_scrollRect` `Sprite` (which trims graphics that should be invisible). * Its position is modified by `updateInternalSpritePositions()`, which is called on camera's resize and scale events. */ - public var canvas:Sprite; + @:deprecated("canvas is deprecated, use camera.viewQuad.canvas, instead") + public var canvas(get, set):Sprite; + inline function set_canvas(value:Sprite):Sprite return viewQuad.canvas = value; + inline function get_canvas():Sprite return viewQuad.canvas; #if FLX_DEBUG /** @@ -516,391 +595,166 @@ class FlxCamera extends FlxBasic * It is a child of `_scrollRect` `Sprite` (which trims graphics that should be invisible). * Its position is modified by `updateInternalSpritePositions()`, which is called on camera's resize and scale events. */ - public var debugLayer:Sprite; + @:deprecated("debugLayer is deprecated, use camera.viewQuad.debugLayer, instead") + public var debugLayer(get, set):Sprite; + inline function set_debugLayer(value:Sprite):Sprite return viewQuad.debugLayer; + inline function get_debugLayer():Sprite return viewQuad.debugLayer; #end - var _helperMatrix:FlxMatrix = new FlxMatrix(); + @:deprecated("_helperMatrix is deprecated, use FlxBlitRenderer/FlxQuadRenderer._helperMatrix, instead") + var _helperMatrix(get, set):FlxMatrix; + inline function get__helperMatrix():FlxMatrix + { + return untyped FlxG.renderer._helperMatrix; + } + inline function set__helperMatrix(value:FlxMatrix):FlxMatrix + { + return untyped FlxG.renderer._helperMatrix = value; + } - var _helperPoint:Point = new Point(); + @:deprecated("_helperPoint is deprecated, use FlxBlitRenderer._helperPoint, instead") + var _helperPoint(get, set):Point; + inline function get__helperPoint():Point + { + return cast(FlxG.renderer, FlxBlitRenderer)._helperPoint; + } + inline function set__helperPoint(value:Point):Point + { + return cast(FlxG.renderer, FlxBlitRenderer)._helperPoint = value; + } /** * Currently used draw stack item */ - var _currentDrawItem:FlxDrawBaseItem; + @:deprecated("_currentDrawItem is deprecated, use camera.viewQuad._currentDrawItem, instead") + var _currentDrawItem(get, set):FlxDrawBaseItem; + inline function get__currentDrawItem():FlxDrawBaseItem return viewQuad._currentDrawItem; + inline function set__currentDrawItem(value:FlxDrawBaseItem):FlxDrawBaseItem return viewQuad._currentDrawItem = value; /** * Pointer to head of stack with draw items */ - var _headOfDrawStack:FlxDrawBaseItem; + @:deprecated("_headOfDrawStack is deprecated, use camera.viewQuad._headOfDrawStack, instead") + var _headOfDrawStack(get, set):FlxDrawBaseItem; + inline function get__headOfDrawStack():FlxDrawBaseItem return viewQuad._headOfDrawStack; + inline function set__headOfDrawStack(value:FlxDrawBaseItem):FlxDrawBaseItem return viewQuad._headOfDrawStack = value; /** * Last draw tiles item */ - var _headTiles:FlxDrawQuadsItem; + @:deprecated("_headTiles is deprecated, use camera.viewQuad._headTiles, instead") + var _headTiles(get, set):FlxDrawQuadsItem; + inline function get__headTiles():FlxDrawQuadsItem return viewQuad._headTiles; + inline function set__headTiles(value:FlxDrawQuadsItem):FlxDrawQuadsItem return viewQuad._headTiles = value; /** * Last draw triangles item */ - var _headTriangles:FlxDrawTrianglesItem; + @:deprecated("_headTriangles is deprecated, use camera.viewQuad._headTriangles, instead") + var _headTriangles(get, set):FlxDrawTrianglesItem; + inline function get__headTriangles():FlxDrawTrianglesItem return viewQuad._headTriangles; + inline function set__headTriangles(value:FlxDrawTrianglesItem):FlxDrawTrianglesItem return viewQuad._headTriangles = value; /** * Draw tiles stack items that can be reused */ - static var _storageTilesHead:FlxDrawQuadsItem; + @:deprecated("_storageTilesHead is deprecated, use FlxQuadView._storageTilesHead, instead") + static var _storageTilesHead(get, set):FlxDrawQuadsItem; + static inline function get__storageTilesHead():FlxDrawQuadsItem return FlxQuadView._storageTilesHead; + static inline function set__storageTilesHead(value:FlxDrawQuadsItem):FlxDrawQuadsItem return FlxQuadView._storageTilesHead = value; /** * Draw triangles stack items that can be reused */ - static var _storageTrianglesHead:FlxDrawTrianglesItem; + @:deprecated("_storageTrianglesHead is deprecated, use FlxQuadView._storageTrianglesHead, instead") + static var _storageTrianglesHead(get, set):FlxDrawTrianglesItem; + static inline function get__storageTrianglesHead():FlxDrawTrianglesItem return FlxQuadView._storageTrianglesHead; + static inline function set__storageTrianglesHead(value:FlxDrawTrianglesItem):FlxDrawTrianglesItem return FlxQuadView._storageTrianglesHead = value; /** * Internal variable, used for visibility checks to minimize `drawTriangles()` calls. */ - static var drawVertices:Vector = new Vector(); + @:deprecated("drawVertices is deprecated, use FlxBlitRenderer.drawVertices, instead") + static var drawVertices(get, set):Vector; + static inline function get_drawVertices():Vector return FlxBlitRenderer.drawVertices; + static inline function set_drawVertices(value:Vector):Vector return FlxBlitRenderer.drawVertices = value; /** * Internal variable, used in blit render mode to render triangles (`drawTriangles()`) on camera's buffer. */ - static var trianglesSprite:Sprite = new Sprite(); + @:deprecated("trianglesSprite is deprecated, use FlxBlitRenderer.trianglesSprite, instead") + static var trianglesSprite(get, set):Sprite; + static inline function get_trianglesSprite():Sprite return FlxBlitRenderer.trianglesSprite; + static inline function set_trianglesSprite(value:Sprite):Sprite return FlxBlitRenderer.trianglesSprite = value; /** * Internal variables, used in blit render mode to draw trianglesSprite on camera's buffer. * Added for less garbage creation. */ - static var renderPoint:FlxPoint = FlxPoint.get(); + @:deprecated("renderPoint is deprecated, use FlxBlitRenderer.renderPoint, instead") + static var renderPoint(get, set):FlxPoint; + static inline function get_renderPoint():FlxPoint return FlxBlitRenderer.renderPoint; + static inline function set_renderPoint(value:FlxPoint):FlxPoint return FlxBlitRenderer.renderPoint = value; - static var renderRect:FlxRect = FlxRect.get(); + @:deprecated("renderRect is deprecated, use FlxBlitRenderer.renderRect, instead") + static var renderRect(get, set):FlxRect; + static inline function get_renderRect():FlxRect return FlxBlitRenderer.renderRect; + static inline function set_renderRect(value:FlxRect):FlxRect return FlxBlitRenderer.renderRect = value; @:noCompletion public function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader) { - #if FLX_RENDER_TRIANGLE - return startTrianglesBatch(graphic, smooth, colored, blend); - #else - var itemToReturn = null; - - if (_currentDrawItem != null - && _currentDrawItem.type == FlxDrawItemType.TILES - && _headTiles.graphics == graphic - && _headTiles.colored == colored - && _headTiles.hasColorOffsets == hasColorOffsets - && _headTiles.blend == blend - && _headTiles.antialiasing == smooth - && _headTiles.shader == shader) - { - return _headTiles; - } - - if (_storageTilesHead != null) - { - itemToReturn = _storageTilesHead; - var newHead = _storageTilesHead.nextTyped; - itemToReturn.reset(); - _storageTilesHead = newHead; - } - else - { - itemToReturn = new FlxDrawQuadsItem(); - } - - // TODO: catch this error when the dev actually messes up, not in the draw phase - if (graphic.isDestroyed) - throw 'Cannot queue ${graphic.key}. This sprite was destroyed.'; - - itemToReturn.graphics = graphic; - itemToReturn.antialiasing = smooth; - itemToReturn.colored = colored; - itemToReturn.hasColorOffsets = hasColorOffsets; - itemToReturn.blend = blend; - itemToReturn.shader = shader; - - itemToReturn.nextTyped = _headTiles; - _headTiles = itemToReturn; - - if (_headOfDrawStack == null) - { - _headOfDrawStack = itemToReturn; - } - - if (_currentDrawItem != null) - { - _currentDrawItem.next = itemToReturn; - } - - _currentDrawItem = itemToReturn; - - return itemToReturn; - #end + return viewQuad.startQuadBatch(graphic, colored, hasColorOffsets, blend, smooth, shader); } @:noCompletion public function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader):FlxDrawTrianglesItem { - if (_currentDrawItem != null - && _currentDrawItem.type == FlxDrawItemType.TRIANGLES - && _headTriangles.graphics == graphic - && _headTriangles.antialiasing == smoothing - && _headTriangles.colored == isColored - && _headTriangles.blend == blend - && _headTriangles.hasColorOffsets == hasColorOffsets - && _headTriangles.shader == shader - ) - { - return _headTriangles; - } - - return getNewDrawTrianglesItem(graphic, smoothing, isColored, blend, hasColorOffsets, shader); + return viewQuad.startTrianglesBatch(graphic, smoothing, isColored, blend, hasColorOffsets, shader); } @:noCompletion public function getNewDrawTrianglesItem(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader):FlxDrawTrianglesItem { - var itemToReturn:FlxDrawTrianglesItem = null; - - if (_storageTrianglesHead != null) - { - itemToReturn = _storageTrianglesHead; - var newHead:FlxDrawTrianglesItem = _storageTrianglesHead.nextTyped; - itemToReturn.reset(); - _storageTrianglesHead = newHead; - } - else - { - itemToReturn = new FlxDrawTrianglesItem(); - } - - itemToReturn.graphics = graphic; - itemToReturn.antialiasing = smoothing; - itemToReturn.colored = isColored; - itemToReturn.blend = blend; - itemToReturn.hasColorOffsets = hasColorOffsets; - itemToReturn.shader = shader; - - itemToReturn.nextTyped = _headTriangles; - _headTriangles = itemToReturn; - - if (_headOfDrawStack == null) - { - _headOfDrawStack = itemToReturn; - } - - if (_currentDrawItem != null) - { - _currentDrawItem.next = itemToReturn; - } - - _currentDrawItem = itemToReturn; - - return itemToReturn; + return viewQuad.getNewDrawTrianglesItem(graphic, smoothing, isColored, blend, hasColorOffsets, shader); } @:allow(flixel.system.frontEnds.CameraFrontEnd) - function clearDrawStack():Void + @:deprecated("camera.render() is deprecated, use FlxG.renderer.render() instead.") + function render():Void { - var currTiles = _headTiles; - var newTilesHead; - - while (currTiles != null) - { - newTilesHead = currTiles.nextTyped; - currTiles.reset(); - currTiles.nextTyped = _storageTilesHead; - _storageTilesHead = currTiles; - currTiles = newTilesHead; - } - - var currTriangles:FlxDrawTrianglesItem = _headTriangles; - var newTrianglesHead:FlxDrawTrianglesItem; - - while (currTriangles != null) - { - newTrianglesHead = currTriangles.nextTyped; - currTriangles.reset(); - currTriangles.nextTyped = _storageTrianglesHead; - _storageTrianglesHead = currTriangles; - currTriangles = newTrianglesHead; - } - - _currentDrawItem = null; - _headOfDrawStack = null; - _headTiles = null; - _headTriangles = null; + FlxG.renderer.begin(this); + FlxG.renderer.render(); } @:allow(flixel.system.frontEnds.CameraFrontEnd) - function render():Void + function clearDrawStack():Void { - flashSprite.filters = filtersEnabled ? filters : null; - - var currItem:FlxDrawBaseItem = _headOfDrawStack; - while (currItem != null) - { - currItem.render(this); - currItem = currItem.next; - } + viewQuad.clearDrawStack(); } + @:deprecated("camera.drawPixels() is deprecated, use FlxG.renderer.drawPixels() instead.") public function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader):Void { - if (FlxG.renderBlit) - { - _helperMatrix.copyFrom(matrix); - - if (_useBlitMatrix) - { - _helperMatrix.concat(_blitMatrix); - buffer.draw(pixels, _helperMatrix, null, null, null, (smoothing || antialiasing)); - } - else - { - _helperMatrix.translate(-viewMarginLeft, -viewMarginTop); - buffer.draw(pixels, _helperMatrix, null, blend, null, (smoothing || antialiasing)); - } - } - else - { - var isColored = (transform != null #if !html5 && transform.hasRGBMultipliers() #end); - var hasColorOffsets:Bool = (transform != null && transform.hasRGBAOffsets()); - - #if FLX_RENDER_TRIANGLE - final drawItem:FlxDrawTrianglesItem = startTrianglesBatch(frame.parent, smoothing, isColored, blend, hasColorOffsets, shader); - #else - final drawItem:FlxDrawQuadsItem = startQuadBatch(frame.parent, isColored, hasColorOffsets, blend, smoothing, shader); - #end - drawItem.addQuad(frame, matrix, transform); - } + FlxG.renderer.begin(this); + FlxG.renderer.drawPixels(frame, pixels, matrix, transform, blend, smoothing, shader); } + @:deprecated("camera.copyPixels() is deprecated, use FlxG.renderer.copyPixels() instead.") public function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader):Void { - if (FlxG.renderBlit) - { - if (pixels != null) - { - if (_useBlitMatrix) - { - _helperMatrix.identity(); - _helperMatrix.translate(destPoint.x, destPoint.y); - _helperMatrix.concat(_blitMatrix); - buffer.draw(pixels, _helperMatrix, null, null, null, (smoothing || antialiasing)); - } - else - { - _helperPoint.x = destPoint.x - Std.int(viewMarginLeft); - _helperPoint.y = destPoint.y - Std.int(viewMarginTop); - buffer.copyPixels(pixels, sourceRect, _helperPoint, null, null, true); - } - } - else if (frame != null) - { - // TODO: fix this case for zoom less than initial zoom... - frame.paint(buffer, destPoint, true); - } - } - else - { - _helperMatrix.identity(); - _helperMatrix.translate(destPoint.x + frame.offset.x, destPoint.y + frame.offset.y); - - var isColored = (transform != null && transform.hasRGBMultipliers()); - var hasColorOffsets:Bool = (transform != null && transform.hasRGBAOffsets()); - - #if FLX_RENDER_TRIANGLE - final drawItem:FlxDrawTrianglesItem = startTrianglesBatch(frame.parent, smoothing, isColored, blend, hasColorOffsets, shader); - #else - final drawItem:FlxDrawQuadsItem = startQuadBatch(frame.parent, isColored, hasColorOffsets, blend, smoothing, shader); - #end - drawItem.addQuad(frame, _helperMatrix, transform); - } + FlxG.renderer.begin(this); + FlxG.renderer.copyPixels(frame, pixels, sourceRect, destPoint, transform, blend, smoothing, shader); } + @:deprecated("camera.drawTriangles() is deprecated, use FlxG.renderer.drawTriangles() instead.") public function drawTriangles(graphic:FlxGraphic, vertices:DrawData, indices:DrawData, uvtData:DrawData, ?colors:DrawData, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader):Void { - final cameraBounds = _bounds.set(viewMarginLeft, viewMarginTop, viewWidth, viewHeight); - - if (FlxG.renderBlit) - { - if (position == null) - position = renderPoint.zero(); - - var verticesLength:Int = vertices.length; - var currentVertexPosition:Int = 0; - - var tempX:Float, tempY:Float; - var i:Int = 0; - var bounds = renderRect.set(); - drawVertices.splice(0, drawVertices.length); - - while (i < verticesLength) - { - tempX = position.x + vertices[i]; - tempY = position.y + vertices[i + 1]; - - drawVertices[currentVertexPosition++] = tempX; - drawVertices[currentVertexPosition++] = tempY; - - if (i == 0) - { - bounds.set(tempX, tempY, 0, 0); - } - else - { - FlxDrawTrianglesItem.inflateBounds(bounds, tempX, tempY); - } - - i += 2; - } - - position.putWeak(); - - if (!cameraBounds.overlaps(bounds)) - { - drawVertices.splice(drawVertices.length - verticesLength, verticesLength); - } - else - { - trianglesSprite.graphics.clear(); - trianglesSprite.graphics.beginBitmapFill(graphic.bitmap, null, repeat, smoothing); - trianglesSprite.graphics.drawTriangles(drawVertices, indices, uvtData); - trianglesSprite.graphics.endFill(); - - // TODO: check this block of code for cases, when zoom < 1 (or initial zoom?)... - if (_useBlitMatrix) - _helperMatrix.copyFrom(_blitMatrix); - else - { - _helperMatrix.identity(); - _helperMatrix.translate(-viewMarginLeft, -viewMarginTop); - } - - buffer.draw(trianglesSprite, _helperMatrix, transform); - - #if FLX_DEBUG - if (FlxG.debugger.drawDebug) - { - var gfx:Graphics = FlxSpriteUtil.flashGfx; - gfx.clear(); - gfx.lineStyle(1, FlxColor.BLUE, 0.5); - gfx.drawTriangles(drawVertices, indices); - buffer.draw(FlxSpriteUtil.flashGfxSprite, _helperMatrix); - } - #end - // End of TODO... - } - - bounds.put(); - } - else - { - final isColored = (colors != null && colors.length != 0) || (transform != null && transform.hasRGBMultipliers()); - final hasColorOffsets = (transform != null && transform.hasRGBAOffsets()); - - final drawItem = startTrianglesBatch(graphic, smoothing, isColored, blend, hasColorOffsets, shader); - drawItem.addTriangles(vertices, indices, uvtData, colors, position, cameraBounds, transform); - } + FlxG.renderer.begin(this); + FlxG.renderer.drawTriangles(graphic, vertices, indices, uvtData, colors, position, blend, repeat, smoothing, transform, shader); } /** @@ -908,22 +762,9 @@ class FlxCamera extends FlxBasic * @param rect rectangle to prepare for rendering * @return transformed rectangle with respect to camera's zoom factor */ - function transformRect(rect:FlxRect):FlxRect + inline function transformRect(rect:FlxRect):FlxRect { - if (FlxG.renderBlit) - { - rect.offset(-viewMarginLeft, -viewMarginTop); - - if (_useBlitMatrix) - { - rect.x *= zoom; - rect.y *= zoom; - rect.width *= zoom; - rect.height *= zoom; - } - } - - return rect; + return view.transformRect(rect); } /** @@ -931,17 +772,9 @@ class FlxCamera extends FlxBasic * @param point point to prepare for rendering * @return transformed point with respect to camera's zoom factor */ - function transformPoint(point:FlxPoint):FlxPoint + inline function transformPoint(point:FlxPoint):FlxPoint { - if (FlxG.renderBlit) - { - point.subtract(viewMarginLeft, viewMarginTop); - - if (_useBlitMatrix) - point.scale(zoom); - } - - return point; + return view.transformPoint(point); } /** @@ -951,10 +784,7 @@ class FlxCamera extends FlxBasic */ inline function transformVector(vector:FlxPoint):FlxPoint { - if (FlxG.renderBlit && _useBlitMatrix) - vector.scale(zoom); - - return vector; + return view.transformVector(vector); } /** @@ -964,18 +794,9 @@ class FlxCamera extends FlxBasic * @param object display object to apply transformations to. * @return transformed object. */ - function transformObject(object:DisplayObject):DisplayObject + inline function transformObject(object:DisplayObject):DisplayObject { - object.scaleX *= totalScaleX; - object.scaleY *= totalScaleY; - - object.x -= scroll.x * totalScaleX; - object.y -= scroll.y * totalScaleY; - - object.x -= 0.5 * width * (scaleX - initialZoom) * FlxG.scaleMode.scale.x; - object.y -= 0.5 * height * (scaleY - initialZoom) * FlxG.scaleMode.scale.y; - - return object; + return view.transformObject(object); } /** @@ -1006,33 +827,14 @@ class FlxCamera extends FlxBasic this.width = width; this.height = height; - _flashRect = new Rectangle(0, 0, width, height); - flashSprite.addChild(_scrollRect); - _scrollRect.scrollRect = new Rectangle(); + view = FlxCameraView.create(this); + if (view is FlxQuadView) + viewQuad = cast view; + else if (view is FlxBlitView) + viewBlit = cast view; - pixelPerfectRender = FlxG.renderBlit; - - if (FlxG.renderBlit) - { - screen = new FlxSprite(); - buffer = new BitmapData(width, height, true, 0); - screen.pixels = buffer; - screen.origin.zero(); - _flashBitmap = new Bitmap(buffer); - _scrollRect.addChild(_flashBitmap); - _fill = new BitmapData(width, height, true, FlxColor.TRANSPARENT); - } - else - { - canvas = new Sprite(); - _scrollRect.addChild(canvas); - - #if FLX_DEBUG - debugLayer = new Sprite(); - _scrollRect.addChild(debugLayer); - #end - } + pixelPerfectRender = FlxG.renderer.method == BLITTING; set_color(FlxColor.WHITE); @@ -1052,53 +854,13 @@ class FlxCamera extends FlxBasic */ override public function destroy():Void { - FlxDestroyUtil.removeChild(flashSprite, _scrollRect); + view.destroy(); - if (FlxG.renderBlit) - { - FlxDestroyUtil.removeChild(_scrollRect, _flashBitmap); - screen = FlxDestroyUtil.destroy(screen); - buffer = null; - _flashBitmap = null; - _fill = FlxDestroyUtil.dispose(_fill); - } - else - { - #if FLX_DEBUG - FlxDestroyUtil.removeChild(_scrollRect, debugLayer); - debugLayer = null; - #end - - FlxDestroyUtil.removeChild(_scrollRect, canvas); - if (canvas != null) - { - for (i in 0...canvas.numChildren) - { - canvas.removeChildAt(0); - } - canvas = null; - } - - if (_headOfDrawStack != null) - { - clearDrawStack(); - } - - _blitMatrix = null; - _helperMatrix = null; - _helperPoint = null; - } - - _bounds = FlxDestroyUtil.put(_bounds); scroll = FlxDestroyUtil.put(scroll); targetOffset = FlxDestroyUtil.put(targetOffset); deadzone = FlxDestroyUtil.put(deadzone); target = null; - flashSprite = null; - _scrollRect = null; - _flashRect = null; - _flashPoint = null; _fxFlashComplete = null; _fxFadeComplete = null; _fxShakeComplete = null; @@ -1315,6 +1077,9 @@ class FlxCamera extends FlxBasic } else { + var offsetX:Float = 0; + var offsetY:Float = 0; + final pixelPerfect = pixelPerfectShake == null ? pixelPerfectRender : pixelPerfectShake; if (_fxShakeAxes.x) { @@ -1322,7 +1087,7 @@ class FlxCamera extends FlxBasic if (pixelPerfect) shakePixels = Math.round(shakePixels); - flashSprite.x += shakePixels * zoom * FlxG.scaleMode.scale.x; + offsetX = shakePixels * zoom * FlxG.scaleMode.scale.x; } if (_fxShakeAxes.y) @@ -1331,8 +1096,10 @@ class FlxCamera extends FlxBasic if (pixelPerfect) shakePixels = Math.round(shakePixels); - flashSprite.y += shakePixels * zoom * FlxG.scaleMode.scale.y; + offsetY = shakePixels * zoom * FlxG.scaleMode.scale.y; } + + view.offsetView(offsetX, offsetY); } } } @@ -1343,11 +1110,8 @@ class FlxCamera extends FlxBasic */ function updateFlashSpritePosition():Void { - if (flashSprite != null) - { - flashSprite.x = x * FlxG.scaleMode.scale.x + _flashOffset.x; - flashSprite.y = y * FlxG.scaleMode.scale.y + _flashOffset.y; - } + if (view != null) + view.updatePosition(); } /** @@ -1356,8 +1120,8 @@ class FlxCamera extends FlxBasic */ function updateFlashOffset():Void { - _flashOffset.x = width * 0.5 * FlxG.scaleMode.scale.x * initialZoom; - _flashOffset.y = height * 0.5 * FlxG.scaleMode.scale.y * initialZoom; + if (view != null) + view.updateOffset(); } /** @@ -1370,20 +1134,8 @@ class FlxCamera extends FlxBasic */ function updateScrollRect():Void { - var rect:Rectangle = (_scrollRect != null) ? _scrollRect.scrollRect : null; - - if (rect != null) - { - rect.x = rect.y = 0; - - rect.width = width * initialZoom * FlxG.scaleMode.scale.x; - rect.height = height * initialZoom * FlxG.scaleMode.scale.y; - - _scrollRect.scrollRect = rect; - - _scrollRect.x = -0.5 * rect.width; - _scrollRect.y = -0.5 * rect.height; - } + if (view != null) + view.updateScrollRect(); } /** @@ -1394,36 +1146,8 @@ class FlxCamera extends FlxBasic */ function updateInternalSpritePositions():Void { - if (FlxG.renderBlit) - { - if (_flashBitmap != null) - { - _flashBitmap.x = 0; - _flashBitmap.y = 0; - } - } - else - { - if (canvas != null) - { - canvas.x = -0.5 * width * (scaleX - initialZoom) * FlxG.scaleMode.scale.x; - canvas.y = -0.5 * height * (scaleY - initialZoom) * FlxG.scaleMode.scale.y; - - canvas.scaleX = totalScaleX; - canvas.scaleY = totalScaleY; - - #if FLX_DEBUG - if (debugLayer != null) - { - debugLayer.x = canvas.x; - debugLayer.y = canvas.y; - - debugLayer.scaleX = totalScaleX; - debugLayer.scaleY = totalScaleY; - } - #end - } - } + if (view != null) + view.updateInternals(); } /** @@ -1638,105 +1362,58 @@ class FlxCamera extends FlxBasic /** * Fill the camera with the specified color. * - * @param Color The color to fill with in `0xAARRGGBB` hex format. - * @param BlendAlpha Whether to blend the alpha value or just wipe the previous contents. Default is `true`. + * @param color The color to fill with in `0xAARRGGBB` hex format. + * @param blendAlpha Whether to blend the alpha value or just wipe the previous contents. Default is `true`. */ - public function fill(Color:FlxColor, BlendAlpha:Bool = true, FxAlpha:Float = 1.0, ?graphics:Graphics):Void + @:deprecated("camera.fill() is deprecated, use FlxG.renderer.fill() instead.") + public function fill(color:FlxColor, blendAlpha:Bool = true, fxAlpha:Float = 1.0, ?graphics:Graphics):Void { - if (FlxG.renderBlit) - { - if (BlendAlpha) - { - _fill.fillRect(_flashRect, Color); - buffer.copyPixels(_fill, _flashRect, _flashPoint, null, null, BlendAlpha); - } - else - { - buffer.fillRect(_flashRect, Color); - } - } - else - { - final targetGraphics = (graphics == null) ? canvas.graphics : graphics; - - targetGraphics.overrideBlendMode(null); - targetGraphics.beginFill(Color, FxAlpha); - // i'm drawing rect with these parameters to avoid light lines at the top and left of the camera, - // which could appear while cameras fading - targetGraphics.drawRect(viewMarginLeft - 1, viewMarginTop - 1, viewWidth + 2, viewHeight + 2); - targetGraphics.endFill(); - } + color.alphaFloat = fxAlpha; + + FlxG.renderer.begin(this); + + if (viewQuad != null && graphics != null) + viewQuad.targetGraphics = graphics; + + FlxG.renderer.fill(color, blendAlpha); } /** * Internal helper function, handles the actual drawing of all the special effects. */ - @:allow(flixel.system.frontEnds.CameraFrontEnd) + @:allow(flixel.system.render.FlxCameraView) function drawFX():Void { + FlxG.renderer.begin(this); + // Draw the "flash" special effect onto the buffer if (_fxFlashAlpha > 0.0) { - if (FlxG.renderBlit) - { - var color = _fxFlashColor; - color.alphaFloat *= _fxFlashAlpha; - fill(color); - } - else - { - final alpha = _fxFlashColor.alphaFloat * _fxFlashAlpha; - fill(_fxFlashColor.rgb, true, alpha, canvas.graphics); - } + var color = _fxFlashColor; + color.alphaFloat *= _fxFlashAlpha; + FlxG.renderer.fill(color); } // Draw the "fade" special effect onto the buffer if (_fxFadeAlpha > 0.0) { - if (FlxG.renderBlit) - { - var color = _fxFadeColor; - color.alphaFloat *= _fxFadeAlpha; - fill(color); - } - else - { - final alpha = _fxFadeColor.alphaFloat * _fxFadeAlpha; - fill(_fxFadeColor.rgb, true, alpha, canvas.graphics); - } + var color = _fxFadeColor; + color.alphaFloat *= _fxFadeAlpha; + FlxG.renderer.fill(color); } } - @:allow(flixel.system.frontEnds.CameraFrontEnd) + @:deprecated("checkResize() is deprecated") function checkResize():Void { - if (FlxG.renderBlit) - { - if (width != buffer.width || height != buffer.height) - { - var oldBuffer:FlxGraphic = screen.graphic; - buffer = new BitmapData(width, height, true, 0); - screen.pixels = buffer; - screen.origin.zero(); - _flashBitmap.bitmapData = buffer; - _flashRect.width = width; - _flashRect.height = height; - _fill = FlxDestroyUtil.dispose(_fill); - _fill = new BitmapData(width, height, true, FlxColor.TRANSPARENT); - FlxG.bitmap.removeIfNoUse(oldBuffer); - } - - updateBlitMatrix(); - } + if (FlxG.renderer.method == BLITTING) + viewBlit.checkResize(); } + @:deprecated("updateBlitMatrix() is deprecated, use camera.viewBlit.updateBlitMatrix(), instead") inline function updateBlitMatrix():Void { - _blitMatrix.identity(); - _blitMatrix.translate(-viewMarginLeft, -viewMarginTop); - _blitMatrix.scale(scaleX, scaleY); - - _useBlitMatrix = (scaleX < initialZoom) || (scaleY < initialZoom); + viewBlit.updateBlitMatrix(); } /** @@ -2142,24 +1819,7 @@ class FlxCamera extends FlxBasic totalScaleX = scaleX * FlxG.scaleMode.scale.x; totalScaleY = scaleY * FlxG.scaleMode.scale.y; - if (FlxG.renderBlit) - { - updateBlitMatrix(); - - if (_useBlitMatrix) - { - _flashBitmap.scaleX = initialZoom * FlxG.scaleMode.scale.x; - _flashBitmap.scaleY = initialZoom * FlxG.scaleMode.scale.y; - } - else - { - _flashBitmap.scaleX = totalScaleX; - _flashBitmap.scaleY = totalScaleY; - } - } - - calcMarginX(); - calcMarginY(); + view.updateScale(); updateScrollRect(); updateInternalSpritePositions(); @@ -2220,6 +1880,7 @@ class FlxCamera extends FlxBasic if (width != Value && Value > 0) { width = Value; + calcMarginX(); updateFlashOffset(); updateScrollRect(); @@ -2235,6 +1896,7 @@ class FlxCamera extends FlxBasic if (height != Value && Value > 0) { height = Value; + calcMarginY(); updateFlashOffset(); updateScrollRect(); @@ -2252,69 +1914,32 @@ class FlxCamera extends FlxBasic return zoom; } - function set_alpha(Alpha:Float):Float + function set_alpha(alpha:Float):Float { - alpha = FlxMath.bound(Alpha, 0, 1); - if (FlxG.renderBlit) - { - _flashBitmap.alpha = Alpha; - } - else - { - canvas.alpha = Alpha; - } - return Alpha; + this.alpha = FlxMath.bound(alpha, 0, 1); + view.alpha = alpha; + return alpha; } - function set_angle(Angle:Float):Float + function set_angle(angle:Float):Float { - angle = Angle; - flashSprite.rotation = Angle; - return Angle; + this.angle = angle; + view.angle = angle; + return angle; } - function set_color(Color:FlxColor):FlxColor + function set_color(color:FlxColor):FlxColor { - color = Color; - var colorTransform:ColorTransform; - - if (FlxG.renderBlit) - { - if (_flashBitmap == null) - { - return Color; - } - colorTransform = _flashBitmap.transform.colorTransform; - } - else - { - colorTransform = canvas.transform.colorTransform; - } - - colorTransform.redMultiplier = color.redFloat; - colorTransform.greenMultiplier = color.greenFloat; - colorTransform.blueMultiplier = color.blueFloat; - - if (FlxG.renderBlit) - { - _flashBitmap.transform.colorTransform = colorTransform; - } - else - { - canvas.transform.colorTransform = colorTransform; - } - - return Color; + this.color = color; + view.color = color; + return color; } - function set_antialiasing(Antialiasing:Bool):Bool + function set_antialiasing(antialiasing:Bool):Bool { - antialiasing = Antialiasing; - if (FlxG.renderBlit) - { - _flashBitmap.smoothing = Antialiasing; - } - return Antialiasing; + this.antialiasing = antialiasing; + view.antialiasing = antialiasing; + return antialiasing; } function set_x(x:Float):Float @@ -2333,10 +1958,7 @@ class FlxCamera extends FlxBasic override function set_visible(visible:Bool):Bool { - if (flashSprite != null) - { - flashSprite.visible = visible; - } + view.visible = visible; return this.visible = visible; } @@ -2419,6 +2041,11 @@ class FlxCamera extends FlxBasic { return scroll.y + viewMarginBottom; } + + inline function get_display():DisplayObjectContainer + { + return view.display; + } /** * Do not use the following fields! They only exists because FlxCamera extends FlxBasic, @@ -2439,7 +2066,6 @@ class FlxCamera extends FlxBasic @:deprecated("don't reference camera.cameras") @:noCompletion override function set_cameras(value:Array):Array throw "don't reference camera.cameras"; - } enum FlxCameraFollowStyle diff --git a/flixel/FlxG.hx b/flixel/FlxG.hx index 99559cddc7..7229b2fa6a 100644 --- a/flixel/FlxG.hx +++ b/flixel/FlxG.hx @@ -1,5 +1,6 @@ package flixel; +import flixel.system.render.FlxRenderer; import flixel.math.FlxMath; import flixel.math.FlxRandom; import flixel.math.FlxRect; @@ -143,10 +144,33 @@ class FlxG */ public static var onMobile(get, never):Bool; - public static var renderMethod(default, null):FlxRenderMethod; + @:deprecated("renderMethod is deprecated, use FlxG.render.method, instead.") + public static var renderMethod(get, null):flixel.system.render.FlxRenderer.FlxRenderMethod; + @:noCompletion static inline function get_renderMethod():flixel.system.render.FlxRenderer.FlxRenderMethod + { + return FlxG.renderer.method; + } + + @:deprecated("renderBlit is deprecated, compare against FlxG.render.method, instead.") + public static var renderBlit(get, never):Bool; + @:noCompletion static inline function get_renderBlit():Bool + { + return FlxG.renderer.method == BLITTING; + } + + @:deprecated("renderTile is deprecated, compare against FlxG.render.method, instead.") + public static var renderTile(get, never):Bool; + @:noCompletion static inline function get_renderTile():Bool + { + return FlxG.renderer.method != BLITTING; + } - public static var renderBlit(default, null):Bool; - public static var renderTile(default, null):Bool; + /** + * The global renderer instance. + * + * @see `FlxRenderer` + */ + public static var renderer(default, null):FlxRenderer; /** * Represents the amount of time in seconds that passed since last frame. @@ -541,10 +565,6 @@ class FlxG FlxG.height = height; initRenderMethod(); - #if FLX_OPENGL_AVAILABLE - // Query once when window is created and cache for later - bitmap.get_maxTextureSize(); - #end FlxG.initialWidth = width; FlxG.initialHeight = height; @@ -590,28 +610,8 @@ class FlxG static function initRenderMethod():Void { - #if !flash - renderMethod = switch (stage.window.context.type) - { - case OPENGL, OPENGLES, WEBGL: DRAW_TILES; - default: BLITTING; - } - #else - #if web - renderMethod = BLITTING; - #else - renderMethod = DRAW_TILES; - #end - #end - - #if air - renderMethod = BLITTING; - #end - - renderBlit = renderMethod == BLITTING; - renderTile = renderMethod == DRAW_TILES; - - FlxObject.defaultPixelPerfectPosition = renderBlit; + renderer = FlxRenderer.create(); + FlxObject.defaultPixelPerfectPosition = FlxG.renderer.method == BLITTING; } #if FLX_SAVE @@ -750,8 +750,5 @@ class FlxG } } -enum FlxRenderMethod -{ - DRAW_TILES; - BLITTING; -} +@:deprecated("FlxG.FlxRenderMethod is deprecated, use FlxRenderer.FlxRenderMethod instead") +typedef FlxRenderMethod = flixel.system.render.FlxRenderer.FlxRenderMethod; diff --git a/flixel/FlxGame.hx b/flixel/FlxGame.hx index 6f9eb08b3b..9a6af108ce 100644 --- a/flixel/FlxGame.hx +++ b/flixel/FlxGame.hx @@ -1,6 +1,6 @@ package flixel; -import flixel.graphics.tile.FlxDrawBaseItem; +import flixel.system.render.FlxRenderer; import flixel.system.FlxSplash; import flixel.util.FlxArrayUtil; import flixel.util.FlxDestroyUtil; @@ -803,10 +803,9 @@ class FlxGame extends Sprite FlxG.signals.preDraw.dispatch(); - if (FlxG.renderTile) - FlxDrawBaseItem.drawCalls = 0; + FlxRenderer.totalDrawCalls = 0; - FlxG.cameras.lock(); + FlxG.cameras.clear(); if (FlxG.plugins.drawOnTop) { @@ -819,17 +818,15 @@ class FlxGame extends Sprite _state.draw(); } - if (FlxG.renderTile) - { - FlxG.cameras.render(); + FlxG.cameras.render(); + if (FlxG.renderer.method != BLITTING) + { #if FLX_DEBUG - debugger.stats.drawCalls(FlxDrawBaseItem.drawCalls); + debugger.stats.drawCalls(FlxRenderer.totalDrawCalls); #end } - FlxG.cameras.unlock(); - FlxG.signals.postDraw.dispatch(); #if FLX_DEBUG diff --git a/flixel/FlxObject.hx b/flixel/FlxObject.hx index 4549076555..936875fc43 100644 --- a/flixel/FlxObject.hx +++ b/flixel/FlxObject.hx @@ -1308,7 +1308,7 @@ class FlxObject extends FlxBasic return; final rect = getBoundingBox(camera); - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { final view = camera.getViewMarginRect(); view.pad(2); @@ -1318,18 +1318,27 @@ class FlxObject extends FlxBasic if (rect.width > 0 && rect.height > 0) { - final gfx = beginDrawDebug(camera); - drawDebugBoundingBox(gfx, rect, allowCollisions, immovable); - endDrawDebug(camera); + FlxG.renderer.beginDrawDebug(camera); + drawDebugBoundingBox(rect, allowCollisions); + FlxG.renderer.endDrawDebug(); } } - function drawDebugBoundingBox(gfx:Graphics, rect:FlxRect, allowCollisions:FlxDirectionFlags, partial:Bool) + @:deprecated("drawDebugBoundingBox(gfx, rect, allowCollisions, partial) is deprecated. Use drawDebugBoundingBox(rect, allowCollisions) instead.") + overload extern inline function drawDebugBoundingBox(gfx:Graphics, rect:FlxRect, allowCollisions:FlxDirectionFlags, partial:Bool) { // Find the color to use final color = getDebugBoundingBoxColor(allowCollisions); drawDebugBoundingBoxColor(gfx, rect, color); } + + overload extern inline function drawDebugBoundingBox(rect:FlxRect, allowCollisions:FlxDirectionFlags) + { + // Find the color to use + var color = getDebugBoundingBoxColor(allowCollisions); + color.alphaFloat = 0.75; + drawDebugBoundingBoxColor(rect, color); + } function getDebugBoundingBoxColor(allowCollisions:FlxDirectionFlags) { @@ -1346,30 +1355,38 @@ class FlxObject extends FlxBasic } - function drawDebugBoundingBoxColor(gfx:Graphics, rect:FlxRect, color:FlxColor) + @:deprecated("drawDebugBoundingBoxColor(gfx, rect, color) is deprecated, use drawDebugBoundingBoxColor(rect, color) instead") + overload extern inline function drawDebugBoundingBoxColor(gfx:Graphics, rect:FlxRect, color:FlxColor) { // fill static graphics object with square shape gfx.lineStyle(1, color, 0.75, false, null, null, MITER, 255); gfx.drawRect(rect.x + 0.5, rect.y + 0.5, rect.width - 1.0, rect.height - 1.0); } + overload extern inline function drawDebugBoundingBoxColor(rect:FlxRect, color:FlxColor) + { + FlxG.renderer.drawDebugRect(rect.x + 0.5, rect.y + 0.5, rect.width - 1.0, rect.height - 1.0, color); + } + + @:deprecated("use object.beginDrawDebug(camera) is deprecated, FlxG.renderer.beginDrawDebug(camera) instead") inline function beginDrawDebug(camera:FlxCamera):Graphics { - if (FlxG.renderBlit) + FlxG.renderer.beginDrawDebug(camera); + + if (FlxG.renderer.method == BLITTING) { - FlxSpriteUtil.flashGfx.clear(); return FlxSpriteUtil.flashGfx; } else { - return camera.debugLayer.graphics; + return camera.viewQuad.debugLayer.graphics; } } + @:deprecated("use object.endDrawDebug(camera) is deprecated, FlxG.renderer.endDrawDebug() instead") inline function endDrawDebug(camera:FlxCamera) { - if (FlxG.renderBlit) - camera.buffer.draw(FlxSpriteUtil.flashGfxSprite); + FlxG.renderer.endDrawDebug(); } #end diff --git a/flixel/FlxSprite.hx b/flixel/FlxSprite.hx index 3894e93e40..d9a67b2a93 100644 --- a/flixel/FlxSprite.hx +++ b/flixel/FlxSprite.hx @@ -149,7 +149,7 @@ class FlxSprite extends FlxObject public var framePixels:BitmapData; /** - * Always `true` on `FlxG.renderBlit`. On `FlxG.renderTile` it determines whether + * Always `true` when using the blitting renderer. On other renderers it determines whether * `framePixels` is used and defaults to `false` for performance reasons. */ public var useFramePixels(default, set):Bool = true; @@ -248,7 +248,7 @@ class FlxSprite extends FlxObject /** * Change the size of your sprite's graphic. * NOTE: The hitbox is not automatically adjusted, use `updateHitbox()` for that. - * **WARNING:** With `FlxG.renderBlit`, scaling sprites decreases rendering performance by a factor of about x10! + * **WARNING:** With `the blitting renderer, scaling sprites decreases rendering performance by a factor of about x10! * @see https://snippets.haxeflixel.com/sprites/scale/ */ public var scale(default, null):FlxPoint; @@ -384,7 +384,7 @@ class FlxSprite extends FlxObject { super(X, Y); - useFramePixels = FlxG.renderBlit; + useFramePixels = FlxG.renderer.method == BLITTING; if (SimpleGraphic != null) loadGraphic(SimpleGraphic); } @@ -908,7 +908,7 @@ class FlxSprite extends FlxObject centerOrigin(); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { dirty = true; updateFramePixels(); @@ -963,6 +963,8 @@ class FlxSprite extends FlxObject for (camera in getCamerasLegacy()) { + FlxG.renderer.begin(camera); + if (!camera.visible || !camera.exists || !isOnScreen(camera)) continue; @@ -1009,7 +1011,7 @@ class FlxSprite extends FlxObject _point.floor(); _point.copyTo(_flashPoint); - camera.copyPixels(_frame, framePixels, _flashRect, _flashPoint, colorTransform, blend, antialiasing); + FlxG.renderer.copyPixels(_frame, framePixels, _flashRect, _flashPoint, colorTransform, blend, antialiasing); } @:noCompletion @@ -1025,7 +1027,7 @@ class FlxSprite extends FlxObject final matrix = drawComplexMatrix; // TODO: Just use local? prepareComplexMatrix(matrix, frame, camera); - camera.drawPixels(frame, framePixels, matrix, colorTransform, blend, antialiasing, shader); + FlxG.renderer.drawPixels(frame, framePixels, matrix, colorTransform, blend, antialiasing, shader); } function prepareComplexMatrix(matrix:FlxMatrix, frame:FlxFrame, camera:FlxCamera) @@ -1095,7 +1097,7 @@ class FlxSprite extends FlxObject graphic.bitmap.draw(bitmapData, _matrix, null, brushBlend, null, Brush.antialiasing); } - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { dirty = true; calcFrame(); @@ -1110,7 +1112,7 @@ class FlxSprite extends FlxObject */ public function drawFrame(Force:Bool = false):Void { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { if (Force || dirty) { @@ -1169,7 +1171,7 @@ class FlxSprite extends FlxObject /** * Sets the sprite's color transformation with control over color offsets. - * With `FlxG.renderTile`, offsets are only supported on OpenFL Next version 3.6.0 or higher. + * With the DRAW_TILES renderer, offsets are only supported on OpenFL Next version 3.6.0 or higher. * * @param redMultiplier The value for the red multiplier, in the range from `0` to `1`. * @param greenMultiplier The value for the green multiplier, in the range from `0` to `1`. @@ -1564,7 +1566,7 @@ class FlxSprite extends FlxObject { checkEmptyFrame(); - if (FlxG.renderTile && !force) + if (FlxG.renderer.method != BLITTING && !force) return; updateFramePixels(); @@ -1580,7 +1582,7 @@ class FlxSprite extends FlxObject // don't try to regenerate frame pixels if _frame already uses it as source of graphics // if you'll try then it will clear framePixels and you won't see anything - if (FlxG.renderTile && _frameGraphic != null) + if (FlxG.renderer.method != BLITTING && _frameGraphic != null) { dirty = false; return framePixels; @@ -1598,12 +1600,12 @@ class FlxSprite extends FlxObject framePixels = _frame.paintRotatedAndFlipped(framePixels, _flashPointZero, FlxFrameAngle.ANGLE_0, doFlipX, doFlipY, false, true); } - if (FlxG.renderBlit && hasColorTransform()) + if (FlxG.renderer.method == BLITTING && hasColorTransform()) { framePixels.colorTransform(_flashRect, colorTransform); } - if (FlxG.renderTile && useFramePixels) + if (FlxG.renderer.method != BLITTING && useFramePixels) { // recreate _frame for native target, so it will use modified framePixels _frameGraphic = FlxDestroyUtil.destroy(_frameGraphic); @@ -1672,12 +1674,12 @@ class FlxSprite extends FlxObject } /** - * Returns the result of `isSimpleRenderBlit()` if `FlxG.renderBlit` is - * `true`, or `false` if `FlxG.renderTile` is `true`. + * Returns the result of `isSimpleRenderBlit()` if the blitting renderer is used, + * or `false` elsewhere. */ public function isSimpleRender(?camera:FlxCamera):Bool { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) return false; return isSimpleRenderBlit(camera); @@ -1846,7 +1848,7 @@ class FlxSprite extends FlxObject return null; } - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { _frameGraphic = FlxDestroyUtil.destroy(_frameGraphic); } @@ -2004,7 +2006,7 @@ class FlxSprite extends FlxObject @:noCompletion function set_flipX(Value:Bool):Bool { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { _facingHorizontalMult = Value ? -1 : 1; } @@ -2015,7 +2017,7 @@ class FlxSprite extends FlxObject @:noCompletion function set_flipY(Value:Bool):Bool { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { _facingVerticalMult = Value ? -1 : 1; } @@ -2032,7 +2034,7 @@ class FlxSprite extends FlxObject @:noCompletion function set_useFramePixels(value:Bool):Bool { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { if (value != useFramePixels) { diff --git a/flixel/FlxStrip.hx b/flixel/FlxStrip.hx index 6696952a97..3fa1d58ddf 100644 --- a/flixel/FlxStrip.hx +++ b/flixel/FlxStrip.hx @@ -58,7 +58,8 @@ class FlxStrip extends FlxSprite getScreenPosition(_point, camera); _point -= offset; - camera.drawTriangles(graphic, vertices, indices, uvtData, colors, _point, blend, repeat, antialiasing, colorTransform, shader); + FlxG.renderer.begin(camera); + FlxG.renderer.drawTriangles(graphic, vertices, indices, uvtData, colors, _point, blend, repeat, antialiasing, colorTransform, shader); } } } diff --git a/flixel/FlxSubState.hx b/flixel/FlxSubState.hx index e7cca132f6..0edb330869 100644 --- a/flixel/FlxSubState.hx +++ b/flixel/FlxSubState.hx @@ -53,7 +53,7 @@ class FlxSubState extends FlxState closeCallback = null; openCallback = null; - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { _bgSprite = new FlxBGSprite(); } @@ -63,14 +63,15 @@ class FlxSubState extends FlxState override public function draw():Void { // Draw background - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { for (camera in getCamerasLegacy()) { - camera.fill(bgColor); + FlxG.renderer.begin(camera); + FlxG.renderer.fill(bgColor); } } - else // FlxG.renderTile + else // FlxG.renderer.method != BLITTING { if (_bgSprite != null && _bgSprite.visible) { @@ -110,7 +111,7 @@ class FlxSubState extends FlxState @:noCompletion override function set_bgColor(value:FlxColor):FlxColor { - if (FlxG.renderTile && _bgSprite != null) + if (FlxG.renderer.method != BLITTING && _bgSprite != null) { _bgSprite.alpha = value.alphaFloat; _bgSprite.visible = _bgSprite.alpha > 0; diff --git a/flixel/effects/FlxMatrixSprite.hx b/flixel/effects/FlxMatrixSprite.hx index 67676a32f3..96ca1652db 100644 --- a/flixel/effects/FlxMatrixSprite.hx +++ b/flixel/effects/FlxMatrixSprite.hx @@ -23,7 +23,7 @@ class FlxMatrixSprite extends FlxSprite super(x, y, simpleGraphic); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) FlxG.log.warn("FlxMatrixSprites do not work on blit targets"); } @@ -59,4 +59,4 @@ class FlxMatrixSprite extends FlxSprite matrix.ty = Math.floor(matrix.ty); } } -} \ No newline at end of file +} diff --git a/flixel/effects/particles/FlxEmitter.hx b/flixel/effects/particles/FlxEmitter.hx index 53021ab8ab..1538b97a29 100644 --- a/flixel/effects/particles/FlxEmitter.hx +++ b/flixel/effects/particles/FlxEmitter.hx @@ -264,7 +264,7 @@ class FlxTypedEmitter extends FlxTypedGroup var particle:T = Type.createInstance(particleClass, []); var frame = Multiple ? FlxG.random.int(0, totalFrames - 1) : -1; - if (FlxG.renderBlit && bakedRotationAngles > 0) + if (FlxG.renderer.method == BLITTING && bakedRotationAngles > 0) particle.loadRotatedGraphic(Graphics, bakedRotationAngles, frame, false, AutoBuffer); else particle.loadGraphic(Graphics, Multiple); diff --git a/flixel/graphics/FlxGraphic.hx b/flixel/graphics/FlxGraphic.hx index 656a0ace93..a668ab0b11 100644 --- a/flixel/graphics/FlxGraphic.hx +++ b/flixel/graphics/FlxGraphic.hx @@ -609,7 +609,7 @@ class FlxGraphic implements IFlxDestroyable height = bitmap.height; #if FLX_OPENGL_AVAILABLE - var max:Int = FlxG.bitmap.maxTextureSize; + var max:Int = FlxG.renderer.maxTextureSize; if (max > 0) { if (width > max || height > max) diff --git a/flixel/graphics/frames/FlxFrame.hx b/flixel/graphics/frames/FlxFrame.hx index 40f2cf87b6..24ee97351e 100644 --- a/flixel/graphics/frames/FlxFrame.hx +++ b/flixel/graphics/frames/FlxFrame.hx @@ -159,7 +159,7 @@ class FlxFrame implements IFlxDestroyable offset = FlxPoint.get(); blitMatrix = new MatrixVector(); - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) tileMatrix = new MatrixVector(); } @@ -169,7 +169,7 @@ class FlxFrame implements IFlxDestroyable { blitMatrix.copyFrom(this, true); - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) tileMatrix.copyFrom(this, false); } @@ -279,7 +279,7 @@ class FlxFrame implements IFlxDestroyable */ public function prepareMatrix(mat:FlxMatrix, rotation:FlxFrameAngle = FlxFrameAngle.ANGLE_0, flipX:Bool = false, flipY:Bool = false):FlxMatrix { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { mat.identity(); return mat; diff --git a/flixel/graphics/tile/FlxDrawBaseItem.hx b/flixel/graphics/tile/FlxDrawBaseItem.hx index fc91f4d8a1..6127ce907a 100644 --- a/flixel/graphics/tile/FlxDrawBaseItem.hx +++ b/flixel/graphics/tile/FlxDrawBaseItem.hx @@ -2,6 +2,7 @@ package flixel.graphics.tile; import flixel.FlxCamera; import flixel.graphics.frames.FlxFrame; +import flixel.system.render.FlxRenderer; import flixel.math.FlxMatrix; import openfl.display.BlendMode; import openfl.geom.ColorTransform; @@ -14,7 +15,18 @@ class FlxDrawBaseItem /** * Tracks the total number of draw calls made each frame. */ - public static var drawCalls:Int = 0; + @:deprecated("drawCalls is deprecated, use FlxRenderer.totalDrawCalls instead") + public static var drawCalls(get, set):Int; + + static function set_drawCalls(value:Int):Int + { + return FlxRenderer.totalDrawCalls = value; + } + + static function get_drawCalls():Int + { + return FlxRenderer.totalDrawCalls; + } @:noCompletion @:deprecated("blendToInt() is deprecated, remove all references to it") @@ -63,7 +75,7 @@ class FlxDrawBaseItem public function render(camera:FlxCamera):Void { - drawCalls++; + FlxRenderer.totalDrawCalls++; } public function addQuad(frame:FlxFrame, matrix:FlxMatrix, ?transform:ColorTransform):Void {} diff --git a/flixel/graphics/tile/FlxDrawQuadsItem.hx b/flixel/graphics/tile/FlxDrawQuadsItem.hx index be24ceaf80..97c09d9dac 100644 --- a/flixel/graphics/tile/FlxDrawQuadsItem.hx +++ b/flixel/graphics/tile/FlxDrawQuadsItem.hx @@ -133,10 +133,10 @@ class FlxDrawQuadsItem extends FlxDrawBaseItem setParameterValue(shader.hasTransform, true); setParameterValue(shader.hasColorTransform, colored || hasColorOffsets); - camera.canvas.graphics.overrideBlendMode(blend); - camera.canvas.graphics.beginShaderFill(shader); - camera.canvas.graphics.drawQuads(rects, null, transforms); - camera.canvas.graphics.endFill(); + camera.viewQuad.canvas.graphics.overrideBlendMode(blend); + camera.viewQuad.canvas.graphics.beginShaderFill(shader); + camera.viewQuad.canvas.graphics.drawQuads(rects, null, transforms); + camera.viewQuad.canvas.graphics.endFill(); super.render(camera); } diff --git a/flixel/graphics/tile/FlxDrawTrianglesItem.hx b/flixel/graphics/tile/FlxDrawTrianglesItem.hx index 38fbcd7b04..e3ac8acb43 100644 --- a/flixel/graphics/tile/FlxDrawTrianglesItem.hx +++ b/flixel/graphics/tile/FlxDrawTrianglesItem.hx @@ -75,20 +75,20 @@ class FlxDrawTrianglesItem extends FlxDrawBaseItem setParameterValue(shader.hasTransform, true); setParameterValue(shader.hasColorTransform, colored || hasColorOffsets); - camera.canvas.graphics.overrideBlendMode(blend); + camera.viewQuad.canvas.graphics.overrideBlendMode(blend); - camera.canvas.graphics.beginShaderFill(shader); + camera.viewQuad.canvas.graphics.beginShaderFill(shader); #else - camera.canvas.graphics.beginBitmapFill(graphics.bitmap, null, true, (camera.antialiasing || antialiasing)); + camera.viewQuad.canvas.graphics.beginBitmapFill(graphics.bitmap, null, true, (camera.antialiasing || antialiasing)); #end - camera.canvas.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NONE); - camera.canvas.graphics.endFill(); + camera.viewQuad.canvas.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NONE); + camera.viewQuad.canvas.graphics.endFill(); #if FLX_DEBUG if (FlxG.debugger.drawDebug) { - var gfx:Graphics = camera.debugLayer.graphics; + var gfx:Graphics = camera.viewQuad.debugLayer.graphics; gfx.lineStyle(1, FlxColor.BLUE, 0.5); gfx.drawTriangles(vertices, indices, uvtData); } diff --git a/flixel/path/FlxBasePath.hx b/flixel/path/FlxBasePath.hx index 3fa14e379a..a84e621fda 100644 --- a/flixel/path/FlxBasePath.hx +++ b/flixel/path/FlxBasePath.hx @@ -318,18 +318,8 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy */ public function drawDebugOnCamera(camera:FlxCamera):Void { - // Set up our global flash graphics object to draw out the path - var gfx:Graphics = null; - if (FlxG.renderBlit) - { - gfx = FlxSpriteUtil.flashGfx; - gfx.clear(); - } - else - { - gfx = camera.debugLayer.graphics; - } - + FlxG.renderer.beginDrawDebug(camera); + final length = nodes.length; // Then fill up the object with node and path graphics for (i=>node in nodes) @@ -355,24 +345,20 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy } // draw a box for the node - drawNode(gfx, prevNodeScreen, nodeSize, nodeColor); + drawNode(camera, prevNodeScreen, nodeSize, nodeColor); if (i + 1 < length || loopType == LOOP) { // draw a line to the next node, if LOOP, get connect the tail and head final nextNode = nodes[(i + 1) % length]; final nextNodeScreen = copyWorldToScreenPos(nextNode, camera); - drawLine(gfx, prevNodeScreen, nextNodeScreen); + drawLine(camera, prevNodeScreen, nextNodeScreen); nextNodeScreen.put(); } prevNodeScreen.put(); } - if (FlxG.renderBlit) - { - // then stamp the path down onto the game buffer - camera.buffer.draw(FlxSpriteUtil.flashGfxSprite); - } + FlxG.renderer.endDrawDebug(); } @:access(flixel.FlxCamera) @@ -386,7 +372,7 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy result.y -= camera.scroll.y * object.scrollFactor.y; } - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { result.x -= camera.viewMarginX; result.y -= camera.viewMarginY; @@ -396,16 +382,14 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy return result; } - inline function drawNode(gfx:Graphics, node:FlxPoint, size:Int, color:FlxColor) + inline function drawNode(camera:FlxCamera, node:FlxPoint, size:Int, color:FlxColor) { - gfx.beginFill(color.rgb, color.alphaFloat); - gfx.lineStyle(); final offset = Math.floor(size * 0.5); - gfx.drawRect(node.x - offset, node.y - offset, size, size); - gfx.endFill(); + FlxG.renderer.drawDebugFilledRect(node.x - offset, node.y - offset, size, size, color); } - function drawLine(gfx:Graphics, node1:FlxPoint, node2:FlxPoint) + @:deprecated("drawLine(gfx, node1, node2) is deprecated. Use drawLine(camera, node1, node2) instead.") + overload extern inline function drawLine(gfx:Graphics, node1:FlxPoint, node2:FlxPoint) { // then draw a line to the next node final color = debugDrawData.lineColor; @@ -416,6 +400,16 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy gfx.moveTo(node1.x + lineOffset, node1.y + lineOffset); gfx.lineTo(node2.x + lineOffset, node2.y + lineOffset); } + + overload extern inline function drawLine(camera:FlxCamera, node1:FlxPoint, node2:FlxPoint) + { + // then draw a line to the next node + final color = debugDrawData.lineColor; + final size = debugDrawData.lineSize; + final lineOffset = debugDrawData.lineSize / 2; + + FlxG.renderer.drawDebugLine(node1.x + lineOffset, node1.y + lineOffset, node2.x + lineOffset, node2.y + lineOffset, color, size); + } #end } diff --git a/flixel/system/FlxBGSprite.hx b/flixel/system/FlxBGSprite.hx index b5608493ab..25a6f55050 100644 --- a/flixel/system/FlxBGSprite.hx +++ b/flixel/system/FlxBGSprite.hx @@ -31,7 +31,9 @@ class FlxBGSprite extends FlxSprite _matrix.identity(); _matrix.scale(camera.viewWidth + 1, camera.viewHeight + 1); _matrix.translate(camera.viewMarginLeft, camera.viewMarginTop); - camera.drawPixels(frame, _matrix, colorTransform); + + FlxG.renderer.begin(camera); + FlxG.renderer.drawPixels(frame, _matrix, colorTransform); #if FLX_DEBUG FlxBasic.visibleCount++; diff --git a/flixel/system/debug/interaction/Interaction.hx b/flixel/system/debug/interaction/Interaction.hx index 799201e498..200c379f20 100644 --- a/flixel/system/debug/interaction/Interaction.hx +++ b/flixel/system/debug/interaction/Interaction.hx @@ -16,6 +16,7 @@ import flixel.system.debug.interaction.tools.TrackObject; import flixel.system.debug.interaction.tools.Transform; import flixel.util.FlxDestroyUtil; import flixel.util.FlxSpriteUtil; +import flixel.util.FlxColor; import openfl.display.BitmapData; import openfl.display.DisplayObject; import openfl.display.Graphics; @@ -377,9 +378,10 @@ class Interaction extends Window drawItemsSelection(); } + @:deprecated("getDebugGraphics() is deprecated. Use the debug draw functions from FlxCamera instead.") public function getDebugGraphics():Graphics { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { FlxSpriteUtil.flashGfx.clear(); return FlxSpriteUtil.flashGfx; @@ -394,25 +396,23 @@ class Interaction extends Window function drawItemsSelection():Void { - var gfx:Graphics = getDebugGraphics(); - if (gfx == null) - return; + final camera = FlxG.camera; + FlxG.renderer.beginDrawDebug(camera); for (member in selectedItems) { if (member != null && member.scrollFactor != null && member.isOnScreen()) { final margin = 0.5; - final scroll = FlxG.camera.scroll; + final scroll = camera.scroll; // Render a white rectangle centered at the selected item - gfx.lineStyle(1.0, 0xFFFFFF, 0.75); - gfx.drawRect(member.x - scroll.x - margin, member.y - scroll.y - margin, member.width + margin*2, member.height + margin*2); + + final color:FlxColor = FlxColor.fromRGBFloat(1, 1, 1, 0.75); + FlxG.renderer.drawDebugRect(member.x - scroll.x - margin, member.y - scroll.y - margin, member.width + margin*2, member.height + margin*2, color); } } - // Draw the debug info to the main camera buffer. - if (FlxG.renderBlit) - FlxG.camera.buffer.draw(FlxSpriteUtil.flashGfxSprite); + FlxG.renderer.endDrawDebug(); } /** @@ -790,19 +790,19 @@ class Interaction extends Window public function toDebugX(worldX:Float, camera:FlxCamera) { - if (FlxG.renderTile) - return camera.canvas.localToGlobal(new Point(worldX, 0)).x; + if (FlxG.renderer.method != BLITTING) + return camera.viewQuad.canvas.localToGlobal(new Point(worldX, 0)).x; else @:privateAccess - return camera._flashBitmap.localToGlobal(new Point(worldX, 0)).x; + return camera.viewBlit._flashBitmap.localToGlobal(new Point(worldX, 0)).x; } public function toDebugY(worldY:Float, camera:FlxCamera) { - if (FlxG.renderTile) - return camera.canvas.localToGlobal(new Point(0, worldY)).y; + if (FlxG.renderer.method != BLITTING) + return camera.viewQuad.canvas.localToGlobal(new Point(0, worldY)).y; else @:privateAccess - return camera._flashBitmap.localToGlobal(new Point(0, worldY)).y; + return camera.viewBlit._flashBitmap.localToGlobal(new Point(0, worldY)).y; } } diff --git a/flixel/system/debug/interaction/tools/Pointer.hx b/flixel/system/debug/interaction/tools/Pointer.hx index ecc4d354a4..050ffb3814 100644 --- a/flixel/system/debug/interaction/tools/Pointer.hx +++ b/flixel/system/debug/interaction/tools/Pointer.hx @@ -9,6 +9,7 @@ import flixel.math.FlxRect; import flixel.system.debug.Icon; import flixel.system.debug.interaction.Interaction; import flixel.util.FlxSpriteUtil; +import flixel.util.FlxColor; using flixel.util.FlxArrayUtil; @@ -133,9 +134,7 @@ class Pointer extends Tool override public function draw():Void { - var gfx:Graphics = _brain.getDebugGraphics(); - if (gfx == null) - return; + FlxG.renderer.beginDrawDebug(FlxG.camera); switch state { @@ -144,14 +143,13 @@ class Pointer extends Tool final rect = FlxRect.get(); setAbsRect(rect, startX, startY, _brain.flixelPointer.x, _brain.flixelPointer.y); // Render the selection rectangle - gfx.lineStyle(0.9, 0xbb0000); - gfx.drawRect(FlxG.camera.scroll.x + rect.x, FlxG.camera.scroll.y + rect.y, rect.width, rect.height); + var color:FlxColor = 0xbb0000; + color.alphaFloat = 0.9; + FlxG.renderer.drawDebugRect(FlxG.camera.scroll.x + rect.x, FlxG.camera.scroll.y + rect.y, rect.width, rect.height, color); rect.put(); } - // Render everything into the camera buffer - if (FlxG.renderBlit) - FlxG.camera.buffer.draw(FlxSpriteUtil.flashGfxSprite); + FlxG.renderer.endDrawDebug(); } static function setAbsRect(rect:FlxRect, x1:Float, y1:Float, x2:Float, y2:Float) @@ -174,4 +172,4 @@ private enum Selection { TOP(obj:Null); ALL(objs:Array); -} \ No newline at end of file +} diff --git a/flixel/system/debug/interaction/tools/Transform.hx b/flixel/system/debug/interaction/tools/Transform.hx index 428fa4b505..0c3bf0a3d3 100644 --- a/flixel/system/debug/interaction/tools/Transform.hx +++ b/flixel/system/debug/interaction/tools/Transform.hx @@ -232,34 +232,34 @@ class Transform extends Tool case TRANSFORM(target, _, _, _): target; } - - final gfx = _brain.getDebugGraphics(); - if (gfx == null) - return; - - drawSelection(gfx, target.getDefaultCamera()); - Marker.draw(target.x + target.origin.x, target.y + target.origin.y, false, gfx); - - // Draw the debug info to the main camera buffer. - if (FlxG.renderBlit) - FlxG.camera.buffer.draw(FlxSpriteUtil.flashGfxSprite); + + final camera = target.getDefaultCamera(); + + FlxG.renderer.beginDrawDebug(camera); + drawSelection(camera); + Marker.draw(target.x + target.origin.x, target.y + target.origin.y, false, camera); + FlxG.renderer.endDrawDebug(); } - - function drawSelection(gfx:Graphics, camera:FlxCamera) + + function drawSelection(camera:FlxCamera) { - gfx.lineStyle(1.0, FlxColor.MAGENTA, 1.0, false, LineScaleMode.NORMAL, CapsStyle.SQUARE); - // draw lines - gfx.moveTo(markers[3].x, markers[3].y); + var prevX = markers[3].x; + var prevY = markers[3].y; for (marker in markers) - gfx.lineTo(marker.x, marker.y); + { + FlxG.renderer.drawDebugLine(prevX, prevY, marker.x, marker.y, FlxColor.MAGENTA); + + prevX = marker.x; + prevY = marker.y; + } // draw markers for (marker in markers) { final x = marker.x; final y = marker.y; - Marker.draw(x, y, marker.type == ROTATE, gfx); + Marker.draw(x, y, marker.type == ROTATE, camera); } } } @@ -297,15 +297,15 @@ private class Marker y = target.y + target.origin.y + rot.y; rot.put(); } - - public static function draw(screenX:Float, screenY:Float, circle:Bool, gfx:Graphics) + + public static function draw(screenX:Float, screenY:Float, circle:Bool, camera:FlxCamera) { - gfx.beginFill(FlxColor.MAGENTA); + FlxG.renderer.begin(camera); + if (circle) - gfx.drawCircle(screenX, screenY, CIRCLE_RADIUS); + FlxG.renderer.drawDebugFilledCircle(screenX, screenY, CIRCLE_RADIUS, FlxColor.MAGENTA); else - gfx.drawRect(screenX - RECT_MARGIN, screenY - RECT_MARGIN, RECT_SIZE, RECT_SIZE); - gfx.endFill(); + FlxG.renderer.drawDebugFilledRect(screenX - RECT_MARGIN, screenY - RECT_MARGIN, RECT_SIZE, RECT_SIZE, FlxColor.MAGENTA); } } @@ -353,4 +353,4 @@ private enum TransformAction SET_SCALE_X(start:Float); SET_SCALE_Y(start:Float); SET_SCALE_XY(startX:Float, startY:Float); -} \ No newline at end of file +} diff --git a/flixel/system/debug/stats/Stats.hx b/flixel/system/debug/stats/Stats.hx index c76b12963b..8b82b00dac 100644 --- a/flixel/system/debug/stats/Stats.hx +++ b/flixel/system/debug/stats/Stats.hx @@ -88,7 +88,7 @@ class Stats extends Window { super("Stats", Icon.stats, 0, 0, false); - var minHeight = if (FlxG.renderTile) 200 else 185; + var minHeight = if (FlxG.renderer.method != BLITTING) 200 else 185; minSize.y = minHeight; resize(INITIAL_WIDTH, minHeight); @@ -130,7 +130,7 @@ class Stats extends Window _leftTextField.multiline = _rightTextField.multiline = true; var drawMethod = ""; - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { drawMethod = #if FLX_RENDER_TRIANGLE @@ -267,7 +267,7 @@ class Stats extends Window } visibleCount = Std.int(divide(visibleCount, _visibleObjectMarker)); - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { for (i in 0..._drawCallsMarker) { @@ -280,7 +280,7 @@ class Stats extends Window _drawMarker = 0; _activeObjectMarker = 0; _visibleObjectMarker = 0; - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { _drawCallsMarker = 0; } @@ -298,7 +298,10 @@ class Stats extends Window updateTimeGraph.update(updTime); _rightTextField.text = activeCount + " (" + updTime + "ms)\n" + visibleCount + " (" + drwTime + "ms)\n" - + (FlxG.renderTile ? (drawCallsCount + "\n") : "") + FlxQuadTree._NUM_CACHED_QUAD_TREES + "\n" + FlxLinkedList._NUM_CACHED_FLX_LIST; + + (FlxG.renderer.method != BLITTING ? (drawCallsCount + "\n") : "") + + FlxQuadTree._NUM_CACHED_QUAD_TREES + + "\n" + + FlxLinkedList._NUM_CACHED_FLX_LIST; } function divide(f1:Float, f2:Float):Float diff --git a/flixel/system/frontEnds/BitmapFrontEnd.hx b/flixel/system/frontEnds/BitmapFrontEnd.hx index 8e17339206..cd8bf697f8 100644 --- a/flixel/system/frontEnds/BitmapFrontEnd.hx +++ b/flixel/system/frontEnds/BitmapFrontEnd.hx @@ -8,9 +8,6 @@ import flixel.system.FlxAssets; import flixel.util.FlxColor; import openfl.Assets; import openfl.display.BitmapData; -#if FLX_OPENGL_AVAILABLE -import lime.graphics.opengl.GL; -#end /** * Internal storage system to prevent graphics from being used repeatedly in memory. @@ -19,7 +16,6 @@ import lime.graphics.opengl.GL; */ class BitmapFrontEnd { - #if FLX_OPENGL_AVAILABLE /** * Returns the maximum allowed width and height (in pixels) for a texture. * This value is only available on hardware-accelerated targets that use OpenGL. @@ -27,12 +23,12 @@ class BitmapFrontEnd * * @see https://opengl.gpuinfo.org/displaycapability.php?name=GL_MAX_TEXTURE_SIZE */ + @:deprecated("maxTextureSize is deprecated, use FlxG.renderer.maxTextureSize instead.") public var maxTextureSize(get, never):Int; - #end /** * Helper FlxFrame object. Containing only one frame. - * Useful for drawing colored rectangles of all sizes in FlxG.renderTile mode. + * Useful for drawing colored rectangles of all sizes when not using the blitting renderer. */ public var whitePixel(get, never):FlxFrame; @@ -341,18 +337,10 @@ class BitmapFrontEnd } } - #if FLX_OPENGL_AVAILABLE - static var _maxTextureSize = -1; - - @:allow(flixel.FlxG) - function get_maxTextureSize():Int + inline function get_maxTextureSize():Int { - if (_maxTextureSize < 0) - _maxTextureSize = FlxG.renderTile ? cast GL.getParameter(GL.MAX_TEXTURE_SIZE) : 0; - - return _maxTextureSize; + return FlxG.renderer.maxTextureSize; } - #end function get_whitePixel():FlxFrame { diff --git a/flixel/system/frontEnds/CameraFrontEnd.hx b/flixel/system/frontEnds/CameraFrontEnd.hx index 965d0eff3d..eb28bcb776 100644 --- a/flixel/system/frontEnds/CameraFrontEnd.hx +++ b/flixel/system/frontEnds/CameraFrontEnd.hx @@ -1,5 +1,6 @@ package flixel.system.frontEnds; +import flixel.system.render.blit.FlxBlitRenderer; import openfl.geom.Rectangle; import flixel.FlxCamera; import flixel.FlxG; @@ -44,8 +45,11 @@ class CameraFrontEnd /** * Allows you to possibly slightly optimize the rendering process IF * you are not doing any pre-processing in your game state's draw() call. + * + * **NOTE**: Only works with the blitting renderer. */ - public var useBufferLocking:Bool = false; + @:deprecated("useBufferLocking is deprecated, use FlxBlitRenderer.useBufferLocking, instead.") + public var useBufferLocking(get, set):Bool; /** * Internal helper variable for clearing the cameras each frame. @@ -64,7 +68,7 @@ class CameraFrontEnd */ public function add(NewCamera:T, DefaultDrawTarget:Bool = true):T { - FlxG.game.addChildAt(NewCamera.flashSprite, FlxG.game.getChildIndex(FlxG.game._inputContainer)); + FlxG.game.addChildAt(NewCamera.view.display, FlxG.game.getChildIndex(FlxG.game._inputContainer)); list.push(NewCamera); if (DefaultDrawTarget) @@ -97,8 +101,8 @@ class CameraFrontEnd if (position >= list.length) return add(newCamera); - final childIndex = FlxG.game.getChildIndex(list[position].flashSprite); - FlxG.game.addChildAt(newCamera.flashSprite, childIndex); + final childIndex = FlxG.game.getChildIndex(list[position].view.display); + FlxG.game.addChildAt(newCamera.view.display, childIndex); list.insert(position, newCamera); if (defaultDrawTarget) @@ -122,7 +126,7 @@ class CameraFrontEnd var index:Int = list.indexOf(Camera); if (Camera != null && index != -1) { - FlxG.game.removeChild(Camera.flashSprite); + FlxG.game.removeChild(Camera.view.display); list.splice(index, 1); defaults.remove(Camera); } @@ -132,7 +136,7 @@ class CameraFrontEnd return; } - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { for (i in 0...list.length) { @@ -253,87 +257,52 @@ class CameraFrontEnd * Called by the game object to lock all the camera buffers and clear them for the next draw pass. */ @:allow(flixel.FlxGame) + @:deprecated("lock() is deprecated, use clear() instead.") inline function lock():Void + { + clear(); + } + + /** + * Called by the game object to clear all the camera buffers for the next draw pass. + */ + @:allow(flixel.FlxGame) + inline function clear():Void { for (camera in list) { - if (camera == null || !camera.exists || !camera.visible) - { - continue; - } - - if (FlxG.renderBlit) + if ((camera != null) && camera.exists && camera.visible) { - camera.checkResize(); - - if (useBufferLocking) - { - camera.buffer.lock(); - } - } - - if (FlxG.renderTile) - { - camera.clearDrawStack(); - camera.canvas.graphics.clear(); - // Clearing camera's debug sprite - #if FLX_DEBUG - camera.debugLayer.graphics.clear(); - #end - } - - if (FlxG.renderBlit) - { - camera.fill(camera.bgColor, camera.useBgAlphaBlending); - camera.screen.dirty = true; - } - else - { - camera.fill(camera.bgColor.rgb, camera.useBgAlphaBlending, camera.bgColor.alphaFloat); + FlxG.renderer.begin(camera); + FlxG.renderer.clear(); } } } + /** + * Called by the game object to draw everything onto the screen. + */ @:allow(flixel.FlxGame) inline function render():Void { - if (FlxG.renderTile) + for (camera in list) { - for (camera in list) + if ((camera != null) && camera.exists && camera.visible) { - if ((camera != null) && camera.exists && camera.visible) - { - camera.render(); - } + FlxG.renderer.begin(camera); + FlxG.renderer.render(); } } } /** - * Called by the game object to draw the special FX and unlock all the camera buffers. + * Called by the game object to draw everything onto the screen. */ @:allow(flixel.FlxGame) + @:deprecated("unlock() is deprecated, use render() instead.") inline function unlock():Void { - for (camera in list) - { - if ((camera == null) || !camera.exists || !camera.visible) - { - continue; - } - - camera.drawFX(); - - if (FlxG.renderBlit) - { - if (useBufferLocking) - { - camera.buffer.unlock(); - } - - camera.screen.dirty = true; - } - } + render(); } /** @@ -377,4 +346,20 @@ class CameraFrontEnd return Color; } + + function get_useBufferLocking():Bool + { + if (FlxG.renderer.method == BLITTING) + return FlxBlitRenderer.useBufferLocking; + + return false; + } + + function set_useBufferLocking(value:Bool):Bool + { + if (FlxG.renderer.method == BLITTING) + return FlxBlitRenderer.useBufferLocking = value; + + return value; + } } diff --git a/flixel/system/render/FlxCameraView.hx b/flixel/system/render/FlxCameraView.hx new file mode 100644 index 0000000000..05cad513a0 --- /dev/null +++ b/flixel/system/render/FlxCameraView.hx @@ -0,0 +1,209 @@ +package flixel.system.render; + +import openfl.display.DisplayObjectContainer; +import openfl.display.DisplayObject; +import flixel.math.FlxRect; +import flixel.FlxG; +import flixel.FlxCamera; +import flixel.util.FlxDestroyUtil; +import flixel.math.FlxPoint; +import flixel.util.FlxColor; + +/** + * A `FlxCameraView` is a helper added to cameras, that holds some rendering-related objects + */ +@:allow(flixel.FlxCamera) +class FlxCameraView implements IFlxDestroyable +{ + /** + * Creates a `FlxCameraView` object tied to a camera, based on the target and project configuration. + * This function is dynamic, which means that you can change the return value yourself. + * + * @param camera The camera to create the view for + */ + public static dynamic function create(camera:FlxCamera):FlxCameraView + { + if (!FlxG.renderer.isHardware) + { + return cast new flixel.system.render.blit.FlxBlitView(camera); + } + else + { + return cast new flixel.system.render.quad.FlxQuadView(camera); + } + } + + /** + * Display object which is used as a container for all of the camera's graphics. + * This object is added to the display tree. + */ + public var display(get, never):DisplayObjectContainer; + + /** + * The parent camera for this view. + */ + public var camera(default, null):FlxCamera; + + /** + * A shortcut for `camera.antialiasing`. Used so implementations can listen to changes. + */ + public var antialiasing(get, set):Bool; + + /** + * A shortcut for `camera.angle`. Used so implementations can listen to changes. + */ + public var angle(get, set):Float; + + /** + * A shortcut for `camera.alpha`. Used so implementations can listen to changes. + */ + public var alpha(get, set):Float; + + /** + * A shortcut for `camera.color`. Used so implementations can listen to changes. + */ + public var color(get, set):FlxColor; + + /** + * A shortcut for `camera.visible`. Used so implementations can listen to changes. + */ + public var visible(get, set):Bool; + + var _flashOffset:FlxPoint = FlxPoint.get(); + + function new(camera:FlxCamera) + { + this.camera = camera; + } + + public function destroy():Void + { + _flashOffset = FlxDestroyUtil.put(_flashOffset); + } + + public function offsetView(x:Float, y:Float):Void {} + + function updateScale():Void + { + camera.calcMarginX(); + camera.calcMarginY(); + } + + function updatePosition():Void {} + + function updateInternals():Void {} + + function updateOffset():Void + { + _flashOffset.x = camera.width * 0.5 * FlxG.scaleMode.scale.x * camera.initialZoom; + _flashOffset.y = camera.height * 0.5 * FlxG.scaleMode.scale.y * camera.initialZoom; + } + + function updateScrollRect():Void {} + + /** + * Helper method preparing debug rectangle for rendering in blit render mode + * @param rect rectangle to prepare for rendering + * @return transformed rectangle with respect to camera's zoom factor + */ + function transformRect(rect:FlxRect):FlxRect + { + return rect; + } + + /** + * Helper method preparing debug point for rendering in blit render mode (for debug path rendering, for example) + * @param point point to prepare for rendering + * @return transformed point with respect to camera's zoom factor + */ + function transformPoint(point:FlxPoint):FlxPoint + { + return point; + } + + /** + * Helper method preparing debug vectors (relative positions) for rendering in blit render mode + * @param vector relative position to prepare for rendering + * @return transformed vector with respect to camera's zoom factor + */ + function transformVector(vector:FlxPoint):FlxPoint + { + return vector; + } + + /** + * Helper method for applying transformations (scaling and offsets) + * to specified display objects which has been added to the camera display list. + * For example, debug sprite for nape debug rendering. + * @param object display object to apply transformations to. + * @return transformed object. + */ + function transformObject(object:DisplayObject):DisplayObject + { + object.scaleX *= camera.totalScaleX; + object.scaleY *= camera.totalScaleY; + + object.x -= camera.scroll.x * camera.totalScaleX; + object.y -= camera.scroll.y * camera.totalScaleY; + + object.x -= 0.5 * camera.width * (camera.scaleX - camera.initialZoom) * FlxG.scaleMode.scale.x; + object.y -= 0.5 * camera.height * (camera.scaleY - camera.initialZoom) * FlxG.scaleMode.scale.y; + + return object; + } + + function get_display():DisplayObjectContainer + { + return null; + } + + function get_color():FlxColor + { + return camera.color; + } + + function set_color(color:FlxColor):FlxColor + { + return color; + } + + function get_antialiasing():Bool + { + return camera.antialiasing; + } + + function set_antialiasing(antialiasing:Bool):Bool + { + return antialiasing; + } + + function get_angle():Float + { + return camera.angle; + } + + function set_angle(angle:Float):Float + { + return angle; + } + + function get_visible():Bool + { + return camera.visible; + } + + function set_visible(visible:Bool):Bool + { + return visible; + } + + function get_alpha():Float + { + return camera.alpha; + } + + function set_alpha(alpha:Float):Float + { + return alpha; + } +} diff --git a/flixel/system/render/FlxRenderer.hx b/flixel/system/render/FlxRenderer.hx new file mode 100644 index 0000000000..2d0036c47f --- /dev/null +++ b/flixel/system/render/FlxRenderer.hx @@ -0,0 +1,277 @@ +package flixel.system.render; + +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxFrame; +import flixel.graphics.tile.FlxDrawTrianglesItem.DrawData; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.system.FlxAssets.FlxShader; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil.IFlxDestroyable; +import openfl.display.BitmapData; +import openfl.display.BlendMode; +import openfl.geom.ColorTransform; +import openfl.geom.Point; +import openfl.geom.Rectangle; + +/** + * `FlxRenderer` is the base class for all rendering functionality. + * It does not contain any rendering logic by itself, rather it is extended by the various renderer implementations. + * + * You can access a global renderer instance via `FlxG.renderer`. + * + * The `FlxRenderer` API replaces the previous renderer implementation in `FlxCamera`. + * Because it's not tied to a camera, it also works slightly differently. + * Before any drawing commands are executed, `FlxG.renderer.begin(camera);` is called to use the camera as a render target. + * This is called internally by Flixel during a sprite's draw phase, so you shouldn't worry about calling it yourself unless + * you have a reason to. + */ +class FlxRenderer implements IFlxDestroyable +{ + /** + * The number of total draw calls in the current frame. + */ + public static var totalDrawCalls:Int = 0; + + /** + * Creates a renderer instance, based on the used rendering backend. + * This function is dynamic, which means that you can change the return value yourself. + * + * @return A `FlxRenderer` instance. + */ + public static dynamic function create():FlxRenderer + { + if (!FlxG.renderer.isHardware) + { + return new flixel.system.render.blit.FlxBlitRenderer(); + } + else + { + return new flixel.system.render.quad.FlxQuadRenderer(); + } + } + + /** + * Returns the current render method as an enum. + */ + public var method(default, null):FlxRenderMethod; + + /** + * Returns whether the current renderer is hardware accelerated. + */ + public var isHardware(get, never):Bool; + @:noCompletion inline function get_isHardware():Bool + { + return FlxG.stage.window.context.attributes.hardware; + } + + /** + * Returns whether OpenGL access is available for the current renderer. + */ + public var isGL(get, never):Bool; + @:noCompletion inline function get_isGL():Bool + { + #if FLX_OPENGL_AVAILABLE + return FlxG.stage.window.context.type == OPENGL + || FlxG.stage.window.context.type == OPENGLES + || FlxG.stage.window.context.type == WEBGL; + #else + return false; + #end + } + + /** + * Returns the maximum allowed width and height (in pixels) for a texture. + * This value is only available on hardware-accelerated targets that use OpenGL. + * On unsupported targets, the returned value will always be -1. + * + * @see https://opengl.gpuinfo.org/displaycapability.php?name=GL_MAX_TEXTURE_SIZE + */ + public var maxTextureSize(default, null):Int; + + /** + * The current camera in use. + */ + public var camera(default, null):FlxCamera; + + public function new() + { + maxTextureSize = -1; + } + + public function destroy():Void + { + camera = null; + } + + // ------------------------ RENDERING ------------------------ + + /** + * Sets `camera` as the current render target. + * Any drawing commands will be executed on the camera. + * + * **NOTE:** Manually calling this during the draw phase could mess things up. + * If you must, please remember to reset the state back to where it was + * + * @param camera The camera to draw to. + */ + public function begin(camera:FlxCamera):Void + { + this.camera = camera; + } + + /** + * Called before a new rendering frame, clears all previously drawn graphics. + */ + public function clear():Void {} + + /** + * Flushes any remaining graphics and renders everything to the screen. + */ + public function render():Void {} + + /** + * Draws `frame` or `pixels` (depends on the renderer backend) onto the current render target. + * + * @param frame The frame to draw (used only with the DRAW_TILES renderer). + * @param pixels The pixels to draw (used only with the BLITTING renderer). + * @param matrix The transformation matrix to use. + * @param transform The color transform to use, optional. + * @param blend The blend mode to use, optional. + * @param smoothing Whether to use smoothing (anti-aliasing) when drawing. + * @param shader The shader to use, optional (used only with the DRAW_TILES renderer). + */ + public function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, smoothing:Bool = false, + ?shader:FlxShader):Void {} + + /** + * Draws `frame` or `pixels` (depends on the renderer backend) onto the current render target. + * + * Unlike `drawPixels()`, this method does not use a matrix. This means that complex transformations + * are not supported with this method. The `destPoint` argument is used to determine the position to draw to. + * + * @param frame The frame to draw (used only with the DRAW_TILES renderer). + * @param pixels The pixels to draw (used only with the BLITTING renderer). + * @param sourceRect A rectangle that defines the area of the pixels to use (used only with the BLITTING renderer). + * @param destPoint A point representing the top-left position to draw to. + * @param transform The color transform to use, optional. + * @param blend The blend mode to use, optional. + * @param smoothing Whether to use smoothing (anti-aliasing) when drawing. + * @param shader The shader to use, optional (used only with the DRAW_TILES renderer). + */ + public function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, + smoothing:Bool = false, ?shader:FlxShader):Void {} + + /** + * Draws a set of triangles onto the current render target. + * + * @param graphic The graphic to use for the triangles. + * @param vertices A vector where each element is a coordinate location. 2 elements make up an (x, y) pair. + * @param indices A vector where each element is an index to a vertex (x, y) pair. 3 indices make up a triangle. + * @param uvtData A vector where each element is a normalized coordinate (from 0.0 to 1.0), per vertex, used to apply texture mapping. + * @param colors A vector containing the colors to use per vertex. Currently does not work with any renderer. + * @param position A point representing the top-left position to draw to. + * @param blend The blend mode to use, optional. + * @param repeat Whether the graphic should repeat. + * @param smoothing Whether to use smoothing (anti-aliasing) when drawing. + * @param transform The color transform to use, optional. + * @param shader The shader to use, optional (used only with the DRAW_TILES renderer). + */ + public function drawTriangles(graphic:FlxGraphic, vertices:DrawData, indices:DrawData, uvtData:DrawData, ?colors:DrawData, + ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader):Void {} + + /** + * Fills the current render target with `color`. + * + * @param color The color (in 0xAARRGGBB format) to fill the screen with. + * @param blendAlpha Whether to blend the alpha value or just wipe the previous contents. + */ + public function fill(color:FlxColor, blendAlpha:Bool = true):Void {} + + // ------------------------ DEBUG DRAW ------------------------ + + /** + * Begins debug draw on the current (or optionally specified) camera. + * Any debug drawing commands will be executed on the camera. + * + * @param camera Optional, the camera to draw to. + */ + public function beginDrawDebug(?camera:FlxCamera):Void + { + if (camera != null) + { + this.camera = camera; + } + } + + /** + * Cleans up and finalizes the debug draw. + */ + public function endDrawDebug():Void {} + + /** + * Draws a rectangle with an outline. + * + * @param x The x position of the rectangle. + * @param y The y position of the rectangle. + * @param width The width of the rectangle (in pixels). + * @param height The height of the rectangle (in pixels). + * @param color The color (in 0xAARRGGBB hex format) of the rectangle's outline. + * @param thickness The thickness of the rectangle's outline. + */ + public function drawDebugRect(x:Float, y:Float, width:Float, height:Float, color:FlxColor, thickness:Float = 1.0):Void {} + + /** + * Draws a filled rectangle. + * + * @param x The x position of the rectangle. + * @param y The y position of the rectangle. + * @param width The width of the rectangle (in pixels). + * @param height The height of the rectangle (in pixels). + * @param color The color (in 0xAARRGGBB hex format) of the rectangle's fill. + */ + public function drawDebugFilledRect(x:Float, y:Float, width:Float, height:Float, color:FlxColor):Void {} + + /** + * Draws a filled circle. + * + * @param x The x position of the circle. + * @param y The y position of the circle. + * @param radius The radius of the circle. + * @param color The color (in 0xAARRGGBB hex format) of the circle's fill. + */ + public function drawDebugFilledCircle(x:Float, y:Float, radius:Float, color:FlxColor):Void {} + + /** + * Draws a line. + * + * @param x1 The start x position of the line. + * @param y1 The start y position of the line. + * @param x2 The end x position of the line. + * @param y2 The end y position of the line. + * @param color The color (in 0xAARRGGBB hex format) of the line. + * @param thickness The thickness of the line. + */ + public function drawDebugLine(x1:Float, y1:Float, x2:Float, y2:Float, color:FlxColor, thickness:Float = 1.0):Void {} +} + +/** + * An enum representing the available rendering methods. + */ +enum FlxRenderMethod +{ + /** + * Uses the `drawQuads()` method from OpenFL's Graphics API to achieve hardware accelerated rendering. + * + * This method is the default and is used on all targets (when hardware acceleration is available), except for Flash. + */ + DRAW_TILES; + + /** + * Draws sprites directly onto bitmaps using a software renderer. + * + * This method is mainly used by the Flash target, though other targets will use it too if + * hardware acceleration is unavailable. + */ + BLITTING; +} diff --git a/flixel/system/render/blit/FlxBlitRenderer.hx b/flixel/system/render/blit/FlxBlitRenderer.hx new file mode 100644 index 0000000000..3fb13042c3 --- /dev/null +++ b/flixel/system/render/blit/FlxBlitRenderer.hx @@ -0,0 +1,296 @@ +package flixel.system.render.blit; + +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxFrame; +import flixel.graphics.tile.FlxDrawTrianglesItem.DrawData; +import flixel.graphics.tile.FlxDrawTrianglesItem; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.math.FlxRect; +import flixel.system.FlxAssets.FlxShader; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; +import flixel.util.FlxSpriteUtil; +import openfl.Vector; +import openfl.display.BitmapData; +import openfl.display.BlendMode; +import openfl.display.Graphics; +import openfl.display.Sprite; +import openfl.geom.ColorTransform; +import openfl.geom.Point; +import openfl.geom.Rectangle; + +@:access(flixel.FlxCamera) +@:access(flixel.system.render.blit) +class FlxBlitRenderer extends FlxRenderer +{ + /** + * Whether the camera's buffer should be locked and unlocked during render calls. + * + * Allows you to possibly slightly optimize the rendering process IF + * you are not doing any pre-processing in your game state's draw() call. + * + * This property only has effects when targeting Flash. + */ + public static var useBufferLocking:Bool = false; + + /** + * Internal variable, used in blit render mode to render triangles (`drawTriangles()`) on camera's buffer. + */ + static var trianglesSprite:Sprite = new Sprite(); + + /** + * Internal variables, used in blit render mode to draw trianglesSprite on camera's buffer. + * Added for less garbage creation. + */ + static var renderPoint:FlxPoint = FlxPoint.get(); + + static var renderRect:FlxRect = FlxRect.get(); + + /** + * Internal variable, used for visibility checks to minimize `drawTriangles()` calls. + */ + static var drawVertices:Vector = new Vector(); + + /** + * Helper rect for `drawTriangles()` visibility checks + */ + var _bounds:FlxRect = FlxRect.get(); + + var _helperMatrix:FlxMatrix = new FlxMatrix(); + var _helperPoint:Point = new Point(); + + /** + * Internal, used in blit render mode in camera's `fill()` method for less garbage creation: + * Its coordinates are always `(0,0)`, where camera's buffer filling should start. + * Do not modify it unless you know what are you doing. + */ + var _flashPoint:Point = new Point(); + + /** + * Convenience shortcut for `camera.viewBlit` + */ + var view(get, never):FlxBlitView; + + @:noCompletion inline function get_view():FlxBlitView + return camera.viewBlit; + + public function new() + { + super(); + method = BLITTING; + } + + override function destroy():Void + { + super.destroy(); + _bounds = FlxDestroyUtil.put(_bounds); + _helperMatrix = null; + _helperPoint = null; + _flashPoint = null; + } + + override function clear():Void + { + view.checkResize(); + + if (useBufferLocking) + { + view.buffer.lock(); + } + + fill(camera.bgColor, camera.useBgAlphaBlending); + view.screen.dirty = true; + } + + override function render():Void + { + camera.drawFX(); + + if (useBufferLocking) + { + view.buffer.unlock(); + } + + view.screen.dirty = true; + } + + override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, smoothing:Bool = false, + ?shader:FlxShader):Void + { + _helperMatrix.copyFrom(matrix); + + if (view._useBlitMatrix) + { + _helperMatrix.concat(view._blitMatrix); + view.buffer.draw(pixels, _helperMatrix, null, null, null, (smoothing || camera.antialiasing)); + } + else + { + _helperMatrix.translate(-camera.viewMarginLeft, -camera.viewMarginTop); + view.buffer.draw(pixels, _helperMatrix, null, blend, null, (smoothing || camera.antialiasing)); + } + } + + override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, + smoothing:Bool = false, ?shader:FlxShader) + { + if (pixels != null) + { + if (view._useBlitMatrix) + { + _helperMatrix.identity(); + _helperMatrix.translate(destPoint.x, destPoint.y); + _helperMatrix.concat(view._blitMatrix); + view.buffer.draw(pixels, _helperMatrix, null, null, null, (smoothing || camera.antialiasing)); + } + else + { + _helperPoint.x = destPoint.x - Std.int(camera.viewMarginLeft); + _helperPoint.y = destPoint.y - Std.int(camera.viewMarginTop); + view.buffer.copyPixels(pixels, sourceRect, _helperPoint, null, null, true); + } + } + else if (frame != null) + { + // TODO: fix this case for zoom less than initial zoom... + frame.paint(view.buffer, destPoint, true); + } + } + + override function drawTriangles(graphic:FlxGraphic, vertices:DrawData, indices:DrawData, uvtData:DrawData, ?colors:DrawData, + ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader) + { + final cameraBounds = _bounds.set(camera.viewMarginLeft, camera.viewMarginTop, camera.viewWidth, camera.viewHeight); + + if (position == null) + position = renderPoint.set(); + + var verticesLength:Int = vertices.length; + var currentVertexPosition:Int = 0; + + var tempX:Float, tempY:Float; + var i:Int = 0; + var bounds = renderRect.set(); + drawVertices.splice(0, drawVertices.length); + + while (i < verticesLength) + { + tempX = position.x + vertices[i]; + tempY = position.y + vertices[i + 1]; + + drawVertices[currentVertexPosition++] = tempX; + drawVertices[currentVertexPosition++] = tempY; + + if (i == 0) + { + bounds.set(tempX, tempY, 0, 0); + } + else + { + FlxDrawTrianglesItem.inflateBounds(bounds, tempX, tempY); + } + + i += 2; + } + + position.putWeak(); + + if (!cameraBounds.overlaps(bounds)) + { + drawVertices.splice(drawVertices.length - verticesLength, verticesLength); + } + else + { + trianglesSprite.graphics.clear(); + trianglesSprite.graphics.beginBitmapFill(graphic.bitmap, null, repeat, smoothing); + trianglesSprite.graphics.drawTriangles(drawVertices, indices, uvtData); + trianglesSprite.graphics.endFill(); + + // TODO: check this block of code for cases, when zoom < 1 (or initial zoom?)... + if (view._useBlitMatrix) + _helperMatrix.copyFrom(view._blitMatrix); + else + { + _helperMatrix.identity(); + _helperMatrix.translate(-camera.viewMarginLeft, -camera.viewMarginTop); + } + + view.buffer.draw(trianglesSprite, _helperMatrix, transform); + + #if FLX_DEBUG + if (FlxG.debugger.drawDebug) + { + // TODO: add a drawDebugTriangles method + var gfx:Graphics = FlxSpriteUtil.flashGfx; + gfx.clear(); + gfx.lineStyle(1, FlxColor.BLUE, 0.5); + gfx.drawTriangles(drawVertices, indices); + view.buffer.draw(FlxSpriteUtil.flashGfxSprite, _helperMatrix); + } + #end + // End of TODO... + } + + bounds.put(); + } + + override function fill(color:FlxColor, blendAlpha:Bool = true) + { + if (blendAlpha) + { + view._fill.fillRect(view._flashRect, color); + view.buffer.copyPixels(view._fill, view._flashRect, _flashPoint, null, null, blendAlpha); + } + else + { + view.buffer.fillRect(view._flashRect, color); + } + } + + override function beginDrawDebug(?camera:FlxCamera):Void + { + super.beginDrawDebug(camera); + + FlxSpriteUtil.flashGfx.clear(); + } + + override function endDrawDebug():Void + { + view.buffer.draw(FlxSpriteUtil.flashGfxSprite); + } + + #if FLX_DEBUG + override public function drawDebugRect(x:Float, y:Float, width:Float, height:Float, color:FlxColor, thickness:Float = 1.0):Void + { + final gfx = FlxSpriteUtil.flashGfx; + gfx.lineStyle(thickness, color.rgb, color.alphaFloat, false, null, null, MITER, 255); + gfx.drawRect(x, y, width, height); + } + + override public function drawDebugFilledRect(x:Float, y:Float, width:Float, height:Float, color:FlxColor):Void + { + final gfx = FlxSpriteUtil.flashGfx; + gfx.lineStyle(); + gfx.beginFill(color.rgb, color.alphaFloat); + gfx.drawRect(x, y, width, height); + gfx.endFill(); + } + + override public function drawDebugFilledCircle(x:Float, y:Float, radius:Float, color:FlxColor):Void + { + final gfx = FlxSpriteUtil.flashGfx; + gfx.beginFill(color.rgb, color.alphaFloat); + gfx.drawCircle(x, y, radius); + gfx.endFill(); + } + + override public function drawDebugLine(x1:Float, y1:Float, x2:Float, y2:Float, color:FlxColor, thickness:Float = 1.0):Void + { + final gfx = FlxSpriteUtil.flashGfx; + gfx.lineStyle(thickness, color.rgb, color.alphaFloat, false, null, null, MITER, 255); + gfx.moveTo(x1, y1); + gfx.lineTo(x2, y2); + } + #end +} diff --git a/flixel/system/render/blit/FlxBlitView.hx b/flixel/system/render/blit/FlxBlitView.hx new file mode 100644 index 0000000000..d35df84630 --- /dev/null +++ b/flixel/system/render/blit/FlxBlitView.hx @@ -0,0 +1,282 @@ +package flixel.system.render.blit; + +import flixel.FlxCamera; +import flixel.FlxG; +import flixel.graphics.FlxGraphic; +import flixel.math.FlxRect; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.system.render.FlxCameraView; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; +import openfl.display.Bitmap; +import openfl.display.BitmapData; +import openfl.display.DisplayObjectContainer; +import openfl.display.Sprite; +import openfl.geom.Rectangle; +import openfl.geom.ColorTransform; + +class FlxBlitView extends FlxCameraView +{ + /** + * Used to render buffer to screen space. + * NOTE: We don't recommend modifying this directly unless you are fairly experienced. + * Uses include 3D projection, advanced display list modification, and more. + * This is container for everything else that is used by camera and rendered to the camera. + * + * Its position is modified by `updateFlashSpritePosition()` which is called every frame. + */ + public var flashSprite:Sprite = new Sprite(); + + /** + * Sometimes it's easier to just work with a `FlxSprite`, than it is to work directly with the `BitmapData` buffer. + * This sprite reference will allow you to do exactly that. + * Basically, this sprite's `pixels` property is the camera's `BitmapData` buffer. + * + * **NOTE:** This field is only used in blit render mode. + */ + public var screen:FlxSprite; + + /** + * The actual `BitmapData` of the camera display itself. + * Used in blit render mode, where you can manipulate its pixels for achieving some visual effects. + */ + public var buffer:BitmapData; + + /** + * Internal sprite, used for correct trimming of camera viewport. + * It is a child of `flashSprite`. + * Its position is modified by `updateScrollRect()` method, which is called on camera's resize and scale events. + */ + var _scrollRect:Sprite = new Sprite(); + + /** + * Internal, used in blit render mode in camera's `fill()` method for less garbage creation. + * It represents the size of buffer `BitmapData` + * (the area of camera's buffer which should be filled with `bgColor`). + * Do not modify it unless you know what are you doing. + */ + var _flashRect:Rectangle; + + /** + * Internal, used to render buffer to screen space. Used it blit render mode only. + * This Bitmap used for rendering camera's buffer (`_flashBitmap.bitmapData = buffer;`) + * Its position is modified by `updateInternalSpritePositions()`, which is called on camera's resize and scale events. + * It is a child of the `_scrollRect` `Sprite`. + */ + var _flashBitmap:Bitmap; + + /** + * Internal helper variable for doing better wipes/fills between renders. + * Used it blit render mode only (in `fill()` method). + */ + var _fill:BitmapData; + + /** + * Logical flag for tracking whether to apply _blitMatrix transformation to objects or not. + */ + var _useBlitMatrix:Bool = false; + + /** + * Helper matrix object. Used in blit render mode when camera's zoom is less than initialZoom + * (it is applied to all objects rendered on the camera at such circumstances). + */ + var _blitMatrix:FlxMatrix = new FlxMatrix(); + + @:allow(flixel.system.render.FlxCameraView) + function new(camera:FlxCamera) + { + super(camera); + + flashSprite.addChild(_scrollRect); + _scrollRect.scrollRect = new Rectangle(); + + _flashRect = new Rectangle(0, 0, camera.width, camera.height); + + screen = new FlxSprite(); + buffer = new BitmapData(camera.width, camera.height, true, 0); + screen.pixels = buffer; + screen.origin.zero(); + _flashBitmap = new Bitmap(buffer); + _scrollRect.addChild(_flashBitmap); + _fill = new BitmapData(camera.width, camera.height, true, FlxColor.TRANSPARENT); + } + + override function destroy():Void + { + super.destroy(); + + FlxDestroyUtil.removeChild(flashSprite, _scrollRect); + FlxDestroyUtil.removeChild(_scrollRect, _flashBitmap); + screen = FlxDestroyUtil.destroy(screen); + buffer = null; + _flashBitmap = null; + _fill = FlxDestroyUtil.dispose(_fill); + flashSprite = null; + _scrollRect = null; + _flashRect = null; + } + + override function offsetView(x:Float, y:Float):Void + { + flashSprite.x += x; + flashSprite.y += y; + } + + override function updatePosition():Void + { + if (flashSprite != null) + { + flashSprite.x = camera.x * FlxG.scaleMode.scale.x + _flashOffset.x; + flashSprite.y = camera.y * FlxG.scaleMode.scale.y + _flashOffset.y; + } + } + + override function updateScrollRect():Void + { + var rect:Rectangle = (_scrollRect != null) ? _scrollRect.scrollRect : null; + + if (rect != null) + { + rect.x = rect.y = 0; + + rect.width = camera.width * camera.initialZoom * FlxG.scaleMode.scale.x; + rect.height = camera.height * camera.initialZoom * FlxG.scaleMode.scale.y; + + _scrollRect.scrollRect = rect; + + _scrollRect.x = -0.5 * rect.width; + _scrollRect.y = -0.5 * rect.height; + } + } + + override function updateScale():Void + { + updateBlitMatrix(); + + if (_useBlitMatrix) + { + _flashBitmap.scaleX = camera.initialZoom * FlxG.scaleMode.scale.x; + _flashBitmap.scaleY = camera.initialZoom * FlxG.scaleMode.scale.y; + } + else + { + _flashBitmap.scaleX = camera.totalScaleX; + _flashBitmap.scaleY = camera.totalScaleY; + } + + super.updateScale(); + } + + override function updateInternals():Void + { + if (_flashBitmap != null) + { + _flashBitmap.x = 0; + _flashBitmap.y = 0; + } + } + + function checkResize():Void + { + if (camera.width != buffer.width || camera.height != buffer.height) + { + var oldBuffer:FlxGraphic = screen.graphic; + buffer = new BitmapData(camera.width, camera.height, true, 0); + screen.pixels = buffer; + screen.origin.zero(); + _flashBitmap.bitmapData = buffer; + _flashRect.width = camera.width; + _flashRect.height = camera.height; + _fill = FlxDestroyUtil.dispose(_fill); + _fill = new BitmapData(camera.width, camera.height, true, FlxColor.TRANSPARENT); + FlxG.bitmap.removeIfNoUse(oldBuffer); + } + + updateBlitMatrix(); + } + + inline function updateBlitMatrix():Void + { + _blitMatrix.identity(); + _blitMatrix.translate(-camera.viewMarginLeft, -camera.viewMarginTop); + _blitMatrix.scale(camera.scaleX, camera.scaleY); + + _useBlitMatrix = (camera.scaleX < camera.initialZoom) || (camera.scaleY < camera.initialZoom); + } + + override function transformRect(rect:FlxRect):FlxRect + { + rect.offset(-camera.viewMarginLeft, -camera.viewMarginTop); + + if (_useBlitMatrix) + { + rect.x *= camera.zoom; + rect.y *= camera.zoom; + rect.width *= camera.zoom; + rect.height *= camera.zoom; + } + + return rect; + } + + override function transformPoint(point:FlxPoint):FlxPoint + { + point.subtract(camera.viewMarginLeft, camera.viewMarginTop); + + if (_useBlitMatrix) + point.scale(camera.zoom); + + return point; + } + + override function transformVector(vector:FlxPoint):FlxPoint + { + if (_useBlitMatrix) + vector.scale(camera.zoom); + + return vector; + } + + override function get_display():DisplayObjectContainer + { + return flashSprite; + } + + override function set_color(color:FlxColor):FlxColor + { + if (_flashBitmap != null) + { + final colorTransform:ColorTransform = _flashBitmap.transform.colorTransform; + + colorTransform.redMultiplier = color.redFloat; + colorTransform.greenMultiplier = color.greenFloat; + colorTransform.blueMultiplier = color.blueFloat; + + _flashBitmap.transform.colorTransform = colorTransform; + } + + return color; + } + + override function set_antialiasing(antialiasing:Bool):Bool + { + return _flashBitmap.smoothing = antialiasing; + } + + override function set_alpha(alpha:Float):Float + { + return _flashBitmap.alpha = alpha; + } + + override function set_angle(angle:Float):Float + { + return flashSprite.rotation = angle; + } + + override function set_visible(visible:Bool):Bool + { + flashSprite.visible = visible; + return visible; + } +} diff --git a/flixel/system/render/quad/FlxQuadRenderer.hx b/flixel/system/render/quad/FlxQuadRenderer.hx new file mode 100644 index 0000000000..b21d2d4ccb --- /dev/null +++ b/flixel/system/render/quad/FlxQuadRenderer.hx @@ -0,0 +1,175 @@ +package flixel.system.render.quad; + +import openfl.geom.Point; +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxFrame; +import flixel.graphics.tile.FlxDrawBaseItem; +import flixel.graphics.tile.FlxDrawQuadsItem; +import flixel.graphics.tile.FlxDrawTrianglesItem; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.math.FlxRect; +import flixel.system.FlxAssets.FlxShader; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; +import openfl.display.BitmapData; +import openfl.display.BlendMode; +import openfl.geom.ColorTransform; +import openfl.geom.Rectangle; +#if FLX_OPENGL_AVAILABLE +import lime.graphics.opengl.GL; +#end + +using flixel.util.FlxColorTransformUtil; + +@:access(flixel.FlxCamera) +@:access(flixel.system.render.quad) +class FlxQuadRenderer extends FlxRenderer +{ + /** + * Convenience shortcut for `camera.viewQuad` + */ + var view(get, never):FlxQuadView; + @:noCompletion inline function get_view():FlxQuadView + return camera.viewQuad; + + var _helperMatrix:FlxMatrix = new FlxMatrix(); + + /** + * Helper rect for `drawTriangles()` visibility checks + */ + var _bounds:FlxRect = FlxRect.get(); + + public function new() + { + super(); + method = DRAW_TILES; + + #if FLX_OPENGL_AVAILBLE + if (isGL) + maxTextureSize = cast GL.getParameter(GL.MAX_TEXTURE_SIZE); + #end + } + + override function destroy():Void + { + super.destroy(); + _bounds = FlxDestroyUtil.put(_bounds); + _helperMatrix = null; + } + + override function clear():Void + { + view.clearDrawStack(); + + view.canvas.graphics.clear(); + #if FLX_DEBUG + // Clearing camera's debug sprite + view.debugLayer.graphics.clear(); + #end + + view.targetGraphics = view.canvas.graphics; + fill(camera.bgColor, camera.useBgAlphaBlending); + } + + override function render():Void + { + view.flashSprite.filters = camera.filtersEnabled ? camera.filters : null; + + var currItem:FlxDrawBaseItem = view._headOfDrawStack; + while (currItem != null) + { + currItem.render(camera); + currItem = currItem.next; + } + + camera.drawFX(); + } + + override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, smoothing:Bool = false, + ?shader:FlxShader) + { + var isColored = (transform != null #if !html5 && transform.hasRGBMultipliers() #end); + var hasColorOffsets:Bool = (transform != null && transform.hasRGBAOffsets()); + + #if FLX_RENDER_TRIANGLE + final drawItem:FlxDrawTrianglesItem = view.startTrianglesBatch(frame.parent, smoothing, isColored, blend, hasColorOffsets, shader); + #else + final drawItem:FlxDrawQuadsItem = view.startQuadBatch(frame.parent, isColored, hasColorOffsets, blend, smoothing, shader); + #end + drawItem.addQuad(frame, matrix, transform); + } + + override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, + smoothing:Bool = false, ?shader:FlxShader) + { + _helperMatrix.identity(); + _helperMatrix.translate(destPoint.x + frame.offset.x, destPoint.y + frame.offset.y); + + var isColored = (transform != null && transform.hasRGBMultipliers()); + var hasColorOffsets:Bool = (transform != null && transform.hasRGBAOffsets()); + + #if FLX_RENDER_TRIANGLE + final drawItem:FlxDrawTrianglesItem = view.startTrianglesBatch(frame.parent, smoothing, isColored, blend, hasColorOffsets, shader); + #else + final drawItem:FlxDrawQuadsItem = view.startQuadBatch(frame.parent, isColored, hasColorOffsets, blend, smoothing, shader); + #end + drawItem.addQuad(frame, _helperMatrix, transform); + } + + override function drawTriangles(graphic:FlxGraphic, vertices:DrawData, indices:DrawData, uvtData:DrawData, ?colors:DrawData, + ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader) + { + final cameraBounds = _bounds.set(camera.viewMarginLeft, camera.viewMarginTop, camera.viewWidth, camera.viewHeight); + + final isColored = (colors != null && colors.length != 0) || (transform != null && transform.hasRGBMultipliers()); + final hasColorOffsets = (transform != null && transform.hasRGBAOffsets()); + + final drawItem = view.startTrianglesBatch(graphic, smoothing, isColored, blend, hasColorOffsets, shader); + drawItem.addTriangles(vertices, indices, uvtData, colors, position, cameraBounds, transform); + } + + override function fill(color:FlxColor, blendAlpha:Bool = true):Void + { + view.targetGraphics.overrideBlendMode(null); + view.targetGraphics.beginFill(color.rgb, color.alphaFloat); + // i'm drawing rect with these parameters to avoid light lines at the top and left of the camera, + // which could appear while cameras fading + view.targetGraphics.drawRect(camera.viewMarginLeft - 1, camera.viewMarginTop - 1, camera.viewWidth + 2, camera.viewHeight + 2); + view.targetGraphics.endFill(); + } + + #if FLX_DEBUG + override function drawDebugRect(x:Float, y:Float, width:Float, height:Float, color:FlxColor, thickness:Float = 1.0):Void + { + final gfx = view.debugLayer.graphics; + gfx.lineStyle(thickness, color.rgb, color.alphaFloat, false, null, null, MITER, 255); + gfx.drawRect(x, y, width, height); + } + + override function drawDebugFilledRect(x:Float, y:Float, width:Float, height:Float, color:FlxColor):Void + { + final gfx = view.debugLayer.graphics; + gfx.lineStyle(); + gfx.beginFill(color.rgb, color.alphaFloat); + gfx.drawRect(x, y, width, height); + gfx.endFill(); + } + + override function drawDebugFilledCircle(x:Float, y:Float, radius:Float, color:FlxColor):Void + { + final gfx = view.debugLayer.graphics; + gfx.beginFill(color.rgb, color.alphaFloat); + gfx.drawCircle(x, y, radius); + gfx.endFill(); + } + + override function drawDebugLine(x1:Float, y1:Float, x2:Float, y2:Float, color:FlxColor, thickness:Float = 1.0):Void + { + final gfx = view.debugLayer.graphics; + gfx.lineStyle(thickness, color.rgb, color.alphaFloat, false, null, null, MITER, 255); + gfx.moveTo(x1, y1); + gfx.lineTo(x2, y2); + } + #end +} diff --git a/flixel/system/render/quad/FlxQuadView.hx b/flixel/system/render/quad/FlxQuadView.hx new file mode 100644 index 0000000000..5d8713562b --- /dev/null +++ b/flixel/system/render/quad/FlxQuadView.hx @@ -0,0 +1,385 @@ +package flixel.system.render.quad; + +import flixel.FlxCamera; +import flixel.FlxG; +import flixel.graphics.FlxGraphic; +import flixel.graphics.tile.FlxDrawBaseItem; +import flixel.graphics.tile.FlxDrawQuadsItem; +import flixel.graphics.tile.FlxDrawTrianglesItem; +import flixel.system.FlxAssets.FlxShader; +import flixel.system.render.FlxCameraView; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; +import openfl.display.BlendMode; +import openfl.display.DisplayObjectContainer; +import openfl.display.Graphics; +import openfl.display.Sprite; +import openfl.geom.ColorTransform; +import openfl.geom.Rectangle; + +using flixel.util.FlxColorTransformUtil; + +class FlxQuadView extends FlxCameraView +{ + /** + * Sprite used for actual rendering in tile render mode (instead of `_flashBitmap` for blitting). + * Its graphics is used as a drawing surface for `drawTriangles()` and `drawTiles()` methods. + * It is a child of `_scrollRect` `Sprite` (which trims graphics that should be invisible). + * Its position is modified by `updateInternalSpritePositions()`, which is called on camera's resize and scale events. + */ + public var canvas:Sprite; + + #if FLX_DEBUG + /** + * Sprite for visual effects (flash and fade) and drawDebug information + * (bounding boxes are drawn on it) for tile render mode. + * It is a child of `_scrollRect` `Sprite` (which trims graphics that should be invisible). + * Its position is modified by `updateInternalSpritePositions()`, which is called on camera's resize and scale events. + */ + public var debugLayer:Sprite; + #end + + /** + * Used to render buffer to screen space. + * NOTE: We don't recommend modifying this directly unless you are fairly experienced. + * Uses include 3D projection, advanced display list modification, and more. + * This is container for everything else that is used by camera and rendered to the camera. + * + * Its position is modified by `updateFlashSpritePosition()` which is called every frame. + */ + public var flashSprite:Sprite = new Sprite(); + + /** + * Internal sprite, used for correct trimming of camera viewport. + * It is a child of `flashSprite`. + * Its position is modified by `updateScrollRect()` method, which is called on camera's resize and scale events. + */ + var _scrollRect:Sprite = new Sprite(); + + var targetGraphics:Graphics; + + @:allow(flixel.system.render.FlxCameraView) + function new(camera:FlxCamera) + { + super(camera); + + flashSprite.addChild(_scrollRect); + _scrollRect.scrollRect = new Rectangle(); + + canvas = new Sprite(); + _scrollRect.addChild(canvas); + + #if FLX_DEBUG + debugLayer = new Sprite(); + _scrollRect.addChild(debugLayer); + #end + + targetGraphics = canvas.graphics; + } + + override function destroy():Void + { + super.destroy(); + + FlxDestroyUtil.removeChild(flashSprite, _scrollRect); + #if FLX_DEBUG + FlxDestroyUtil.removeChild(_scrollRect, debugLayer); + debugLayer = null; + #end + + FlxDestroyUtil.removeChild(_scrollRect, canvas); + if (canvas != null) + { + for (i in 0...canvas.numChildren) + { + canvas.removeChildAt(0); + } + canvas = null; + } + + if (_headOfDrawStack != null) + { + clearDrawStack(); + } + + flashSprite = null; + _scrollRect = null; + } + + override function offsetView(x:Float, y:Float):Void + { + flashSprite.x += x; + flashSprite.y += y; + } + + override function updatePosition():Void + { + if (flashSprite != null) + { + flashSprite.x = camera.x * FlxG.scaleMode.scale.x + _flashOffset.x; + flashSprite.y = camera.y * FlxG.scaleMode.scale.y + _flashOffset.y; + } + } + + override function updateScrollRect():Void + { + var rect:Rectangle = (_scrollRect != null) ? _scrollRect.scrollRect : null; + + if (rect != null) + { + rect.x = rect.y = 0; + + rect.width = camera.width * camera.initialZoom * FlxG.scaleMode.scale.x; + rect.height = camera.height * camera.initialZoom * FlxG.scaleMode.scale.y; + + _scrollRect.scrollRect = rect; + + _scrollRect.x = -0.5 * rect.width; + _scrollRect.y = -0.5 * rect.height; + } + } + + override function updateInternals():Void + { + if (canvas != null) + { + canvas.x = -0.5 * camera.width * (camera.scaleX - camera.initialZoom) * FlxG.scaleMode.scale.x; + canvas.y = -0.5 * camera.height * (camera.scaleY - camera.initialZoom) * FlxG.scaleMode.scale.y; + + canvas.scaleX = camera.totalScaleX; + canvas.scaleY = camera.totalScaleY; + + #if FLX_DEBUG + if (debugLayer != null) + { + debugLayer.x = canvas.x; + debugLayer.y = canvas.y; + + debugLayer.scaleX = camera.totalScaleX; + debugLayer.scaleY = camera.totalScaleY; + } + #end + } + } + + override function set_color(color:FlxColor):FlxColor + { + final colorTransform:ColorTransform = canvas.transform.colorTransform; + + colorTransform.redMultiplier = color.redFloat; + colorTransform.greenMultiplier = color.greenFloat; + colorTransform.blueMultiplier = color.blueFloat; + + canvas.transform.colorTransform = colorTransform; + + return color; + } + + override function set_alpha(alpha:Float):Float + { + return canvas.alpha = alpha; + } + + override function set_angle(angle:Float):Float + { + return flashSprite.rotation = angle; + } + + override function set_visible(visible:Bool):Bool + { + flashSprite.visible = visible; + return visible; + } + + override function get_display():DisplayObjectContainer + { + return flashSprite; + } + + /** + * Currently used draw stack item + */ + var _currentDrawItem:FlxDrawBaseItem; + + /** + * Pointer to head of stack with draw items + */ + var _headOfDrawStack:FlxDrawBaseItem; + + /** + * Last draw tiles item + */ + var _headTiles:FlxDrawQuadsItem; + + /** + * Last draw triangles item + */ + var _headTriangles:FlxDrawTrianglesItem; + + /** + * Draw tiles stack items that can be reused + */ + static var _storageTilesHead:FlxDrawQuadsItem; + + /** + * Draw triangles stack items that can be reused + */ + static var _storageTrianglesHead:FlxDrawTrianglesItem; + + @:noCompletion + public function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader) + { + #if FLX_RENDER_TRIANGLE + return startTrianglesBatch(graphic, smooth, colored, blend); + #else + var itemToReturn = null; + + if (_currentDrawItem != null + && _currentDrawItem.type == FlxDrawItemType.TILES + && _headTiles.graphics == graphic + && _headTiles.colored == colored + && _headTiles.hasColorOffsets == hasColorOffsets + && _headTiles.blend == blend + && _headTiles.antialiasing == smooth + && _headTiles.shader == shader) + { + return _headTiles; + } + + if (_storageTilesHead != null) + { + itemToReturn = _storageTilesHead; + var newHead = _storageTilesHead.nextTyped; + itemToReturn.reset(); + _storageTilesHead = newHead; + } + else + { + itemToReturn = new FlxDrawQuadsItem(); + } + + // TODO: catch this error when the dev actually messes up, not in the draw phase + if (graphic.isDestroyed) + throw 'Cannot queue ${graphic.key}. This sprite was destroyed.'; + + itemToReturn.graphics = graphic; + itemToReturn.antialiasing = smooth; + itemToReturn.colored = colored; + itemToReturn.hasColorOffsets = hasColorOffsets; + itemToReturn.blend = blend; + itemToReturn.shader = shader; + + itemToReturn.nextTyped = _headTiles; + _headTiles = itemToReturn; + + if (_headOfDrawStack == null) + { + _headOfDrawStack = itemToReturn; + } + + if (_currentDrawItem != null) + { + _currentDrawItem.next = itemToReturn; + } + + _currentDrawItem = itemToReturn; + + return itemToReturn; + #end + } + + @:noCompletion + public function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, + ?shader:FlxShader):FlxDrawTrianglesItem + { + if (_currentDrawItem != null + && _currentDrawItem.type == FlxDrawItemType.TRIANGLES + && _headTriangles.graphics == graphic + && _headTriangles.antialiasing == smoothing + && _headTriangles.colored == isColored + && _headTriangles.blend == blend + && _headTriangles.hasColorOffsets == hasColorOffsets + && _headTriangles.shader == shader) + { + return _headTriangles; + } + + return getNewDrawTrianglesItem(graphic, smoothing, isColored, blend, hasColorOffsets, shader); + } + + @:noCompletion + public function getNewDrawTrianglesItem(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, + ?shader:FlxShader):FlxDrawTrianglesItem + { + var itemToReturn:FlxDrawTrianglesItem = null; + + if (_storageTrianglesHead != null) + { + itemToReturn = _storageTrianglesHead; + var newHead:FlxDrawTrianglesItem = _storageTrianglesHead.nextTyped; + itemToReturn.reset(); + _storageTrianglesHead = newHead; + } + else + { + itemToReturn = new FlxDrawTrianglesItem(); + } + + itemToReturn.graphics = graphic; + itemToReturn.antialiasing = smoothing; + itemToReturn.colored = isColored; + itemToReturn.blend = blend; + itemToReturn.hasColorOffsets = hasColorOffsets; + itemToReturn.shader = shader; + + itemToReturn.nextTyped = _headTriangles; + _headTriangles = itemToReturn; + + if (_headOfDrawStack == null) + { + _headOfDrawStack = itemToReturn; + } + + if (_currentDrawItem != null) + { + _currentDrawItem.next = itemToReturn; + } + + _currentDrawItem = itemToReturn; + + return itemToReturn; + } + + @:noCompletion + public function clearDrawStack():Void + { + var currTiles = _headTiles; + var newTilesHead; + + while (currTiles != null) + { + newTilesHead = currTiles.nextTyped; + currTiles.reset(); + currTiles.nextTyped = _storageTilesHead; + _storageTilesHead = currTiles; + currTiles = newTilesHead; + } + + var currTriangles:FlxDrawTrianglesItem = _headTriangles; + var newTrianglesHead:FlxDrawTrianglesItem; + + while (currTriangles != null) + { + newTrianglesHead = currTriangles.nextTyped; + currTriangles.reset(); + currTriangles.nextTyped = _storageTrianglesHead; + _storageTrianglesHead = currTriangles; + currTriangles = newTrianglesHead; + } + + _currentDrawItem = null; + _headOfDrawStack = null; + _headTiles = null; + _headTriangles = null; + } +} diff --git a/flixel/system/scaleModes/StageSizeScaleMode.hx b/flixel/system/scaleModes/StageSizeScaleMode.hx index e6cecff086..15c041ff63 100644 --- a/flixel/system/scaleModes/StageSizeScaleMode.hx +++ b/flixel/system/scaleModes/StageSizeScaleMode.hx @@ -32,8 +32,8 @@ class StageSizeScaleMode extends BaseScaleMode var newH = Math.ceil(Height / FlxG.camera.zoom); FlxG.camera.setSize(newW, newH); - FlxG.camera.flashSprite.x += (newW - oldW) / 2; - FlxG.camera.flashSprite.y += (newH - oldH) / 2; + FlxG.camera.display.x += (newW - oldW) / 2; + FlxG.camera.display.y += (newH - oldH) / 2; } } } diff --git a/flixel/text/FlxBitmapText.hx b/flixel/text/FlxBitmapText.hx index e6f5ead1a2..f1ab0b7b8d 100644 --- a/flixel/text/FlxBitmapText.hx +++ b/flixel/text/FlxBitmapText.hx @@ -235,7 +235,7 @@ class FlxBitmapText extends FlxSprite this.font = (font == null) ? FlxBitmapFont.getDefaultFont() : font; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pixels = new BitmapData(1, 1, true, FlxColor.TRANSPARENT); } @@ -247,6 +247,11 @@ class FlxBitmapText extends FlxSprite } this.text = text; + + // initialize at runtime instead of statically to avoid a crash + // because FlxG.renderer(.method) is null + if (frameDrawHelper == null) + frameDrawHelper = new ReusableFrame(); } /** @@ -264,7 +269,7 @@ class FlxBitmapText extends FlxSprite _colorParams = null; - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { textData = null; textDrawData = null; @@ -278,13 +283,13 @@ class FlxBitmapText extends FlxSprite */ override public function drawFrame(Force:Bool = false):Void { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { Force = true; } pendingTextBitmapChange = pendingTextBitmapChange || Force; checkPendingChanges(false); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { super.drawFrame(Force); } @@ -298,7 +303,7 @@ class FlxBitmapText extends FlxSprite function checkPendingChanges(useTiles:Bool = false):Void { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { useTiles = false; } @@ -326,10 +331,10 @@ class FlxBitmapText extends FlxSprite static final borderColorTransformDrawHelper = new ColorTransform(); static final textColorTransformDrawHelper = new ColorTransform(); static final matrixDrawHelper = new FlxMatrix(); - static final frameDrawHelper = new ReusableFrame(); + static var frameDrawHelper:Null; override function draw() { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { checkPendingChanges(false); super.draw(); @@ -374,6 +379,8 @@ class FlxBitmapText extends FlxSprite continue; } + FlxG.renderer.begin(camera); + getScreenPosition(screenPos, camera).subtract(offset); if (isPixelPerfectRender(camera)) @@ -400,7 +407,7 @@ class FlxBitmapText extends FlxSprite matrix.translate(screenPos.x + originX, screenPos.y + originY); final colorTransform = bgColorTransformDrawHelper.reset(); colorTransform.setMultipliers(colorHelper).scaleMultipliers(backgroundColor); - camera.drawPixels(FlxG.bitmap.whitePixel, null, matrix, colorTransform, blend, antialiasing); + FlxG.renderer.drawPixels(FlxG.bitmap.whitePixel, null, matrix, colorTransform, blend, antialiasing); } final hasColorOffsets = (colorTransform != null && colorTransform.hasRGBAOffsets()); @@ -452,7 +459,7 @@ class FlxBitmapText extends FlxSprite override function set_clipRect(Rect:FlxRect):FlxRect { super.set_clipRect(Rect); - if (!FlxG.renderBlit) + if (FlxG.renderer.method != BLITTING) { pendingTextBitmapChange = true; } @@ -462,7 +469,7 @@ class FlxBitmapText extends FlxSprite override function set_color(Color:FlxColor):FlxColor { super.set_color(Color); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pendingTextBitmapChange = true; } @@ -472,7 +479,7 @@ class FlxBitmapText extends FlxSprite override function set_alpha(value:Float):Float { super.set_alpha(value); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pendingTextBitmapChange = true; } @@ -484,7 +491,7 @@ class FlxBitmapText extends FlxSprite if (textColor != value) { textColor = value; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pendingPixelsChange = true; } @@ -498,7 +505,7 @@ class FlxBitmapText extends FlxSprite if (useTextColor != value) { useTextColor = value; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pendingPixelsChange = true; } @@ -509,7 +516,7 @@ class FlxBitmapText extends FlxSprite override function calcFrame(RunOnCpp:Bool = false):Void { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { drawFrame(RunOnCpp); } @@ -1001,7 +1008,7 @@ class FlxBitmapText extends FlxSprite { computeTextSize(); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { useTiles = false; } @@ -1021,7 +1028,7 @@ class FlxBitmapText extends FlxSprite textBitmap.lock(); } - else if (FlxG.renderTile) + else if (FlxG.renderer.method != BLITTING) { textData.clear(); } @@ -1069,7 +1076,7 @@ class FlxBitmapText extends FlxSprite function drawLine(line:UnicodeString, posX:Int, posY:Int, useTiles:Bool = false):Void { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { useTiles = false; } @@ -1099,7 +1106,7 @@ class FlxBitmapText extends FlxSprite function tileLine(line:UnicodeString, startX:Int, startY:Int) { - if (!FlxG.renderTile) + if (FlxG.renderer.method != DRAW_TILES) return; addLineData(line, startX, startY, textData); @@ -1172,7 +1179,7 @@ class FlxBitmapText extends FlxSprite var colorForFill:Int = background ? backgroundColor : FlxColor.TRANSPARENT; var bitmap:BitmapData = null; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { if (pixels == null || (frameWidth != pixels.width || frameHeight != pixels.height)) { @@ -1224,7 +1231,7 @@ class FlxBitmapText extends FlxSprite bitmap.unlock(); } - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { dirty = true; } @@ -1319,7 +1326,7 @@ class FlxBitmapText extends FlxSprite function drawText(posX:Int, posY:Int, isFront:Bool = true, ?bitmap:BitmapData, useTiles:Bool = false):Void { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { useTiles = false; } @@ -1366,7 +1373,7 @@ class FlxBitmapText extends FlxSprite function tileText(posX:Int, posY:Int, isFront:Bool = true):Void { - if (!FlxG.renderTile) + if (FlxG.renderer.method != DRAW_TILES) return; final data:CharList = isFront ? textDrawData : borderDrawData; @@ -1553,7 +1560,7 @@ class FlxBitmapText extends FlxSprite if (background != value) { background = value; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pendingPixelsChange = true; } @@ -1567,7 +1574,7 @@ class FlxBitmapText extends FlxSprite if (backgroundColor != value) { backgroundColor = value; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pendingPixelsChange = true; } @@ -1592,7 +1599,7 @@ class FlxBitmapText extends FlxSprite if (borderColor != value) { borderColor = value; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pendingPixelsChange = true; } @@ -1793,8 +1800,6 @@ private class ReusableFrame extends FlxFrame public function new () { super(null); - // We need to define this now, since it's created before renderTile is set - tileMatrix = new MatrixVector(); } override function destroy() {} diff --git a/flixel/text/FlxText.hx b/flixel/text/FlxText.hx index b3dad3d00f..b608b7f57f 100644 --- a/flixel/text/FlxText.hx +++ b/flixel/text/FlxText.hx @@ -1071,7 +1071,7 @@ class FlxText extends FlxSprite if (textField == null) return; - if (FlxG.renderTile && !RunOnCpp) + if (FlxG.renderer.method != BLITTING && !RunOnCpp) return; regenGraphic(); diff --git a/flixel/tile/FlxTilemap.hx b/flixel/tile/FlxTilemap.hx index 85d3478b32..2694519df5 100644 --- a/flixel/tile/FlxTilemap.hx +++ b/flixel/tile/FlxTilemap.hx @@ -286,7 +286,7 @@ class FlxTypedTilemap extends FlxBaseTilemap { super(); - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { _helperPoint = new Point(); _matrix = new FlxMatrix(); @@ -305,7 +305,7 @@ class FlxTypedTilemap extends FlxBaseTilemap debugBoundingBoxColorPartial = FlxColor.PINK; debugBoundingBoxColorNotSolid = FlxColor.TRANSPARENT; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) FlxG.debugger.drawDebugChanged.add(onDrawDebugChanged); #end } @@ -321,7 +321,7 @@ class FlxTypedTilemap extends FlxBaseTilemap _tileObjects = FlxDestroyUtil.destroyArray(_tileObjects); _buffers = FlxDestroyUtil.destroyArray(_buffers); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { #if FLX_DEBUG _debugRect = null; @@ -351,7 +351,7 @@ class FlxTypedTilemap extends FlxBaseTilemap FlxG.cameras.cameraResized.remove(onCameraChanged); #if FLX_DEBUG - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) FlxG.debugger.drawDebugChanged.remove(onDrawDebugChanged); #end @@ -499,7 +499,7 @@ class FlxTypedTilemap extends FlxBaseTilemap function updateDebugTile(tileBitmap:BitmapData, color:FlxColor):BitmapData { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) return null; if (tileWidth <= 0 || tileHeight <= 0) @@ -530,7 +530,7 @@ class FlxTypedTilemap extends FlxBaseTilemap override function updateMap():Void { #if FLX_DEBUG - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) _debugRect = new Rectangle(0, 0, tileWidth, tileHeight); #end @@ -542,9 +542,11 @@ class FlxTypedTilemap extends FlxBaseTilemap #if FLX_DEBUG override function drawDebugOnCamera(camera:FlxCamera):Void { - if (!FlxG.renderTile) + if (FlxG.renderer.method != DRAW_TILES) return; + FlxG.renderer.beginDrawDebug(camera); + var buffer:FlxTilemapBuffer = null; var l:Int = FlxG.cameras.list.length; @@ -595,7 +597,7 @@ class FlxTypedTilemap extends FlxBaseTilemap if (color != null) { final colStr = color.toHexString(); - drawDebugBoundingBoxColor(camera.debugLayer.graphics, rect, color); + drawDebugBoundingBoxColor(rect, color); } } } @@ -656,7 +658,7 @@ class FlxTypedTilemap extends FlxBaseTilemap buffer = _buffers[i]; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { if (buffer.isDirty(this, camera)) drawTilemap(buffer, camera); @@ -704,7 +706,7 @@ class FlxTypedTilemap extends FlxBaseTilemap */ override function setDirty(dirty:Bool = true):Void { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) return; for (buffer in _buffers) @@ -1214,7 +1216,7 @@ class FlxTypedTilemap extends FlxBaseTilemap var scaledHeight:Float = 0; var drawItem = null; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { buffer.fill(); } @@ -1268,7 +1270,7 @@ class FlxTypedTilemap extends FlxBaseTilemap { frame = tile.frame; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { frame.paint(buffer.pixels, _flashPoint, true); @@ -1316,13 +1318,13 @@ class FlxTypedTilemap extends FlxBaseTilemap } } - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) _flashPoint.x += tileWidth; columnIndex++; } - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) _flashPoint.y += tileHeight; rowIndex += widthInTiles; } @@ -1330,7 +1332,7 @@ class FlxTypedTilemap extends FlxBaseTilemap buffer.x = screenXInTiles * scaledTileWidth; buffer.y = screenYInTiles * scaledTileHeight; - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { if (isColored) buffer.colorTransform(colorTransform); @@ -1347,7 +1349,7 @@ class FlxTypedTilemap extends FlxBaseTilemap #if FLX_DEBUG function makeDebugTile(color:FlxColor):BitmapData { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) return null; var debugTile = new BitmapData(tileWidth, tileHeight, true, 0); diff --git a/flixel/tile/FlxTilemapBuffer.hx b/flixel/tile/FlxTilemapBuffer.hx index e5593b3d7c..454650fb2a 100644 --- a/flixel/tile/FlxTilemapBuffer.hx +++ b/flixel/tile/FlxTilemapBuffer.hx @@ -61,7 +61,7 @@ class FlxTilemapBuffer implements IFlxDestroyable public var pixelPerfectRender:Null; /** - * The actual buffer BitmapData. (Only used if FlxG.renderBlit == true) + * The actual buffer BitmapData. (Only used with the blitting renderer) */ public var pixels(default, null):BitmapData; @@ -117,7 +117,7 @@ class FlxTilemapBuffer implements IFlxDestroyable updateColumns(tileWidth, widthInTiles, scaleX, camera); updateRows(tileHeight, heightInTiles, scaleY, camera); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { final newWidth = Std.int(columns * tileWidth); final newHeight = Std.int(rows * tileHeight); @@ -144,7 +144,7 @@ class FlxTilemapBuffer implements IFlxDestroyable */ public function destroy():Void { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pixels = FlxDestroyUtil.dispose(pixels); blend = null; @@ -161,7 +161,7 @@ class FlxTilemapBuffer implements IFlxDestroyable */ public function fill(color = FlxColor.TRANSPARENT):Void { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pixels.fillRect(_flashRect, color); } @@ -180,17 +180,19 @@ class FlxTilemapBuffer implements IFlxDestroyable flashPoint.x = Math.floor(flashPoint.x); flashPoint.y = Math.floor(flashPoint.y); } - + + FlxG.renderer.begin(camera); + if (isPixelPerfectRender(camera) && (scaleX == 1.0 && scaleY == 1.0) && blend == null) { - camera.copyPixels(pixels, _flashRect, flashPoint, null, null, true); + FlxG.renderer.copyPixels(pixels, _flashRect, flashPoint, null, null, true); } else { _matrix.identity(); _matrix.scale(scaleX, scaleY); _matrix.translate(flashPoint.x, flashPoint.y); - camera.drawPixels(pixels, _matrix, null, blend, antialiasing); + FlxG.renderer.drawPixels(pixels, _matrix, null, blend, antialiasing); } } diff --git a/flixel/ui/FlxBar.hx b/flixel/ui/FlxBar.hx index dcc0ac13d1..fa26277b06 100644 --- a/flixel/ui/FlxBar.hx +++ b/flixel/ui/FlxBar.hx @@ -172,7 +172,7 @@ class FlxBar extends FlxSprite _filledBarPoint = new Point(); _filledBarRect = new Rectangle(); - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { _zeroOffset = new Point(); _emptyBarRect = new Rectangle(); @@ -198,7 +198,7 @@ class FlxBar extends FlxSprite { positionOffset = FlxDestroyUtil.put(positionOffset); - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { frontFrames = null; _filledFlxRect = FlxDestroyUtil.put(_filledFlxRect); @@ -352,7 +352,7 @@ class FlxBar extends FlxSprite */ public function createColoredEmptyBar(empty:FlxColor, showBorder:Bool = false, border:FlxColor = FlxColor.WHITE, borderSize:Int = 1):FlxBar { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { var emptyKey:String = "empty: " + barWidth + "x" + barHeight + ":" + empty.toHexString(); if (showBorder) @@ -406,7 +406,7 @@ class FlxBar extends FlxSprite */ public function createColoredFilledBar(fill:FlxColor, showBorder:Bool = false, border:FlxColor = FlxColor.WHITE, borderSize:Int = 1):FlxBar { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { var filledKey:String = "filled: " + barWidth + "x" + barHeight + ":" + fill.toHexString(); if (showBorder) @@ -484,7 +484,7 @@ class FlxBar extends FlxSprite public function createGradientEmptyBar(empty:Array, chunkSize:Int = 1, rotation:Int = 180, showBorder:Bool = false, border:FlxColor = FlxColor.WHITE, borderSize:Int = 1):FlxBar { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { var emptyKey:String = "Gradient:" + barWidth + "x" + barHeight + ",colors:["; for (col in empty) @@ -552,7 +552,7 @@ class FlxBar extends FlxSprite public function createGradientFilledBar(fill:Array, chunkSize:Int = 1, rotation:Int = 180, showBorder:Bool = false, border:FlxColor = FlxColor.WHITE, borderSize:Int = 1):FlxBar { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { var filledKey:String = "Gradient:" + barWidth + "x" + barHeight + ",colors:["; for (col in fill) @@ -639,7 +639,7 @@ class FlxBar extends FlxSprite { var emptyGraphic:FlxGraphic = FlxG.bitmap.add(empty); - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { frames = emptyGraphic.imageFrame; } @@ -681,7 +681,7 @@ class FlxBar extends FlxSprite { var filledGraphic:FlxGraphic = FlxG.bitmap.add(fill); - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { frontFrames = filledGraphic.imageFrame; } @@ -744,7 +744,7 @@ class FlxBar extends FlxSprite */ public function updateEmptyBar():Void { - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pixels.copyPixels(_emptyBar, _emptyBarRect, _zeroOffset); dirty = true; @@ -806,7 +806,7 @@ class FlxBar extends FlxSprite _filledBarPoint.y = Std.int((barHeight - _filledBarRect.height) / 2); } - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { pixels.copyPixels(_filledBar, _filledBarRect, _filledBarPoint, null, null, true); } @@ -823,7 +823,7 @@ class FlxBar extends FlxSprite } } - if (FlxG.renderBlit) + if (FlxG.renderer.method == BLITTING) { dirty = true; } @@ -852,7 +852,7 @@ class FlxBar extends FlxSprite { super.draw(); - if (!FlxG.renderTile) + if (FlxG.renderer.method != DRAW_TILES) return; if (alpha == 0) @@ -890,14 +890,15 @@ class FlxBar extends FlxSprite _matrix.ty = Math.floor(_matrix.ty); } - camera.drawPixels(_frontFrame, _matrix, colorTransform, blend, antialiasing, shader); + FlxG.renderer.begin(camera); + FlxG.renderer.drawPixels(_frontFrame, _matrix, colorTransform, blend, antialiasing, shader); } } } override function set_pixels(pixels:BitmapData):BitmapData { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { return pixels; // hack } @@ -982,7 +983,7 @@ class FlxBar extends FlxSprite function get_frontFrames():FlxImageFrame { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { return frontFrames; } @@ -991,7 +992,7 @@ class FlxBar extends FlxSprite function set_frontFrames(value:FlxImageFrame):FlxImageFrame { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { if (value != null) value.parent.incrementUseCount(); @@ -1011,7 +1012,7 @@ class FlxBar extends FlxSprite function get_backFrames():FlxImageFrame { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { return cast frames; } @@ -1020,7 +1021,7 @@ class FlxBar extends FlxSprite function set_backFrames(value:FlxImageFrame):FlxImageFrame { - if (FlxG.renderTile) + if (FlxG.renderer.method != BLITTING) { frames = value; } diff --git a/tests/unit/src/flixel/FlxGTest.hx b/tests/unit/src/flixel/FlxGTest.hx index 58d3daac76..1db3789e96 100644 --- a/tests/unit/src/flixel/FlxGTest.hx +++ b/tests/unit/src/flixel/FlxGTest.hx @@ -23,6 +23,9 @@ class FlxGTest extends FlxTest @Test function testSaveNull():Void Assert.isNotNull(FlxG.save); + @Test function testRendererNull():Void + Assert.isNotNull(FlxG.renderer); + #if FLX_MOUSE @Test function testMouseNull():Void Assert.isNotNull(FlxG.mouse);