diff --git a/spine-flutter/example/lib/animation_state_events.dart b/spine-flutter/example/lib/animation_state_events.dart index 90e878d93..5c1e2056b 100644 --- a/spine-flutter/example/lib/animation_state_events.dart +++ b/spine-flutter/example/lib/animation_state_events.dart @@ -24,7 +24,7 @@ class AnimationStateEvents extends StatelessWidget { controller.animationState.setListener((type, trackEntry, event) { if (type == EventType.event) { print( - "User event: { name: ${event?.getData().getName()}, intValue: ${event?.getIntValue()}, floatValue: ${event?.getFloatValue()}, stringValue: ${event?.getStringValue()} }", + "User event: { name: ${event?.data.name}, intValue: ${event?.intValue}, floatValue: ${event?.floatValue}, stringValue: ${event?.stringValue} }", ); } }); diff --git a/spine-flutter/example/lib/debug_rendering.dart b/spine-flutter/example/lib/debug_rendering.dart index 5799fd90c..f45a7f680 100644 --- a/spine-flutter/example/lib/debug_rendering.dart +++ b/spine-flutter/example/lib/debug_rendering.dart @@ -40,7 +40,7 @@ class DebugRendering extends StatelessWidget { const debugRenderer = DebugRenderer(); final controller = SpineWidgetController( onInitialized: (controller) { - controller.animationState.setAnimationByName(0, "walk", true); + controller.animationState.setAnimation(0, "walk", true); }, onBeforePaint: (controller, canvas) { // Save the current transform and other canvas state diff --git a/spine-flutter/example/lib/dress_up.dart b/spine-flutter/example/lib/dress_up.dart index 15155792e..59f7b3baf 100644 --- a/spine-flutter/example/lib/dress_up.dart +++ b/spine-flutter/example/lib/dress_up.dart @@ -41,7 +41,7 @@ class DressUp extends StatefulWidget { class DressUpState extends State { static const double thumbnailSize = 200; - late SkeletonDrawable _drawable; + late SkeletonDrawableFlutter _drawable; Skin? _customSkin; final Map _skinImages = {}; final Map _selectedSkins = {}; @@ -50,17 +50,19 @@ class DressUpState extends State { void initState() { reportLeaks(); super.initState(); - SkeletonDrawable.fromAsset("assets/mix-and-match.atlas", "assets/mix-and-match-pro.skel").then((drawable) async { + SkeletonDrawableFlutter.fromAsset("assets/mix-and-match.atlas", "assets/mix-and-match-pro.skel") + .then((drawable) async { _drawable = drawable; - for (var skin in drawable.skeletonData.getSkins()) { - if (skin.getName() == "default") continue; + for (var skin in drawable.skeletonData.skins) { + if (skin == null) continue; + if (skin.name == "default") continue; var skeleton = drawable.skeleton; - skeleton.setSkin(skin); - skeleton.setToSetupPose(); + skeleton.setSkin2(skin); + skeleton.setupPose(); skeleton.update(0); skeleton.updateWorldTransform(Physics.update); - _skinImages[skin.getName()] = await drawable.renderToRawImageData(thumbnailSize, thumbnailSize, 0xffffffff); - _selectedSkins[skin.getName()] = false; + _skinImages[skin.name] = await drawable.renderToRawImageData(thumbnailSize, thumbnailSize, 0xffffffff); + _selectedSkins[skin.name] = false; } _toggleSkin("full-skins/girl"); setState(() {}); @@ -69,7 +71,7 @@ class DressUpState extends State { void _toggleSkin(String skinName) { _selectedSkins[skinName] = !_selectedSkins[skinName]!; - _drawable.skeleton.setSkinByName("default"); + _drawable.skeleton.setSkin("default"); if (_customSkin != null) _customSkin?.dispose(); _customSkin = Skin("custom-skin"); for (var skinName in _selectedSkins.keys) { @@ -78,15 +80,15 @@ class DressUpState extends State { if (skin != null) _customSkin?.addSkin(skin); } } - _drawable.skeleton.setSkin(_customSkin!); - _drawable.skeleton.setSlotsToSetupPose(); + _drawable.skeleton.setSkin2(_customSkin!); + _drawable.skeleton.setupPoseSlots(); } @override Widget build(BuildContext context) { final controller = SpineWidgetController( onInitialized: (controller) { - controller.animationState.setAnimationByName(0, "dance", true); + controller.animationState.setAnimation(0, "dance", true); }, ); diff --git a/spine-flutter/example/lib/flame_example.dart b/spine-flutter/example/lib/flame_example.dart index f331a93f8..6fb007237 100644 --- a/spine-flutter/example/lib/flame_example.dart +++ b/spine-flutter/example/lib/flame_example.dart @@ -36,7 +36,7 @@ import 'package:flutter/material.dart'; class SpineComponent extends PositionComponent { final BoundsProvider _boundsProvider; - final SkeletonDrawable _drawable; + final SkeletonDrawableFlutter _drawable; late final Bounds _bounds; final bool _ownsDrawable; @@ -70,7 +70,7 @@ class SpineComponent extends PositionComponent { int? priority, }) async { return SpineComponent( - await SkeletonDrawable.fromAsset(atlasFile, skeletonFile, bundle: bundle), + await SkeletonDrawableFlutter.fromAsset(atlasFile, skeletonFile, bundle: bundle), ownsDrawable: true, boundsProvider: boundsProvider, position: position, @@ -137,15 +137,15 @@ class SimpleFlameExample extends FlameGame { } class DragonExample extends FlameGame { - late final Atlas cachedAtlas; + late final AtlasFlutter cachedAtlas; late final SkeletonData cachedSkeletonData; late final SpineComponent dragon; @override Future onLoad() async { - cachedAtlas = await Atlas.fromAsset("assets/dragon.atlas"); - cachedSkeletonData = await SkeletonData.fromAsset(cachedAtlas, "assets/dragon-ess.skel"); - final drawable = SkeletonDrawable(cachedAtlas, cachedSkeletonData, false); + cachedAtlas = await AtlasFlutter.fromAsset("assets/dragon.atlas"); + cachedSkeletonData = await SkeletonDataFlutter.fromAsset(cachedAtlas, "assets/dragon-ess.skel"); + final drawable = SkeletonDrawableFlutter(cachedAtlas, cachedSkeletonData, false); dragon = SpineComponent( drawable, scale: Vector2(0.4, 0.4), @@ -168,21 +168,21 @@ class DragonExample extends FlameGame { class PreloadAndShareSpineDataExample extends FlameGame { late final SkeletonData cachedSkeletonData; - late final Atlas cachedAtlas; + late final AtlasFlutter cachedAtlas; late final List spineboys = []; @override Future onLoad() async { // Pre-load the atlas and skeleton data once. - cachedAtlas = await Atlas.fromAsset("assets/spineboy.atlas"); - cachedSkeletonData = await SkeletonData.fromAsset(cachedAtlas, "assets/spineboy-pro.skel"); + cachedAtlas = await AtlasFlutter.fromAsset("assets/spineboy.atlas"); + cachedSkeletonData = await SkeletonDataFlutter.fromAsset(cachedAtlas, "assets/spineboy-pro.skel"); // Instantiate many spineboys from the pre-loaded data. Each SpineComponent // gets their own SkeletonDrawable copy derived from the cached data. The // SkeletonDrawable copies do not own the underlying skeleton data and atlas. final rng = Random(); for (int i = 0; i < 100; i++) { - final drawable = SkeletonDrawable(cachedAtlas, cachedSkeletonData, false); + final drawable = SkeletonDrawableFlutter(cachedAtlas, cachedSkeletonData, false); final scale = 0.1 + rng.nextDouble() * 0.2; final position = Vector2(rng.nextDouble() * size.x, rng.nextDouble() * size.y); final spineboy = SpineComponent(drawable, scale: Vector2(scale, scale), position: position); diff --git a/spine-flutter/example/lib/ik_following.dart b/spine-flutter/example/lib/ik_following.dart index 4f6fc22c1..1fdb128b5 100644 --- a/spine-flutter/example/lib/ik_following.dart +++ b/spine-flutter/example/lib/ik_following.dart @@ -48,17 +48,19 @@ class IkFollowingState extends State { controller = SpineWidgetController( onInitialized: (controller) { // Set the walk animation on track 0, let it loop - controller.animationState.setAnimationByName(0, "walk", true); - controller.animationState.setAnimationByName(1, "aim", true); + controller.animationState.setAnimation(0, "walk", true); + controller.animationState.setAnimation(1, "aim", true); }, onAfterUpdateWorldTransforms: (controller) { final worldPosition = crossHairPosition; if (worldPosition == null) return; final bone = controller.skeleton.findBone("crosshair")!; - final parent = bone.getParent()!; - final position = parent.worldToLocal(worldPosition.dx, worldPosition.dy); - bone.setX(position.x); - bone.setY(position.y); + final parent = bone.parent; + if (parent != null) { + final position = parent.appliedPose.worldToLocal(worldPosition.dx, worldPosition.dy); + bone.appliedPose.x = position.x; + bone.appliedPose.y = position.y; + } }, ); } diff --git a/spine-flutter/example/lib/pause_play_animation.dart b/spine-flutter/example/lib/pause_play_animation.dart index 89df8b749..ae7f2b1ba 100644 --- a/spine-flutter/example/lib/pause_play_animation.dart +++ b/spine-flutter/example/lib/pause_play_animation.dart @@ -31,7 +31,7 @@ import 'package:spine_flutter/spine_flutter.dart'; import 'package:flutter/material.dart'; class PlayPauseAnimation extends StatefulWidget { - const PlayPauseAnimation({Key? key}) : super(key: key); + const PlayPauseAnimation({super.key}); @override PlayPauseAnimationState createState() => PlayPauseAnimationState(); @@ -45,7 +45,7 @@ class PlayPauseAnimationState extends State { super.initState(); controller = SpineWidgetController( onInitialized: (controller) { - controller.animationState.setAnimationByName(0, "flying", true); + controller.animationState.setAnimation(0, "flying", true); }, ); } diff --git a/spine-flutter/example/lib/physics.dart b/spine-flutter/example/lib/physics.dart index 27ebdd24f..6f228a4b2 100644 --- a/spine-flutter/example/lib/physics.dart +++ b/spine-flutter/example/lib/physics.dart @@ -48,8 +48,8 @@ class PhysicsState extends State { controller = SpineWidgetController( onInitialized: (controller) { - controller.animationState.setAnimationByName(0, "eyeblink-long", true); - controller.animationState.setAnimationByName(1, "wings-and-feet", true); + controller.animationState.setAnimation(0, "eyeblink-long", true); + controller.animationState.setAnimation(1, "wings-and-feet", true); }, onAfterUpdateWorldTransforms: (controller) { if (lastMousePosition == null) { diff --git a/spine-flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift b/spine-flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift index bfa0333a3..cccf817a5 100644 --- a/spine-flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/spine-flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,5 +5,6 @@ import FlutterMacOS import Foundation + func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { } diff --git a/spine-flutter/example/macos/Podfile.lock b/spine-flutter/example/macos/Podfile.lock index 57fc42d38..25ed49044 100644 --- a/spine-flutter/example/macos/Podfile.lock +++ b/spine-flutter/example/macos/Podfile.lock @@ -15,8 +15,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - spine_flutter: 75f9d54a630ac150d238210f9c211529c37c11ba + spine_flutter: 8469a2cfb87c5a7101a7c87dc7c14ee49699ea3b PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/spine-flutter/example/macos/Runner/AppDelegate.swift b/spine-flutter/example/macos/Runner/AppDelegate.swift index bfe34620c..33b0f3edd 100644 --- a/spine-flutter/example/macos/Runner/AppDelegate.swift +++ b/spine-flutter/example/macos/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true diff --git a/spine-flutter/generate-bindings.sh b/spine-flutter/generate-bindings.sh index 60b1dd829..6f6687674 100755 --- a/spine-flutter/generate-bindings.sh +++ b/spine-flutter/generate-bindings.sh @@ -21,6 +21,16 @@ if [ ! -d "codegen/node_modules" ]; then fi fi +# Generating spine-c bindings +log_action "Generating spine-c bindings" +if LOG=$(cd ../spine-c && ./build.sh codegen 2>&1); then + log_ok +else + log_fail + log_error_output "$LOG" + exit 1 +fi + # Copy spine-c and spine-cpp sources log_action "Setting up source files" if ./setup.sh > /dev/null 2>&1; then @@ -32,19 +42,21 @@ fi # Run the codegen log_action "Generating Dart bindings" -if npx tsx codegen/src/index.ts > /dev/null 2>&1; then +if LOG=$(npx tsx codegen/src/index.ts 2>&1); then log_ok else log_fail + log_error_output "$LOG" exit 1 fi # Build test spine_flutter shared library log_action "Building test library" -if (cd test && ./build.sh > /dev/null 2>&1); then +if LOG=$(cd test && ./build.sh 2>&1); then log_ok else log_fail + log_error_output "$LOG" exit 1 fi diff --git a/spine-flutter/ios/Classes/spine_flutter.cpp b/spine-flutter/ios/Classes/spine_flutter.cpp deleted file mode 100644 index d0997749f..000000000 --- a/spine-flutter/ios/Classes/spine_flutter.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Relative import to be able to reuse the C sources. -// See the comment in ../{projectName}}.podspec for more information. -#include "../../src/spine-cpp-lite/spine-cpp-lite.cpp" diff --git a/spine-flutter/ios/spine_flutter.podspec b/spine-flutter/ios/spine_flutter.podspec index 908ab41b2..56314b687 100644 --- a/spine-flutter/ios/spine_flutter.podspec +++ b/spine-flutter/ios/spine_flutter.podspec @@ -12,14 +12,9 @@ A new Flutter FFI plugin project. s.homepage = 'http://example.com' s.license = { :file => '../LICENSE' } s.author = { 'Your Company' => 'email@example.com' } - - # This will ensure the source files in Classes/ are included in the native - # builds of apps using this FFI plugin. Podspec does not support relative - # paths, so Classes contains a forwarder C file that relatively imports - # `../src/*` so that the C sources can be shared among all target platforms. s.source = { :path => '.' } s.source_files = 'Classes/**/*.{cpp}' - s.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/Classes/spine-cpp/include"' } + s.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/Classes/spine-cpp/include" "$(PODS_TARGET_SRCROOT)/Classes/spine-c/include"' } s.dependency 'Flutter' s.platform = :ios, '9.0' diff --git a/spine-flutter/lib/extensions.dart b/spine-flutter/lib/extensions.dart deleted file mode 100644 index 132f5101c..000000000 --- a/spine-flutter/lib/extensions.dart +++ /dev/null @@ -1,4296 +0,0 @@ -/// -/// Spine Runtimes License Agreement -/// Last updated April 5, 2025. Replaces all prior versions. -/// -/// Copyright (c) 2013-2025, Esoteric Software LLC -/// -/// Integration of the Spine Runtimes into software or otherwise creating -/// derivative works of the Spine Runtimes is permitted under the terms and -/// conditions of Section 2 of the Spine Editor License Agreement: -/// http://esotericsoftware.com/spine-editor-license -/// -/// Otherwise, it is permitted to integrate the Spine Runtimes into software -/// or otherwise create derivative works of the Spine Runtimes (collectively, -/// "Products"), provided that each user of the Products must obtain their own -/// Spine Editor license and redistribution of the Products in any form must -/// include this license and copyright notice. -/// -/// THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY -/// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -/// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -/// DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY -/// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -/// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, -/// BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND -/// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -/// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -/// THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -/// - -import 'dart:convert' as convert; -import 'dart:io'; -import 'dart:typed_data'; -import 'dart:ui'; - -import 'package:flutter/foundation.dart' show kIsWeb; -import 'package:flutter/material.dart' as material; -import 'package:flutter/rendering.dart' as rendering; -import 'package:flutter/services.dart'; -import 'package:http/http.dart' as http; -import 'package:path/path.dart' as path; - -import 'ffi_proxy.dart'; -import 'spine_dart_init.dart' if (dart.library.html) 'spine_flutter_init_web.dart'; -import 'spine_dart.dart'; -import 'raw_image_provider.dart'; - -export 'spine_widget.dart'; - -late SpineFlutterBindings _bindings; -late Allocator _allocator; - -Future initSpineFlutter({bool useStaticLinkage = false, bool enableMemoryDebugging = false}) async { - final ffi = await initSpineFlutterFFI(useStaticLinkage); - _bindings = SpineFlutterBindings(ffi.dylib); - _allocator = ffi.allocator; - if (enableMemoryDebugging) _bindings.spine_enable_debug_extension(true); - - // Initialize the global bindings for generated code - initializeSpineFlutter(_bindings); - - return; -} - -int majorVersion() => _bindings.spine_major_version(); - -int minorVersion() => _bindings.spine_minor_version(); - -void reportLeaks() => _bindings.spine_report_leaks(); - -/// A color made of red, green, blue, and alpha components, -/// ranging from 0-1. -class Color { - double r; - double g; - double b; - double a; - - Color(this.r, this.g, this.b, this.a); -} - -/// Bounds denoted by the top left corner coordinates [x] and [y] -/// and the [width] and [height]. -class Bounds { - double x; - double y; - double width; - double height; - - Bounds(this.x, this.y, this.width, this.height); -} - -/// A two-dimensional vector with [x] and [y] components. -class Vec2 { - double x; - double y; - - Vec2(this.x, this.y); -} - -/// Atlas data loaded from a `.atlas` file and its corresponding `.png` files. For each atlas image, -/// a corresponding [Image] and [Paint] is constructed, which are used when rendering a skeleton -/// that uses this atlas. -/// -/// Use the static methods [fromAsset], [fromFile], and [fromHttp] to load an atlas. Call [dispose] -/// when the atlas is no longer in use to release its resources. -class Atlas { - static FilterQuality filterQuality = FilterQuality.none; - final spine_atlas _atlas; - final List atlasPages; - final List> atlasPagePaints; - bool _disposed; - - Atlas._(this._atlas, this.atlasPages, this.atlasPagePaints) : _disposed = false; - - static Future _load(String atlasFileName, Future Function(String name) loadFile) async { - final atlasBytes = await loadFile(atlasFileName); - final atlasData = convert.utf8.decode(atlasBytes); - final atlasDataNative = atlasData.toNativeUtf8(allocator: _allocator); - final atlas = _bindings.spine_atlas_load(atlasDataNative.cast()); - _allocator.free(atlasDataNative); - if (_bindings.spine_atlas_get_error(atlas).address != nullptr.address) { - final Pointer error = _bindings.spine_atlas_get_error(atlas).cast(); - final message = error.toDartString(); - _bindings.spine_atlas_dispose(atlas); - throw Exception("Couldn't load atlas: $message"); - } - - final atlasDir = path.dirname(atlasFileName); - List atlasPages = []; - List> atlasPagePaints = []; - final numImagePaths = _bindings.spine_atlas_get_num_image_paths(atlas); - for (int i = 0; i < numImagePaths; i++) { - final Pointer atlasPageFile = _bindings.spine_atlas_get_image_path(atlas, i).cast(); - final imagePath = "$atlasDir/${atlasPageFile.toDartString()}"; - var imageData = await loadFile(imagePath); - final Codec codec = await instantiateImageCodec(imageData); - final FrameInfo frameInfo = await codec.getNextFrame(); - final Image image = frameInfo.image; - atlasPages.add(image); - Map paints = {}; - for (final blendMode in BlendMode.values) { - paints[blendMode] = Paint() - ..shader = ImageShader( - image, - TileMode.clamp, - TileMode.clamp, - Matrix4.identity().storage, - filterQuality: Atlas.filterQuality, - ) - ..isAntiAlias = true - ..blendMode = blendMode.canvasBlendMode; - } - atlasPagePaints.add(paints); - } - - return Atlas._(atlas, atlasPages, atlasPagePaints); - } - - /// Loads an [Atlas] from the file [atlasFileName] in the root bundle or the optionally provided [bundle]. - /// - /// Throws an [Exception] in case the atlas could not be loaded. - static Future fromAsset(String atlasFileName, {AssetBundle? bundle}) async { - bundle ??= rootBundle; - return _load(atlasFileName, (file) async => (await bundle!.load(file)).buffer.asUint8List()); - } - - /// Loads an [Atlas] from the file [atlasFileName]. - /// - /// Throws an [Exception] in case the atlas could not be loaded. - static Future fromFile(String atlasFileName) async { - return _load(atlasFileName, (file) => File(file).readAsBytes()); - } - - /// Loads an [Atlas] from the URL [atlasURL]. - /// - /// Throws an [Exception] in case the atlas could not be loaded. - static Future fromHttp(String atlasURL) async { - return _load(atlasURL, (file) async { - return (await http.get(Uri.parse(file))).bodyBytes; - }); - } - - /// Disposes the (native) resources of this atlas. The atlas can no longer be - /// used after calling this function. Only the first call to this method will - /// have an effect. Subsequent calls are ignored. - void dispose() { - if (_disposed) return; - _disposed = true; - _bindings.spine_atlas_dispose(_atlas); - for (final image in atlasPages) { - image.dispose(); - } - atlasPagePaints.clear(); - } -} - -/// Skeleton data loaded from a skeleton `.json` or `.skel` file. Contains bones, slots, constraints, -/// skins, animations, and so on making up a skeleton. Also contains meta data such as the skeletons -/// setup pose bounding box, the Spine editor version it was exported from, and so on. -/// -/// Skeleton data is stateless. Stateful [Skeleton] instances can be constructed from a [SkeletonData] instance. -/// A single [SkeletonData] instance can be shared by multiple [Skeleton] instances. -/// -/// Use the static methods [fromJson], [fromBinary], [fromAsset], [fromFile], and [fromURL] to load -/// skeleton data. Call [dispose] when the skeleton data is no longer in use to free its resources. -/// -/// See [Data objects](http://esotericsoftware.com/spine-runtime-architecture#Data-objects) in the Spine -/// Runtimes Guide. -class SkeletonData { - final spine_skeleton_data _data; - bool _disposed; - - SkeletonData._(this._data) : _disposed = false; - - /// Loads a [SkeletonData] from the [json] string, using the provided [atlas] to resolve attachment - /// images. - /// - /// Throws an [Exception] in case the atlas could not be loaded. - static SkeletonData fromJson(Atlas atlas, String json) { - final jsonNative = json.toNativeUtf8(allocator: _allocator); - final path = "".toNativeUtf8(allocator: _allocator); - final result = _bindings.spine_skeleton_data_load_json(atlas._atlas, jsonNative.cast(), path.cast()); - _allocator.free(jsonNative); - if (_bindings.spine_skeleton_data_result_get_error(result).address != nullptr.address) { - final Pointer error = _bindings.spine_skeleton_data_result_get_error(result).cast(); - final message = error.toDartString(); - _bindings.spine_skeleton_data_result_dispose(result); - throw Exception("Couldn't load skeleton data: $message"); - } - var data = SkeletonData._(_bindings.spine_skeleton_data_result_get_data(result)); - _bindings.spine_skeleton_data_result_dispose(result); - return data; - } - - /// Loads a [SkeletonData] from the [binary] skeleton data, using the provided [atlas] to resolve attachment - /// images. - /// - /// Throws an [Exception] in case the skeleton data could not be loaded. - static SkeletonData fromBinary(Atlas atlas, Uint8List binary) { - final Pointer binaryNative = _allocator.allocate(binary.lengthInBytes); - binaryNative.asTypedList(binary.lengthInBytes).setAll(0, binary); - final path = "".toNativeUtf8(allocator: _allocator); - final result = - _bindings.spine_skeleton_data_load_binary(atlas._atlas, binaryNative.cast(), binary.lengthInBytes, path.cast()); - _allocator.free(binaryNative); - if (_bindings.spine_skeleton_data_result_get_error(result).address != nullptr.address) { - final Pointer error = _bindings.spine_skeleton_data_result_get_error(result).cast(); - final message = error.toDartString(); - _bindings.spine_skeleton_data_result_dispose(result); - throw Exception("Couldn't load skeleton data: $message"); - } - var data = SkeletonData._(_bindings.spine_skeleton_data_result_get_data(result)); - _bindings.spine_skeleton_data_result_dispose(result); - return data; - } - - /// Loads a [SkeletonData] from the file [skeletonFile] in the root bundle or the optionally provided [bundle]. - /// Uses the provided [atlas] to resolve attachment images. - /// - /// Throws an [Exception] in case the skeleton data could not be loaded. - static Future fromAsset(Atlas atlas, String skeletonFile, {AssetBundle? bundle}) async { - bundle ??= rootBundle; - if (skeletonFile.endsWith(".json")) { - return fromJson(atlas, await bundle.loadString(skeletonFile)); - } else { - return fromBinary(atlas, (await bundle.load(skeletonFile)).buffer.asUint8List()); - } - } - - /// Loads a [SkeletonData] from the file [skeletonFile]. Uses the provided [atlas] to resolve attachment images. - /// - /// Throws an [Exception] in case the skeleton data could not be loaded. - static Future fromFile(Atlas atlas, String skeletonFile) async { - if (skeletonFile.endsWith(".json")) { - return fromJson(atlas, convert.utf8.decode(await File(skeletonFile).readAsBytes())); - } else { - return fromBinary(atlas, await File(skeletonFile).readAsBytes()); - } - } - - /// Loads a [SkeletonData] from the URL [skeletonURL]. Uses the provided [atlas] to resolve attachment images. - /// - /// Throws an [Exception] in case the skeleton data could not be loaded. - static Future fromHttp(Atlas atlas, String skeletonURL) async { - if (skeletonURL.endsWith(".json")) { - return fromJson(atlas, convert.utf8.decode((await http.get(Uri.parse(skeletonURL))).bodyBytes)); - } else { - return fromBinary(atlas, (await http.get(Uri.parse(skeletonURL))).bodyBytes); - } - } - - /// The skeleton's bones, sorted parent first. The root bone is always the first bone. - List getBones() { - final bones = _bindings.spine_skeleton_data_get_bones(_data); - - final List bones = []; - final numBones = _bindings.spine_skeleton_data_get_num_bones(_data); - final nativeBones = _bindings.spine_skeleton_data_get_bones(_data); - for (int i = 0; i < numBones; i++) { - bones.add(BoneData._(nativeBones[i])); - } - return bones; - } - - /// Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it multiple times. - BoneData? findBone(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final bone = _bindings.spine_skeleton_data_find_bone(_data, nativeName.cast()); - _allocator.free(nativeName); - if (bone.address == nullptr.address) return null; - return BoneData._(bone); - } - - /// The skeleton's slots. - List getSlots() { - final List slots = []; - final numSlots = _bindings.spine_skeleton_data_get_num_slots(_data); - final nativeSlots = _bindings.spine_skeleton_data_get_slots(_data); - for (int i = 0; i < numSlots; i++) { - slots.add(SlotData._(nativeSlots[i])); - } - return slots; - } - - /// Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it multiple times. - SlotData? findSlot(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final slot = _bindings.spine_skeleton_data_find_slot(_data, nativeName.cast()); - _allocator.free(nativeName); - if (slot.address == nullptr.address) return null; - return SlotData._(slot); - } - - /// All skins, including the default skin. - List getSkins() { - final List skins = []; - final numSkins = _bindings.spine_skeleton_data_get_num_skins(_data); - final nativeSkins = _bindings.spine_skeleton_data_get_skins(_data); - for (int i = 0; i < numSkins; i++) { - skins.add(Skin._(nativeSkins[i])); - } - return skins; - } - - /// The skeleton's default skin. By default this skin contains all attachments that were not in a skin in Spine. - Skin? getDefaultSkin() { - final skin = _bindings.spine_skeleton_data_get_default_skin(_data); - if (skin.address == nullptr.address) return null; - return Skin._(skin); - } - - void setDefaultSkin(Skin? skin) { - if (skin == null) { - _bindings.spine_skeleton_data_set_default_skin(_data, nullptr); - } else { - _bindings.spine_skeleton_data_set_default_skin(_data, skin._skin); - } - } - - /// Finds a skin by comparing each skin's name. It is more efficient to cache the results of this method than to call it - /// multiple times. - Skin? findSkin(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final skin = _bindings.spine_skeleton_data_find_skin(_data, nativeName.cast()); - _allocator.free(nativeName); - if (skin.address == nullptr.address) return null; - return Skin._(skin); - } - - /// The skeleton's events. - List getEvents() { - final List events = []; - final numEvents = _bindings.spine_skeleton_data_get_num_events(_data); - final nativeEvents = _bindings.spine_skeleton_data_get_events(_data); - for (int i = 0; i < numEvents; i++) { - events.add(EventData._(nativeEvents[i])); - } - return events; - } - - /// Finds an event by comparing each events's name. It is more efficient to cache the results of this method than to call it - /// multiple times. - EventData? findEvent(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final event = _bindings.spine_skeleton_data_find_event(_data, nativeName.cast()); - _allocator.free(nativeName); - if (event.address == nullptr.address) return null; - return EventData._(event); - } - - /// The skeleton's animations. - List getAnimations() { - final List events = []; - final numAnimation = _bindings.spine_skeleton_data_get_num_animations(_data); - final nativeAnimations = _bindings.spine_skeleton_data_get_animations(_data); - for (int i = 0; i < numAnimation; i++) { - events.add(Animation._(nativeAnimations[i])); - } - return events; - } - - /// Finds an animation by comparing each animation's name. It is more efficient to cache the results of this method than to - /// call it multiple times. - Animation? findAnimation(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final animation = _bindings.spine_skeleton_data_find_animation(_data, nativeName.cast()); - _allocator.free(nativeName); - if (animation.address == nullptr.address) return null; - return Animation._(animation); - } - - /// The skeleton's IK constraints. - List getIkConstraints() { - final List constraints = []; - final numConstraints = _bindings.spine_skeleton_data_get_num_ik_constraints(_data); - final nativeConstraints = _bindings.spine_skeleton_data_get_ik_constraints(_data); - for (int i = 0; i < numConstraints; i++) { - constraints.add(IkConstraintData._(nativeConstraints[i])); - } - return constraints; - } - - /// Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method - /// than to call it multiple times. - IkConstraintData? findIkConstraint(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final constraint = _bindings.spine_skeleton_data_find_ik_constraint(_data, nativeName.cast()); - _allocator.free(nativeName); - if (constraint.address == nullptr.address) return null; - return IkConstraintData._(constraint); - } - - /// The skeleton's transform constraints. - List getTransformConstraints() { - final List constraints = []; - final numConstraints = _bindings.spine_skeleton_data_get_num_transform_constraints(_data); - final nativeConstraints = _bindings.spine_skeleton_data_get_transform_constraints(_data); - for (int i = 0; i < numConstraints; i++) { - constraints.add(TransformConstraint._(nativeConstraints[i].cast())); - } - return constraints; - } - - /// Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of - /// this method than to call it multiple times. - TransformConstraintData? findTransformConstraint(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final constraint = _bindings.spine_skeleton_data_find_transform_constraint(_data, nativeName.cast()); - _allocator.free(nativeName); - if (constraint.address == nullptr.address) return null; - return TransformConstraintData._(constraint); - } - - /// The skeleton's path constraints. - List getPathConstraints() { - final List constraints = []; - final numConstraints = _bindings.spine_skeleton_data_get_num_path_constraints(_data); - final nativeConstraints = _bindings.spine_skeleton_data_get_path_constraints(_data); - for (int i = 0; i < numConstraints; i++) { - constraints.add(PathConstraintData._(nativeConstraints[i])); - } - return constraints; - } - - /// Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method - /// than to call it multiple times. - PathConstraintData? findPathConstraint(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final constraint = _bindings.spine_skeleton_data_find_path_constraint(_data, nativeName.cast()); - _allocator.free(nativeName); - if (constraint.address == nullptr.address) return null; - return PathConstraintData._(constraint); - } - - /// The skeleton's name, which by default is the name of the skeleton data file when possible, or null when a name hasn't been - /// set. - String? getName() { - Pointer name = _bindings.spine_skeleton_data_get_name(_data).cast(); - if (name.address == nullptr.address) return null; - return name.toDartString(); - } - - /// The X coordinate of the skeleton's axis aligned bounding box in the setup pose. - double getX() { - return _bindings.spine_skeleton_data_get_x(_data); - } - - void setX(double x) { - _bindings.spine_skeleton_data_set_x(_data, x); - } - - /// The Y coordinate of the skeleton's axis aligned bounding box in the setup pose. - double getY() { - return _bindings.spine_skeleton_data_get_y(_data); - } - - void setY(double y) { - _bindings.spine_skeleton_data_set_x(_data, y); - } - - /// The width of the skeleton's axis aligned bounding box in the setup pose. - double getWidth() { - return _bindings.spine_skeleton_data_get_width(_data); - } - - void setWidth(double width) { - _bindings.spine_skeleton_data_set_width(_data, width); - } - - /// The height of the skeleton's axis aligned bounding box in the setup pose. - double getHeight() { - return _bindings.spine_skeleton_data_get_height(_data); - } - - void setHeight(double height) { - _bindings.spine_skeleton_data_set_height(_data, height); - } - - /// The Spine version used to export the skeleton data. - String? getVersion() { - Pointer name = _bindings.spine_skeleton_data_get_version(_data).cast(); - if (name.address == nullptr.address) return null; - return name.toDartString(); - } - - /// The skeleton data hash. This value will change if any of the skeleton data has changed. - String? getHash() { - Pointer name = _bindings.spine_skeleton_data_get_hash(_data).cast(); - if (name.address == nullptr.address) return null; - return name.toDartString(); - } - - /// The path to the images directory as defined in Spine, or null if nonessential data was not exported. - String? getImagesPath() { - Pointer name = _bindings.spine_skeleton_data_get_images_path(_data).cast(); - if (name.address == nullptr.address) return null; - return name.toDartString(); - } - - /// The path to the audio directory as defined in Spine, or null if nonessential data was not exported. - String? getAudioPath() { - Pointer name = _bindings.spine_skeleton_data_get_audio_path(_data).cast(); - if (name.address == nullptr.address) return null; - return name.toDartString(); - } - - /// The dopesheet FPS in Spine, or zero if nonessential data was not exported. - double getFps() { - return _bindings.spine_skeleton_data_get_fps(_data); - } - - /// Disposes the (native) resources of this skeleton data. The skeleton data can no longer be - /// used after calling this function. Only the first call to this method will - /// have an effect. Subsequent calls are ignored. - void dispose() { - if (_disposed) return; - _disposed = true; - _bindings.spine_skeleton_data_dispose(_data); - } -} - -/// Determines how images are blended with existing pixels when drawn. See [Blending](http://esotericsoftware.com/spine-slots#Blending) in -/// the Spine User Guide. -enum BlendMode { - normal(0, rendering.BlendMode.srcOver), - additive(1, rendering.BlendMode.plus), - multiply(2, rendering.BlendMode.multiply), - screen(3, rendering.BlendMode.screen); - - final int value; - final rendering.BlendMode canvasBlendMode; - - const BlendMode(this.value, this.canvasBlendMode); -} - -/// Determines how a bone inherits world transforms from parent bones. See [Transform inheritance](esotericsoftware.com/spine-bones#Transform-inheritance) -/// in the Spine User Guide. -enum Inherit { - normal(0), - onlyTranslation(1), - noRotationOrReflection(2), - noScale(3), - noScaleOrReflection(4); - - final int value; - - const Inherit(this.value); -} - -/// Determines how physics and other non-deterministic updates are applied. -enum Physics { - none(0), - reset(1), - update(2), - pose(3); - - final int value; - - const Physics(this.value); -} - -/// Controls how the first bone is positioned along the path. -/// -/// See [Position mode](http://esotericsoftware.com/spine-path-constraints#Position-mode) in the Spine User Guide. -enum PositionMode { - fixed(0), - percent(1); - - final int value; - - const PositionMode(this.value); -} - -/// Controls how bones after the first bone are positioned along the path. -/// -/// See [Spacing mode](http://esotericsoftware.com/spine-path-constraints#Spacing-mode) in the Spine User Guide. -enum SpacingMode { - length(0), - fixed(1), - percent(2), - proportional(3); - - final int value; - - const SpacingMode(this.value); -} - -/// Controls how bones are rotated, translated, and scaled to match the path. -/// -/// See [Rotate mode](https://esotericsoftware.com/spine-path-constraints#Rotate-Mix) in the Spine User Guide. -enum RotateMode { - tangent(0), - chain(1), - chainScale(2); - - final int value; - - const RotateMode(this.value); -} - -/// Stores the setup pose for a [Bone]. -class BoneData { - final spine_bone_data _data; - - BoneData._(this._data); - - /// The index of the bone in [Skeleton.getBones]. - int getIndex() { - return _bindings.spine_bone_data_get_index(_data); - } - - /// The name of the bone, which is unique across all bones in the skeleton. - String getName() { - Pointer name = _bindings.spine_bone_data_get_name(_data).cast(); - return name.toDartString(); - } - - /// The parent bone or `null` if this is the root bone. - BoneData? getParent() { - final parent = _bindings.spine_bone_data_get_parent(_data); - if (parent.address == nullptr.address) return null; - return BoneData._(parent); - } - - /// The bone's length. - double getLength() { - return _bindings.spine_bone_data_get_length(_data); - } - - void setLength(double length) { - _bindings.spine_bone_data_set_length(_data, length); - } - - /// The local x translation. - double getX() { - return _bindings.spine_bone_data_get_x(_data); - } - - void setX(double x) { - _bindings.spine_bone_data_set_x(_data, x); - } - - /// The local y translation. - double getY() { - return _bindings.spine_bone_data_get_y(_data); - } - - void setY(double y) { - _bindings.spine_bone_data_set_y(_data, y); - } - - /// The local rotation in degrees. - double getRotation() { - return _bindings.spine_bone_data_get_rotation(_data); - } - - void setRotation(double rotation) { - _bindings.spine_bone_data_set_rotation(_data, rotation); - } - - /// The local scaleX. - double getScaleX() { - return _bindings.spine_bone_data_get_scale_x(_data); - } - - void setScaleX(double scaleX) { - _bindings.spine_bone_data_set_scale_x(_data, scaleX); - } - - /// The local scaleY. - double getScaleY() { - return _bindings.spine_bone_data_get_scale_y(_data); - } - - void setScaleY(double scaleY) { - _bindings.spine_bone_data_set_scale_y(_data, scaleY); - } - - /// The local shearX. - double getShearX() { - return _bindings.spine_bone_data_get_shear_x(_data); - } - - void setShearX(double shearX) { - _bindings.spine_bone_data_set_shear_x(_data, shearX); - } - - /// The local shearY. - double getShearY() { - return _bindings.spine_bone_data_get_shear_y(_data); - } - - void setShearY(double shearY) { - _bindings.spine_bone_data_set_shear_y(_data, shearY); - } - - /// The [Inherit] for how parent world transforms affect this bone. - Inherit getInherit() { - final nativeMode = _bindings.spine_bone_data_get_inherit(_data); - return Inherit.values[nativeMode]; - } - - void setInherit(Inherit inherit) { - _bindings.spine_bone_data_set_inherit(_data, inherit.value); - } - - /// When true, [Skeleton.updateWorldTransform] only updates this bone if the [Skeleton.getSkin] contains this bone. - /// - /// See [Skin.getBones]. - bool isSkinRequired() { - return _bindings.spine_bone_data_is_skin_required(_data) == -1; - } - - void setIsSkinRequired(bool isSkinRequired) { - _bindings.spine_bone_data_set_is_skin_required(_data, isSkinRequired ? -1 : 0); - } - - /// The [Color] of the bone as it was in Spine, or a default color if nonessential data was not exported. Bones are not usually - /// rendered at runtime. - Color getColor() { - final color = _bindings.spine_bone_data_get_color(_data); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(double r, double g, double b, double a) { - _bindings.spine_bone_data_set_color(_data, r, g, b, a); - } - - @override - String toString() { - return getName(); - } -} - -/// Stores a bone's current pose. -/// -/// A bone has a local transform which is used to compute its world transform. A bone also has an applied transform, which is a -/// local transform that can be applied to compute the world transform. The local transform and applied transform may differ if a -/// constraint or application code modifies the world transform after it was computed from the local transform. -class Bone { - final spine_bone _bone; - - Bone._(this._bone); - - /// Assume y-axis pointing down for all calculations. - static void setIsYDown(bool isYDown) { - _bindings.spine_bone_set_is_y_down(isYDown ? -1 : 0); - } - - static bool getIsYDown() { - return _bindings.spine_bone_get_is_y_down() == 1; - } - - /// Computes the world transform using the parent bone and this bone's local applied transform. - void update() { - _bindings.spine_bone_update(_bone); - } - - /// Computes the world transform using the parent bone and this bone's local transform. - /// - /// See [updateWorldTransformWith]. - void updateWorldTransform() { - _bindings.spine_bone_update_world_transform(_bone); - } - - /// Computes the world transform using the parent bone and the specified local transform. The applied transform is set to the - /// specified local transform. Child bones are not updated. - /// - /// See [World transform](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine - /// Runtimes Guide. - void updateWorldTransformWith( - double x, - double y, - double rotation, - double scaleX, - double scaleY, - double shearX, - double shearY, - ) { - _bindings.spine_bone_update_world_transform_with(_bone, x, y, rotation, scaleX, scaleY, shearX, shearY); - } - - /// Computes the applied transform values from the world transform. - /// - /// If the world transform is modified (by a constraint, [rotateWorld], etc) then this method should be called so - /// the applied transform matches the world transform. The applied transform may be needed by other code (eg to apply another - /// constraint). - /// - /// Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. The applied transform after - /// calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. - void updateAppliedTransform() { - _bindings.spine_bone_update_applied_transform(_bone); - } - - /// Sets this bone's local transform to the setup pose. - void setToSetupPose() { - _bindings.spine_bone_set_to_setup_pose(_bone); - } - - /// Transforms a point from world coordinates to the bone's local coordinates. - Vec2 worldToLocal(double worldX, double worldY) { - final local = _bindings.spine_bone_world_to_local(_bone, worldX, worldY); - final result = Vec2(_bindings.spine_vector_get_x(local), _bindings.spine_vector_get_y(local)); - return result; - } - - /// Transforms a point from the bone's local coordinates to world coordinates. - Vec2 localToWorld(double localX, double localY) { - final world = _bindings.spine_bone_local_to_world(_bone, localX, localY); - final result = Vec2(_bindings.spine_vector_get_x(world), _bindings.spine_vector_get_y(world)); - return result; - } - - /// Transforms a world rotation to a local rotation. - double worldToLocalRotation(double worldRotation) { - return _bindings.spine_bone_world_to_local_rotation(_bone, worldRotation); - } - - /// Transforms a local rotation to a world rotation. - double localToWorldRotation(double localRotation) { - return _bindings.spine_bone_local_to_world_rotation(_bone, localRotation); - } - - /// Rotates the world transform the specified amount. - /// - /// After changes are made to the world transform, [updateAppliedTransform] should be called and [update] will - /// need to be called on any child bones, recursively. - void rotateWorld(double degrees) { - _bindings.spine_bone_rotate_world(_bone, degrees); - } - - double getWorldToLocalRotationX() { - return _bindings.spine_bone_get_world_rotation_x(_bone); - } - - double getWorldToLocalRotationY() { - return _bindings.spine_bone_get_world_to_local_rotation_y(_bone); - } - - /// The bone's setup pose data. - BoneData getData() { - return BoneData._(_bindings.spine_bone_get_data(_bone)); - } - - /// The skeleton this bone belongs to. - Skeleton getSkeleton() { - return Skeleton._(_bindings.spine_bone_get_skeleton(_bone)); - } - - /// The parent bone, or null if this is the root bone. - Bone? getParent() { - final parent = _bindings.spine_bone_get_parent(_bone); - if (parent.address == nullptr.address) return null; - return Bone._(parent); - } - - /// The immediate children of this bone. - List getChildren() { - List children = []; - final numChildren = _bindings.spine_bone_get_num_children(_bone); - final nativeChildren = _bindings.spine_bone_get_children(_bone); - for (int i = 0; i < numChildren; i++) { - children.add(Bone._(nativeChildren[i])); - } - return children; - } - - /// The local x translation. - double getX() { - return _bindings.spine_bone_get_x(_bone); - } - - void setX(double x) { - _bindings.spine_bone_set_x(_bone, x); - } - - /// The local y translation. - double getY() { - return _bindings.spine_bone_get_y(_bone); - } - - void setY(double y) { - _bindings.spine_bone_set_y(_bone, y); - } - - /// The local rotation in degrees, counter clockwise. - double getRotation() { - return _bindings.spine_bone_get_rotation(_bone); - } - - void setRotation(double rotation) { - _bindings.spine_bone_set_rotation(_bone, rotation); - } - - /// The local scaleX. - double getScaleX() { - return _bindings.spine_bone_get_scale_x(_bone); - } - - void setScaleX(double scaleX) { - _bindings.spine_bone_set_scale_x(_bone, scaleX); - } - - /// The local scaleY. - double getScaleY() { - return _bindings.spine_bone_get_scale_y(_bone); - } - - void setScaleY(double scaleY) { - _bindings.spine_bone_set_scale_y(_bone, scaleY); - } - - /// The local shearX. - double getShearX() { - return _bindings.spine_bone_get_shear_x(_bone); - } - - void setShearX(double shearX) { - _bindings.spine_bone_set_shear_x(_bone, shearX); - } - - /// The local shearY. - double getShearY() { - return _bindings.spine_bone_get_shear_y(_bone); - } - - void setShearY(double shearY) { - _bindings.spine_bone_set_shear_y(_bone, shearY); - } - - /// The applied local x translation. - double getAX() { - return _bindings.spine_bone_get_a_x(_bone); - } - - void setAX(double x) { - _bindings.spine_bone_set_a_x(_bone, x); - } - - /// The applied local y translation. - double getAY() { - return _bindings.spine_bone_get_a_y(_bone); - } - - void setAY(double y) { - _bindings.spine_bone_set_a_y(_bone, y); - } - - /// The applied local rotation in degrees, counter clockwise. - double getAppliedRotation() { - return _bindings.spine_bone_get_applied_rotation(_bone); - } - - void setAppliedRotation(double rotation) { - _bindings.spine_bone_set_applied_rotation(_bone, rotation); - } - - /// The applied local scaleX. - double getAScaleX() { - return _bindings.spine_bone_get_a_scale_x(_bone); - } - - void setAScaleX(double scaleX) { - _bindings.spine_bone_set_a_scale_x(_bone, scaleX); - } - - /// The applied local scaleY. - double getAScaleY() { - return _bindings.spine_bone_get_a_scale_y(_bone); - } - - void setAScaleY(double scaleY) { - _bindings.spine_bone_set_a_scale_y(_bone, scaleY); - } - - /// The applied local shearX. - double getAShearX() { - return _bindings.spine_bone_get_a_shear_x(_bone); - } - - void setAShearX(double shearX) { - _bindings.spine_bone_set_a_shear_x(_bone, shearX); - } - - /// The applied local shearY. - double getAShearY() { - return _bindings.spine_bone_get_a_shear_y(_bone); - } - - void setAShearY(double shearY) { - _bindings.spine_bone_set_a_shear_y(_bone, shearY); - } - - /// Part of the world transform matrix for the X axis. If changed, [updateAppliedTransform] should be called. - double getA() { - return _bindings.spine_bone_get_a(_bone); - } - - void setA(double a) { - _bindings.spine_bone_set_a(_bone, a); - } - - /// Part of the world transform matrix for the Y axis. If changed, [updateAppliedTransform] should be called. - double getB() { - return _bindings.spine_bone_get_b(_bone); - } - - void setB(double b) { - _bindings.spine_bone_set_b(_bone, b); - } - - /// Part of the world transform matrix for the X axis. If changed, [updateAppliedTransform] should be called. - double getC() { - return _bindings.spine_bone_get_c(_bone); - } - - void setC(double c) { - _bindings.spine_bone_set_c(_bone, c); - } - - /// Part of the world transform matrix for the Y axis. If changed, [updateAppliedTransform] should be called. - double getD() { - return _bindings.spine_bone_get_d(_bone); - } - - void setD(double d) { - _bindings.spine_bone_set_a(_bone, d); - } - - /// The world X position. If changed, [updateAppliedTransform] should be called. - double getWorldX() { - return _bindings.spine_bone_get_world_x(_bone); - } - - void setWorldX(double worldX) { - _bindings.spine_bone_set_world_x(_bone, worldX); - } - - /// The world Y position. If changed, [updateAppliedTransform] should be called. - double getWorldY() { - return _bindings.spine_bone_get_world_y(_bone); - } - - void setWorldY(double worldY) { - _bindings.spine_bone_set_world_y(_bone, worldY); - } - - /// The world rotation for the X axis, calculated using [getA] and [getC]. - double getWorldRotationX() { - return _bindings.spine_bone_get_world_rotation_x(_bone); - } - - /// The world rotation for the Y axis, calculated using [getB] and [getD]. - double getWorldRotationY() { - return _bindings.spine_bone_get_world_rotation_y(_bone); - } - - /// The magnitude (always positive) of the world scale X, calculated using [getA] and [getC]. - double getWorldScaleX() { - return _bindings.spine_bone_get_world_scale_x(_bone); - } - - /// The magnitude (always positive) of the world scale Y, calculated using [getB] and [getD]. - double getWorldScaleY() { - return _bindings.spine_bone_get_world_scale_y(_bone); - } - - /// Returns false when the bone has not been computed because [BoneData.getSkinRequired] is true and the - /// active skin (see [Skeleton.getSkin]) does not contain this bone (see [Skin.getBones]). - bool isActive() { - return _bindings.spine_bone_get_is_active(_bone) == -1; - } - - void setIsActive(bool isActive) { - _bindings.spine_bone_set_is_active(_bone, isActive ? -1 : 0); - } -} - -/// Stores the setup pose for a [Slot]. -class SlotData { - final spine_slot_data _data; - - SlotData._(this._data); - - /// The index of the slot in [Skeleton.getSlots]. - int getIndex() { - return _bindings.spine_slot_data_get_index(_data); - } - - /// The name of the slot, which is unique across all slots in the skeleton. - String getName() { - final Pointer value = _bindings.spine_slot_data_get_name(_data).cast(); - return value.toDartString(); - } - - /// The bone this slot belongs to. - BoneData getBoneData() { - return BoneData._(_bindings.spine_slot_data_get_bone_data(_data)); - } - - /// The [Color] used to tint the slot's attachment. If [hasDarkColor] is true, this is used as the light color for two - /// color tinting. - Color getColor() { - final color = _bindings.spine_slot_data_get_color(_data); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(double r, double g, double b, double a) { - _bindings.spine_slot_data_set_color(_data, r, g, b, a); - } - - /// The dark color used to tint the slot's attachment for two color tinting, if [hasDarkColor] is true. The dark - /// color's alpha is not used. - Color getDarkColor() { - final color = _bindings.spine_slot_data_get_dark_color(_data); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setDarkColor(double r, double g, double b, double a) { - _bindings.spine_slot_data_set_dark_color(_data, r, g, b, a); - } - - /// Returns whether this slot has a dark color set for two color tinting. - bool hasDarkColor() { - return _bindings.spine_slot_data_has_dark_color(_data) == -1; - } - - void setHasDarkColor(bool hasDarkColor) { - _bindings.spine_slot_data_set_has_dark_color(_data, hasDarkColor ? -1 : 0); - } - - /// The name of the attachment that is visible for this slot in the setup pose, or null if no attachment is visible. - String getAttachmentName() { - final Pointer value = _bindings.spine_slot_data_get_attachment_name(_data).cast(); - return value.toDartString(); - } - - void setAttachmentName(String attachmentName) { - final nativeName = attachmentName.toNativeUtf8(allocator: _allocator); - _bindings.spine_slot_data_set_attachment_name(_data, nativeName.cast()); - _allocator.free(nativeName); - } - - /// The [BlendMode] for drawing the slot's attachment. - BlendMode getBlendMode() { - return BlendMode.values[_bindings.spine_slot_data_get_blend_mode(_data)]; - } - - void setBlendMode(BlendMode mode) { - _bindings.spine_slot_data_set_blend_mode(_data, mode.value); - } - - @override - String toString() { - return getName(); - } -} - -/// Stores a slot's current pose. Slots organize attachments for [Skeleton.getDrawOrder] purposes and provide a place to store -/// state for an attachment. State cannot be stored in an attachment itself because attachments are stateless and may be shared -/// across multiple skeletons. -class Slot { - final spine_slot _slot; - - Slot._(this._slot); - - /// Sets this slot to the setup pose. - void setToSetupPose() { - _bindings.spine_slot_set_to_setup_pose(_slot); - } - - /// The slot's setup pose data. - SlotData getData() { - return SlotData._(_bindings.spine_slot_get_data(_slot)); - } - - /// The bone this slot belongs to. - Bone getBone() { - return Bone._(_bindings.spine_slot_get_bone(_slot)); - } - - /// The skeleton this slot belongs to. - Skeleton getSkeleton() { - return Skeleton._(_bindings.spine_slot_get_skeleton(_slot)); - } - - /// The color used to tint the slot's attachment. If [hasDarkColor] is true, this is used as the light color for two - /// color tinting. - Color getColor() { - final color = _bindings.spine_slot_get_color(_slot); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(Color color) { - _bindings.spine_slot_set_color(_slot, color.r, color.g, color.b, color.a); - } - - /// The dark color used to tint the slot's attachment for two color tinting, if [hasDarkColor] is true. The dark - /// color's alpha is not used. - Color getDarkColor() { - final color = _bindings.spine_slot_get_dark_color(_slot); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setDarkColor(Color color) { - _bindings.spine_slot_set_dark_color(_slot, color.r, color.g, color.b, color.a); - } - - /// Returns whether this slot has a dark color set for two color tinting. - bool hasDarkColor() { - return _bindings.spine_slot_has_dark_color(_slot) == -1; - } - - /// The current attachment for the slot, or null if the slot has no attachment. - Attachment? getAttachment() { - final attachment = _bindings.spine_slot_get_attachment(_slot); - if (attachment.address == nullptr.address) return null; - return Attachment._toSubclass(attachment); - } - - void setAttachment(Attachment? attachment) { - _bindings.spine_slot_set_attachment(_slot, attachment != null ? attachment._attachment.cast() : nullptr); - } - - @override - String toString() { - return getData().getName(); - } - - /// The index of the texture region to display when the slot's attachment has a [Sequence]. -1 represents the - /// [Sequence.getSetupIndex]. - int getSequenceIndex() { - return _bindings.spine_slot_get_sequence_index(_slot); - } - - void setSequenceIndex(int sequenceIndex) { - _bindings.spine_slot_set_sequence_index(_slot, sequenceIndex); - } -} - -/// A region within a texture, given in normalized texture coordinates of the top left ([getU], [getV]) and -/// bottom left ([getU2], [getV2]) corner of the region within the texture. -class TextureRegion { - final spine_texture_region _region; - - TextureRegion._(this._region); - - Pointer getTexture() { - return _bindings.spine_texture_region_get_texture(_region); - } - - void setTexture(Pointer texture) { - _bindings.spine_texture_region_set_texture(_region, texture); - } - - double getU() { - return _bindings.spine_texture_region_get_u(_region); - } - - void setU(double u) { - _bindings.spine_texture_region_set_u(_region, u); - } - - double getV() { - return _bindings.spine_texture_region_get_v(_region); - } - - void setV(double v) { - _bindings.spine_texture_region_set_v(_region, v); - } - - double getU2() { - return _bindings.spine_texture_region_get_u2(_region); - } - - void setU2(double u2) { - _bindings.spine_texture_region_set_u2(_region, u2); - } - - double getV2() { - return _bindings.spine_texture_region_get_v2(_region); - } - - void setV2(double v2) { - _bindings.spine_texture_region_set_v2(_region, v2); - } - - int getDegrees() { - return _bindings.spine_texture_region_get_degrees(_region); - } - - void setDegrees(int degrees) { - _bindings.spine_texture_region_set_degrees(_region, degrees); - } - - double getOffsetX() { - return _bindings.spine_texture_region_get_offset_x(_region); - } - - void setOffsetX(double offsetX) { - _bindings.spine_texture_region_set_offset_x(_region, offsetX); - } - - double getOffsetY() { - return _bindings.spine_texture_region_get_offset_x(_region); - } - - void setOffsetY(double offsetX) { - _bindings.spine_texture_region_set_offset_x(_region, offsetX); - } - - int getWidth() { - return _bindings.spine_texture_region_get_width(_region); - } - - void setWidth(int width) { - _bindings.spine_texture_region_set_width(_region, width); - } - - int getHeight() { - return _bindings.spine_texture_region_get_height(_region); - } - - void setHeight(int height) { - _bindings.spine_texture_region_set_height(_region, height); - } - - int getOriginalWidth() { - return _bindings.spine_texture_region_get_original_width(_region); - } - - void setOriginalWidth(int originalWidth) { - _bindings.spine_texture_region_set_original_width(_region, originalWidth); - } - - int getOriginalHeight() { - return _bindings.spine_texture_region_get_original_height(_region); - } - - void setOriginalHeight(int originalHeight) { - _bindings.spine_texture_region_set_original_height(_region, originalHeight); - } -} - -/// Stores a sequence of [TextureRegion] instances that will switched through when set on an attachment. -class Sequence { - final spine_sequence _sequence; - - Sequence._(this._sequence); - - void apply(Slot slot, Attachment attachment) { - _bindings.spine_sequence_apply(_sequence, slot._slot, attachment._attachment.cast()); - } - - String getPath(String basePath, int index) { - final nativeBasePath = basePath.toNativeUtf8(allocator: _allocator); - final Pointer path = _bindings.spine_sequence_get_path(_sequence, nativeBasePath.cast(), index).cast(); - final result = path.toDartString(); - _allocator.free(nativeBasePath); - _allocator.free(path); - return result; - } - - int getId() { - return _bindings.spine_sequence_get_id(_sequence); - } - - void setId(int id) { - _bindings.spine_sequence_set_id(_sequence, id); - } - - int getStart() { - return _bindings.spine_sequence_get_start(_sequence); - } - - void setStart(int start) { - _bindings.spine_sequence_set_start(_sequence, start); - } - - int getDigits() { - return _bindings.spine_sequence_get_digits(_sequence); - } - - void setDigits(int digits) { - _bindings.spine_sequence_set_digits(_sequence, digits); - } - - int getSetupIndex() { - return _bindings.spine_sequence_get_setup_index(_sequence); - } - - void setSetupIndex(int setupIndex) { - _bindings.spine_sequence_set_setup_index(_sequence, setupIndex); - } - - List getRegions() { - List result = []; - final num = _bindings.spine_sequence_get_num_regions(_sequence); - final nativeRegions = _bindings.spine_sequence_get_regions(_sequence); - for (int i = 0; i < num; i++) { - result.add(TextureRegion._(nativeRegions[i])); - } - return result; - } -} - -/// Attachment types. -enum AttachmentType { - region(0), - mesh(1), - clipping(2), - boundingBox(3), - path(4), - point(5); - - final int value; - - const AttachmentType(this.value); -} - -/// The base class for all attachments. -abstract class Attachment { - final T _attachment; - - Attachment._(this._attachment); - - /// The attachment's name. - String getName() { - Pointer name = _bindings.spine_attachment_get_name(_attachment.cast()).cast(); - return name.toString(); - } - - /// The attachment's type. - AttachmentType getType() { - final type = _bindings.spine_attachment_get_type(_attachment.cast()); - return AttachmentType.values[type]; - } - - static Attachment _toSubclass(spine_attachment attachment) { - final type = AttachmentType.values[_bindings.spine_attachment_get_type(attachment)]; - switch (type) { - case AttachmentType.region: - return RegionAttachment._(attachment.cast()); - case AttachmentType.mesh: - return MeshAttachment._(attachment.cast()); - case AttachmentType.clipping: - return ClippingAttachment._(attachment.cast()); - case AttachmentType.boundingBox: - return BoundingBoxAttachment._(attachment.cast()); - case AttachmentType.path: - return PathAttachment._(attachment.cast()); - case AttachmentType.point: - return PointAttachment._(attachment.cast()); - } - } - - /// Returns a copy of the attachment. Copied attachments need to be disposed manually - /// when no longer in use via the [dispose] method. - Attachment copy() { - return _toSubclass(_bindings.spine_attachment_copy(_attachment.cast())); - } - - void dispose() { - _bindings.spine_attachment_dispose(_attachment.cast()); - } -} - -/// An attachment that displays a textured quadrilateral. -/// -/// See [Region attachments](http://esotericsoftware.com/spine-regions) in the Spine User Guide. -class RegionAttachment extends Attachment { - RegionAttachment._(super.attachment) : super._(); - - /// Transforms and returns the attachment's four vertices to world coordinates. If the attachment has a [Sequence], the region may - /// be changed. - /// - /// See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine - /// Runtimes Guide. - List computeWorldVertices(Slot slot) { - Pointer vertices = _allocator.allocate(4 * 8).cast(); - _bindings.spine_region_attachment_compute_world_vertices(_attachment, slot._slot, vertices); - final result = vertices.asTypedList(8).toList(); - _allocator.free(vertices); - return result; - } - - /// The local x translation. - double getX() { - return _bindings.spine_region_attachment_get_x(_attachment); - } - - void setX(double x) { - _bindings.spine_region_attachment_set_x(_attachment, x); - } - - /// The local y translation. - double getY() { - return _bindings.spine_region_attachment_get_y(_attachment); - } - - void setY(double y) { - _bindings.spine_region_attachment_set_y(_attachment, y); - } - - /// The local rotation. - double getRotation() { - return _bindings.spine_region_attachment_get_rotation(_attachment); - } - - void setRotation(double rotation) { - _bindings.spine_region_attachment_set_rotation(_attachment, rotation); - } - - /// The local scaleX. - double getScaleX() { - return _bindings.spine_region_attachment_get_scale_x(_attachment); - } - - void setScaleX(double scaleX) { - _bindings.spine_region_attachment_set_scale_x(_attachment, scaleX); - } - - /// The local scaleY. - double getScaleY() { - return _bindings.spine_region_attachment_get_scale_y(_attachment); - } - - void setScaleY(double scaleY) { - _bindings.spine_region_attachment_set_scale_x(_attachment, scaleY); - } - - /// The width of the region attachment in Spine. - double getWidth() { - return _bindings.spine_region_attachment_get_width(_attachment); - } - - void setWidth(double width) { - _bindings.spine_region_attachment_set_width(_attachment, width); - } - - /// The height of the region attachment in Spine. - double getHeight() { - return _bindings.spine_region_attachment_get_height(_attachment); - } - - void setHeight(double height) { - _bindings.spine_region_attachment_set_height(_attachment, height); - } - - Color getColor() { - final color = _bindings.spine_region_attachment_get_color(_attachment); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(double r, double g, double b, double a) { - _bindings.spine_region_attachment_set_color(_attachment, r, g, b, a); - } - - String getPath() { - Pointer path = _bindings.spine_region_attachment_get_path(_attachment).cast(); - return path.toDartString(); - } - - TextureRegion? getRegion() { - final region = _bindings.spine_region_attachment_get_region(_attachment); - if (region.address == nullptr.address) return null; - return TextureRegion._(region); - } - - Sequence? getSequence() { - final sequence = _bindings.spine_region_attachment_get_sequence(_attachment); - if (sequence.address == nullptr.address) return null; - return Sequence._(sequence); - } - - /// For each of the 4 vertices, a pair of `x,y` values that is the local position of the vertex. - /// - /// See [updateRegion]. - Float32List getOffset() { - final num = _bindings.spine_region_attachment_get_num_offset(_attachment); - final offset = _bindings.spine_region_attachment_get_offset(_attachment); - return offset.asTypedList(num); - } - - Float32List getUVs() { - final num = _bindings.spine_region_attachment_get_num_uvs(_attachment); - final uvs = _bindings.spine_region_attachment_get_uvs(_attachment); - return uvs.asTypedList(num); - } -} - -/// Base class for an attachment with vertices that are transformed by one or more bones and can be deformed by a slot's -/// [Slot.getDeform]. -class VertexAttachment extends Attachment { - VertexAttachment._(super.attachment) : super._(); - - /// Transforms and returns the attachment's local [getVertices] to world coordinates. If the slot's [Slot.getDeform] is - /// not empty, it is used to deform the vertices. - - /// See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine - /// Runtimes Guide. - List computeWorldVertices(Slot slot) { - final worldVerticesLength = _bindings.spine_vertex_attachment_get_world_vertices_length(_attachment.cast()); - Pointer vertices = _allocator.allocate(4 * worldVerticesLength).cast(); - _bindings.spine_vertex_attachment_compute_world_vertices(_attachment.cast(), slot._slot, vertices); - final result = vertices.asTypedList(worldVerticesLength).toList(); - _allocator.free(vertices); - return result; - } - - /// The bones which affect the [getVertices]. The array entries are, for each vertex, the number of bones affecting - /// the vertex followed by that many bone indices, which is the index of the bone in [Skeleton.getBones]. Will be null - /// if this attachment has no weights. - Int32List getBones() { - final num = _bindings.spine_vertex_attachment_get_num_bones(_attachment.cast()); - final bones = _bindings.spine_vertex_attachment_get_bones(_attachment.cast()); - return bones.asTypedList(num); - } - - /// The vertex positions in the bone's coordinate system. For a non-weighted attachment, the values are `x,y` - /// entries for each vertex. For a weighted attachment, the values are `x,y,weight` entries for each bone affecting - /// each vertex. - Float32List getVertices() { - final num = _bindings.spine_vertex_attachment_get_num_vertices(_attachment.cast()); - final vertices = _bindings.spine_vertex_attachment_get_vertices(_attachment.cast()); - return vertices.asTypedList(num); - } - - /// Timelines for the timeline attachment are also applied to this attachment. May return `null` if not - /// attachment-specific timelines should be applied. - Attachment? getTimelineAttachment() { - final attachment = _bindings.spine_vertex_attachment_get_timeline_attachment(_attachment.cast()); - if (_attachment.address == nullptr.address) return null; - return Attachment._toSubclass(attachment); - } - - void setTimelineAttachment(Attachment? attachment) { - _bindings.spine_vertex_attachment_set_timeline_attachment( - _attachment.cast(), - attachment == null ? nullptr : attachment._attachment.cast(), - ); - } -} - -/// An attachment that displays a textured mesh. A mesh has hull vertices and internal vertices within the hull. Holes are not -/// supported. Each vertex has UVs (texture coordinates) and triangles are used to map an image on to the mesh. -/// -/// See [Mesh attachments](http://esotericsoftware.com/spine-meshes) in the Spine User Guide. -class MeshAttachment extends VertexAttachment { - MeshAttachment._(spine_mesh_attachment attachment) : super._(attachment.cast()); - - /// Calculates texture coordinates returned by [getUVs] using the coordinates returned by [getRegionUVs] and region. Must be called if - /// the region, the region's properties, or the [getRegionUVs] are changed. - void updateRegion() { - _bindings.spine_mesh_attachment_update_region(_attachment); - } - - /// The number of entries at the beginning of {@link #vertices} that make up the mesh hull. - int getHullLength() { - return _bindings.spine_mesh_attachment_get_hull_length(_attachment); - } - - void setHullLength(int hullLength) { - _bindings.spine_mesh_attachment_set_hull_length(_attachment, hullLength); - } - - /// The UV pair for each vertex, normalized within the texture region. - Float32List getRegionUVs() { - final num = _bindings.spine_mesh_attachment_get_num_region_uvs(_attachment); - final uvs = _bindings.spine_mesh_attachment_get_region_uvs(_attachment); - return uvs.asTypedList(num); - } - - /// The UV pair for each vertex, normalized within the entire texture. - /// - /// See [updateRegion]. - Float32List getUVs() { - final num = _bindings.spine_mesh_attachment_get_num_uvs(_attachment); - final uvs = _bindings.spine_mesh_attachment_get_uvs(_attachment); - return uvs.asTypedList(num); - } - - /// Triplets of vertex indices which describe the mesh's triangulation. - Uint16List getTriangles() { - final num = _bindings.spine_mesh_attachment_get_num_triangles(_attachment); - final triangles = _bindings.spine_mesh_attachment_get_triangles(_attachment); - return triangles.asTypedList(num); - } - - Color getColor() { - final color = _bindings.spine_mesh_attachment_get_color(_attachment); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(double r, double g, double b, double a) { - _bindings.spine_mesh_attachment_set_color(_attachment, r, g, b, a); - } - - String getPath() { - Pointer path = _bindings.spine_mesh_attachment_get_path(_attachment).cast(); - return path.toDartString(); - } - - TextureRegion? getRegion() { - final region = _bindings.spine_mesh_attachment_get_region(_attachment); - if (region.address == nullptr.address) return null; - return TextureRegion._(region); - } - - Sequence? getSequence() { - final sequence = _bindings.spine_mesh_attachment_get_sequence(_attachment); - if (sequence.address == nullptr.address) return null; - return Sequence._(sequence); - } - - /// The parent mesh if this is a linked mesh, else null. A linked mesh shares the bones, vertices, - /// region UVs, triangles, hull length, edges, width, and height with the - /// parent mesh, but may have a different name or path (and therefore a different texture). - MeshAttachment? getParentMesh() { - final parent = _bindings.spine_mesh_attachment_get_parent_mesh(_attachment); - if (parent.address == nullptr.address) return null; - return MeshAttachment._(parent); - } - - void setParentMesh(MeshAttachment? parentMesh) { - _bindings.spine_mesh_attachment_set_parent_mesh(_attachment, parentMesh == null ? nullptr : parentMesh._attachment); - } - - /// Vertex index pairs describing edges for controlling triangulation, or be null if nonessential data was not exported. Mesh - /// triangles will never cross edges. Triangulation is not performed at runtime. - Uint16List getEdges() { - final num = _bindings.spine_mesh_attachment_get_num_edges(_attachment); - final edges = _bindings.spine_mesh_attachment_get_edges(_attachment); - return edges.asTypedList(num); - } - - /// The width of the mesh's image, or zero if nonessential data was not exported. - double getWidth() { - return _bindings.spine_mesh_attachment_get_width(_attachment); - } - - void setWidth(double width) { - _bindings.spine_mesh_attachment_set_width(_attachment, width); - } - - /// The height of the mesh's image, or zero if nonessential data was not exported. - double getHeight() { - return _bindings.spine_mesh_attachment_get_height(_attachment); - } - - void setHeight(double height) { - _bindings.spine_mesh_attachment_set_height(_attachment, height); - } -} - -/// An attachment with vertices that make up a polygon used for clipping the rendering of other attachments. -class ClippingAttachment extends VertexAttachment { - ClippingAttachment._(spine_clipping_attachment attachment) : super._(attachment.cast()); - - /// Clipping is performed between the clipping attachment's slot and the end slot. If null clipping is done until the end of - /// the skeleton's rendering. - SlotData? getEndSlot() { - final endSlot = _bindings.spine_clipping_attachment_get_end_slot(_attachment); - if (endSlot.address == nullptr.address) return null; - return SlotData._(endSlot); - } - - void setEndSlot(SlotData? endSlot) { - _bindings.spine_clipping_attachment_set_end_slot(_attachment, endSlot == null ? nullptr : endSlot._data); - } - - /// The color of the clipping attachment as it was in Spine, or a default color if nonessential data was not exported. Clipping - /// attachments are not usually rendered at runtime. - Color getColor() { - final color = _bindings.spine_clipping_attachment_get_color(_attachment); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(double r, double g, double b, double a) { - _bindings.spine_clipping_attachment_set_color(_attachment, r, g, b, a); - } -} - -/// An attachment with vertices that make up a polygon. Can be used for hit detection, creating physics bodies, spawning particle -/// effects, and more. -/// -/// See [SkeletonBounds] and [Bounding boxes](http://esotericsoftware.com/spine-bounding-boxes) in the Spine User -/// Guide. -class BoundingBoxAttachment extends VertexAttachment { - BoundingBoxAttachment._(super.attachment) : super._(); - - /// The color of the bounding box as it was in Spine, or a default color if nonessential data was not exported. Bounding boxes - /// are not usually rendered at runtime. - Color getColor() { - final color = _bindings.spine_bounding_box_attachment_get_color(_attachment); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(double r, double g, double b, double a) { - _bindings.spine_bounding_box_attachment_set_color(_attachment, r, g, b, a); - } -} - -/// An attachment whose vertices make up a composite Bezier curve. -/// -/// See [PathConstraint] and [Paths](http://esotericsoftware.com/spine-paths) in the Spine User Guide. -class PathAttachment extends VertexAttachment { - PathAttachment._(super.attachment) : super._(); - - /// The lengths along the path in the setup pose from the start of the path to the end of each Bezier curve. - Float32List getLengths() { - final num = _bindings.spine_path_attachment_get_num_lengths(_attachment); - final lengths = _bindings.spine_path_attachment_get_lengths(_attachment); - return lengths.asTypedList(num); - } - - /// If true, the start and end knots are connected. - bool isClosed() { - return _bindings.spine_path_attachment_get_is_closed(_attachment) == -1; - } - - void setIsClosed(bool isClosed) { - _bindings.spine_path_attachment_set_is_closed(_attachment, isClosed ? -1 : 0); - } - - /// If true, additional calculations are performed to make computing positions along the path more accurate and movement along - /// the path have a constant speed. - bool isConstantSpeed() { - return _bindings.spine_path_attachment_get_is_constant_speed(_attachment) == -1; - } - - void setIsConstantSpeed(bool isClosed) { - _bindings.spine_path_attachment_set_is_constant_speed(_attachment, isClosed ? -1 : 0); - } - - /// The color of the path as it was in Spine, or a default color if nonessential data was not exported. Paths are not usually - /// rendered at runtime. - Color getColor() { - final color = _bindings.spine_path_attachment_get_color(_attachment); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(double r, double g, double b, double a) { - _bindings.spine_path_attachment_set_color(_attachment, r, g, b, a); - } -} - -/// An attachment which is a single point and a rotation. This can be used to spawn projectiles, particles, etc. A bone can be -/// used in similar ways, but a PointAttachment is slightly less expensive to compute and can be hidden, shown, and placed in a -/// skin. -/// -/// See [Point Attachments](https://esotericsoftware.com/spine-points) in the Spine User Guide. -class PointAttachment extends Attachment { - PointAttachment._(super.attachment) : super._(); - - Vec2 computeWorldPosition(Bone bone) { - final position = _bindings.spine_point_attachment_compute_world_position(_attachment, bone._bone); - final result = Vec2(_bindings.spine_vector_get_x(position), _bindings.spine_vector_get_y(position)); - return result; - } - - double computeWorldRotation(Bone bone) { - return _bindings.spine_point_attachment_compute_world_rotation(_attachment, bone._bone); - } - - double getX() { - return _bindings.spine_point_attachment_get_x(_attachment); - } - - void setX(double x) { - _bindings.spine_point_attachment_set_x(_attachment, x); - } - - double getY() { - return _bindings.spine_point_attachment_get_y(_attachment); - } - - void setY(double y) { - _bindings.spine_point_attachment_set_y(_attachment, y); - } - - double getRotation() { - return _bindings.spine_point_attachment_get_rotation(_attachment); - } - - void setRotation(double rotation) { - _bindings.spine_point_attachment_set_x(_attachment, rotation); - } - - /// The color of the point attachment as it was in Spine, or a default clor if nonessential data was not exported. Point - /// attachments are not usually rendered at runtime. - Color getColor() { - final color = _bindings.spine_point_attachment_get_color(_attachment); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(double r, double g, double b, double a) { - _bindings.spine_point_attachment_set_color(_attachment, r, g, b, a); - } -} - -/// An entry storing the attachment to be used for a specific slot within [Skin]. -class SkinEntry { - final int slotIndex; - final String name; - final Attachment? attachment; - - SkinEntry(this.slotIndex, this.name, this.attachment); -} - -/// Stores attachments by slot index and attachment name. -/// -/// Skins constructed manually via the `Skin(String name)` constructor must be manually disposed via the [dipose] method if they -/// are no longer used. -/// -/// See [SkeletonData.defaultSkin], [Skeleton.getSkin}, and [Runtime skins](http://esotericsoftware.com/spine-runtime-skins) in the -/// Spine Runtimes Guide. -class Skin { - late final bool _isCustomSkin; - late final spine_skin _skin; - - Skin._(this._skin) : _isCustomSkin = false; - - /// Constructs a new empty skin using the given [name]. Skins constructed this way must be manually disposed via the [dispose] method - /// if they are no longer used. - Skin(String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - _skin = _bindings.spine_skin_create(nativeName.cast()); - _allocator.free(nativeName); - _isCustomSkin = true; - } - - /// Diposes this skin. - void dispose() { - if (!_isCustomSkin) return; - _bindings.spine_skin_dispose(_skin); - } - - /// Adds an attachment to the skin for the specified slot index and name. - void setAttachment(int slotIndex, String name, Attachment? attachment) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - _bindings.spine_skin_set_attachment( - _skin, - slotIndex, - nativeName.cast(), - attachment == null ? nullptr : attachment._attachment.cast(), - ); - _allocator.free(nativeName); - } - - /// Returns the attachment for the specified slot index and name, or null. - Attachment? getAttachment(int slotIndex, String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - final attachment = _bindings.spine_skin_get_attachment(_skin, slotIndex, nativeName.cast()); - _allocator.free(nativeName); - if (attachment.address == nullptr.address) return null; - return Attachment._toSubclass(attachment); - } - - /// Removes the attachment in the skin for the specified slot index and name, if any. - void removeAttachment(int slotIndex, String name) { - final nativeName = name.toNativeUtf8(allocator: _allocator); - _bindings.spine_skin_remove_attachment(_skin, slotIndex, nativeName.cast()); - _allocator.free(nativeName); - } - - /// The skin's name, which is unique across all skins in the skeleton. - String getName() { - Pointer name = _bindings.spine_skin_get_name(_skin).cast(); - return name.toDartString(); - } - - /// Adds all attachments, bones, and constraints from the specified skin to this skin. - void addSkin(Skin other) { - _bindings.spine_skin_add_skin(_skin, other._skin); - } - - /// Returns all entries in this skin. - List getEntries() { - List result = []; - final entries = _bindings.spine_skin_get_entries(_skin); - int numEntries = _bindings.spine_skin_entries_get_num_entries(entries); - for (int i = 0; i < numEntries; i++) { - final entry = _bindings.spine_skin_entries_get_entry(entries, i); - Pointer name = _bindings.spine_skin_entry_get_name(entry).cast(); - result.add( - SkinEntry( - _bindings.spine_skin_entry_get_slot_index(entry), - name.toDartString(), - _bindings.spine_skin_entry_get_attachment(entry).address == nullptr.address - ? null - : Attachment._toSubclass(_bindings.spine_skin_entry_get_attachment(entry)), - ), - ); - } - return result; - } - - List getBones() { - List bones = []; - final numBones = _bindings.spine_skin_get_num_bones(_skin); - final nativeBones = _bindings.spine_skin_get_bones(_skin); - for (int i = 0; i < numBones; i++) { - bones.add(BoneData._(nativeBones[i])); - } - return bones; - } - - List getConstraints() { - List constraints = []; - final numConstraints = _bindings.spine_skin_get_num_constraints(_skin); - final nativeConstraints = _bindings.spine_skin_get_constraints(_skin); - for (int i = 0; i < numConstraints; i++) { - final nativeConstraint = nativeConstraints[i]; - final type = _bindings.spine_constraint_data_get_type(nativeConstraint); - switch (type) { - case spine_constraint_type.SPINE_CONSTRAINT_IK: - constraints.add(IkConstraintData._(nativeConstraint.cast())); - break; - case spine_constraint_type.SPINE_CONSTRAINT_TRANSFORM: - constraints.add(TransformConstraintData._(nativeConstraint.cast())); - break; - case spine_constraint_type.SPINE_CONSTRAINT_PATH: - constraints.add(PathConstraintData._(nativeConstraint.cast())); - break; - } - } - return constraints; - } - - /// Adds all bones and constraints and copies of all attachments from the specified skin to this skin. Mesh attachments are not - /// copied, instead a new linked mesh is created. The attachment copies can be modified without affecting the originals. - void copy(Skin other) { - _bindings.spine_skin_copy_skin(_skin, other._skin); - } -} - -/// The base class for all constraint datas. -class ConstraintData { - final T _data; - - ConstraintData._(this._data); - - /// The constraint's name, which is unique across all constraints in the skeleton of the same type. - String getName() { - final Pointer name = _bindings.spine_constraint_data_get_name(_data.cast()).cast(); - return name.toDartString(); - } - - /// The ordinal of this constraint for the order a skeleton's constraints will be applied by - /// [Skeleton.updateWorldTransform]. - int getOrder() { - return _bindings.spine_constraint_data_get_order(_data.cast()); - } - - void setOrder(int order) { - _bindings.spine_constraint_data_set_order(_data.cast(), order); - } - - /// When true, [Skeleton.updateWorldTransform] only updates this constraint if the skin returned by [Skeleton.getSkin] contains - /// this constraint. - /// - /// See [Skin.getConstraints]. - bool isSkinRequired() { - return _bindings.spine_constraint_data_get_is_skin_required(_data.cast()) == 1; - } - - void setIsSkinRequired(bool isSkinRequired) { - _bindings.spine_constraint_data_set_is_skin_required(_data.cast(), isSkinRequired ? -1 : 0); - } -} - -/// Stores the setup pose for an [IkConstraint]. -/// -/// See [IK constraints](http://esotericsoftware.com/spine-ik-constraints) in the Spine User Guide. -class IkConstraintData extends ConstraintData { - IkConstraintData._(super.data) : super._(); - - /// The bones that are constrained by this IK constraint. - List getBones() { - final List result = []; - final numBones = _bindings.spine_ik_constraint_data_get_num_bones(_data); - final nativeBones = _bindings.spine_ik_constraint_data_get_bones(_data); - for (int i = 0; i < numBones; i++) { - result.add(BoneData._(nativeBones[i])); - } - return result; - } - - /// The bone that is the IK target. - BoneData getTarget() { - return BoneData._(_bindings.spine_ik_constraint_data_get_target(_data)); - } - - void setTarget(BoneData target) { - _bindings.spine_ik_constraint_data_set_target(_data, target._data); - } - - /// For two bone IK, controls the bend direction of the IK bones, either 1 or -1. - int getBendDirection() { - return _bindings.spine_ik_constraint_data_get_bend_direction(_data); - } - - void setBendDirection(int bendDirection) { - _bindings.spine_ik_constraint_data_set_bend_direction(_data, bendDirection); - } - - /// For one bone IK, when true and the target is too close, the bone is scaled to reach it. - bool getCompress() { - return _bindings.spine_ik_constraint_data_get_compress(_data) == -1; - } - - void setCompress(bool compress) { - _bindings.spine_ik_constraint_data_set_compress(_data, compress ? -1 : 0); - } - - /// When true and the target is out of range, the parent bone is scaled to reach it. - /// - /// For two bone IK: 1) the child bone's local Y translation is set to 0, 2) stretch is not applied if [getSoftness] is - /// > 0, and 3) if the parent bone has local nonuniform scale, stretch is not applied. - bool getStretch() { - return _bindings.spine_ik_constraint_data_get_stretch(_data) == -1; - } - - void setStretch(bool stretch) { - _bindings.spine_ik_constraint_data_set_stretch(_data, stretch ? -1 : 0); - } - - /// When true and [getCompress] or [getStretch] is used, the bone is scaled on both the X and Y axes. - bool getUniform() { - return _bindings.spine_ik_constraint_data_get_uniform(_data) == -1; - } - - void setUniform(bool uniform) { - _bindings.spine_ik_constraint_data_set_uniform(_data, uniform ? -1 : 0); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. - /// - /// For two bone IK: if the parent bone has local nonuniform scale, the child bone's local Y translation is set to 0. - double getMix() { - return _bindings.spine_ik_constraint_data_get_mix(_data); - } - - void setMix(double mix) { - _bindings.spine_ik_constraint_data_set_mix(_data, mix); - } - - /// For two bone IK, the target bone's distance from the maximum reach of the bones where rotation begins to slow. The bones - /// will not straighten completely until the target is this far out of range. - double getSoftness() { - return _bindings.spine_ik_constraint_data_get_softness(_data); - } - - void setSoftness(double softness) { - _bindings.spine_ik_constraint_data_set_softness(_data, softness); - } -} - -/// Stores the current pose for an IK constraint. An IK constraint adjusts the rotation of 1 or 2 constrained bones so the tip of -/// the last bone is as close to the target bone as possible. -///

-/// See IK constraints in the Spine User Guide. -class IkConstraint { - final spine_ik_constraint _constraint; - - IkConstraint._(this._constraint); - - /// Applies the constraint to the constrained bones. - void update() { - _bindings.spine_ik_constraint_update(_constraint); - } - - int getOrder() { - return _bindings.spine_ik_constraint_get_order(_constraint); - } - - /// The IK constraint's setup pose data. - IkConstraintData getData() { - return IkConstraintData._(_bindings.spine_ik_constraint_get_data(_constraint)); - } - - /// The bones that will be modified by this IK constraint. - List getBones() { - List result = []; - final num = _bindings.spine_ik_constraint_get_num_bones(_constraint); - final nativeBones = _bindings.spine_ik_constraint_get_bones(_constraint); - for (int i = 0; i < num; i++) { - result.add(Bone._(nativeBones[i])); - } - return result; - } - - /// The bone that is the IK target. - Bone getTarget() { - return Bone._(_bindings.spine_ik_constraint_get_target(_constraint)); - } - - void setTarget(Bone target) { - _bindings.spine_ik_constraint_set_target(_constraint, target._bone); - } - - /// For two bone IK, controls the bend direction of the IK bones, either 1 or -1. - int getBendDirection() { - return _bindings.spine_ik_constraint_get_bend_direction(_constraint); - } - - void setBendDirection(int bendDirection) { - _bindings.spine_ik_constraint_set_bend_direction(_constraint, bendDirection); - } - - /// For one bone IK, when true and the target is too close, the bone is scaled to reach it. - bool getCompress() { - return _bindings.spine_ik_constraint_get_compress(_constraint) == -1; - } - - void setCompress(bool compress) { - _bindings.spine_ik_constraint_set_compress(_constraint, compress ? -1 : 0); - } - - /// When true and the target is out of range, the parent bone is scaled to reach it. - /// - /// For two bone IK: 1) the child bone's local Y translation is set to 0, 2) stretch is not applied if [getSoftness] is - /// > 0, and 3) if the parent bone has local nonuniform scale, stretch is not applied. - bool getStretch() { - return _bindings.spine_ik_constraint_get_stretch(_constraint) == -1; - } - - void setStretch(bool stretch) { - _bindings.spine_ik_constraint_set_stretch(_constraint, stretch ? -1 : 0); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. - /// - /// For two bone IK: if the parent bone has local nonuniform scale, the child bone's local Y translation is set to 0. - double getMix() { - return _bindings.spine_ik_constraint_get_mix(_constraint); - } - - void setMix(double mix) { - _bindings.spine_ik_constraint_set_mix(_constraint, mix); - } - - /// For two bone IK, the target bone's distance from the maximum reach of the bones where rotation begins to slow. The bones - /// will not straighten completely until the target is this far out of range. - double getSoftness() { - return _bindings.spine_ik_constraint_get_softness(_constraint); - } - - void setSoftness(double softness) { - _bindings.spine_ik_constraint_set_softness(_constraint, softness); - } - - bool isActive() { - return _bindings.spine_ik_constraint_get_is_active(_constraint) == -1; - } - - void setIsActive(bool isActive) { - _bindings.spine_ik_constraint_set_is_active(_constraint, isActive ? -1 : 0); - } -} - -/// Stores the setup pose for a {@link TransformConstraint}. -/// -/// See [Transform constraints](http://esotericsoftware.com/spine-transform-constraints) in the Spine User Guide. -class TransformConstraintData extends ConstraintData { - TransformConstraintData._(super.data) : super._(); - - /// The bones that will be modified by this transform constraint. - List getBones() { - final List result = []; - final numBones = _bindings.spine_transform_constraint_data_get_num_bones(_data); - final nativeBones = _bindings.spine_transform_constraint_data_get_bones(_data); - for (int i = 0; i < numBones; i++) { - result.add(BoneData._(nativeBones[i])); - } - return result; - } - - /// The target bone whose world transform will be copied to the constrained bones. - BoneData getTarget() { - return BoneData._(_bindings.spine_transform_constraint_data_get_target(_data)); - } - - void setTarget(BoneData target) { - _bindings.spine_transform_constraint_data_set_target(_data, target._data); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. - double getMixRotate() { - return _bindings.spine_transform_constraint_data_get_mix_rotate(_data); - } - - void setMixRotate(double mixRotate) { - _bindings.spine_transform_constraint_data_set_mix_rotate(_data, mixRotate); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. - double getMixX() { - return _bindings.spine_transform_constraint_data_get_mix_x(_data); - } - - void setMixX(double mixX) { - _bindings.spine_transform_constraint_data_set_mix_x(_data, mixX); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. - double getMixY() { - return _bindings.spine_transform_constraint_data_get_mix_y(_data); - } - - void setMixY(double mixY) { - _bindings.spine_transform_constraint_data_set_mix_y(_data, mixY); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. - double getMixScaleX() { - return _bindings.spine_transform_constraint_data_get_mix_scale_x(_data); - } - - void setMixScaleX(double mixScaleX) { - _bindings.spine_transform_constraint_data_set_mix_scale_x(_data, mixScaleX); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained scale Y. - double getMixScaleY() { - return _bindings.spine_transform_constraint_data_get_mix_scale_y(_data); - } - - void setMixScaleY(double mixScaleY) { - _bindings.spine_transform_constraint_data_set_mix_scale_y(_data, mixScaleY); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained shear Y. - double getMixShearY() { - return _bindings.spine_transform_constraint_data_get_mix_shear_y(_data); - } - - void setMixShearY(double mixShearY) { - _bindings.spine_transform_constraint_data_set_mix_shear_y(_data, mixShearY); - } - - /// An offset added to the constrained bone rotation. - double getOffsetRotation() { - return _bindings.spine_transform_constraint_data_get_offset_rotation(_data); - } - - void setOffsetRotation(double offsetRotation) { - _bindings.spine_transform_constraint_data_set_offset_rotation(_data, offsetRotation); - } - - /// An offset added to the constrained bone X translation. - double getOffsetX() { - return _bindings.spine_transform_constraint_data_get_offset_x(_data); - } - - void setOffsetX(double offsetX) { - _bindings.spine_transform_constraint_data_set_offset_x(_data, offsetX); - } - - /// An offset added to the constrained bone Y translation. - double getOffsetY() { - return _bindings.spine_transform_constraint_data_get_offset_y(_data); - } - - /// An offset added to the constrained bone scaleX. - void setOffsetY(double offsetY) { - _bindings.spine_transform_constraint_data_set_offset_y(_data, offsetY); - } - - /// An offset added to the constrained bone scaleX. - double getOffsetScaleX() { - return _bindings.spine_transform_constraint_data_get_offset_scale_x(_data); - } - - void setOffsetScaleX(double offsetScaleX) { - _bindings.spine_transform_constraint_data_set_offset_x(_data, offsetScaleX); - } - - /// An offset added to the constrained bone scaleY. - double getOffsetScaleY() { - return _bindings.spine_transform_constraint_data_get_offset_scale_y(_data); - } - - void setOffsetScaleY(double offsetScaleY) { - _bindings.spine_transform_constraint_data_set_offset_scale_y(_data, offsetScaleY); - } - - /// An offset added to the constrained bone shearY. - double getOffsetShearY() { - return _bindings.spine_transform_constraint_data_get_offset_shear_y(_data); - } - - void setOffsetShearY(double offsetShearY) { - _bindings.spine_transform_constraint_data_set_offset_shear_y(_data, offsetShearY); - } - - bool isRelative() { - return _bindings.spine_transform_constraint_data_get_is_relative(_data) == -1; - } - - void setIsRelative(bool isRelative) { - _bindings.spine_transform_constraint_data_set_is_relative(_data, isRelative ? -1 : 0); - } - - bool isLocal() { - return _bindings.spine_transform_constraint_data_get_is_local(_data) == -1; - } - - void setIsLocal(bool isLocal) { - _bindings.spine_transform_constraint_data_set_is_local(_data, isLocal ? -1 : 0); - } -} - -/// Stores the current pose for a transform constraint. A transform constraint adjusts the world transform of the constrained -/// bones to match that of the target bone. -/// -/// See [Transform constraints](http://esotericsoftware.com/spine-transform-constraints) in the Spine User Guide. -class TransformConstraint { - final spine_transform_constraint _constraint; - - TransformConstraint._(this._constraint); - - /// Applies the constraint to the constrained bones. - void update() { - _bindings.spine_transform_constraint_update(_constraint); - } - - int getOrder() { - return _bindings.spine_transform_constraint_get_order(_constraint); - } - - /// The transform constraint's setup pose data. - TransformConstraintData getData() { - return TransformConstraintData._(_bindings.spine_transform_constraint_get_data(_constraint)); - } - - /// The bones that will be modified by this transform constraint. - List getBones() { - List result = []; - final num = _bindings.spine_transform_constraint_get_num_bones(_constraint); - final nativeBones = _bindings.spine_transform_constraint_get_bones(_constraint); - for (int i = 0; i < num; i++) { - result.add(Bone._(nativeBones[i])); - } - return result; - } - - /// The target bone whose world transform will be copied to the constrained bones. - Bone getTarget() { - return Bone._(_bindings.spine_transform_constraint_get_target(_constraint)); - } - - void setTarget(Bone target) { - _bindings.spine_transform_constraint_set_target(_constraint, target._bone); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. - double getMixRotate() { - return _bindings.spine_transform_constraint_get_mix_rotate(_constraint); - } - - void setMixRotate(double mixRotate) { - _bindings.spine_transform_constraint_set_mix_rotate(_constraint, mixRotate); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. - double getMixX() { - return _bindings.spine_transform_constraint_get_mix_x(_constraint); - } - - void setMixX(double mixX) { - _bindings.spine_transform_constraint_set_mix_x(_constraint, mixX); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. - double getMixY() { - return _bindings.spine_transform_constraint_get_mix_y(_constraint); - } - - void setMixY(double mixY) { - _bindings.spine_transform_constraint_set_mix_y(_constraint, mixY); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. - double getMixScaleX() { - return _bindings.spine_transform_constraint_get_mix_scale_x(_constraint); - } - - void setMixScaleX(double mixScaleX) { - _bindings.spine_transform_constraint_set_mix_scale_x(_constraint, mixScaleX); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. - double getMixScaleY() { - return _bindings.spine_transform_constraint_get_mix_scale_y(_constraint); - } - - void setMixScaleY(double mixScaleY) { - _bindings.spine_transform_constraint_set_mix_scale_y(_constraint, mixScaleY); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained shear Y. - double getMixShearY() { - return _bindings.spine_transform_constraint_get_mix_shear_y(_constraint); - } - - void setMixShearY(double mixShearY) { - _bindings.spine_transform_constraint_set_mix_shear_y(_constraint, mixShearY); - } - - bool isActive() { - return _bindings.spine_transform_constraint_get_is_active(_constraint) == -1; - } - - void setIsActive(bool isActive) { - _bindings.spine_transform_constraint_set_is_active(_constraint, isActive ? -1 : 0); - } -} - -/// Stores the setup pose for a [PathConstraint]. -/// -/// See [Path constraints](http://esotericsoftware.com/spine-path-constraints) in the Spine User Guide. -class PathConstraintData extends ConstraintData { - PathConstraintData._(super.data) : super._(); - - /// The bones that will be modified by this path constraint. - List getBones() { - final List result = []; - final numBones = _bindings.spine_path_constraint_data_get_num_bones(_data); - final nativeBones = _bindings.spine_path_constraint_data_get_bones(_data); - for (int i = 0; i < numBones; i++) { - result.add(BoneData._(nativeBones[i])); - } - return result; - } - - /// The slot whose path attachment will be used to constrained the bones. - SlotData getTarget() { - return SlotData._(_bindings.spine_path_constraint_data_get_target(_data)); - } - - void setTarget(SlotData target) { - _bindings.spine_path_constraint_data_set_target(_data, target._data); - } - - /// The mode for positioning the first bone on the path. - PositionMode getPositionMode() { - return PositionMode.values[_bindings.spine_path_constraint_data_get_position_mode(_data)]; - } - - void setPositionMode(PositionMode positionMode) { - _bindings.spine_path_constraint_data_set_position_mode(_data, positionMode.value); - } - - /// The mode for positioning the bones after the first bone on the path. - SpacingMode getSpacingMode() { - return SpacingMode.values[_bindings.spine_path_constraint_data_get_spacing_mode(_data)]; - } - - void setSpacingMode(SpacingMode spacingMode) { - _bindings.spine_path_constraint_data_set_spacing_mode(_data, spacingMode.value); - } - - /// The mode for adjusting the rotation of the bones. - RotateMode getRotateMode() { - return RotateMode.values[_bindings.spine_path_constraint_data_get_rotate_mode(_data)]; - } - - void setRotateMode(RotateMode rotateMode) { - _bindings.spine_path_constraint_data_set_rotate_mode(_data, rotateMode.value); - } - - /// An offset added to the constrained bone rotation. - double getOffsetRotation() { - return _bindings.spine_path_constraint_data_get_offset_rotation(_data); - } - - void setOffsetRotation(double offsetRotation) { - _bindings.spine_path_constraint_data_set_offset_rotation(_data, offsetRotation); - } - - /// The position along the path. - double getPosition() { - return _bindings.spine_path_constraint_data_get_position(_data); - } - - void setPosition(double position) { - _bindings.spine_path_constraint_data_set_position(_data, position); - } - - /// The spacing between bones. - double getSpacing() { - return _bindings.spine_path_constraint_data_get_spacing(_data); - } - - void setSpacing(double spacing) { - _bindings.spine_path_constraint_data_set_spacing(_data, spacing); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. - double getMixRotate() { - return _bindings.spine_path_constraint_data_get_mix_rotate(_data); - } - - void setMixRotate(double mixRotate) { - _bindings.spine_path_constraint_data_set_mix_rotate(_data, mixRotate); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. - double getMixX() { - return _bindings.spine_path_constraint_data_get_mix_x(_data); - } - - void setMixX(double mixX) { - _bindings.spine_path_constraint_data_set_mix_x(_data, mixX); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. - double getMixY() { - return _bindings.spine_path_constraint_data_get_mix_x(_data); - } - - void setMixY(double mixY) { - _bindings.spine_path_constraint_data_set_mix_y(_data, mixY); - } -} - -/// Stores the current pose for a path constraint. A path constraint adjusts the rotation, translation, and scale of the -/// constrained bones so they follow a [PathAttachment]. -/// -/// See [Path constraints](http://esotericsoftware.com/spine-path-constraints) in the Spine User Guide. -class PathConstraint { - final spine_path_constraint _constraint; - - PathConstraint._(this._constraint); - - /// Applies the constraint to the constrained bones. - void update() { - _bindings.spine_path_constraint_update(_constraint); - } - - int getOrder() { - return _bindings.spine_path_constraint_get_order(_constraint); - } - - /// The bones that will be modified by this path constraint. - List getBones() { - List result = []; - final num = _bindings.spine_path_constraint_get_num_bones(_constraint); - final nativeBones = _bindings.spine_path_constraint_get_bones(_constraint); - for (int i = 0; i < num; i++) { - result.add(Bone._(nativeBones[i])); - } - return result; - } - - /// The slot whose path attachment will be used to constrained the bones. - Slot getTarget() { - return Slot._(_bindings.spine_path_constraint_get_target(_constraint)); - } - - void setTarget(Slot target) { - _bindings.spine_path_constraint_set_target(_constraint, target._slot); - } - - /// The position along the path. - double getPosition() { - return _bindings.spine_path_constraint_get_position(_constraint); - } - - void setPosition(double position) { - _bindings.spine_path_constraint_set_position(_constraint, position); - } - - /// The spacing between bones. - double getSpacing() { - return _bindings.spine_path_constraint_get_spacing(_constraint); - } - - void setSpacing(double spacing) { - _bindings.spine_path_constraint_set_spacing(_constraint, spacing); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. - double getMixRotate() { - return _bindings.spine_path_constraint_get_mix_rotate(_constraint); - } - - void setMixRotate(double mixRotate) { - _bindings.spine_path_constraint_set_mix_rotate(_constraint, mixRotate); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. - double getMixX() { - return _bindings.spine_path_constraint_get_mix_x(_constraint); - } - - void setMixX(double mixX) { - _bindings.spine_path_constraint_set_mix_x(_constraint, mixX); - } - - /// A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. - double getMixY() { - return _bindings.spine_path_constraint_get_mix_y(_constraint); - } - - void setMixY(double mixY) { - _bindings.spine_path_constraint_set_mix_y(_constraint, mixY); - } - - bool isActive() { - return _bindings.spine_path_constraint_get_is_active(_constraint) == -1; - } - - void setIsActive(bool isActive) { - _bindings.spine_path_constraint_set_is_active(_constraint, isActive ? -1 : 0); - } -} - -/// Stores the current pose for a skeleton. -/// -/// See [Instance objects](http://esotericsoftware.com/spine-runtime-architecture#Instance-objects) in the Spine -/// Runtimes Guide. -class Skeleton { - final spine_skeleton _skeleton; - - Skeleton._(this._skeleton); - - /// Caches information about bones and constraints. Must be called if the [getSkin] is modified or if bones, - /// constraints, or weighted path attachments are added or removed. - void updateCache() { - _bindings.spine_skeleton_update_cache(_skeleton); - } - - /// Updates the world transform for each bone and applies all constraints. - /// - /// See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine - /// Runtimes Guide. - void updateWorldTransform(Physics physics) { - _bindings.spine_skeleton_update_world_transform(_skeleton, physics.value); - } - - /// Temporarily sets the root bone as a child of the specified bone, then updates the world transform for each bone and applies - /// all constraints. - /// - /// See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine - /// Runtimes Guide. - void updateWorldTransformBone(Physics physics, Bone parent) { - _bindings.spine_skeleton_update_world_transform_bone(_skeleton, physics.value, parent._bone); - } - - /// Sets the bones, constraints, slots, and draw order to their setup pose values. - void setToSetupPose() { - _bindings.spine_skeleton_set_to_setup_pose(_skeleton); - } - - /// Sets the bones and constraints to their setup pose values. - void setBonesToSetupPose() { - _bindings.spine_skeleton_set_bones_to_setup_pose(_skeleton); - } - - /// Sets the slots and draw order to their setup pose values. - void setSlotsToSetupPose() { - _bindings.spine_skeleton_set_slots_to_setup_pose(_skeleton); - } - - /// Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it - /// repeatedly. - Bone? findBone(String boneName) { - final nameNative = boneName.toNativeUtf8(allocator: _allocator); - final bone = _bindings.spine_skeleton_find_bone(_skeleton, nameNative.cast()); - _allocator.free(nameNative); - if (bone.address == nullptr.address) return null; - return Bone._(bone); - } - - /// Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it - /// repeatedly. - Slot? findSlot(String slotName) { - final nameNative = slotName.toNativeUtf8(allocator: _allocator); - final slot = _bindings.spine_skeleton_find_slot(_skeleton, nameNative.cast()); - _allocator.free(nameNative); - if (slot.address == nullptr.address) return null; - return Slot._(slot); - } - - /// Sets a skin by name. - /// - /// See [setSkin]. - void setSkinByName(String skinName) { - final nameNative = skinName.toNativeUtf8(allocator: _allocator); - _bindings.spine_skeleton_set_skin_by_name(_skeleton, nameNative.cast()); - _allocator.free(nameNative); - } - - /// Sets the skin used to look up attachments before looking in the default skin (see [SkeletonData.getDefaultSkin]). If the - /// skin is changed, [updateCache] is called. - /// - /// Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was no - /// old skin, each slot's setup mode attachment is attached from the new skin. - /// - /// After changing the skin, the visible attachments can be reset to those attached in the setup pose by calling - /// [setSlotsToSetupPose]. Also, often [AnimationState.apply] is called before the next time the - /// skeleton is rendered to allow any attachment keys in the current animation(s) to hide or show attachments from the new - /// skin. - void setSkin(Skin skin) { - _bindings.spine_skeleton_set_skin(_skeleton, skin._skin); - } - - /// Finds an attachment by looking in the currently set skin (see [getSkin]) and default skin (see [SkeletonData.getDefaultSkin]) using - /// the slot name and attachment name. - /// - /// See [getAttachment]. - Attachment? getAttachmentByName(String slotName, String attachmentName) { - final slotNameNative = slotName.toNativeUtf8(allocator: _allocator); - final attachmentNameNative = attachmentName.toNativeUtf8(allocator: _allocator); - final attachment = _bindings.spine_skeleton_get_attachment_by_name( - _skeleton, - slotNameNative.cast(), - attachmentNameNative.cast(), - ); - _allocator.free(slotNameNative); - _allocator.free(attachmentNameNative); - if (attachment.address == nullptr.address) return null; - return Attachment._toSubclass(attachment); - } - - /// Finds an attachment by looking in the currently set skin (see [getSkin]) and default skin (see [SkeletonData.getDefaultSkin]) using the - /// slot index and attachment name. First the skin is checked and if the attachment was not found, the default skin is checked. - /// - /// See [Runtime skins](http://esotericsoftware.com/spine-runtime-skins) in the Spine Runtimes Guide. - Attachment? getAttachment(int slotIndex, String attachmentName) { - final attachmentNameNative = attachmentName.toNativeUtf8(allocator: _allocator); - final attachment = _bindings.spine_skeleton_get_attachment(_skeleton, slotIndex, attachmentNameNative.cast()); - _allocator.free(attachmentNameNative); - if (attachment.address == nullptr.address) return null; - return Attachment._toSubclass(attachment); - } - - /// A convenience method to set an attachment by finding the slot with [findSlot], finding the attachment with - /// [getAttachment], then setting the slot's attachment. The [attachmentName] may be an empty string to clear the slot's attachment. - void setAttachment(String slotName, String attachmentName) { - final slotNameNative = slotName.toNativeUtf8(allocator: _allocator); - final attachmentNameNative = attachmentName.toNativeUtf8(allocator: _allocator); - _bindings.spine_skeleton_set_attachment(_skeleton, slotNameNative.cast(), attachmentNameNative.cast()); - _allocator.free(slotNameNative); - _allocator.free(attachmentNameNative); - } - - /// Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method - /// than to call it repeatedly. - IkConstraint? findIkConstraint(String constraintName) { - final nameNative = constraintName.toNativeUtf8(allocator: _allocator); - final constraint = _bindings.spine_skeleton_find_ik_constraint(_skeleton, nameNative.cast()); - _allocator.free(nameNative); - if (constraint.address == nullptr.address) return null; - return IkConstraint._(constraint); - } - - /// Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of - /// this method than to call it repeatedly. - TransformConstraint? findTransformConstraint(String constraintName) { - final nameNative = constraintName.toNativeUtf8(allocator: _allocator); - final constraint = _bindings.spine_skeleton_find_transform_constraint(_skeleton, nameNative.cast()); - _allocator.free(nameNative); - if (constraint.address == nullptr.address) return null; - return TransformConstraint._(constraint); - } - - /// Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method - /// than to call it repeatedly. - PathConstraint? findPathConstraint(String constraintName) { - final nameNative = constraintName.toNativeUtf8(allocator: _allocator); - final constraint = _bindings.spine_skeleton_find_path_constraint(_skeleton, nameNative.cast()); - _allocator.free(nameNative); - if (constraint.address == nullptr.address) return null; - return PathConstraint._(constraint); - } - - /// Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. - Bounds getBounds() { - final nativeBounds = _bindings.spine_skeleton_get_bounds(_skeleton); - final bounds = Bounds( - _bindings.spine_bounds_get_x(nativeBounds), - _bindings.spine_bounds_get_y(nativeBounds), - _bindings.spine_bounds_get_width(nativeBounds), - _bindings.spine_bounds_get_height(nativeBounds), - ); - return bounds; - } - - /// Returns the root bone, or null if the skeleton has no bones. - Bone? getRootBone() { - final bone = _bindings.spine_skeleton_get_root_bone(_skeleton); - if (bone.address == nullptr.address) return null; - return Bone._(bone); - } - - /// The skeleton's setup pose data. - SkeletonData? getData() { - final data = _bindings.spine_skeleton_get_data(_skeleton); - if (data.address == nullptr.address) return null; - return SkeletonData._(data); - } - - /// The skeleton's bones, sorted parent first. The root bone is always the first bone. - List getBones() { - final List bones = []; - final numBones = _bindings.spine_skeleton_get_num_bones(_skeleton); - final nativeBones = _bindings.spine_skeleton_get_bones(_skeleton); - for (int i = 0; i < numBones; i++) { - bones.add(Bone._(nativeBones[i])); - } - return bones; - } - - /// The skeleton's slots. - List getSlots() { - final List slots = []; - final numSlots = _bindings.spine_skeleton_get_num_slots(_skeleton); - final nativeSlots = _bindings.spine_skeleton_get_slots(_skeleton); - for (int i = 0; i < numSlots; i++) { - slots.add(Slot._(nativeSlots[i])); - } - return slots; - } - - /// The skeleton's slots in the order they should be drawn. The returned array may be modified to change the draw order. - List getDrawOrder() { - final List slots = []; - final numSlots = _bindings.spine_skeleton_get_num_draw_order(_skeleton); - final nativeDrawOrder = _bindings.spine_skeleton_get_draw_order(_skeleton); - for (int i = 0; i < numSlots; i++) { - slots.add(Slot._(nativeDrawOrder[i])); - } - return slots; - } - - /// The skeleton's IK constraints. - List getIkConstraints() { - final List constraints = []; - final numConstraints = _bindings.spine_skeleton_get_num_ik_constraints(_skeleton); - final nativeConstraints = _bindings.spine_skeleton_get_ik_constraints(_skeleton); - for (int i = 0; i < numConstraints; i++) { - constraints.add(IkConstraint._(nativeConstraints[i])); - } - return constraints; - } - - /// The skeleton's path constraints. - List getPathConstraints() { - final List constraints = []; - final numConstraints = _bindings.spine_skeleton_get_num_path_constraints(_skeleton); - final nativeConstraints = _bindings.spine_skeleton_get_path_constraints(_skeleton); - for (int i = 0; i < numConstraints; i++) { - constraints.add(PathConstraint._(nativeConstraints[i])); - } - return constraints; - } - - /// The skeleton's transform constraints. - List getTransformConstraints() { - final List constraints = []; - final numConstraints = _bindings.spine_skeleton_get_num_transform_constraints(_skeleton); - final nativeConstraints = _bindings.spine_skeleton_get_transform_constraints(_skeleton); - for (int i = 0; i < numConstraints; i++) { - constraints.add(TransformConstraint._(nativeConstraints[i])); - } - return constraints; - } - - /// The skeleton's current skin. - Skin? getSkin() { - final skin = _bindings.spine_skeleton_get_skin(_skeleton); - if (skin.address == nullptr.address) return null; - return Skin._(skin); - } - - /// The color to tint all the skeleton's attachments. - Color getColor() { - final color = _bindings.spine_skeleton_get_color(_skeleton); - return Color( - _bindings.spine_color_get_r(color), - _bindings.spine_color_get_g(color), - _bindings.spine_color_get_b(color), - _bindings.spine_color_get_a(color), - ); - } - - void setColor(Color color) { - _bindings.spine_skeleton_set_color(_skeleton, color.r, color.g, color.b, color.a); - } - - /// Sets the skeleton X and Y position, which is added to the root bone worldX and worldY position. - /// - /// Bones that do not inherit translation are still affected by this property. - void setPosition(double x, double y) { - _bindings.spine_skeleton_set_position(_skeleton, x, y); - } - - Vec2 getPosition() { - final x = _bindings.spine_skeleton_get_x(_skeleton); - final y = _bindings.spine_skeleton_get_y(_skeleton); - return Vec2(x, y); - } - - /// Sets the skeleton X position, which is added to the root bone worldX position. - /// - /// Bones that do not inherit translation are still affected by this property. - double getX() { - return _bindings.spine_skeleton_get_x(_skeleton); - } - - void setX(double x) { - _bindings.spine_skeleton_set_x(_skeleton, x); - } - - /// Sets the skeleton Y position, which is added to the root bone worldY position. - ///

- /// Bones that do not inherit translation are still affected by this property. - double getY() { - return _bindings.spine_skeleton_get_y(_skeleton); - } - - void setY(double y) { - _bindings.spine_skeleton_set_y(_skeleton, y); - } - - /// Scales the entire skeleton on the X axis. - /// - /// Bones that do not inherit scale are still affected by this property. - double getScaleX() { - return _bindings.spine_skeleton_get_scale_x(_skeleton); - } - - void setScaleX(double scaleX) { - _bindings.spine_skeleton_set_scale_x(_skeleton, scaleX); - } - - /// Scales the entire skeleton on the Y axis. - /// - /// Bones that do not inherit scale are still affected by this property. - double getScaleY() { - return _bindings.spine_skeleton_get_scale_y(_skeleton); - } - - void setScaleY(double scaleY) { - _bindings.spine_skeleton_set_scale_y(_skeleton, scaleY); - } - - double getTime() { - return _bindings.spine_skeleton_get_time(_skeleton); - } - - void setTime(double time) { - return _bindings.spine_skeleton_set_time(_skeleton, time); - } - - void update(double delta) { - _bindings.spine_skeleton_update(_skeleton, delta); - } -} - -/// Stores a list of timelines to animate a skeleton's pose over time. -class Animation { - final spine_animation _animation; - - Animation._(this._animation); - - /// The animation's name, which is unique across all animations in the skeleton. - String getName() { - final Pointer value = _bindings.spine_animation_get_name(_animation).cast(); - return value.toDartString(); - } - - /// The duration of the animation in seconds, which is usually the highest time of all frames in the timeline. The duration is - /// used to know when it has completed and when it should loop back to the start. - double getDuration() { - return _bindings.spine_animation_get_duration(_animation); - } -} - -/// Controls how timeline values are mixed with setup pose values or current pose values when a timeline is applied with -/// alpha < 1. -enum MixBlend { - /// Transitions from the setup value to the timeline value (the current value is not used). Before the first frame, the - /// setup value is set. - setup(0), - - /// Transitions from the current value to the timeline value. Before the first frame, transitions from the current value to - /// the setup value. Timelines which perform instant transitions, such as {@link DrawOrderTimeline} or - /// {link AttachmentTimeline}, use the setup value before the first frame. - ///

- /// first is intended for the first animations applied, not for animations layered on top of those. - first(1), - - /// Transitions from the current value to the timeline value. No change is made before the first frame (the current value is - /// kept until the first frame). - ///

- /// replace is intended for animations layered on top of others, not for the first animations applied. - replace(2), - - /// Transitions from the current value to the current value plus the timeline value. No change is made before the first - /// frame (the current value is kept until the first frame). - ///

- /// add is intended for animations layered on top of others, not for the first animations applied. Properties - /// set by additive animations must be set manually or by another animation before applying the additive animations, else the - /// property values will increase each time the additive animations are applied. - add(3); - - final int value; - - const MixBlend(this.value); -} - -/// Stores settings and other state for the playback of an animation on an [AnimationState] track. -/// -/// References to a track entry must not be kept after the dispose [EventType] is reported to [AnimationStateListener]. -class TrackEntry { - final spine_track_entry _entry; - final AnimationState _state; - - TrackEntry._(this._entry, this._state); - - /// The index of the track where this track entry is either current or queued. - /// - /// See [AnimationState.getCurrent]. - int getTtrackIndex() { - return _bindings.spine_track_entry_get_track_index(_entry); - } - - /// The animation to apply for this track entry. - Animation getAnimation() { - return Animation._(_bindings.spine_track_entry_get_animation(_entry)); - } - - /// If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its - /// duration. - bool getLoop() { - return _bindings.spine_track_entry_get_loop(_entry) == -1; - } - - void setLoop(bool loop) { - _bindings.spine_track_entry_set_loop(_entry, loop ? -1 : 0); - } - - /// Seconds to postpone playing the animation. When this track entry is the current track entry, delay - /// postpones incrementing the [getTrackTime]. When this track entry is queued, delay is the time from - /// the start of the previous animation to when this track entry will become the current track entry (ie when the previous - /// track entry [getTrackTime] >= this track entry's delay). - /// - /// [getTimeScale] affects the delay. - /// - /// When using [AnimationState.addAnimation] with a delay <= 0, the delay - /// is set using the mix duration from the [AnimationStateData]. If [getMixDuration] is set afterward, the delay - /// may need to be adjusted. - bool getHoldPrevious() { - return _bindings.spine_track_entry_get_hold_previous(_entry) == -1; - } - - void setHoldPrevious(bool holdPrevious) { - _bindings.spine_track_entry_set_hold_previous(_entry, holdPrevious ? -1 : 0); - } - - /// If true, the animation will be applied in reverse. Events are not fired when an animation is applied in reverse. - bool getReverse() { - return _bindings.spine_track_entry_get_reverse(_entry) == -1; - } - - void setReverse(bool reverse) { - _bindings.spine_track_entry_set_reverse(_entry, reverse ? -1 : 0); - } - - /// If true, mixing rotation between tracks always uses the shortest rotation direction. If the rotation is animated, the - /// shortest rotation direction may change during the mix. - /// - /// If false, the shortest rotation direction is remembered when the mix starts and the same direction is used for the rest - /// of the mix. Defaults to false. - bool getShortestRotation() { - return _bindings.spine_track_entry_get_shortest_rotation(_entry) == 1; - } - - void setShortestRotation(bool shortestRotation) { - _bindings.spine_track_entry_set_shortest_rotation(_entry, shortestRotation ? -1 : 0); - } - - /// Seconds to postpone playing the animation. When this track entry is the current track entry, delay - /// postpones incrementing the [getTrackTime]. When this track entry is queued, delay is the time from - /// the start of the previous animation to when this track entry will become the current track entry (ie when the previous - /// track entry [getTrackTime] >= this track entry's delay). - /// - /// [getTimeScale] affects the delay. - /// - /// When using [AnimationState.addAnimation] with a delay <= 0, the delay - /// is set using the mix duration from the [AnimationStateData]. If [getMixDuration] is set afterward, the delay - /// may need to be adjusted. - double getDelay() { - return _bindings.spine_track_entry_get_delay(_entry); - } - - void setDelay(double delay) { - _bindings.spine_track_entry_set_delay(_entry, delay); - } - - /// Current time in seconds this track entry has been the current track entry. The track time determines - /// [getAnimationTime]. The track time can be set to start the animation at a time other than 0, without affecting - /// looping. - double getTrackTime() { - return _bindings.spine_track_entry_get_track_time(_entry); - } - - void setTrackTime(double trackTime) { - _bindings.spine_track_entry_set_track_time(_entry, trackTime); - } - - /// The track time in seconds when this animation will be removed from the track. Defaults to the highest possible float - /// value, meaning the animation will be applied until a new animation is set or the track is cleared. If the track end time - /// is reached, no other animations are queued for playback, and mixing from any previous animations is complete, then the - /// properties keyed by the animation are set to the setup pose and the track is cleared. - /// - /// It may be desired to use [AnimationState.addEmptyAnimation] rather than have the animation - /// abruptly cease being applied. - double getTrackEnd() { - return _bindings.spine_track_entry_get_track_end(_entry); - } - - void setTrackEnd(double trackEnd) { - _bindings.spine_track_entry_set_track_end(_entry, trackEnd); - } - - /// Seconds when this animation starts, both initially and after looping. Defaults to 0. - /// - /// When changing the animationStart time, it often makes sense to set [getAnimationLast] to the same - /// value to prevent timeline keys before the start time from triggering. - double getAnimationStart() { - return _bindings.spine_track_entry_get_animation_start(_entry); - } - - void setAnimationStart(double animationStart) { - _bindings.spine_track_entry_set_animation_start(_entry, animationStart); - } - - /// Seconds for the last frame of this animation. Non-looping animations won't play past this time. Looping animations will - /// loop back to [getAnimationStart] at this time. Defaults to the animation [Animation.getDuration]. - double getAnimationEnd() { - return _bindings.spine_track_entry_get_animation_end(_entry); - } - - void setAnimationEnd(double animationEnd) { - _bindings.spine_track_entry_set_animation_end(_entry, animationEnd); - } - - /// The time in seconds this animation was last applied. Some timelines use this for one-time triggers. Eg, when this - /// animation is applied, event timelines will fire all events between the animationLast time (exclusive) and - /// animationTime (inclusive). Defaults to -1 to ensure triggers on frame 0 happen the first time this animation - /// is applied. - double getAnimationLast() { - return _bindings.spine_track_entry_get_animation_last(_entry); - } - - void setAnimationLast(double animationLast) { - _bindings.spine_track_entry_set_animation_last(_entry, animationLast); - } - - /// Uses [getTrackTime] to compute the animationTime. When the trackTime is 0, the - /// animationTime is equal to the animationStart time. - ///

- /// The animationTime is between [getAnimationStart] and [getAnimationEnd], except if this - /// track entry is non-looping and [getAnimationEnd] is >= to the animation [Animation.getDuration], then - /// animationTime continues to increase past [getAnimationEnd]. - double getAnimationTime() { - return _bindings.spine_track_entry_get_animation_time(_entry); - } - - /// Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or - /// faster. Defaults to 1. - /// - /// Values < 0 are not supported. To play an animation in reverse, use [getReverse]. - /// - /// [getMixTime] is not affected by track entry time scale, so [getMixDuration] may need to be adjusted to - /// match the animation speed. - /// - /// When using [AnimationState.addAnimation] with a delay <= 0, the - /// [getDelay] is set using the mix duration from the [AnimationStateData], assuming time scale to be 1. If - /// the time scale is not 1, the delay may need to be adjusted. - /// - /// See [AnimationState.getTimeScale] for affecting all animations. - double getTimeScale() { - return _bindings.spine_track_entry_get_time_scale(_entry); - } - - void setTimeScale(double timeScale) { - _bindings.spine_track_entry_set_time_scale(_entry, timeScale); - } - - /// Values < 1 mix this animation with the skeleton's current pose (usually the pose resulting from lower tracks). Defaults - /// to 1, which overwrites the skeleton's current pose with this animation. - /// - /// Typically track 0 is used to completely pose the skeleton, then alpha is used on higher tracks. It doesn't make sense to - /// use alpha on track 0 if the skeleton pose is from the last frame render. - Future getAlpha() async { - return _bindings.spine_track_entry_get_alpha(_entry); - } - - void setAlpha(double alpha) { - _bindings.spine_track_entry_set_alpha(_entry, alpha); - } - - /// When the mix percentage ([getMixTime] / [getMixDuration]) is less than the - /// eventThreshold, event timelines are applied while this animation is being mixed out. Defaults to 0, so event - /// timelines are not applied while this animation is being mixed out. - double getEventThreshold() { - return _bindings.spine_track_entry_get_event_threshold(_entry); - } - - void setEventThreshold(double eventThreshold) { - _bindings.spine_track_entry_set_event_threshold(_entry, eventThreshold); - } - - /// Values less than 1 mix this animation with the last skeleton pose. Defaults to 1, which overwrites the last skeleton pose with - /// this animation. - /// - /// Typically track 0 is used to completely pose the skeleton, then alpha can be used on higher tracks. It doesn't make sense - /// to use alpha on track 0 if the skeleton pose is from the last frame render. - double getAlphaAttachmentThreshold() { - return _bindings.spine_track_entry_get_alpha_attachment_threshold(_entry); - } - - void setAlphaAttachmentThreshold(double attachmentThreshold) { - _bindings.spine_track_entry_set_alpha_attachment_threshold(_entry, attachmentThreshold); - } - - /// When the mix percentage ([getMixTime] / [getMixDuration]) is less than the - /// attachmentThreshold, attachment timelines are applied while this animation is being mixed out. Defaults to - /// 0, so attachment timelines are not applied while this animation is being mixed out. - double getMixAttachmentThreshold() { - return _bindings.spine_track_entry_get_mix_attachment_threshold(_entry); - } - - void setMixAttachmentThreshold(double attachmentThreshold) { - _bindings.spine_track_entry_set_mix_attachment_threshold(_entry, attachmentThreshold); - } - - /// When the mix percentage ([getMixTime] / [getMixDuration]) is less than the - /// drawOrderThreshold, draw order timelines are applied while this animation is being mixed out. Defaults to 0, - /// so draw order timelines are not applied while this animation is being mixed out. - double getMixDrawOrderThreshold() { - return _bindings.spine_track_entry_get_mix_draw_order_threshold(_entry); - } - - void setMixDrawOrderThreshold(double drawOrderThreshold) { - _bindings.spine_track_entry_set_mix_draw_order_threshold(_entry, drawOrderThreshold); - } - - /// The animation queued to start after this animation, or null if there is none. next makes up a doubly linked - /// list. - /// - /// See [AnimationState.clearNext] to truncate the list. - TrackEntry? getNext() { - final next = _bindings.spine_track_entry_get_next(_entry); - if (next.address == nullptr.address) return null; - return TrackEntry._(next, _state); - } - - /// Returns true if at least one loop has been completed. - bool isComplete() { - return _bindings.spine_track_entry_is_complete(_entry) == -1; - } - - /// Seconds from 0 to the [getMixDuration] when mixing from the previous animation to this animation. May be - /// slightly more than mixDuration when the mix is complete. - double getMixTime() { - return _bindings.spine_track_entry_get_mix_time(_entry); - } - - void setMixTime(double mixTime) { - _bindings.spine_track_entry_set_mix_time(_entry, mixTime); - } - - /// Seconds for mixing from the previous animation to this animation. Defaults to the value provided by - /// [AnimationStateData.getMix] based on the animation before this animation (if any). - /// - /// A mix duration of 0 still mixes out over one frame to provide the track entry being mixed out a chance to revert the - /// properties it was animating. A mix duration of 0 can be set at any time to end the mix on the next - /// [AnimationState.update]. - /// - /// The mixDuration can be set manually rather than use the value from - /// [AnimationStateData.getMix]. In that case, the mixDuration can be set for a new - /// track entry only before [AnimationState.update] is first called. - ///

- /// When using [AnimationState.addAnimation] with a delay <= 0, the - /// [getDelay] is set using the mix duration from the [AnimationStateData]. If mixDuration is set - /// afterward, the delay may need to be adjusted. For example: - /// entry.delay = entry.previous.getTrackComplete() - entry.mixDuration; - double getMixDuration() { - return _bindings.spine_track_entry_get_mix_duration(_entry); - } - - void setMixDuration(double mixDuration) { - _bindings.spine_track_entry_set_mix_duration(_entry, mixDuration); - } - - /// Controls how properties keyed in the animation are mixed with lower tracks. Defaults to [MixBlend.replace]. - /// - /// Track entries on track 0 ignore this setting and always use {@link MixBlend#first}. - /// - /// The mixBlend can be set for a new track entry only before [AnimationState.apply] is first - /// called. - MixBlend getMixBlend() { - return MixBlend.values[_bindings.spine_track_entry_get_mix_blend(_entry)]; - } - - void setMixBlend(MixBlend mixBlend) { - _bindings.spine_track_entry_set_mix_blend(_entry, mixBlend.value); - } - - /// The track entry for the previous animation when mixing from the previous animation to this animation, or null if no - /// mixing is currently occurring. When mixing from multiple animations, mixingFrom makes up a linked list. - TrackEntry? getMixingFrom() { - final from = _bindings.spine_track_entry_get_mixing_from(_entry); - if (from.address == nullptr.address) return null; - return TrackEntry._(from, _state); - } - - /// The track entry for the next animation when mixing from this animation to the next animation, or null if no mixing is - /// currently occurring. When mixing to multiple animations, mixingTo makes up a linked list. - TrackEntry? getMixingTo() { - final to = _bindings.spine_track_entry_get_mixing_to(_entry); - if (to.address == nullptr.address) return null; - return TrackEntry._(to, _state); - } - - /// Resets the rotation directions for mixing this entry's rotate timelines. This can be useful to avoid bones rotating the - /// long way around when using alpha and starting animations on other tracks. - /// - /// Mixing involves finding a rotation between two others, which has two possible solutions: the short way or the long way around. - /// The two rotations likely change over time, so which direction is the short or long way also changes. - /// If the short way was always chosen, bones would flip to the other side when that direction became the long way. - /// TrackEntry chooses the short way the first time it is applied and remembers that direction. - void resetRotationDirections() { - _bindings.spine_track_entry_reset_rotation_directions(_entry); - } - - /// If this track entry is non-looping, the track time in seconds when [getAnimationEnd] is reached, or the current - /// [getTrackTime] if it has already been reached. If this track entry is looping, the track time when this - /// animation will reach its next [getAnimationEnd] (the next loop completion). - double getTrackComplete() { - return _bindings.spine_track_entry_get_track_complete(_entry); - } - - bool wasApplied() { - return _bindings.spine_track_entry_was_applied(_entry) == -1; - } - - bool isNextReady() { - return _bindings.spine_track_entry_is_next_ready(_entry) == -1; - } - - /// The listener for events generated by this track entry, or null. - /// - /// A track entry returned from [AnimationState.setAnimation] is already the current animation - /// for the track, so the track entry listener will not be called for [EventType.start]. - void setListener(AnimationStateListener? listener) { - _state._setTrackEntryListener(_entry, listener); - } -} - -/// The event type passed to [AnimationStateListener] -enum EventType { - /// Emitted when [TrackEntry] has been set as the current entry. [EventType.end] will occur when this entry will no - /// longer be applied. - start, - - /// Emitted when another entry has replaced the current entry. This entry may continue being applied for - /// mixing. - interrupt, - - /// Emitted when this entry will never be applied again. This only occurs if this entry has previously been set as the - /// current entry ([EventType.start] was emitted). - end, - - /// Emitted every time the current entry's animation completes a loop. This may occur during mixing (after - /// [EventType.interrupted] is emitted). - /// - /// If [TrackEntry.getMixingTo] of the entry reported by the event is not null, the entry is mixing out (it is not the current entry). - /// - /// Because this event is triggered at the end of [AnimationState.apply], any animations set in response to - /// the event won't be applied until the next time the [AnimationState] is applied. - complete, - - /// Emitted when this entry will be disposed. This may occur without the entry ever being set as the current entry. - /// - /// References to the entry should not be kept after dispose is called, as it may be destroyed or reused. - dispose, - - /// Invoked when the current entry's animation triggers an event. This may occur during mixing (after - /// [EventType.interrupt] is emitted), see [TrackEntry.getEventThreshold]. - /// - /// Because this event is triggered at the end of [AnimationState.apply], any animations set in response to - /// the event won't be applied until the next time the [AnimationState] is applied. - event, -} - -/// Stores the setup pose values for an [Event]. -/// -/// See Events in the Spine User Guide. -class EventData { - final spine_event_data _data; - - EventData._(this._data); - - /// The name of the event, which is unique across all events in the skeleton. - String getName() { - final Pointer value = _bindings.spine_event_data_get_name(_data).cast(); - return value.toDartString(); - } - - int getIntValue() { - return _bindings.spine_event_data_get_int_value(_data); - } - - void setIntValue(int value) { - _bindings.spine_event_data_set_int_value(_data, value); - } - - double getFloatValue() { - return _bindings.spine_event_data_get_float_value(_data); - } - - void setFloatValue(double value) { - _bindings.spine_event_data_set_float_value(_data, value); - } - - String getStringValue() { - final Pointer value = _bindings.spine_event_data_get_string_value(_data).cast(); - return value.toDartString(); - } - - void setStringValue(String value) { - final nativeString = value.toNativeUtf8(allocator: _allocator); - _bindings.spine_event_data_set_string_value(_data, nativeString.cast()); - _allocator.free(nativeString); - } - - String getAudioPath() { - final Pointer value = _bindings.spine_event_data_get_audio_path(_data).cast(); - return value.toDartString(); - } - - double getVolume() { - return _bindings.spine_event_data_get_volume(_data); - } - - void setVolume(double volume) { - _bindings.spine_event_data_set_volume(_data, volume); - } - - double getBalance() { - return _bindings.spine_event_data_get_balance(_data); - } - - void setBalance(double value) { - _bindings.spine_event_data_set_balance(_data, value); - } -} - -/// Stores the current pose values for an {@link Event}. -/// -/// See [AnimationStateListener], [EventType.event], and -/// Events in the Spine User Guide. -class Event { - final spine_event _event; - - Event._(this._event); - - /// The events's setup pose data. - EventData getData() { - return EventData._(_bindings.spine_event_get_data(_event)); - } - - /// The animation time this event was keyed. - double getTime() { - return _bindings.spine_event_get_time(_event); - } - - int getIntValue() { - return _bindings.spine_event_get_int_value(_event); - } - - void setIntValue(int value) { - _bindings.spine_event_set_int_value(_event, value); - } - - double getFloatValue() { - return _bindings.spine_event_get_float_value(_event); - } - - void setFloatValue(double value) { - _bindings.spine_event_set_float_value(_event, value); - } - - String getStringValue() { - final Pointer value = _bindings.spine_event_get_string_value(_event).cast(); - return value.toDartString(); - } - - void setStringValue(String value) { - final nativeString = value.toNativeUtf8(allocator: _allocator); - _bindings.spine_event_set_string_value(_event, nativeString.cast()); - _allocator.free(nativeString); - } - - double getVolume() { - return _bindings.spine_event_get_volume(_event); - } - - void setVolume(double volume) { - _bindings.spine_event_set_volume(_event, volume); - } - - double getBalance() { - return _bindings.spine_event_get_balance(_event); - } - - void setBalance(double balance) { - _bindings.spine_event_set_balance(_event, balance); - } -} - -/// The callback to implement for receiving [TrackEntry] events. It is always safe to call [AnimationState] methods when receiving -/// events. -/// -/// TrackEntry events are collected during [AnimationState.update] and [AnimationState.apply] and -/// fired only after those methods are finished. -/// -/// See [TrackEntry.setListener] and [AnimationState.setListener]. -typedef AnimationStateListener = void Function(EventType type, TrackEntry entry, Event? event); - -/// Stores mix (crossfade) durations to be applied when {@link AnimationState} animations are changed. -class AnimationStateData { - final spine_animation_state_data _data; - - AnimationStateData._(this._data); - - /// The SkeletonData to look up animations when they are specified by name. - SkeletonData getSkeletonData() { - return SkeletonData._(_bindings.spine_animation_state_data_get_skeleton_data(_data)); - } - - double getDefaultMix() { - return _bindings.spine_animation_state_data_get_default_mix(_data); - } - - void setDefaultMix(double defaultMix) { - _bindings.spine_animation_state_data_set_default_mix(_data, defaultMix); - } - - /// Sets a mix duration by animation name. - /// - /// See [setMix]. - void setMixByName(String fromName, String toName, double duration) { - final fromNative = fromName.toNativeUtf8(allocator: _allocator); - final toNative = toName.toNativeUtf8(allocator: _allocator); - _bindings.spine_animation_state_data_set_mix_by_name(_data, fromNative.cast(), toNative.cast(), duration); - _allocator.free(fromNative); - _allocator.free(toNative); - } - - /// Returns the mix duration to use when changing from the specified animation to the other, or the [getDefaultMix] if - /// no mix duration has been set. - double getMixByName(String fromName, String toName) { - final fromNative = fromName.toNativeUtf8(allocator: _allocator); - final toNative = toName.toNativeUtf8(allocator: _allocator); - final duration = _bindings.spine_animation_state_data_get_mix_by_name(_data, fromNative.cast(), toNative.cast()); - _allocator.free(fromNative); - _allocator.free(toNative); - return duration; - } - - /// Sets the mix duration when changing from the specified animation to the other. - /// - /// See [TrackEntry.mixDuration]. - Future setMix(Animation from, Animation to, double duration) async { - _bindings.spine_animation_state_data_set_mix(_data, from._animation, to._animation, duration); - } - - /// Returns the mix duration to use when changing from the specified animation to the other, or the [getDefaultMix] if - /// no mix duration has been set. - double getMix(Animation from, Animation to) { - return _bindings.spine_animation_state_data_get_mix(_data, from._animation, to._animation); - } - - /// Removes all mix durations. - void clear() { - _bindings.spine_animation_state_data_clear(_data); - } -} - -/// Applies animations over time, queues animations for later playback, mixes (crossfading) between animations, and applies -/// multiple animations on top of each other (layering). -/// -/// See Applying Animations in the Spine Runtimes Guide. -class AnimationState { - final spine_animation_state _state; - final spine_animation_state_events _events; - final Map _trackEntryListeners; - AnimationStateListener? _stateListener; - - AnimationState._(this._state, this._events) : _trackEntryListeners = {}; - - void _setTrackEntryListener(spine_track_entry entry, AnimationStateListener? listener) { - if (listener == null) { - _trackEntryListeners.remove(entry); - } else { - _trackEntryListeners[entry] = listener; - } - } - - /// Increments each track entry [TrackEntry.getTrackTime], setting queued animations as current if needed. - void update(double delta) { - _bindings.spine_animation_state_update(_state, delta); - - final numEvents = _bindings.spine_animation_state_events_get_num_events(_events); - if (numEvents > 0) { - for (int i = 0; i < numEvents; i++) { - late final EventType type; - switch (_bindings.spine_animation_state_events_get_event_type(_events, i)) { - case 0: - type = EventType.start; - break; - case 1: - type = EventType.interrupt; - break; - case 2: - type = EventType.end; - break; - case 3: - type = EventType.complete; - break; - case 4: - type = EventType.dispose; - break; - case 5: - type = EventType.event; - break; - } - final nativeEntry = _bindings.spine_animation_state_events_get_track_entry(_events, i); - final entry = TrackEntry._(nativeEntry, this); - final nativeEvent = _bindings.spine_animation_state_events_get_event(_events, i); - final event = nativeEvent.address == nullptr.address ? null : Event._(nativeEvent); - if (_trackEntryListeners.containsKey(nativeEntry)) { - _trackEntryListeners[nativeEntry]?.call(type, entry, event); - } - if (_stateListener != null) { - _stateListener?.call(type, entry, event); - } - if (type == EventType.dispose) { - _bindings.spine_animation_state_dispose_track_entry(_state, nativeEntry); - } - } - } - _bindings.spine_animation_state_events_reset(_events); - } - - /// Poses the skeleton using the track entry animations. The animation state is not changed, so can be applied to multiple - /// skeletons to pose them identically. - /// - /// Returns true if any animations were applied. - void apply(Skeleton skeleton) { - _bindings.spine_animation_state_apply(_state, skeleton._skeleton); - } - - /// Removes all animations from all tracks, leaving skeletons in their current pose. - /// - /// It may be desired to use [setEmptyAnimations] to mix the skeletons back to the setup pose, - /// rather than leaving them in their current pose. - void clearTracks() { - _bindings.spine_animation_state_clear_tracks(_state); - } - - /// Removes all animations from the track, leaving skeletons in their current pose. - /// - /// It may be desired to use [setEmptyAnimations] to mix the skeletons back to the setup pose, - /// rather than leaving them in their current pose. - void clearTrack(int trackIndex) { - _bindings.spine_animation_state_clear_track(_state, trackIndex); - } - - /// Sets an animation by name. - /// - /// See [setAnimation]. - TrackEntry setAnimationByName(int trackIndex, String animationName, bool loop) { - final animation = animationName.toNativeUtf8(allocator: _allocator); - final entry = _bindings.spine_animation_state_set_animation_by_name( - _state, - trackIndex, - animation.cast(), - loop ? -1 : 0, - ); - _allocator.free(animation); - if (entry.address == nullptr.address) throw Exception("Couldn't set animation $animationName"); - return TrackEntry._(entry, this); - } - - /// Sets the current [animation] for a track at [trackIndex], discarding any queued animations. If the formerly current track entry was never - /// applied to a skeleton, it is replaced (not mixed from). - /// - /// If [loop] is true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its - /// duration. In either case [TrackEntry.getTrackEnd] determines when the track is cleared. - /// - /// Returns a track entry to allow further customization of animation playback. References to the track entry must not be kept - /// after the [EventType.dispose] event occurs. - TrackEntry setAnimation(int trackIndex, Animation animation, bool loop) { - final entry = _bindings.spine_animation_state_set_animation( - _state, - trackIndex, - animation._animation, - loop ? -1 : 0, - ); - if (entry.address == nullptr.address) throw Exception("Couldn't set animation ${animation.getName()}"); - return TrackEntry._(entry, this); - } - - /// Queues an animation by name. - /// - /// See [addAnimation]. - TrackEntry addAnimationByName(int trackIndex, String animationName, bool loop, double delay) { - final animation = animationName.toNativeUtf8(allocator: _allocator); - final entry = _bindings.spine_animation_state_add_animation_by_name( - _state, - trackIndex, - animation.cast(), - loop ? -1 : 0, - delay, - ); - _allocator.free(animation); - if (entry.address == nullptr.address) throw Exception("Couldn't add animation $animationName"); - return TrackEntry._(entry, this); - } - - /// Adds an [animation] to be played after the current or last queued animation for a track at [trackIndex]. If the track is empty, it is - /// equivalent to calling [setAnimation]. - /// - /// If [delay] > 0, sets [TrackEntry.getDelay]. If [delay] <= 0, the delay set is the duration of the previous track entry - /// minus any mix duration (from the [AnimationStateData]) plus the specified delay (ie the mix - /// ends at (delay = 0) or before (delay < 0) the previous track entry duration). If the - /// previous entry is looping, its next loop completion is used instead of its duration. - /// - /// Returns a track entry to allow further customization of animation playback. References to the track entry must not be kept - /// after the [EventType.dispose] event occurs. - TrackEntry addAnimation(int trackIndex, Animation animation, bool loop, double delay) { - final entry = _bindings.spine_animation_state_add_animation( - _state, - trackIndex, - animation._animation, - loop ? -1 : 0, - delay, - ); - if (entry.address == nullptr.address) throw Exception("Couldn't add animation ${animation.getName()}"); - return TrackEntry._(entry, this); - } - - /// Sets an empty animation for a track at [trackIndex], discarding any queued animations, and sets the track entry's - /// [TrackEntry.getMixDuration] to [mixDuration]. An empty animation has no timelines and serves as a placeholder for mixing in or out. - /// - /// Mixing out is done by setting an empty animation with a mix duration using either [setEmptyAnimation], - /// [setEmptyAnimations], or [addEmptyAnimation]. Mixing to an empty animation causes - /// the previous animation to be applied less and less over the mix duration. Properties keyed in the previous animation - /// transition to the value from lower tracks or to the setup pose value if no lower tracks key the property. A mix duration of - /// 0 still mixes out over one frame. - /// - /// Mixing in is done by first setting an empty animation, then adding an animation using - /// [addAnimation] with the desired delay (an empty animation has a duration of 0) and on - /// the returned track entry, set the [TrackEntry.setMixDuration]. Mixing from an empty animation causes the new - /// animation to be applied more and more over the mix duration. Properties keyed in the new animation transition from the value - /// from lower tracks or from the setup pose value if no lower tracks key the property to the value keyed in the new - /// animation. - TrackEntry setEmptyAnimation(int trackIndex, double mixDuration) { - final entry = _bindings.spine_animation_state_set_empty_animation(_state, trackIndex, mixDuration); - return TrackEntry._(entry, this); - } - - /// Adds an empty animation to be played after the current or last queued animation for a track, and sets the track entry's - /// [TrackEntry.getMixDuration]. If the track is empty, it is equivalent to calling - /// [setEmptyAnimation]. - /// - /// See [setEmptyAnimation]. - /// - /// If [delay] > 0, sets [TrackEntry.getDelay]. If <= 0, the delay set is the duration of the previous track entry - /// minus any mix duration plus the specified delay (ie the mix ends at (delay = 0) or - /// before (delay < 0) the previous track entry duration). If the previous entry is looping, its next - /// loop completion is used instead of its duration. - /// - /// Returns a track entry to allow further customization of animation playback. References to the track entry must not be kept - /// after the [EventType.dispose] event occurs. - TrackEntry addEmptyAnimation(int trackIndex, double mixDuration, double delay) { - final entry = _bindings.spine_animation_state_add_empty_animation(_state, trackIndex, mixDuration, delay); - return TrackEntry._(entry, this); - } - - /// Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. - TrackEntry? getCurrent(int trackIndex) { - final entry = _bindings.spine_animation_state_get_current(_state, trackIndex); - if (entry.address == nullptr.address) return null; - return TrackEntry._(entry, this); - } - - /// Returns the number of tracks that have animations queued. - int getNumTracks() { - return _bindings.spine_animation_state_get_num_tracks(_state); - } - - /// Sets an empty animation for every track, discarding any queued animations, and mixes to it over the specified mix - /// duration. - void setEmptyAnimations(double mixDuration) { - _bindings.spine_animation_state_set_empty_animations(_state, mixDuration); - } - - /// Multiplier for the delta time when the animation state is updated, causing time for all animations and mixes to play slower - /// or faster. Defaults to 1. - /// - /// See [TrackEntry.getTimeScale] for affecting a single animation. - double getTimeScale() { - return _bindings.spine_animation_state_get_time_scale(_state); - } - - void setTimeScale(double timeScale) { - _bindings.spine_animation_state_set_time_scale(_state, timeScale); - } - - /// The [AnimationStateData] to look up mix durations. - AnimationStateData getData() { - return AnimationStateData._(_bindings.spine_animation_state_get_data(_state)); - } - - /// The listener for events generated for all tracks managed by the AnimationState, or null. - /// - /// A track entry returned from [setAnimation] is already the current animation - /// for the track, so the track entry listener will not be called for [EventType.start]. - void setListener(AnimationStateListener? listener) { - _stateListener = listener; - } -} - -/// A SkeletonDrawable bundles loading, updating, and rendering an [Atlas], [Skeleton], and [AnimationState] -/// into a single easy to use class. -/// -/// Use the [fromAsset], [fromFile], or [fromHttp] methods to construct a SkeletonDrawable. To have -/// multiple skeleton drawable instances share the same [Atlas] and [SkeletonData], use the constructor. -/// -/// You can then directly access the [atlas], [skeletonData], [skeleton], [animationStateData], and [animationState] -/// to query and animate the skeleton. Use the [AnimationState] to queue animations on one or more tracks -/// via [AnimationState.setAnimation] or [AnimationState.addAnimation]. -/// -/// To update the [AnimationState] and apply it to the [Skeleton] call the [update] function, providing it -/// a delta time in seconds to advance the animations. -/// -/// To render the current pose of the [Skeleton], use the rendering methods [render], [renderToCanvas], [renderToPictureRecorder], -/// [renderToPng], or [renderToRawImageData], depending on your needs. -/// -/// When the skeleton drawable is no longer needed, call the [dispose] method to release its resources. If -/// the skeleton drawable was constructed from a shared [Atlas] and [SkeletonData], make sure to dispose the -/// atlas and skeleton data as well, if no skeleton drawable references them anymore. -class SkeletonDrawable { - final Atlas atlas; - final SkeletonData skeletonData; - late final spine_skeleton_drawable _drawable; - late final Skeleton skeleton; - late final AnimationStateData animationStateData; - late final AnimationState animationState; - final bool _ownsAtlasAndSkeletonData; - bool _disposed; - - /// Constructs a new skeleton drawable from the given (possibly shared) [Atlas] and [SkeletonData]. If - /// the atlas and skeleton data are not shared, the drawable can take ownership by passing true for [_ownsAtlasAndSkeletonData]. - /// In that case a call to [dispose] will also dispose the atlas and skeleton data. - SkeletonDrawable(this.atlas, this.skeletonData, this._ownsAtlasAndSkeletonData) : _disposed = false { - _drawable = _bindings.spine_skeleton_drawable_create(skeletonData._data); - skeleton = Skeleton._(_bindings.spine_skeleton_drawable_get_skeleton(_drawable)); - animationStateData = AnimationStateData._(_bindings.spine_skeleton_drawable_get_animation_state_data(_drawable)); - animationState = AnimationState._( - _bindings.spine_skeleton_drawable_get_animation_state(_drawable), - _bindings.spine_skeleton_drawable_get_animation_state_events(_drawable), - ); - skeleton.updateWorldTransform(Physics.none); - } - - /// Constructs a new skeleton drawable from the [atlasFile] and [skeletonFile] from the root asset bundle - /// or the optionally provided [bundle]. - /// - /// Throws an exception in case the data could not be loaded. - static Future fromAsset(String atlasFile, String skeletonFile, {AssetBundle? bundle}) async { - bundle ??= rootBundle; - var atlas = await Atlas.fromAsset(atlasFile, bundle: bundle); - var skeletonData = await SkeletonData.fromAsset(atlas, skeletonFile, bundle: bundle); - return SkeletonDrawable(atlas, skeletonData, true); - } - - /// Constructs a new skeleton drawable from the [atlasFile] and [skeletonFile]. - /// - /// Throws an exception in case the data could not be loaded. - static Future fromFile(String atlasFile, String skeletonFile) async { - var atlas = await Atlas.fromFile(atlasFile); - var skeletonData = await SkeletonData.fromFile(atlas, skeletonFile); - return SkeletonDrawable(atlas, skeletonData, true); - } - - /// Constructs a new skeleton drawable from the [atlasUrl] and [skeletonUrl]. - /// - /// Throws an exception in case the data could not be loaded. - static Future fromHttp(String atlasUrl, String skeletonUrl) async { - var atlas = await Atlas.fromHttp(atlasUrl); - var skeletonData = await SkeletonData.fromHttp(atlas, skeletonUrl); - return SkeletonDrawable(atlas, skeletonData, true); - } - - /// Updates the [AnimationState] using the [delta] time given in seconds, applies the - /// animation state to the [Skeleton] and updates the world transforms of the skeleton - /// to calculate its current pose. - void update(double delta) { - if (_disposed) return; - animationState.update(delta); - animationState.apply(skeleton); - skeleton.update(delta); - skeleton.updateWorldTransform(Physics.update); - } - - /// Renders to current skeleton pose to a list of [RenderCommand] instances. The render commands - /// can be rendered via [Canvas.drawVertices]. - List render() { - if (_disposed) return []; - spine_render_command nativeCmd = _bindings.spine_skeleton_drawable_render(_drawable); - List commands = []; - while (nativeCmd.address != nullptr.address) { - final atlasPage = atlas.atlasPages[_bindings.spine_render_command_get_atlas_page(nativeCmd)]; - commands.add(RenderCommand._(nativeCmd, atlasPage.width.toDouble(), atlasPage.height.toDouble())); - nativeCmd = _bindings.spine_render_command_get_next(nativeCmd); - } - return commands; - } - - /// Renders the skeleton drawable's current pose to the given [canvas]. Does not perform any - /// scaling or fitting. - List renderToCanvas(Canvas canvas) { - var commands = render(); - for (final cmd in commands) { - canvas.drawVertices( - cmd.vertices, - rendering.BlendMode.modulate, - atlas.atlasPagePaints[cmd.atlasPageIndex][cmd.blendMode]!, - ); - } - return commands; - } - - /// Renders the skeleton drawable's current pose to a [PictureRecorder] with the given [width] and [height]. - /// Uses [bgColor], a 32-bit ARGB color value, to paint the background. - /// Scales and centers the skeleton to fit the within the bounds of [width] and [height]. - PictureRecorder renderToPictureRecorder(double width, double height, int bgColor) { - var bounds = skeleton.getBounds(); - var scale = 1 / (bounds.width > bounds.height ? bounds.width / width : bounds.height / height); - - var recorder = PictureRecorder(); - var canvas = Canvas(recorder); - var paint = Paint() - ..color = material.Color(bgColor) - ..style = PaintingStyle.fill; - canvas.drawRect(Rect.fromLTWH(0, 0, width, height), paint); - canvas.translate(width / 2, height / 2); - canvas.scale(scale, scale); - canvas.translate(-(bounds.x + bounds.width / 2), -(bounds.y + bounds.height / 2)); - canvas.drawRect(const Rect.fromLTRB(-5, -5, 5, -5), paint..color = material.Colors.red); - renderToCanvas(canvas); - return recorder; - } - - /// Renders the skeleton drawable's current pose to a PNG encoded in a [Uint8List], with the given [width] and [height]. - /// Uses [bgColor], a 32-bit ARGB color value, to paint the background. - /// Scales and centers the skeleton to fit the within the bounds of [width] and [height]. - Future renderToPng(double width, double height, int bgColor) async { - final recorder = renderToPictureRecorder(width, height, bgColor); - final image = await recorder.endRecording().toImage(width.toInt(), height.toInt()); - return (await image.toByteData(format: ImageByteFormat.png))!.buffer.asUint8List(); - } - - /// Renders the skeleton drawable's current pose to a [RawImageData], with the given [width] and [height]. - /// Uses [bgColor], a 32-bit ARGB color value, to paint the background. - /// Scales and centers the skeleton to fit the within the bounds of [width] and [height]. - Future renderToRawImageData(double width, double height, int bgColor) async { - final recorder = renderToPictureRecorder(width, height, bgColor); - var rawImageData = (await (await recorder.endRecording().toImage( - width.toInt(), - height.toInt(), - )) - .toByteData(format: ImageByteFormat.rawRgba))! - .buffer - .asUint8List(); - return RawImageData(rawImageData, width.toInt(), height.toInt()); - } - - /// Disposes the skeleton drawable's resources. If the skeleton drawable owns the atlas - /// and skeleton data, they are disposed as well. Must be called when the skeleton drawable - /// is no longer in use. - void dispose() { - if (_disposed) return; - _disposed = true; - if (_ownsAtlasAndSkeletonData) { - atlas.dispose(); - skeletonData.dispose(); - } - _bindings.spine_skeleton_drawable_dispose(_drawable); - } -} - -/// Stores the vertices, indices, and atlas page index to be used for rendering one or more attachments -/// of a [Skeleton] to a [Canvas]. See the implementation of [SkeletonDrawable.renderToCanvas] on how to use this data to render it to a -/// [Canvas]. -class RenderCommand { - late final Vertices vertices; - late final int atlasPageIndex; - late final Float32List positions; - late final Float32List uvs; - late final Int32List colors; - late final Uint16List indices; - late final BlendMode blendMode; - - RenderCommand._(spine_render_command nativeCmd, double pageWidth, double pageHeight) { - atlasPageIndex = _bindings.spine_render_command_get_atlas_page(nativeCmd); - int numVertices = _bindings.spine_render_command_get_num_vertices(nativeCmd); - int numIndices = _bindings.spine_render_command_get_num_indices(nativeCmd); - positions = _bindings.spine_render_command_get_positions(nativeCmd).asTypedList(numVertices * 2); - uvs = _bindings.spine_render_command_get_uvs(nativeCmd).asTypedList(numVertices * 2); - for (int i = 0; i < numVertices * 2; i += 2) { - uvs[i] *= pageWidth; - uvs[i + 1] *= pageHeight; - } - colors = _bindings.spine_render_command_get_colors(nativeCmd).asTypedList(numVertices); - indices = _bindings.spine_render_command_get_indices(nativeCmd).asTypedList(numIndices); - blendMode = BlendMode.values[_bindings.spine_render_command_get_blend_mode(nativeCmd)]; - - if (!kIsWeb) { - // We pass the native data as views directly to Vertices.raw. According to the sources, the data - // is copied, so it doesn't matter that we free up the underlying memory on the next - // render call. See the implementation of Vertices.raw() here: - // https://github.com/flutter/engine/blob/5c60785b802ad2c8b8899608d949342d5c624952/lib/ui/painting/vertices.cc#L21 - // - // Impeller is currently using a slow path when using vertex colors. - // See https://github.com/flutter/flutter/issues/127486 - // - // We thus batch all meshes not only by atlas page and blend mode, but also vertex color. - // See spine_flutter.cpp, batch_commands(). - // - // If the vertex color equals (1, 1, 1, 1), we do not store - // colors, which will trigger the fast path in Impeller. Otherwise we have to go the slow path, which - // has to render to an offscreen surface. - if (colors.isNotEmpty && colors[0] == -1) { - vertices = Vertices.raw(VertexMode.triangles, positions, textureCoordinates: uvs, indices: indices); - } else { - vertices = Vertices.raw( - VertexMode.triangles, - positions, - textureCoordinates: uvs, - colors: colors, - indices: indices, - ); - } - } else { - // On the web, rendering is done through CanvasKit, which requires copies of the native data. - final positionsCopy = Float32List.fromList(positions); - final uvsCopy = Float32List.fromList(uvs); - final colorsCopy = Int32List.fromList(colors); - final indicesCopy = Uint16List.fromList(indices); - vertices = Vertices.raw( - VertexMode.triangles, - positionsCopy, - textureCoordinates: uvsCopy, - colors: colorsCopy, - indices: indicesCopy, - ); - } - } -} - -/// Renders debug information for a [SkeletonDrawable], like bone locations, to a [Canvas]. -/// See [DebugRenderer.render]. -class DebugRenderer { - const DebugRenderer(); - - void render(SkeletonDrawable drawable, Canvas canvas, List commands) { - final bonePaint = Paint() - ..color = material.Colors.blue - ..style = PaintingStyle.fill; - for (final bone in drawable.skeleton.getBones()) { - canvas.drawRect( - Rect.fromCenter(center: Offset(bone.getWorldX(), bone.getWorldY()), width: 5, height: 5), - bonePaint, - ); - } - } -} diff --git a/spine-flutter/lib/generated/animation.dart b/spine-flutter/lib/generated/animation.dart index 2cd4485b6..8a604f6ba 100644 --- a/spine-flutter/lib/generated/animation.dart +++ b/spine-flutter/lib/generated/animation.dart @@ -80,10 +80,10 @@ class Animation { SpineBindings.bindings.spine_animation_set_duration(_ptr, value); } - void apply(Skeleton skeleton, double lastTime, double time, bool loop, ArrayEvent? pEvents, double alpha, + void apply(Skeleton skeleton, double lastTime, double time, bool loop, ArrayEvent? events, double alpha, MixBlend blend, MixDirection direction, bool appliedPose) { SpineBindings.bindings.spine_animation_apply(_ptr, skeleton.nativePtr.cast(), lastTime, time, loop, - pEvents?.nativePtr.cast() ?? Pointer.fromAddress(0), alpha, blend.value, direction.value, appliedPose); + events?.nativePtr.cast() ?? Pointer.fromAddress(0), alpha, blend.value, direction.value, appliedPose); } String get name { diff --git a/spine-flutter/lib/generated/spine_dart_bindings_generated.dart b/spine-flutter/lib/generated/spine_dart_bindings_generated.dart index 12de883a4..c6e6ac148 100644 --- a/spine-flutter/lib/generated/spine_dart_bindings_generated.dart +++ b/spine-flutter/lib/generated/spine_dart_bindings_generated.dart @@ -5867,6 +5867,793 @@ class SpineDartBindings { late final _spine_array_update_buffer = _spine_array_update_bufferPtr.asFunction Function(spine_array_update)>(); + spine_bone_pose spine_bone_pose_create() { + return _spine_bone_pose_create(); + } + + late final _spine_bone_pose_createPtr = + _lookup>('spine_bone_pose_create'); + late final _spine_bone_pose_create = _spine_bone_pose_createPtr.asFunction(); + + void spine_bone_pose_dispose( + spine_bone_pose self, + ) { + return _spine_bone_pose_dispose( + self, + ); + } + + late final _spine_bone_pose_disposePtr = + _lookup>('spine_bone_pose_dispose'); + late final _spine_bone_pose_dispose = _spine_bone_pose_disposePtr.asFunction(); + + spine_rtti spine_bone_pose_get_rtti( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_rtti( + self, + ); + } + + late final _spine_bone_pose_get_rttiPtr = + _lookup>('spine_bone_pose_get_rtti'); + late final _spine_bone_pose_get_rtti = + _spine_bone_pose_get_rttiPtr.asFunction(); + + void spine_bone_pose_update( + spine_bone_pose self, + spine_skeleton skeleton, + int physics, + ) { + return _spine_bone_pose_update( + self, + skeleton, + physics, + ); + } + + late final _spine_bone_pose_updatePtr = + _lookup>( + 'spine_bone_pose_update'); + late final _spine_bone_pose_update = + _spine_bone_pose_updatePtr.asFunction(); + + void spine_bone_pose_update_world_transform( + spine_bone_pose self, + spine_skeleton skeleton, + ) { + return _spine_bone_pose_update_world_transform( + self, + skeleton, + ); + } + + late final _spine_bone_pose_update_world_transformPtr = + _lookup>( + 'spine_bone_pose_update_world_transform'); + late final _spine_bone_pose_update_world_transform = + _spine_bone_pose_update_world_transformPtr.asFunction(); + + void spine_bone_pose_update_local_transform( + spine_bone_pose self, + spine_skeleton skeleton, + ) { + return _spine_bone_pose_update_local_transform( + self, + skeleton, + ); + } + + late final _spine_bone_pose_update_local_transformPtr = + _lookup>( + 'spine_bone_pose_update_local_transform'); + late final _spine_bone_pose_update_local_transform = + _spine_bone_pose_update_local_transformPtr.asFunction(); + + void spine_bone_pose_validate_local_transform( + spine_bone_pose self, + spine_skeleton skeleton, + ) { + return _spine_bone_pose_validate_local_transform( + self, + skeleton, + ); + } + + late final _spine_bone_pose_validate_local_transformPtr = + _lookup>( + 'spine_bone_pose_validate_local_transform'); + late final _spine_bone_pose_validate_local_transform = + _spine_bone_pose_validate_local_transformPtr.asFunction(); + + void spine_bone_pose_modify_local( + spine_bone_pose self, + spine_skeleton skeleton, + ) { + return _spine_bone_pose_modify_local( + self, + skeleton, + ); + } + + late final _spine_bone_pose_modify_localPtr = + _lookup>('spine_bone_pose_modify_local'); + late final _spine_bone_pose_modify_local = + _spine_bone_pose_modify_localPtr.asFunction(); + + void spine_bone_pose_modify_world( + spine_bone_pose self, + int update, + ) { + return _spine_bone_pose_modify_world( + self, + update, + ); + } + + late final _spine_bone_pose_modify_worldPtr = + _lookup>('spine_bone_pose_modify_world'); + late final _spine_bone_pose_modify_world = + _spine_bone_pose_modify_worldPtr.asFunction(); + + void spine_bone_pose_reset_world( + spine_bone_pose self, + int update, + ) { + return _spine_bone_pose_reset_world( + self, + update, + ); + } + + late final _spine_bone_pose_reset_worldPtr = + _lookup>('spine_bone_pose_reset_world'); + late final _spine_bone_pose_reset_world = + _spine_bone_pose_reset_worldPtr.asFunction(); + + double spine_bone_pose_get_a( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_a( + self, + ); + } + + late final _spine_bone_pose_get_aPtr = + _lookup>('spine_bone_pose_get_a'); + late final _spine_bone_pose_get_a = _spine_bone_pose_get_aPtr.asFunction(); + + void spine_bone_pose_set_a( + spine_bone_pose self, + double a, + ) { + return _spine_bone_pose_set_a( + self, + a, + ); + } + + late final _spine_bone_pose_set_aPtr = + _lookup>('spine_bone_pose_set_a'); + late final _spine_bone_pose_set_a = _spine_bone_pose_set_aPtr.asFunction(); + + double spine_bone_pose_get_b( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_b( + self, + ); + } + + late final _spine_bone_pose_get_bPtr = + _lookup>('spine_bone_pose_get_b'); + late final _spine_bone_pose_get_b = _spine_bone_pose_get_bPtr.asFunction(); + + void spine_bone_pose_set_b( + spine_bone_pose self, + double b, + ) { + return _spine_bone_pose_set_b( + self, + b, + ); + } + + late final _spine_bone_pose_set_bPtr = + _lookup>('spine_bone_pose_set_b'); + late final _spine_bone_pose_set_b = _spine_bone_pose_set_bPtr.asFunction(); + + double spine_bone_pose_get_c( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_c( + self, + ); + } + + late final _spine_bone_pose_get_cPtr = + _lookup>('spine_bone_pose_get_c'); + late final _spine_bone_pose_get_c = _spine_bone_pose_get_cPtr.asFunction(); + + void spine_bone_pose_set_c( + spine_bone_pose self, + double c, + ) { + return _spine_bone_pose_set_c( + self, + c, + ); + } + + late final _spine_bone_pose_set_cPtr = + _lookup>('spine_bone_pose_set_c'); + late final _spine_bone_pose_set_c = _spine_bone_pose_set_cPtr.asFunction(); + + double spine_bone_pose_get_d( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_d( + self, + ); + } + + late final _spine_bone_pose_get_dPtr = + _lookup>('spine_bone_pose_get_d'); + late final _spine_bone_pose_get_d = _spine_bone_pose_get_dPtr.asFunction(); + + void spine_bone_pose_set_d( + spine_bone_pose self, + double d, + ) { + return _spine_bone_pose_set_d( + self, + d, + ); + } + + late final _spine_bone_pose_set_dPtr = + _lookup>('spine_bone_pose_set_d'); + late final _spine_bone_pose_set_d = _spine_bone_pose_set_dPtr.asFunction(); + + double spine_bone_pose_get_world_x( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_world_x( + self, + ); + } + + late final _spine_bone_pose_get_world_xPtr = + _lookup>('spine_bone_pose_get_world_x'); + late final _spine_bone_pose_get_world_x = + _spine_bone_pose_get_world_xPtr.asFunction(); + + void spine_bone_pose_set_world_x( + spine_bone_pose self, + double worldX, + ) { + return _spine_bone_pose_set_world_x( + self, + worldX, + ); + } + + late final _spine_bone_pose_set_world_xPtr = + _lookup>('spine_bone_pose_set_world_x'); + late final _spine_bone_pose_set_world_x = + _spine_bone_pose_set_world_xPtr.asFunction(); + + double spine_bone_pose_get_world_y( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_world_y( + self, + ); + } + + late final _spine_bone_pose_get_world_yPtr = + _lookup>('spine_bone_pose_get_world_y'); + late final _spine_bone_pose_get_world_y = + _spine_bone_pose_get_world_yPtr.asFunction(); + + void spine_bone_pose_set_world_y( + spine_bone_pose self, + double worldY, + ) { + return _spine_bone_pose_set_world_y( + self, + worldY, + ); + } + + late final _spine_bone_pose_set_world_yPtr = + _lookup>('spine_bone_pose_set_world_y'); + late final _spine_bone_pose_set_world_y = + _spine_bone_pose_set_world_yPtr.asFunction(); + + double spine_bone_pose_get_world_rotation_x( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_world_rotation_x( + self, + ); + } + + late final _spine_bone_pose_get_world_rotation_xPtr = + _lookup>('spine_bone_pose_get_world_rotation_x'); + late final _spine_bone_pose_get_world_rotation_x = + _spine_bone_pose_get_world_rotation_xPtr.asFunction(); + + double spine_bone_pose_get_world_rotation_y( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_world_rotation_y( + self, + ); + } + + late final _spine_bone_pose_get_world_rotation_yPtr = + _lookup>('spine_bone_pose_get_world_rotation_y'); + late final _spine_bone_pose_get_world_rotation_y = + _spine_bone_pose_get_world_rotation_yPtr.asFunction(); + + double spine_bone_pose_get_world_scale_x( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_world_scale_x( + self, + ); + } + + late final _spine_bone_pose_get_world_scale_xPtr = + _lookup>('spine_bone_pose_get_world_scale_x'); + late final _spine_bone_pose_get_world_scale_x = + _spine_bone_pose_get_world_scale_xPtr.asFunction(); + + double spine_bone_pose_get_world_scale_y( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_world_scale_y( + self, + ); + } + + late final _spine_bone_pose_get_world_scale_yPtr = + _lookup>('spine_bone_pose_get_world_scale_y'); + late final _spine_bone_pose_get_world_scale_y = + _spine_bone_pose_get_world_scale_yPtr.asFunction(); + + void spine_bone_pose_world_to_local( + spine_bone_pose self, + double worldX, + double worldY, + ffi.Pointer outLocalX, + ffi.Pointer outLocalY, + ) { + return _spine_bone_pose_world_to_local( + self, + worldX, + worldY, + outLocalX, + outLocalY, + ); + } + + late final _spine_bone_pose_world_to_localPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(spine_bone_pose, ffi.Float, ffi.Float, ffi.Pointer, + ffi.Pointer)>>('spine_bone_pose_world_to_local'); + late final _spine_bone_pose_world_to_local = _spine_bone_pose_world_to_localPtr + .asFunction, ffi.Pointer)>(); + + void spine_bone_pose_local_to_world( + spine_bone_pose self, + double localX, + double localY, + ffi.Pointer outWorldX, + ffi.Pointer outWorldY, + ) { + return _spine_bone_pose_local_to_world( + self, + localX, + localY, + outWorldX, + outWorldY, + ); + } + + late final _spine_bone_pose_local_to_worldPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(spine_bone_pose, ffi.Float, ffi.Float, ffi.Pointer, + ffi.Pointer)>>('spine_bone_pose_local_to_world'); + late final _spine_bone_pose_local_to_world = _spine_bone_pose_local_to_worldPtr + .asFunction, ffi.Pointer)>(); + + void spine_bone_pose_world_to_parent( + spine_bone_pose self, + double worldX, + double worldY, + ffi.Pointer outParentX, + ffi.Pointer outParentY, + ) { + return _spine_bone_pose_world_to_parent( + self, + worldX, + worldY, + outParentX, + outParentY, + ); + } + + late final _spine_bone_pose_world_to_parentPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(spine_bone_pose, ffi.Float, ffi.Float, ffi.Pointer, + ffi.Pointer)>>('spine_bone_pose_world_to_parent'); + late final _spine_bone_pose_world_to_parent = _spine_bone_pose_world_to_parentPtr + .asFunction, ffi.Pointer)>(); + + void spine_bone_pose_parent_to_world( + spine_bone_pose self, + double parentX, + double parentY, + ffi.Pointer outWorldX, + ffi.Pointer outWorldY, + ) { + return _spine_bone_pose_parent_to_world( + self, + parentX, + parentY, + outWorldX, + outWorldY, + ); + } + + late final _spine_bone_pose_parent_to_worldPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(spine_bone_pose, ffi.Float, ffi.Float, ffi.Pointer, + ffi.Pointer)>>('spine_bone_pose_parent_to_world'); + late final _spine_bone_pose_parent_to_world = _spine_bone_pose_parent_to_worldPtr + .asFunction, ffi.Pointer)>(); + + double spine_bone_pose_world_to_local_rotation( + spine_bone_pose self, + double worldRotation, + ) { + return _spine_bone_pose_world_to_local_rotation( + self, + worldRotation, + ); + } + + late final _spine_bone_pose_world_to_local_rotationPtr = + _lookup>( + 'spine_bone_pose_world_to_local_rotation'); + late final _spine_bone_pose_world_to_local_rotation = + _spine_bone_pose_world_to_local_rotationPtr.asFunction(); + + double spine_bone_pose_local_to_world_rotation( + spine_bone_pose self, + double localRotation, + ) { + return _spine_bone_pose_local_to_world_rotation( + self, + localRotation, + ); + } + + late final _spine_bone_pose_local_to_world_rotationPtr = + _lookup>( + 'spine_bone_pose_local_to_world_rotation'); + late final _spine_bone_pose_local_to_world_rotation = + _spine_bone_pose_local_to_world_rotationPtr.asFunction(); + + void spine_bone_pose_rotate_world( + spine_bone_pose self, + double degrees, + ) { + return _spine_bone_pose_rotate_world( + self, + degrees, + ); + } + + late final _spine_bone_pose_rotate_worldPtr = + _lookup>('spine_bone_pose_rotate_world'); + late final _spine_bone_pose_rotate_world = + _spine_bone_pose_rotate_worldPtr.asFunction(); + + void spine_bone_pose_set( + spine_bone_pose self, + spine_bone_local pose, + ) { + return _spine_bone_pose_set( + self, + pose, + ); + } + + late final _spine_bone_pose_setPtr = + _lookup>('spine_bone_pose_set'); + late final _spine_bone_pose_set = + _spine_bone_pose_setPtr.asFunction(); + + double spine_bone_pose_get_x( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_x( + self, + ); + } + + late final _spine_bone_pose_get_xPtr = + _lookup>('spine_bone_pose_get_x'); + late final _spine_bone_pose_get_x = _spine_bone_pose_get_xPtr.asFunction(); + + void spine_bone_pose_set_x( + spine_bone_pose self, + double x, + ) { + return _spine_bone_pose_set_x( + self, + x, + ); + } + + late final _spine_bone_pose_set_xPtr = + _lookup>('spine_bone_pose_set_x'); + late final _spine_bone_pose_set_x = _spine_bone_pose_set_xPtr.asFunction(); + + double spine_bone_pose_get_y( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_y( + self, + ); + } + + late final _spine_bone_pose_get_yPtr = + _lookup>('spine_bone_pose_get_y'); + late final _spine_bone_pose_get_y = _spine_bone_pose_get_yPtr.asFunction(); + + void spine_bone_pose_set_y( + spine_bone_pose self, + double y, + ) { + return _spine_bone_pose_set_y( + self, + y, + ); + } + + late final _spine_bone_pose_set_yPtr = + _lookup>('spine_bone_pose_set_y'); + late final _spine_bone_pose_set_y = _spine_bone_pose_set_yPtr.asFunction(); + + void spine_bone_pose_set_position( + spine_bone_pose self, + double x, + double y, + ) { + return _spine_bone_pose_set_position( + self, + x, + y, + ); + } + + late final _spine_bone_pose_set_positionPtr = + _lookup>( + 'spine_bone_pose_set_position'); + late final _spine_bone_pose_set_position = + _spine_bone_pose_set_positionPtr.asFunction(); + + double spine_bone_pose_get_rotation( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_rotation( + self, + ); + } + + late final _spine_bone_pose_get_rotationPtr = + _lookup>('spine_bone_pose_get_rotation'); + late final _spine_bone_pose_get_rotation = + _spine_bone_pose_get_rotationPtr.asFunction(); + + void spine_bone_pose_set_rotation( + spine_bone_pose self, + double rotation, + ) { + return _spine_bone_pose_set_rotation( + self, + rotation, + ); + } + + late final _spine_bone_pose_set_rotationPtr = + _lookup>('spine_bone_pose_set_rotation'); + late final _spine_bone_pose_set_rotation = + _spine_bone_pose_set_rotationPtr.asFunction(); + + double spine_bone_pose_get_scale_x( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_scale_x( + self, + ); + } + + late final _spine_bone_pose_get_scale_xPtr = + _lookup>('spine_bone_pose_get_scale_x'); + late final _spine_bone_pose_get_scale_x = + _spine_bone_pose_get_scale_xPtr.asFunction(); + + void spine_bone_pose_set_scale_x( + spine_bone_pose self, + double scaleX, + ) { + return _spine_bone_pose_set_scale_x( + self, + scaleX, + ); + } + + late final _spine_bone_pose_set_scale_xPtr = + _lookup>('spine_bone_pose_set_scale_x'); + late final _spine_bone_pose_set_scale_x = + _spine_bone_pose_set_scale_xPtr.asFunction(); + + double spine_bone_pose_get_scale_y( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_scale_y( + self, + ); + } + + late final _spine_bone_pose_get_scale_yPtr = + _lookup>('spine_bone_pose_get_scale_y'); + late final _spine_bone_pose_get_scale_y = + _spine_bone_pose_get_scale_yPtr.asFunction(); + + void spine_bone_pose_set_scale_y( + spine_bone_pose self, + double scaleY, + ) { + return _spine_bone_pose_set_scale_y( + self, + scaleY, + ); + } + + late final _spine_bone_pose_set_scale_yPtr = + _lookup>('spine_bone_pose_set_scale_y'); + late final _spine_bone_pose_set_scale_y = + _spine_bone_pose_set_scale_yPtr.asFunction(); + + void spine_bone_pose_set_scale_1( + spine_bone_pose self, + double scaleX, + double scaleY, + ) { + return _spine_bone_pose_set_scale_1( + self, + scaleX, + scaleY, + ); + } + + late final _spine_bone_pose_set_scale_1Ptr = + _lookup>( + 'spine_bone_pose_set_scale_1'); + late final _spine_bone_pose_set_scale_1 = + _spine_bone_pose_set_scale_1Ptr.asFunction(); + + void spine_bone_pose_set_scale_2( + spine_bone_pose self, + double scale, + ) { + return _spine_bone_pose_set_scale_2( + self, + scale, + ); + } + + late final _spine_bone_pose_set_scale_2Ptr = + _lookup>('spine_bone_pose_set_scale_2'); + late final _spine_bone_pose_set_scale_2 = + _spine_bone_pose_set_scale_2Ptr.asFunction(); + + double spine_bone_pose_get_shear_x( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_shear_x( + self, + ); + } + + late final _spine_bone_pose_get_shear_xPtr = + _lookup>('spine_bone_pose_get_shear_x'); + late final _spine_bone_pose_get_shear_x = + _spine_bone_pose_get_shear_xPtr.asFunction(); + + void spine_bone_pose_set_shear_x( + spine_bone_pose self, + double shearX, + ) { + return _spine_bone_pose_set_shear_x( + self, + shearX, + ); + } + + late final _spine_bone_pose_set_shear_xPtr = + _lookup>('spine_bone_pose_set_shear_x'); + late final _spine_bone_pose_set_shear_x = + _spine_bone_pose_set_shear_xPtr.asFunction(); + + double spine_bone_pose_get_shear_y( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_shear_y( + self, + ); + } + + late final _spine_bone_pose_get_shear_yPtr = + _lookup>('spine_bone_pose_get_shear_y'); + late final _spine_bone_pose_get_shear_y = + _spine_bone_pose_get_shear_yPtr.asFunction(); + + void spine_bone_pose_set_shear_y( + spine_bone_pose self, + double shearY, + ) { + return _spine_bone_pose_set_shear_y( + self, + shearY, + ); + } + + late final _spine_bone_pose_set_shear_yPtr = + _lookup>('spine_bone_pose_set_shear_y'); + late final _spine_bone_pose_set_shear_y = + _spine_bone_pose_set_shear_yPtr.asFunction(); + + int spine_bone_pose_get_inherit( + spine_bone_pose self, + ) { + return _spine_bone_pose_get_inherit( + self, + ); + } + + late final _spine_bone_pose_get_inheritPtr = + _lookup>('spine_bone_pose_get_inherit'); + late final _spine_bone_pose_get_inherit = _spine_bone_pose_get_inheritPtr.asFunction(); + + void spine_bone_pose_set_inherit( + spine_bone_pose self, + int inherit, + ) { + return _spine_bone_pose_set_inherit( + self, + inherit, + ); + } + + late final _spine_bone_pose_set_inheritPtr = + _lookup>('spine_bone_pose_set_inherit'); + late final _spine_bone_pose_set_inherit = + _spine_bone_pose_set_inheritPtr.asFunction(); + + spine_rtti spine_bone_pose_rtti() { + return _spine_bone_pose_rtti(); + } + + late final _spine_bone_pose_rttiPtr = _lookup>('spine_bone_pose_rtti'); + late final _spine_bone_pose_rtti = _spine_bone_pose_rttiPtr.asFunction(); + void spine_atlas_dispose( spine_atlas self, ) { @@ -6922,7 +7709,7 @@ class SpineDartBindings { late final _spine_skin_entry_get_attachment = _spine_skin_entry_get_attachmentPtr.asFunction(); - /// Skeleton bounds function + /// Skeleton functions spine_bounds spine_skeleton_get_bounds( spine_skeleton skeleton, ) { @@ -6936,6 +7723,92 @@ class SpineDartBindings { late final _spine_skeleton_get_bounds = _spine_skeleton_get_boundsPtr.asFunction(); + spine_vector spine_skeleton_get_position_v( + spine_skeleton skeleton, + ) { + return _spine_skeleton_get_position_v( + skeleton, + ); + } + + late final _spine_skeleton_get_position_vPtr = + _lookup>('spine_skeleton_get_position_v'); + late final _spine_skeleton_get_position_v = + _spine_skeleton_get_position_vPtr.asFunction(); + + /// BonePose functions + spine_vector spine_bone_pose_world_to_local_v( + spine_bone_pose self, + double world_x, + double world_y, + ) { + return _spine_bone_pose_world_to_local_v( + self, + world_x, + world_y, + ); + } + + late final _spine_bone_pose_world_to_local_vPtr = + _lookup>( + 'spine_bone_pose_world_to_local_v'); + late final _spine_bone_pose_world_to_local_v = + _spine_bone_pose_world_to_local_vPtr.asFunction(); + + spine_vector spine_bone_pose_local_to_world_v( + spine_bone_pose self, + double local_x, + double local_y, + ) { + return _spine_bone_pose_local_to_world_v( + self, + local_x, + local_y, + ); + } + + late final _spine_bone_pose_local_to_world_vPtr = + _lookup>( + 'spine_bone_pose_local_to_world_v'); + late final _spine_bone_pose_local_to_world_v = + _spine_bone_pose_local_to_world_vPtr.asFunction(); + + spine_vector spine_bone_pose_world_to_parent_v( + spine_bone_pose self, + double world_x, + double world_y, + ) { + return _spine_bone_pose_world_to_parent_v( + self, + world_x, + world_y, + ); + } + + late final _spine_bone_pose_world_to_parent_vPtr = + _lookup>( + 'spine_bone_pose_world_to_parent_v'); + late final _spine_bone_pose_world_to_parent_v = + _spine_bone_pose_world_to_parent_vPtr.asFunction(); + + spine_vector spine_bone_pose_parent_to_world_v( + spine_bone_pose self, + double parent_x, + double parent_y, + ) { + return _spine_bone_pose_parent_to_world_v( + self, + parent_x, + parent_y, + ); + } + + late final _spine_bone_pose_parent_to_world_vPtr = + _lookup>( + 'spine_bone_pose_parent_to_world_v'); + late final _spine_bone_pose_parent_to_world_v = + _spine_bone_pose_parent_to_world_vPtr.asFunction(); + spine_alpha_timeline spine_alpha_timeline_create( int frameCount, int bezierCount, @@ -6985,7 +7858,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -6996,7 +7869,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -7467,7 +8340,7 @@ class SpineDartBindings { double lastTime, double time, bool loop, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -7479,7 +8352,7 @@ class SpineDartBindings { lastTime, time, loop, - pEvents, + events, alpha, blend, direction, @@ -9567,7 +10440,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -9578,7 +10451,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -10452,793 +11325,6 @@ class SpineDartBindings { late final _spine_bone_local_set_inherit = _spine_bone_local_set_inheritPtr.asFunction(); - spine_bone_pose spine_bone_pose_create() { - return _spine_bone_pose_create(); - } - - late final _spine_bone_pose_createPtr = - _lookup>('spine_bone_pose_create'); - late final _spine_bone_pose_create = _spine_bone_pose_createPtr.asFunction(); - - void spine_bone_pose_dispose( - spine_bone_pose self, - ) { - return _spine_bone_pose_dispose( - self, - ); - } - - late final _spine_bone_pose_disposePtr = - _lookup>('spine_bone_pose_dispose'); - late final _spine_bone_pose_dispose = _spine_bone_pose_disposePtr.asFunction(); - - spine_rtti spine_bone_pose_get_rtti( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_rtti( - self, - ); - } - - late final _spine_bone_pose_get_rttiPtr = - _lookup>('spine_bone_pose_get_rtti'); - late final _spine_bone_pose_get_rtti = - _spine_bone_pose_get_rttiPtr.asFunction(); - - void spine_bone_pose_update( - spine_bone_pose self, - spine_skeleton skeleton, - int physics, - ) { - return _spine_bone_pose_update( - self, - skeleton, - physics, - ); - } - - late final _spine_bone_pose_updatePtr = - _lookup>( - 'spine_bone_pose_update'); - late final _spine_bone_pose_update = - _spine_bone_pose_updatePtr.asFunction(); - - void spine_bone_pose_update_world_transform( - spine_bone_pose self, - spine_skeleton skeleton, - ) { - return _spine_bone_pose_update_world_transform( - self, - skeleton, - ); - } - - late final _spine_bone_pose_update_world_transformPtr = - _lookup>( - 'spine_bone_pose_update_world_transform'); - late final _spine_bone_pose_update_world_transform = - _spine_bone_pose_update_world_transformPtr.asFunction(); - - void spine_bone_pose_update_local_transform( - spine_bone_pose self, - spine_skeleton skeleton, - ) { - return _spine_bone_pose_update_local_transform( - self, - skeleton, - ); - } - - late final _spine_bone_pose_update_local_transformPtr = - _lookup>( - 'spine_bone_pose_update_local_transform'); - late final _spine_bone_pose_update_local_transform = - _spine_bone_pose_update_local_transformPtr.asFunction(); - - void spine_bone_pose_validate_local_transform( - spine_bone_pose self, - spine_skeleton skeleton, - ) { - return _spine_bone_pose_validate_local_transform( - self, - skeleton, - ); - } - - late final _spine_bone_pose_validate_local_transformPtr = - _lookup>( - 'spine_bone_pose_validate_local_transform'); - late final _spine_bone_pose_validate_local_transform = - _spine_bone_pose_validate_local_transformPtr.asFunction(); - - void spine_bone_pose_modify_local( - spine_bone_pose self, - spine_skeleton skeleton, - ) { - return _spine_bone_pose_modify_local( - self, - skeleton, - ); - } - - late final _spine_bone_pose_modify_localPtr = - _lookup>('spine_bone_pose_modify_local'); - late final _spine_bone_pose_modify_local = - _spine_bone_pose_modify_localPtr.asFunction(); - - void spine_bone_pose_modify_world( - spine_bone_pose self, - int update, - ) { - return _spine_bone_pose_modify_world( - self, - update, - ); - } - - late final _spine_bone_pose_modify_worldPtr = - _lookup>('spine_bone_pose_modify_world'); - late final _spine_bone_pose_modify_world = - _spine_bone_pose_modify_worldPtr.asFunction(); - - void spine_bone_pose_reset_world( - spine_bone_pose self, - int update, - ) { - return _spine_bone_pose_reset_world( - self, - update, - ); - } - - late final _spine_bone_pose_reset_worldPtr = - _lookup>('spine_bone_pose_reset_world'); - late final _spine_bone_pose_reset_world = - _spine_bone_pose_reset_worldPtr.asFunction(); - - double spine_bone_pose_get_a( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_a( - self, - ); - } - - late final _spine_bone_pose_get_aPtr = - _lookup>('spine_bone_pose_get_a'); - late final _spine_bone_pose_get_a = _spine_bone_pose_get_aPtr.asFunction(); - - void spine_bone_pose_set_a( - spine_bone_pose self, - double a, - ) { - return _spine_bone_pose_set_a( - self, - a, - ); - } - - late final _spine_bone_pose_set_aPtr = - _lookup>('spine_bone_pose_set_a'); - late final _spine_bone_pose_set_a = _spine_bone_pose_set_aPtr.asFunction(); - - double spine_bone_pose_get_b( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_b( - self, - ); - } - - late final _spine_bone_pose_get_bPtr = - _lookup>('spine_bone_pose_get_b'); - late final _spine_bone_pose_get_b = _spine_bone_pose_get_bPtr.asFunction(); - - void spine_bone_pose_set_b( - spine_bone_pose self, - double b, - ) { - return _spine_bone_pose_set_b( - self, - b, - ); - } - - late final _spine_bone_pose_set_bPtr = - _lookup>('spine_bone_pose_set_b'); - late final _spine_bone_pose_set_b = _spine_bone_pose_set_bPtr.asFunction(); - - double spine_bone_pose_get_c( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_c( - self, - ); - } - - late final _spine_bone_pose_get_cPtr = - _lookup>('spine_bone_pose_get_c'); - late final _spine_bone_pose_get_c = _spine_bone_pose_get_cPtr.asFunction(); - - void spine_bone_pose_set_c( - spine_bone_pose self, - double c, - ) { - return _spine_bone_pose_set_c( - self, - c, - ); - } - - late final _spine_bone_pose_set_cPtr = - _lookup>('spine_bone_pose_set_c'); - late final _spine_bone_pose_set_c = _spine_bone_pose_set_cPtr.asFunction(); - - double spine_bone_pose_get_d( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_d( - self, - ); - } - - late final _spine_bone_pose_get_dPtr = - _lookup>('spine_bone_pose_get_d'); - late final _spine_bone_pose_get_d = _spine_bone_pose_get_dPtr.asFunction(); - - void spine_bone_pose_set_d( - spine_bone_pose self, - double d, - ) { - return _spine_bone_pose_set_d( - self, - d, - ); - } - - late final _spine_bone_pose_set_dPtr = - _lookup>('spine_bone_pose_set_d'); - late final _spine_bone_pose_set_d = _spine_bone_pose_set_dPtr.asFunction(); - - double spine_bone_pose_get_world_x( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_world_x( - self, - ); - } - - late final _spine_bone_pose_get_world_xPtr = - _lookup>('spine_bone_pose_get_world_x'); - late final _spine_bone_pose_get_world_x = - _spine_bone_pose_get_world_xPtr.asFunction(); - - void spine_bone_pose_set_world_x( - spine_bone_pose self, - double worldX, - ) { - return _spine_bone_pose_set_world_x( - self, - worldX, - ); - } - - late final _spine_bone_pose_set_world_xPtr = - _lookup>('spine_bone_pose_set_world_x'); - late final _spine_bone_pose_set_world_x = - _spine_bone_pose_set_world_xPtr.asFunction(); - - double spine_bone_pose_get_world_y( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_world_y( - self, - ); - } - - late final _spine_bone_pose_get_world_yPtr = - _lookup>('spine_bone_pose_get_world_y'); - late final _spine_bone_pose_get_world_y = - _spine_bone_pose_get_world_yPtr.asFunction(); - - void spine_bone_pose_set_world_y( - spine_bone_pose self, - double worldY, - ) { - return _spine_bone_pose_set_world_y( - self, - worldY, - ); - } - - late final _spine_bone_pose_set_world_yPtr = - _lookup>('spine_bone_pose_set_world_y'); - late final _spine_bone_pose_set_world_y = - _spine_bone_pose_set_world_yPtr.asFunction(); - - double spine_bone_pose_get_world_rotation_x( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_world_rotation_x( - self, - ); - } - - late final _spine_bone_pose_get_world_rotation_xPtr = - _lookup>('spine_bone_pose_get_world_rotation_x'); - late final _spine_bone_pose_get_world_rotation_x = - _spine_bone_pose_get_world_rotation_xPtr.asFunction(); - - double spine_bone_pose_get_world_rotation_y( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_world_rotation_y( - self, - ); - } - - late final _spine_bone_pose_get_world_rotation_yPtr = - _lookup>('spine_bone_pose_get_world_rotation_y'); - late final _spine_bone_pose_get_world_rotation_y = - _spine_bone_pose_get_world_rotation_yPtr.asFunction(); - - double spine_bone_pose_get_world_scale_x( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_world_scale_x( - self, - ); - } - - late final _spine_bone_pose_get_world_scale_xPtr = - _lookup>('spine_bone_pose_get_world_scale_x'); - late final _spine_bone_pose_get_world_scale_x = - _spine_bone_pose_get_world_scale_xPtr.asFunction(); - - double spine_bone_pose_get_world_scale_y( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_world_scale_y( - self, - ); - } - - late final _spine_bone_pose_get_world_scale_yPtr = - _lookup>('spine_bone_pose_get_world_scale_y'); - late final _spine_bone_pose_get_world_scale_y = - _spine_bone_pose_get_world_scale_yPtr.asFunction(); - - void spine_bone_pose_world_to_local( - spine_bone_pose self, - double worldX, - double worldY, - ffi.Pointer outLocalX, - ffi.Pointer outLocalY, - ) { - return _spine_bone_pose_world_to_local( - self, - worldX, - worldY, - outLocalX, - outLocalY, - ); - } - - late final _spine_bone_pose_world_to_localPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(spine_bone_pose, ffi.Float, ffi.Float, ffi.Pointer, - ffi.Pointer)>>('spine_bone_pose_world_to_local'); - late final _spine_bone_pose_world_to_local = _spine_bone_pose_world_to_localPtr - .asFunction, ffi.Pointer)>(); - - void spine_bone_pose_local_to_world( - spine_bone_pose self, - double localX, - double localY, - ffi.Pointer outWorldX, - ffi.Pointer outWorldY, - ) { - return _spine_bone_pose_local_to_world( - self, - localX, - localY, - outWorldX, - outWorldY, - ); - } - - late final _spine_bone_pose_local_to_worldPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(spine_bone_pose, ffi.Float, ffi.Float, ffi.Pointer, - ffi.Pointer)>>('spine_bone_pose_local_to_world'); - late final _spine_bone_pose_local_to_world = _spine_bone_pose_local_to_worldPtr - .asFunction, ffi.Pointer)>(); - - void spine_bone_pose_world_to_parent( - spine_bone_pose self, - double worldX, - double worldY, - ffi.Pointer outParentX, - ffi.Pointer outParentY, - ) { - return _spine_bone_pose_world_to_parent( - self, - worldX, - worldY, - outParentX, - outParentY, - ); - } - - late final _spine_bone_pose_world_to_parentPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(spine_bone_pose, ffi.Float, ffi.Float, ffi.Pointer, - ffi.Pointer)>>('spine_bone_pose_world_to_parent'); - late final _spine_bone_pose_world_to_parent = _spine_bone_pose_world_to_parentPtr - .asFunction, ffi.Pointer)>(); - - void spine_bone_pose_parent_to_world( - spine_bone_pose self, - double parentX, - double parentY, - ffi.Pointer outWorldX, - ffi.Pointer outWorldY, - ) { - return _spine_bone_pose_parent_to_world( - self, - parentX, - parentY, - outWorldX, - outWorldY, - ); - } - - late final _spine_bone_pose_parent_to_worldPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(spine_bone_pose, ffi.Float, ffi.Float, ffi.Pointer, - ffi.Pointer)>>('spine_bone_pose_parent_to_world'); - late final _spine_bone_pose_parent_to_world = _spine_bone_pose_parent_to_worldPtr - .asFunction, ffi.Pointer)>(); - - double spine_bone_pose_world_to_local_rotation( - spine_bone_pose self, - double worldRotation, - ) { - return _spine_bone_pose_world_to_local_rotation( - self, - worldRotation, - ); - } - - late final _spine_bone_pose_world_to_local_rotationPtr = - _lookup>( - 'spine_bone_pose_world_to_local_rotation'); - late final _spine_bone_pose_world_to_local_rotation = - _spine_bone_pose_world_to_local_rotationPtr.asFunction(); - - double spine_bone_pose_local_to_world_rotation( - spine_bone_pose self, - double localRotation, - ) { - return _spine_bone_pose_local_to_world_rotation( - self, - localRotation, - ); - } - - late final _spine_bone_pose_local_to_world_rotationPtr = - _lookup>( - 'spine_bone_pose_local_to_world_rotation'); - late final _spine_bone_pose_local_to_world_rotation = - _spine_bone_pose_local_to_world_rotationPtr.asFunction(); - - void spine_bone_pose_rotate_world( - spine_bone_pose self, - double degrees, - ) { - return _spine_bone_pose_rotate_world( - self, - degrees, - ); - } - - late final _spine_bone_pose_rotate_worldPtr = - _lookup>('spine_bone_pose_rotate_world'); - late final _spine_bone_pose_rotate_world = - _spine_bone_pose_rotate_worldPtr.asFunction(); - - void spine_bone_pose_set( - spine_bone_pose self, - spine_bone_local pose, - ) { - return _spine_bone_pose_set( - self, - pose, - ); - } - - late final _spine_bone_pose_setPtr = - _lookup>('spine_bone_pose_set'); - late final _spine_bone_pose_set = - _spine_bone_pose_setPtr.asFunction(); - - double spine_bone_pose_get_x( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_x( - self, - ); - } - - late final _spine_bone_pose_get_xPtr = - _lookup>('spine_bone_pose_get_x'); - late final _spine_bone_pose_get_x = _spine_bone_pose_get_xPtr.asFunction(); - - void spine_bone_pose_set_x( - spine_bone_pose self, - double x, - ) { - return _spine_bone_pose_set_x( - self, - x, - ); - } - - late final _spine_bone_pose_set_xPtr = - _lookup>('spine_bone_pose_set_x'); - late final _spine_bone_pose_set_x = _spine_bone_pose_set_xPtr.asFunction(); - - double spine_bone_pose_get_y( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_y( - self, - ); - } - - late final _spine_bone_pose_get_yPtr = - _lookup>('spine_bone_pose_get_y'); - late final _spine_bone_pose_get_y = _spine_bone_pose_get_yPtr.asFunction(); - - void spine_bone_pose_set_y( - spine_bone_pose self, - double y, - ) { - return _spine_bone_pose_set_y( - self, - y, - ); - } - - late final _spine_bone_pose_set_yPtr = - _lookup>('spine_bone_pose_set_y'); - late final _spine_bone_pose_set_y = _spine_bone_pose_set_yPtr.asFunction(); - - void spine_bone_pose_set_position( - spine_bone_pose self, - double x, - double y, - ) { - return _spine_bone_pose_set_position( - self, - x, - y, - ); - } - - late final _spine_bone_pose_set_positionPtr = - _lookup>( - 'spine_bone_pose_set_position'); - late final _spine_bone_pose_set_position = - _spine_bone_pose_set_positionPtr.asFunction(); - - double spine_bone_pose_get_rotation( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_rotation( - self, - ); - } - - late final _spine_bone_pose_get_rotationPtr = - _lookup>('spine_bone_pose_get_rotation'); - late final _spine_bone_pose_get_rotation = - _spine_bone_pose_get_rotationPtr.asFunction(); - - void spine_bone_pose_set_rotation( - spine_bone_pose self, - double rotation, - ) { - return _spine_bone_pose_set_rotation( - self, - rotation, - ); - } - - late final _spine_bone_pose_set_rotationPtr = - _lookup>('spine_bone_pose_set_rotation'); - late final _spine_bone_pose_set_rotation = - _spine_bone_pose_set_rotationPtr.asFunction(); - - double spine_bone_pose_get_scale_x( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_scale_x( - self, - ); - } - - late final _spine_bone_pose_get_scale_xPtr = - _lookup>('spine_bone_pose_get_scale_x'); - late final _spine_bone_pose_get_scale_x = - _spine_bone_pose_get_scale_xPtr.asFunction(); - - void spine_bone_pose_set_scale_x( - spine_bone_pose self, - double scaleX, - ) { - return _spine_bone_pose_set_scale_x( - self, - scaleX, - ); - } - - late final _spine_bone_pose_set_scale_xPtr = - _lookup>('spine_bone_pose_set_scale_x'); - late final _spine_bone_pose_set_scale_x = - _spine_bone_pose_set_scale_xPtr.asFunction(); - - double spine_bone_pose_get_scale_y( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_scale_y( - self, - ); - } - - late final _spine_bone_pose_get_scale_yPtr = - _lookup>('spine_bone_pose_get_scale_y'); - late final _spine_bone_pose_get_scale_y = - _spine_bone_pose_get_scale_yPtr.asFunction(); - - void spine_bone_pose_set_scale_y( - spine_bone_pose self, - double scaleY, - ) { - return _spine_bone_pose_set_scale_y( - self, - scaleY, - ); - } - - late final _spine_bone_pose_set_scale_yPtr = - _lookup>('spine_bone_pose_set_scale_y'); - late final _spine_bone_pose_set_scale_y = - _spine_bone_pose_set_scale_yPtr.asFunction(); - - void spine_bone_pose_set_scale_1( - spine_bone_pose self, - double scaleX, - double scaleY, - ) { - return _spine_bone_pose_set_scale_1( - self, - scaleX, - scaleY, - ); - } - - late final _spine_bone_pose_set_scale_1Ptr = - _lookup>( - 'spine_bone_pose_set_scale_1'); - late final _spine_bone_pose_set_scale_1 = - _spine_bone_pose_set_scale_1Ptr.asFunction(); - - void spine_bone_pose_set_scale_2( - spine_bone_pose self, - double scale, - ) { - return _spine_bone_pose_set_scale_2( - self, - scale, - ); - } - - late final _spine_bone_pose_set_scale_2Ptr = - _lookup>('spine_bone_pose_set_scale_2'); - late final _spine_bone_pose_set_scale_2 = - _spine_bone_pose_set_scale_2Ptr.asFunction(); - - double spine_bone_pose_get_shear_x( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_shear_x( - self, - ); - } - - late final _spine_bone_pose_get_shear_xPtr = - _lookup>('spine_bone_pose_get_shear_x'); - late final _spine_bone_pose_get_shear_x = - _spine_bone_pose_get_shear_xPtr.asFunction(); - - void spine_bone_pose_set_shear_x( - spine_bone_pose self, - double shearX, - ) { - return _spine_bone_pose_set_shear_x( - self, - shearX, - ); - } - - late final _spine_bone_pose_set_shear_xPtr = - _lookup>('spine_bone_pose_set_shear_x'); - late final _spine_bone_pose_set_shear_x = - _spine_bone_pose_set_shear_xPtr.asFunction(); - - double spine_bone_pose_get_shear_y( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_shear_y( - self, - ); - } - - late final _spine_bone_pose_get_shear_yPtr = - _lookup>('spine_bone_pose_get_shear_y'); - late final _spine_bone_pose_get_shear_y = - _spine_bone_pose_get_shear_yPtr.asFunction(); - - void spine_bone_pose_set_shear_y( - spine_bone_pose self, - double shearY, - ) { - return _spine_bone_pose_set_shear_y( - self, - shearY, - ); - } - - late final _spine_bone_pose_set_shear_yPtr = - _lookup>('spine_bone_pose_set_shear_y'); - late final _spine_bone_pose_set_shear_y = - _spine_bone_pose_set_shear_yPtr.asFunction(); - - int spine_bone_pose_get_inherit( - spine_bone_pose self, - ) { - return _spine_bone_pose_get_inherit( - self, - ); - } - - late final _spine_bone_pose_get_inheritPtr = - _lookup>('spine_bone_pose_get_inherit'); - late final _spine_bone_pose_get_inherit = _spine_bone_pose_get_inheritPtr.asFunction(); - - void spine_bone_pose_set_inherit( - spine_bone_pose self, - int inherit, - ) { - return _spine_bone_pose_set_inherit( - self, - inherit, - ); - } - - late final _spine_bone_pose_set_inheritPtr = - _lookup>('spine_bone_pose_set_inherit'); - late final _spine_bone_pose_set_inherit = - _spine_bone_pose_set_inheritPtr.asFunction(); - - spine_rtti spine_bone_pose_rtti() { - return _spine_bone_pose_rtti(); - } - - late final _spine_bone_pose_rttiPtr = _lookup>('spine_bone_pose_rtti'); - late final _spine_bone_pose_rtti = _spine_bone_pose_rttiPtr.asFunction(); - void spine_bone_timeline_dispose( spine_bone_timeline self, ) { @@ -11333,7 +11419,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -11344,7 +11430,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -11737,7 +11823,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -11748,7 +11834,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -13564,7 +13650,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -13575,7 +13661,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -13804,7 +13890,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -13815,7 +13901,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -14181,7 +14267,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -14192,7 +14278,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -14453,7 +14539,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -14464,7 +14550,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -14683,7 +14769,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -14694,7 +14780,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -15360,7 +15446,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -15371,7 +15457,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -16742,7 +16828,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -16753,7 +16839,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -17091,7 +17177,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -17102,7 +17188,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -18982,7 +19068,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -18993,7 +19079,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -19507,7 +19593,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -19518,7 +19604,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -19979,7 +20065,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -19990,7 +20076,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -20759,7 +20845,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -20770,7 +20856,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -21808,7 +21894,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -21819,7 +21905,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -22282,7 +22368,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -22293,7 +22379,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -22755,7 +22841,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -22766,7 +22852,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -23224,7 +23310,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -23235,7 +23321,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -23937,7 +24023,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -23948,7 +24034,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -24160,7 +24246,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -24171,7 +24257,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -24615,7 +24701,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -24626,7 +24712,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -25069,7 +25155,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -25080,7 +25166,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -26703,7 +26789,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -26714,7 +26800,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -27017,7 +27103,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -27028,7 +27114,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -27326,7 +27412,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -27337,7 +27423,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -27632,7 +27718,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -27643,7 +27729,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -27912,7 +27998,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -27923,7 +28009,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -28390,7 +28476,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -28401,7 +28487,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -28694,7 +28780,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -28705,7 +28791,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -29121,7 +29207,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -29132,7 +29218,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -29740,7 +29826,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -29751,7 +29837,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -29961,7 +30047,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -29972,7 +30058,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -30265,7 +30351,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -30276,7 +30362,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -30692,7 +30778,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -30703,7 +30789,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -31481,7 +31567,7 @@ class SpineDartBindings { ffi.Pointer outWidth, ffi.Pointer outHeight, spine_array_float outVertexBuffer, - spine_skeleton_clipping clipper, + spine_skeleton_clipping clipping, ) { return _spine_skeleton_get_bounds_2( self, @@ -31490,7 +31576,7 @@ class SpineDartBindings { outWidth, outHeight, outVertexBuffer, - clipper, + clipping, ); } @@ -31693,6 +31779,24 @@ class SpineDartBindings { late final _spine_skeleton_set_position = _spine_skeleton_set_positionPtr.asFunction(); + void spine_skeleton_get_position( + spine_skeleton self, + ffi.Pointer x, + ffi.Pointer y, + ) { + return _spine_skeleton_get_position( + self, + x, + y, + ); + } + + late final _spine_skeleton_get_positionPtr = + _lookup, ffi.Pointer)>>( + 'spine_skeleton_get_position'); + late final _spine_skeleton_get_position = _spine_skeleton_get_positionPtr + .asFunction, ffi.Pointer)>(); + double spine_skeleton_get_wind_x( spine_skeleton self, ) { @@ -33442,7 +33546,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -33453,7 +33557,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -33963,7 +34067,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -33974,7 +34078,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -34496,7 +34600,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -34507,7 +34611,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -35396,7 +35500,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -35407,7 +35511,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -37996,7 +38100,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -38007,7 +38111,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -38347,7 +38451,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -38358,7 +38462,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -38660,7 +38764,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -38671,7 +38775,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -39091,7 +39195,7 @@ class SpineDartBindings { spine_skeleton skeleton, double lastTime, double time, - spine_array_event pEvents, + spine_array_event events, double alpha, int blend, int direction, @@ -39102,7 +39206,7 @@ class SpineDartBindings { skeleton, lastTime, time, - pEvents, + events, alpha, blend, direction, @@ -40789,6 +40893,9 @@ typedef spine_array_track_entry = ffi.Pointer; typedef spine_track_entry = ffi.Pointer; typedef spine_array_update = ffi.Pointer; typedef spine_update = ffi.Pointer; +typedef spine_rtti = ffi.Pointer; +typedef spine_skeleton = ffi.Pointer; +typedef spine_bone_local = ffi.Pointer; typedef spine_atlas = ffi.Pointer; typedef spine_skeleton_data = ffi.Pointer; @@ -40827,24 +40934,6 @@ final class spine_texture_loader_wrapper extends ffi.Struct { external int _dummy; } -typedef spine_atlas_result = ffi.Pointer; - -/// Texture loader callbacks -typedef spine_texture_loader_load_func = ffi.Pointer>; -typedef spine_texture_loader_load_funcFunction = ffi.Pointer Function(ffi.Pointer path); -typedef spine_texture_loader_unload_func = ffi.Pointer>; -typedef spine_texture_loader_unload_funcFunction = ffi.Void Function(ffi.Pointer texture); -typedef Dartspine_texture_loader_unload_funcFunction = void Function(ffi.Pointer texture); -typedef spine_skeleton_data_result = ffi.Pointer; -typedef spine_skeleton_drawable = ffi.Pointer; -typedef spine_render_command = ffi.Pointer; -typedef spine_skeleton = ffi.Pointer; -typedef spine_animation_state = ffi.Pointer; -typedef spine_animation_state_data = ffi.Pointer; -typedef spine_animation_state_events = ffi.Pointer; -typedef spine_skin_entries = ffi.Pointer; -typedef spine_skin_entry = ffi.Pointer; - /// Bounds struct final class spine_bounds extends ffi.Struct { @ffi.Float() @@ -40860,8 +40949,32 @@ final class spine_bounds extends ffi.Struct { external double height; } +/// Vector struct +final class spine_vector extends ffi.Struct { + @ffi.Float() + external double x; + + @ffi.Float() + external double y; +} + +typedef spine_atlas_result = ffi.Pointer; + +/// Texture loader callbacks +typedef spine_texture_loader_load_func = ffi.Pointer>; +typedef spine_texture_loader_load_funcFunction = ffi.Pointer Function(ffi.Pointer path); +typedef spine_texture_loader_unload_func = ffi.Pointer>; +typedef spine_texture_loader_unload_funcFunction = ffi.Void Function(ffi.Pointer texture); +typedef Dartspine_texture_loader_unload_funcFunction = void Function(ffi.Pointer texture); +typedef spine_skeleton_data_result = ffi.Pointer; +typedef spine_skeleton_drawable = ffi.Pointer; +typedef spine_render_command = ffi.Pointer; +typedef spine_animation_state = ffi.Pointer; +typedef spine_animation_state_data = ffi.Pointer; +typedef spine_animation_state_events = ffi.Pointer; +typedef spine_skin_entries = ffi.Pointer; +typedef spine_skin_entry = ffi.Pointer; typedef spine_alpha_timeline = ffi.Pointer; -typedef spine_rtti = ffi.Pointer; typedef spine_atlas_attachment_loader = ffi.Pointer; typedef spine_region_attachment = ffi.Pointer; typedef spine_sequence = ffi.Pointer; @@ -40871,7 +40984,6 @@ typedef spine_point_attachment = ffi.Pointer; typedef spine_clipping_attachment = ffi.Pointer; typedef spine_attachment_loader = ffi.Pointer; typedef spine_attachment_timeline = ffi.Pointer; -typedef spine_bone_local = ffi.Pointer; typedef spine_color = ffi.Pointer; typedef spine_bone_timeline = ffi.Pointer; typedef spine_bone_timeline1 = ffi.Pointer; diff --git a/spine-flutter/lib/generated/timeline.dart b/spine-flutter/lib/generated/timeline.dart index 5dc74cb06..d3264115b 100644 --- a/spine-flutter/lib/generated/timeline.dart +++ b/spine-flutter/lib/generated/timeline.dart @@ -52,10 +52,10 @@ abstract class Timeline { return Rtti.fromPointer(result); } - void apply(Skeleton skeleton, double lastTime, double time, ArrayEvent? pEvents, double alpha, MixBlend blend, + void apply(Skeleton skeleton, double lastTime, double time, ArrayEvent? events, double alpha, MixBlend blend, MixDirection direction, bool appliedPose) { SpineBindings.bindings.spine_timeline_apply(_ptr, skeleton.nativePtr.cast(), lastTime, time, - pEvents?.nativePtr.cast() ?? Pointer.fromAddress(0), alpha, blend.value, direction.value, appliedPose); + events?.nativePtr.cast() ?? Pointer.fromAddress(0), alpha, blend.value, direction.value, appliedPose); } int get frameEntries { diff --git a/spine-flutter/lib/spine_dart.dart b/spine-flutter/lib/spine_dart.dart index 1cde752ca..506e57dc7 100644 --- a/spine-flutter/lib/spine_dart.dart +++ b/spine-flutter/lib/spine_dart.dart @@ -50,6 +50,7 @@ import 'generated/event.dart'; import 'generated/event_type.dart'; import 'generated/render_command.dart'; import 'generated/physics.dart'; +import 'generated/bone_pose.dart'; // Export generated classes export 'generated/api.dart'; @@ -321,20 +322,24 @@ extension TrackEntryExtensions on TrackEntry { /// Represents a bounding box with position and dimensions class Bounds { - final double x; - final double y; - final double width; - final double height; - - const Bounds({ + double x; + double y; + double width; + double height; + + Bounds({ required this.x, required this.y, required this.width, required this.height, }); - - @override - String toString() => 'Bounds(x: $x, y: $y, width: $width, height: $height)'; +} + +class Vector { + double x; + double y; + + Vector({required this.x, required this.y}); } /// Extension to add bounds property to Skeleton @@ -349,6 +354,33 @@ extension SkeletonExtensions on Skeleton { height: spineBounds.height, ); } + + Vector getPosition() { + final position = SpineBindings.bindings.spine_skeleton_get_position_v(nativePtr.cast()); + return Vector(x: position.x, y: position.y); + } +} + +extension BonePoseExtensions on BonePose { + Vector worldToLocal(double worldX, double worldY) { + final result = SpineBindings.bindings.spine_bone_pose_world_to_local_v(nativePtr.cast(), worldX, worldY); + return Vector(x: result.x, y: result.y); + } + + Vector localToWorld(double localX, double localY) { + final result = SpineBindings.bindings.spine_bone_pose_local_to_world_v(nativePtr.cast(), localX, localY); + return Vector(x: result.x, y: result.y); + } + + Vector worldToParent(double worldX, double worldY) { + final result = SpineBindings.bindings.spine_bone_pose_world_to_parent_v(nativePtr.cast(), worldX, worldY); + return Vector(x: result.x, y: result.y); + } + + Vector parentToWorld(double parentX, double parentY) { + final result = SpineBindings.bindings.spine_bone_pose_parent_to_world_v(nativePtr.cast(), parentX, parentY); + return Vector(x: result.x, y: result.y); + } } /// Convenient drawable that combines skeleton, animation state, and rendering @@ -419,7 +451,7 @@ class SkeletonDrawable { // Apply animation state to skeleton animationState.apply(skeleton); - + // Update skeleton physics and world transforms skeleton.update(delta); skeleton.updateWorldTransform(Physics.update); diff --git a/spine-flutter/lib/spine_flutter.dart b/spine-flutter/lib/spine_flutter.dart index eb8a3e786..88b65a6f5 100644 --- a/spine-flutter/lib/spine_flutter.dart +++ b/spine-flutter/lib/spine_flutter.dart @@ -24,14 +24,13 @@ Future initSpineFlutter({bool useStaticLinkage = false, bool enableMemoryD } /// Flutter wrapper for Atlas that manages texture loading and Paint creation -class AtlasFlutter { +class AtlasFlutter extends Atlas { static FilterQuality filterQuality = FilterQuality.low; - final Atlas atlas; final List atlasPages; final List> atlasPagePaints; bool _disposed = false; - AtlasFlutter._(this.atlas, this.atlasPages, this.atlasPagePaints); + AtlasFlutter._(super.ptr, this.atlasPages, this.atlasPagePaints) : super.fromPointer(); /// Internal method to load atlas and images static Future _load(String atlasFileName, Future Function(String name) loadFile) async { @@ -77,7 +76,7 @@ class AtlasFlutter { paints.add(pagePaints); } - return AtlasFlutter._(atlas, pages, paints); + return AtlasFlutter._(atlas.nativePtr.cast(), pages, paints); } /// Loads an [AtlasFlutter] from the file [atlasFileName] in the root bundle or the optionally provided [bundle]. @@ -103,10 +102,11 @@ class AtlasFlutter { } /// Disposes all resources including the native atlas and images + @override void dispose() { if (_disposed) return; _disposed = true; - atlas.dispose(); + super.dispose(); for (final image in atlasPages) { image.dispose(); } @@ -114,6 +114,64 @@ class AtlasFlutter { } } +/// Flutter wrapper for SkeletonData that provides convenient loading methods +class SkeletonDataFlutter extends SkeletonData { + SkeletonDataFlutter._(super.ptr) : super.fromPointer(); + + /// Loads a [SkeletonDataFlutter] from the file [skeletonFile] in the root bundle or the optionally provided [bundle]. + /// Uses the provided [atlasFlutter] to resolve attachment images. + /// + /// Throws an [Exception] in case the skeleton data could not be loaded. + static Future fromAsset(AtlasFlutter atlas, String skeletonFile, {AssetBundle? bundle}) async { + bundle ??= rootBundle; + if (skeletonFile.endsWith(".json")) { + final jsonData = await bundle.loadString(skeletonFile); + final skeletonData = loadSkeletonDataJson(atlas, jsonData, path: skeletonFile); + return SkeletonDataFlutter._(skeletonData.nativePtr.cast()); + } else { + final binaryData = (await bundle.load(skeletonFile)).buffer.asUint8List(); + final skeletonData = loadSkeletonDataBinary(atlas, binaryData, path: skeletonFile); + return SkeletonDataFlutter._(skeletonData.nativePtr.cast()); + } + } + + /// Loads a [SkeletonDataFlutter] from the file [skeletonFile]. Uses the provided [atlasFlutter] to resolve attachment images. + /// + /// Throws an [Exception] in case the skeleton data could not be loaded. + static Future fromFile(AtlasFlutter atlasFlutter, String skeletonFile) async { + if (skeletonFile.endsWith(".json")) { + final jsonData = await File(skeletonFile).readAsString(); + final skeletonData = loadSkeletonDataJson(atlasFlutter, jsonData, path: skeletonFile); + return SkeletonDataFlutter._(skeletonData.nativePtr.cast()); + } else { + final binaryData = await File(skeletonFile).readAsBytes(); + final skeletonData = loadSkeletonDataBinary(atlasFlutter, binaryData, path: skeletonFile); + return SkeletonDataFlutter._(skeletonData.nativePtr.cast()); + } + } + + /// Loads a [SkeletonDataFlutter] from the URL [skeletonURL]. Uses the provided [atlasFlutter] to resolve attachment images. + /// + /// Throws an [Exception] in case the skeleton data could not be loaded. + static Future fromHttp(AtlasFlutter atlasFlutter, String skeletonURL) async { + if (skeletonURL.endsWith(".json")) { + final response = await http.get(Uri.parse(skeletonURL)); + if (response.statusCode != 200) { + throw Exception('Failed to load skeleton from $skeletonURL: ${response.statusCode}'); + } + final skeletonData = loadSkeletonDataJson(atlasFlutter, response.body, path: skeletonURL); + return SkeletonDataFlutter._(skeletonData.nativePtr.cast()); + } else { + final response = await http.get(Uri.parse(skeletonURL)); + if (response.statusCode != 200) { + throw Exception('Failed to load skeleton from $skeletonURL: ${response.statusCode}'); + } + final skeletonData = loadSkeletonDataBinary(atlasFlutter, response.bodyBytes, path: skeletonURL); + return SkeletonDataFlutter._(skeletonData.nativePtr.cast()); + } + } +} + /// Extension to convert Spine BlendMode to Flutter BlendMode extension BlendModeExtensions on BlendMode { rendering.BlendMode toFlutterBlendMode() { @@ -184,7 +242,6 @@ class RenderCommandFlutter { // See https://github.com/flutter/flutter/issues/127486 // // We thus batch all meshes not only by atlas page and blend mode, but also vertex color. - // See spine_flutter.cpp, batch_commands(). // // If the vertex color equals (1, 1, 1, 1), we do not store // colors, which will trigger the fast path in Impeller. Otherwise we have to go the slow path, which @@ -218,13 +275,13 @@ class RenderCommandFlutter { } } -/// A SkeletonDrawable bundles loading, updating, and rendering an [Atlas], [Skeleton], and [AnimationState] +/// A SkeletonDrawable bundles loading, updating, and rendering an [AtlasFlutter], [Skeleton], and [AnimationState] /// into a single easy to use class. /// /// Use the [fromAsset], [fromFile], or [fromHttp] methods to construct a SkeletonDrawable. To have -/// multiple skeleton drawable instances share the same [Atlas] and [SkeletonData], use the constructor. +/// multiple skeleton drawable instances share the same [AtlasFlutter] and [SkeletonDataFlutter], use the constructor. /// -/// You can then directly access the [atlas], [skeletonData], [skeleton], [animationStateData], and [animationState] +/// You can then directly access the [atlasFlutter], [skeletonDataFlutter], [skeleton], [animationStateData], and [animationState] /// to query and animate the skeleton. Use the [AnimationState] to queue animations on one or more tracks /// via [AnimationState.setAnimation] or [AnimationState.addAnimation]. /// @@ -235,27 +292,18 @@ class RenderCommandFlutter { /// [renderToPng], or [renderToRawImageData], depending on your needs. /// /// When the skeleton drawable is no longer needed, call the [dispose] method to release its resources. If -/// the skeleton drawable was constructed from a shared [Atlas] and [SkeletonData], make sure to dispose the +/// the skeleton drawable was constructed from a shared [AtlasFlutter] and [SkeletonDataFlutter], make sure to dispose the /// atlas and skeleton data as well, if no skeleton drawable references them anymore. -class SkeletonDrawableFlutter { +class SkeletonDrawableFlutter extends SkeletonDrawable { final AtlasFlutter atlasFlutter; final SkeletonData skeletonData; - late final SkeletonDrawable _drawable; - late final Skeleton skeleton; - late final AnimationStateData animationStateData; - late final AnimationState animationState; final bool _ownsAtlasAndSkeletonData; bool _disposed = false; - /// Constructs a new skeleton drawable from the given (possibly shared) [Atlas] and [SkeletonData]. If + /// Constructs a new skeleton drawable from the given (possibly shared) [AtlasFlutter] and [SkeletonDataFlutter]. If /// the atlas and skeleton data are not shared, the drawable can take ownership by passing true for [_ownsAtlasAndSkeletonData]. /// In that case a call to [dispose] will also dispose the atlas and skeleton data. - SkeletonDrawableFlutter(this.atlasFlutter, this.skeletonData, this._ownsAtlasAndSkeletonData) { - _drawable = SkeletonDrawable(skeletonData); - skeleton = _drawable.skeleton; - animationStateData = _drawable.animationStateData; - animationState = _drawable.animationState; - } + SkeletonDrawableFlutter(this.atlasFlutter, this.skeletonData, this._ownsAtlasAndSkeletonData) : super(skeletonData); /// Constructs a new skeleton drawable from the [atlasFile] and [skeletonFile] from the root asset bundle /// or the optionally provided [bundle]. @@ -264,13 +312,8 @@ class SkeletonDrawableFlutter { static Future fromAsset(String atlasFile, String skeletonFile, {AssetBundle? bundle}) async { bundle ??= rootBundle; final atlasFlutter = await AtlasFlutter.fromAsset(atlasFile, bundle: bundle); - - final skeletonData = await bundle.loadString(skeletonFile); - final skeleton = skeletonFile.endsWith('.json') - ? loadSkeletonDataJson(atlasFlutter.atlas, skeletonData) - : throw Exception('Binary skeleton data loading from assets not yet implemented'); - - return SkeletonDrawableFlutter(atlasFlutter, skeleton, true); + final skeletonDataFlutter = await SkeletonDataFlutter.fromAsset(atlasFlutter, skeletonFile, bundle: bundle); + return SkeletonDrawableFlutter(atlasFlutter, skeletonDataFlutter, true); } /// Constructs a new skeleton drawable from the [atlasFile] and [skeletonFile]. @@ -278,17 +321,8 @@ class SkeletonDrawableFlutter { /// Throws an exception in case the data could not be loaded. static Future fromFile(String atlasFile, String skeletonFile) async { final atlasFlutter = await AtlasFlutter.fromFile(atlasFile); - - final SkeletonData skeleton; - if (skeletonFile.endsWith('.json')) { - final skeletonData = await File(skeletonFile).readAsString(); - skeleton = loadSkeletonDataJson(atlasFlutter.atlas, skeletonData); - } else { - final skeletonData = await File(skeletonFile).readAsBytes(); - skeleton = loadSkeletonDataBinary(atlasFlutter.atlas, skeletonData); - } - - return SkeletonDrawableFlutter(atlasFlutter, skeleton, true); + final skeletonDataFlutter = await SkeletonDataFlutter.fromFile(atlasFlutter, skeletonFile); + return SkeletonDrawableFlutter(atlasFlutter, skeletonDataFlutter, true); } /// Constructs a new skeleton drawable from the [atlasUrl] and [skeletonUrl]. @@ -296,45 +330,22 @@ class SkeletonDrawableFlutter { /// Throws an exception in case the data could not be loaded. static Future fromHttp(String atlasUrl, String skeletonUrl) async { final atlasFlutter = await AtlasFlutter.fromHttp(atlasUrl); - - final SkeletonData skeleton; - if (skeletonUrl.endsWith('.json')) { - final skeletonResponse = await http.get(Uri.parse(skeletonUrl)); - if (skeletonResponse.statusCode != 200) { - throw Exception('Failed to load skeleton from $skeletonUrl: ${skeletonResponse.statusCode}'); - } - skeleton = loadSkeletonDataJson(atlasFlutter.atlas, skeletonResponse.body); - } else { - final skeletonResponse = await http.get(Uri.parse(skeletonUrl)); - if (skeletonResponse.statusCode != 200) { - throw Exception('Failed to load skeleton from $skeletonUrl: ${skeletonResponse.statusCode}'); - } - skeleton = loadSkeletonDataBinary(atlasFlutter.atlas, skeletonResponse.bodyBytes); - } - - return SkeletonDrawableFlutter(atlasFlutter, skeleton, true); - } - - /// Updates the [AnimationState] using the [delta] time given in seconds, applies the - /// animation state to the [Skeleton] and updates the world transforms of the skeleton - /// to calculate its current pose. - void update(double delta) { - if (_disposed) return; - _drawable.update(delta); + final skeletonDataFlutter = await SkeletonDataFlutter.fromHttp(atlasFlutter, skeletonUrl); + return SkeletonDrawableFlutter(atlasFlutter, skeletonDataFlutter, true); } /// Renders to current skeleton pose to a list of [RenderCommandFlutter] instances. The render commands /// can be rendered via [Canvas.drawVertices]. - List render() { + List renderFlutter() { if (_disposed) return []; var commands = []; - var nativeCmd = _drawable.render(); + var nativeCmd = render(); while (nativeCmd != null) { // Get page dimensions from atlas final pageIndex = nativeCmd.texture?.address ?? 0; - final pages = atlasFlutter.atlas.pages; + final pages = atlasFlutter.pages; final page = pages[pageIndex]; if (page != null) { commands.add(RenderCommandFlutter._(nativeCmd, page.width.toDouble(), page.height.toDouble())); @@ -350,7 +361,7 @@ class SkeletonDrawableFlutter { /// Renders the skeleton drawable's current pose to the given [canvas]. Does not perform any /// scaling or fitting. List renderToCanvas(Canvas canvas) { - var commands = render(); + var commands = renderFlutter(); for (final cmd in commands) { // Get the paint for this atlas page and blend mode @@ -425,10 +436,11 @@ class SkeletonDrawableFlutter { /// Disposes the skeleton drawable's resources. If the skeleton drawable owns the atlas /// and skeleton data, they are disposed as well. Must be called when the skeleton drawable /// is no longer in use. + @override void dispose() { if (_disposed) return; _disposed = true; - _drawable.dispose(); + super.dispose(); if (_ownsAtlasAndSkeletonData) { atlasFlutter.dispose(); diff --git a/spine-flutter/lib/spine_widget.dart b/spine-flutter/lib/spine_widget.dart index 19a2ca052..55db834f3 100644 --- a/spine-flutter/lib/spine_widget.dart +++ b/spine-flutter/lib/spine_widget.dart @@ -26,6 +26,7 @@ /// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF /// THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// +library; import 'dart:math'; @@ -34,7 +35,7 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; -import 'spine_dart.dart'; +import 'spine_flutter.dart'; /// Controls how the skeleton of a [SpineWidget] is animated and rendered. /// @@ -54,7 +55,7 @@ import 'spine_dart.dart'; /// [SpineWidget] then renderes the skeleton's current pose, and finally calls the optional [onAfterPaint], which /// can render additional objects on top of the skeleton. /// -/// The underlying [Atlas], [SkeletonData], [Skeleton], [AnimationStateData], [AnimationState], and [SkeletonDrawable] +/// The underlying [AtlasFlutter], [SkeletonData], [Skeleton], [AnimationStateData], [AnimationState], and [SkeletonDrawableFlutter] /// can be accessed through their respective getters to inspect and/or modify the skeleton and its associated data. Accessing /// this data is only allowed if the [SpineWidget] and its data have been initialized and have not been disposed yet. /// @@ -62,7 +63,7 @@ import 'spine_dart.dart'; /// and rendering the skeleton. The [resume] method resumes updating and rendering the skeleton. The [isPlaying] getter /// reports the current state. class SpineWidgetController { - SkeletonDrawable? _drawable; + SkeletonDrawableFlutter? _drawable; double _offsetX = 0, _offsetY = 0, _scaleX = 1, _scaleY = 1; bool _isPlaying = true; _SpineRenderObject? _renderObject; @@ -70,7 +71,8 @@ class SpineWidgetController { final void Function(SpineWidgetController controller)? onBeforeUpdateWorldTransforms; final void Function(SpineWidgetController controller)? onAfterUpdateWorldTransforms; final void Function(SpineWidgetController controller, Canvas canvas)? onBeforePaint; - final void Function(SpineWidgetController controller, Canvas canvas, List commands)? onAfterPaint; + final void Function(SpineWidgetController controller, Canvas canvas, List commands)? + onAfterPaint; /// Constructs a new [SpineWidget] controller. See the class documentation of [SpineWidgetController] for information on /// the optional arguments. @@ -82,16 +84,16 @@ class SpineWidgetController { this.onAfterPaint, }); - void _initialize(SkeletonDrawable drawable) { + void _initialize(SkeletonDrawableFlutter drawable) { var wasInitialized = _drawable != null; _drawable = drawable; if (!wasInitialized) onInitialized?.call(this); } - /// The [Atlas] from which images to render the skeleton are sourced. - Atlas get atlas { + /// The [AtlasFlutter] from which images to render the skeleton are sourced. + AtlasFlutter get atlasFlutter { if (_drawable == null) throw Exception("Controller is not initialized yet."); - return _drawable!.atlas; + return _drawable!.atlasFlutter; } /// The setup-pose data used by the skeleton. @@ -119,8 +121,8 @@ class SpineWidgetController { return _drawable!.skeleton; } - /// The [SkeletonDrawable] - SkeletonDrawable get drawable { + /// The [SkeletonDrawableFlutter] + SkeletonDrawableFlutter get drawable { if (_drawable == null) throw Exception("Controller is not initialized yet."); return _drawable!; } @@ -170,7 +172,7 @@ enum _AssetType { asset, file, http, drawable } abstract class BoundsProvider { const BoundsProvider(); - Bounds computeBounds(SkeletonDrawable drawable); + Bounds computeBounds(SkeletonDrawableFlutter drawable); } /// A [BoundsProvider] that calculates the bounding box of the skeleton based on the visible @@ -179,8 +181,10 @@ class SetupPoseBounds extends BoundsProvider { const SetupPoseBounds(); @override - Bounds computeBounds(SkeletonDrawable drawable) { - return drawable.skeleton.getBounds(); + Bounds computeBounds(SkeletonDrawableFlutter drawable) { + drawable.skeleton.setupPose(); + drawable.skeleton.updateWorldTransform(Physics.none); + return drawable.skeleton.bounds; } } @@ -191,8 +195,8 @@ class RawBounds extends BoundsProvider { RawBounds(this.x, this.y, this.width, this.height); @override - Bounds computeBounds(SkeletonDrawable drawable) { - return Bounds(x, y, width, height); + Bounds computeBounds(SkeletonDrawableFlutter drawable) { + return Bounds(x: x, y: y, width: width, height: height); } } @@ -211,17 +215,17 @@ class SkinAndAnimationBounds extends BoundsProvider { : skins = skins == null || skins.isEmpty ? ["default"] : skins; @override - Bounds computeBounds(SkeletonDrawable drawable) { + Bounds computeBounds(SkeletonDrawableFlutter drawable) { final data = drawable.skeletonData; - final oldSkin = drawable.skeleton.getSkin(); + final oldSkin = drawable.skeleton.skin; final customSkin = Skin("custom-skin"); for (final skinName in skins) { final skin = data.findSkin(skinName); if (skin == null) continue; customSkin.addSkin(skin); } - drawable.skeleton.setSkin(customSkin); - drawable.skeleton.setToSetupPose(); + drawable.skeleton.setSkin2(customSkin); + drawable.skeleton.setupPose(); final animation = this.animation != null ? data.findAnimation(this.animation!) : null; double minX = double.infinity; @@ -229,35 +233,37 @@ class SkinAndAnimationBounds extends BoundsProvider { double maxX = double.negativeInfinity; double maxY = double.negativeInfinity; if (animation == null) { - final bounds = drawable.skeleton.getBounds(); + drawable.skeleton.updateWorldTransform(Physics.none); + final bounds = drawable.skeleton.bounds; minX = bounds.x; minY = bounds.y; maxX = minX + bounds.width; maxY = minY + bounds.height; } else { - drawable.animationState.setAnimation(0, animation, false); - final steps = max(animation.getDuration() / stepTime, 1.0).toInt(); + drawable.animationState.setAnimation(0, animation.name, false); + final steps = max(animation.duration / stepTime, 1.0).toInt(); for (int i = 0; i < steps; i++) { drawable.update(i > 0 ? stepTime : 0); - final bounds = drawable.skeleton.getBounds(); + drawable.skeleton.updateWorldTransform(Physics.none); + final bounds = drawable.skeleton.bounds; minX = min(minX, bounds.x); minY = min(minY, bounds.y); maxX = max(maxX, minX + bounds.width); maxY = max(maxY, minY + bounds.height); } } - drawable.skeleton.setSkinByName("default"); + drawable.skeleton.setSkin("default"); drawable.animationState.clearTracks(); - if (oldSkin != null) drawable.skeleton.setSkin(oldSkin); - drawable.skeleton.setToSetupPose(); + if (oldSkin != null) drawable.skeleton.setSkin2(oldSkin); + drawable.skeleton.setupPose(); drawable.update(0); customSkin.dispose(); - return Bounds(minX, minY, maxX - minX, maxY - minY); + return Bounds(x: minX, y: minY, width: maxX - minX, height: maxY - minY); } } /// A [StatefulWidget] to display a Spine skeleton. The skeleton can be loaded from an asset bundle ([SpineWidget.fromAsset], -/// local files [SpineWidget.fromFile], URLs [SpineWidget.fromHttp], or a pre-loaded [SkeletonDrawable] ([SpineWidget.fromDrawable]). +/// local files [SpineWidget.fromFile], URLs [SpineWidget.fromHttp], or a pre-loaded [SkeletonDrawableFlutter] ([SpineWidget.fromDrawable]). /// /// The skeleton displayed by a `SpineWidget` can be controlled via a [SpineWidgetController]. /// @@ -268,7 +274,7 @@ class SpineWidget extends StatefulWidget { final AssetBundle? _bundle; final String? _skeletonFile; final String? _atlasFile; - final SkeletonDrawable? _drawable; + final SkeletonDrawableFlutter? _drawable; final SpineWidgetController _controller; final BoxFit _fit; final Alignment _alignment; @@ -361,7 +367,7 @@ class SpineWidget extends StatefulWidget { _sizedByBounds = sizedByBounds ?? false, _drawable = null; - /// Constructs a new [SpineWidget] from a [SkeletonDrawable]. + /// Constructs a new [SpineWidget] from a [SkeletonDrawableFlutter]. /// /// After initialization is complete, the provided [_controller] is invoked as per the [SpineWidgetController] semantics, to allow /// modifying how the skeleton inside the widget is animated and rendered. @@ -394,7 +400,7 @@ class SpineWidget extends StatefulWidget { class _SpineWidgetState extends State { late Bounds _computedBounds; - SkeletonDrawable? _drawable; + SkeletonDrawableFlutter? _drawable; @override void initState() { @@ -436,7 +442,7 @@ class _SpineWidgetState extends State { } } - void loadDrawable(SkeletonDrawable drawable) { + void loadDrawable(SkeletonDrawableFlutter drawable) { _drawable = drawable; _computedBounds = widget._boundsProvider.computeBounds(drawable); widget._controller._initialize(drawable); @@ -446,13 +452,13 @@ class _SpineWidgetState extends State { void loadFromAsset(AssetBundle? bundle, String atlasFile, String skeletonFile, _AssetType assetType) async { switch (assetType) { case _AssetType.asset: - loadDrawable(await SkeletonDrawable.fromAsset(atlasFile, skeletonFile, bundle: bundle)); + loadDrawable(await SkeletonDrawableFlutter.fromAsset(atlasFile, skeletonFile, bundle: bundle)); break; case _AssetType.file: - loadDrawable(await SkeletonDrawable.fromFile(atlasFile, skeletonFile)); + loadDrawable(await SkeletonDrawableFlutter.fromFile(atlasFile, skeletonFile)); break; case _AssetType.http: - loadDrawable(await SkeletonDrawable.fromHttp(atlasFile, skeletonFile)); + loadDrawable(await SkeletonDrawableFlutter.fromHttp(atlasFile, skeletonFile)); break; case _AssetType.drawable: throw Exception("Drawable can not be loaded via loadFromAsset()."); @@ -483,7 +489,7 @@ class _SpineWidgetState extends State { } class _SpineRenderObjectWidget extends LeafRenderObjectWidget { - final SkeletonDrawable _skeletonDrawable; + final SkeletonDrawableFlutter _skeletonDrawable; final SpineWidgetController _controller; final BoxFit _fit; final Alignment _alignment; @@ -515,7 +521,7 @@ class _SpineRenderObjectWidget extends LeafRenderObjectWidget { } class _SpineRenderObject extends RenderBox { - SkeletonDrawable _skeletonDrawable; + SkeletonDrawableFlutter _skeletonDrawable; final SpineWidgetController _controller; double _deltaTime = 0; final Stopwatch _stopwatch = Stopwatch(); @@ -535,7 +541,7 @@ class _SpineRenderObject extends RenderBox { this._sizedByBounds, ); - set skeletonDrawable(SkeletonDrawable skeletonDrawable) { + set skeletonDrawable(SkeletonDrawableFlutter skeletonDrawable) { if (_skeletonDrawable == skeletonDrawable) return; _skeletonDrawable = skeletonDrawable; @@ -721,7 +727,11 @@ class _SpineRenderObject extends RenderBox { if (_firstUpdated) { _controller.onBeforePaint?.call(_controller, canvas); - final commands = _skeletonDrawable.renderToCanvas(canvas); + final commands = _skeletonDrawable.renderFlutter(); + for (final cmd in commands) { + final paint = _skeletonDrawable.atlasFlutter.atlasPagePaints[cmd.atlasPageIndex][cmd.blendMode]!; + canvas.drawVertices(cmd.vertices, rendering.BlendMode.modulate, paint); + } _controller.onAfterPaint?.call(_controller, canvas, commands); } diff --git a/spine-flutter/macos/Classes/spine_flutter.cpp b/spine-flutter/macos/Classes/spine_flutter.cpp deleted file mode 100644 index d0997749f..000000000 --- a/spine-flutter/macos/Classes/spine_flutter.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Relative import to be able to reuse the C sources. -// See the comment in ../{projectName}}.podspec for more information. -#include "../../src/spine-cpp-lite/spine-cpp-lite.cpp" diff --git a/spine-flutter/macos/spine_flutter.podspec b/spine-flutter/macos/spine_flutter.podspec index 7c68ee67e..e0cdb9a88 100644 --- a/spine-flutter/macos/spine_flutter.podspec +++ b/spine-flutter/macos/spine_flutter.podspec @@ -12,14 +12,9 @@ A new Flutter FFI plugin project. s.homepage = 'http://example.com' s.license = { :file => '../LICENSE' } s.author = { 'Your Company' => 'email@example.com' } - - # This will ensure the source files in Classes/ are included in the native - # builds of apps using this FFI plugin. Podspec does not support relative - # paths, so Classes contains a forwarder C file that relatively imports - # `../src/*` so that the C sources can be shared among all target platforms. s.source = { :path => '.' } - s.source_files = 'Classes/**/*.{cpp}' - s.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/Classes/spine-cpp/include"' } + s.source_files = 'Classes/spine-c/src/**/*.{cpp,h}', 'Classes/spine-cpp/src/**/*.{cpp,h}' + s.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/Classes/spine-cpp/include" "$(PODS_TARGET_SRCROOT)/Classes/spine-c/include"' } s.dependency 'FlutterMacOS' s.platform = :osx, '10.11' diff --git a/spine-flutter/pubspec.yaml b/spine-flutter/pubspec.yaml index 0da49038a..99886d214 100644 --- a/spine-flutter/pubspec.yaml +++ b/spine-flutter/pubspec.yaml @@ -44,5 +44,3 @@ flutter: assets: - lib/assets/libspine_flutter.js - lib/assets/libspine_flutter.wasm - - src/spine-cpp-lite/spine-cpp-lite.cpp - - src/spine-cpp-lite/spine-cpp-lite.h diff --git a/spine-flutter/test/skeleton_drawable_test.dart b/spine-flutter/test/skeleton_drawable_test.dart index adec84551..3290bef05 100644 --- a/spine-flutter/test/skeleton_drawable_test.dart +++ b/spine-flutter/test/skeleton_drawable_test.dart @@ -16,12 +16,12 @@ void main() async { // Create skeleton drawable final drawable = SkeletonDrawable(skeletonData); print('SkeletonDrawable created successfully'); - + // Test skeleton bounds print('\nTesting skeleton bounds:'); final bounds = drawable.skeleton.bounds; print(' Initial bounds: $bounds'); - + // Set skeleton to pose and update bounds drawable.skeleton.setupPose(); drawable.skeleton.updateWorldTransform(Physics.none); @@ -76,13 +76,13 @@ void main() async { for (final event in events) { print(' $event'); } - + // Test bounds after animation updates print('\nTesting bounds after animation:'); drawable.skeleton.updateWorldTransform(Physics.none); final boundsAfterAnimation = drawable.skeleton.bounds; print(' Bounds after animation: $boundsAfterAnimation'); - + // Test with different animations that might have different bounds print('\nTesting bounds with jump animation:'); drawable.animationState.setAnimation(0, 'jump', false);