diff --git a/flixel/FlxCamera.hx b/flixel/FlxCamera.hx index c2c92ca4e7..43214fb110 100644 --- a/flixel/FlxCamera.hx +++ b/flixel/FlxCamera.hx @@ -10,15 +10,21 @@ 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.FlxVertexBuffer; +import flixel.system.render.blit.FlxBlitRenderer; +import flixel.system.render.blit.FlxBlitView; +import flixel.system.render.quad.FlxQuadRenderer; +import flixel.system.render.quad.FlxQuadView; 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; import openfl.display.BlendMode; import openfl.display.DisplayObject; +import openfl.display.DisplayObjectContainer; import openfl.display.Graphics; import openfl.display.Sprite; import openfl.filters.BitmapFilter; @@ -32,15 +38,8 @@ 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) */ +@:access(flixel.system.render) class FlxCamera extends FlxBasic { /** @@ -97,6 +96,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. + */ + var viewQuad(default, null):Null; + + /** + * This camera's `view`, typed as a `FlxBlitView`. + * + * **NOTE**: May be null depending on the render implementation used. + */ + var viewBlit(default, null):Null; + /** * Tells the camera to use this following style. */ @@ -156,27 +174,12 @@ class FlxCamera extends FlxBasic */ public var scroll:FlxPoint = FlxPoint.get(); - /** - * 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; - /** * The natural background color of the camera, in `AARRGGBB` format. Defaults to `FlxG.cameras.bgColor`. * On Flash, transparent backgrounds can be used in conjunction with `useBgAlphaBlending`. */ public var bgColor:FlxColor; - /** - * 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; - /** * Whether to use alpha blending for the camera's background fill or not. * If `true`, then the previously drawn graphics won't be erased, @@ -188,20 +191,10 @@ class FlxCamera extends FlxBasic */ public var useBgAlphaBlending:Bool = false; - /** - * 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(); - /** * 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,17 +310,6 @@ class FlxCamera extends FlxBasic */ public var viewBottom(get, never):Float; - /** - * 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(); - - /** - * Logical flag for tracking whether to apply _blitMatrix transformation to objects or not. - */ - var _useBlitMatrix:Bool = false; - /** * The alpha value of this camera display (a number between `0.0` and `1.0`). */ @@ -347,6 +329,8 @@ class FlxCamera extends FlxBasic * Whether the camera display is smooth and filtered, or chunky and pixelated. * Default behavior is chunky-style. */ + @:noCompletion + @:deprecated("camera.antialiasing is deprecated, use camera.view.anstialiasing instead") public var antialiasing(default, set):Bool = false; /** @@ -359,30 +343,6 @@ class FlxCamera extends FlxBasic */ public var filtersEnabled:Bool = true; - /** - * 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 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(); - - /** - * Internal, used for positioning camera's `flashSprite` on screen. - * Basically it represents position of camera's center point in game sprite. - * It's recalculated every time you resize game or camera. - * 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(); - /** * Internal, represents the color of `flash()` special effect. */ @@ -474,710 +434,236 @@ class FlxCamera extends FlxBasic * Camera's initial zoom value. Used for camera's scale handling. */ public var initialZoom(default, null):Float = 1; - - /** - * Internal helper variable for doing better wipes/fills between renders. - * Used it blit render mode only (in `fill()` method). - */ - var _fill:BitmapData; - - /** - * 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 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(); - - /** - * Helper rect for `drawTriangles()` visibility checks - */ - var _bounds:FlxRect = FlxRect.get(); - - /** - * 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 - - var _helperMatrix:FlxMatrix = new FlxMatrix(); - - var _helperPoint:Point = new Point(); - - /** - * 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 + * 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 */ - static var _storageTrianglesHead:FlxDrawTrianglesItem; + inline function transformRect(rect:FlxRect):FlxRect + { + return view.transformRect(rect); + } /** - * Internal variable, used for visibility checks to minimize `drawTriangles()` calls. + * 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 */ - static var drawVertices:Vector = new Vector(); + inline function transformPoint(point:FlxPoint):FlxPoint + { + return view.transformPoint(point); + } /** - * Internal variable, used in blit render mode to render triangles (`drawTriangles()`) on camera's buffer. + * 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 */ - static var trianglesSprite:Sprite = new Sprite(); - + inline function transformVector(vector:FlxPoint):FlxPoint + { + return view.transformVector(vector); + } + /** - * Internal variables, used in blit render mode to draw trianglesSprite on camera's buffer. - * Added for less garbage creation. + * Instantiates a new camera at the specified location, with the specified size and zoom level. + * + * @param x X location of the camera's display in pixels. Uses native, 1:1 resolution, ignores zoom. + * @param y Y location of the camera's display in pixels. Uses native, 1:1 resolution, ignores zoom. + * @param width The width of the camera display in pixels. + * @param height The height of the camera display in pixels. + * @param zoom The initial zoom level of the camera. + * A zoom level of 2 will make all pixels display at 2x resolution. */ - static var renderPoint:FlxPoint = FlxPoint.get(); - - static var renderRect:FlxRect = FlxRect.get(); - - @:noCompletion - public function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader) + @:haxe.warning("-WDeprecated") + public function new(x = 0.0, y = 0.0, width = 0, height = 0, zoom = 0.0) { - #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.'; + super(); - itemToReturn.graphics = graphic; - itemToReturn.antialiasing = smooth; - itemToReturn.colored = colored; - itemToReturn.hasColorOffsets = hasColorOffsets; - itemToReturn.blend = blend; - itemToReturn.shader = shader; + this.x = x; + this.y = y; - itemToReturn.nextTyped = _headTiles; - _headTiles = itemToReturn; + if (zoom == 0) + zoom = defaultZoom; + + // Use the game dimensions if width / height are <= 0 + if (width <= 0) + width = Math.ceil(FlxG.width / zoom); + if (height <= 0) + height = Math.ceil(FlxG.height / zoom); + + this.width = width; + this.height = height; - if (_headOfDrawStack == null) + view = createView(); + if (view is FlxQuadView) { - _headOfDrawStack = itemToReturn; + viewQuad = Std.downcast(view, FlxQuadView); + @:bypassAccessor _flashPoint = new Point(); + @:bypassAccessor _blitMatrix = new FlxMatrix(); + @:bypassAccessor _flashRect = new Rectangle(); + + @:bypassAccessor flashSprite = viewQuad.flashSprite; + @:bypassAccessor _flashOffset = viewQuad._flashOffset; + @:bypassAccessor _scrollRect = viewQuad._scrollRect; + @:bypassAccessor canvas = viewQuad.canvas; + #if FLX_DEBUG + @:bypassAccessor debugLayer = viewQuad.canvas; + #end + } - - if (_currentDrawItem != null) + else if (view is FlxBlitView) { - _currentDrawItem.next = itemToReturn; + viewBlit = Std.downcast(view, FlxBlitView); + @:bypassAccessor _flashPoint = viewBlit._flashPoint; + @:bypassAccessor flashSprite = viewBlit.flashSprite; + @:bypassAccessor _flashOffset = viewBlit._flashOffset; + @:bypassAccessor _scrollRect = viewBlit._scrollRect; + @:bypassAccessor _flashRect = viewBlit._flashRect; + + @:bypassAccessor screen = viewBlit.screen; + @:bypassAccessor buffer = viewBlit.buffer; + @:bypassAccessor _flashBitmap = viewBlit._flashBitmap; + @:bypassAccessor _blitMatrix = viewBlit._blitMatrix; + @:bypassAccessor _fill = viewBlit._fill; } - _currentDrawItem = itemToReturn; + pixelPerfectRender = FlxG.renderer.blit; - return itemToReturn; - #end - } + set_color(FlxColor.WHITE); + + // sets the scale of flash sprite, which in turn loads flashOffset values + this.zoom = initialZoom = zoom; + + updateScrollRect(); + updateFlashOffset(); + updateFlashSpritePosition(); + updateInternalSpritePositions(); - @:noCompletion - public function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader):FlxDrawTrianglesItem + bgColor = FlxG.cameras.bgColor; + } + + function createView() { - 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 FlxG.renderer.createCameraView(this); } - @:noCompletion - public function getNewDrawTrianglesItem(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader):FlxDrawTrianglesItem + /** + * Clean up memory. + */ + @:haxe.warning("-WDeprecated") + override public function destroy():Void { - var itemToReturn:FlxDrawTrianglesItem = null; - - if (_storageTrianglesHead != null) - { - itemToReturn = _storageTrianglesHead; - var newHead:FlxDrawTrianglesItem = _storageTrianglesHead.nextTyped; - itemToReturn.reset(); - _storageTrianglesHead = newHead; - } - else - { - itemToReturn = new FlxDrawTrianglesItem(); - } + view.destroy(); - itemToReturn.graphics = graphic; - itemToReturn.antialiasing = smoothing; - itemToReturn.colored = isColored; - itemToReturn.blend = blend; - itemToReturn.hasColorOffsets = hasColorOffsets; - itemToReturn.shader = shader; + scroll = FlxDestroyUtil.put(scroll); + targetOffset = FlxDestroyUtil.put(targetOffset); + deadzone = FlxDestroyUtil.put(deadzone); - itemToReturn.nextTyped = _headTriangles; - _headTriangles = itemToReturn; + target = null; + _fxFlashComplete = null; + _fxFadeComplete = null; + _fxShakeComplete = null; + + // --- deprecated view fields + @:bypassAccessor buffer = null; + @:bypassAccessor screen = null; + @:bypassAccessor flashSprite = null; + @:bypassAccessor _blitMatrix = null; + @:bypassAccessor _flashRect = null; + @:bypassAccessor _flashPoint = null; + @:bypassAccessor _flashOffset = null; + @:bypassAccessor _fill = null; + @:bypassAccessor _flashBitmap = null; + @:bypassAccessor _scrollRect = null; + @:bypassAccessor canvas = null; + @:bypassAccessor _currentDrawItem = null; + @:bypassAccessor _headOfDrawStack = null; + @:bypassAccessor _headTiles = null; + @:bypassAccessor _headTriangles = null; + @:bypassAccessor _bounds = FlxDestroyUtil.put(_bounds); + #if FLX_DEBUG + @:bypassAccessor debugLayer = null; + #end + + _helperMatrix = null; + _helperPoint = null; - if (_headOfDrawStack == null) - { - _headOfDrawStack = itemToReturn; - } + super.destroy(); + } - if (_currentDrawItem != null) + /** + * Updates the camera scroll as well as special effects like screen-shake or fades. + */ + override public function update(elapsed:Float):Void + { + // follow the target, if there is one + if (target != null) { - _currentDrawItem.next = itemToReturn; + updateFollow(); + updateLerp(elapsed); } - _currentDrawItem = itemToReturn; + updateScroll(); + updateFlash(elapsed); + updateFade(elapsed); - return itemToReturn; + updateFlashSpritePosition(); + updateShake(elapsed); } - @:allow(flixel.system.frontEnds.CameraFrontEnd) - function clearDrawStack():Void + /** + * Updates (bounds) the camera scroll. + * Called every frame by camera's `update()` method. + */ + public function updateScroll():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; - } + // Make sure we didn't go outside the camera's bounds + bindScrollPos(scroll); + } + + /** + * Takes the desired scroll position and restricts it to the camera's min/max scroll properties. + * This modifies the given point. + * + * @param scrollPos The scroll position + * @return The same point passed in, moved within the scroll bounds + * @since 5.4.0 + */ + public function bindScrollPos(scrollPos:FlxPoint) + { + final minX:Null = minScrollX == null ? null : minScrollX - viewMarginLeft; + final maxX:Null = maxScrollX == null ? null : maxScrollX - viewMarginRight; + final minY:Null = minScrollY == null ? null : minScrollY - viewMarginTop; + final maxY:Null = maxScrollY == null ? null : maxScrollY - viewMarginBottom; - _currentDrawItem = null; - _headOfDrawStack = null; - _headTiles = null; - _headTriangles = null; + // keep point within bounds + scrollPos.x = FlxMath.bound(scrollPos.x, minX, maxX); + scrollPos.y = FlxMath.bound(scrollPos.y, minY, maxY); + return scrollPos; } - @:allow(flixel.system.frontEnds.CameraFrontEnd) - function render():Void + /** + * Updates camera's scroll. + * Called every frame by camera's `update()` method (if camera's `target` isn't `null`). + */ + function updateFollow():Void { - flashSprite.filters = filtersEnabled ? filters : null; - - var currItem:FlxDrawBaseItem = _headOfDrawStack; - while (currItem != null) + // Either follow the object closely, + // or double check our deadzone and update accordingly. + if (deadzone == null) { - currItem.render(this); - currItem = currItem.next; + target.getMidpoint(_point); + _point.add(targetOffset); + _scrollTarget.set(_point.x - width * 0.5, _point.y - height * 0.5); } - } - - public function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, - ?shader:FlxShader):Void - { - if (FlxG.renderBlit) + else { - _helperMatrix.copyFrom(matrix); + var edge:Float; + var targetX:Float = target.x + targetOffset.x; + var targetY:Float = target.y + targetOffset.y; - 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); - } - } - - 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); - } - } - - 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); - } - } - - /** - * 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 - { - if (FlxG.renderBlit) - { - rect.offset(-viewMarginLeft, -viewMarginTop); - - if (_useBlitMatrix) - { - rect.x *= zoom; - rect.y *= zoom; - rect.width *= zoom; - rect.height *= zoom; - } - } - - 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 - { - if (FlxG.renderBlit) - { - point.subtract(viewMarginLeft, viewMarginTop); - - if (_useBlitMatrix) - point.scale(zoom); - } - - 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 - */ - inline function transformVector(vector:FlxPoint):FlxPoint - { - if (FlxG.renderBlit && _useBlitMatrix) - vector.scale(zoom); - - 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 *= 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; - } - - /** - * Instantiates a new camera at the specified location, with the specified size and zoom level. - * - * @param x X location of the camera's display in pixels. Uses native, 1:1 resolution, ignores zoom. - * @param y Y location of the camera's display in pixels. Uses native, 1:1 resolution, ignores zoom. - * @param width The width of the camera display in pixels. - * @param height The height of the camera display in pixels. - * @param zoom The initial zoom level of the camera. - * A zoom level of 2 will make all pixels display at 2x resolution. - */ - public function new(x = 0.0, y = 0.0, width = 0, height = 0, zoom = 0.0) - { - super(); - - this.x = x; - this.y = y; - - if (zoom == 0) - zoom = defaultZoom; - - // Use the game dimensions if width / height are <= 0 - if (width <= 0) - width = Math.ceil(FlxG.width / zoom); - if (height <= 0) - height = Math.ceil(FlxG.height / zoom); - - this.width = width; - this.height = height; - _flashRect = new Rectangle(0, 0, width, height); - - flashSprite.addChild(_scrollRect); - _scrollRect.scrollRect = new Rectangle(); - - 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 - } - - set_color(FlxColor.WHITE); - - // sets the scale of flash sprite, which in turn loads flashOffset values - this.zoom = initialZoom = zoom; - - updateScrollRect(); - updateFlashOffset(); - updateFlashSpritePosition(); - updateInternalSpritePositions(); - - bgColor = FlxG.cameras.bgColor; - } - - /** - * Clean up memory. - */ - override public function destroy():Void - { - FlxDestroyUtil.removeChild(flashSprite, _scrollRect); - - 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; - - super.destroy(); - } - - /** - * Updates the camera scroll as well as special effects like screen-shake or fades. - */ - override public function update(elapsed:Float):Void - { - // follow the target, if there is one - if (target != null) - { - updateFollow(); - updateLerp(elapsed); - } - - updateScroll(); - updateFlash(elapsed); - updateFade(elapsed); - - updateFlashSpritePosition(); - updateShake(elapsed); - } - - /** - * Updates (bounds) the camera scroll. - * Called every frame by camera's `update()` method. - */ - public function updateScroll():Void - { - // Make sure we didn't go outside the camera's bounds - bindScrollPos(scroll); - } - - /** - * Takes the desired scroll position and restricts it to the camera's min/max scroll properties. - * This modifies the given point. - * - * @param scrollPos The scroll position - * @return The same point passed in, moved within the scroll bounds - * @since 5.4.0 - */ - public function bindScrollPos(scrollPos:FlxPoint) - { - final minX:Null = minScrollX == null ? null : minScrollX - viewMarginLeft; - final maxX:Null = maxScrollX == null ? null : maxScrollX - viewMarginRight; - final minY:Null = minScrollY == null ? null : minScrollY - viewMarginTop; - final maxY:Null = maxScrollY == null ? null : maxScrollY - viewMarginBottom; - - // keep point within bounds - scrollPos.x = FlxMath.bound(scrollPos.x, minX, maxX); - scrollPos.y = FlxMath.bound(scrollPos.y, minY, maxY); - return scrollPos; - } - - /** - * Updates camera's scroll. - * Called every frame by camera's `update()` method (if camera's `target` isn't `null`). - */ - function updateFollow():Void - { - // Either follow the object closely, - // or double check our deadzone and update accordingly. - if (deadzone == null) - { - target.getMidpoint(_point); - _point.add(targetOffset); - _scrollTarget.set(_point.x - width * 0.5, _point.y - height * 0.5); - } - else - { - var edge:Float; - var targetX:Float = target.x + targetOffset.x; - var targetY:Float = target.y + targetOffset.y; - - if (style == SCREEN_BY_SCREEN) + if (style == SCREEN_BY_SCREEN) { if (targetX >= viewRight) { @@ -1315,6 +801,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 +811,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 +820,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 +834,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 +844,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 +858,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 +870,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(); } /** @@ -1635,110 +1083,29 @@ class FlxCamera extends FlxBasic return this; } - /** - * 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`. - */ - 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(); - } - } - /** * 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 { // 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; + view.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; + view.fill(color); } } - - @:allow(flixel.system.frontEnds.CameraFrontEnd) - 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(); - } - } - - inline function updateBlitMatrix():Void - { - _blitMatrix.identity(); - _blitMatrix.translate(-viewMarginLeft, -viewMarginTop); - _blitMatrix.scale(scaleX, scaleY); - - _useBlitMatrix = (scaleX < initialZoom) || (scaleY < initialZoom); - } - + /** * Shortcut for setting both `width` and `height`. * @@ -2142,22 +1509,8 @@ 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; - } - } - + view.updateScale(); + calcMarginX(); calcMarginY(); @@ -2220,6 +1573,7 @@ class FlxCamera extends FlxBasic if (width != Value && Value > 0) { width = Value; + calcMarginX(); updateFlashOffset(); updateScrollRect(); @@ -2235,6 +1589,7 @@ class FlxCamera extends FlxBasic if (height != Value && Value > 0) { height = Value; + calcMarginY(); updateFlashOffset(); updateScrollRect(); @@ -2248,75 +1603,30 @@ class FlxCamera extends FlxBasic function set_zoom(Zoom:Float):Float { zoom = (Zoom == 0) ? defaultZoom : Zoom; - setScale(zoom, zoom); - return zoom; - } - - function set_alpha(Alpha:Float):Float - { - alpha = FlxMath.bound(Alpha, 0, 1); - if (FlxG.renderBlit) - { - _flashBitmap.alpha = Alpha; - } - else - { - canvas.alpha = Alpha; - } - return Alpha; - } - - function set_angle(Angle:Float):Float - { - angle = Angle; - flashSprite.rotation = Angle; - return Angle; - } - - 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; + setScale(zoom, zoom); + return zoom; } - function set_antialiasing(Antialiasing:Bool):Bool + function set_alpha(value:Float):Float { - antialiasing = Antialiasing; - if (FlxG.renderBlit) - { - _flashBitmap.smoothing = Antialiasing; - } - return Antialiasing; + return this.alpha = view.alpha = FlxMath.bound(value, 0, 1); } - + + function set_angle(value:Float):Float + { + return this.angle = view.angle = value; + } + + function set_color(value:FlxColor):FlxColor + { + return this.color = view.color = value; + } + + function set_antialiasing(value:Bool):Bool + { + return this.antialiasing = view.antialiasing = value; + } + function set_x(x:Float):Float { this.x = x; @@ -2331,13 +1641,9 @@ class FlxCamera extends FlxBasic return y; } - override function set_visible(visible:Bool):Bool + override function set_visible(value:Bool):Bool { - if (flashSprite != null) - { - flashSprite.visible = visible; - } - return this.visible = visible; + return this.visible = view.visible = value; } inline function calcMarginX():Void @@ -2440,6 +1746,499 @@ class FlxCamera extends FlxBasic @:noCompletion override function set_cameras(value:Array):Array throw "don't reference camera.cameras"; + //{ region ------ DEPRECATED VIEW FIELDS ------ + + @:noCompletion + @:deprecated("camera.transformObject is deprecated, there will be no replacement") + 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; + } + + @:noCompletion + @:deprecated("camera.startQuadBatch() is deprecated, use view.startQuadBatch() instead.") // 6.2.0 + public function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader) + { + return viewQuad.startQuadBatch(graphic, colored, hasColorOffsets, blend, smooth, shader); + } + + @:noCompletion + @:deprecated("camera.startTrianglesBatch() is deprecated, use view.startTrianglesBatch() instead.") // 6.2.0 + public function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader):FlxDrawTrianglesItem + { + return viewQuad.startTrianglesBatch(graphic, smoothing, isColored, blend, hasColorOffsets, shader); + } + + @:noCompletion + @:deprecated("camera.getNewDrawTrianglesItem() is deprecated, use view.getNewDrawTrianglesItem() instead.") // 6.2.0 + public function getNewDrawTrianglesItem(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader):FlxDrawTrianglesItem + { + return viewQuad.getNewDrawTrianglesItem(graphic, smoothing, isColored, blend, hasColorOffsets, shader); + } + + @:noCompletion + @:deprecated("camera.render() is deprecated, use view.render() instead.") // 6.2.0 + function render():Void + { + view.render(); + } + + @:noCompletion + @:deprecated("camera.fill() is deprecated, use camera.view.fill() instead.") // 6.2.0 + public function fill(color:FlxColor, blendAlpha:Bool = true, fxAlpha:Float = 1.0, ?graphics:Graphics):Void + { + color.alphaFloat = fxAlpha; + + final useTargetGraphic = graphics != null #if FLX_DEBUG && graphics != view.getDebugBuffer() #end; + if (useTargetGraphic) + { + graphics.overrideBlendMode(null); + final buffer:FlxVertexBuffer = cast graphics; + // 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 + buffer.drawFilledRect(camera.viewMarginLeft - 1, camera.viewMarginTop - 1, camera.viewWidth + 2, camera.viewHeight + 2, color); + return; + } + + view.fill(color, blendAlpha); + } + + @:noCompletion + @:deprecated("camera.clearDrawStack() is deprecated, use camera.viewQuad.render() instead.") // 6.2.0 + function clearDrawStack():Void + { + viewQuad.clearDrawStack(); + } + + @:noCompletion + @:deprecated("camera.drawPixels() is deprecated, use camera.view.drawPixels or drawFrame instead.") // 6.2.0 + public function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, + ?shader:FlxShader):Void + { + if (pixels != null) + view.drawPixels(pixels, matrix, transform, blend, smoothing, shader); + else if (frame != null) + view.drawFrame(frame, matrix, transform, blend, smoothing, shader); + else + FlxG.log.error("camera.drawPixels must have either the frame or pixels arg"); + } + + @:noCompletion + @:deprecated("camera.copyPixels() is deprecated, use camera.view.copyPixels or copyFrame instead.") // 6.2.0 + public function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, + ?smoothing:Bool = false, ?shader:FlxShader):Void + { + if (pixels != null) + view.copyPixels(pixels, sourceRect, destPoint, transform, blend, smoothing, shader); + else if (frame != null) + view.copyFrame(frame, destPoint, transform, blend, smoothing, shader); + else + FlxG.log.error("camera.copyPixels must have either the frame or pixels arg"); + + } + + @:noCompletion + @:deprecated("camera.drawTriangles() is deprecated, use camera.view.drawTriangles instead.") // 6.2.0 + 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 + { + view.drawTriangles(graphic, vertices, indices, uvtData, colors, position, blend, repeat, smoothing, transform, shader); + } + + @:noCompletion + @:deprecated("checkResize() is deprecated") // 6.2.0 + function checkResize():Void + { + if (FlxG.renderer.blit) + viewBlit.checkResize(); + } + + @:noCompletion + @:deprecated("updateBlitMatrix() is deprecated, use camera.viewBlit.updateBlitMatrix(), instead") // 6.2.0 + inline function updateBlitMatrix():Void + { + viewBlit.updateBlitMatrix(); + } + + @:noCompletion + @:deprecated("buffer is deprecated, use camera.viewBlit.buffer, instead") // 6.2.0 + @:isVar public var buffer(get, set):Null; + function get_buffer() + { + if (viewBlit != null) + this.buffer = viewBlit.buffer; + + return this.buffer; + } + function set_buffer(value:BitmapData) + { + return if (viewBlit != null) + this.buffer = viewBlit.buffer = value; + else + this.buffer = value; + } + + @:noCompletion + @:deprecated("screen is deprecated, use camera.viewBlit.screen, instead") // 6.2.0 + @:isVar public var screen(get, set):Null; + function get_screen() + { + if (viewBlit != null) + this.screen = viewBlit.screen; + + return this.screen; + } + function set_screen(value:FlxSprite) + { + return if (viewBlit != null) + this.screen = viewBlit.screen = value; + else + this.screen = value; + } + + @:noCompletion + @:deprecated("flashSprite is deprecated, use camera.viewBlit.flashSprite or camera.viewQuad.flashSprite, instead") // 6.2.0 + @:isVar public var flashSprite(get, set):Sprite; + function get_flashSprite() + { + if (viewBlit != null) + this.flashSprite = viewBlit.flashSprite; + else if (viewQuad != null) + this.flashSprite = viewQuad.flashSprite; + + return this.flashSprite; + } + function set_flashSprite(value:Sprite) + { + return if (viewBlit != null) + this.flashSprite = viewBlit.flashSprite = value; + else if (viewQuad != null) + this.flashSprite = viewQuad.flashSprite = value; + else + this.flashSprite = value; + } + + @:noCompletion + @:deprecated("_blitMatrix is deprecated, use camera.viewBlit.blitMatrix, instead") // 6.2.0 + @:isVar var _blitMatrix(get, set):FlxMatrix; + function get__blitMatrix() + { + if (viewBlit != null) + this._blitMatrix = viewBlit._blitMatrix; + + return this._blitMatrix; + } + function set__blitMatrix(value:FlxMatrix) + { + return if (viewBlit != null) + this._blitMatrix = viewBlit._blitMatrix = value; + else + this._blitMatrix = value; + } + + @:noCompletion + @:deprecated("_useBlitMatrix is deprecated, use camera.viewBlit._useBlitMatrix, instead") // 6.2.0 + @:isVar var _useBlitMatrix(get, set):Bool; + function get__useBlitMatrix() + { + if (viewBlit != null) + this._useBlitMatrix = viewBlit._useBlitMatrix; + + return this._useBlitMatrix; + } + function set__useBlitMatrix(value:Bool) + { + return if (viewBlit != null) + this._useBlitMatrix = viewBlit._useBlitMatrix = value; + else + this._useBlitMatrix = value; + } + + @:noCompletion + @:deprecated("_flashRect is deprecated, use camera.viewBlit._flashRect, instead") // 6.2.0 + @:isVar var _flashRect(get, set):Rectangle; + function get__flashRect() + { + if (viewBlit != null) + this._flashRect = viewBlit._flashRect; + + return this._flashRect; + } + function set__flashRect(value:Rectangle) + { + return if (viewBlit != null) + this._flashRect = viewBlit._flashRect = value; + else + this._flashRect = value; + } + + @:noCompletion + @:deprecated("_flashPoint is deprecated, use viewBlit._flashPoint, instead") // 6.2.0 + @:isVar var _flashPoint(get, set):Point; + function get__flashPoint() + { + if (viewBlit != null) + this._flashPoint = viewBlit._flashPoint; + + return this._flashPoint; + } + function set__flashPoint(value:Point) + { + return if (viewBlit != null) + this._flashPoint = viewBlit._flashPoint = value; + else + this._flashPoint = value; + } + + @:noCompletion + @:deprecated("_flashOffset is deprecated, use camera.view._flashOffset, instead") // 6.2.0 + @:isVar var _flashOffset(get, set):Null; + function get__flashOffset() + { + if (viewBlit != null) + this._flashOffset = viewBlit._flashOffset; + else if (viewQuad != null) + this._flashOffset = viewQuad._flashOffset; + + return this._flashOffset; + } + function set__flashOffset(value:FlxPoint) + { + return if (viewBlit != null) + this._flashOffset = viewBlit._flashOffset = value; + else if (viewQuad != null) + this._flashOffset = viewQuad._flashOffset = value; + else + this._flashOffset = value; + } + + @:noCompletion + @:deprecated("_fill is deprecated, use camera.viewBlit._fill, instead") // 6.2.0 + @:isVar var _fill(get, set):BitmapData; + function get__fill():BitmapData + { + if (viewBlit != null) + this._fill = viewBlit._fill; + + return this._fill; + } + function set__fill(value:BitmapData):BitmapData + { + return if (viewBlit != null) + this._fill = viewBlit._fill = value; + else + this._fill = value; + } + + @:noCompletion + @:deprecated("_flashBitmap is deprecated, use camera.viewBlit._flashBitmap, instead") // 6.2.0 + @:isVar var _flashBitmap(get, set):Bitmap; + function get__flashBitmap():Bitmap + { + if (viewBlit != null) + this._flashBitmap = viewBlit._flashBitmap; + + return this._flashBitmap; + } + inline function set__flashBitmap(value:Bitmap):Bitmap + { + return if (viewBlit != null) + this._flashBitmap = viewBlit._flashBitmap = value; + else + this._flashBitmap = value; + } + + @:noCompletion + @:deprecated("_scrollRect is deprecated, use camera.viewQuad._scrollRect or camera.viewBlit._scrollRect, instead") // 6.2.0 + @:isVar var _scrollRect(get, set):Sprite; + function get__scrollRect():Sprite + { + if (viewBlit != null) + this._scrollRect = viewBlit._scrollRect; + else if (viewQuad != null) + this._scrollRect = viewQuad._scrollRect; + + return this._scrollRect; + } + function set__scrollRect(value:Sprite):Sprite + { + return if (viewBlit != null) + this._scrollRect = viewBlit._scrollRect = value; + else if (viewQuad != null) + this._scrollRect = viewQuad._scrollRect = value; + else + this._scrollRect = value; + } + + @:noCompletion + @:deprecated("_bounds is deprecated, there will be no replacement") // 6.2.0 + var _bounds = new FlxRect(); + + @:noCompletion + @:deprecated("canvas is deprecated, use camera.viewQuad.canvas, instead") // 6.2.0 + @:isVar public var canvas(get, set):Null; + function get_canvas() + { + if (viewQuad != null) + this.canvas = viewQuad.canvas; + + return this.canvas; + } + function set_canvas(value:Null) + { + return if (viewQuad != null) + this.canvas = viewQuad.canvas = value; + else + this.canvas = value; + } + + #if FLX_DEBUG + @:noCompletion + @:deprecated("debugLayer is deprecated, use camera.viewQuad.debugLayer, instead") // 6.2.0 + @:isVar public var debugLayer(get, set):Null; + function get_debugLayer() + { + if (viewQuad != null) + this.debugLayer = viewQuad.debugLayer; + + return this.debugLayer; + } + function set_debugLayer(value:Null) + { + return if (viewQuad != null) + this.debugLayer = viewQuad.debugLayer = value; + else + this.debugLayer = value; + } + #end + + @:noCompletion + @:deprecated("_helperMatrix is deprecated, there will be no replacement") // 6.2.0 + var _helperMatrix = new FlxMatrix(); + + @:noCompletion + @:deprecated("_helperPoint is deprecated, there will be no replacement") // 6.2.0 + var _helperPoint = new Point(); + + @:noCompletion + @:deprecated("_currentDrawItem is deprecated, use camera.viewQuad._currentDrawItem, instead") // 6.2.0 + @:isVar var _currentDrawItem(get, set):Null>; + function get__currentDrawItem() + { + if (viewQuad != null) + this._currentDrawItem = viewQuad._currentDrawItem; + + return this._currentDrawItem; + } + function set__currentDrawItem(value:Null>) + { + return if (viewQuad != null) + this._currentDrawItem = viewQuad._currentDrawItem = value; + else + this._currentDrawItem = value; + } + + @:noCompletion + @:deprecated("_headOfDrawStack is deprecated, use camera.viewQuad._headOfDrawStack, instead") // 6.2.0 + @:isVar var _headOfDrawStack(get, set):Null>; + function get__headOfDrawStack() + { + if (viewQuad != null) + this._headOfDrawStack = viewQuad._headOfDrawStack; + + return this._headOfDrawStack; + } + function set__headOfDrawStack(value:Null>) + { + return if (viewQuad != null) + this._headOfDrawStack = viewQuad._headOfDrawStack = value; + else + this._headOfDrawStack = value; + } + + @:noCompletion + @:deprecated("_headTiles is deprecated, use camera.viewQuad._headTiles, instead") // 6.2.0 + @:isVar var _headTiles(get, set):Null; + function get__headTiles() + { + if (viewQuad != null) + this._headTiles = viewQuad._headTiles; + + return this._headTiles; + } + function set__headTiles(value:Null) + { + return if (viewQuad != null) + this._headTiles = viewQuad._headTiles = value; + else + this._headTiles = value; + } + + @:noCompletion + @:deprecated("_headTriangles is deprecated, use camera.viewQuad._headTriangles, instead") // 6.2.0 + @:isVar var _headTriangles(get, set):Null; + function get__headTriangles() + { + if (viewQuad != null) + this._headTriangles = viewQuad._headTriangles; + + return this._headTriangles; + } + function set__headTriangles(value:Null) + { + return if (viewQuad != null) + this._headTriangles = viewQuad._headTriangles = value; + else + this._headTriangles = value; + } + + @:noCompletion + @:deprecated("_storageTilesHead is deprecated, use FlxQuadView._storageTilesHead, instead") // 6.2.0 + static var _storageTilesHead(get, set):Null; + static inline function get__storageTilesHead():Null return FlxQuadView._storageTilesHead; + static inline function set__storageTilesHead(value:Null):FlxDrawQuadsItem return FlxQuadView._storageTilesHead = value; + + @:noCompletion + @:deprecated("_storageTrianglesHead is deprecated, use FlxQuadView._storageTrianglesHead, instead") // 6.2.0 + 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; + + @:noCompletion + @:deprecated("drawVertices is deprecated, there will be no replacement") // 6.2.0 + static var drawVertices = new Vector(); + + @:noCompletion + @:deprecated("trianglesSprite is deprecated, there will be no replacement") // 6.2.0 + static var trianglesSprite = new Sprite(); + + @:noCompletion + @:deprecated("renderPoint is deprecated, there will be no replacement") // 6.2.0 + static var renderPoint = new FlxPoint(); + + @:noCompletion + @:deprecated("renderRect is deprecated, there will be no replacement") // 6.2.0 + static var renderRect = new FlxRect(); + + // @:bypassAccess doesn't work from external classes in haxe 4. So call this when needed + @:noCompletion inline function setColorBypass (value:FlxColor):FlxColor return @:bypassAccessor this.color = value; + @:noCompletion inline function setAlphaBypass (value:Float ):Float return @:bypassAccessor this.alpha = value; + @:noCompletion inline function setAngleBypass (value:Float ):Float return @:bypassAccessor this.angle = value; + @:noCompletion inline function setVisibleBypass (value:Bool ):Bool return @:bypassAccessor this.visible = value; + @:haxe.warning("-WDeprecated") + @:noCompletion inline function setAntialiasingBypass(value:Bool ):Bool return @:bypassAccessor this.antialiasing = value; + + + //{ endregion --- DEPRECATED VIEW FIELDS ------ } enum FlxCameraFollowStyle @@ -2473,4 +2272,4 @@ enum FlxCameraFollowStyle * Camera has no deadzone, just tracks the focus object directly and centers it. */ NO_DEAD_ZONE; -} +} \ No newline at end of file diff --git a/flixel/FlxG.hx b/flixel/FlxG.hx index 99559cddc7..b7a8270a7a 100644 --- a/flixel/FlxG.hx +++ b/flixel/FlxG.hx @@ -18,6 +18,7 @@ import flixel.system.frontEnds.SignalFrontEnd; import flixel.system.frontEnds.SoundFrontEnd; import flixel.system.frontEnds.VCRFrontEnd; import flixel.system.frontEnds.WatchFrontEnd; +import flixel.system.render.FlxRenderer; import flixel.system.scaleModes.BaseScaleMode; import flixel.system.scaleModes.RatioScaleMode; import flixel.util.FlxCollision; @@ -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.renderer.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 renderer.method; + } + + @:deprecated("renderBlit is deprecated, compare against FlxG.renderer.blit, instead.") + public static var renderBlit(get, never):Bool; + @:noCompletion static inline function get_renderBlit():Bool + { + return renderer.blit; + } + + @:deprecated("renderTile is deprecated, compare against FlxG.renderer.tile, instead.") + public static var renderTile(get, never):Bool; + @:noCompletion static inline function get_renderTile():Bool + { + return renderer.tile; + } - 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(); + renderer.initGlobals(); } #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..81efba61b9 100644 --- a/flixel/FlxGame.hx +++ b/flixel/FlxGame.hx @@ -1,7 +1,7 @@ package flixel; -import flixel.graphics.tile.FlxDrawBaseItem; import flixel.system.FlxSplash; +import flixel.system.render.FlxRenderer; import flixel.util.FlxArrayUtil; import flixel.util.FlxDestroyUtil; import flixel.util.typeLimit.NextState; @@ -803,10 +803,9 @@ class FlxGame extends Sprite FlxG.signals.preDraw.dispatch(); - if (FlxG.renderTile) - FlxDrawBaseItem.drawCalls = 0; + FlxG.renderer.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.tile) + { #if FLX_DEBUG - debugger.stats.drawCalls(FlxDrawBaseItem.drawCalls); + debugger.stats.drawCalls(FlxG.renderer.totalDrawCalls); #end } - FlxG.cameras.unlock(); - FlxG.signals.postDraw.dispatch(); #if FLX_DEBUG diff --git a/flixel/FlxObject.hx b/flixel/FlxObject.hx index 4549076555..03530287e3 100644 --- a/flixel/FlxObject.hx +++ b/flixel/FlxObject.hx @@ -5,6 +5,8 @@ import flixel.math.FlxPoint; import flixel.math.FlxRect; import flixel.math.FlxVelocity; import flixel.path.FlxPath; +import flixel.system.render.FlxCameraView; +import flixel.system.render.FlxVertexBuffer; import flixel.tile.FlxBaseTilemap; import flixel.util.FlxAxes; import flixel.util.FlxColor; @@ -1306,9 +1308,11 @@ class FlxObject extends FlxBasic { if (!camera.visible || !camera.exists || !isOnScreen(camera)) return; - + final rect = getBoundingBox(camera); - if (FlxG.renderTile) + + // TODO: Remove and handle this in the view via drawDebugRect + if (FlxG.renderer.tile) { final view = camera.getViewMarginRect(); view.pad(2); @@ -1318,12 +1322,14 @@ class FlxObject extends FlxBasic if (rect.width > 0 && rect.height > 0) { - final gfx = beginDrawDebug(camera); - drawDebugBoundingBox(gfx, rect, allowCollisions, immovable); - endDrawDebug(camera); + camera.view.beginDrawDebug(); + drawDebugBoundingBoxTo(camera.view.getDebugBuffer(), rect); + camera.view.endDrawDebug(); } } + // TODO: throw warning on overrides + @:deprecated("drawDebugBoundingBox is deprecated, use drawDebugBoundingBoxTo instead") // 6.2.0 function drawDebugBoundingBox(gfx:Graphics, rect:FlxRect, allowCollisions:FlxDirectionFlags, partial:Bool) { // Find the color to use @@ -1331,6 +1337,12 @@ class FlxObject extends FlxBasic drawDebugBoundingBoxColor(gfx, rect, color); } + @:haxe.warning("-WDeprecated") + function drawDebugBoundingBoxTo(buffer:FlxVertexBuffer, rect:FlxRect) + { + drawDebugBoundingBox(buffer, rect, allowCollisions, immovable); + } + function getDebugBoundingBoxColor(allowCollisions:FlxDirectionFlags) { if (debugBoundingBoxColor != null) @@ -1346,30 +1358,31 @@ class FlxObject extends FlxBasic } + // TODO: throw warning on overrides + @:deprecated("beginDrawDebug(gfx) is deprecated, drawDebugBoundingBoxTo instead") 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); + final buffer:FlxVertexBuffer = gfx; + buffer.drawRect(rect.x + 0.5, rect.y + 0.5, rect.width - 1.0, rect.height - 1.0, color, 1); } - + + @:haxe.warning("-WDeprecated") + function drawDebugBoundingBoxColorTo(view:FlxCameraView, bounds:FlxRect, color:FlxColor) + { + drawDebugBoundingBoxColor(view.getDebugBuffer(), bounds, color); + } + + @:deprecated("beginDrawDebug(camera) is deprecated, use camera.view.beginDrawDebug() instead") inline function beginDrawDebug(camera:FlxCamera):Graphics { - if (FlxG.renderBlit) - { - FlxSpriteUtil.flashGfx.clear(); - return FlxSpriteUtil.flashGfx; - } - else - { - return camera.debugLayer.graphics; - } + camera.view.beginDrawDebug(); + return camera.view.getDebugBuffer(); } + @:deprecated("endDrawDebug(camera) is deprecated, use camera.view.endDrawDebug() instead") inline function endDrawDebug(camera:FlxCamera) { - if (FlxG.renderBlit) - camera.buffer.draw(FlxSpriteUtil.flashGfxSprite); + camera.view.endDrawDebug(); } #end diff --git a/flixel/FlxSprite.hx b/flixel/FlxSprite.hx index e97b906ea4..26a4c5d8b7 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.blit; if (SimpleGraphic != null) loadGraphic(SimpleGraphic); } @@ -908,7 +908,7 @@ class FlxSprite extends FlxObject centerOrigin(); - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { dirty = true; updateFramePixels(); @@ -1009,7 +1009,10 @@ class FlxSprite extends FlxObject _point.floor(); _point.copyTo(_flashPoint); - camera.copyPixels(_frame, framePixels, _flashRect, _flashPoint, colorTransform, blend, antialiasing); + if (framePixels != null && useFramePixels) + camera.view.copyPixels(framePixels, _flashRect, _flashPoint, colorTransform, blend, antialiasing); + else + camera.view.copyFrame(_frame, _flashPoint, colorTransform, blend, antialiasing); } @:noCompletion @@ -1025,7 +1028,10 @@ class FlxSprite extends FlxObject final matrix = drawComplexMatrix; // TODO: Just use local? prepareComplexMatrix(matrix, frame, camera); - camera.drawPixels(frame, framePixels, matrix, colorTransform, blend, antialiasing, shader); + if (framePixels != null && useFramePixels) + camera.view.drawPixels(framePixels, matrix, colorTransform, blend, antialiasing, shader); + else + camera.view.drawFrame(frame, matrix, colorTransform, blend, antialiasing, shader); } function prepareComplexMatrix(matrix:FlxMatrix, frame:FlxFrame, camera:FlxCamera) @@ -1095,7 +1101,7 @@ class FlxSprite extends FlxObject graphic.bitmap.draw(bitmapData, _matrix, null, brushBlend, null, Brush.antialiasing); } - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { dirty = true; calcFrame(); @@ -1110,7 +1116,7 @@ class FlxSprite extends FlxObject */ public function drawFrame(Force:Bool = false):Void { - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { if (Force || dirty) { @@ -1169,7 +1175,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,10 +1570,8 @@ class FlxSprite extends FlxObject { checkEmptyFrame(); - if (FlxG.renderTile && !force) - return; - - updateFramePixels(); + if (FlxG.renderer.blit || force) + updateFramePixels(); } /** @@ -1580,7 +1584,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.tile && _frameGraphic != null) { dirty = false; return framePixels; @@ -1598,12 +1602,12 @@ class FlxSprite extends FlxObject framePixels = _frame.paintRotatedAndFlipped(framePixels, _flashPointZero, FlxFrameAngle.ANGLE_0, doFlipX, doFlipY, false, true); } - if (FlxG.renderBlit && hasColorTransform()) + if (FlxG.renderer.blit && hasColorTransform()) { framePixels.colorTransform(_flashRect, colorTransform); } - if (FlxG.renderTile && useFramePixels) + if (FlxG.renderer.tile && useFramePixels) { // recreate _frame for native target, so it will use modified framePixels _frameGraphic = FlxDestroyUtil.destroy(_frameGraphic); @@ -1672,15 +1676,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) - return false; - - return isSimpleRenderBlit(camera); + return FlxG.renderer.blit && isSimpleRenderBlit(camera); } /** @@ -1846,7 +1847,7 @@ class FlxSprite extends FlxObject return null; } - if (FlxG.renderTile) + if (FlxG.renderer.tile) { _frameGraphic = FlxDestroyUtil.destroy(_frameGraphic); } @@ -2004,7 +2005,7 @@ class FlxSprite extends FlxObject @:noCompletion function set_flipX(Value:Bool):Bool { - if (FlxG.renderTile) + if (FlxG.renderer.tile) { _facingHorizontalMult = Value ? -1 : 1; } @@ -2015,7 +2016,7 @@ class FlxSprite extends FlxObject @:noCompletion function set_flipY(Value:Bool):Bool { - if (FlxG.renderTile) + if (FlxG.renderer.tile) { _facingVerticalMult = Value ? -1 : 1; } @@ -2032,25 +2033,26 @@ class FlxSprite extends FlxObject @:noCompletion function set_useFramePixels(value:Bool):Bool { - if (FlxG.renderTile) + switch FlxG.renderer.method { - if (value != useFramePixels) - { - useFramePixels = value; - resetFrame(); - - if (value) + case DRAW_TILES: + if (value != useFramePixels) { - updateFramePixels(); + useFramePixels = value; + resetFrame(); + + if (value) + { + updateFramePixels(); + } } - } - return value; - } - else - { - useFramePixels = true; - return true; + return value; + case BLITTING: + useFramePixels = true; + return true; + case CUSTOM: + return useFramePixels = value; } } diff --git a/flixel/FlxStrip.hx b/flixel/FlxStrip.hx index 6696952a97..9f34e21b50 100644 --- a/flixel/FlxStrip.hx +++ b/flixel/FlxStrip.hx @@ -58,7 +58,7 @@ class FlxStrip extends FlxSprite getScreenPosition(_point, camera); _point -= offset; - camera.drawTriangles(graphic, vertices, indices, uvtData, colors, _point, blend, repeat, antialiasing, colorTransform, shader); + camera.view.drawTriangles(graphic, vertices, indices, uvtData, colors, _point, blend, repeat, antialiasing, colorTransform, shader); } } } diff --git a/flixel/FlxSubState.hx b/flixel/FlxSubState.hx index e7cca132f6..fa0d465de9 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.tile) { _bgSprite = new FlxBGSprite(); } @@ -63,20 +63,18 @@ class FlxSubState extends FlxState override public function draw():Void { // Draw background - if (FlxG.renderBlit) + switch FlxG.renderer.method { - for (camera in getCamerasLegacy()) - { - camera.fill(bgColor); - } - } - else // FlxG.renderTile - { - if (_bgSprite != null && _bgSprite.visible) - { - _bgSprite.cameras = getCameras(); - _bgSprite.draw(); - } + case BLITTING: + for (camera in getCamerasLegacy()) + camera.view.fill(bgColor); + case DRAW_TILES: + if (_bgSprite != null && _bgSprite.visible) + { + _bgSprite.cameras = getCameras(); + _bgSprite.draw(); + } + case CUSTOM: } // Now draw all children @@ -110,7 +108,7 @@ class FlxSubState extends FlxState @:noCompletion override function set_bgColor(value:FlxColor):FlxColor { - if (FlxG.renderTile && _bgSprite != null) + if (FlxG.renderer.tile && _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..4b6c05891a 100644 --- a/flixel/effects/particles/FlxEmitter.hx +++ b/flixel/effects/particles/FlxEmitter.hx @@ -1,6 +1,5 @@ package flixel.effects.particles; -import openfl.display.BlendMode; import flixel.FlxG; import flixel.FlxObject; import flixel.FlxSprite; @@ -15,6 +14,7 @@ import flixel.util.FlxDirectionFlags; import flixel.util.helpers.FlxBounds; import flixel.util.helpers.FlxPointRangeBounds; import flixel.util.helpers.FlxRangeBounds; +import openfl.display.BlendMode; typedef FlxEmitter = FlxTypedEmitter; @@ -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.blit && 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..08b19279a4 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.tile) tileMatrix = new MatrixVector(); } @@ -169,7 +169,7 @@ class FlxFrame implements IFlxDestroyable { blitMatrix.copyFrom(this, true); - if (FlxG.renderTile) + if (FlxG.renderer.tile) 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.blit) { mat.identity(); return mat; diff --git a/flixel/graphics/tile/FlxDrawBaseItem.hx b/flixel/graphics/tile/FlxDrawBaseItem.hx index fc91f4d8a1..3f216571c4 100644 --- a/flixel/graphics/tile/FlxDrawBaseItem.hx +++ b/flixel/graphics/tile/FlxDrawBaseItem.hx @@ -3,6 +3,7 @@ package flixel.graphics.tile; import flixel.FlxCamera; import flixel.graphics.frames.FlxFrame; import flixel.math.FlxMatrix; +import flixel.system.render.FlxRenderer; 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 FlxG.renderer.totalDrawCalls instead") + public static var drawCalls(get, set):Int; + + static function set_drawCalls(value:Int):Int + { + return FlxG.renderer.totalDrawCalls = value; + } + + static function get_drawCalls():Int + { + return FlxG.renderer.totalDrawCalls; + } @:noCompletion @:deprecated("blendToInt() is deprecated, remove all references to it") @@ -63,7 +75,7 @@ class FlxDrawBaseItem public function render(camera:FlxCamera):Void { - drawCalls++; + FlxG.renderer.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..b4b4b3573f 100644 --- a/flixel/graphics/tile/FlxDrawQuadsItem.hx +++ b/flixel/graphics/tile/FlxDrawQuadsItem.hx @@ -121,7 +121,7 @@ class FlxDrawQuadsItem extends FlxDrawBaseItem final shader = shader != null ? shader : graphics.shader; shader.bitmap.input = graphics.bitmap; - shader.bitmap.filter = (camera.antialiasing || antialiasing) ? LINEAR : NEAREST; + shader.bitmap.filter = (camera.view.antialiasing || antialiasing) ? LINEAR : NEAREST; shader.alpha.value = alphas; if (colored || hasColorOffsets) @@ -132,11 +132,13 @@ 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(); + + @:privateAccess + final view = camera.viewQuad; + view.canvas.graphics.overrideBlendMode(blend); + view.canvas.graphics.beginShaderFill(shader); + view.canvas.graphics.drawQuads(rects, null, transforms); + view.canvas.graphics.endFill(); super.render(camera); } diff --git a/flixel/graphics/tile/FlxDrawTrianglesItem.hx b/flixel/graphics/tile/FlxDrawTrianglesItem.hx index 38fbcd7b04..c98efdf407 100644 --- a/flixel/graphics/tile/FlxDrawTrianglesItem.hx +++ b/flixel/graphics/tile/FlxDrawTrianglesItem.hx @@ -54,10 +54,13 @@ class FlxDrawTrianglesItem extends FlxDrawBaseItem if (numTriangles <= 0) return; + @:privateAccess + final view = camera.viewQuad; + #if !flash var shader = shader != null ? shader : graphics.shader; shader.bitmap.input = graphics.bitmap; - shader.bitmap.filter = (camera.antialiasing || antialiasing) ? LINEAR : NEAREST; + shader.bitmap.filter = (camera.view.antialiasing || antialiasing) ? LINEAR : NEAREST; shader.bitmap.wrap = REPEAT; // in order to prevent breaking tiling behaviour in classes that use drawTriangles shader.alpha.value = alphas; @@ -75,20 +78,20 @@ class FlxDrawTrianglesItem extends FlxDrawBaseItem setParameterValue(shader.hasTransform, true); setParameterValue(shader.hasColorTransform, colored || hasColorOffsets); - camera.canvas.graphics.overrideBlendMode(blend); + view.canvas.graphics.overrideBlendMode(blend); - camera.canvas.graphics.beginShaderFill(shader); + view.canvas.graphics.beginShaderFill(shader); #else - camera.canvas.graphics.beginBitmapFill(graphics.bitmap, null, true, (camera.antialiasing || antialiasing)); + view.canvas.graphics.beginBitmapFill(graphics.bitmap, null, true, (camera.antialiasing || antialiasing)); #end - camera.canvas.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NONE); - camera.canvas.graphics.endFill(); + view.canvas.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NONE); + view.canvas.graphics.endFill(); #if FLX_DEBUG if (FlxG.debugger.drawDebug) { - var gfx:Graphics = camera.debugLayer.graphics; + var gfx:Graphics = view.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..d47856b175 100644 --- a/flixel/path/FlxBasePath.hx +++ b/flixel/path/FlxBasePath.hx @@ -4,6 +4,8 @@ import flixel.FlxBasic; import flixel.FlxG; import flixel.FlxObject; import flixel.math.FlxPoint; +import flixel.system.render.FlxCameraView; +import flixel.system.render.FlxVertexBuffer; import flixel.util.FlxAxes; import flixel.util.FlxColor; import flixel.util.FlxDestroyUtil; @@ -316,19 +318,11 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy * * @param camera The camera object the path will draw to. */ + @:haxe.warning("-WDeprecated") 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; - } + camera.view.beginDrawDebug(); final length = nodes.length; // Then fill up the object with node and path graphics @@ -354,25 +348,22 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy } } + final buffer = camera.view.getDebugBuffer(); // draw a box for the node - drawNode(gfx, prevNodeScreen, nodeSize, nodeColor); + drawNode(buffer, 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(buffer, prevNodeScreen, nextNodeScreen); nextNodeScreen.put(); } prevNodeScreen.put(); } - if (FlxG.renderBlit) - { - // then stamp the path down onto the game buffer - camera.buffer.draw(FlxSpriteUtil.flashGfxSprite); - } + camera.view.endDrawDebug(); } @:access(flixel.FlxCamera) @@ -386,7 +377,7 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy result.y -= camera.scroll.y * object.scrollFactor.y; } - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { result.x -= camera.viewMarginX; result.y -= camera.viewMarginY; @@ -396,25 +387,22 @@ class FlxTypedBasePath extends FlxBasic implements IFlxDestroy return result; } - inline function drawNode(gfx:Graphics, node:FlxPoint, size:Int, color:FlxColor) + inline function drawNode(buffer:FlxVertexBuffer, 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(); + buffer.drawFilledRect(node.x - offset, node.y - offset, size, size, color); } - function drawLine(gfx:Graphics, node1:FlxPoint, node2:FlxPoint) + @:deprecated("drawLine is deprecated, use drawCable, instead") + function drawLine(gfx:Graphics, node1:FlxPoint, node2:FlxPoint) // TODO: warn on override + { + drawLink(gfx, node1, node2); + } + + function drawLink(buffer:FlxVertexBuffer, node1:FlxPoint, node2:FlxPoint) { - // then draw a line to the next node - final color = debugDrawData.lineColor; - final size = debugDrawData.lineSize; - gfx.lineStyle(size, color.rgb, color.alphaFloat); - final lineOffset = debugDrawData.lineSize / 2; - gfx.moveTo(node1.x + lineOffset, node1.y + lineOffset); - gfx.lineTo(node2.x + lineOffset, node2.y + lineOffset); + buffer.drawLine(node1.x + lineOffset, node1.y + lineOffset, node2.x + lineOffset, node2.y + lineOffset, debugDrawData.lineColor); } #end } diff --git a/flixel/system/FlxBGSprite.hx b/flixel/system/FlxBGSprite.hx index b5608493ab..4cbc91101a 100644 --- a/flixel/system/FlxBGSprite.hx +++ b/flixel/system/FlxBGSprite.hx @@ -31,7 +31,8 @@ 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); + + camera.view.drawFrame(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..a8cebafa13 100644 --- a/flixel/system/debug/interaction/Interaction.hx +++ b/flixel/system/debug/interaction/Interaction.hx @@ -14,6 +14,7 @@ import flixel.system.debug.interaction.tools.ToggleBounds; import flixel.system.debug.interaction.tools.Tool; import flixel.system.debug.interaction.tools.TrackObject; import flixel.system.debug.interaction.tools.Transform; +import flixel.util.FlxColor; import flixel.util.FlxDestroyUtil; import flixel.util.FlxSpriteUtil; import openfl.display.BitmapData; @@ -377,16 +378,17 @@ 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.blit) { FlxSpriteUtil.flashGfx.clear(); return FlxSpriteUtil.flashGfx; } #if FLX_DEBUG - return FlxG.camera.debugLayer.graphics; + return FlxG.camera.view.getDebugBuffer(); #end return null; @@ -394,25 +396,27 @@ class Interaction extends Window function drawItemsSelection():Void { - var gfx:Graphics = getDebugGraphics(); - if (gfx == null) - return; + #if FLX_DEBUG + final view = FlxG.camera.view; + view.beginDrawDebug(); + final buffer = view.getDebugBuffer(); for (member in selectedItems) { if (member != null && member.scrollFactor != null && member.isOnScreen()) { - final margin = 0.5; final scroll = FlxG.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); + final MARGIN = 0.5; + final MARGIN_2 = MARGIN * 2; + buffer.drawRect(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); + view.endDrawDebug(); + #end } /** @@ -790,19 +794,21 @@ class Interaction extends Window public function toDebugX(worldX:Float, camera:FlxCamera) { - if (FlxG.renderTile) - return camera.canvas.localToGlobal(new Point(worldX, 0)).x; - else - @:privateAccess - return camera._flashBitmap.localToGlobal(new Point(worldX, 0)).x; + #if FLX_DEBUG + @:privateAccess + return camera.view.worldToDebugX(worldX); + #else + return worldX; + #end } public function toDebugY(worldY:Float, camera:FlxCamera) { - if (FlxG.renderTile) - return camera.canvas.localToGlobal(new Point(0, worldY)).y; - else - @:privateAccess - return camera._flashBitmap.localToGlobal(new Point(0, worldY)).y; + #if FLX_DEBUG + @:privateAccess + return camera.view.worldToDebugY(worldY); + #else + return worldY; + #end } } diff --git a/flixel/system/debug/interaction/tools/Pointer.hx b/flixel/system/debug/interaction/tools/Pointer.hx index ecc4d354a4..d6987cc16c 100644 --- a/flixel/system/debug/interaction/tools/Pointer.hx +++ b/flixel/system/debug/interaction/tools/Pointer.hx @@ -1,14 +1,15 @@ package flixel.system.debug.interaction.tools; -import openfl.display.BitmapData; -import openfl.display.Graphics; -import openfl.ui.Keyboard; import flixel.FlxBasic; import flixel.math.FlxPoint; import flixel.math.FlxRect; import flixel.system.debug.Icon; import flixel.system.debug.interaction.Interaction; +import flixel.util.FlxColor; import flixel.util.FlxSpriteUtil; +import openfl.display.BitmapData; +import openfl.display.Graphics; +import openfl.ui.Keyboard; using flixel.util.FlxArrayUtil; @@ -131,11 +132,12 @@ class Pointer extends Tool state = IDLE; } + #if FLX_DEBUG override public function draw():Void { - var gfx:Graphics = _brain.getDebugGraphics(); - if (gfx == null) - return; + final view = FlxG.camera.view; + view.beginDrawDebug(); + final buffer = view.getDebugBuffer(); switch state { @@ -144,15 +146,14 @@ 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); + final scroll = view.camera.scroll; + buffer.drawRect(rect.x - scroll.x, rect.y - scroll.y, rect.width, rect.height, 0xFFbb0000, 0.9); rect.put(); } - // Render everything into the camera buffer - if (FlxG.renderBlit) - FlxG.camera.buffer.draw(FlxSpriteUtil.flashGfxSprite); + view.endDrawDebug(); } + #end static function setAbsRect(rect:FlxRect, x1:Float, y1:Float, x2:Float, y2:Float) { @@ -174,4 +175,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..2e2e1be2df 100644 --- a/flixel/system/debug/interaction/tools/Transform.hx +++ b/flixel/system/debug/interaction/tools/Transform.hx @@ -7,6 +7,7 @@ import flixel.math.FlxRect; import flixel.system.debug.Icon; import flixel.system.debug.Tooltip; import flixel.system.debug.interaction.Interaction; +import flixel.system.render.FlxVertexBuffer; import flixel.util.FlxColor; import flixel.util.FlxSpriteUtil; import openfl.display.BitmapData; @@ -218,6 +219,7 @@ class Transform extends Tool } } + #if FLX_DEBUG override function draw():Void { if (!isActive()) @@ -232,36 +234,36 @@ 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(); + + final view = camera.view; + view.beginDrawDebug(); + final buffer = view.getDebugBuffer(); + drawSelection(buffer, camera); + Marker.draw(buffer, target.x + target.origin.x, target.y + target.origin.y, false); + view.endDrawDebug(); } - - function drawSelection(gfx:Graphics, camera:FlxCamera) + + function drawSelection(buffer:FlxVertexBuffer, 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); - for (marker in markers) - gfx.lineTo(marker.x, marker.y); + final scroll = camera.scroll; + for (i => marker in markers) + { + final prev = markers[(i + 3) % 4]; + buffer.drawLine(prev.x - scroll.x, prev.y - scroll.y, marker.x - scroll.x, marker.y - scroll.y, FlxColor.MAGENTA); + } // draw markers for (marker in markers) { final x = marker.x; final y = marker.y; - Marker.draw(x, y, marker.type == ROTATE, gfx); + Marker.draw(buffer, x - scroll.x, y - scroll.y, marker.type == ROTATE); } } + #end } private class Marker @@ -297,15 +299,13 @@ 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(buffer:FlxVertexBuffer, screenX:Float, screenY:Float, circle:Bool) { - gfx.beginFill(FlxColor.MAGENTA); if (circle) - gfx.drawCircle(screenX, screenY, CIRCLE_RADIUS); + buffer.drawFilledCircle(screenX, screenY, CIRCLE_RADIUS, FlxColor.MAGENTA); else - gfx.drawRect(screenX - RECT_MARGIN, screenY - RECT_MARGIN, RECT_SIZE, RECT_SIZE); - gfx.endFill(); + buffer.drawFilledRect(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/log/BitmapLog.hx b/flixel/system/debug/log/BitmapLog.hx index 6ebbb496eb..bd6b48dc6a 100644 --- a/flixel/system/debug/log/BitmapLog.hx +++ b/flixel/system/debug/log/BitmapLog.hx @@ -248,6 +248,7 @@ class BitmapLog extends Window public function clear():Void { entries.resize(0); + index = -1; drawCanvas(); } diff --git a/flixel/system/debug/stats/Stats.hx b/flixel/system/debug/stats/Stats.hx index c76b12963b..5f88c71d2a 100644 --- a/flixel/system/debug/stats/Stats.hx +++ b/flixel/system/debug/stats/Stats.hx @@ -1,8 +1,5 @@ package flixel.system.debug.stats; -import openfl.display.BitmapData; -import openfl.system.System; -import openfl.text.TextField; import flixel.FlxG; import flixel.math.FlxMath; import flixel.system.FlxLinkedList; @@ -10,6 +7,9 @@ import flixel.system.FlxQuadTree; import flixel.system.debug.DebuggerUtil; import flixel.system.ui.FlxSystemButton; import flixel.util.FlxColor; +import openfl.display.BitmapData; +import openfl.system.System; +import openfl.text.TextField; /** @@ -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.tile) 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.tile) { 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.tile) { 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.tile) { _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.tile ? (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/debug/watch/Tracker.hx b/flixel/system/debug/watch/Tracker.hx index 29c86db1e5..26530e991b 100644 --- a/flixel/system/debug/watch/Tracker.hx +++ b/flixel/system/debug/watch/Tracker.hx @@ -1,22 +1,19 @@ package flixel.system.debug.watch; #if FLX_DEBUG -import openfl.display.DisplayObject; -import openfl.geom.Matrix; -import openfl.geom.Point; -import openfl.geom.Rectangle; import flixel.FlxBasic; import flixel.FlxCamera; import flixel.FlxG; import flixel.FlxObject; import flixel.FlxSprite; import flixel.FlxState; +import flixel.animation.FlxAnimationController; import flixel.effects.particles.FlxEmitter.FlxTypedEmitter; -import flixel.group.FlxSpriteGroup; import flixel.group.FlxGroup.FlxTypedGroup; +import flixel.group.FlxSpriteGroup; +import flixel.input.FlxSwipe; import flixel.input.gamepad.FlxGamepad; import flixel.input.mouse.FlxMouse; -import flixel.input.FlxSwipe; import flixel.math.FlxPoint; import flixel.math.FlxRect; import flixel.path.FlxPath; @@ -26,7 +23,10 @@ import flixel.tweens.FlxTween; import flixel.ui.FlxBar; import flixel.ui.FlxButton.FlxTypedButton; import flixel.util.FlxTimer; -import flixel.animation.FlxAnimationController; +import openfl.display.DisplayObject; +import openfl.geom.Matrix; +import openfl.geom.Point; +import openfl.geom.Rectangle; #if FLX_TOUCH import flixel.input.touch.FlxTouch; #end @@ -265,26 +265,4 @@ class Tracker extends Watch add(variable, FIELD(_object, variable)); } #end -} - -class TrackerProfile -{ - public var objectClass:Class; - public var variables:Array; - public var extensions:Array>; - - public function new(ObjectClass:Class, ?Variables:Array, ?Extensions:Array>) - { - objectClass = ObjectClass; - variables = Variables; - extensions = Extensions; - } - - public function toString():String - { - return FlxStringUtil.getDebugString([ - LabelValuePair.weak("variables", variables), - LabelValuePair.weak("extensions", extensions) - ]); - } -} +} \ No newline at end of file diff --git a/flixel/system/debug/watch/TrackerProfile.hx b/flixel/system/debug/watch/TrackerProfile.hx new file mode 100644 index 0000000000..e7498f3b29 --- /dev/null +++ b/flixel/system/debug/watch/TrackerProfile.hx @@ -0,0 +1,25 @@ +package flixel.system.debug.watch; + +import flixel.util.FlxStringUtil; + +class TrackerProfile +{ + public var objectClass:Class; + public var variables:Array; + public var extensions:Array>; + + public function new(ObjectClass:Class, ?Variables:Array, ?Extensions:Array>) + { + objectClass = ObjectClass; + variables = Variables; + extensions = Extensions; + } + + public function toString():String + { + return FlxStringUtil.getDebugString([ + LabelValuePair.weak("variables", variables), + LabelValuePair.weak("extensions", extensions) + ]); + } +} 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..e46b5eb49c 100644 --- a/flixel/system/frontEnds/CameraFrontEnd.hx +++ b/flixel/system/frontEnds/CameraFrontEnd.hx @@ -1,11 +1,12 @@ package flixel.system.frontEnds; -import openfl.geom.Rectangle; import flixel.FlxCamera; import flixel.FlxG; +import flixel.system.render.blit.FlxBlitRenderer; import flixel.util.FlxAxes; import flixel.util.FlxColor; import flixel.util.FlxSignal.FlxTypedSignal; +import openfl.geom.Rectangle; using flixel.util.FlxArrayUtil; @@ -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.tile) { for (i in 0...list.length) { @@ -253,87 +257,46 @@ 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) - { - 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); - } + if ((camera != null) && camera.exists && camera.visible) + camera.view.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) - { - camera.render(); - } - } + if ((camera != null) && camera.exists && camera.visible) + camera.view.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 +340,20 @@ class CameraFrontEnd return Color; } + + function get_useBufferLocking():Bool + { + if (FlxG.renderer.blit) + return cast(FlxG.renderer, FlxBlitRenderer).useBufferLocking; + + return false; + } + + function set_useBufferLocking(value:Bool):Bool + { + if (FlxG.renderer.blit) + return cast(FlxG.renderer, FlxBlitRenderer).useBufferLocking = value; + + return value; + } } diff --git a/flixel/system/frontEnds/DebuggerFrontEnd.hx b/flixel/system/frontEnds/DebuggerFrontEnd.hx index 2046760228..d6197fd5a6 100644 --- a/flixel/system/frontEnds/DebuggerFrontEnd.hx +++ b/flixel/system/frontEnds/DebuggerFrontEnd.hx @@ -4,9 +4,7 @@ import flixel.FlxG; import flixel.input.keyboard.FlxKey; import flixel.system.debug.FlxDebugger; import flixel.system.debug.Window; -import flixel.system.debug.interaction.Interaction; -import flixel.system.debug.interaction.tools.Tool; -import flixel.system.debug.watch.Tracker; +import flixel.system.debug.watch.TrackerProfile; import flixel.system.ui.FlxSystemButton; import flixel.util.FlxHorizontalAlign; import flixel.util.FlxSignal; @@ -15,6 +13,12 @@ import openfl.display.BitmapData; using flixel.util.FlxArrayUtil; using flixel.util.FlxStringUtil; +#if FLX_DEBUG +import flixel.system.debug.interaction.Interaction; +import flixel.system.debug.interaction.tools.Tool; +import flixel.system.debug.watch.Tracker; +#end + /** * Accessed via `FlxG.debugger`. */ diff --git a/flixel/system/render/FlxCameraView.hx b/flixel/system/render/FlxCameraView.hx new file mode 100644 index 0000000000..4ae557934a --- /dev/null +++ b/flixel/system/render/FlxCameraView.hx @@ -0,0 +1,333 @@ +package flixel.system.render; + +import flixel.FlxCamera; +import flixel.FlxG; +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxFrame; +import flixel.graphics.tile.FlxDrawTrianglesItem; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.math.FlxRect; +import flixel.system.FlxAssets; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; +import openfl.display.BitmapData; +import openfl.display.BlendMode; +import openfl.display.DisplayObject; +import openfl.display.DisplayObjectContainer; +import openfl.display.Graphics; +import openfl.geom.ColorTransform; +import openfl.geom.Point; +import openfl.geom.Rectangle; + +/** + * A `FlxCameraView` is a helper added to cameras, that holds some rendering-related objects + * @since 6.2.0 + */ +@:allow(flixel.FlxCamera) +@:access(flixel.FlxCamera) +abstract class FlxCameraView implements IFlxDestroyable +{ + /** + * 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; + + /** + * Whether the camera display is smooth and filtered, or chunky and pixelated. + * Default behavior is chunky-style. + */ + public var antialiasing(default, set):Bool; + + /** + * A shortcut for `camera.angle`. Used so implementations can listen to changes. + */ + public var angle(default, set):Float; + + /** + * A shortcut for `camera.alpha`. Used so implementations can listen to changes. + */ + public var alpha(default, set):Float; + + /** + * A shortcut for `camera.color`. Used so implementations can listen to changes. + */ + public var color(default, set):FlxColor; + + /** + * A shortcut for `camera.visible`. Used so implementations can listen to changes. + */ + public var visible(default, set):Bool; + + function new(camera:FlxCamera) + { + this.camera = camera; + } + + public function destroy():Void {} + + // ============================================================================= + //{ region RENDERING + // ============================================================================= + + /** + * Flushes any remaining graphics and renders everything to the screen. + */ + public function render() + { + throw "Not implemented"; + // Note: Abstract methods with default values are broken on cpp in haxe 4.3. https://github.com/HaxeFoundation/haxe/issues/11666 + } + + /** + * Called before a new rendering frame, clears all previously drawn graphics. + */ + public function clear() + { + throw "Not implemented"; + // Note: Abstract methods with default values are broken on cpp in haxe 4.3. https://github.com/HaxeFoundation/haxe/issues/11666 + } + + /** + * 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) + { + throw "Not implemented"; + // Note: Abstract methods with default values are broken on cpp in haxe 4.3. https://github.com/HaxeFoundation/haxe/issues/11666 + } + + /** + * Draws the pixels onto the current render target. + * + * @param pixels The pixels to draw. + * @param transform The color transform to use. + * @param blend The blend mode to use. + * @param smoothing Whether to use smoothing (anti-aliasing) when drawing. + * @param shader The shader to use. + */ + public function drawPixels(pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, smoothing = false, ?shader:FlxShader) + { + throw "Not implemented"; + // Note: Abstract methods with default values are broken on cpp in haxe 4.3. https://github.com/HaxeFoundation/haxe/issues/11666 + } + + /** + * Draws the pixels 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 pixels The pixels to draw. + * @param sourceRect A rectangle that defines the area of the pixels to use. + * @param destPoint A point representing the top-left position to draw to. + * @param transform The color transform to use. + * @param blend The blend mode to use. + * @param smoothing Whether to use smoothing (anti-aliasing) when drawing. + * @param shader The shader to use. + */ + public function copyPixels(pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, + smoothing:Bool = false, ?shader:FlxShader) + { + throw "Not implemented"; + // Note: Abstract methods with default values are broken on cpp in haxe 4.3. https://github.com/HaxeFoundation/haxe/issues/11666 + } + + /** + * Draws the frame onto the current render target. + * + * @param frame The frame to draw. + * @param matrix The transformation matrix to use. + * @param transform The color transform to use. + * @param blend The blend mode to use. + * @param smoothing Whether to use smoothing (anti-aliasing) when drawing. + * @param shader The shader to use. + */ + public function drawFrame(frame:FlxFrame, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, smoothing:Bool = false, ?shader:FlxShader) + { + throw "Not implemented"; + // Note: Abstract methods with default values are broken on cpp in haxe 4.3. https://github.com/HaxeFoundation/haxe/issues/11666 + } + + /** + * Draws the frame onto the current render target. + * + * Unlike `drawFrame()`, 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 + * @param destPoint A point representing the top-left position to draw to. + * @param transform The color transform to use. + * @param blend The blend mode to use. + * @param smoothing Whether to use smoothing (anti-aliasing) when drawing. + * @param shader The shader to use + */ + public function copyFrame(frame:FlxFrame, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, smoothing = false, ?shader:FlxShader) + { + throw "Not implemented"; + // Note: Abstract methods with default values are broken on cpp in haxe 4.3. https://github.com/HaxeFoundation/haxe/issues/11666 + } + + /** + * 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) + { + throw "Not implemented"; + // Note: Abstract methods with default values are broken on cpp in haxe 4.3. https://github.com/HaxeFoundation/haxe/issues/11666 + } + + // ============================================================================= + //} endregion RENDERING + // ============================================================================= + + abstract public function offsetView(x:Float, y:Float):Void; + + abstract function updateScale():Void; + + abstract function updatePosition():Void; + + abstract function updateInternals():Void; + + abstract function updateOffset():Void; + + abstract function updateScrollRect():Void; + + // ============================================================================= + //{ region 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. + */ + abstract public function beginDrawDebug():Void; + + /** + * Cleans up and finalizes the debug draw. + */ + abstract public function endDrawDebug():Void; + + #if FLX_DEBUG + + abstract public function getDebugBuffer():FlxVertexBuffer; + + abstract function worldToDebugX(worldX:Float):Float;//TODO: find out what "debug space" actually is, rename and make public + abstract function worldToDebugY(worldY:Float):Float;//TODO: find out what "debug space" actually is, rename and make public + + #end + + // ============================================================================= + //} endregion DEBUG DRAW + // ============================================================================= + + // ============================================================================= + //{ region HELPERS + // ============================================================================= + + /** + * 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; + } + + // ============================================================================= + //} endregion HELPERS + // ============================================================================= + + // ============================================================================= + //{ region GETTERS + // ============================================================================= + + abstract function get_display():DisplayObjectContainer; + + @:haxe.warning("-WDeprecated") + function set_antialiasing(value:Bool):Bool + { + camera.setAntialiasingBypass(value); + return this.antialiasing = value; + } + + function set_color(value:FlxColor):FlxColor + { + camera.setColorBypass(value); + return this.color = value; + } + + function set_angle(value:Float):Float + { + camera.setAngleBypass(value); + return this.angle = value; + } + + function set_visible(value:Bool):Bool + { + camera.setVisibleBypass(value); + return this.visible = value; + } + + function set_alpha(value:Float):Float + { + camera.setAlphaBypass(value); + return this.alpha = value; + } + + // @:bypassAccess doesn't work from external classes in haxe 4. So call this when needed + @:noCompletion inline function setColorBypass (value:FlxColor):FlxColor return @:bypassAccessor this.color = value; + @:noCompletion inline function setAlphaBypass (value:Float ):Float return @:bypassAccessor this.alpha = value; + @:noCompletion inline function setAngleBypass (value:Float ):Float return @:bypassAccessor this.angle = value; + @:noCompletion inline function setAntialiasingBypass(value:Bool ):Bool return @:bypassAccessor this.antialiasing = value; + @:noCompletion inline function setVisibleBypass (value:Bool ):Bool return @:bypassAccessor this.visible = value; + + // ============================================================================= + //} endregion GETTERS + // ============================================================================= +} diff --git a/flixel/system/render/FlxRenderer.hx b/flixel/system/render/FlxRenderer.hx new file mode 100644 index 0000000000..a30b5b99da --- /dev/null +++ b/flixel/system/render/FlxRenderer.hx @@ -0,0 +1,138 @@ +package flixel.system.render; + +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxFrame; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; +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. + */ +typedef FlxRenderer = FlxTypedRenderer; + +/** + * Typed Renderer, override this to handle specific backends that require specific cavera views + */ +abstract class FlxTypedRenderer implements IFlxDestroyable +{ + /** + * 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 cast new flixel.system.render.blit.FlxBlitRenderer(); + } + else + { + return cast new flixel.system.render.quad.FlxQuadRenderer(); + } + } + + /** + * The number of total draw calls in the current frame. + */ + public var totalDrawCalls:Int = 0; + + /** + * Returns the current render method as an enum. + */ + public var method(default, null):FlxRenderMethod; + + public var blit(get, never):Bool; + inline function get_blit() return method.match(BLITTING); + + public var tile(get, never):Bool; + inline function get_tile() return method.match(DRAW_TILES); + + /** + * 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 = -1; + + function new() {} + + /** + * Initializes and global fields that are dependant on the global rendering method. + * Called automatically by `FlxG.init` + */ + public function initGlobals() {} + + public function destroy():Void {} + + abstract function createCameraView(camera:FlxCamera):TView; +} + +/** + * 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; + + /** + * A custom backend + */ + CUSTOM; +} diff --git a/flixel/system/render/FlxVertexBuffer.hx b/flixel/system/render/FlxVertexBuffer.hx new file mode 100644 index 0000000000..4d18d2762f --- /dev/null +++ b/flixel/system/render/FlxVertexBuffer.hx @@ -0,0 +1,71 @@ +package flixel.system.render; + +import flixel.util.FlxColor; +import openfl.display.BlendMode; +import openfl.display.Graphics; +import openfl.geom.ColorTransform; +import openfl.geom.Point; +import openfl.geom.Rectangle; + +/** + * Helper for interfacing with a openfl Graphics, in 7.0.0 this will change from + * an abstract to a class wrapping graphic that implements an interface. All + * references to Graphic need to be removed first + */ +@:forward +abstract FlxVertexBuffer(Graphics) from Graphics to Graphics +{ + /** + * Wipes all drawn vertices from the buffer + */ + public inline function clear():Void + { + this.clear(); + } + + /** + * Draws a hollow axis-aligned rectangle to the buffer + * @param x + * @param y + * @param width + * @param height + * @param color The Color of the outline + * @param thickness The thickness of the outline + */ + public function drawRect(x:Float, y:Float, width:Float, height:Float, color:FlxColor, thickness:Float = 1.0):Void + { + this.lineStyle(thickness, color.rgb, color.alphaFloat, false, null, null, MITER, 255); + this.drawRect(x, y, width, height); + } + + /** + * Draws a solid axis-aligned rectangle to the buffer + */ + public function drawFilledRect(x:Float, y:Float, width:Float, height:Float, color:FlxColor):Void + { + this.lineStyle(); + this.beginFill(color.rgb, color.alphaFloat); + this.drawRect(x, y, width, height); + this.endFill(); + } + + /** + * Draws an antialiased solid circle to the buffer + */ + public function drawFilledCircle(x:Float, y:Float, radius:Float, color:FlxColor):Void + { + this.beginFill(color.rgb, color.alphaFloat); + this.drawCircle(x, y, radius); + this.endFill(); + } + + /** + * Draws an antialiased line to the buffer + */ + public function drawLine(x1:Float, y1:Float, x2:Float, y2:Float, color:FlxColor, thickness:Float = 1.0):Void + { + this.lineStyle(thickness, color.rgb, color.alphaFloat, false, null, null, MITER, 255); + this.moveTo(x1, y1); + this.lineTo(x2, y2); + } +} \ No newline at end of file diff --git a/flixel/system/render/blit/FlxBlitRenderer.hx b/flixel/system/render/blit/FlxBlitRenderer.hx new file mode 100644 index 0000000000..4933e55519 --- /dev/null +++ b/flixel/system/render/blit/FlxBlitRenderer.hx @@ -0,0 +1,54 @@ +package flixel.system.render.blit; + +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxFrame; +import flixel.graphics.tile.FlxDrawTrianglesItem; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.math.FlxRect; +import flixel.system.FlxAssets; +import flixel.system.render.FlxRenderer; +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 FlxTypedRenderer +{ + /** + * 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 var useBufferLocking:Bool = false; + + public function new() + { + super(); + method = BLITTING; + } + + override function initGlobals() + { + super.initGlobals(); + + FlxObject.defaultPixelPerfectPosition = true; + } + + public function createCameraView(camera:FlxCamera) + { + return new FlxBlitView(camera); + } +} diff --git a/flixel/system/render/blit/FlxBlitView.hx b/flixel/system/render/blit/FlxBlitView.hx new file mode 100644 index 0000000000..da30f52847 --- /dev/null +++ b/flixel/system/render/blit/FlxBlitView.hx @@ -0,0 +1,564 @@ +package flixel.system.render.blit; + +import flixel.FlxCamera; +import flixel.FlxG; +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxFrame; +import flixel.graphics.tile.FlxDrawTrianglesItem; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.math.FlxRect; +import flixel.system.FlxAssets; +import flixel.system.render.FlxCameraView; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; +import flixel.util.FlxSpriteUtil; +import openfl.display.Bitmap; +import openfl.display.BitmapData; +import openfl.display.BlendMode; +import openfl.display.DisplayObjectContainer; +import openfl.display.Graphics; +import openfl.display.Sprite; +import openfl.geom.ColorTransform; +import openfl.geom.Point; +import openfl.geom.Rectangle; + +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; + + #if FLX_DEBUG + /** + * Sprite for drawDebug information + */ + public var debugSprite:Sprite = new Sprite(); + #end + + /** + * 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, 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(); + + /** + * 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(); + + var _flashOffset:FlxPoint = FlxPoint.get(); + + var _renderer(get, never):FlxBlitRenderer; + inline function get__renderer() return cast (FlxG.renderer, FlxBlitRenderer); + + @: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; + _flashOffset = FlxDestroyUtil.put(_flashOffset); + } + + // ============================================================================= + //{ region RENDERING + // ============================================================================= + + override function render() + { + // super.render(); + + camera.drawFX(); + + if (_renderer.useBufferLocking) + { + buffer.unlock(); + } + + screen.dirty = true; + } + + override function clear() + { + // super.clear(); + + checkResize(); + + if (_renderer.useBufferLocking) + { + buffer.lock(); + } + + fill(camera.bgColor, camera.useBgAlphaBlending); + screen.dirty = true; + } + + @:haxe.warning("-WDeprecated") + override function fill(color:FlxColor, blendAlpha:Bool = true) + { + // super.fill(color, blendAlpha); + + if (blendAlpha) + { + _fill.fillRect(_flashRect, color); + buffer.copyPixels(_fill, _flashRect, _flashPoint, null, null, blendAlpha); + } + else + { + buffer.fillRect(_flashRect, color); + } + } + + @:noCompletion + static final _helperMatrix = new FlxMatrix(); + override function drawPixels(pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, smoothing = false, ?shader:FlxShader) + { + // super.drawPixels(pixels, matrix, transform, blend, smoothing, shader); + + _helperMatrix.copyFrom(matrix); + + if (_useBlitMatrix) + { + _helperMatrix.concat(_blitMatrix); + buffer.draw(pixels, _helperMatrix, null, null, null, (smoothing || antialiasing)); + } + else + { + _helperMatrix.translate(-camera.viewMarginLeft, -camera.viewMarginTop); + buffer.draw(pixels, _helperMatrix, null, blend, null, (smoothing || antialiasing)); + } + } + + @:noCompletion + static final _helperPoint:Point = new Point(); + override function copyPixels(pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, smoothing = false, ?shader) + { + // super.copyPixels(pixels, sourceRect, destPoint, transform, blend, smoothing); + + 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(camera.viewMarginLeft); + _helperPoint.y = destPoint.y - Std.int(camera.viewMarginTop); + buffer.copyPixels(pixels, sourceRect, _helperPoint, null, null, true); + } + } + + override function drawFrame(frame:FlxFrame, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, smoothing = false, ?shader:FlxShader) + { + throw "Not Implemented on blit"; + } + + override function copyFrame(frame:FlxFrame, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, smoothing = false, ?shader:FlxShader) + { + // TODO: fix this case for zoom less than initial zoom... + frame.paint(buffer, destPoint, true); + } + + @:noCompletion + static final _trianglesSprite = new Sprite(); + + @:noCompletion + static final drawVertices = new DrawData(); + override function drawTriangles(graphic:FlxGraphic, vertices:DrawData, indices:DrawData, uvtData:DrawData, ?colors:DrawData, + ?position, ?blend, repeat = false, smoothing = false, ?transform, ?shader) + { + // super.drawTriangles(graphic, vertices, indices, uvtData, colors, position, blend, repeat, smoothing, transform, shader); + + final cameraBounds = FlxRect.weak(camera.viewMarginLeft, camera.viewMarginTop, camera.viewWidth, camera.viewHeight); + + if (position == null) + position = FlxPoint.weak(); + + final verticesLength:Int = vertices.length >> 1; + + final bounds = FlxRect.get(); + drawVertices.splice(0, drawVertices.length); + + for (i in 0...verticesLength) + { + final tempX = position.x + vertices[(i << 1) + 0]; + final tempY = position.y + vertices[(i << 1) + 1]; + + drawVertices.push(tempX); + drawVertices.push(tempY); + + if (i == 0) + { + bounds.set(tempX, tempY, 0, 0); + } + else + { + FlxDrawTrianglesItem.inflateBounds(bounds, tempX, tempY); + } + } + + position.putWeak(); + + final overlaps = cameraBounds.overlaps(bounds); + bounds.put(); + + if (!overlaps) + { + drawVertices.splice(drawVertices.length - verticesLength, verticesLength); + return; + } + + _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(-camera.viewMarginLeft, -camera.viewMarginTop); + } + + 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); + buffer.draw(FlxSpriteUtil.flashGfxSprite, _helperMatrix); + } + #end + // End of TODO... + } + + // ============================================================================= + //} endregion RENDERING + // ============================================================================= + + // ============================================================================= + //{ region INTERNALS + // ============================================================================= + + function offsetView(x:Float, y:Float) + { + flashSprite.x += x; + flashSprite.y += y; + } + + function updatePosition() + { + if (flashSprite != null) + { + flashSprite.x = camera.x * FlxG.scaleMode.scale.x + _flashOffset.x; + flashSprite.y = camera.y * FlxG.scaleMode.scale.y + _flashOffset.y; + } + } + + function updateOffset() + { + _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() + { + final 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; + } + } + + function updateScale() + { + 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; + } + } + + function updateInternals() + { + if (_flashBitmap != null) + { + _flashBitmap.x = 0; + _flashBitmap.y = 0; + } + } + + // ============================================================================= + //} endregion INTERNALS + // ============================================================================= + + // ============================================================================= + //{ region DEBUG DRAW + // ============================================================================= + + function beginDrawDebug() + { + #if FLX_DEBUG + debugSprite.graphics.clear(); + #end + } + + function endDrawDebug():Void + { + #if FLX_DEBUG + buffer.draw(debugSprite); + #end + } + + #if FLX_DEBUG + + function getDebugBuffer():FlxVertexBuffer + { + return debugSprite.graphics; + } + + static final toDebugHelper = new openfl.geom.Point(); + function worldToDebugX(worldX:Float)//TODO: rename + { + toDebugHelper.setTo(worldX, 0); + return _flashBitmap.localToGlobal(toDebugHelper).x; + } + + function worldToDebugY(worldY:Float)//TODO: rename + { + toDebugHelper.setTo(0, worldY); + return _flashBitmap.localToGlobal(toDebugHelper).y; + } + #end + + //} endregion DEBUG DRAW + // ============================================================================= + + // ============================================================================= + //{ region HELPERS + // ============================================================================= + + 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; + } + + //} endregion HELPERS + // ============================================================================= + + // ============================================================================= + //{ region GETTERS + // ============================================================================= + + function get_display():DisplayObjectContainer + { + return flashSprite; + } + + override function set_color(value:FlxColor):FlxColor + { + if (_flashBitmap != null) + { + final colorTransform:ColorTransform = _flashBitmap.transform.colorTransform; + + colorTransform.redMultiplier = value.redFloat; + colorTransform.greenMultiplier = value.greenFloat; + colorTransform.blueMultiplier = value.blueFloat; + + _flashBitmap.transform.colorTransform = colorTransform; + } + + return super.set_color(value); + } + + override function set_antialiasing(value:Bool):Bool + { + _flashBitmap.smoothing = value; + return super.set_antialiasing(value); + } + + override function set_alpha(value:Float):Float + { + _flashBitmap.alpha = value; + return super.set_alpha(value); + } + + override function set_angle(value:Float):Float + { + flashSprite.rotation = value; + return super.set_angle(value); + } + + override function set_visible(value:Bool):Bool + { + flashSprite.visible = value; + return super.set_visible(value); + } + + //} endregion GETTERS + // ============================================================================= +} \ No newline at end of file diff --git a/flixel/system/render/quad/FlxQuadRenderer.hx b/flixel/system/render/quad/FlxQuadRenderer.hx new file mode 100644 index 0000000000..a081818eb8 --- /dev/null +++ b/flixel/system/render/quad/FlxQuadRenderer.hx @@ -0,0 +1,30 @@ +package flixel.system.render.quad; + +import flixel.system.render.FlxRenderer; + +using flixel.util.FlxColorTransformUtil; +#if FLX_OPENGL_AVAILABLE +import lime.graphics.opengl.GL; +#end + + +@:access(flixel.FlxCamera) +@:access(flixel.system.render.quad) +class FlxQuadRenderer extends FlxTypedRenderer +{ + public function new() + { + super(); + method = DRAW_TILES; + + #if FLX_OPENGL_AVAILBLE + if (isGL) + maxTextureSize = cast GL.getParameter(GL.MAX_TEXTURE_SIZE); + #end + } + + public function createCameraView(camera:FlxCamera) + { + return new FlxQuadView(camera); + } +} diff --git a/flixel/system/render/quad/FlxQuadView.hx b/flixel/system/render/quad/FlxQuadView.hx new file mode 100644 index 0000000000..fc239c3fdb --- /dev/null +++ b/flixel/system/render/quad/FlxQuadView.hx @@ -0,0 +1,550 @@ +package flixel.system.render.quad; + +import flixel.FlxCamera; +import flixel.FlxG; +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.system.render.FlxCameraView; +import flixel.util.FlxColor; +import flixel.util.FlxDestroyUtil; +import openfl.display.BitmapData; +import openfl.display.BlendMode; +import openfl.display.DisplayObjectContainer; +import openfl.display.Graphics; +import openfl.display.Sprite; +import openfl.geom.ColorTransform; +import openfl.geom.Point; +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 _flashOffset:FlxPoint = FlxPoint.get(); + + var _renderer(get, never):FlxQuadRenderer; + inline function get__renderer() return cast (FlxG.renderer, FlxQuadRenderer); + + @: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 + } + + 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; + _flashOffset = FlxDestroyUtil.put(_flashOffset); + } + + // ============================================================================= + //{ region RENDERING + // ============================================================================= + + override function render() + { + // super.render(); + + flashSprite.filters = camera.filtersEnabled ? camera.filters : null; + + var currItem:FlxDrawBaseItem = _headOfDrawStack; + while (currItem != null) + { + currItem.render(camera); + currItem = currItem.next; + } + + camera.drawFX(); + } + + override function clear() + { + // super.clear(); + + clearDrawStack(); + + canvas.graphics.clear(); + #if FLX_DEBUG + // Clearing camera's debug sprite + debugLayer.graphics.clear(); + #end + + fill(camera.bgColor, camera.useBgAlphaBlending); + } + + 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; + } + + override function fill(color:FlxColor, blendAlpha:Bool = true) + { + // super.fill(color, blendAlpha); + + canvas.graphics.overrideBlendMode(null); + canvas.graphics.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 + canvas.graphics.drawRect(camera.viewMarginLeft - 1, camera.viewMarginTop - 1, camera.viewWidth + 2, camera.viewHeight + 2); + canvas.graphics.endFill(); + } + + override function drawPixels(pixels, matrix, ?transform, ?blend, smoothing = false, ?shader) + { + // super.drawPixels(frame, matrix, transform, blend, smoothing, shader); + throw "Not implemented"; + } + + override function copyPixels(pixels, ?sourceRect, destPoint, ?transform, ?blend, smoothing = false, ?shader) + { + // super.copyPixels(pixels, sourceRect, destPoint, transform, blend, smoothing, shader); + throw "Not implemented"; + } + + override function drawFrame(frame:FlxFrame, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, smoothing = false, ?shader) + { + // super.drawFrame(frame, matrix, transform, blend, smoothing, shader); + + 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); + } + + @:noCompletion + static final _helperMatrix = new FlxMatrix(); + override function copyFrame(frame:FlxFrame, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, smoothing = false, ?shader:FlxShader) + { + // super.copyFrame(frame, destPoint, transform, blend, smoothing, shader); + + _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); + } + + override function drawTriangles(graphic:FlxGraphic, vertices:DrawData, indices:DrawData, uvtData:DrawData, ?colors:DrawData, + ?position:FlxPoint, ?blend:BlendMode, repeat = false, smoothing = false, ?transform:ColorTransform, ?shader:FlxShader) + { + // super.drawTriangles(graphic, vertices, indices, uvtData, colors, position, blend, repeat, smoothing, transform, shader); + + final cameraBounds = FlxRect.weak(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 = startTrianglesBatch(graphic, smoothing, isColored, blend, hasColorOffsets, shader); + drawItem.addTriangles(vertices, indices, uvtData, colors, position, cameraBounds, transform); + } + + // ============================================================================= + //} endregion RENDERING + // ============================================================================= + + // ============================================================================= + //{ region INTERNALS + // ============================================================================= + + function offsetView(x:Float, y:Float) + { + flashSprite.x += x; + flashSprite.y += y; + } + + function updatePosition() + { + if (flashSprite != null) + { + flashSprite.x = camera.x * FlxG.scaleMode.scale.x + _flashOffset.x; + flashSprite.y = camera.y * FlxG.scaleMode.scale.y + _flashOffset.y; + } + } + + function updateOffset() + { + _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() + { + final 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; + } + } + + function updateScale() {} + + function updateInternals() + { + 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(value:FlxColor):FlxColor + { + final colorTransform:ColorTransform = canvas.transform.colorTransform; + + colorTransform.redMultiplier = value.redFloat; + colorTransform.greenMultiplier = value.greenFloat; + colorTransform.blueMultiplier = value.blueFloat; + + canvas.transform.colorTransform = colorTransform; + + return super.set_color(value); + } + + override function set_alpha(value:Float):Float + { + canvas.alpha = alpha; + return super.set_alpha(value); + } + + override function set_angle(value:Float):Float + { + flashSprite.rotation = value; + return super.set_angle(value); + } + + override function set_visible(value:Bool):Bool + { + flashSprite.visible = value; + return super.set_visible(value); + } + + 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; + + public function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets = false, ?blend:BlendMode, smooth = 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 + } + + public function startTrianglesBatch(graphic:FlxGraphic, smoothing = false, isColored = 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); + } + + public function getNewDrawTrianglesItem(graphic:FlxGraphic, smoothing = false, isColored = 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; + } + + //} endregion INTERNALS + // ============================================================================= + + // ============================================================================= + //{ region DEBUG DRAW + // ============================================================================= + + public function beginDrawDebug() {} + + public function endDrawDebug() {} + + #if FLX_DEBUG + + public function getDebugBuffer():FlxVertexBuffer + { + return debugLayer.graphics; + } + + static final toDebugHelper = new openfl.geom.Point(); + function worldToDebugX(worldX:Float)//TODO: rename? + { + toDebugHelper.setTo(worldX, 0); + return canvas.localToGlobal(toDebugHelper).x; + } + + function worldToDebugY(worldY:Float)//TODO: rename? + { + toDebugHelper.setTo(worldY, 0); + return canvas.localToGlobal(toDebugHelper).y; + } + #end + + //} endregion DEBUG DRAW + // ============================================================================= +} diff --git a/flixel/system/scaleModes/StageSizeScaleMode.hx b/flixel/system/scaleModes/StageSizeScaleMode.hx index e6cecff086..97c79910d9 100644 --- a/flixel/system/scaleModes/StageSizeScaleMode.hx +++ b/flixel/system/scaleModes/StageSizeScaleMode.hx @@ -25,15 +25,15 @@ class StageSizeScaleMode extends BaseScaleMode if (FlxG.camera != null) { - var oldW = FlxG.camera.width; - var oldH = FlxG.camera.height; + final camera = FlxG.camera; + final oldW = camera.width; + final oldH = camera.height; - var newW = Math.ceil(Width / FlxG.camera.zoom); - var newH = Math.ceil(Height / FlxG.camera.zoom); + final newW = Math.ceil(Width / camera.zoom); + final newH = Math.ceil(Height / camera.zoom); - FlxG.camera.setSize(newW, newH); - FlxG.camera.flashSprite.x += (newW - oldW) / 2; - FlxG.camera.flashSprite.y += (newH - oldH) / 2; + camera.setPosition(0, 0); + camera.setSize(newW, newH); } } } diff --git a/flixel/text/FlxBitmapText.hx b/flixel/text/FlxBitmapText.hx index 4f6afe65a3..8ceca5e933 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(); @@ -400,11 +405,13 @@ 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); + camera.view.drawFrame(FlxG.bitmap.whitePixel, matrix, colorTransform, blend, antialiasing); } final hasColorOffsets = (colorTransform != null && colorTransform.hasRGBAOffsets()); - final drawItem = camera.startQuadBatch(font.parent, true, hasColorOffsets, blend, antialiasing, shader); + @:privateAccess + final view = camera.viewQuad; // TODO: handle better + final drawItem = view.startQuadBatch(font.parent, true, hasColorOffsets, blend, antialiasing, shader); function addQuad(charCode:Int, x:Float, y:Float, color:ColorTransform) { var frame = font.getCharFrame(charCode); @@ -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..e105e6534b 100644 --- a/flixel/text/FlxText.hx +++ b/flixel/text/FlxText.hx @@ -245,7 +245,7 @@ class FlxText extends FlxSprite allowCollisions = NONE; moves = false; - drawFrame(); + drawFrame(); // TODO: drawFrame(FlxG.renderer.blit); } /** @@ -1071,7 +1071,7 @@ class FlxText extends FlxSprite if (textField == null) return; - if (FlxG.renderTile && !RunOnCpp) + if (!FlxG.renderer.blit && !RunOnCpp) return; regenGraphic(); diff --git a/flixel/tile/FlxTilemap.hx b/flixel/tile/FlxTilemap.hx index fbeb5385b1..b47b0814fc 100644 --- a/flixel/tile/FlxTilemap.hx +++ b/flixel/tile/FlxTilemap.hx @@ -16,6 +16,7 @@ import flixel.math.FlxPoint; import flixel.math.FlxRect; import flixel.system.FlxAssets.FlxShader; import flixel.system.FlxAssets.FlxTilemapGraphicAsset; +import flixel.system.render.quad.FlxQuadView; import flixel.util.FlxColor; import flixel.util.FlxDestroyUtil; import flixel.util.FlxDirectionFlags; @@ -286,7 +287,7 @@ class FlxTypedTilemap extends FlxBaseTilemap { super(); - if (FlxG.renderTile) + if (FlxG.renderer.tile) { _helperPoint = new Point(); _matrix = new FlxMatrix(); @@ -305,7 +306,7 @@ class FlxTypedTilemap extends FlxBaseTilemap debugBoundingBoxColorPartial = FlxColor.PINK; debugBoundingBoxColorNotSolid = FlxColor.TRANSPARENT; - if (FlxG.renderBlit) + if (FlxG.renderer.blit) FlxG.debugger.drawDebugChanged.add(onDrawDebugChanged); #end } @@ -321,19 +322,19 @@ class FlxTypedTilemap extends FlxBaseTilemap _tileObjects = FlxDestroyUtil.destroyArray(_tileObjects); _buffers = FlxDestroyUtil.destroyArray(_buffers); - if (FlxG.renderBlit) + switch FlxG.renderer.method { - #if FLX_DEBUG - _debugRect = null; - _debugTileNotSolid = FlxDestroyUtil.dispose(_debugTileNotSolid); - _debugTilePartial = FlxDestroyUtil.dispose(_debugTilePartial); - _debugTileSolid = FlxDestroyUtil.dispose(_debugTileSolid); - #end - } - else - { - _helperPoint = null; - _matrix = null; + case BLITTING: + #if FLX_DEBUG + _debugRect = null; + _debugTileNotSolid = FlxDestroyUtil.dispose(_debugTileNotSolid); + _debugTilePartial = FlxDestroyUtil.dispose(_debugTilePartial); + _debugTileSolid = FlxDestroyUtil.dispose(_debugTileSolid); + #end + case DRAW_TILES: + _helperPoint = null; + _matrix = null; + case CUSTOM: } frames = null; @@ -351,7 +352,7 @@ class FlxTypedTilemap extends FlxBaseTilemap FlxG.cameras.cameraResized.remove(onCameraChanged); #if FLX_DEBUG - if (FlxG.renderBlit) + if (FlxG.renderer.blit) FlxG.debugger.drawDebugChanged.remove(onDrawDebugChanged); #end @@ -499,7 +500,7 @@ class FlxTypedTilemap extends FlxBaseTilemap function updateDebugTile(tileBitmap:BitmapData, color:FlxColor):BitmapData { - if (FlxG.renderTile) + if (!FlxG.renderer.blit) return null; if (tileWidth <= 0 || tileHeight <= 0) @@ -530,7 +531,7 @@ class FlxTypedTilemap extends FlxBaseTilemap override function updateMap():Void { #if FLX_DEBUG - if (FlxG.renderBlit) + if (FlxG.renderer.blit) _debugRect = new Rectangle(0, 0, tileWidth, tileHeight); #end @@ -542,7 +543,7 @@ class FlxTypedTilemap extends FlxBaseTilemap #if FLX_DEBUG override function drawDebugOnCamera(camera:FlxCamera):Void { - if (!FlxG.renderTile) + if (!FlxG.renderer.tile) return; var buffer:FlxTilemapBuffer = null; @@ -595,7 +596,7 @@ class FlxTypedTilemap extends FlxBaseTilemap if (color != null) { final colStr = color.toHexString(); - drawDebugBoundingBoxColor(camera.debugLayer.graphics, rect, color); + drawDebugBoundingBoxColorTo(camera.view, rect, color); } } } @@ -656,7 +657,7 @@ class FlxTypedTilemap extends FlxBaseTilemap buffer = _buffers[i]; - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { if (buffer.isDirty(this, camera)) drawTilemap(buffer, camera); @@ -704,7 +705,7 @@ class FlxTypedTilemap extends FlxBaseTilemap */ override function setDirty(dirty:Bool = true):Void { - if (FlxG.renderTile) + if (!FlxG.renderer.blit) return; for (buffer in _buffers) @@ -1034,7 +1035,7 @@ class FlxTypedTilemap extends FlxBaseTilemap var scaledHeight:Float = 0; var drawItem = null; - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { buffer.fill(); } @@ -1049,7 +1050,7 @@ class FlxTypedTilemap extends FlxBaseTilemap scaledHeight = scaledTileHeight; var hasColorOffsets:Bool = (colorTransform != null && colorTransform.hasRGBAOffsets()); - drawItem = camera.startQuadBatch(graphic, isColored, hasColorOffsets, blend, antialiasing, shader); + drawItem = cast (camera.view, FlxQuadView).startQuadBatch(graphic, isColored, hasColorOffsets, blend, antialiasing, shader); } // Copy tile images into the tile buffer @@ -1088,7 +1089,7 @@ class FlxTypedTilemap extends FlxBaseTilemap { frame = tile.frame; - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { frame.paint(buffer.pixels, _flashPoint, true); @@ -1136,13 +1137,13 @@ class FlxTypedTilemap extends FlxBaseTilemap } } - if (FlxG.renderBlit) + if (FlxG.renderer.blit) _flashPoint.x += tileWidth; columnIndex++; } - if (FlxG.renderBlit) + if (FlxG.renderer.blit) _flashPoint.y += tileHeight; rowIndex += widthInTiles; } @@ -1150,7 +1151,7 @@ class FlxTypedTilemap extends FlxBaseTilemap buffer.x = screenXInTiles * scaledTileWidth; buffer.y = screenYInTiles * scaledTileHeight; - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { if (isColored) buffer.colorTransform(colorTransform); @@ -1167,7 +1168,7 @@ class FlxTypedTilemap extends FlxBaseTilemap #if FLX_DEBUG function makeDebugTile(color:FlxColor):BitmapData { - if (FlxG.renderTile) + if (FlxG.renderer.tile) return null; var debugTile = new BitmapData(tileWidth, tileHeight, true, 0); diff --git a/flixel/tile/FlxTilemapBuffer.hx b/flixel/tile/FlxTilemapBuffer.hx index e5593b3d7c..18078df9d6 100644 --- a/flixel/tile/FlxTilemapBuffer.hx +++ b/flixel/tile/FlxTilemapBuffer.hx @@ -1,16 +1,16 @@ package flixel.tile; -import openfl.display.BitmapData; -import openfl.geom.Point; -import openfl.geom.Rectangle; import flixel.FlxCamera; import flixel.FlxG; import flixel.math.FlxMatrix; import flixel.tile.FlxTilemap; import flixel.util.FlxColor; import flixel.util.FlxDestroyUtil; +import openfl.display.BitmapData; import openfl.display.BlendMode; import openfl.geom.ColorTransform; +import openfl.geom.Point; +import openfl.geom.Rectangle; /** * A helper object to keep tilemap drawing performance decent across the new multi-camera system. @@ -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.blit) { 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.blit) { 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.blit) { pixels.fillRect(_flashRect, color); } @@ -180,17 +180,17 @@ class FlxTilemapBuffer implements IFlxDestroyable flashPoint.x = Math.floor(flashPoint.x); flashPoint.y = Math.floor(flashPoint.y); } - + if (isPixelPerfectRender(camera) && (scaleX == 1.0 && scaleY == 1.0) && blend == null) { - camera.copyPixels(pixels, _flashRect, flashPoint, null, null, true); + camera.view.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); + camera.view.drawPixels(pixels, _matrix, null, blend, antialiasing); } } diff --git a/flixel/ui/FlxBar.hx b/flixel/ui/FlxBar.hx index dcc0ac13d1..dbcd8b8d44 100644 --- a/flixel/ui/FlxBar.hx +++ b/flixel/ui/FlxBar.hx @@ -1,8 +1,5 @@ package flixel.ui; -import openfl.display.BitmapData; -import openfl.geom.Point; -import openfl.geom.Rectangle; import flixel.FlxG; import flixel.FlxSprite; import flixel.graphics.FlxGraphic; @@ -15,6 +12,9 @@ import flixel.util.FlxColor; import flixel.util.FlxDestroyUtil; import flixel.util.FlxGradient; import flixel.util.FlxStringUtil; +import openfl.display.BitmapData; +import openfl.geom.Point; +import openfl.geom.Rectangle; // TODO: better handling bars with borders (don't take border into account while drawing its front). @@ -172,15 +172,14 @@ class FlxBar extends FlxSprite _filledBarPoint = new Point(); _filledBarRect = new Rectangle(); - if (FlxG.renderBlit) + switch FlxG.renderer.method { - _zeroOffset = new Point(); - _emptyBarRect = new Rectangle(); - makeGraphic(width, height, FlxColor.TRANSPARENT, true); - } - else - { - _filledFlxRect = FlxRect.get(); + case BLITTING: + _zeroOffset = new Point(); + _emptyBarRect = new Rectangle(); + makeGraphic(width, height, FlxColor.TRANSPARENT, true); + case DRAW_TILES | CUSTOM: + _filledFlxRect = FlxRect.get(); } if (parentRef != null) @@ -198,17 +197,17 @@ class FlxBar extends FlxSprite { positionOffset = FlxDestroyUtil.put(positionOffset); - if (FlxG.renderTile) - { - frontFrames = null; - _filledFlxRect = FlxDestroyUtil.put(_filledFlxRect); - } - else + switch FlxG.renderer.method { - _emptyBarRect = null; - _zeroOffset = null; - _emptyBar = FlxDestroyUtil.dispose(_emptyBar); - _filledBar = FlxDestroyUtil.dispose(_filledBar); + case DRAW_TILES: + frontFrames = null; + _filledFlxRect = FlxDestroyUtil.put(_filledFlxRect); + case BLITTING: + _emptyBarRect = null; + _zeroOffset = null; + _emptyBar = FlxDestroyUtil.dispose(_emptyBar); + _filledBar = FlxDestroyUtil.dispose(_filledBar); + case CUSTOM: } _filledBarRect = null; _filledBarPoint = null; @@ -352,45 +351,45 @@ class FlxBar extends FlxSprite */ public function createColoredEmptyBar(empty:FlxColor, showBorder:Bool = false, border:FlxColor = FlxColor.WHITE, borderSize:Int = 1):FlxBar { - if (FlxG.renderTile) + switch FlxG.renderer.method { - var emptyKey:String = "empty: " + barWidth + "x" + barHeight + ":" + empty.toHexString(); - if (showBorder) - emptyKey += ",border: " + border.toHexString() + "borderSize: " + borderSize; - - if (!FlxG.bitmap.checkCache(emptyKey)) - { - var emptyBar:BitmapData = null; - + case DRAW_TILES: + var emptyKey:String = "empty: " + barWidth + "x" + barHeight + ":" + empty.toHexString(); + if (showBorder) + emptyKey += ",border: " + border.toHexString() + "borderSize: " + borderSize; + + if (!FlxG.bitmap.checkCache(emptyKey)) + { + var emptyBar:BitmapData = null; + + if (showBorder) + { + emptyBar = new BitmapData(barWidth, barHeight, true, border); + emptyBar.fillRect(new Rectangle(borderSize, borderSize, barWidth - borderSize * 2, barHeight - borderSize * 2), empty); + } + else + { + emptyBar = new BitmapData(barWidth, barHeight, true, empty); + } + + FlxG.bitmap.add(emptyBar, false, emptyKey); + } + + frames = FlxG.bitmap.get(emptyKey).imageFrame; + case BLITTING: if (showBorder) { - emptyBar = new BitmapData(barWidth, barHeight, true, border); - emptyBar.fillRect(new Rectangle(borderSize, borderSize, barWidth - borderSize * 2, barHeight - borderSize * 2), empty); + _emptyBar = new BitmapData(barWidth, barHeight, true, border); + _emptyBar.fillRect(new Rectangle(borderSize, borderSize, barWidth - borderSize * 2, barHeight - borderSize * 2), empty); } else { - emptyBar = new BitmapData(barWidth, barHeight, true, empty); + _emptyBar = new BitmapData(barWidth, barHeight, true, empty); } - FlxG.bitmap.add(emptyBar, false, emptyKey); - } - - frames = FlxG.bitmap.get(emptyKey).imageFrame; - } - else - { - if (showBorder) - { - _emptyBar = new BitmapData(barWidth, barHeight, true, border); - _emptyBar.fillRect(new Rectangle(borderSize, borderSize, barWidth - borderSize * 2, barHeight - borderSize * 2), empty); - } - else - { - _emptyBar = new BitmapData(barWidth, barHeight, true, empty); - } - - _emptyBarRect.setTo(0, 0, barWidth, barHeight); - updateEmptyBar(); + _emptyBarRect.setTo(0, 0, barWidth, barHeight); + updateEmptyBar(); + case CUSTOM: } return this; @@ -406,45 +405,45 @@ class FlxBar extends FlxSprite */ public function createColoredFilledBar(fill:FlxColor, showBorder:Bool = false, border:FlxColor = FlxColor.WHITE, borderSize:Int = 1):FlxBar { - if (FlxG.renderTile) + switch FlxG.renderer.method { - var filledKey:String = "filled: " + barWidth + "x" + barHeight + ":" + fill.toHexString(); - if (showBorder) - filledKey += ",border: " + border.toHexString() + "borderSize: " + borderSize; + case DRAW_TILES: + var filledKey:String = "filled: " + barWidth + "x" + barHeight + ":" + fill.toHexString(); + if (showBorder) + filledKey += ",border: " + border.toHexString() + "borderSize: " + borderSize; - if (!FlxG.bitmap.checkCache(filledKey)) - { - var filledBar:BitmapData = null; + if (!FlxG.bitmap.checkCache(filledKey)) + { + var filledBar:BitmapData = null; + + if (showBorder) + { + filledBar = new BitmapData(barWidth, barHeight, true, border); + filledBar.fillRect(new Rectangle(borderSize, borderSize, barWidth - borderSize * 2, barHeight - borderSize * 2), fill); + } + else + { + filledBar = new BitmapData(barWidth, barHeight, true, fill); + } + FlxG.bitmap.add(filledBar, false, filledKey); + } + + frontFrames = FlxG.bitmap.get(filledKey).imageFrame; + case BLITTING: if (showBorder) { - filledBar = new BitmapData(barWidth, barHeight, true, border); - filledBar.fillRect(new Rectangle(borderSize, borderSize, barWidth - borderSize * 2, barHeight - borderSize * 2), fill); + _filledBar = new BitmapData(barWidth, barHeight, true, border); + _filledBar.fillRect(new Rectangle(borderSize, borderSize, barWidth - borderSize * 2, barHeight - borderSize * 2), fill); } else { - filledBar = new BitmapData(barWidth, barHeight, true, fill); + _filledBar = new BitmapData(barWidth, barHeight, true, fill); } - FlxG.bitmap.add(filledBar, false, filledKey); - } - - frontFrames = FlxG.bitmap.get(filledKey).imageFrame; - } - else - { - if (showBorder) - { - _filledBar = new BitmapData(barWidth, barHeight, true, border); - _filledBar.fillRect(new Rectangle(borderSize, borderSize, barWidth - borderSize * 2, barHeight - borderSize * 2), fill); - } - else - { - _filledBar = new BitmapData(barWidth, barHeight, true, fill); - } - - _filledBarRect.setTo(0, 0, barWidth, barHeight); - updateFilledBar(); + _filledBarRect.setTo(0, 0, barWidth, barHeight); + updateFilledBar(); + case CUSTOM: } return this; } @@ -484,57 +483,57 @@ 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) + switch FlxG.renderer.method { - var emptyKey:String = "Gradient:" + barWidth + "x" + barHeight + ",colors:["; - for (col in empty) - { - emptyKey += col.toHexString() + ","; - } - emptyKey += "],chunkSize: " + chunkSize + ",rotation: " + rotation; - - if (showBorder) - { - emptyKey += ",border: " + border.toHexString() + "borderSize: " + borderSize; - } - - if (!FlxG.bitmap.checkCache(emptyKey)) - { - var emptyBar:BitmapData = null; - + case DRAW_TILES: + var emptyKey:String = "Gradient:" + barWidth + "x" + barHeight + ",colors:["; + for (col in empty) + { + emptyKey += col.toHexString() + ","; + } + emptyKey += "],chunkSize: " + chunkSize + ",rotation: " + rotation; + if (showBorder) { - emptyBar = new BitmapData(barWidth, barHeight, true, border); - FlxGradient.overlayGradientOnBitmapData(emptyBar, barWidth - borderSize * 2, barHeight - borderSize * 2, empty, borderSize, borderSize, + emptyKey += ",border: " + border.toHexString() + "borderSize: " + borderSize; + } + + if (!FlxG.bitmap.checkCache(emptyKey)) + { + var emptyBar:BitmapData = null; + + if (showBorder) + { + emptyBar = new BitmapData(barWidth, barHeight, true, border); + FlxGradient.overlayGradientOnBitmapData(emptyBar, barWidth - borderSize * 2, barHeight - borderSize * 2, empty, borderSize, borderSize, + chunkSize, rotation); + } + else + { + emptyBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, empty, chunkSize, rotation); + } + + FlxG.bitmap.add(emptyBar, false, emptyKey); + } + + frames = FlxG.bitmap.get(emptyKey).imageFrame; + case BLITTING: + if (showBorder) + { + _emptyBar = new BitmapData(barWidth, barHeight, true, border); + FlxGradient.overlayGradientOnBitmapData(_emptyBar, barWidth - borderSize * 2, barHeight - borderSize * 2, empty, borderSize, borderSize, chunkSize, rotation); } else { - emptyBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, empty, chunkSize, rotation); + _emptyBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, empty, chunkSize, rotation); } - - FlxG.bitmap.add(emptyBar, false, emptyKey); - } - - frames = FlxG.bitmap.get(emptyKey).imageFrame; - } - else - { - if (showBorder) - { - _emptyBar = new BitmapData(barWidth, barHeight, true, border); - FlxGradient.overlayGradientOnBitmapData(_emptyBar, barWidth - borderSize * 2, barHeight - borderSize * 2, empty, borderSize, borderSize, - chunkSize, rotation); - } - else - { - _emptyBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, empty, chunkSize, rotation); - } - - _emptyBarRect.setTo(0, 0, barWidth, barHeight); - updateEmptyBar(); + + _emptyBarRect.setTo(0, 0, barWidth, barHeight); + updateEmptyBar(); + case CUSTOM: } - + return this; } @@ -552,57 +551,57 @@ 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) + switch FlxG.renderer.method { - var filledKey:String = "Gradient:" + barWidth + "x" + barHeight + ",colors:["; - for (col in fill) - { - filledKey += col.toHexString() + ","; - } - filledKey += "],chunkSize: " + chunkSize + ",rotation: " + rotation; - - if (showBorder) - { - filledKey += ",border: " + border.toHexString() + "borderSize: " + borderSize; - } - - if (!FlxG.bitmap.checkCache(filledKey)) - { - var filledBar:BitmapData = null; - + case DRAW_TILES: + var filledKey:String = "Gradient:" + barWidth + "x" + barHeight + ",colors:["; + for (col in fill) + { + filledKey += col.toHexString() + ","; + } + filledKey += "],chunkSize: " + chunkSize + ",rotation: " + rotation; + + if (showBorder) + { + filledKey += ",border: " + border.toHexString() + "borderSize: " + borderSize; + } + + if (!FlxG.bitmap.checkCache(filledKey)) + { + var filledBar:BitmapData = null; + + if (showBorder) + { + filledBar = new BitmapData(barWidth, barHeight, true, border); + FlxGradient.overlayGradientOnBitmapData(filledBar, barWidth - borderSize * 2, barHeight - borderSize * 2, fill, borderSize, borderSize, + chunkSize, rotation); + } + else + { + filledBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, fill, chunkSize, rotation); + } + + FlxG.bitmap.add(filledBar, false, filledKey); + } + + frontFrames = FlxG.bitmap.get(filledKey).imageFrame; + case BLITTING: if (showBorder) { - filledBar = new BitmapData(barWidth, barHeight, true, border); - FlxGradient.overlayGradientOnBitmapData(filledBar, barWidth - borderSize * 2, barHeight - borderSize * 2, fill, borderSize, borderSize, + _filledBar = new BitmapData(barWidth, barHeight, true, border); + FlxGradient.overlayGradientOnBitmapData(_filledBar, barWidth - borderSize * 2, barHeight - borderSize * 2, fill, borderSize, borderSize, chunkSize, rotation); } else { - filledBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, fill, chunkSize, rotation); + _filledBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, fill, chunkSize, rotation); } - - FlxG.bitmap.add(filledBar, false, filledKey); - } - - frontFrames = FlxG.bitmap.get(filledKey).imageFrame; - } - else - { - if (showBorder) - { - _filledBar = new BitmapData(barWidth, barHeight, true, border); - FlxGradient.overlayGradientOnBitmapData(_filledBar, barWidth - borderSize * 2, barHeight - borderSize * 2, fill, borderSize, borderSize, - chunkSize, rotation); - } - else - { - _filledBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, fill, chunkSize, rotation); - } - - _filledBarRect.setTo(0, 0, barWidth, barHeight); - updateFilledBar(); + + _filledBarRect.setTo(0, 0, barWidth, barHeight); + updateFilledBar(); + case CUSTOM: } - + return this; } @@ -638,26 +637,26 @@ class FlxBar extends FlxSprite if (empty != null) { var emptyGraphic:FlxGraphic = FlxG.bitmap.add(empty); - - if (FlxG.renderTile) + + switch FlxG.renderer.method { - frames = emptyGraphic.imageFrame; - } - else - { - _emptyBar = emptyGraphic.bitmap.clone(); - - barWidth = _emptyBar.width; - barHeight = _emptyBar.height; - - _emptyBarRect.setTo(0, 0, barWidth, barHeight); - - if (graphic == null || (frame.sourceSize.x != barWidth || frame.sourceSize.y != barHeight)) - { - makeGraphic(barWidth, barHeight, FlxColor.TRANSPARENT, true); - } - - updateEmptyBar(); + case DRAW_TILES: + frames = emptyGraphic.imageFrame; + case BLITTING: + _emptyBar = emptyGraphic.bitmap.clone(); + + barWidth = _emptyBar.width; + barHeight = _emptyBar.height; + + _emptyBarRect.setTo(0, 0, barWidth, barHeight); + + if (graphic == null || (frame.sourceSize.x != barWidth || frame.sourceSize.y != barHeight)) + { + makeGraphic(barWidth, barHeight, FlxColor.TRANSPARENT, true); + } + + updateEmptyBar(); + case CUSTOM: } } else @@ -680,24 +679,24 @@ class FlxBar extends FlxSprite if (fill != null) { var filledGraphic:FlxGraphic = FlxG.bitmap.add(fill); - - if (FlxG.renderTile) + + switch FlxG.renderer.method { - frontFrames = filledGraphic.imageFrame; - } - else - { - _filledBar = filledGraphic.bitmap.clone(); - - _filledBarRect.setTo(0, 0, barWidth, barHeight); - - if (graphic == null || (frame.sourceSize.x != barWidth || frame.sourceSize.y != barHeight)) - { - makeGraphic(barWidth, barHeight, FlxColor.TRANSPARENT, true); - } - - pxPerPercent = (_fillHorizontal) ? (barWidth / _maxPercent) : (barHeight / _maxPercent); - updateFilledBar(); + case DRAW_TILES: + frontFrames = filledGraphic.imageFrame; + case BLITTING: + _filledBar = filledGraphic.bitmap.clone(); + + _filledBarRect.setTo(0, 0, barWidth, barHeight); + + if (graphic == null || (frame.sourceSize.x != barWidth || frame.sourceSize.y != barHeight)) + { + makeGraphic(barWidth, barHeight, FlxColor.TRANSPARENT, true); + } + + pxPerPercent = (_fillHorizontal) ? (barWidth / _maxPercent) : (barHeight / _maxPercent); + updateFilledBar(); + case CUSTOM: } } else @@ -744,7 +743,7 @@ class FlxBar extends FlxSprite */ public function updateEmptyBar():Void { - if (FlxG.renderBlit) + if (FlxG.renderer.blit) { pixels.copyPixels(_emptyBar, _emptyBarRect, _zeroOffset); dirty = true; @@ -806,27 +805,23 @@ class FlxBar extends FlxSprite _filledBarPoint.y = Std.int((barHeight - _filledBarRect.height) / 2); } - if (FlxG.renderBlit) + switch FlxG.renderer.method { - pixels.copyPixels(_filledBar, _filledBarRect, _filledBarPoint, null, null, true); - } - else - { - if (frontFrames != null) - { - _filledFlxRect.copyFromFlash(_filledBarRect).round(); - if (Std.int(percent) > 0) + case BLITTING: + pixels.copyPixels(_filledBar, _filledBarRect, _filledBarPoint, null, null, true); + dirty = true; + case DRAW_TILES: + if (frontFrames != null) { - _frontFrame = frontFrames.frame.clipTo(_filledFlxRect, _frontFrame); + _filledFlxRect.copyFromFlash(_filledBarRect).round(); + if (Std.int(percent) > 0) + { + _frontFrame = frontFrames.frame.clipTo(_filledFlxRect, _frontFrame); + } } - } + case CUSTOM: } } - - if (FlxG.renderBlit) - { - dirty = true; - } } override public function update(elapsed:Float):Void @@ -852,7 +847,7 @@ class FlxBar extends FlxSprite { super.draw(); - if (!FlxG.renderTile) + if (!FlxG.renderer.tile) return; if (alpha == 0) @@ -890,14 +885,14 @@ class FlxBar extends FlxSprite _matrix.ty = Math.floor(_matrix.ty); } - camera.drawPixels(_frontFrame, _matrix, colorTransform, blend, antialiasing, shader); + camera.view.drawFrame(_frontFrame, _matrix, colorTransform, blend, antialiasing, shader); } } } override function set_pixels(pixels:BitmapData):BitmapData { - if (FlxG.renderTile) + if (FlxG.renderer.tile) { return pixels; // hack } @@ -982,7 +977,7 @@ class FlxBar extends FlxSprite function get_frontFrames():FlxImageFrame { - if (FlxG.renderTile) + if (FlxG.renderer.tile) { return frontFrames; } @@ -991,7 +986,7 @@ class FlxBar extends FlxSprite function set_frontFrames(value:FlxImageFrame):FlxImageFrame { - if (FlxG.renderTile) + if (FlxG.renderer.tile) { if (value != null) value.parent.incrementUseCount(); @@ -1011,7 +1006,7 @@ class FlxBar extends FlxSprite function get_backFrames():FlxImageFrame { - if (FlxG.renderTile) + if (FlxG.renderer.tile) { return cast frames; } @@ -1020,14 +1015,15 @@ class FlxBar extends FlxSprite function set_backFrames(value:FlxImageFrame):FlxImageFrame { - if (FlxG.renderTile) + switch FlxG.renderer.method { - frames = value; - } - else - { - createImageEmptyBar(value.frame.paint()); + case DRAW_TILES: + frames = value; + case BLITTING: + createImageEmptyBar(value.frame.paint()); + case CUSTOM: } + return value; } } diff --git a/tests/coverage/Project.xml b/tests/coverage/Project.xml index 089e8ad176..49d23baa7b 100644 --- a/tests/coverage/Project.xml +++ b/tests/coverage/Project.xml @@ -1,6 +1,6 @@ - + @@ -34,7 +34,7 @@ - +
diff --git a/tests/unit/project.xml b/tests/unit/project.xml index 412ea43a19..70a754e2ed 100644 --- a/tests/unit/project.xml +++ b/tests/unit/project.xml @@ -1,6 +1,6 @@ - + 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); diff --git a/tests/unit/src/flixel/system/frontEnds/DebuggerFrontEndTest.hx b/tests/unit/src/flixel/system/frontEnds/DebuggerFrontEndTest.hx index 514cf90e50..430932f268 100644 --- a/tests/unit/src/flixel/system/frontEnds/DebuggerFrontEndTest.hx +++ b/tests/unit/src/flixel/system/frontEnds/DebuggerFrontEndTest.hx @@ -1,7 +1,8 @@ package flixel.system.frontEnds; import flixel.FlxG; -import flixel.system.debug.watch.Tracker.TrackerProfile; +import flixel.system.debug.watch.Tracker; +import flixel.system.debug.watch.TrackerProfile; import flixel.util.FlxSignal; import massive.munit.Assert;