diff --git a/examples/export/runtimes.sh b/examples/export/runtimes.sh index 72885bb39..71294a77d 100755 --- a/examples/export/runtimes.sh +++ b/examples/export/runtimes.sh @@ -95,10 +95,16 @@ cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-flutter/example/assets/" cp -f ../spineboy/export/spineboy-pro.skel "$ROOT/spine-flutter/example/assets/" cp -f ../spineboy/export/spineboy.atlas "$ROOT/spine-flutter/example/assets/" cp -f ../spineboy/export/spineboy.png "$ROOT/spine-flutter/example/assets/" + cp -f ../mix-and-match/export/mix-and-match-pro.skel "$ROOT/spine-flutter/example/assets/" cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-flutter/example/assets/" cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-flutter/example/assets/" +cp -f ../dragon/export/dragon-ess.skel "$ROOT/spine-flutter/example/assets/" +cp -f ../dragon/export/dragon.atlas "$ROOT/spine-flutter/example/assets/" +cp -f ../dragon/export/dragon.png "$ROOT/spine-flutter/example/assets/" +cp -f ../dragon/export/dragon_*.png "$ROOT/spine-flutter/example/assets/" + echo "spine-godot" rm -f "$ROOT"/spine-godot/example/assets/spineboy/*.atlas rm -f "$ROOT"/spine-godot/example/assets/spineboy/*.png diff --git a/spine-flutter/example/assets/dragon-ess.skel b/spine-flutter/example/assets/dragon-ess.skel new file mode 100644 index 000000000..27e251df1 Binary files /dev/null and b/spine-flutter/example/assets/dragon-ess.skel differ diff --git a/spine-flutter/example/assets/dragon.atlas b/spine-flutter/example/assets/dragon.atlas new file mode 100644 index 000000000..bca5b1e1b --- /dev/null +++ b/spine-flutter/example/assets/dragon.atlas @@ -0,0 +1,123 @@ +dragon.png + size: 1024, 1024 + filter: Linear, Linear +back + bounds: 564, 534, 190, 185 +chest + bounds: 2, 645, 136, 122 +chin + bounds: 140, 619, 214, 146 +front-toe-a + bounds: 2, 862, 29, 50 + rotate: 90 +front-toe-b + bounds: 467, 835, 56, 57 + rotate: 90 +head + bounds: 756, 398, 296, 260 + rotate: 90 +left-front-leg + bounds: 599, 834, 84, 57 +left-front-thigh + bounds: 782, 819, 84, 72 +left-rear-leg + bounds: 356, 558, 206, 177 +left-rear-thigh + bounds: 216, 767, 91, 149 + rotate: 90 +left-wing01 + bounds: 2, 268, 264, 589 + rotate: 90 +left-wing02 + bounds: 2, 2, 264, 589 + rotate: 90 +right-front-leg + bounds: 113, 769, 101, 89 +right-front-thigh + bounds: 758, 709, 108, 108 +right-rear-leg + bounds: 640, 721, 116, 100 +right-rear-thigh + bounds: 367, 742, 91, 149 + rotate: 90 +right-rear-toe + bounds: 2, 781, 109, 77 +tail01 + bounds: 868, 696, 120, 153 + rotate: 90 +tail02 + bounds: 518, 737, 95, 120 + rotate: 90 +tail03 + bounds: 868, 818, 73, 92 + rotate: 90 +tail04 + bounds: 526, 835, 56, 71 + rotate: 90 +tail05 + bounds: 406, 839, 52, 59 + rotate: 90 +tail06 + bounds: 685, 823, 95, 68 +thiagobrayner + bounds: 54, 860, 350, 31 + +dragon_2.png + size: 1024, 1024 + filter: Linear, Linear +left-wing03 + bounds: 2, 534, 264, 589 + rotate: 90 +left-wing04 + bounds: 2, 268, 264, 589 + rotate: 90 +left-wing05 + bounds: 593, 209, 264, 589 +left-wing06 + bounds: 2, 2, 264, 589 + rotate: 90 + +dragon_3.png + size: 1024, 1024 + filter: Linear, Linear +left-wing07 + bounds: 2, 694, 264, 589 + rotate: 90 +left-wing08 + bounds: 2, 428, 264, 589 + rotate: 90 +left-wing09 + bounds: 593, 369, 264, 589 +right-wing01 + bounds: 2, 2, 365, 643 + rotate: 90 + +dragon_4.png + size: 1024, 1024 + filter: Linear, Linear +right-wing02 + bounds: 2, 369, 365, 643 +right-wing03 + bounds: 369, 369, 365, 643 +right-wing04 + bounds: 2, 2, 365, 643 + rotate: 90 + +dragon_5.png + size: 1024, 1024 + filter: Linear, Linear +right-wing05 + bounds: 2, 369, 365, 643 +right-wing06 + bounds: 369, 369, 365, 643 +right-wing07 + bounds: 2, 2, 365, 643 + rotate: 90 + +dragon_6.png + size: 1024, 1024 + filter: Linear, Linear +right-wing08 + bounds: 2, 2, 365, 643 +right-wing09 + bounds: 369, 2, 365, 643 diff --git a/spine-flutter/example/assets/dragon.png b/spine-flutter/example/assets/dragon.png new file mode 100644 index 000000000..f39141c47 Binary files /dev/null and b/spine-flutter/example/assets/dragon.png differ diff --git a/spine-flutter/example/assets/dragon_2.png b/spine-flutter/example/assets/dragon_2.png new file mode 100644 index 000000000..09429b5f8 Binary files /dev/null and b/spine-flutter/example/assets/dragon_2.png differ diff --git a/spine-flutter/example/assets/dragon_3.png b/spine-flutter/example/assets/dragon_3.png new file mode 100644 index 000000000..647bcb73b Binary files /dev/null and b/spine-flutter/example/assets/dragon_3.png differ diff --git a/spine-flutter/example/assets/dragon_4.png b/spine-flutter/example/assets/dragon_4.png new file mode 100644 index 000000000..8de760989 Binary files /dev/null and b/spine-flutter/example/assets/dragon_4.png differ diff --git a/spine-flutter/example/assets/dragon_5.png b/spine-flutter/example/assets/dragon_5.png new file mode 100644 index 000000000..5a98f7efa Binary files /dev/null and b/spine-flutter/example/assets/dragon_5.png differ diff --git a/spine-flutter/example/assets/dragon_6.png b/spine-flutter/example/assets/dragon_6.png new file mode 100644 index 000000000..49a39f648 Binary files /dev/null and b/spine-flutter/example/assets/dragon_6.png differ diff --git a/spine-flutter/example/lib/dress_up.dart b/spine-flutter/example/lib/dress_up.dart index e225d084d..9ae0b842f 100644 --- a/spine-flutter/example/lib/dress_up.dart +++ b/spine-flutter/example/lib/dress_up.dart @@ -107,7 +107,7 @@ class DressUpState extends State { ), ), Expanded( - child: SpineWidget.drawable(_drawable, _controller, boundsProvider: SkinAndAnimationBounds(["full-skins/girl"]),) + child: SpineWidget.drawable(_drawable, _controller, boundsProvider: SkinAndAnimationBounds(skins: ["full-skins/girl"]),) ) ] ) diff --git a/spine-flutter/example/lib/pause_play_animation.dart b/spine-flutter/example/lib/pause_play_animation.dart index 9173a51a7..38c158d82 100644 --- a/spine-flutter/example/lib/pause_play_animation.dart +++ b/spine-flutter/example/lib/pause_play_animation.dart @@ -16,7 +16,7 @@ class PlayPauseAnimationState extends State { void initState() { super.initState(); controller = SpineWidgetController(onInitialized: (controller) { - controller.animationState.setAnimationByName(0, "walk", true); + controller.animationState.setAnimationByName(0, "flying", true); }); isPlaying = true; } @@ -33,7 +33,7 @@ class PlayPauseAnimationState extends State { return Scaffold( appBar: AppBar(title: const Text('Play/Pause')), - body: SpineWidget.asset("assets/spineboy.atlas", "assets/spineboy-pro.skel", controller), + body: SpineWidget.asset("assets/dragon.atlas", "assets/dragon-ess.skel", controller, boundsProvider: SkinAndAnimationBounds(animation: "flying"),), floatingActionButton: FloatingActionButton( onPressed: _togglePlay, child: Icon(isPlaying ? Icons.pause : Icons.play_arrow), diff --git a/spine-flutter/example/lib/skins.dart b/spine-flutter/example/lib/skins.dart index d1f5ae576..53920819b 100644 --- a/spine-flutter/example/lib/skins.dart +++ b/spine-flutter/example/lib/skins.dart @@ -70,7 +70,7 @@ class SkinsState extends State { ) ), Expanded( - child: SpineWidget.drawable(_drawable, _controller, boundsProvider: SkinAndAnimationBounds(["full-skins/girl"])) + child: SpineWidget.drawable(_drawable, _controller, boundsProvider: SkinAndAnimationBounds(skins: ["full-skins/girl"])) ) ] ) diff --git a/spine-flutter/lib/spine_widget.dart b/spine-flutter/lib/spine_widget.dart index 821542a48..1ac5b0654 100644 --- a/spine-flutter/lib/spine_widget.dart +++ b/spine-flutter/lib/spine_widget.dart @@ -97,33 +97,54 @@ class RawBounds extends BoundsProvider { } class SkinAndAnimationBounds extends BoundsProvider { - final List _skins; - final String? _animation; + final List skins; + final String? animation; + final double stepTime; - SkinAndAnimationBounds(this._skins, [this._animation]); + SkinAndAnimationBounds({List? skins, this.animation, this.stepTime = 0.1}) : + skins = skins == null || skins.isEmpty? ["default"] : skins; @override Bounds computeBounds(SkeletonDrawable drawable) { var data = drawable.skeletonData; - var oldSkin = drawable.skeleton.getSkin(); var customSkin = Skin("custom-skin"); - for (var skinName in _skins) { + for (var skinName in skins) { var skin = data.findSkin(skinName); if (skin == null) continue; customSkin.addSkin(skin); } drawable.skeleton.setSkin(customSkin); drawable.skeleton.setToSetupPose(); - var bounds = drawable.skeleton.getBounds(); - customSkin.dispose(); - if (oldSkin == null) { - drawable.skeleton.setSkinByName(""); + final animation = data.findAnimation(this.animation!); + double minX = double.infinity; + double minY = double.infinity; + double maxX = double.negativeInfinity; + double maxY = double.negativeInfinity; + if (animation == null) { + final bounds = drawable.skeleton.getBounds(); + minX = bounds.x; + minY = bounds.y; + maxX = minX + bounds.width; + maxY = minY + bounds.height; } else { - drawable.skeleton.setSkin(oldSkin); + drawable.animationState.setAnimation(0, animation, false); + final steps = max(animation.getDuration() / stepTime, 1.0).toInt(); + for (int i = 0; i < steps; i++) { + drawable.update(i > 0 ? stepTime : 0); + final bounds = drawable.skeleton.getBounds(); + minX = min(minX, bounds.x); + minY = min(minY, bounds.y); + maxX = max(maxX, minX + bounds.width); + maxY = max(maxY, minY + bounds.height); + } } + customSkin.dispose(); + drawable.skeleton.setSkinByName("default"); + drawable.animationState.clearTracks(); drawable.skeleton.setToSetupPose(); - return bounds; + drawable.update(0); + return Bounds(minX, minY, maxX - minX, maxY - minY); } } @@ -189,6 +210,7 @@ class SpineWidget extends StatefulWidget { } class _SpineWidgetState extends State { + late Bounds _computedBounds; @override void initState() { @@ -201,6 +223,7 @@ class _SpineWidgetState extends State { } void loadDrawable(SkeletonDrawable drawable) { + _computedBounds = widget._boundsProvider.computeBounds(drawable); widget._controller._initialize(drawable); setState(() {}); } @@ -224,7 +247,7 @@ class _SpineWidgetState extends State { @override Widget build(BuildContext context) { if (widget._controller._drawable != null) { - return _SpineRenderObjectWidget(widget._controller._drawable!, widget._controller, widget._fit, widget._alignment, widget._boundsProvider, widget._sizedByBounds); + return _SpineRenderObjectWidget(widget._controller._drawable!, widget._controller, widget._fit, widget._alignment, _computedBounds, widget._sizedByBounds); } else { return const SizedBox(); } @@ -242,14 +265,14 @@ class _SpineRenderObjectWidget extends LeafRenderObjectWidget { final SpineWidgetController _controller; final BoxFit _fit; final Alignment _alignment; - final BoundsProvider _boundsProvider; + final Bounds _bounds; final bool _sizedByBounds; - const _SpineRenderObjectWidget(this._skeletonDrawable, this._controller, this._fit, this._alignment, this._boundsProvider, this._sizedByBounds); + const _SpineRenderObjectWidget(this._skeletonDrawable, this._controller, this._fit, this._alignment, this._bounds, this._sizedByBounds); @override RenderObject createRenderObject(BuildContext context) { - return _SpineRenderObject(_skeletonDrawable, _controller, _fit, _alignment, _boundsProvider, _sizedByBounds); + return _SpineRenderObject(_skeletonDrawable, _controller, _fit, _alignment, _bounds, _sizedByBounds); } @override @@ -257,7 +280,7 @@ class _SpineRenderObjectWidget extends LeafRenderObjectWidget { renderObject.skeletonDrawable = _skeletonDrawable; renderObject.fit = _fit; renderObject.alignment = _alignment; - renderObject.boundsProvider = _boundsProvider; + renderObject.bounds = _bounds; renderObject.sizedByBounds = _sizedByBounds; } } @@ -269,16 +292,14 @@ class _SpineRenderObject extends RenderBox { final Stopwatch _stopwatch = Stopwatch(); BoxFit _fit; Alignment _alignment; - BoundsProvider _boundsProvider; - bool _sizedByBounds; Bounds _bounds; - _SpineRenderObject(this._skeletonDrawable, this._controller, this._fit, this._alignment, this._boundsProvider, this._sizedByBounds): _bounds = _boundsProvider.computeBounds(_skeletonDrawable); + bool _sizedByBounds; + _SpineRenderObject(this._skeletonDrawable, this._controller, this._fit, this._alignment, this._bounds, this._sizedByBounds); set skeletonDrawable(SkeletonDrawable skeletonDrawable) { if (_skeletonDrawable == skeletonDrawable) return; _skeletonDrawable = skeletonDrawable; - _bounds = _boundsProvider.computeBounds(_skeletonDrawable); markNeedsLayout(); markNeedsPaint(); } @@ -303,12 +324,11 @@ class _SpineRenderObject extends RenderBox { } } - BoundsProvider get boundsProvider => _boundsProvider; + Bounds get bounds => _bounds; - set boundsProvider(BoundsProvider boundsProvider) { - if (boundsProvider != _boundsProvider) { - _boundsProvider = boundsProvider; - _bounds = boundsProvider.computeBounds(_skeletonDrawable); + set bounds(Bounds bounds) { + if (bounds != _bounds) { + _bounds = bounds; markNeedsLayout(); markNeedsPaint(); } diff --git a/spine-flutter/src/main.cpp b/spine-flutter/src/main.cpp index 311fbe988..170a9e0b4 100644 --- a/spine-flutter/src/main.cpp +++ b/spine-flutter/src/main.cpp @@ -3,48 +3,81 @@ using namespace spine; +String blendMode(spine_blend_mode mode) { + switch(mode) { + case SPINE_BLEND_MODE_NORMAL: + return "normal"; + case SPINE_BLEND_MODE_ADDITIVE: + return "additiev"; + case SPINE_BLEND_MODE_MULTIPLY: + return "multiply"; + case SPINE_BLEND_MODE_SCREEN: + return "screen"; + } +} + int main(int argc, char** argv) { int atlasLength = 0; - void* atlasData = SpineExtension::getInstance()->_readFile("/Users/badlogic/workspaces/spine-runtimes/spine-flutter/example/assets/spineboy.atlas", &atlasLength); + void* atlasData = SpineExtension::getInstance()->_readFile("/Users/badlogic/workspaces/spine-runtimes/spine-flutter/example/assets/dragon.atlas", &atlasLength); uint8_t* cstringAtlas = SpineExtension::calloc(atlasLength + 1, __FILE__, __LINE__); memcpy(cstringAtlas, atlasData, atlasLength); int dataLength = 0; - uint8_t* data = (uint8_t*)SpineExtension::getInstance()->_readFile("/Users/badlogic/workspaces/spine-runtimes/spine-flutter/example/assets/spineboy-pro.skel", &dataLength); + uint8_t* data = (uint8_t*)SpineExtension::getInstance()->_readFile("/Users/badlogic/workspaces/spine-runtimes/spine-flutter/example/assets/dragon-ess.skel", &dataLength); spine_atlas atlas = spine_atlas_load((const utf8*)cstringAtlas); + Vector atlasPages; + for (int i = 0, n = spine_atlas_get_num_image_paths(atlas); i < n; i++) { + atlasPages.add(spine_atlas_get_image_path(atlas, i)); + } + spine_skeleton_data_result result = spine_skeleton_data_load_binary(atlas, data, dataLength); spine_skeleton_drawable drawable = spine_skeleton_drawable_create(spine_skeleton_data_result_get_data(result)); spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable); spine_skeleton_update_world_transform(skeleton); spine_render_command cmd = spine_skeleton_drawable_render(drawable); - int numVertices = spine_render_command_get_num_vertices(cmd); - int numIndices = spine_render_command_get_num_indices(cmd); - float* positions = spine_render_command_get_positions(cmd); - float* uvs = spine_render_command_get_uvs(cmd); - int32_t *colors = spine_render_command_get_colors(cmd); - uint16_t *indices = spine_render_command_get_indices(cmd); - String str; - str.append(numVertices); - str.append("\n"); - str.append(numIndices); - str.append("\n"); - for (int i = 0; i < numVertices * 2; i++) { - str.append(positions[i]); + + int batchId = 0; + while(cmd) { + int numVertices = spine_render_command_get_num_vertices(cmd); + int numIndices = spine_render_command_get_num_indices(cmd); + float *positions = spine_render_command_get_positions(cmd); + float *uvs = spine_render_command_get_uvs(cmd); + int32_t *colors = spine_render_command_get_colors(cmd); + uint16_t *indices = spine_render_command_get_indices(cmd); + String str; + int atlasPage = spine_render_command_get_atlas_page(cmd); + str.append(atlasPages[atlasPage]); str.append("\n"); - } - for (int i = 0; i < numVertices * 2; i++) { - str.append(uvs[i]); + str.append(blendMode(spine_render_command_get_blend_mode(cmd))); str.append("\n"); - } - for (int i = 0; i < numVertices; i++) { - str.append(colors[i]); + str.append(numVertices); str.append("\n"); - } - for (int i = 0; i < numIndices; i++) { - str.append(indices[i]); + str.append(numIndices); str.append("\n"); + for (int i = 0; i < numVertices * 2; i++) { + str.append(positions[i]); + str.append("\n"); + } + for (int i = 0; i < numVertices * 2; i++) { + str.append(uvs[i]); + str.append("\n"); + } + for (int i = 0; i < numVertices; i++) { + str.append(colors[i]); + str.append("\n"); + } + for (int i = 0; i < numIndices; i++) { + str.append(indices[i]); + str.append("\n"); + } + String outputFile = ""; + outputFile.append("/Users/badlogic/Desktop/dragon-"); + outputFile.append(batchId); + outputFile.append(".mesh"); + FILE *file = fopen(outputFile.buffer(), "w"); + fwrite(str.buffer(), str.length(), 1, file); + fclose(file); + batchId++; + cmd = spine_render_command_get_next(cmd); } - FILE *file = fopen("/Users/badlogic/Desktop/spineboy.mesh", "w"); - fwrite(str.buffer(), str.length(), 1, file); - fclose(file); } \ No newline at end of file diff --git a/spine-flutter/src/spine_flutter.cpp b/spine-flutter/src/spine_flutter.cpp index 4e772c55b..c19cd37ba 100644 --- a/spine-flutter/src/spine_flutter.cpp +++ b/spine-flutter/src/spine_flutter.cpp @@ -657,7 +657,7 @@ void spine_skeleton_drawable_dispose(spine_skeleton_drawable drawable) { } static _spine_render_command *batch_sub_commands(BlockAllocator &allocator, Vector<_spine_render_command*> &commands, int first, int last, int numVertices, int numIndices) { - _spine_render_command *batched = spine_render_command_create(allocator, numVertices, numIndices, commands[0]->blendMode, commands[0]->atlasPage); + _spine_render_command *batched = spine_render_command_create(allocator, numVertices, numIndices, commands[first]->blendMode, commands[first]->atlasPage); float *positions = batched->positions; float *uvs = batched->uvs; int32_t *colors = batched->colors;