[flutter] Skin.getEntries() extension

This commit is contained in:
Mario Zechner 2025-07-29 22:19:04 +02:00
parent fd939f4401
commit 001f4d384f
3 changed files with 119 additions and 93 deletions

View File

@ -6494,80 +6494,6 @@ class SpineDartBindings {
late final _spine_report_leaksPtr = _lookup<ffi.NativeFunction<ffi.Void Function()>>('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()>(); late final _spine_report_leaks = _spine_report_leaksPtr.asFunction<void Function()>();
/// Bounds functions
double spine_bounds_get_x(
spine_bounds bounds,
) {
return _spine_bounds_get_x(
bounds,
);
}
late final _spine_bounds_get_xPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(spine_bounds)>>('spine_bounds_get_x');
late final _spine_bounds_get_x = _spine_bounds_get_xPtr.asFunction<double Function(spine_bounds)>();
double spine_bounds_get_y(
spine_bounds bounds,
) {
return _spine_bounds_get_y(
bounds,
);
}
late final _spine_bounds_get_yPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(spine_bounds)>>('spine_bounds_get_y');
late final _spine_bounds_get_y = _spine_bounds_get_yPtr.asFunction<double Function(spine_bounds)>();
double spine_bounds_get_width(
spine_bounds bounds,
) {
return _spine_bounds_get_width(
bounds,
);
}
late final _spine_bounds_get_widthPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(spine_bounds)>>('spine_bounds_get_width');
late final _spine_bounds_get_width = _spine_bounds_get_widthPtr.asFunction<double Function(spine_bounds)>();
double spine_bounds_get_height(
spine_bounds bounds,
) {
return _spine_bounds_get_height(
bounds,
);
}
late final _spine_bounds_get_heightPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(spine_bounds)>>('spine_bounds_get_height');
late final _spine_bounds_get_height = _spine_bounds_get_heightPtr.asFunction<double Function(spine_bounds)>();
/// Vector functions
double spine_vector_get_x(
spine_vector vector,
) {
return _spine_vector_get_x(
vector,
);
}
late final _spine_vector_get_xPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(spine_vector)>>('spine_vector_get_x');
late final _spine_vector_get_x = _spine_vector_get_xPtr.asFunction<double Function(spine_vector)>();
double spine_vector_get_y(
spine_vector vector,
) {
return _spine_vector_get_y(
vector,
);
}
late final _spine_vector_get_yPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(spine_vector)>>('spine_vector_get_y');
late final _spine_vector_get_y = _spine_vector_get_yPtr.asFunction<double Function(spine_vector)>();
/// Atlas functions /// Atlas functions
spine_atlas_result spine_atlas_load( spine_atlas_result spine_atlas_load(
ffi.Pointer<ffi.Char> atlasData, ffi.Pointer<ffi.Char> atlasData,
@ -6724,7 +6650,7 @@ class SpineDartBindings {
late final _spine_skeleton_data_result_dispose = late final _spine_skeleton_data_result_dispose =
_spine_skeleton_data_result_disposePtr.asFunction<void Function(spine_skeleton_data_result)>(); _spine_skeleton_data_result_disposePtr.asFunction<void Function(spine_skeleton_data_result)>();
/// Skeleton drawable functions /// Skeleton drawable functionsp
spine_skeleton_drawable spine_skeleton_drawable_create( spine_skeleton_drawable spine_skeleton_drawable_create(
spine_skeleton_data skeletonData, spine_skeleton_data skeletonData,
) { ) {
@ -6823,15 +6749,20 @@ class SpineDartBindings {
_spine_skeleton_drawable_get_animation_state_eventsPtr _spine_skeleton_drawable_get_animation_state_eventsPtr
.asFunction<spine_animation_state_events Function(spine_skeleton_drawable)>(); .asFunction<spine_animation_state_events Function(spine_skeleton_drawable)>();
/// Skin entries functions /// Skin functions
spine_skin_entries spine_skin_entries_create() { spine_skin_entries spine_skin_get_entries(
return _spine_skin_entries_create(); spine_skin skin,
) {
return _spine_skin_get_entries(
skin,
);
} }
late final _spine_skin_entries_createPtr = late final _spine_skin_get_entriesPtr =
_lookup<ffi.NativeFunction<spine_skin_entries Function()>>('spine_skin_entries_create'); _lookup<ffi.NativeFunction<spine_skin_entries Function(spine_skin)>>('spine_skin_get_entries');
late final _spine_skin_entries_create = _spine_skin_entries_createPtr.asFunction<spine_skin_entries Function()>(); late final _spine_skin_get_entries = _spine_skin_get_entriesPtr.asFunction<spine_skin_entries Function(spine_skin)>();
/// Skin entries functions
void spine_skin_entries_dispose( void spine_skin_entries_dispose(
spine_skin_entries entries, spine_skin_entries entries,
) { ) {
@ -40752,16 +40683,6 @@ final class spine_skeleton_data_result_wrapper extends ffi.Struct {
external int _dummy; external int _dummy;
} }
final class spine_bounds_wrapper extends ffi.Struct {
@ffi.Char()
external int _dummy;
}
final class spine_vector_wrapper extends ffi.Struct {
@ffi.Char()
external int _dummy;
}
final class spine_skeleton_drawable_wrapper extends ffi.Struct { final class spine_skeleton_drawable_wrapper extends ffi.Struct {
@ffi.Char() @ffi.Char()
external int _dummy; external int _dummy;
@ -40787,8 +40708,6 @@ final class spine_texture_loader_wrapper extends ffi.Struct {
external int _dummy; external int _dummy;
} }
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>; typedef spine_atlas_result = ffi.Pointer<spine_atlas_result_wrapper>;
/// Texture loader callbacks /// Texture loader callbacks

View File

@ -34,6 +34,15 @@ import 'dart:typed_data';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'generated/atlas.dart'; import 'generated/atlas.dart';
import 'generated/skeleton_data.dart'; import 'generated/skeleton_data.dart';
import 'generated/skin.dart';
import 'generated/attachment.dart';
import 'generated/region_attachment.dart';
import 'generated/mesh_attachment.dart';
import 'generated/bounding_box_attachment.dart';
import 'generated/clipping_attachment.dart';
import 'generated/path_attachment.dart';
import 'generated/point_attachment.dart';
import 'generated/rtti.dart';
// Export generated classes // Export generated classes
export 'generated/api.dart'; export 'generated/api.dart';
@ -130,3 +139,77 @@ SkeletonData loadSkeletonDataBinary(Atlas atlas, Uint8List binaryData, {String?
SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast()); SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast());
return skeletonData; return skeletonData;
} }
/// Represents an entry in a skin
class SkinEntry {
final int slotIndex;
final String name;
final Attachment? attachment;
SkinEntry._({required this.slotIndex, required this.name, required this.attachment});
}
/// Extension method for Skin to get all entries
extension SkinExtensions on Skin {
/// Get all entries (slot/attachment pairs) in this skin
List<SkinEntry> getEntries() {
final entriesPtr = SpineBindings.bindings.spine_skin_get_entries(nativePtr.cast());
if (entriesPtr == nullptr) return [];
try {
final numEntries = SpineBindings.bindings.spine_skin_entries_get_num_entries(entriesPtr.cast());
final entries = <SkinEntry>[];
for (int i = 0; i < numEntries; i++) {
final entryPtr = SpineBindings.bindings.spine_skin_entries_get_entry(entriesPtr.cast(), i);
if (entryPtr != nullptr) {
final slotIndex = SpineBindings.bindings.spine_skin_entry_get_slot_index(entryPtr.cast());
final namePtr = SpineBindings.bindings.spine_skin_entry_get_name(entryPtr.cast());
final name = namePtr.cast<Utf8>().toDartString();
final attachmentPtr = SpineBindings.bindings.spine_skin_entry_get_attachment(entryPtr.cast());
Attachment? attachment;
if (attachmentPtr.address != 0) {
// Use RTTI to determine the concrete attachment type
final rtti = SpineBindings.bindings.spine_attachment_get_rtti(attachmentPtr);
final className = SpineBindings.bindings.spine_rtti_get_class_name(rtti).cast<Utf8>().toDartString();
switch (className) {
case 'spine_region_attachment':
attachment = RegionAttachment.fromPointer(attachmentPtr.cast());
break;
case 'spine_mesh_attachment':
attachment = MeshAttachment.fromPointer(attachmentPtr.cast());
break;
case 'spine_bounding_box_attachment':
attachment = BoundingBoxAttachment.fromPointer(attachmentPtr.cast());
break;
case 'spine_clipping_attachment':
attachment = ClippingAttachment.fromPointer(attachmentPtr.cast());
break;
case 'spine_path_attachment':
attachment = PathAttachment.fromPointer(attachmentPtr.cast());
break;
case 'spine_point_attachment':
attachment = PointAttachment.fromPointer(attachmentPtr.cast());
break;
default:
// Unknown attachment type, treat as generic Attachment
attachment = null;
}
}
entries.add(SkinEntry._(
slotIndex: slotIndex,
name: name,
attachment: attachment,
));
}
}
return entries;
} finally {
SpineBindings.bindings.spine_skin_entries_dispose(entriesPtr.cast());
}
}
}

View File

@ -27,6 +27,30 @@ void main() async {
print('Skeleton created successfully'); print('Skeleton created successfully');
print('Skeleton has ${skeleton.slots.length} slots and ${skeleton.bones.length} bones'); print('Skeleton has ${skeleton.slots.length} slots and ${skeleton.bones.length} bones');
// Test skin entries
print('\nTesting skin entries...');
final defaultSkin = skeletonData.defaultSkin;
if (defaultSkin != null) {
final entries = defaultSkin.getEntries();
print('Default skin has ${entries.length} entries');
// Print first few entries
for (int i = 0; i < 5 && i < entries.length; i++) {
final entry = entries[i];
print(' Entry $i: slot=${entry.slotIndex}, name="${entry.name}", attachment=${entry.attachment?.runtimeType}');
}
}
// Test named skins
print('\nChecking named skins...');
for (int i = 0; i < skeletonData.skins.length; i++) {
final skin = skeletonData.skins[i];
if (skin != null) {
final entries = skin.getEntries();
print('Skin "${skin.name}" has ${entries.length} entries');
}
}
// Cleanup // Cleanup
skeleton.dispose(); skeleton.dispose();
skeletonData.dispose(); skeletonData.dispose();