diff --git a/spine-flutter/lib/generated/spine_dart_bindings_generated.dart b/spine-flutter/lib/generated/spine_dart_bindings_generated.dart index e5b8f1cc1..02a7cecd6 100644 --- a/spine-flutter/lib/generated/spine_dart_bindings_generated.dart +++ b/spine-flutter/lib/generated/spine_dart_bindings_generated.dart @@ -6494,80 +6494,6 @@ class SpineDartBindings { late final _spine_report_leaksPtr = _lookup>('spine_report_leaks'); late final _spine_report_leaks = _spine_report_leaksPtr.asFunction(); - /// Bounds functions - double spine_bounds_get_x( - spine_bounds bounds, - ) { - return _spine_bounds_get_x( - bounds, - ); - } - - late final _spine_bounds_get_xPtr = - _lookup>('spine_bounds_get_x'); - late final _spine_bounds_get_x = _spine_bounds_get_xPtr.asFunction(); - - double spine_bounds_get_y( - spine_bounds bounds, - ) { - return _spine_bounds_get_y( - bounds, - ); - } - - late final _spine_bounds_get_yPtr = - _lookup>('spine_bounds_get_y'); - late final _spine_bounds_get_y = _spine_bounds_get_yPtr.asFunction(); - - double spine_bounds_get_width( - spine_bounds bounds, - ) { - return _spine_bounds_get_width( - bounds, - ); - } - - late final _spine_bounds_get_widthPtr = - _lookup>('spine_bounds_get_width'); - late final _spine_bounds_get_width = _spine_bounds_get_widthPtr.asFunction(); - - double spine_bounds_get_height( - spine_bounds bounds, - ) { - return _spine_bounds_get_height( - bounds, - ); - } - - late final _spine_bounds_get_heightPtr = - _lookup>('spine_bounds_get_height'); - late final _spine_bounds_get_height = _spine_bounds_get_heightPtr.asFunction(); - - /// Vector functions - double spine_vector_get_x( - spine_vector vector, - ) { - return _spine_vector_get_x( - vector, - ); - } - - late final _spine_vector_get_xPtr = - _lookup>('spine_vector_get_x'); - late final _spine_vector_get_x = _spine_vector_get_xPtr.asFunction(); - - double spine_vector_get_y( - spine_vector vector, - ) { - return _spine_vector_get_y( - vector, - ); - } - - late final _spine_vector_get_yPtr = - _lookup>('spine_vector_get_y'); - late final _spine_vector_get_y = _spine_vector_get_yPtr.asFunction(); - /// Atlas functions spine_atlas_result spine_atlas_load( ffi.Pointer atlasData, @@ -6724,7 +6650,7 @@ class SpineDartBindings { late final _spine_skeleton_data_result_dispose = _spine_skeleton_data_result_disposePtr.asFunction(); - /// Skeleton drawable functions + /// Skeleton drawable functionsp spine_skeleton_drawable spine_skeleton_drawable_create( spine_skeleton_data skeletonData, ) { @@ -6823,15 +6749,20 @@ class SpineDartBindings { _spine_skeleton_drawable_get_animation_state_eventsPtr .asFunction(); - /// Skin entries functions - spine_skin_entries spine_skin_entries_create() { - return _spine_skin_entries_create(); + /// Skin functions + spine_skin_entries spine_skin_get_entries( + spine_skin skin, + ) { + return _spine_skin_get_entries( + skin, + ); } - late final _spine_skin_entries_createPtr = - _lookup>('spine_skin_entries_create'); - late final _spine_skin_entries_create = _spine_skin_entries_createPtr.asFunction(); + late final _spine_skin_get_entriesPtr = + _lookup>('spine_skin_get_entries'); + late final _spine_skin_get_entries = _spine_skin_get_entriesPtr.asFunction(); + /// Skin entries functions void spine_skin_entries_dispose( spine_skin_entries entries, ) { @@ -40752,16 +40683,6 @@ final class spine_skeleton_data_result_wrapper extends ffi.Struct { 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 { @ffi.Char() external int _dummy; @@ -40787,8 +40708,6 @@ final class spine_texture_loader_wrapper extends ffi.Struct { external int _dummy; } -typedef spine_bounds = ffi.Pointer; -typedef spine_vector = ffi.Pointer; typedef spine_atlas_result = ffi.Pointer; /// Texture loader callbacks diff --git a/spine-flutter/lib/spine_dart.dart b/spine-flutter/lib/spine_dart.dart index 360ca6354..1b9c46ebd 100644 --- a/spine-flutter/lib/spine_dart.dart +++ b/spine-flutter/lib/spine_dart.dart @@ -34,6 +34,15 @@ import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'generated/atlas.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/api.dart'; @@ -130,3 +139,77 @@ SkeletonData loadSkeletonDataBinary(Atlas atlas, Uint8List binaryData, {String? SpineBindings.bindings.spine_skeleton_data_result_dispose(resultPtr.cast()); 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 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 = []; + + 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().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().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()); + } + } +} diff --git a/spine-flutter/test/headless_test.dart b/spine-flutter/test/headless_test.dart index 2162c761c..ffa5ee05c 100644 --- a/spine-flutter/test/headless_test.dart +++ b/spine-flutter/test/headless_test.dart @@ -27,6 +27,30 @@ void main() async { print('Skeleton created successfully'); 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 skeleton.dispose(); skeletonData.dispose();