diff --git a/spine-flutter/example/lib/main.dart b/spine-flutter/example/lib/main.dart index 466ad2a09..7fdd8b288 100644 --- a/spine-flutter/example/lib/main.dart +++ b/spine-flutter/example/lib/main.dart @@ -5,7 +5,6 @@ class ExampleSelector extends StatelessWidget { @override Widget build(BuildContext context) { const spacer = SizedBox(height: 10); - return Scaffold( appBar: AppBar(title: const Text('Spine Examples')), body: Center( @@ -48,6 +47,6 @@ class Spineboy extends StatelessWidget { void main() { runApp(MaterialApp( title: "Spine Examples", - home: Spineboy() + home: ExampleSelector() )); } diff --git a/spine-flutter/lib/spine_flutter.dart b/spine-flutter/lib/spine_flutter.dart index 36d6e339d..7499ddd57 100644 --- a/spine-flutter/lib/spine_flutter.dart +++ b/spine-flutter/lib/spine_flutter.dart @@ -12,13 +12,15 @@ import 'package:path/path.dart' as Path; int majorVersion() => _bindings.spine_major_version(); int minorVersion() => _bindings.spine_minor_version(); +void reportLeaks() => _bindings.spine_report_leaks(); class SpineAtlas { Pointer _atlas; List atlasPages; List atlasPagePaints; + bool _disposed; - SpineAtlas(this._atlas, this.atlasPages, this.atlasPagePaints); + SpineAtlas(this._atlas, this.atlasPages, this.atlasPagePaints): _disposed = false; static Future fromAsset(AssetBundle assetBundle, String atlasFileName) async { final atlasData = await assetBundle.loadString(atlasFileName); @@ -51,12 +53,20 @@ class SpineAtlas { return SpineAtlas(atlas, atlasPages, atlasPagePaints); } + + void dispose() { + if (_disposed) return; + _disposed = true; + _bindings.spine_atlas_dispose(this._atlas); + for (final image in atlasPages) image.dispose(); + } } class SpineSkeletonData { Pointer _skeletonData; + bool _disposed; - SpineSkeletonData(this._skeletonData); + SpineSkeletonData(this._skeletonData): _disposed = false; static SpineSkeletonData fromJson(SpineAtlas atlas, String json) { final jsonNative = json.toNativeUtf8(); @@ -83,22 +93,31 @@ class SpineSkeletonData { } return SpineSkeletonData(skeletonData); } + + void dispose() { + if (_disposed) return; + _disposed = true; + _bindings.spine_skeleton_data_dispose(this._skeletonData); + } } class SpineSkeletonDrawable { SpineAtlas atlas; SpineSkeletonData skeletonData; late Pointer _drawable; + bool _disposed; - SpineSkeletonDrawable(this.atlas, this.skeletonData) { + SpineSkeletonDrawable(this.atlas, this.skeletonData): _disposed = false { _drawable = _bindings.spine_skeleton_drawable_create(skeletonData._skeletonData); } void update(double delta) { + if (_disposed) return; _bindings.spine_skeleton_drawable_update(_drawable, delta); } List render() { + if (_disposed) return []; Pointer nativeCmd = _bindings.spine_skeleton_drawable_render(_drawable); List commands = []; while(nativeCmd.address != nullptr.address) { @@ -108,6 +127,14 @@ class SpineSkeletonDrawable { } return commands; } + + void dispose() { + if (_disposed) return; + _disposed = true; + atlas.dispose(); + skeletonData.dispose(); + _bindings.spine_skeleton_drawable_dispose(_drawable); + } } class SpineRenderCommand { diff --git a/spine-flutter/lib/spine_flutter_bindings_generated.dart b/spine-flutter/lib/spine_flutter_bindings_generated.dart index fea84fb18..285053f2f 100644 --- a/spine-flutter/lib/spine_flutter_bindings_generated.dart +++ b/spine-flutter/lib/spine_flutter_bindings_generated.dart @@ -44,6 +44,15 @@ class SpineFlutterBindings { late final _spine_minor_version = _spine_minor_versionPtr.asFunction(); + void spine_report_leaks() { + return _spine_report_leaks(); + } + + late final _spine_report_leaksPtr = + _lookup>('spine_report_leaks'); + late final _spine_report_leaks = + _spine_report_leaksPtr.asFunction(); + ffi.Pointer spine_atlas_load( ffi.Pointer atlasData, ) { @@ -254,5 +263,7 @@ class spine_skeleton_drawable extends ffi.Struct { external ffi.Pointer animationState; + external ffi.Pointer clipping; + external ffi.Pointer renderCommand; } diff --git a/spine-flutter/lib/spine_widget.dart b/spine-flutter/lib/spine_widget.dart index 06a0443b4..7d6c4b004 100644 --- a/spine-flutter/lib/spine_widget.dart +++ b/spine-flutter/lib/spine_widget.dart @@ -47,6 +47,12 @@ class _SpineWidgetState extends State { return SizedBox(); } } + + @override + void dispose() { + skeletonDrawable?.dispose(); + super.dispose(); + } } class _SpineRenderObjectWidget extends LeafRenderObjectWidget { @@ -76,7 +82,6 @@ class _SpineRenderObject extends RenderBox { set skeletonDrawable(SpineSkeletonDrawable skeletonDrawable) { if (_skeletonDrawable == skeletonDrawable) return; - // FIXME dispose old drawable here? _skeletonDrawable = skeletonDrawable; markNeedsPaint(); } diff --git a/spine-flutter/src/CMakeLists.txt b/spine-flutter/src/CMakeLists.txt index bf3dec3a6..d6e5384e2 100644 --- a/spine-flutter/src/CMakeLists.txt +++ b/spine-flutter/src/CMakeLists.txt @@ -18,6 +18,4 @@ set_target_properties(spine_flutter PROPERTIES ) target_include_directories(spine_flutter PUBLIC spine-cpp/include) target_compile_definitions(spine_flutter PUBLIC DART_SHARED_LIB) -#target_compile_options(spine_flutter PUBLIC -fsanitize=address -fno-omit-frame-pointer) -#set_target_properties(spine_flutter PROPERTIES LINK_FLAGS -fsanitize=address) diff --git a/spine-flutter/src/spine_flutter.cpp b/spine-flutter/src/spine_flutter.cpp index 6806a2d3c..8131a393a 100644 --- a/spine-flutter/src/spine_flutter.cpp +++ b/spine-flutter/src/spine_flutter.cpp @@ -1,6 +1,7 @@ #include "spine_flutter.h" #include #include +#include using namespace spine; @@ -26,6 +27,10 @@ FFI_PLUGIN_EXPORT spine_atlas* spine_atlas_load(const char *atlasData) { return result; } +void spine_report_leaks() { + ((DebugExtension*)spine::SpineExtension::getInstance())->reportLeaks(); +} + FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas) { if (!atlas) return; if (atlas->atlas) delete (Atlas*)atlas->atlas; @@ -33,6 +38,7 @@ FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas) { for (int i = 0; i < atlas->numImagePaths; i++) { free(atlas->imagePaths[i]); } + SpineExtension::free(atlas->imagePaths, __FILE__, __LINE__); SpineExtension::free(atlas, __FILE__, __LINE__); } @@ -74,27 +80,6 @@ FFI_PLUGIN_EXPORT void spine_skeleton_data_dispose(spine_skeleton_data *skeleton SpineExtension::free(skeletonData, __FILE__, __LINE__); } -FFI_PLUGIN_EXPORT spine_skeleton_drawable *spine_skeleton_drawable_create(spine_skeleton_data *skeletonData) { - spine_skeleton_drawable *drawable = SpineExtension::calloc(1, __FILE__, __LINE__); - drawable->skeleton = new Skeleton((SkeletonData*)skeletonData->skeletonData); - drawable->animationState = new AnimationState(new AnimationStateData((SkeletonData*)skeletonData->skeletonData)); - drawable->clipping = new SkeletonClipping(); - return drawable; -} - -FFI_PLUGIN_EXPORT void spine_skeleton_drawable_update(spine_skeleton_drawable *drawable, float deltaTime) { - if (!drawable) return; - if (!drawable->skeleton) return; - if (!drawable->animationState) return; - if (!drawable->clipping) return; - - Skeleton *skeleton = (Skeleton*)drawable->skeleton; - AnimationState *animationState = (AnimationState*)drawable->animationState; - animationState->update(deltaTime); - animationState->apply(*skeleton); - skeleton->updateWorldTransform(); -} - spine_render_command *spine_render_command_create(int32_t numVertices, int32_t numIndices, spine_blend_mode blendMode, int pageIndex) { spine_render_command *cmd = SpineExtension::alloc(1, __FILE__, __LINE__); cmd->positions = SpineExtension::alloc(numVertices << 1, __FILE__, __LINE__); @@ -118,6 +103,44 @@ void spine_render_command_dispose(spine_render_command *cmd) { SpineExtension::free(cmd, __FILE__, __LINE__); } +FFI_PLUGIN_EXPORT spine_skeleton_drawable *spine_skeleton_drawable_create(spine_skeleton_data *skeletonData) { + spine_skeleton_drawable *drawable = SpineExtension::calloc(1, __FILE__, __LINE__); + drawable->skeleton = new Skeleton((SkeletonData*)skeletonData->skeletonData); + drawable->animationState = new AnimationState(new AnimationStateData((SkeletonData*)skeletonData->skeletonData)); + drawable->clipping = new SkeletonClipping(); + return drawable; +} + +FFI_PLUGIN_EXPORT void spine_skeleton_drawable_dispose(spine_skeleton_drawable *drawable) { + if (!drawable) return; + if (drawable->skeleton) delete (Skeleton*)drawable->skeleton; + if (drawable->animationState) { + AnimationState *state = (AnimationState*)drawable->animationState; + delete state->getData(); + delete (AnimationState*)state; + } + if (drawable->clipping) delete (SkeletonClipping*)drawable->clipping; + while (drawable->renderCommand) { + spine_render_command *cmd = drawable->renderCommand; + drawable->renderCommand = cmd->next; + spine_render_command_dispose(cmd); + } + SpineExtension::free(drawable, __FILE__, __LINE__); +} + +FFI_PLUGIN_EXPORT void spine_skeleton_drawable_update(spine_skeleton_drawable *drawable, float deltaTime) { + if (!drawable) return; + if (!drawable->skeleton) return; + if (!drawable->animationState) return; + if (!drawable->clipping) return; + + Skeleton *skeleton = (Skeleton*)drawable->skeleton; + AnimationState *animationState = (AnimationState*)drawable->animationState; + animationState->update(deltaTime); + animationState->apply(*skeleton); + skeleton->updateWorldTransform(); +} + FFI_PLUGIN_EXPORT spine_render_command *spine_skeleton_drawable_render(spine_skeleton_drawable *drawable) { if (!drawable) return nullptr; if (!drawable->skeleton) return nullptr; @@ -238,19 +261,6 @@ FFI_PLUGIN_EXPORT spine_render_command *spine_skeleton_drawable_render(spine_ske return drawable->renderCommand; } -FFI_PLUGIN_EXPORT void spine_skeleton_drawable_dispose(spine_skeleton_drawable *drawable) { - if (!drawable) return; - if (drawable->skeleton) delete (Skeleton*)drawable->skeleton; - if (drawable->animationState) delete (AnimationState*)drawable->animationState; - if (drawable->clipping) delete (SkeletonClipping*)drawable->clipping; - while (drawable->renderCommand) { - spine_render_command *cmd = drawable->renderCommand; - drawable->renderCommand = cmd->next; - spine_render_command_dispose(cmd); - } - SpineExtension::free(drawable, __FILE__, __LINE__); -} - spine::SpineExtension *spine::getDefaultExtension() { - return new spine::DefaultSpineExtension(); + return new spine::DebugExtension(new spine::DefaultSpineExtension()); } diff --git a/spine-flutter/src/spine_flutter.h b/spine-flutter/src/spine_flutter.h index 3fdb7bdfc..1e7fcbb34 100644 --- a/spine-flutter/src/spine_flutter.h +++ b/spine-flutter/src/spine_flutter.h @@ -25,6 +25,7 @@ FFI_PLUGIN_EXPORT int32_t spine_major_version(); FFI_PLUGIN_EXPORT int32_t spine_minor_version(); +FFI_PLUGIN_EXPORT void spine_report_leaks(); typedef struct spine_atlas { void *atlas;