From 656e672ee06c8dddc16665ac88f1b2292b2e76df Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Mon, 22 Aug 2022 16:49:25 +0200 Subject: [PATCH] [flutter] Refactor, widget scafold. --- spine-flutter/example/lib/main.dart | 81 ++++++++------- spine-flutter/lib/spine_flutter.dart | 141 +++++++++++++++------------ 2 files changed, 125 insertions(+), 97 deletions(-) diff --git a/spine-flutter/example/lib/main.dart b/spine-flutter/example/lib/main.dart index 781421cd0..6230d3e36 100644 --- a/spine-flutter/example/lib/main.dart +++ b/spine-flutter/example/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:spine_flutter/spine_flutter.dart' as spine_flutter; import 'package:flutter/services.dart' show rootBundle; +import 'package:spine_flutter/spine_flutter_bindings_generated.dart'; void main() { runApp(const MyApp()); @@ -13,27 +14,54 @@ class MyApp extends StatefulWidget { _MyAppState createState() => _MyAppState(); } -class _MyAppState extends State { - late int majorVersion; - late int minorVersion; +class SpinePainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + var paint = Paint() + ..color = Colors.teal + ..strokeWidth = 5 + ..strokeCap = StrokeCap.round; + canvas.drawLine(Offset(0, 0), Offset(size.width, size.height), paint); + } + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return false; + } +} + +class SpineWidget extends StatelessWidget { + String skeletonFile; + String atlasFile; + late spine_flutter.SpineSkeletonDrawable skeletonDrawable; + + SpineWidget(this.skeletonFile, this.atlasFile) { + loadSkeleton(); + } + + void loadSkeleton() async { + final atlas = await spine_flutter.SpineAtlas.fromAsset(rootBundle, atlasFile); + final skeletonData = skeletonFile.endsWith(".json") ? + spine_flutter.SpineSkeletonData.fromJson(atlas, await rootBundle.loadString(skeletonFile)) + : spine_flutter.SpineSkeletonData.fromBinary(atlas, await rootBundle.load(skeletonFile)); + skeletonDrawable = spine_flutter.SpineSkeletonDrawable(atlas, skeletonData); + skeletonDrawable.update(0.016); + print("Loaded skeleton"); + } + + @override + Widget build(BuildContext context) { + return CustomPaint( + painter: SpinePainter(), + child: Container() + ); + } +} + +class _MyAppState extends State { @override void initState() { super.initState(); - majorVersion = spine_flutter.majorVersion(); - minorVersion = spine_flutter.minorVersion(); - - loadSkeleton(); - } - - void loadSkeleton() async { - final atlas = await spine_flutter.loadAtlas(rootBundle, "assets/skeleton.atlas"); - final skeletonData = spine_flutter.loadSkeletonDataJson(atlas, await rootBundle.loadString("assets/skeleton.json")); - // final skeletonDataBinary = spine_flutter.loadSkeletonDataBinary(atlas, await rootBundle.load("assets/spineboy-pro.skel")); - final skeletonDrawable = spine_flutter.createSkeletonDrawable(skeletonData); - spine_flutter.updateSkeletonDrawable(skeletonDrawable, 0.016); - final renderCommands = spine_flutter.renderSkeletonDrawable(skeletonDrawable); - print(renderCommands[0].vertices); } @override @@ -41,24 +69,7 @@ class _MyAppState extends State { const textStyle = TextStyle(fontSize: 25); const spacerSmall = SizedBox(height: 10); return MaterialApp( - home: Scaffold( - body: SingleChildScrollView( - child: Container( - padding: const EdgeInsets.all(10), - child: Column( - children: [ - const Image(image: AssetImage("assets/spineboy.png")), - spacerSmall, - Text( - 'Spine version: $majorVersion.$minorVersion', - style: textStyle, - textAlign: TextAlign.center, - ) - ], - ), - ), - ), - ), + home: SpineWidget("assets/skeleton.json", "assets/skeleton.atlas") ); } } diff --git a/spine-flutter/lib/spine_flutter.dart b/spine-flutter/lib/spine_flutter.dart index 05d7cfd2b..0f12882c2 100644 --- a/spine-flutter/lib/spine_flutter.dart +++ b/spine-flutter/lib/spine_flutter.dart @@ -13,69 +13,97 @@ import 'package:path/path.dart' as Path; int majorVersion() => _bindings.spine_major_version(); int minorVersion() => _bindings.spine_minor_version(); -Future> loadAtlas(AssetBundle assetBundle, String atlasFileName) async { - final atlasData = await assetBundle.loadString(atlasFileName); - final atlasDataNative = atlasData.toNativeUtf8(); - final atlas = _bindings.spine_atlas_load(atlasDataNative.cast()); - calloc.free(atlasDataNative); - if (atlas.ref.error.address != nullptr.address) { - final Pointer error = atlas.ref.error.cast(); - final message = error.toDartString(); - _bindings.spine_atlas_dispose(atlas); - throw Exception("Couldn't load atlas: " + message); +class SpineAtlas { + Pointer _atlas; + List _atlasPages; + + SpineAtlas(this._atlas, this._atlasPages); + + static Future fromAsset(AssetBundle assetBundle, String atlasFileName) async { + final atlasData = await assetBundle.loadString(atlasFileName); + final atlasDataNative = atlasData.toNativeUtf8(); + final atlas = _bindings.spine_atlas_load(atlasDataNative.cast()); + calloc.free(atlasDataNative); + if (atlas.ref.error.address != nullptr.address) { + final Pointer error = atlas.ref.error.cast(); + final message = error.toDartString(); + _bindings.spine_atlas_dispose(atlas); + throw Exception("Couldn't load atlas: " + message); + } + + final atlasDir = Path.dirname(atlasFileName); + List atlasPages = []; + for (int i = 0; i < atlas.ref.numImagePaths; i++) { + final Pointer atlasPageFile = atlas.ref.imagePaths[i].cast(); + final imagePath = Path.join(atlasDir, atlasPageFile.toDartString()); + atlasPages.add(Image(image: AssetImage(imagePath))); + } + + return SpineAtlas(atlas, atlasPages); + } +} + +class SpineSkeletonData { + Pointer _skeletonData; + + SpineSkeletonData(this._skeletonData); + + static SpineSkeletonData fromJson(SpineAtlas atlas, String json) { + final jsonNative = json.toNativeUtf8(); + final skeletonData = _bindings.spine_skeleton_data_load_json(atlas._atlas, jsonNative.cast()); + if (skeletonData.ref.error.address != nullptr.address) { + final Pointer error = skeletonData.ref.error.cast(); + final message = error.toDartString(); + _bindings.spine_skeleton_data_dispose(skeletonData); + throw Exception("Couldn't load skeleton data: " + message); + } + return SpineSkeletonData(skeletonData); } - final atlasDir = Path.dirname(atlasFileName); - List atlasPages = []; - for (int i = 0; i < atlas.ref.numImagePaths; i++) { - final Pointer atlasPageFile = atlas.ref.imagePaths[i].cast(); - final imagePath = Path.join(atlasDir, atlasPageFile.toDartString()); - atlasPages.add(await Image(image: AssetImage(imagePath))); + static SpineSkeletonData fromBinary(SpineAtlas atlas, ByteData binary) { + final Pointer binaryNative = malloc.allocate(binary.lengthInBytes); + binaryNative.asTypedList(binary.lengthInBytes).setAll(0, binary.buffer.asUint8List()); + final skeletonData = _bindings.spine_skeleton_data_load_binary(atlas._atlas, binaryNative.cast(), binary.lengthInBytes); + malloc.free(binaryNative); + if (skeletonData.ref.error.address != nullptr.address) { + final Pointer error = skeletonData.ref.error.cast(); + final message = error.toDartString(); + _bindings.spine_skeleton_data_dispose(skeletonData); + throw Exception("Couldn't load skeleton data: " + message); + } + return SpineSkeletonData(skeletonData); + } +} + +class SpineSkeletonDrawable { + SpineAtlas atlas; + SpineSkeletonData skeletonData; + late Pointer _drawable; + + SpineSkeletonDrawable(this.atlas, this.skeletonData) { + _drawable = _bindings.spine_skeleton_drawable_create(skeletonData._skeletonData); } - return atlas; -} - -Pointer loadSkeletonDataJson(Pointer atlas, String json) { - final jsonNative = json.toNativeUtf8(); - final skeletonData = _bindings.spine_skeleton_data_load_json(atlas, jsonNative.cast()); - if (skeletonData.ref.error.address != nullptr.address) { - final Pointer error = skeletonData.ref.error.cast(); - final message = error.toDartString(); - _bindings.spine_skeleton_data_dispose(skeletonData); - throw Exception("Couldn't load skeleton data: " + message); + void update(double delta) { + _bindings.spine_skeleton_drawable_update(_drawable, delta); } - return skeletonData; -} -Pointer loadSkeletonDataBinary(Pointer atlas, ByteData binary) { - final Pointer binaryNative = malloc.allocate(binary.lengthInBytes); - binaryNative.asTypedList(binary.lengthInBytes).setAll(0, binary.buffer.asUint8List()); - final skeletonData = _bindings.spine_skeleton_data_load_binary(atlas, binaryNative.cast(), binary.lengthInBytes); - malloc.free(binaryNative); - if (skeletonData.ref.error.address != nullptr.address) { - final Pointer error = skeletonData.ref.error.cast(); - final message = error.toDartString(); - _bindings.spine_skeleton_data_dispose(skeletonData); - throw Exception("Couldn't load skeleton data: " + message); + List render() { + Pointer nativeCmd = _bindings.spine_skeleton_drawable_render(_drawable); + List commands = []; + while(nativeCmd.address != nullptr.address) { + commands.add(SpineRenderCommand(nativeCmd)); + nativeCmd = nativeCmd.ref.next; + } + return commands; } - return skeletonData; } -Pointer createSkeletonDrawable(Pointer skeletonData) { - return _bindings.spine_skeleton_drawable_create(skeletonData); -} - -void updateSkeletonDrawable(Pointer drawable, double deltaTime) { - _bindings.spine_skeleton_drawable_update(drawable, deltaTime); -} - -class RenderCommand { +class SpineRenderCommand { late Vertices vertices; late int atlasPageIndex; - RenderCommand? next; - RenderCommand(Pointer nativeCmd) { + SpineRenderCommand(Pointer nativeCmd) { atlasPageIndex = nativeCmd.ref.atlasPage; int numVertices = nativeCmd.ref.numVertices; int numIndices = nativeCmd.ref.numIndices; @@ -91,17 +119,6 @@ class RenderCommand { } } -List renderSkeletonDrawable(Pointer drawable) { - Pointer nativeCmd = _bindings.spine_skeleton_drawable_render(drawable); - List commands = []; - while(nativeCmd.address != nullptr.address) { - commands.add(RenderCommand(nativeCmd)); - nativeCmd = nativeCmd.ref.next; - } - return commands; - -} - const String _libName = 'spine_flutter'; final DynamicLibrary _dylib = () {