mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 17:26:01 +08:00
[flutter] Proper disposal of native resources.
This commit is contained in:
parent
ac03e51d0b
commit
2438f0c39e
@ -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()
|
||||
));
|
||||
}
|
||||
|
||||
@ -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<spine_atlas> _atlas;
|
||||
List<Image> atlasPages;
|
||||
List<Paint> atlasPagePaints;
|
||||
bool _disposed;
|
||||
|
||||
SpineAtlas(this._atlas, this.atlasPages, this.atlasPagePaints);
|
||||
SpineAtlas(this._atlas, this.atlasPages, this.atlasPagePaints): _disposed = false;
|
||||
|
||||
static Future<SpineAtlas> 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<spine_skeleton_data> _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<spine_skeleton_drawable> _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<SpineRenderCommand> render() {
|
||||
if (_disposed) return [];
|
||||
Pointer<spine_render_command> nativeCmd = _bindings.spine_skeleton_drawable_render(_drawable);
|
||||
List<SpineRenderCommand> 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 {
|
||||
|
||||
@ -44,6 +44,15 @@ class SpineFlutterBindings {
|
||||
late final _spine_minor_version =
|
||||
_spine_minor_versionPtr.asFunction<int Function()>();
|
||||
|
||||
void spine_report_leaks() {
|
||||
return _spine_report_leaks();
|
||||
}
|
||||
|
||||
late final _spine_report_leaksPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function()>>('spine_report_leaks');
|
||||
late final _spine_report_leaks =
|
||||
_spine_report_leaksPtr.asFunction<void Function()>();
|
||||
|
||||
ffi.Pointer<spine_atlas> spine_atlas_load(
|
||||
ffi.Pointer<ffi.Int8> atlasData,
|
||||
) {
|
||||
@ -254,5 +263,7 @@ class spine_skeleton_drawable extends ffi.Struct {
|
||||
|
||||
external ffi.Pointer<ffi.Void> animationState;
|
||||
|
||||
external ffi.Pointer<ffi.Void> clipping;
|
||||
|
||||
external ffi.Pointer<spine_render_command> renderCommand;
|
||||
}
|
||||
|
||||
@ -47,6 +47,12 @@ class _SpineWidgetState extends State<SpineWidget> {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "spine_flutter.h"
|
||||
#include <spine/spine.h>
|
||||
#include <spine/Version.h>
|
||||
#include <spine/Debug.h>
|
||||
|
||||
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<spine_skeleton_drawable>(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<spine_render_command>(1, __FILE__, __LINE__);
|
||||
cmd->positions = SpineExtension::alloc<float>(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<spine_skeleton_drawable>(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());
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user