[flutter] Atas loading POC including async image load.

This commit is contained in:
Mario Zechner 2022-08-15 12:29:33 +02:00
parent 54aa6a0dc6
commit 75a656ebfc
7 changed files with 127 additions and 22 deletions

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:spine_flutter/spine_flutter.dart' as spine_flutter;
import 'package:flutter/services.dart' show rootBundle;
void main() {
runApp(const MyApp());
@ -21,8 +20,9 @@ class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
majorVersion = spine_flutter.spine_major_version();
minorVersion = spine_flutter.spine_minor_version();
majorVersion = spine_flutter.majorVersion();
minorVersion = spine_flutter.minorVersion();
spine_flutter.loadAtlas(rootBundle, "assets/spineboy.atlas");
}
@override
@ -31,20 +31,12 @@ class _MyAppState extends State<MyApp> {
const spacerSmall = SizedBox(height: 10);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Native Packages'),
),
body: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
children: [
const Text(
'This calls a native function through FFI that is shipped as source in the package. '
'The native code is built as part of the Flutter Runner build.',
style: textStyle,
textAlign: TextAlign.center,
),
const Image(image: AssetImage("assets/spineboy.png")),
spacerSmall,
Text(
'Spine version: $majorVersion.$minorVersion',

View File

@ -57,6 +57,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
flutter:
dependency: "direct main"
description: flutter

View File

@ -1,17 +1,41 @@
import 'dart:async';
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'package:ffi/ffi.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'spine_flutter_bindings_generated.dart';
import 'package:path/path.dart' as Path;
int spine_major_version() => _bindings.spine_major_version();
int spine_minor_version() => _bindings.spine_minor_version();
int majorVersion() => _bindings.spine_major_version();
int minorVersion() => _bindings.spine_minor_version();
void 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<Utf8> 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<Image> atlasPages = [];
for (int i = 0; i < atlas.ref.numImagePaths; i++) {
final Pointer<Utf8> atlasPageFile = atlas.ref.imagePaths[i].cast();
final imagePath = Path.join(atlasDir, atlasPageFile.toDartString());
atlasPages.add(await Image(image: AssetImage(imagePath)));
}
_bindings.spine_atlas_dispose(atlas);
}
const String _libName = 'spine_flutter';
/// The dynamic library in which the symbols for [SpineFlutterBindings] can be found.
final DynamicLibrary _dylib = () {
if (Platform.isMacOS || Platform.isIOS) {
return DynamicLibrary.open('$_libName.framework/$_libName');
@ -25,5 +49,4 @@ final DynamicLibrary _dylib = () {
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
}();
/// The bindings to the native functions in [_dylib].
final SpineFlutterBindings _bindings = SpineFlutterBindings(_dylib);

View File

@ -43,4 +43,44 @@ class SpineFlutterBindings {
_lookup<ffi.NativeFunction<ffi.Int32 Function()>>('spine_minor_version');
late final _spine_minor_version =
_spine_minor_versionPtr.asFunction<int Function()>();
ffi.Pointer<spine_atlas> spine_atlas_load(
ffi.Pointer<ffi.Int8> atlasData,
) {
return _spine_atlas_load(
atlasData,
);
}
late final _spine_atlas_loadPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<spine_atlas> Function(
ffi.Pointer<ffi.Int8>)>>('spine_atlas_load');
late final _spine_atlas_load = _spine_atlas_loadPtr
.asFunction<ffi.Pointer<spine_atlas> Function(ffi.Pointer<ffi.Int8>)>();
void spine_atlas_dispose(
ffi.Pointer<spine_atlas> atlas,
) {
return _spine_atlas_dispose(
atlas,
);
}
late final _spine_atlas_disposePtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<spine_atlas>)>>(
'spine_atlas_dispose');
late final _spine_atlas_dispose = _spine_atlas_disposePtr
.asFunction<void Function(ffi.Pointer<spine_atlas>)>();
}
class spine_atlas extends ffi.Struct {
external ffi.Pointer<ffi.Void> atlas;
external ffi.Pointer<ffi.Pointer<ffi.Int8>> imagePaths;
@ffi.Int32()
external int numImagePaths;
external ffi.Pointer<ffi.Int8> error;
}

View File

@ -11,13 +11,14 @@ dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.0.2
ffi: ^1.1.2
dev_dependencies:
ffi: ^1.1.2
ffigen: ^4.1.2
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
ffi: ^1.1.2
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

View File

@ -2,14 +2,39 @@
#include <spine/spine.h>
#include <spine/Version.h>
int32_t spine_major_version() {
using namespace spine;
FFI_PLUGIN_EXPORT int32_t spine_major_version() {
return SPINE_MAJOR_VERSION;
}
int32_t spine_minor_version() {
FFI_PLUGIN_EXPORT int32_t spine_minor_version() {
return SPINE_MINOR_VERSION;
}
FFI_PLUGIN_EXPORT spine_atlas* spine_atlas_load(const char *atlasData) {
int length = strlen(atlasData);
auto atlas = new Atlas(atlasData, length, "", (TextureLoader*)nullptr, false);
spine_atlas *result = SpineExtension::calloc<spine_atlas>(1, __FILE__, __LINE__);
result->atlas = atlas;
result->numImagePaths = atlas->getPages().size();
result->imagePaths = SpineExtension::calloc<char *>(result->numImagePaths, __FILE__, __LINE__);
for (int i = 0; i < result->numImagePaths; i++) {
result->imagePaths[i] = strdup(atlas->getPages()[i]->texturePath.buffer());
}
return result;
}
FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas) {
if (!atlas) return;
if (atlas->atlas) delete (Atlas*)atlas->atlas;
if (atlas->error) free(atlas->error);
for (int i = 0; i < atlas->numImagePaths; i++) {
free(atlas->imagePaths[i]);
}
SpineExtension::free(atlas, __FILE__, __LINE__);
}
spine::SpineExtension *spine::getDefaultExtension() {
return new spine::DefaultSpineExtension();
}

View File

@ -9,13 +9,30 @@
#include <unistd.h>
#endif
#ifdef __cplusplus
#if _WIN32
#define FFI_PLUGIN_EXPORT extern "C" __declspec(dllexport)
#else
#define FFI_PLUGIN_EXPORT extern "C"
#endif
#else
#if _WIN32
#define FFI_PLUGIN_EXPORT __declspec(dllexport)
#else
#define FFI_PLUGIN_EXPORT
#endif
#endif
FFI_PLUGIN_EXPORT int32_t spine_major_version();
FFI_PLUGIN_EXPORT int32_t spine_minor_version();
typedef struct spine_atlas {
void *atlas;
char **imagePaths;
int32_t numImagePaths;
char *error;
} spine_atlas;
FFI_PLUGIN_EXPORT spine_atlas* spine_atlas_load(const char *atlasData);
FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas);