From 202397a68bd11d5fc3d81db8074c4ed042b6b94f Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Mon, 29 Nov 2021 17:23:05 +0100 Subject: [PATCH 1/6] Removed fallback on web for drawAtlas --- packages/flame/lib/src/sprite_batch.dart | 38 ++++++------------------ 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/packages/flame/lib/src/sprite_batch.dart b/packages/flame/lib/src/sprite_batch.dart index 813cede1961..b2014e464c7 100644 --- a/packages/flame/lib/src/sprite_batch.dart +++ b/packages/flame/lib/src/sprite_batch.dart @@ -260,34 +260,14 @@ class SpriteBatch { Rect? cullRect, Paint? paint, }) { - paint ??= Paint(); - - if (kIsWeb) { - for (final batchItem in _batchItems) { - paint.blendMode = blendMode ?? paint.blendMode; - - canvas - ..save() - ..transform(batchItem.matrix.storage) - ..drawRect(batchItem.destination, batchItem.paint) - ..drawImageRect( - atlas, - batchItem.source, - batchItem.destination, - paint, - ) - ..restore(); - } - } else { - canvas.drawAtlas( - atlas, - _transforms, - _sources, - _colors, - blendMode ?? defaultBlendMode, - cullRect, - paint, - ); - } + canvas.drawAtlas( + atlas, + _transforms, + _sources, + _colors, + blendMode ?? defaultBlendMode, + cullRect, + paint ?? Paint(), + ); } } From 007f840187646531e3f58ce2076ed3fd1dd37d12 Mon Sep 17 00:00:00 2001 From: Luan Nico Date: Thu, 2 Dec 2021 17:30:33 -0500 Subject: [PATCH 2/6] Fix analyzer --- packages/flame/lib/src/sprite_batch.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/flame/lib/src/sprite_batch.dart b/packages/flame/lib/src/sprite_batch.dart index b2014e464c7..d624c79c56f 100644 --- a/packages/flame/lib/src/sprite_batch.dart +++ b/packages/flame/lib/src/sprite_batch.dart @@ -1,8 +1,6 @@ import 'dart:collection'; import 'dart:ui'; -import 'package:flutter/foundation.dart'; - import '../game.dart'; import 'assets/images.dart'; import 'extensions/image.dart'; From baff3d25221120303f1cc46631daa2eca7094cac Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Tue, 7 Dec 2021 15:08:43 +0100 Subject: [PATCH 3/6] Optional argument for not using `drawAtlas` --- packages/flame/lib/src/sprite_batch.dart | 120 +++++++++++++++-------- 1 file changed, 80 insertions(+), 40 deletions(-) diff --git a/packages/flame/lib/src/sprite_batch.dart b/packages/flame/lib/src/sprite_batch.dart index d624c79c56f..4515447a87b 100644 --- a/packages/flame/lib/src/sprite_batch.dart +++ b/packages/flame/lib/src/sprite_batch.dart @@ -8,12 +8,14 @@ import 'extensions/vector2.dart'; import 'flame.dart'; extension SpriteBatchExtension on Game { - /// Utility method to load and cache the image for a [SpriteBatch] based on its options + /// Utility method to load and cache the image for a [SpriteBatch] based on + /// its options Future loadSpriteBatch( String path, { Color defaultColor = const Color(0x00000000), BlendMode defaultBlendMode = BlendMode.srcOver, RSTransform? defaultTransform, + bool drawAtlas = true, }) { return SpriteBatch.load( path, @@ -21,22 +23,19 @@ extension SpriteBatchExtension on Game { defaultBlendMode: defaultBlendMode, defaultTransform: defaultTransform, images: images, + drawAtlas: drawAtlas, ); } } -/// This is the scale value used in [BatchItem.matrix], we can't determine this from the [BatchItem.transform], -/// but we also don't need to do so because it is already calculated inside the transform values. +/// This is the scale value used in [BatchItem.matrix], we can't determine this +/// from the [BatchItem.transform], but we also don't need to do so because it +/// is already calculated inside the transform values. const _defaultScale = 0.0; /// A single item in a SpriteBatch. /// /// Holds all the important information of a batch item, -/// -/// Web currently does not support `Canvas.drawAtlas`, so a BatchItem will -/// automatically calculate a transform matrix based on the [transform] value, to be -/// used when rendering on the web. It will initialize a [destination] object -/// and a [paint] object. class BatchItem { /// The source rectangle on the [SpriteBatch.atlas]. final Rect source; @@ -78,16 +77,19 @@ class BatchItem { /// The SpriteBatch API allows for rendering multiple items at once. /// /// This class allows for optimization when you want to draw many parts of an -/// image onto the canvas. It is more efficient than using multiple calls to [Canvas.drawImageRect] -/// and provides more functionality by allowing each [BatchItem] to have their own transform -/// rotation and color. +/// image onto the canvas. It is more efficient than using multiple calls to +/// [Canvas.drawImageRect] and provides more functionality by allowing each +/// [BatchItem] to have their own transform rotation and color. /// -/// By collecting all the necessary transforms on a single image and sending those transforms -/// in a single batch to the GPU, we can render multiple parts of a single image at once. +/// By collecting all the necessary transforms on a single image and sending +/// those transforms in a single batch to the GPU, we can render multiple parts +/// of a single image at once. /// -/// **Note**: Currently web does not support `Canvas.drawAtlas`, which SpriteBatch uses under -/// the hood, instead it will render each [BatchItem] using `Canvas.drawImageRect`, so there -/// might be a performance hit on web when working with many batch items. +/// **Note**: If you are experiencing problems with ghost lines, the less +/// performant [Canvas.drawImageRect] can be used instead of [Canvas.drawAtlas]. +/// To activate this mode, pass in `drawAtlas = false` to the constructor or +/// load method that you are using and each [BatchItem] will be rendered using +/// the [Canvas.drawImageRect] method instead. class SpriteBatch { /// List of all the existing batch items. final _batchItems = []; @@ -128,7 +130,8 @@ class SpriteBatch { /// The default color, used as a background color for a [BatchItem]. final Color defaultColor; - /// The default transform, used when a transform was not supplied for a [BatchItem]. + /// The default transform, used when a transform was not supplied for a + /// [BatchItem]. final RSTransform? defaultTransform; /// The default blend mode, used for blending a batch item. @@ -143,11 +146,15 @@ class SpriteBatch { /// The size of the [atlas]. Vector2 get size => atlas.size; + /// Whether to use [Canvas.drawAtlas] or not. + final bool drawAtlas; + SpriteBatch( this.atlas, { this.defaultColor = const Color(0x00000000), this.defaultBlendMode = BlendMode.srcOver, this.defaultTransform, + this.drawAtlas = true, }); /// Takes a path of an image, and optional arguments for the SpriteBatch. @@ -159,6 +166,7 @@ class SpriteBatch { BlendMode defaultBlendMode = BlendMode.srcOver, RSTransform? defaultTransform, Images? images, + bool drawAtlas = true, }) async { final _images = images ?? Flame.images; return SpriteBatch( @@ -166,6 +174,7 @@ class SpriteBatch { defaultColor: defaultColor, defaultTransform: defaultTransform ?? RSTransform(1, 0, 0, 0), defaultBlendMode: defaultBlendMode, + drawAtlas: drawAtlas, ); } @@ -173,14 +182,17 @@ class SpriteBatch { /// /// The [source] parameter is the source location on the [atlas]. /// - /// You can position, rotate and scale it on the canvas using the [transform] parameter. + /// You can position, rotate and scale it on the canvas using the [transform] + /// parameter. /// - /// The [color] parameter allows you to render a color behind the batch item, as a background color. + /// The [color] parameter allows you to render a color behind the batch item, + /// as a background color. /// - /// The [add] method may be a simpler way to add a batch item to the batch. However, - /// if there is a way to factor out the computations of the sine and cosine of the - /// rotation so that they can be reused over multiple calls to this constructor, - /// it may be more efficient to directly use this method instead. + /// The [add] method may be a simpler way to add a batch item to the batch. + /// However, if there is a way to factor out the computations of the sine and + /// cosine of the rotation so that they can be reused over multiple calls to + /// this constructor, it may be more efficient to directly use this method + /// instead. void addTransform({ required Rect source, RSTransform? transform, @@ -201,17 +213,22 @@ class SpriteBatch { /// Add a new batch item. /// - /// The [source] parameter is the source location on the [atlas]. You can position it - /// on the canvas using the [offset] parameter. + /// The [source] parameter is the source location on the [atlas]. You can + /// position it on the canvas using the [offset] parameter. /// - /// You can transform the sprite from its [offset] using [scale], [rotation] and [anchor]. + /// You can transform the sprite from its [offset] using [scale], [rotation] + /// and [anchor]. /// - /// The [color] paramater allows you to render a color behind the batch item, as a background color. + /// The [color] paramater allows you to render a color behind the batch item, + /// as a background color. /// - /// This method creates a new [RSTransform] based on the given transform arguments. If many [RSTransform] objects are being - /// created and there is a way to factor out the computations of the sine and cosine of the rotation - /// (which are computed each time this method is called) and reuse them over multiple [RSTransform] objects, - /// it may be more efficient to directly use the more direct [addTransform] method instead. + /// This method creates a new [RSTransform] based on the given transform + /// arguments. If many [RSTransform] objects are being created and there is a + /// way to factor out the computations of the sine and cosine of the rotation + /// (which are computed each time this method is called) and reuse them over + /// multiple [RSTransform] objects, + /// it may be more efficient to directly use the more direct [addTransform] + /// method instead. void add({ required Rect source, double scale = 1.0, @@ -252,20 +269,43 @@ class SpriteBatch { _batchItems.clear(); } + // Used to not create new paint objects in [render] on every tick. + final Paint _emptyPaint = Paint(); + void render( Canvas canvas, { BlendMode? blendMode, Rect? cullRect, Paint? paint, }) { - canvas.drawAtlas( - atlas, - _transforms, - _sources, - _colors, - blendMode ?? defaultBlendMode, - cullRect, - paint ?? Paint(), - ); + paint ??= _emptyPaint; + + if (!drawAtlas) { + for (final batchItem in _batchItems) { + paint.blendMode = blendMode ?? paint.blendMode; + + canvas + ..save() + ..transform(batchItem.matrix.storage) + ..drawRect(batchItem.destination, batchItem.paint) + ..drawImageRect( + atlas, + batchItem.source, + batchItem.destination, + paint, + ) + ..restore(); + } + } else { + canvas.drawAtlas( + atlas, + _transforms, + _sources, + _colors, + blendMode ?? defaultBlendMode, + cullRect, + paint, + ); + } } } From f2e9bcd4235c8cf64f7cbe379a9e291035653530 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Tue, 7 Dec 2021 15:13:07 +0100 Subject: [PATCH 4/6] Add changelog entry --- packages/flame/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flame/CHANGELOG.md b/packages/flame/CHANGELOG.md index b25ffa3c92e..12efbf8eab0 100644 --- a/packages/flame/CHANGELOG.md +++ b/packages/flame/CHANGELOG.md @@ -12,6 +12,7 @@ - `isHud` renamed to `respectCamera` - Fix `HitboxCircle` when component is flipped - `ScaleEffect.by` now applies multiplicatively instead of additively + - Remove fallback to not use `drawAtlas` in SpriteBatch, but added flag `drawCanvas` to activate it ## [1.0.0-releasecandidate.18] - Forcing portrait and landscape mode is now supported on web From 5f91dbf2d1ca040fe19f958ed7c2bd390f97775b Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Tue, 7 Dec 2021 15:34:01 +0100 Subject: [PATCH 5/6] Update to flag name to useAtlas --- packages/flame/CHANGELOG.md | 2 +- packages/flame/lib/src/sprite_batch.dart | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/flame/CHANGELOG.md b/packages/flame/CHANGELOG.md index 12efbf8eab0..ea557d55969 100644 --- a/packages/flame/CHANGELOG.md +++ b/packages/flame/CHANGELOG.md @@ -12,7 +12,7 @@ - `isHud` renamed to `respectCamera` - Fix `HitboxCircle` when component is flipped - `ScaleEffect.by` now applies multiplicatively instead of additively - - Remove fallback to not use `drawAtlas` in SpriteBatch, but added flag `drawCanvas` to activate it + - Remove fallback to not use `drawAtlas` in SpriteBatch, but added flag `useAtlas` to activate it ## [1.0.0-releasecandidate.18] - Forcing portrait and landscape mode is now supported on web diff --git a/packages/flame/lib/src/sprite_batch.dart b/packages/flame/lib/src/sprite_batch.dart index 4515447a87b..42a30f76b24 100644 --- a/packages/flame/lib/src/sprite_batch.dart +++ b/packages/flame/lib/src/sprite_batch.dart @@ -15,7 +15,7 @@ extension SpriteBatchExtension on Game { Color defaultColor = const Color(0x00000000), BlendMode defaultBlendMode = BlendMode.srcOver, RSTransform? defaultTransform, - bool drawAtlas = true, + bool useAtlas = true, }) { return SpriteBatch.load( path, @@ -23,7 +23,7 @@ extension SpriteBatchExtension on Game { defaultBlendMode: defaultBlendMode, defaultTransform: defaultTransform, images: images, - drawAtlas: drawAtlas, + useAtlas: useAtlas, ); } } @@ -87,7 +87,7 @@ class BatchItem { /// /// **Note**: If you are experiencing problems with ghost lines, the less /// performant [Canvas.drawImageRect] can be used instead of [Canvas.drawAtlas]. -/// To activate this mode, pass in `drawAtlas = false` to the constructor or +/// To activate this mode, pass in `useAtlas = false` to the constructor or /// load method that you are using and each [BatchItem] will be rendered using /// the [Canvas.drawImageRect] method instead. class SpriteBatch { @@ -147,14 +147,14 @@ class SpriteBatch { Vector2 get size => atlas.size; /// Whether to use [Canvas.drawAtlas] or not. - final bool drawAtlas; + final bool useAtlas; SpriteBatch( this.atlas, { this.defaultColor = const Color(0x00000000), this.defaultBlendMode = BlendMode.srcOver, this.defaultTransform, - this.drawAtlas = true, + this.useAtlas = true, }); /// Takes a path of an image, and optional arguments for the SpriteBatch. @@ -166,7 +166,7 @@ class SpriteBatch { BlendMode defaultBlendMode = BlendMode.srcOver, RSTransform? defaultTransform, Images? images, - bool drawAtlas = true, + bool useAtlas = true, }) async { final _images = images ?? Flame.images; return SpriteBatch( @@ -174,7 +174,7 @@ class SpriteBatch { defaultColor: defaultColor, defaultTransform: defaultTransform ?? RSTransform(1, 0, 0, 0), defaultBlendMode: defaultBlendMode, - drawAtlas: drawAtlas, + useAtlas: useAtlas, ); } @@ -280,7 +280,7 @@ class SpriteBatch { }) { paint ??= _emptyPaint; - if (!drawAtlas) { + if (!useAtlas) { for (final batchItem in _batchItems) { paint.blendMode = blendMode ?? paint.blendMode; From 5f4caa7c42ba15235c7d0a7564c42139b7e5d857 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Tue, 7 Dec 2021 15:34:53 +0100 Subject: [PATCH 6/6] Update changelog entry --- packages/flame/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flame/CHANGELOG.md b/packages/flame/CHANGELOG.md index ea557d55969..0e4faa6121c 100644 --- a/packages/flame/CHANGELOG.md +++ b/packages/flame/CHANGELOG.md @@ -12,7 +12,7 @@ - `isHud` renamed to `respectCamera` - Fix `HitboxCircle` when component is flipped - `ScaleEffect.by` now applies multiplicatively instead of additively - - Remove fallback to not use `drawAtlas` in SpriteBatch, but added flag `useAtlas` to activate it + - Remove web fallback for `drawAtlas` in SpriteBatch, but added flag `useAtlas` to activate it ## [1.0.0-releasecandidate.18] - Forcing portrait and landscape mode is now supported on web