[flutter] Implement blend modes, see #2200

This commit is contained in:
Mario Zechner 2023-03-06 11:43:14 +01:00
parent 2fc2e98c36
commit 714edf501c
4 changed files with 35 additions and 27 deletions

View File

@ -21,10 +21,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.0" version: "1.17.1"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
@ -98,10 +98,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.5" version: "0.6.7"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@ -122,10 +122,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.9.0"
ordered_set: ordered_set:
dependency: transitive dependency: transitive
description: description:
@ -169,7 +169,7 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "4.2.11" version: "4.2.12"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
@ -211,5 +211,5 @@ packages:
source: hosted source: hosted
version: "0.7.4" version: "0.7.4"
sdks: sdks:
dart: ">=2.18.0 <3.0.0" dart: ">=2.19.0 <4.0.0"
flutter: ">=3.7.3" flutter: ">=3.7.6"

View File

@ -102,7 +102,7 @@ class Vec2 {
class Atlas { class Atlas {
final spine_atlas _atlas; final spine_atlas _atlas;
final List<Image> atlasPages; final List<Image> atlasPages;
final List<Paint> atlasPagePaints; final List<Map<BlendMode, Paint>> atlasPagePaints;
bool _disposed; bool _disposed;
Atlas._(this._atlas, this.atlasPages, this.atlasPagePaints) : _disposed = false; Atlas._(this._atlas, this.atlasPages, this.atlasPagePaints) : _disposed = false;
@ -122,7 +122,7 @@ class Atlas {
final atlasDir = path.dirname(atlasFileName); final atlasDir = path.dirname(atlasFileName);
List<Image> atlasPages = []; List<Image> atlasPages = [];
List<Paint> atlasPagePaints = []; List<Map<BlendMode, Paint>> atlasPagePaints = [];
final numImagePaths = _bindings.spine_atlas_get_num_image_paths(atlas); final numImagePaths = _bindings.spine_atlas_get_num_image_paths(atlas);
for (int i = 0; i < numImagePaths; i++) { for (int i = 0; i < numImagePaths; i++) {
final Pointer<Utf8> atlasPageFile = _bindings.spine_atlas_get_image_path(atlas, i).cast(); final Pointer<Utf8> atlasPageFile = _bindings.spine_atlas_get_image_path(atlas, i).cast();
@ -132,9 +132,16 @@ class Atlas {
final FrameInfo frameInfo = await codec.getNextFrame(); final FrameInfo frameInfo = await codec.getNextFrame();
final Image image = frameInfo.image; final Image image = frameInfo.image;
atlasPages.add(image); atlasPages.add(image);
atlasPagePaints.add(Paint() Map<BlendMode, Paint> paints = {};
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage, filterQuality: FilterQuality.high) for (final blendMode in BlendMode.values) {
..isAntiAlias = true); paints[blendMode] = Paint()
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4
.identity()
.storage, filterQuality: FilterQuality.high)
..isAntiAlias = true
..blendMode = blendMode.canvasBlendMode;
}
atlasPagePaints.add(paints);
} }
return Atlas._(atlas, atlasPages, atlasPagePaints); return Atlas._(atlas, atlasPages, atlasPagePaints);
@ -540,14 +547,15 @@ class SkeletonData {
/// Determines how images are blended with existing pixels when drawn. See [Blending](http://esotericsoftware.com/spine-slots#Blending) in /// Determines how images are blended with existing pixels when drawn. See [Blending](http://esotericsoftware.com/spine-slots#Blending) in
/// the Spine User Guide. /// the Spine User Guide.
enum BlendMode { enum BlendMode {
normal(0), normal(0, rendering.BlendMode.srcOver),
additive(1), additive(1, rendering.BlendMode.plus),
multiply(2), multiply(2, rendering.BlendMode.modulate),
screen(3); screen(3, rendering.BlendMode.screen);
final int value; final int value;
final rendering.BlendMode canvasBlendMode;
const BlendMode(this.value); const BlendMode(this.value, this.canvasBlendMode);
} }
/// Determines how a bone inherits world transforms from parent bones. See [Transform inheritance](esotericsoftware.com/spine-bones#Transform-inheritance) /// Determines how a bone inherits world transforms from parent bones. See [Transform inheritance](esotericsoftware.com/spine-bones#Transform-inheritance)
@ -3968,11 +3976,12 @@ class SkeletonDrawable {
/// Renders the skeleton drawable's current pose to the given [canvas]. Does not perform any /// Renders the skeleton drawable's current pose to the given [canvas]. Does not perform any
/// scaling or fitting. /// scaling or fitting.
void renderToCanvas(Canvas canvas) { List<RenderCommand> renderToCanvas(Canvas canvas) {
var commands = render(); var commands = render();
for (final cmd in commands) { for (final cmd in commands) {
canvas.drawVertices(cmd.vertices, rendering.BlendMode.modulate, atlas.atlasPagePaints[cmd.atlasPageIndex]); canvas.drawVertices(cmd.vertices, rendering.BlendMode.modulate, atlas.atlasPagePaints[cmd.atlasPageIndex][cmd.blendMode]!);
} }
return commands;
} }
/// Renders the skeleton drawable's current pose to a [PictureRecorder] with the given [width] and [height]. /// Renders the skeleton drawable's current pose to a [PictureRecorder] with the given [width] and [height].
@ -4041,6 +4050,7 @@ class RenderCommand {
late final Float32List uvs; late final Float32List uvs;
late final Int32List colors; late final Int32List colors;
late final Uint16List indices; late final Uint16List indices;
late final BlendMode blendMode;
RenderCommand._(spine_render_command nativeCmd, double pageWidth, double pageHeight) { RenderCommand._(spine_render_command nativeCmd, double pageWidth, double pageHeight) {
atlasPageIndex = _bindings.spine_render_command_get_atlas_page(nativeCmd); atlasPageIndex = _bindings.spine_render_command_get_atlas_page(nativeCmd);
@ -4054,6 +4064,7 @@ class RenderCommand {
} }
colors = _bindings.spine_render_command_get_colors(nativeCmd).asTypedList(numVertices); colors = _bindings.spine_render_command_get_colors(nativeCmd).asTypedList(numVertices);
indices = _bindings.spine_render_command_get_indices(nativeCmd).asTypedList(numIndices); indices = _bindings.spine_render_command_get_indices(nativeCmd).asTypedList(numIndices);
blendMode = BlendMode.values[_bindings.spine_render_command_get_blend_mode(nativeCmd)];
if (!kIsWeb) { if (!kIsWeb) {
// We pass the native data as views directly to Vertices.raw. According to the sources, the data // We pass the native data as views directly to Vertices.raw. According to the sources, the data

View File

@ -670,10 +670,7 @@ class _SpineRenderObject extends RenderBox {
_setCanvasTransform(canvas, offset); _setCanvasTransform(canvas, offset);
_controller.onBeforePaint?.call(_controller, canvas); _controller.onBeforePaint?.call(_controller, canvas);
var commands = _skeletonDrawable.render(); final commands = _skeletonDrawable.renderToCanvas(canvas);
for (final cmd in commands) {
canvas.drawVertices(cmd.vertices, rendering.BlendMode.modulate, _skeletonDrawable.atlas.atlasPagePaints[cmd.atlasPageIndex]);
}
_controller.onAfterPaint?.call(_controller, canvas, commands); _controller.onAfterPaint?.call(_controller, canvas, commands);
canvas.restore(); canvas.restore();

View File

@ -1,6 +1,6 @@
name: spine_flutter name: spine_flutter
description: The official Spine Flutter Runtime to load, display and interact with Spine animations. description: The official Spine Flutter Runtime to load, display and interact with Spine animations.
version: 4.2.11 version: 4.2.12
homepage: https://esotericsoftware.com homepage: https://esotericsoftware.com
repository: https://github.com/esotericsoftware/spine-runtimes repository: https://github.com/esotericsoftware/spine-runtimes
issue_tracker: https://github.com/esotericsoftware/spine-runtimes/issues issue_tracker: https://github.com/esotericsoftware/spine-runtimes/issues
@ -8,7 +8,7 @@ documentation: https://esotericsoftware.com/spine-flutter
environment: environment:
sdk: ">=2.17.6 <3.0.0" sdk: ">=2.17.6 <3.0.0"
flutter: ">=3.7.3" flutter: ">=3.7.6"
dependencies: dependencies:
flutter: flutter: