mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-01 05:09:07 +08:00
[flutter] Atas loading POC including async image load.
This commit is contained in:
parent
54aa6a0dc6
commit
75a656ebfc
@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:spine_flutter/spine_flutter.dart' as spine_flutter;
|
import 'package:spine_flutter/spine_flutter.dart' as spine_flutter;
|
||||||
|
import 'package:flutter/services.dart' show rootBundle;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@ -21,8 +20,9 @@ class _MyAppState extends State<MyApp> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
majorVersion = spine_flutter.spine_major_version();
|
majorVersion = spine_flutter.majorVersion();
|
||||||
minorVersion = spine_flutter.spine_minor_version();
|
minorVersion = spine_flutter.minorVersion();
|
||||||
|
spine_flutter.loadAtlas(rootBundle, "assets/spineboy.atlas");
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -31,20 +31,12 @@ class _MyAppState extends State<MyApp> {
|
|||||||
const spacerSmall = SizedBox(height: 10);
|
const spacerSmall = SizedBox(height: 10);
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Native Packages'),
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
const Image(image: AssetImage("assets/spineboy.png")),
|
||||||
'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,
|
|
||||||
),
|
|
||||||
spacerSmall,
|
spacerSmall,
|
||||||
Text(
|
Text(
|
||||||
'Spine version: $majorVersion.$minorVersion',
|
'Spine version: $majorVersion.$minorVersion',
|
||||||
|
|||||||
@ -57,6 +57,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
ffi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|||||||
@ -1,17 +1,41 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'dart:io';
|
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 'spine_flutter_bindings_generated.dart';
|
||||||
|
import 'package:path/path.dart' as Path;
|
||||||
|
|
||||||
int spine_major_version() => _bindings.spine_major_version();
|
int majorVersion() => _bindings.spine_major_version();
|
||||||
int spine_minor_version() => _bindings.spine_minor_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';
|
const String _libName = 'spine_flutter';
|
||||||
|
|
||||||
/// The dynamic library in which the symbols for [SpineFlutterBindings] can be found.
|
|
||||||
final DynamicLibrary _dylib = () {
|
final DynamicLibrary _dylib = () {
|
||||||
if (Platform.isMacOS || Platform.isIOS) {
|
if (Platform.isMacOS || Platform.isIOS) {
|
||||||
return DynamicLibrary.open('$_libName.framework/$_libName');
|
return DynamicLibrary.open('$_libName.framework/$_libName');
|
||||||
@ -25,5 +49,4 @@ final DynamicLibrary _dylib = () {
|
|||||||
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
|
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
|
||||||
}();
|
}();
|
||||||
|
|
||||||
/// The bindings to the native functions in [_dylib].
|
|
||||||
final SpineFlutterBindings _bindings = SpineFlutterBindings(_dylib);
|
final SpineFlutterBindings _bindings = SpineFlutterBindings(_dylib);
|
||||||
@ -43,4 +43,44 @@ class SpineFlutterBindings {
|
|||||||
_lookup<ffi.NativeFunction<ffi.Int32 Function()>>('spine_minor_version');
|
_lookup<ffi.NativeFunction<ffi.Int32 Function()>>('spine_minor_version');
|
||||||
late final _spine_minor_version =
|
late final _spine_minor_version =
|
||||||
_spine_minor_versionPtr.asFunction<int Function()>();
|
_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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,13 +11,14 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
plugin_platform_interface: ^2.0.2
|
plugin_platform_interface: ^2.0.2
|
||||||
|
ffi: ^1.1.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
ffi: ^1.1.2
|
|
||||||
ffigen: ^4.1.2
|
ffigen: ^4.1.2
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^2.0.0
|
||||||
|
ffi: ^1.1.2
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|||||||
@ -2,14 +2,39 @@
|
|||||||
#include <spine/spine.h>
|
#include <spine/spine.h>
|
||||||
#include <spine/Version.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;
|
return SPINE_MAJOR_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t spine_minor_version() {
|
FFI_PLUGIN_EXPORT int32_t spine_minor_version() {
|
||||||
return 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() {
|
spine::SpineExtension *spine::getDefaultExtension() {
|
||||||
return new spine::DefaultSpineExtension();
|
return new spine::DefaultSpineExtension();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,13 +9,30 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#define FFI_PLUGIN_EXPORT extern "C" __declspec(dllexport)
|
#define FFI_PLUGIN_EXPORT extern "C" __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define FFI_PLUGIN_EXPORT extern "C"
|
#define FFI_PLUGIN_EXPORT extern "C"
|
||||||
#endif
|
#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_major_version();
|
||||||
FFI_PLUGIN_EXPORT int32_t spine_minor_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);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user