From 714edf501cb9d2b8b08f9b116dc408a53f1cd63a Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Mon, 6 Mar 2023 11:43:14 +0100 Subject: [PATCH] [flutter] Implement blend modes, see #2200 --- spine-flutter/example/pubspec.lock | 18 +++++++------- spine-flutter/lib/spine_flutter.dart | 35 ++++++++++++++++++---------- spine-flutter/lib/spine_widget.dart | 5 +--- spine-flutter/pubspec.yaml | 4 ++-- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/spine-flutter/example/pubspec.lock b/spine-flutter/example/pubspec.lock index 88b012f80..394459f77 100644 --- a/spine-flutter/example/pubspec.lock +++ b/spine-flutter/example/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" crypto: dependency: transitive description: @@ -98,10 +98,10 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: @@ -122,10 +122,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.0" ordered_set: dependency: transitive description: @@ -169,7 +169,7 @@ packages: path: ".." relative: true source: path - version: "4.2.11" + version: "4.2.12" string_scanner: dependency: transitive description: @@ -211,5 +211,5 @@ packages: source: hosted version: "0.7.4" sdks: - dart: ">=2.18.0 <3.0.0" - flutter: ">=3.7.3" + dart: ">=2.19.0 <4.0.0" + flutter: ">=3.7.6" diff --git a/spine-flutter/lib/spine_flutter.dart b/spine-flutter/lib/spine_flutter.dart index 6a053a31a..00699148b 100644 --- a/spine-flutter/lib/spine_flutter.dart +++ b/spine-flutter/lib/spine_flutter.dart @@ -102,7 +102,7 @@ class Vec2 { class Atlas { final spine_atlas _atlas; final List atlasPages; - final List atlasPagePaints; + final List> atlasPagePaints; bool _disposed; Atlas._(this._atlas, this.atlasPages, this.atlasPagePaints) : _disposed = false; @@ -122,7 +122,7 @@ class Atlas { final atlasDir = path.dirname(atlasFileName); List atlasPages = []; - List atlasPagePaints = []; + List> atlasPagePaints = []; final numImagePaths = _bindings.spine_atlas_get_num_image_paths(atlas); for (int i = 0; i < numImagePaths; i++) { final Pointer atlasPageFile = _bindings.spine_atlas_get_image_path(atlas, i).cast(); @@ -132,9 +132,16 @@ class Atlas { final FrameInfo frameInfo = await codec.getNextFrame(); final Image image = frameInfo.image; atlasPages.add(image); - atlasPagePaints.add(Paint() - ..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage, filterQuality: FilterQuality.high) - ..isAntiAlias = true); + Map paints = {}; + for (final blendMode in BlendMode.values) { + 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); @@ -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 /// the Spine User Guide. enum BlendMode { - normal(0), - additive(1), - multiply(2), - screen(3); + normal(0, rendering.BlendMode.srcOver), + additive(1, rendering.BlendMode.plus), + multiply(2, rendering.BlendMode.modulate), + screen(3, rendering.BlendMode.screen); 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) @@ -3968,11 +3976,12 @@ class SkeletonDrawable { /// Renders the skeleton drawable's current pose to the given [canvas]. Does not perform any /// scaling or fitting. - void renderToCanvas(Canvas canvas) { + List renderToCanvas(Canvas canvas) { var commands = render(); 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]. @@ -4041,6 +4050,7 @@ class RenderCommand { late final Float32List uvs; late final Int32List colors; late final Uint16List indices; + late final BlendMode blendMode; RenderCommand._(spine_render_command nativeCmd, double pageWidth, double pageHeight) { 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); indices = _bindings.spine_render_command_get_indices(nativeCmd).asTypedList(numIndices); + blendMode = BlendMode.values[_bindings.spine_render_command_get_blend_mode(nativeCmd)]; if (!kIsWeb) { // We pass the native data as views directly to Vertices.raw. According to the sources, the data diff --git a/spine-flutter/lib/spine_widget.dart b/spine-flutter/lib/spine_widget.dart index b28b10eba..7e67f403a 100644 --- a/spine-flutter/lib/spine_widget.dart +++ b/spine-flutter/lib/spine_widget.dart @@ -670,10 +670,7 @@ class _SpineRenderObject extends RenderBox { _setCanvasTransform(canvas, offset); _controller.onBeforePaint?.call(_controller, canvas); - var commands = _skeletonDrawable.render(); - for (final cmd in commands) { - canvas.drawVertices(cmd.vertices, rendering.BlendMode.modulate, _skeletonDrawable.atlas.atlasPagePaints[cmd.atlasPageIndex]); - } + final commands = _skeletonDrawable.renderToCanvas(canvas); _controller.onAfterPaint?.call(_controller, canvas, commands); canvas.restore(); diff --git a/spine-flutter/pubspec.yaml b/spine-flutter/pubspec.yaml index 38066e1d9..015f9ec4b 100644 --- a/spine-flutter/pubspec.yaml +++ b/spine-flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: spine_flutter 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 repository: https://github.com/esotericsoftware/spine-runtimes issue_tracker: https://github.com/esotericsoftware/spine-runtimes/issues @@ -8,7 +8,7 @@ documentation: https://esotericsoftware.com/spine-flutter environment: sdk: ">=2.17.6 <3.0.0" - flutter: ">=3.7.3" + flutter: ">=3.7.6" dependencies: flutter: