mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-12 18:18:43 +08:00
[flutter] Use new loading infra from spine-c
This commit is contained in:
parent
da70193a36
commit
6ad01acc6a
@ -214,7 +214,7 @@ public:
|
||||
static CallbackTextureLoad callbackLoader;
|
||||
|
||||
spine_atlas_result spine_atlas_load_callback(const char *atlasData, const char *atlasDir, spine_texture_loader_load_func load,
|
||||
spine_texture_loader_unload_func unload) {
|
||||
spine_texture_loader_unload_func unload) {
|
||||
if (!atlasData) return nullptr;
|
||||
_spine_atlas_result *result = SpineExtension::calloc<_spine_atlas_result>(1, __FILE__, __LINE__);
|
||||
int32_t length = (int32_t) strlen(atlasData);
|
||||
|
||||
@ -76,7 +76,7 @@ SPINE_C_API float spine_vector_get_y(spine_vector vector);
|
||||
// Atlas functions
|
||||
SPINE_C_API spine_atlas_result spine_atlas_load(const char *atlasData);
|
||||
SPINE_C_API spine_atlas_result spine_atlas_load_callback(const char *atlasData, const char *atlasDir, spine_texture_loader_load_func load,
|
||||
spine_texture_loader_unload_func unload);
|
||||
spine_texture_loader_unload_func unload);
|
||||
SPINE_C_API const char *spine_atlas_result_get_error(spine_atlas_result result);
|
||||
SPINE_C_API spine_atlas spine_atlas_result_get_atlas(spine_atlas_result result);
|
||||
SPINE_C_API void spine_atlas_result_dispose(spine_atlas_result result);
|
||||
|
||||
@ -3,6 +3,10 @@
|
||||
|
||||
using namespace spine;
|
||||
|
||||
void spine_atlas_dispose(spine_atlas self) {
|
||||
delete (Atlas *) self;
|
||||
}
|
||||
|
||||
void spine_atlas_flip_v(spine_atlas self) {
|
||||
Atlas *_self = (Atlas *) self;
|
||||
_self->flipV();
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
SPINE_C_API void spine_atlas_dispose(spine_atlas self);
|
||||
|
||||
SPINE_C_API void spine_atlas_flip_v(spine_atlas self);
|
||||
SPINE_C_API spine_atlas_region spine_atlas_find_region(spine_atlas self, const char *name);
|
||||
SPINE_C_API spine_array_atlas_page spine_atlas_get_pages(spine_atlas self);
|
||||
|
||||
@ -197,7 +197,7 @@ namespace spine {
|
||||
DebugEntry *_head;
|
||||
size_t _size;
|
||||
};
|
||||
#endif // SPINE_NO_CPP_RT
|
||||
#endif// SPINE_NO_CPP_RT
|
||||
|
||||
class SP_API DebugExtension : public SpineExtension {
|
||||
struct Allocation {
|
||||
@ -225,7 +225,7 @@ namespace spine {
|
||||
printf("\"%s:%i (%zu bytes at %p)\n", pair.value.fileName, pair.value.line, pair.value.size, pair.value.address);
|
||||
}
|
||||
#else
|
||||
for (const auto& pair : _allocated) {
|
||||
for (const auto &pair : _allocated) {
|
||||
printf("\"%s:%i (%zu bytes at %p)\n", pair.second.fileName, pair.second.line, pair.second.size, pair.second.address);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -21,7 +21,7 @@ fi
|
||||
npx tsx codegen/src/index.ts
|
||||
|
||||
# Build test spine_flutter shared library
|
||||
pushd ../spine_flutter/test > /dev/null
|
||||
pushd test > /dev/null
|
||||
./build.sh
|
||||
popd
|
||||
|
||||
|
||||
@ -45,6 +45,10 @@ class Atlas {
|
||||
/// Get the native pointer for FFI calls
|
||||
Pointer get nativePtr => _ptr;
|
||||
|
||||
void dispose() {
|
||||
SpineBindings.bindings.spine_atlas_dispose(_ptr);
|
||||
}
|
||||
|
||||
void flipV() {
|
||||
SpineBindings.bindings.spine_atlas_flip_v(_ptr);
|
||||
}
|
||||
|
||||
@ -5867,6 +5867,18 @@ class SpineDartBindings {
|
||||
late final _spine_array_update_buffer =
|
||||
_spine_array_update_bufferPtr.asFunction<ffi.Pointer<spine_update> Function(spine_array_update)>();
|
||||
|
||||
void spine_atlas_dispose(
|
||||
spine_atlas self,
|
||||
) {
|
||||
return _spine_atlas_dispose(
|
||||
self,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_atlas_disposePtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(spine_atlas)>>('spine_atlas_dispose');
|
||||
late final _spine_atlas_dispose = _spine_atlas_disposePtr.asFunction<void Function(spine_atlas)>();
|
||||
|
||||
void spine_atlas_flip_v(
|
||||
spine_atlas self,
|
||||
) {
|
||||
@ -6557,7 +6569,7 @@ class SpineDartBindings {
|
||||
late final _spine_vector_get_y = _spine_vector_get_yPtr.asFunction<double Function(spine_vector)>();
|
||||
|
||||
/// Atlas functions
|
||||
spine_atlas spine_atlas_load(
|
||||
spine_atlas_result spine_atlas_load(
|
||||
ffi.Pointer<ffi.Char> atlasData,
|
||||
) {
|
||||
return _spine_atlas_load(
|
||||
@ -6566,10 +6578,10 @@ class SpineDartBindings {
|
||||
}
|
||||
|
||||
late final _spine_atlas_loadPtr =
|
||||
_lookup<ffi.NativeFunction<spine_atlas Function(ffi.Pointer<ffi.Char>)>>('spine_atlas_load');
|
||||
late final _spine_atlas_load = _spine_atlas_loadPtr.asFunction<spine_atlas Function(ffi.Pointer<ffi.Char>)>();
|
||||
_lookup<ffi.NativeFunction<spine_atlas_result Function(ffi.Pointer<ffi.Char>)>>('spine_atlas_load');
|
||||
late final _spine_atlas_load = _spine_atlas_loadPtr.asFunction<spine_atlas_result Function(ffi.Pointer<ffi.Char>)>();
|
||||
|
||||
spine_atlas spine_atlas_load_callback(
|
||||
spine_atlas_result spine_atlas_load_callback(
|
||||
ffi.Pointer<ffi.Char> atlasData,
|
||||
ffi.Pointer<ffi.Char> atlasDir,
|
||||
spine_texture_loader_load_func load,
|
||||
@ -6585,75 +6597,50 @@ class SpineDartBindings {
|
||||
|
||||
late final _spine_atlas_load_callbackPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
spine_atlas Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, spine_texture_loader_load_func,
|
||||
spine_atlas_result Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, spine_texture_loader_load_func,
|
||||
spine_texture_loader_unload_func)>>('spine_atlas_load_callback');
|
||||
late final _spine_atlas_load_callback = _spine_atlas_load_callbackPtr.asFunction<
|
||||
spine_atlas Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, spine_texture_loader_load_func,
|
||||
spine_atlas_result Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, spine_texture_loader_load_func,
|
||||
spine_texture_loader_unload_func)>();
|
||||
|
||||
int spine_atlas_get_num_image_paths(
|
||||
spine_atlas atlas,
|
||||
ffi.Pointer<ffi.Char> spine_atlas_result_get_error(
|
||||
spine_atlas_result result,
|
||||
) {
|
||||
return _spine_atlas_get_num_image_paths(
|
||||
atlas,
|
||||
return _spine_atlas_result_get_error(
|
||||
result,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_atlas_get_num_image_pathsPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Int32 Function(spine_atlas)>>('spine_atlas_get_num_image_paths');
|
||||
late final _spine_atlas_get_num_image_paths =
|
||||
_spine_atlas_get_num_image_pathsPtr.asFunction<int Function(spine_atlas)>();
|
||||
late final _spine_atlas_result_get_errorPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function(spine_atlas_result)>>('spine_atlas_result_get_error');
|
||||
late final _spine_atlas_result_get_error =
|
||||
_spine_atlas_result_get_errorPtr.asFunction<ffi.Pointer<ffi.Char> Function(spine_atlas_result)>();
|
||||
|
||||
ffi.Pointer<ffi.Char> spine_atlas_get_image_path(
|
||||
spine_atlas atlas,
|
||||
int index,
|
||||
spine_atlas spine_atlas_result_get_atlas(
|
||||
spine_atlas_result result,
|
||||
) {
|
||||
return _spine_atlas_get_image_path(
|
||||
atlas,
|
||||
index,
|
||||
return _spine_atlas_result_get_atlas(
|
||||
result,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_atlas_get_image_pathPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function(spine_atlas, ffi.Int32)>>('spine_atlas_get_image_path');
|
||||
late final _spine_atlas_get_image_path =
|
||||
_spine_atlas_get_image_pathPtr.asFunction<ffi.Pointer<ffi.Char> Function(spine_atlas, int)>();
|
||||
late final _spine_atlas_result_get_atlasPtr =
|
||||
_lookup<ffi.NativeFunction<spine_atlas Function(spine_atlas_result)>>('spine_atlas_result_get_atlas');
|
||||
late final _spine_atlas_result_get_atlas =
|
||||
_spine_atlas_result_get_atlasPtr.asFunction<spine_atlas Function(spine_atlas_result)>();
|
||||
|
||||
bool spine_atlas_is_pma(
|
||||
spine_atlas atlas,
|
||||
void spine_atlas_result_dispose(
|
||||
spine_atlas_result result,
|
||||
) {
|
||||
return _spine_atlas_is_pma(
|
||||
atlas,
|
||||
return _spine_atlas_result_dispose(
|
||||
result,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_atlas_is_pmaPtr = _lookup<ffi.NativeFunction<ffi.Bool Function(spine_atlas)>>('spine_atlas_is_pma');
|
||||
late final _spine_atlas_is_pma = _spine_atlas_is_pmaPtr.asFunction<bool Function(spine_atlas)>();
|
||||
|
||||
ffi.Pointer<ffi.Char> spine_atlas_get_error(
|
||||
spine_atlas atlas,
|
||||
) {
|
||||
return _spine_atlas_get_error(
|
||||
atlas,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_atlas_get_errorPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function(spine_atlas)>>('spine_atlas_get_error');
|
||||
late final _spine_atlas_get_error =
|
||||
_spine_atlas_get_errorPtr.asFunction<ffi.Pointer<ffi.Char> Function(spine_atlas)>();
|
||||
|
||||
void spine_atlas_dispose(
|
||||
spine_atlas atlas,
|
||||
) {
|
||||
return _spine_atlas_dispose(
|
||||
atlas,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_atlas_disposePtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(spine_atlas)>>('spine_atlas_dispose');
|
||||
late final _spine_atlas_dispose = _spine_atlas_disposePtr.asFunction<void Function(spine_atlas)>();
|
||||
late final _spine_atlas_result_disposePtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(spine_atlas_result)>>('spine_atlas_result_dispose');
|
||||
late final _spine_atlas_result_dispose =
|
||||
_spine_atlas_result_disposePtr.asFunction<void Function(spine_atlas_result)>();
|
||||
|
||||
/// Skeleton data functions
|
||||
spine_skeleton_data_result spine_skeleton_data_load_json(
|
||||
@ -40773,6 +40760,11 @@ typedef spine_update = ffi.Pointer<spine_update_wrapper>;
|
||||
typedef spine_atlas = ffi.Pointer<spine_atlas_wrapper>;
|
||||
typedef spine_skeleton_data = ffi.Pointer<spine_skeleton_data_wrapper>;
|
||||
|
||||
final class spine_atlas_result_wrapper extends ffi.Struct {
|
||||
@ffi.Char()
|
||||
external int _dummy;
|
||||
}
|
||||
|
||||
final class spine_skeleton_data_result_wrapper extends ffi.Struct {
|
||||
@ffi.Char()
|
||||
external int _dummy;
|
||||
@ -40815,6 +40807,7 @@ final class spine_texture_loader_wrapper extends ffi.Struct {
|
||||
|
||||
typedef spine_bounds = ffi.Pointer<spine_bounds_wrapper>;
|
||||
typedef spine_vector = ffi.Pointer<spine_vector_wrapper>;
|
||||
typedef spine_atlas_result = ffi.Pointer<spine_atlas_result_wrapper>;
|
||||
|
||||
/// Texture loader callbacks
|
||||
typedef spine_texture_loader_load_func = ffi.Pointer<ffi.NativeFunction<spine_texture_loader_load_funcFunction>>;
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'generated/atlas.dart';
|
||||
import 'generated/skeleton_data.dart';
|
||||
import 'spine_bindings.dart';
|
||||
|
||||
// Atlas Extensions
|
||||
extension AtlasExtensions on Atlas {
|
||||
/// Creates an Atlas from atlas data string (without loading images)
|
||||
static Atlas fromString(String atlasData) {
|
||||
final atlasDataNative = atlasData.toNativeUtf8();
|
||||
final atlasPtr = SpineBindings.bindings.spine_atlas_load(atlasDataNative.cast<Char>());
|
||||
malloc.free(atlasDataNative);
|
||||
return Atlas.fromPointer(atlasPtr);
|
||||
}
|
||||
|
||||
/// Dispose the atlas and free its memory
|
||||
void dispose() {
|
||||
SpineBindings.bindings.spine_atlas_dispose(nativePtr.cast());
|
||||
}
|
||||
}
|
||||
|
||||
// Skeleton Data Result wrapper
|
||||
class SkeletonDataResult {
|
||||
final String? error;
|
||||
final SkeletonData? skeletonData;
|
||||
final Pointer? _resultPtr;
|
||||
|
||||
SkeletonDataResult._(this.error, this.skeletonData, this._resultPtr);
|
||||
|
||||
void dispose() {
|
||||
if (_resultPtr != null) {
|
||||
SpineBindings.bindings.spine_skeleton_data_result_dispose(_resultPtr!.cast());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skeleton Data Extensions
|
||||
extension SkeletonDataExtensions on SkeletonData {
|
||||
/// Load skeleton data from JSON string
|
||||
static SkeletonData fromJson(Atlas atlas, String jsonData, {String? path}) {
|
||||
final jsonDataNative = jsonData.toNativeUtf8();
|
||||
final pathNative = (path ?? '').toNativeUtf8();
|
||||
|
||||
final resultPtr = SpineBindings.bindings
|
||||
.spine_skeleton_data_load_json(atlas.nativePtr.cast(), jsonDataNative.cast<Char>(), pathNative.cast<Char>());
|
||||
|
||||
malloc.free(jsonDataNative);
|
||||
malloc.free(pathNative);
|
||||
|
||||
// Check for error
|
||||
final errorPtr = SpineBindings.bindings.spine_skeleton_data_result_get_error(resultPtr.cast());
|
||||
if (errorPtr != nullptr) {
|
||||
final error = errorPtr.cast<Utf8>().toDartString();
|
||||
SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast());
|
||||
throw Exception("Couldn't load skeleton data: $error");
|
||||
}
|
||||
|
||||
// Get skeleton data
|
||||
final skeletonDataPtr = SpineBindings.bindings.spine_skeleton_data_result_get_data(resultPtr.cast());
|
||||
final skeletonData = SkeletonData.fromPointer(skeletonDataPtr);
|
||||
SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast());
|
||||
return skeletonData;
|
||||
}
|
||||
}
|
||||
@ -29,13 +29,15 @@ library;
|
||||
import 'generated/spine_dart_bindings_generated.dart';
|
||||
import 'spine_bindings.dart';
|
||||
import 'spine_dart_init.dart' if (dart.library.html) 'spine_flutter_init_web.dart';
|
||||
import 'dart:ffi';
|
||||
import 'dart:typed_data';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'generated/atlas.dart';
|
||||
import 'generated/skeleton_data.dart';
|
||||
|
||||
// Export generated classes
|
||||
export 'generated/spine_dart.dart';
|
||||
|
||||
// Export extensions
|
||||
export 'new_extensions.dart';
|
||||
|
||||
Future<void> initSpineFlutter({bool useStaticLinkage = false, bool enableMemoryDebugging = false}) async {
|
||||
final ffi = await initSpineDartFFI(useStaticLinkage);
|
||||
final bindings = SpineDartBindings(ffi.dylib);
|
||||
@ -52,3 +54,77 @@ int majorVersion() => SpineBindings.bindings.spine_major_version();
|
||||
int minorVersion() => SpineBindings.bindings.spine_minor_version();
|
||||
|
||||
void reportLeaks() => SpineBindings.bindings.spine_report_leaks();
|
||||
|
||||
/// Load an Atlas from atlas data string
|
||||
Atlas loadAtlas(String atlasData) {
|
||||
final atlasDataNative = atlasData.toNativeUtf8();
|
||||
final resultPtr = SpineBindings.bindings.spine_atlas_load(atlasDataNative.cast<Char>());
|
||||
malloc.free(atlasDataNative);
|
||||
|
||||
// Check for error
|
||||
final errorPtr = SpineBindings.bindings.spine_atlas_result_get_error(resultPtr.cast());
|
||||
if (errorPtr != nullptr) {
|
||||
final error = errorPtr.cast<Utf8>().toDartString();
|
||||
SpineBindings.bindings.spine_atlas_result_dispose(resultPtr.cast());
|
||||
throw Exception("Couldn't load atlas: $error");
|
||||
}
|
||||
|
||||
// Get atlas
|
||||
final atlasPtr = SpineBindings.bindings.spine_atlas_result_get_atlas(resultPtr.cast());
|
||||
final atlas = Atlas.fromPointer(atlasPtr);
|
||||
SpineBindings.bindings.spine_atlas_result_dispose(resultPtr.cast());
|
||||
return atlas;
|
||||
}
|
||||
|
||||
/// Load skeleton data from JSON string
|
||||
SkeletonData loadSkeletonDataJson(Atlas atlas, String jsonData, {String? path}) {
|
||||
final jsonDataNative = jsonData.toNativeUtf8();
|
||||
final pathNative = (path ?? '').toNativeUtf8();
|
||||
|
||||
final resultPtr = SpineBindings.bindings
|
||||
.spine_skeleton_data_load_json(atlas.nativePtr.cast(), jsonDataNative.cast<Char>(), pathNative.cast<Char>());
|
||||
|
||||
malloc.free(jsonDataNative);
|
||||
malloc.free(pathNative);
|
||||
|
||||
// Check for error
|
||||
final errorPtr = SpineBindings.bindings.spine_skeleton_data_result_get_error(resultPtr.cast());
|
||||
if (errorPtr != nullptr) {
|
||||
final error = errorPtr.cast<Utf8>().toDartString();
|
||||
SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast());
|
||||
throw Exception("Couldn't load skeleton data: $error");
|
||||
}
|
||||
|
||||
// Get skeleton data
|
||||
final skeletonDataPtr = SpineBindings.bindings.spine_skeleton_data_result_get_data(resultPtr.cast());
|
||||
final skeletonData = SkeletonData.fromPointer(skeletonDataPtr);
|
||||
SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast());
|
||||
return skeletonData;
|
||||
}
|
||||
|
||||
/// Load skeleton data from binary data
|
||||
SkeletonData loadSkeletonDataBinary(Atlas atlas, Uint8List binaryData, {String? path}) {
|
||||
final Pointer<Uint8> binaryNative = malloc.allocate(binaryData.lengthInBytes);
|
||||
binaryNative.asTypedList(binaryData.lengthInBytes).setAll(0, binaryData);
|
||||
final pathNative = (path ?? '').toNativeUtf8();
|
||||
|
||||
final resultPtr = SpineBindings.bindings.spine_skeleton_data_load_binary(
|
||||
atlas.nativePtr.cast(), binaryNative.cast(), binaryData.lengthInBytes, pathNative.cast<Char>());
|
||||
|
||||
malloc.free(binaryNative);
|
||||
malloc.free(pathNative);
|
||||
|
||||
// Check for error
|
||||
final errorPtr = SpineBindings.bindings.spine_skeleton_data_result_get_error(resultPtr.cast());
|
||||
if (errorPtr != nullptr) {
|
||||
final error = errorPtr.cast<Utf8>().toDartString();
|
||||
SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast());
|
||||
throw Exception("Couldn't load skeleton data: $error");
|
||||
}
|
||||
|
||||
// Get skeleton data
|
||||
final skeletonDataPtr = SpineBindings.bindings.spine_skeleton_data_result_get_data(resultPtr.cast());
|
||||
final skeletonData = SkeletonData.fromPointer(skeletonDataPtr);
|
||||
SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast());
|
||||
return skeletonData;
|
||||
}
|
||||
|
||||
@ -5,18 +5,18 @@ void main() async {
|
||||
print('Testing atlas and skeleton data loading...');
|
||||
|
||||
// Initialize with debug extension enabled
|
||||
await initSpineFlutter(enableMemoryDebugging: false);
|
||||
await initSpineFlutter(enableMemoryDebugging: true);
|
||||
|
||||
// Load atlas
|
||||
final atlasData = File('../example/assets/spineboy.atlas').readAsStringSync();
|
||||
final atlas = AtlasExtensions.fromString(atlasData);
|
||||
final atlas = loadAtlas(atlasData);
|
||||
|
||||
print('Atlas loaded successfully');
|
||||
print('Number of regions: ${atlas.regions.length}');
|
||||
|
||||
// Load skeleton data
|
||||
final skeletonJson = File('../example/assets/spineboy-pro.json').readAsStringSync();
|
||||
final skeletonData = SkeletonDataExtensions.fromJson(atlas, skeletonJson);
|
||||
final skeletonData = loadSkeletonDataJson(atlas, skeletonJson);
|
||||
|
||||
print('Skeleton data loaded successfully');
|
||||
print('Number of bones: ${skeletonData.bones.length}');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user