diff --git a/lib/archimedes_c_shim.dart b/lib/archimedes_c_shim.dart new file mode 100644 index 0000000..b21a838 --- /dev/null +++ b/lib/archimedes_c_shim.dart @@ -0,0 +1,14 @@ +import 'dart:ffi'; +import 'package:archimedes_mobile_lib/dynloader.dart'; +import 'archimedes_mobile_lib_bindings_generated.dart'; + +final _dylib = getArchimedesCLib(); +final ArchimedesMobileLibBindings _bindings = + ArchimedesMobileLibBindings(_dylib); + +int getImageData(Pointer frame, Pointer data) => + _bindings.archimedes_get_image_data(frame, data); + +Pointer newFrame( + Pointer data, int dataLen, int w, int h, int depth) => + _bindings.new_frame_from_data(data, dataLen, w, h, depth); diff --git a/lib/archimedes_mobile_lib.dart b/lib/archimedes_mobile_lib.dart index d1750a2..b85778a 100644 --- a/lib/archimedes_mobile_lib.dart +++ b/lib/archimedes_mobile_lib.dart @@ -4,43 +4,19 @@ import 'dart:io'; import 'dart:typed_data'; // import 'dart:isolate'; // import 'dart:ui'; +import 'package:archimedes_mobile_lib/archimedes_c_shim.dart'; +import 'package:archimedes_mobile_lib/dynloader.dart'; import "package:ffi/ffi.dart"; import "package:path/path.dart" show dirname, join; import 'dart:io' show Platform; import 'archimedes_mobile_lib_bindings_generated.dart'; -const String _libName = 'archimedes_mobile_lib'; -final here = dirname(Platform.script.path); -final build = join(dirname(here), "build"); - /// The dynamic library in which the symbols for [ArchimedesMobileLibBindings] can be found. -final DynamicLibrary _dylib = () { - if (Platform.isMacOS || Platform.isIOS) { - return DynamicLibrary.open(join(build, '$_libName.framework', _libName)); - } - if (Platform.isAndroid || Platform.isLinux) { - return DynamicLibrary.open(join(build, 'lib$_libName.so')); - } - if (Platform.isWindows) { - return DynamicLibrary.open(join('$_libName.dll')); - } - throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); -}(); - -/// The bindings to the native functions in [_dylib]. -final ArchimedesMobileLibBindings _bindings = - ArchimedesMobileLibBindings(_dylib); - -int getImageData(Pointer frame, Pointer data) => - _bindings.archimedes_get_image_data(frame, data); - -Pointer newFrame( - Pointer data, int dataLen, int w, int h, int depth) => - _bindings.new_frame_from_data(data, dataLen, w, h, depth); +final DynamicLibrary _dylib = getArchimedesCLib(); void main(List arguments) { - final assets = join(dirname(here), "assets"); + final assets = join(HERE.parent.path, "assets"); final testFrames = join(assets, "test", "frames"); final firstFrame = join(testFrames, "0001.png"); final f = File(firstFrame); diff --git a/lib/dynloader.dart b/lib/dynloader.dart new file mode 100644 index 0000000..d6a7499 --- /dev/null +++ b/lib/dynloader.dart @@ -0,0 +1,25 @@ +import 'dart:ffi'; +import 'dart:io'; +import "package:ffi/ffi.dart"; +import "package:path/path.dart" show dirname, join; +import 'dart:io' show Platform; +import 'archimedes_mobile_lib_bindings_generated.dart'; + +const String _libName = 'archimedes_mobile_lib'; +final HERE = File(String.fromEnvironment("CURRENT_EXEC_DIR", + defaultValue: (File(Platform.script.path).parent.absolute.path))); +final BUILD_DIR = File(join(HERE.path, "build")); + +DynamicLibrary getArchimedesCLib() { + if (Platform.isMacOS || Platform.isIOS) { + return DynamicLibrary.open( + join(BUILD_DIR.path, '$_libName.framework', _libName)); + } + if (Platform.isAndroid || Platform.isLinux) { + return DynamicLibrary.open(join(BUILD_DIR.path, 'lib$_libName.so')); + } + if (Platform.isWindows) { + return DynamicLibrary.open(join(BUILD_DIR.path, '$_libName.dll')); + } + throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); +} diff --git a/lib/util.dart b/lib/util.dart new file mode 100644 index 0000000..174db4a --- /dev/null +++ b/lib/util.dart @@ -0,0 +1,50 @@ +import 'dart:collection'; +import 'dart:ffi'; +import 'dart:io'; +import "package:ffi/ffi.dart"; + +class Uint8FlexList extends ListBase { + final List _list = []; + Uint8FlexList(); + + late Pointer pointer; + + @override + Uint8 operator [](int index) => _list[index]; + + set list(List l) { + _list.removeWhere((element) => true); + _list.addAll(l); + pointer = calloc(l.length); + _list.forEach((element) { + pointer[_list.indexOf(element)] = element as int; + }); + } + + @override + void operator []=(int index, Uint8 value) { + _list[index] = value; + pointer[index] = value as int; + } + + @override + int get length => _list.length; + + @override + set length(int newLength) { + throw Error(); + } + + static fromList(List l) { + final l2 = Uint8FlexList(); + } +} + +Pointer readUint8Ptr(File file) { + final l = file.readAsBytesSync().cast(); + final dataPointer = calloc(l.length); + for (int i = 0; i < l.length; ++i) { + dataPointer[i] = l[i]; + } + return dataPointer; +} diff --git a/pubspec.yaml b/pubspec.yaml index 01213d4..a2722d2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,6 +8,8 @@ environment: flutter: '>=3.3.0' dependencies: + test: + ffi: flutter: sdk: flutter plugin_platform_interface: ^2.0.2 diff --git a/scripts/darttest.sh b/scripts/darttest.sh new file mode 100755 index 0000000..2bc9e04 --- /dev/null +++ b/scripts/darttest.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +SOURCE=${BASH_SOURCE[0]} +while [ -L "$SOURCE" ]; do + DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd) + SOURCE=$(readlink "$SOURCE") + [[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE +done +DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd) + +ROOT_DIR=$(realpath ${DIR}..) +LIB_DIR=$(realpath ${DIR}/../lib) +TEST_DIR=$(realpath ${DIR}/../tests) + +printf "\033c" + +dart --define=CURRENT_EXEC_DIR="${ROOT_DIR}" test ${TEST_DIR} \ No newline at end of file diff --git a/scripts/watch_darttest.sh b/scripts/watch_darttest.sh new file mode 100755 index 0000000..a94202b --- /dev/null +++ b/scripts/watch_darttest.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +SOURCE=${BASH_SOURCE[0]} +while [ -L "$SOURCE" ]; do + DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd) + SOURCE=$(readlink "$SOURCE") + [[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE +done +DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd) + +ROOT_DIR=$(realpath ${DIR}/..) +LIB_DIR=$(realpath ${DIR}/../lib) +TEST_DIR=$(realpath ${DIR}/../tests) + +cd ${ROOT_DIR} && find ${LIB_DIR} ${TEST_DIR} -iname '*.dart' | entr -r ${DIR}/darttest.sh \ No newline at end of file diff --git a/tests/main_test.dart b/tests/main_test.dart new file mode 100644 index 0000000..5e7bfbb --- /dev/null +++ b/tests/main_test.dart @@ -0,0 +1,27 @@ +import 'dart:ffi'; +import 'dart:io'; + +import 'package:archimedes_mobile_lib/archimedes_c_shim.dart'; +import 'package:archimedes_mobile_lib/dynloader.dart'; +import 'package:archimedes_mobile_lib/util.dart'; +import 'package:ffi/ffi.dart'; +import 'package:test/test.dart'; +import "package:path/path.dart" show dirname, join; + +final assets = join(HERE.parent.path, "assets"); +final testFrames = join(assets, "test", "frames"); +final firstFrame = join(testFrames, "0001.png"); + +void main() { + group('Unit Tests', () { + setUp(() {}); + + tearDown(() { + // Tear down code + }); + test('newFrame', () { + Pointer frameData = readUint8Ptr(File(firstFrame)); + // newFrame(frameData, fData.length, 768, 768, 1204); + }); + }); +}