mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const spacer = SizedBox(height: 10);
|
const spacer = SizedBox(height: 10);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Spine Examples')),
|
appBar: AppBar(title: const Text('Spine Examples')),
|
||||||
body: Center(
|
body: Center(
|
||||||
@ -48,6 +47,6 @@ class Spineboy extends StatelessWidget {
|
|||||||
void main() {
|
void main() {
|
||||||
runApp(MaterialApp(
|
runApp(MaterialApp(
|
||||||
title: "Spine Examples",
|
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 majorVersion() => _bindings.spine_major_version();
|
||||||
int minorVersion() => _bindings.spine_minor_version();
|
int minorVersion() => _bindings.spine_minor_version();
|
||||||
|
void reportLeaks() => _bindings.spine_report_leaks();
|
||||||
|
|
||||||
class SpineAtlas {
|
class SpineAtlas {
|
||||||
Pointer<spine_atlas> _atlas;
|
Pointer<spine_atlas> _atlas;
|
||||||
List<Image> atlasPages;
|
List<Image> atlasPages;
|
||||||
List<Paint> atlasPagePaints;
|
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 {
|
static Future<SpineAtlas> fromAsset(AssetBundle assetBundle, String atlasFileName) async {
|
||||||
final atlasData = await assetBundle.loadString(atlasFileName);
|
final atlasData = await assetBundle.loadString(atlasFileName);
|
||||||
@ -51,12 +53,20 @@ class SpineAtlas {
|
|||||||
|
|
||||||
return SpineAtlas(atlas, atlasPages, atlasPagePaints);
|
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 {
|
class SpineSkeletonData {
|
||||||
Pointer<spine_skeleton_data> _skeletonData;
|
Pointer<spine_skeleton_data> _skeletonData;
|
||||||
|
bool _disposed;
|
||||||
|
|
||||||
SpineSkeletonData(this._skeletonData);
|
SpineSkeletonData(this._skeletonData): _disposed = false;
|
||||||
|
|
||||||
static SpineSkeletonData fromJson(SpineAtlas atlas, String json) {
|
static SpineSkeletonData fromJson(SpineAtlas atlas, String json) {
|
||||||
final jsonNative = json.toNativeUtf8();
|
final jsonNative = json.toNativeUtf8();
|
||||||
@ -83,22 +93,31 @@ class SpineSkeletonData {
|
|||||||
}
|
}
|
||||||
return SpineSkeletonData(skeletonData);
|
return SpineSkeletonData(skeletonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
if (_disposed) return;
|
||||||
|
_disposed = true;
|
||||||
|
_bindings.spine_skeleton_data_dispose(this._skeletonData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpineSkeletonDrawable {
|
class SpineSkeletonDrawable {
|
||||||
SpineAtlas atlas;
|
SpineAtlas atlas;
|
||||||
SpineSkeletonData skeletonData;
|
SpineSkeletonData skeletonData;
|
||||||
late Pointer<spine_skeleton_drawable> _drawable;
|
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);
|
_drawable = _bindings.spine_skeleton_drawable_create(skeletonData._skeletonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(double delta) {
|
void update(double delta) {
|
||||||
|
if (_disposed) return;
|
||||||
_bindings.spine_skeleton_drawable_update(_drawable, delta);
|
_bindings.spine_skeleton_drawable_update(_drawable, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SpineRenderCommand> render() {
|
List<SpineRenderCommand> render() {
|
||||||
|
if (_disposed) return [];
|
||||||
Pointer<spine_render_command> nativeCmd = _bindings.spine_skeleton_drawable_render(_drawable);
|
Pointer<spine_render_command> nativeCmd = _bindings.spine_skeleton_drawable_render(_drawable);
|
||||||
List<SpineRenderCommand> commands = [];
|
List<SpineRenderCommand> commands = [];
|
||||||
while(nativeCmd.address != nullptr.address) {
|
while(nativeCmd.address != nullptr.address) {
|
||||||
@ -108,6 +127,14 @@ class SpineSkeletonDrawable {
|
|||||||
}
|
}
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
if (_disposed) return;
|
||||||
|
_disposed = true;
|
||||||
|
atlas.dispose();
|
||||||
|
skeletonData.dispose();
|
||||||
|
_bindings.spine_skeleton_drawable_dispose(_drawable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpineRenderCommand {
|
class SpineRenderCommand {
|
||||||
|
|||||||
@ -44,6 +44,15 @@ class SpineFlutterBindings {
|
|||||||
late final _spine_minor_version =
|
late final _spine_minor_version =
|
||||||
_spine_minor_versionPtr.asFunction<int Function()>();
|
_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<spine_atlas> spine_atlas_load(
|
||||||
ffi.Pointer<ffi.Int8> atlasData,
|
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> animationState;
|
||||||
|
|
||||||
|
external ffi.Pointer<ffi.Void> clipping;
|
||||||
|
|
||||||
external ffi.Pointer<spine_render_command> renderCommand;
|
external ffi.Pointer<spine_render_command> renderCommand;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,12 @@ class _SpineWidgetState extends State<SpineWidget> {
|
|||||||
return SizedBox();
|
return SizedBox();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
skeletonDrawable?.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SpineRenderObjectWidget extends LeafRenderObjectWidget {
|
class _SpineRenderObjectWidget extends LeafRenderObjectWidget {
|
||||||
@ -76,7 +82,6 @@ class _SpineRenderObject extends RenderBox {
|
|||||||
set skeletonDrawable(SpineSkeletonDrawable skeletonDrawable) {
|
set skeletonDrawable(SpineSkeletonDrawable skeletonDrawable) {
|
||||||
if (_skeletonDrawable == skeletonDrawable) return;
|
if (_skeletonDrawable == skeletonDrawable) return;
|
||||||
|
|
||||||
// FIXME dispose old drawable here?
|
|
||||||
_skeletonDrawable = skeletonDrawable;
|
_skeletonDrawable = skeletonDrawable;
|
||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,4 @@ set_target_properties(spine_flutter PROPERTIES
|
|||||||
)
|
)
|
||||||
target_include_directories(spine_flutter PUBLIC spine-cpp/include)
|
target_include_directories(spine_flutter PUBLIC spine-cpp/include)
|
||||||
target_compile_definitions(spine_flutter PUBLIC DART_SHARED_LIB)
|
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_flutter.h"
|
||||||
#include <spine/spine.h>
|
#include <spine/spine.h>
|
||||||
#include <spine/Version.h>
|
#include <spine/Version.h>
|
||||||
|
#include <spine/Debug.h>
|
||||||
|
|
||||||
using namespace spine;
|
using namespace spine;
|
||||||
|
|
||||||
@ -26,6 +27,10 @@ FFI_PLUGIN_EXPORT spine_atlas* spine_atlas_load(const char *atlasData) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void spine_report_leaks() {
|
||||||
|
((DebugExtension*)spine::SpineExtension::getInstance())->reportLeaks();
|
||||||
|
}
|
||||||
|
|
||||||
FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas) {
|
FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas) {
|
||||||
if (!atlas) return;
|
if (!atlas) return;
|
||||||
if (atlas->atlas) delete (Atlas*)atlas->atlas;
|
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++) {
|
for (int i = 0; i < atlas->numImagePaths; i++) {
|
||||||
free(atlas->imagePaths[i]);
|
free(atlas->imagePaths[i]);
|
||||||
}
|
}
|
||||||
|
SpineExtension::free(atlas->imagePaths, __FILE__, __LINE__);
|
||||||
SpineExtension::free(atlas, __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__);
|
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 *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__);
|
spine_render_command *cmd = SpineExtension::alloc<spine_render_command>(1, __FILE__, __LINE__);
|
||||||
cmd->positions = SpineExtension::alloc<float>(numVertices << 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__);
|
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) {
|
FFI_PLUGIN_EXPORT spine_render_command *spine_skeleton_drawable_render(spine_skeleton_drawable *drawable) {
|
||||||
if (!drawable) return nullptr;
|
if (!drawable) return nullptr;
|
||||||
if (!drawable->skeleton) 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;
|
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() {
|
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_major_version();
|
||||||
FFI_PLUGIN_EXPORT int32_t spine_minor_version();
|
FFI_PLUGIN_EXPORT int32_t spine_minor_version();
|
||||||
|
FFI_PLUGIN_EXPORT void spine_report_leaks();
|
||||||
|
|
||||||
typedef struct spine_atlas {
|
typedef struct spine_atlas {
|
||||||
void *atlas;
|
void *atlas;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user