From 261bd845fdf0b312d7b25e50dbde4e971e8eeb35 Mon Sep 17 00:00:00 2001 From: David Chavez Date: Mon, 27 Mar 2023 15:39:17 +0200 Subject: [PATCH 1/7] Setup bridging --- lib/bridge_generated.dart | 203 +++++++++++++++++++++++++ lib/ffi.dart | 22 +++ linux/CMakeLists.txt | 4 +- linux/rust.cmake | 21 +++ macos/Runner.xcodeproj/project.pbxproj | 67 +++++++- macos/Runner/bridge_generated.h | 37 +++++ windows/CMakeLists.txt | 1 + windows/rust.cmake | 21 +++ 8 files changed, 373 insertions(+), 3 deletions(-) create mode 100644 lib/bridge_generated.dart create mode 100644 lib/ffi.dart create mode 100644 linux/rust.cmake create mode 100644 macos/Runner/bridge_generated.h create mode 100644 windows/rust.cmake diff --git a/lib/bridge_generated.dart b/lib/bridge_generated.dart new file mode 100644 index 0000000..b638133 --- /dev/null +++ b/lib/bridge_generated.dart @@ -0,0 +1,203 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.72.0. +// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const + +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; + +import 'dart:ffi' as ffi; + +abstract class Native { + Future greet({dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kGreetConstMeta; +} + +class NativeImpl implements Native { + final NativePlatform _platform; + factory NativeImpl(ExternalLibrary dylib) => + NativeImpl.raw(NativePlatform(dylib)); + + /// Only valid on web/WASM platforms. + factory NativeImpl.wasm(FutureOr module) => + NativeImpl(module as ExternalLibrary); + NativeImpl.raw(this._platform); + Future greet({dynamic hint}) { + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_greet(port_), + parseSuccessData: _wire2api_String, + constMeta: kGreetConstMeta, + argValues: [], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kGreetConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "greet", + argNames: [], + ); + + void dispose() { + _platform.dispose(); + } +// Section: wire2api + + String _wire2api_String(dynamic raw) { + return raw as String; + } + + int _wire2api_u8(dynamic raw) { + return raw as int; + } + + Uint8List _wire2api_uint_8_list(dynamic raw) { + return raw as Uint8List; + } +} + +// Section: api2wire + +// Section: finalizer + +class NativePlatform extends FlutterRustBridgeBase { + NativePlatform(ffi.DynamicLibrary dylib) : super(NativeWire(dylib)); + +// Section: api2wire + +// Section: finalizer + +// Section: api_fill_to_wire +} + +// ignore_for_file: camel_case_types, non_constant_identifier_names, avoid_positional_boolean_parameters, annotate_overrides, constant_identifier_names + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint + +/// generated by flutter_rust_bridge +class NativeWire implements FlutterRustBridgeWireBase { + @internal + late final dartApi = DartApiDl(init_frb_dart_api_dl); + + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + NativeWire(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; + + /// The symbols are looked up with [lookup]. + NativeWire.fromLookup( + ffi.Pointer Function(String symbolName) + lookup) + : _lookup = lookup; + + void store_dart_post_cobject( + DartPostCObjectFnType ptr, + ) { + return _store_dart_post_cobject( + ptr, + ); + } + + late final _store_dart_post_cobjectPtr = + _lookup>( + 'store_dart_post_cobject'); + late final _store_dart_post_cobject = _store_dart_post_cobjectPtr + .asFunction(); + + Object get_dart_object( + int ptr, + ) { + return _get_dart_object( + ptr, + ); + } + + late final _get_dart_objectPtr = + _lookup>( + 'get_dart_object'); + late final _get_dart_object = + _get_dart_objectPtr.asFunction(); + + void drop_dart_object( + int ptr, + ) { + return _drop_dart_object( + ptr, + ); + } + + late final _drop_dart_objectPtr = + _lookup>( + 'drop_dart_object'); + late final _drop_dart_object = + _drop_dart_objectPtr.asFunction(); + + int new_dart_opaque( + Object handle, + ) { + return _new_dart_opaque( + handle, + ); + } + + late final _new_dart_opaquePtr = + _lookup>( + 'new_dart_opaque'); + late final _new_dart_opaque = + _new_dart_opaquePtr.asFunction(); + + int init_frb_dart_api_dl( + ffi.Pointer obj, + ) { + return _init_frb_dart_api_dl( + obj, + ); + } + + late final _init_frb_dart_api_dlPtr = + _lookup)>>( + 'init_frb_dart_api_dl'); + late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr + .asFunction)>(); + + void wire_greet( + int port_, + ) { + return _wire_greet( + port_, + ); + } + + late final _wire_greetPtr = + _lookup>('wire_greet'); + late final _wire_greet = _wire_greetPtr.asFunction(); + + void free_WireSyncReturn( + WireSyncReturn ptr, + ) { + return _free_WireSyncReturn( + ptr, + ); + } + + late final _free_WireSyncReturnPtr = + _lookup>( + 'free_WireSyncReturn'); + late final _free_WireSyncReturn = + _free_WireSyncReturnPtr.asFunction(); +} + +class _Dart_Handle extends ffi.Opaque {} + +typedef DartPostCObjectFnType = ffi.Pointer< + ffi.NativeFunction)>>; +typedef DartPort = ffi.Int64; diff --git a/lib/ffi.dart b/lib/ffi.dart new file mode 100644 index 0000000..fd1434a --- /dev/null +++ b/lib/ffi.dart @@ -0,0 +1,22 @@ +// This file initializes the dynamic library and connects it with the stub +// generated by flutter_rust_bridge_codegen. + +import 'dart:ffi'; + +import 'bridge_generated.dart'; +import 'bridge_definitions.dart'; +export 'bridge_definitions.dart'; + +// Re-export the bridge so it is only necessary to import this file. +export 'bridge_generated.dart'; +import 'dart:io' as io; + +const _base = 'native'; + +// On MacOS, the dynamic library is not bundled with the binary, +// but rather directly **linked** against the binary. +final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so'; + +final Native api = NativeImpl(io.Platform.isIOS || io.Platform.isMacOS + ? DynamicLibrary.executable() + : DynamicLibrary.open(_dylib)); diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 67e1441..50d6a47 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -1,5 +1,5 @@ # Project-level configuration. -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.12) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change @@ -89,7 +89,7 @@ set_target_properties(${BINARY_NAME} # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) - +include(./rust.cmake) # === Installation === # By default, "installing" just makes a relocatable bundle in the build diff --git a/linux/rust.cmake b/linux/rust.cmake new file mode 100644 index 0000000..5b36b9e --- /dev/null +++ b/linux/rust.cmake @@ -0,0 +1,21 @@ +# We include Corrosion inline here, but ideally in a project with +# many dependencies we would need to install Corrosion on the system. +# See instructions on https://github.com/AndrewGaspar/corrosion#cmake-install +# Once done, uncomment this line: +# find_package(Corrosion REQUIRED) + +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git + GIT_TAG v0.3 # Optionally specify a commit hash, version tag or branch here +) + +FetchContent_MakeAvailable(Corrosion) + +corrosion_import_crate(MANIFEST_PATH ../native/Cargo.toml IMPORTED_CRATES imported_crates) +target_link_libraries(${BINARY_NAME} PRIVATE ${imported_crates}) +foreach(imported_crate ${imported_crates}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) +endforeach() diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index c66fb96..68de71c 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 9B5E0AC329D1D25F00D7B2EC /* native.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B5E0ABE29D1D25300D7B2EC /* native.dylib */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -37,6 +38,27 @@ remoteGlobalIDString = 33CC111A2044C6BA0003C045; remoteInfo = FLX; }; + 9B5E0ABD29D1D25300D7B2EC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = CA60B7FEF469EAC3B2E0A336; + remoteInfo = "native-cdylib"; + }; + 9B5E0ABF29D1D25300D7B2EC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = CA6043101CA22969E816930C; + remoteInfo = "native-staticlib"; + }; + 9B5E0AC129D1D25B00D7B2EC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = CA60B7FEF469E2440CDF5F92; + remoteInfo = "native-cdylib"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -70,6 +92,7 @@ 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = native.xcodeproj; path = ../native/native.xcodeproj; sourceTree = ""; }; E461E56AD6D6CCC24DEFD045 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; E48AEE54ACC5A2CD38411D5D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; FE12D4B32B2E5B74CCF4B292 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; @@ -80,6 +103,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9B5E0AC329D1D25F00D7B2EC /* native.dylib in Frameworks */, 0471F489798F956AD8890FD6 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -101,6 +125,7 @@ 33CC10E42044A3C60003C045 = { isa = PBXGroup; children = ( + 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */, 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, 33CC10EE2044A3C60003C045 /* Products */, @@ -159,10 +184,18 @@ E461E56AD6D6CCC24DEFD045 /* Pods-Runner.release.xcconfig */, FE12D4B32B2E5B74CCF4B292 /* Pods-Runner.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; + 9B5E0AB929D1D25300D7B2EC /* Products */ = { + isa = PBXGroup; + children = ( + 9B5E0ABE29D1D25300D7B2EC /* native.dylib */, + 9B5E0AC029D1D25300D7B2EC /* libnative_static.a */, + ); + name = Products; + sourceTree = ""; + }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -189,6 +222,7 @@ buildRules = ( ); dependencies = ( + 9B5E0AC229D1D25B00D7B2EC /* PBXTargetDependency */, 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; @@ -233,6 +267,12 @@ mainGroup = 33CC10E42044A3C60003C045; productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 9B5E0AB929D1D25300D7B2EC /* Products */; + ProjectRef = 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */; + }, + ); projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, @@ -241,6 +281,23 @@ }; /* End PBXProject section */ +/* Begin PBXReferenceProxy section */ + 9B5E0ABE29D1D25300D7B2EC /* native.dylib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = native.dylib; + remoteRef = 9B5E0ABD29D1D25300D7B2EC /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 9B5E0AC029D1D25300D7B2EC /* libnative_static.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libnative_static.a; + remoteRef = 9B5E0ABF29D1D25300D7B2EC /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + /* Begin PBXResourcesBuildPhase section */ 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -352,6 +409,11 @@ target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; }; + 9B5E0AC229D1D25B00D7B2EC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "native-cdylib"; + targetProxy = 9B5E0AC129D1D25B00D7B2EC /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -428,6 +490,7 @@ "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = Runner/bridge_generated.h; SWIFT_VERSION = 5.0; }; name = Profile; @@ -554,6 +617,7 @@ "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = Runner/bridge_generated.h; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; @@ -574,6 +638,7 @@ "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = Runner/bridge_generated.h; SWIFT_VERSION = 5.0; }; name = Release; diff --git a/macos/Runner/bridge_generated.h b/macos/Runner/bridge_generated.h new file mode 100644 index 0000000..950c6c9 --- /dev/null +++ b/macos/Runner/bridge_generated.h @@ -0,0 +1,37 @@ +#include +#include +#include +typedef struct _Dart_Handle* Dart_Handle; + +typedef struct DartCObject DartCObject; + +typedef int64_t DartPort; + +typedef bool (*DartPostCObjectFnType)(DartPort port_id, void *message); + +typedef struct DartCObject *WireSyncReturn; + +void store_dart_post_cobject(DartPostCObjectFnType ptr); + +Dart_Handle get_dart_object(uintptr_t ptr); + +void drop_dart_object(uintptr_t ptr); + +uintptr_t new_dart_opaque(Dart_Handle handle); + +intptr_t init_frb_dart_api_dl(void *obj); + +void wire_greet(int64_t port_); + +void free_WireSyncReturn(WireSyncReturn ptr); + +static int64_t dummy_method_to_enforce_bundling(void) { + int64_t dummy_var = 0; + dummy_var ^= ((int64_t) (void*) wire_greet); + dummy_var ^= ((int64_t) (void*) free_WireSyncReturn); + dummy_var ^= ((int64_t) (void*) store_dart_post_cobject); + dummy_var ^= ((int64_t) (void*) get_dart_object); + dummy_var ^= ((int64_t) (void*) drop_dart_object); + dummy_var ^= ((int64_t) (void*) new_dart_opaque); + return dummy_var; +} diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index b245e2d..d92c0cb 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -55,6 +55,7 @@ add_subdirectory("runner") # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) +include(./rust.cmake) # === Installation === diff --git a/windows/rust.cmake b/windows/rust.cmake new file mode 100644 index 0000000..5b36b9e --- /dev/null +++ b/windows/rust.cmake @@ -0,0 +1,21 @@ +# We include Corrosion inline here, but ideally in a project with +# many dependencies we would need to install Corrosion on the system. +# See instructions on https://github.com/AndrewGaspar/corrosion#cmake-install +# Once done, uncomment this line: +# find_package(Corrosion REQUIRED) + +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git + GIT_TAG v0.3 # Optionally specify a commit hash, version tag or branch here +) + +FetchContent_MakeAvailable(Corrosion) + +corrosion_import_crate(MANIFEST_PATH ../native/Cargo.toml IMPORTED_CRATES imported_crates) +target_link_libraries(${BINARY_NAME} PRIVATE ${imported_crates}) +foreach(imported_crate ${imported_crates}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) +endforeach() From 4f87acdb724a0bb9e08d1b8394bf657cee596b3e Mon Sep 17 00:00:00 2001 From: David Chavez Date: Mon, 27 Mar 2023 15:40:18 +0200 Subject: [PATCH 2/7] Add farbe submodule --- .gitmodules | 3 +++ farbe | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 farbe diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..eff0e23 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "farbe"] + path = farbe + url = https://github.com/retrofoundry/farbe.git diff --git a/farbe b/farbe new file mode 160000 index 0000000..6a89ea5 --- /dev/null +++ b/farbe @@ -0,0 +1 @@ +Subproject commit 6a89ea52b817e6213674341013e5b5132ea1a9dd From 8bee819dda87a75ce0e8c4bb62488ddf2508ab36 Mon Sep 17 00:00:00 2001 From: David Chavez Date: Mon, 27 Mar 2023 16:39:57 +0200 Subject: [PATCH 3/7] Add method for going from native to PNG --- .gitmodules | 3 - farbe | 1 - ios/Flutter/Generated.xcconfig | 14 + ios/Flutter/flutter_export_environment.sh | 13 + ios/Runner/GeneratedPluginRegistrant.h | 19 + ios/Runner/GeneratedPluginRegistrant.m | 28 ++ ios/Runner/bridge_generated.h | 49 +++ lib/bridge_definitions.dart | 20 + lib/bridge_generated.dart | 103 +++-- macos/Runner.xcodeproj/project.pbxproj | 48 +-- macos/Runner/AppDelegate.swift | 1 + macos/Runner/bridge_generated.h | 16 +- native/.gitignore | 17 + native/Cargo.toml | 13 + native/native.xcodeproj/project.pbxproj | 373 ++++++++++++++++++ .../xcschemes/xcschememanagement.plist | 19 + native/src/api.rs | 28 ++ native/src/bridge_generated.io.rs | 66 ++++ native/src/bridge_generated.rs | 95 +++++ native/src/lib.rs | 2 + pubspec.lock | 146 ++++++- pubspec.yaml | 5 +- 22 files changed, 1026 insertions(+), 53 deletions(-) delete mode 160000 farbe create mode 100644 ios/Flutter/Generated.xcconfig create mode 100755 ios/Flutter/flutter_export_environment.sh create mode 100644 ios/Runner/GeneratedPluginRegistrant.h create mode 100644 ios/Runner/GeneratedPluginRegistrant.m create mode 100644 ios/Runner/bridge_generated.h create mode 100644 lib/bridge_definitions.dart create mode 100644 native/.gitignore create mode 100644 native/Cargo.toml create mode 100644 native/native.xcodeproj/project.pbxproj create mode 100644 native/native.xcodeproj/xcuserdata/dcvz.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 native/src/api.rs create mode 100644 native/src/bridge_generated.io.rs create mode 100644 native/src/bridge_generated.rs create mode 100644 native/src/lib.rs diff --git a/.gitmodules b/.gitmodules index eff0e23..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "farbe"] - path = farbe - url = https://github.com/retrofoundry/farbe.git diff --git a/farbe b/farbe deleted file mode 160000 index 6a89ea5..0000000 --- a/farbe +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6a89ea52b817e6213674341013e5b5132ea1a9dd diff --git a/ios/Flutter/Generated.xcconfig b/ios/Flutter/Generated.xcconfig new file mode 100644 index 0000000..53247dc --- /dev/null +++ b/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=/Users/dcvz/Github/flutter +FLUTTER_APPLICATION_PATH=/Users/dcvz/Github/retro +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib/main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 0000000..731131a --- /dev/null +++ b/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Users/dcvz/Github/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/dcvz/Github/retro" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/ios/Runner/GeneratedPluginRegistrant.h b/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 0000000..7a89092 --- /dev/null +++ b/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/ios/Runner/GeneratedPluginRegistrant.m b/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 0000000..7b2b7ad --- /dev/null +++ b/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,28 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +#if __has_include() +#import +#else +@import file_picker; +#endif + +#if __has_include() +#import +#else +@import url_launcher_ios; +#endif + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { + [FilePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FilePickerPlugin"]]; + [FLTURLLauncherPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTURLLauncherPlugin"]]; +} + +@end diff --git a/ios/Runner/bridge_generated.h b/ios/Runner/bridge_generated.h new file mode 100644 index 0000000..4643c70 --- /dev/null +++ b/ios/Runner/bridge_generated.h @@ -0,0 +1,49 @@ +#include +#include +#include +typedef struct _Dart_Handle* Dart_Handle; + +typedef struct DartCObject DartCObject; + +typedef int64_t DartPort; + +typedef bool (*DartPostCObjectFnType)(DartPort port_id, void *message); + +typedef struct wire_uint_8_list { + uint8_t *ptr; + int32_t len; +} wire_uint_8_list; + +typedef struct DartCObject *WireSyncReturn; + +void store_dart_post_cobject(DartPostCObjectFnType ptr); + +Dart_Handle get_dart_object(uintptr_t ptr); + +void drop_dart_object(uintptr_t ptr); + +uintptr_t new_dart_opaque(Dart_Handle handle); + +intptr_t init_frb_dart_api_dl(void *obj); + +void wire_convert_native_to_png(int64_t port_, + struct wire_uint_8_list *bytes, + uint8_t format, + uint32_t width, + uint32_t height); + +struct wire_uint_8_list *new_uint_8_list_0(int32_t len); + +void free_WireSyncReturn(WireSyncReturn ptr); + +static int64_t dummy_method_to_enforce_bundling(void) { + int64_t dummy_var = 0; + dummy_var ^= ((int64_t) (void*) wire_convert_native_to_png); + dummy_var ^= ((int64_t) (void*) new_uint_8_list_0); + dummy_var ^= ((int64_t) (void*) free_WireSyncReturn); + dummy_var ^= ((int64_t) (void*) store_dart_post_cobject); + dummy_var ^= ((int64_t) (void*) get_dart_object); + dummy_var ^= ((int64_t) (void*) drop_dart_object); + dummy_var ^= ((int64_t) (void*) new_dart_opaque); + return dummy_var; +} diff --git a/lib/bridge_definitions.dart b/lib/bridge_definitions.dart new file mode 100644 index 0000000..fd03b9f --- /dev/null +++ b/lib/bridge_definitions.dart @@ -0,0 +1,20 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.72.0. +// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const + +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; + +abstract class Native { + Future convertNativeToPng( + {required Uint8List bytes, + required int format, + required int width, + required int height, + dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kConvertNativeToPngConstMeta; +} diff --git a/lib/bridge_generated.dart b/lib/bridge_generated.dart index b638133..69da69b 100644 --- a/lib/bridge_generated.dart +++ b/lib/bridge_generated.dart @@ -2,19 +2,20 @@ // Generated by `flutter_rust_bridge`@ 1.72.0. // ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const +import "bridge_definitions.dart"; import 'dart:convert'; import 'dart:async'; import 'package:meta/meta.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; import 'package:uuid/uuid.dart'; -import 'dart:ffi' as ffi; - -abstract class Native { - Future greet({dynamic hint}); +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; - FlutterRustBridgeTaskConstMeta get kGreetConstMeta; -} +import 'dart:ffi' as ffi; class NativeImpl implements Native { final NativePlatform _platform; @@ -25,20 +26,30 @@ class NativeImpl implements Native { factory NativeImpl.wasm(FutureOr module) => NativeImpl(module as ExternalLibrary); NativeImpl.raw(this._platform); - Future greet({dynamic hint}) { + Future convertNativeToPng( + {required Uint8List bytes, + required int format, + required int width, + required int height, + dynamic hint}) { + var arg0 = _platform.api2wire_uint_8_list(bytes); + var arg1 = api2wire_u8(format); + var arg2 = api2wire_u32(width); + var arg3 = api2wire_u32(height); return _platform.executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => _platform.inner.wire_greet(port_), - parseSuccessData: _wire2api_String, - constMeta: kGreetConstMeta, - argValues: [], + callFfi: (port_) => _platform.inner + .wire_convert_native_to_png(port_, arg0, arg1, arg2, arg3), + parseSuccessData: _wire2api_uint_8_list, + constMeta: kConvertNativeToPngConstMeta, + argValues: [bytes, format, width, height], hint: hint, )); } - FlutterRustBridgeTaskConstMeta get kGreetConstMeta => + FlutterRustBridgeTaskConstMeta get kConvertNativeToPngConstMeta => const FlutterRustBridgeTaskConstMeta( - debugName: "greet", - argNames: [], + debugName: "convert_native_to_png", + argNames: ["bytes", "format", "width", "height"], ); void dispose() { @@ -46,10 +57,6 @@ class NativeImpl implements Native { } // Section: wire2api - String _wire2api_String(dynamic raw) { - return raw as String; - } - int _wire2api_u8(dynamic raw) { return raw as int; } @@ -61,6 +68,16 @@ class NativeImpl implements Native { // Section: api2wire +@protected +int api2wire_u32(int raw) { + return raw; +} + +@protected +int api2wire_u8(int raw) { + return raw; +} + // Section: finalizer class NativePlatform extends FlutterRustBridgeBase { @@ -68,6 +85,12 @@ class NativePlatform extends FlutterRustBridgeBase { // Section: api2wire + @protected + ffi.Pointer api2wire_uint_8_list(Uint8List raw) { + final ans = inner.new_uint_8_list_0(raw.length); + ans.ref.ptr.asTypedList(raw.length).setAll(0, raw); + return ans; + } // Section: finalizer // Section: api_fill_to_wire @@ -169,17 +192,44 @@ class NativeWire implements FlutterRustBridgeWireBase { late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr .asFunction)>(); - void wire_greet( + void wire_convert_native_to_png( int port_, + ffi.Pointer bytes, + int format, + int width, + int height, ) { - return _wire_greet( + return _wire_convert_native_to_png( port_, + bytes, + format, + width, + height, + ); + } + + late final _wire_convert_native_to_pngPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Int64, ffi.Pointer, ffi.Uint8, + ffi.Uint32, ffi.Uint32)>>('wire_convert_native_to_png'); + late final _wire_convert_native_to_png = + _wire_convert_native_to_pngPtr.asFunction< + void Function(int, ffi.Pointer, int, int, int)>(); + + ffi.Pointer new_uint_8_list_0( + int len, + ) { + return _new_uint_8_list_0( + len, ); } - late final _wire_greetPtr = - _lookup>('wire_greet'); - late final _wire_greet = _wire_greetPtr.asFunction(); + late final _new_uint_8_list_0Ptr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Int32)>>('new_uint_8_list_0'); + late final _new_uint_8_list_0 = _new_uint_8_list_0Ptr + .asFunction Function(int)>(); void free_WireSyncReturn( WireSyncReturn ptr, @@ -198,6 +248,13 @@ class NativeWire implements FlutterRustBridgeWireBase { class _Dart_Handle extends ffi.Opaque {} +class wire_uint_8_list extends ffi.Struct { + external ffi.Pointer ptr; + + @ffi.Int32() + external int len; +} + typedef DartPostCObjectFnType = ffi.Pointer< ffi.NativeFunction)>>; typedef DartPort = ffi.Int64; diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 68de71c..ffbea0f 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -27,7 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 9B5E0AC329D1D25F00D7B2EC /* native.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B5E0ABE29D1D25300D7B2EC /* native.dylib */; }; + 9B5E0ADD29D1D6CA00D7B2EC /* native.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B5E0ADA29D1D6B700D7B2EC /* native.dylib */; }; + 9B5E0AE129D1D9F200D7B2EC /* bridge_generated.h in Resources */ = {isa = PBXBuildFile; fileRef = 9B5E0AE029D1D9EA00D7B2EC /* bridge_generated.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -38,23 +39,23 @@ remoteGlobalIDString = 33CC111A2044C6BA0003C045; remoteInfo = FLX; }; - 9B5E0ABD29D1D25300D7B2EC /* PBXContainerItemProxy */ = { + 9B5E0AD929D1D6B700D7B2EC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */; + containerPortal = 9B5E0AD429D1D6B700D7B2EC /* native.xcodeproj */; proxyType = 2; remoteGlobalIDString = CA60B7FEF469EAC3B2E0A336; remoteInfo = "native-cdylib"; }; - 9B5E0ABF29D1D25300D7B2EC /* PBXContainerItemProxy */ = { + 9B5E0ADB29D1D6B700D7B2EC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */; + containerPortal = 9B5E0AD429D1D6B700D7B2EC /* native.xcodeproj */; proxyType = 2; remoteGlobalIDString = CA6043101CA22969E816930C; remoteInfo = "native-staticlib"; }; - 9B5E0AC129D1D25B00D7B2EC /* PBXContainerItemProxy */ = { + 9B5E0ADE29D1D6CF00D7B2EC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */; + containerPortal = 9B5E0AD429D1D6B700D7B2EC /* native.xcodeproj */; proxyType = 1; remoteGlobalIDString = CA60B7FEF469E2440CDF5F92; remoteInfo = "native-cdylib"; @@ -92,7 +93,8 @@ 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = native.xcodeproj; path = ../native/native.xcodeproj; sourceTree = ""; }; + 9B5E0AD429D1D6B700D7B2EC /* native.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = native.xcodeproj; path = ../native/native.xcodeproj; sourceTree = ""; }; + 9B5E0AE029D1D9EA00D7B2EC /* bridge_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bridge_generated.h; sourceTree = ""; }; E461E56AD6D6CCC24DEFD045 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; E48AEE54ACC5A2CD38411D5D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; FE12D4B32B2E5B74CCF4B292 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; @@ -103,7 +105,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9B5E0AC329D1D25F00D7B2EC /* native.dylib in Frameworks */, + 9B5E0ADD29D1D6CA00D7B2EC /* native.dylib in Frameworks */, 0471F489798F956AD8890FD6 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -125,7 +127,7 @@ 33CC10E42044A3C60003C045 = { isa = PBXGroup; children = ( - 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */, + 9B5E0AD429D1D6B700D7B2EC /* native.xcodeproj */, 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, 33CC10EE2044A3C60003C045 /* Products */, @@ -167,6 +169,7 @@ 33FAB671232836740065AC1E /* Runner */ = { isa = PBXGroup; children = ( + 9B5E0AE029D1D9EA00D7B2EC /* bridge_generated.h */, 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 33E51913231747F40026EE4D /* DebugProfile.entitlements */, @@ -187,11 +190,11 @@ path = Pods; sourceTree = ""; }; - 9B5E0AB929D1D25300D7B2EC /* Products */ = { + 9B5E0AD529D1D6B700D7B2EC /* Products */ = { isa = PBXGroup; children = ( - 9B5E0ABE29D1D25300D7B2EC /* native.dylib */, - 9B5E0AC029D1D25300D7B2EC /* libnative_static.a */, + 9B5E0ADA29D1D6B700D7B2EC /* native.dylib */, + 9B5E0ADC29D1D6B700D7B2EC /* libnative_static.a */, ); name = Products; sourceTree = ""; @@ -222,7 +225,7 @@ buildRules = ( ); dependencies = ( - 9B5E0AC229D1D25B00D7B2EC /* PBXTargetDependency */, + 9B5E0ADF29D1D6CF00D7B2EC /* PBXTargetDependency */, 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; @@ -269,8 +272,8 @@ projectDirPath = ""; projectReferences = ( { - ProductGroup = 9B5E0AB929D1D25300D7B2EC /* Products */; - ProjectRef = 9B5E0AB829D1D25300D7B2EC /* native.xcodeproj */; + ProductGroup = 9B5E0AD529D1D6B700D7B2EC /* Products */; + ProjectRef = 9B5E0AD429D1D6B700D7B2EC /* native.xcodeproj */; }, ); projectRoot = ""; @@ -282,18 +285,18 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ - 9B5E0ABE29D1D25300D7B2EC /* native.dylib */ = { + 9B5E0ADA29D1D6B700D7B2EC /* native.dylib */ = { isa = PBXReferenceProxy; fileType = "compiled.mach-o.dylib"; path = native.dylib; - remoteRef = 9B5E0ABD29D1D25300D7B2EC /* PBXContainerItemProxy */; + remoteRef = 9B5E0AD929D1D6B700D7B2EC /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B5E0AC029D1D25300D7B2EC /* libnative_static.a */ = { + 9B5E0ADC29D1D6B700D7B2EC /* libnative_static.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; path = libnative_static.a; - remoteRef = 9B5E0ABF29D1D25300D7B2EC /* PBXContainerItemProxy */; + remoteRef = 9B5E0ADB29D1D6B700D7B2EC /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ @@ -303,6 +306,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9B5E0AE129D1D9F200D7B2EC /* bridge_generated.h in Resources */, 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, ); @@ -409,10 +413,10 @@ target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; }; - 9B5E0AC229D1D25B00D7B2EC /* PBXTargetDependency */ = { + 9B5E0ADF29D1D6CF00D7B2EC /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "native-cdylib"; - targetProxy = 9B5E0AC129D1D25B00D7B2EC /* PBXContainerItemProxy */; + targetProxy = 9B5E0ADE29D1D6CF00D7B2EC /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index d53ef64..156e0c7 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -4,6 +4,7 @@ import FlutterMacOS @NSApplicationMain class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + dummy_method_to_enforce_bundling() return true } } diff --git a/macos/Runner/bridge_generated.h b/macos/Runner/bridge_generated.h index 950c6c9..4643c70 100644 --- a/macos/Runner/bridge_generated.h +++ b/macos/Runner/bridge_generated.h @@ -9,6 +9,11 @@ typedef int64_t DartPort; typedef bool (*DartPostCObjectFnType)(DartPort port_id, void *message); +typedef struct wire_uint_8_list { + uint8_t *ptr; + int32_t len; +} wire_uint_8_list; + typedef struct DartCObject *WireSyncReturn; void store_dart_post_cobject(DartPostCObjectFnType ptr); @@ -21,13 +26,20 @@ uintptr_t new_dart_opaque(Dart_Handle handle); intptr_t init_frb_dart_api_dl(void *obj); -void wire_greet(int64_t port_); +void wire_convert_native_to_png(int64_t port_, + struct wire_uint_8_list *bytes, + uint8_t format, + uint32_t width, + uint32_t height); + +struct wire_uint_8_list *new_uint_8_list_0(int32_t len); void free_WireSyncReturn(WireSyncReturn ptr); static int64_t dummy_method_to_enforce_bundling(void) { int64_t dummy_var = 0; - dummy_var ^= ((int64_t) (void*) wire_greet); + dummy_var ^= ((int64_t) (void*) wire_convert_native_to_png); + dummy_var ^= ((int64_t) (void*) new_uint_8_list_0); dummy_var ^= ((int64_t) (void*) free_WireSyncReturn); dummy_var ^= ((int64_t) (void*) store_dart_post_cobject); dummy_var ^= ((int64_t) (void*) get_dart_object); diff --git a/native/.gitignore b/native/.gitignore new file mode 100644 index 0000000..ea59969 --- /dev/null +++ b/native/.gitignore @@ -0,0 +1,17 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# macOS files +.DS_Store + +# Test files +tests/n64/test.* +tests_output/n64/test.*.png diff --git a/native/Cargo.toml b/native/Cargo.toml new file mode 100644 index 0000000..ac08900 --- /dev/null +++ b/native/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "native" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +farbe = "0.1.0" +flutter_rust_bridge = "1" + +[lib] +crate-type = ["lib", "cdylib", "staticlib"] diff --git a/native/native.xcodeproj/project.pbxproj b/native/native.xcodeproj/project.pbxproj new file mode 100644 index 0000000..683507e --- /dev/null +++ b/native/native.xcodeproj/project.pbxproj @@ -0,0 +1,373 @@ +// !$*UTF8*$! +{ + /* generated with cargo-xcode 1.5.0 */ + archiveVersion = 1; + classes = { + }; + objectVersion = 53; + objects = { +/* Begin PBXBuildFile section */ + + CA60B01C7D1AE2440CDF5F92 /* Cargo.toml in Sources */ = { + isa = PBXBuildFile; + fileRef = CA6017FED9773EF4668187A5 /* Cargo.toml */; + settings = { + COMPILER_FLAGS = "--lib"; /* == OTHER_INPUT_FILE_FLAGS */ + }; + }; + + CA60B01C7D1A42DAEB7745A8 /* Cargo.toml in Sources */ = { + isa = PBXBuildFile; + fileRef = CA6017FED9773EF4668187A5 /* Cargo.toml */; + settings = { + COMPILER_FLAGS = "--lib"; /* == OTHER_INPUT_FILE_FLAGS */ + }; + }; + +/* End PBXBuildFile section */ + +/* Begin PBXBuildRule section */ + CA6017FED977AC6C1400ACA8 /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + dependencyFile = "$(DERIVED_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME).d"; + filePatterns = "*/Cargo.toml"; /* must contain asterisk */ + fileType = pattern.proxy; + inputFiles = (); + isEditable = 0; + name = "Cargo project build"; + outputFiles = ( + "$(OBJECT_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME)", + ); + script = "# generated with cargo-xcode 1.5.0\n\nset -eu; export PATH=\"$PATH:$HOME/.cargo/bin:/usr/local/bin\";\nif [ \"${IS_MACCATALYST-NO}\" = YES ]; then\n CARGO_XCODE_TARGET_TRIPLE=\"${CARGO_XCODE_TARGET_ARCH}-apple-ios-macabi\"\nelse\n CARGO_XCODE_TARGET_TRIPLE=\"${CARGO_XCODE_TARGET_ARCH}-apple-${CARGO_XCODE_TARGET_OS}\"\nfi\nif [ \"$CARGO_XCODE_TARGET_OS\" != \"darwin\" ]; then\n PATH=\"${PATH/\\/Contents\\/Developer\\/Toolchains\\/XcodeDefault.xctoolchain\\/usr\\/bin:/xcode-provided-ld-cant-link-lSystem-for-the-host-build-script:}\"\nfi\nPATH=\"$PATH:/opt/homebrew/bin\" # Rust projects often depend on extra tools like nasm, which Xcode lacks\nif [ \"$CARGO_XCODE_BUILD_MODE\" == release ]; then\n OTHER_INPUT_FILE_FLAGS=\"${OTHER_INPUT_FILE_FLAGS} --release\"\nfi\nif command -v rustup &> /dev/null; then\n if ! rustup target list --installed | egrep -q \"${CARGO_XCODE_TARGET_TRIPLE}\"; then\n echo \"warning: this build requires rustup toolchain for $CARGO_XCODE_TARGET_TRIPLE, but it isn\'t installed\"\n rustup target add \"${CARGO_XCODE_TARGET_TRIPLE}\" || echo >&2 \"warning: can\'t install $CARGO_XCODE_TARGET_TRIPLE\"\n fi\nfi\nif [ \"$ACTION\" = clean ]; then\n ( set -x; cargo clean --manifest-path=\"$SCRIPT_INPUT_FILE\" ${OTHER_INPUT_FILE_FLAGS} --target=\"${CARGO_XCODE_TARGET_TRIPLE}\"; );\nelse\n ( set -x; cargo build --manifest-path=\"$SCRIPT_INPUT_FILE\" --features=\"${CARGO_XCODE_FEATURES:-}\" ${OTHER_INPUT_FILE_FLAGS} --target=\"${CARGO_XCODE_TARGET_TRIPLE}\"; );\nfi\n# it\'s too hard to explain Cargo\'s actual exe path to Xcode build graph, so hardlink to a known-good path instead\nBUILT_SRC=\"${CARGO_TARGET_DIR}/${CARGO_XCODE_TARGET_TRIPLE}/${CARGO_XCODE_BUILD_MODE}/${CARGO_XCODE_CARGO_FILE_NAME}\"\nln -f -- \"$BUILT_SRC\" \"$SCRIPT_OUTPUT_FILE_0\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\nDEP_FILE_SRC=\"${CARGO_TARGET_DIR}/${CARGO_XCODE_TARGET_TRIPLE}/${CARGO_XCODE_BUILD_MODE}/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\nif [ -f \"$DEP_FILE_SRC\" ]; then\n DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\nfi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don\'t stay around after archs change\n# must match input for LipoScript\nFILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\ntouch \"$FILE_LIST\"\nif ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\nfi\n"; + }; +/* End PBXBuildRule section */ + +/* Begin PBXFileReference section */ + + CA60B7FEF469EAC3B2E0A336 /* cdylib */ = { + isa = PBXFileReference; + explicitFileType = "compiled.mach-o.dylib"; + includeInIndex = 0; + name = "native.dylib"; + sourceTree = TARGET_BUILD_DIR; + }; + CA6043101CA22969E816930C /* staticlib */ = { + isa = PBXFileReference; + explicitFileType = "archive.ar"; + includeInIndex = 0; + name = "libnative_static.a"; + sourceTree = TARGET_BUILD_DIR; + }; + CA6017FED9773EF4668187A5 /* Cargo.toml */ = { + isa = PBXFileReference; + lastKnownFileType = text; + fileEncoding = 4; + name = "Cargo.toml"; + path = "Cargo.toml"; + sourceTree = ""; + }; + /* Rust needs libresolv */ + ADDEDBA66A6E1 = { + isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; + name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; + }; + +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + CA6017FED97798AF0B5890DB /* Frameworks */ = { + isa = PBXGroup; + children = ( + ADDEDBA66A6E2, + + ); + name = Frameworks; + sourceTree = ""; + }; + + + ADDEDBA66A6E2 /* Required for static linking */ = { + isa = PBXGroup; + children = ( + ADDEDBA66A6E1 + ); + name = "Required for static linking"; + sourceTree = ""; + }; + + CA6017FED97722869D176AE5 /* Products */ = { + isa = PBXGroup; + children = ( + CA60B7FEF469EAC3B2E0A336, +CA6043101CA22969E816930C, + + ); + name = Products; + sourceTree = ""; + }; + + CA6017FED977D65BC3C892A8 /* Main */ = { + isa = PBXGroup; + children = ( + CA6017FED9773EF4668187A5, +CA6017FED97722869D176AE5, +CA6017FED97798AF0B5890DB, + + ); + sourceTree = ""; + }; + +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + CA60B7FEF469E2440CDF5F92 /* native-cdylib */ = { + isa = PBXNativeTarget; + buildConfigurationList = CA6023760CA3E2440CDF5F92; + buildPhases = ( + CA60FB84A054E2440CDF5F92 /* Sources */, + CA6017FED977AF6EBB7F357C /* Universal Binary lipo */, + ); + buildRules = ( + CA6017FED977AC6C1400ACA8 /* PBXBuildRule */, + ); + dependencies = ( + ); + name = "native-cdylib"; + productName = "native.dylib"; + productReference = CA60B7FEF469EAC3B2E0A336; + productType = "com.apple.product-type.library.dynamic"; + }; + CA6043101CA242DAEB7745A8 /* native-staticlib */ = { + isa = PBXNativeTarget; + buildConfigurationList = CA6023760CA342DAEB7745A8; + buildPhases = ( + CA60FB84A05442DAEB7745A8 /* Sources */, + CA6017FED977AF6EBB7F357C /* Universal Binary lipo */, + ); + buildRules = ( + CA6017FED977AC6C1400ACA8 /* PBXBuildRule */, + ); + dependencies = ( + ); + name = "native-staticlib"; + productName = "libnative_static.a"; + productReference = CA6043101CA22969E816930C; + productType = "com.apple.product-type.library.static"; + }; + +/* End PBXNativeTarget section */ + + CA60FB84A054E2440CDF5F92 = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CA60B01C7D1AE2440CDF5F92 + ); + runOnlyForDeploymentPostprocessing = 0; + }; + + CA6023760CA3E2440CDF5F92 /* cdylib */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CA606D792BBBE2440CDF5F92 /* Release */, + CA6010A1FE93E2440CDF5F92 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CA606D792BBBE2440CDF5F92 /* cdylib */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "native"; + "CARGO_XCODE_CARGO_FILE_NAME" = "libnative.dylib"; + "CARGO_XCODE_CARGO_DEP_FILE_NAME" = "libnative.d"; + SUPPORTED_PLATFORMS = "macosx"; + + DYLIB_COMPATIBILITY_VERSION = "0"; + }; + name = Release; + }; + CA6010A1FE93E2440CDF5F92 /* cdylib */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "native"; + "CARGO_XCODE_CARGO_FILE_NAME" = "libnative.dylib"; + "CARGO_XCODE_CARGO_DEP_FILE_NAME" = "libnative.d"; + SUPPORTED_PLATFORMS = "macosx"; + + DYLIB_COMPATIBILITY_VERSION = "0"; + }; + name = Debug; + };CA60FB84A05442DAEB7745A8 = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CA60B01C7D1A42DAEB7745A8 + ); + runOnlyForDeploymentPostprocessing = 0; + }; + + CA6023760CA342DAEB7745A8 /* staticlib */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CA606D792BBB42DAEB7745A8 /* Release */, + CA6010A1FE9342DAEB7745A8 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CA606D792BBB42DAEB7745A8 /* staticlib */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "native_static"; + "CARGO_XCODE_CARGO_FILE_NAME" = "libnative.a"; + "CARGO_XCODE_CARGO_DEP_FILE_NAME" = "libnative.d"; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; + SKIP_INSTALL = YES; + INSTALL_GROUP = ""; + INSTALL_MODE_FLAG = ""; + INSTALL_OWNER = ""; + + }; + name = Release; + }; + CA6010A1FE9342DAEB7745A8 /* staticlib */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "native_static"; + "CARGO_XCODE_CARGO_FILE_NAME" = "libnative.a"; + "CARGO_XCODE_CARGO_DEP_FILE_NAME" = "libnative.d"; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; + SKIP_INSTALL = YES; + INSTALL_GROUP = ""; + INSTALL_MODE_FLAG = ""; + INSTALL_OWNER = ""; + + }; + name = Debug; + }; + + CA6017FED977AF6EBB7F357C /* LipoScript */ = { + name = "Universal Binary lipo"; + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = (); + inputFileListPaths = (); + inputPaths = ( + "$(DERIVED_FILE_DIR)/$(ARCHS)-$(EXECUTABLE_NAME).xcfilelist", + ); + outputFileListPaths = (); + outputPaths = ( + "$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)" + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# generated with cargo-xcode 1.5.0\n\n set -eux; cat \"$DERIVED_FILE_DIR/$ARCHS-$EXECUTABLE_NAME.xcfilelist\" | tr \'\\n\' \'\\0\' | xargs -0 lipo -create -output \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n if [ ${LD_DYLIB_INSTALL_NAME:+1} ]; then\n install_name_tool -id \"$LD_DYLIB_INSTALL_NAME\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n fi\n "; + }; + + CA6017FED97780E02D6C7F57 = { + isa = XCConfigurationList; + buildConfigurations = ( + CA6084F020463CC16B37690B /* Release */, + CA6084F02046228BE02872F8 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + + CA6084F020463CC16B37690B = { + isa = XCBuildConfiguration; + buildSettings = { + + ALWAYS_SEARCH_USER_PATHS = NO; + SUPPORTS_MACCATALYST = YES; + CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target"; /* for cargo */ + CARGO_XCODE_FEATURES = ""; /* configure yourself */ + DYLIB_INSTALL_NAME_BASE = "$(TARGET_BUILD_DIR)"; + "CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = "aarch64"; + "CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = "x86_64"; /* catalyst adds h suffix */ + "CARGO_XCODE_TARGET_ARCH[arch=i386]" = "i686"; + "CARGO_XCODE_TARGET_OS[sdk=macosx*]" = "darwin"; + "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim"; + "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = "ios"; + "CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = "ios"; + "CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = "tvos"; + "CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = "tvos"; + PRODUCT_NAME = "native"; + MARKETING_VERSION = "0.1.0"; + CURRENT_PROJECT_VERSION = "0.1"; + SDKROOT = macosx; + + "CARGO_XCODE_BUILD_MODE" = "release"; /* for xcode scripts */ + }; + name = Release; + }; + + CA6084F02046228BE02872F8 = { + isa = XCBuildConfiguration; + buildSettings = { + + ALWAYS_SEARCH_USER_PATHS = NO; + SUPPORTS_MACCATALYST = YES; + CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target"; /* for cargo */ + CARGO_XCODE_FEATURES = ""; /* configure yourself */ + DYLIB_INSTALL_NAME_BASE = "$(TARGET_BUILD_DIR)"; + "CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = "aarch64"; + "CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = "x86_64"; /* catalyst adds h suffix */ + "CARGO_XCODE_TARGET_ARCH[arch=i386]" = "i686"; + "CARGO_XCODE_TARGET_OS[sdk=macosx*]" = "darwin"; + "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim"; + "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = "ios"; + "CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = "ios"; + "CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = "tvos"; + "CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = "tvos"; + PRODUCT_NAME = "native"; + MARKETING_VERSION = "0.1.0"; + CURRENT_PROJECT_VERSION = "0.1"; + SDKROOT = macosx; + + "CARGO_XCODE_BUILD_MODE" = "debug"; /* for xcode scripts */ + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + + CA6017FED977E04653AD465F = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + TargetAttributes = { + CA60B7FEF469E2440CDF5F92 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + CA6043101CA242DAEB7745A8 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = CA6017FED97780E02D6C7F57; + compatibilityVersion = "Xcode 11.4"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CA6017FED977D65BC3C892A8; + productRefGroup = CA6017FED97722869D176AE5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + CA60B7FEF469E2440CDF5F92, +CA6043101CA242DAEB7745A8, + + ); + }; + + }; + rootObject = CA6017FED977E04653AD465F; +} + \ No newline at end of file diff --git a/native/native.xcodeproj/xcuserdata/dcvz.xcuserdatad/xcschemes/xcschememanagement.plist b/native/native.xcodeproj/xcuserdata/dcvz.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..4b44de8 --- /dev/null +++ b/native/native.xcodeproj/xcuserdata/dcvz.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,19 @@ + + + + + SchemeUserState + + native-cdylib.xcscheme_^#shared#^_ + + orderHint + 3 + + native-staticlib.xcscheme_^#shared#^_ + + orderHint + 2 + + + + diff --git a/native/src/api.rs b/native/src/api.rs new file mode 100644 index 0000000..01d5c43 --- /dev/null +++ b/native/src/api.rs @@ -0,0 +1,28 @@ +use std::io::Cursor; +use farbe::image::n64::{NativeImage, ImageFormat}; + +fn map_dart_value_to_image_format(value: u8) -> ImageFormat { + match value { + 1 => ImageFormat::RGBA32, + 2 => ImageFormat::RGBA16, + 3 => ImageFormat::CI4, + 4 => ImageFormat::CI8, + 5 => ImageFormat::I4, + 6 => ImageFormat::I8, + 7 => ImageFormat::IA4, + 8 => ImageFormat::IA8, + 9 => ImageFormat::IA16, + _ => panic!("Invalid image format"), + } +} + +pub fn convert_native_to_png(bytes: Vec, format: u8, width: u32, height: u32) -> Vec { + let mut cursor = Cursor::new(bytes); + let format = map_dart_value_to_image_format(format); + let image = NativeImage::read(&mut cursor, format, width, height).unwrap(); + + let mut output = Vec::new(); + image.as_png(&mut output).unwrap(); + + output +} diff --git a/native/src/bridge_generated.io.rs b/native/src/bridge_generated.io.rs new file mode 100644 index 0000000..6314d24 --- /dev/null +++ b/native/src/bridge_generated.io.rs @@ -0,0 +1,66 @@ +use super::*; +// Section: wire functions + +#[no_mangle] +pub extern "C" fn wire_convert_native_to_png( + port_: i64, + bytes: *mut wire_uint_8_list, + format: u8, + width: u32, + height: u32, +) { + wire_convert_native_to_png_impl(port_, bytes, format, width, height) +} + +// Section: allocate functions + +#[no_mangle] +pub extern "C" fn new_uint_8_list_0(len: i32) -> *mut wire_uint_8_list { + let ans = wire_uint_8_list { + ptr: support::new_leak_vec_ptr(Default::default(), len), + len, + }; + support::new_leak_box_ptr(ans) +} + +// Section: related functions + +// Section: impl Wire2Api + +impl Wire2Api> for *mut wire_uint_8_list { + fn wire2api(self) -> Vec { + unsafe { + let wrap = support::box_from_leak_ptr(self); + support::vec_from_leak_ptr(wrap.ptr, wrap.len) + } + } +} +// Section: wire structs + +#[repr(C)] +#[derive(Clone)] +pub struct wire_uint_8_list { + ptr: *mut u8, + len: i32, +} + +// Section: impl NewWithNullPtr + +pub trait NewWithNullPtr { + fn new_with_null_ptr() -> Self; +} + +impl NewWithNullPtr for *mut T { + fn new_with_null_ptr() -> Self { + std::ptr::null_mut() + } +} + +// Section: sync execution mode utility + +#[no_mangle] +pub extern "C" fn free_WireSyncReturn(ptr: support::WireSyncReturn) { + unsafe { + let _ = support::box_from_leak_ptr(ptr); + }; +} diff --git a/native/src/bridge_generated.rs b/native/src/bridge_generated.rs new file mode 100644 index 0000000..77e906c --- /dev/null +++ b/native/src/bridge_generated.rs @@ -0,0 +1,95 @@ +#![allow( + non_camel_case_types, + unused, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + clippy::double_parens, + non_snake_case, + clippy::too_many_arguments +)] +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.72.0. + +use crate::api::*; +use core::panic::UnwindSafe; +use flutter_rust_bridge::*; +use std::ffi::c_void; +use std::sync::Arc; + +// Section: imports + +// Section: wire functions + +fn wire_convert_native_to_png_impl( + port_: MessagePort, + bytes: impl Wire2Api> + UnwindSafe, + format: impl Wire2Api + UnwindSafe, + width: impl Wire2Api + UnwindSafe, + height: impl Wire2Api + UnwindSafe, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap( + WrapInfo { + debug_name: "convert_native_to_png", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || { + let api_bytes = bytes.wire2api(); + let api_format = format.wire2api(); + let api_width = width.wire2api(); + let api_height = height.wire2api(); + move |task_callback| { + Ok(convert_native_to_png( + api_bytes, api_format, api_width, api_height, + )) + } + }, + ) +} +// Section: wrapper structs + +// Section: static checks + +// Section: allocate functions + +// Section: related functions + +// Section: impl Wire2Api + +pub trait Wire2Api { + fn wire2api(self) -> T; +} + +impl Wire2Api> for *mut S +where + *mut S: Wire2Api, +{ + fn wire2api(self) -> Option { + (!self.is_null()).then(|| self.wire2api()) + } +} +impl Wire2Api for u32 { + fn wire2api(self) -> u32 { + self + } +} +impl Wire2Api for u8 { + fn wire2api(self) -> u8 { + self + } +} + +// Section: impl IntoDart + +// Section: executor + +support::lazy_static! { + pub static ref FLUTTER_RUST_BRIDGE_HANDLER: support::DefaultHandler = Default::default(); +} + +#[cfg(not(target_family = "wasm"))] +#[path = "bridge_generated.io.rs"] +mod io; +#[cfg(not(target_family = "wasm"))] +pub use io::*; diff --git a/native/src/lib.rs b/native/src/lib.rs new file mode 100644 index 0000000..97e8ba2 --- /dev/null +++ b/native/src/lib.rs @@ -0,0 +1,2 @@ +mod bridge_generated; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */ +mod api; diff --git a/pubspec.lock b/pubspec.lock index f8b82f8..817775b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.7" + args: + dependency: transitive + description: + name: args + sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a + url: "https://pub.dev" + source: hosted + version: "2.4.1" async: dependency: transitive description: @@ -25,6 +33,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172 + url: "https://pub.dev" + source: hosted + version: "2.1.0" characters: dependency: transitive description: @@ -49,6 +65,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.1" + colorize: + dependency: transitive + description: + name: colorize + sha256: "584746cd6ba1cba0633b6720f494fe6f9601c4170f0666c1579d2aa2a61071ba" + url: "https://pub.dev" + source: hosted + version: "3.0.0" convert: dependency: transitive description: @@ -82,7 +106,7 @@ packages: source: hosted version: "1.3.1" ffi: - dependency: transitive + dependency: "direct main" description: name: ffi sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 @@ -123,6 +147,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.14" + flutter_rust_bridge: + dependency: "direct main" + description: + name: flutter_rust_bridge + sha256: "36e11b79ac7011d9203313468c5827fe1215b0fa03df384cfe2891a68ed74ed5" + url: "https://pub.dev" + source: hosted + version: "1.75.3" flutter_storm: dependency: "direct main" description: @@ -142,6 +174,30 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + http: + dependency: transitive + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" image: dependency: "direct main" description: @@ -166,6 +222,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" lints: dependency: transitive description: @@ -174,6 +238,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + logging: + dependency: transitive + description: + name: logging + sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + url: "https://pub.dev" + source: hosted + version: "1.1.1" matcher: dependency: transitive description: @@ -198,6 +270,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" nested: dependency: transitive description: @@ -238,6 +318,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.7.3" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" provider: dependency: "direct main" description: @@ -246,6 +334,38 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.5" + puppeteer: + dependency: transitive + description: + name: puppeteer + sha256: dd49117259867d0ce0de33ddd95628fb70cff94581a6432c08272447b8dd1d27 + url: "https://pub.dev" + source: hosted + version: "2.24.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" sky_engine: dependency: transitive description: flutter @@ -379,6 +499,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.6" + uuid: + dependency: transitive + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" vector_math: dependency: transitive description: @@ -395,6 +523,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" win32: dependency: transitive description: @@ -420,6 +556,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.3.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.0.0-417 <4.0.0" flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index 869df14..7c8e5a3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=2.18.4 <4.0.0' + sdk: '>=2.18.4 <3.0.0' # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -53,6 +53,9 @@ dependencies: image: ^4.0.7 intl: ^0.18.0 path: ^1.8.2 + ffi: ^2.0.1 + flutter_rust_bridge: ^1.72.0 + freezed_annotation: ^2.2.0 flutter_icons: windows: From fe1d0570e2bd3de95a61c94f7cbda08fd8b4a323 Mon Sep 17 00:00:00 2001 From: David Chavez Date: Tue, 28 Mar 2023 11:40:14 +0200 Subject: [PATCH 4/7] Make async the default From 0967844c2e273538e5d2a3fd35892780b4821cb9 Mon Sep 17 00:00:00 2001 From: David Chavez Date: Fri, 12 May 2023 00:58:12 +0200 Subject: [PATCH 5/7] Rebase --- lib/bridge_definitions.dart | 2 +- .../create_finish/create_finish_screen.dart | 2 +- .../create_finish_viewmodel.dart | 22 +- .../create_replace_textures_viewmodel.dart | 71 +++++-- .../debug_convert_textures_screen.dart | 190 ++++++++++-------- .../debug_font_generator_screen.dart | 12 +- lib/ffi.dart | 10 +- lib/otr/types/texture.dart | 20 +- lib/utils/tex_utils.dart | 2 +- 9 files changed, 203 insertions(+), 128 deletions(-) diff --git a/lib/bridge_definitions.dart b/lib/bridge_definitions.dart index fd03b9f..6d413f6 100644 --- a/lib/bridge_definitions.dart +++ b/lib/bridge_definitions.dart @@ -14,7 +14,7 @@ abstract class Native { required int format, required int width, required int height, - dynamic hint}); + dynamic hint,}); FlutterRustBridgeTaskConstMeta get kConvertNativeToPngConstMeta; } diff --git a/lib/features/create/create_finish/create_finish_screen.dart b/lib/features/create/create_finish/create_finish_screen.dart index da6d4ab..4577f5b 100644 --- a/lib/features/create/create_finish/create_finish_screen.dart +++ b/lib/features/create/create_finish/create_finish_screen.dart @@ -35,7 +35,7 @@ class _CreateFinishBottomBarModalState viewModel.entries[key].runtimeType == CustomTexturesEntry && viewModel.prependAlt; widgets.add(Text("${shouldPrependAlt ? "alt/" : ""}$key", - style: textTheme.titleSmall)); + style: textTheme.titleSmall,),); widgets.addAll( viewModel.entries[key]!.iterables.map( (file) => Row( diff --git a/lib/features/create/create_finish/create_finish_viewmodel.dart b/lib/features/create/create_finish/create_finish_viewmodel.dart index 83d6ae4..59431ff 100644 --- a/lib/features/create/create_finish/create_finish_viewmodel.dart +++ b/lib/features/create/create_finish/create_finish_viewmodel.dart @@ -112,7 +112,7 @@ class CreateFinishViewModel with ChangeNotifier { } totalFiles += replacementMap.values.fold( - 0, (previousValue, element) => previousValue + element.length); + 0, (previousValue, element) => previousValue + element.length,); currentState = AppState.changesStaged; notifyListeners(); } @@ -173,7 +173,7 @@ class CreateFinishViewModel with ChangeNotifier { } Future createGenerationIsolate(HashMap entries, - String outputFile, bool shouldPrependAlt) async { + String outputFile, bool shouldPrependAlt,) async { final receivePort = ReceivePort(); await Isolate.spawn( generateOTR, @@ -210,10 +210,10 @@ class CreateFinishViewModel with ChangeNotifier { } Future generateOTR( - Tuple4, String, SendPort, bool> params) async { + Tuple4, String, SendPort, bool> params,) async { try { MPQArchive? mpqArchive = MPQArchive.create( - params.item2, MPQ_CREATE_SIGNATURE | MPQ_CREATE_ARCHIVE_V2, 12288); + params.item2, MPQ_CREATE_SIGNATURE | MPQ_CREATE_ARCHIVE_V2, 12288,); for (final entry in params.item1.entries) { if (entry.value is CustomStageEntry) { for (final file in (entry.value as CustomStageEntry).files) { @@ -227,7 +227,7 @@ Future generateOTR( DateTime.now().millisecondsSinceEpoch ~/ 1000, fileLength, 0, - MPQ_FILE_COMPRESS); + MPQ_FILE_COMPRESS,); mpqFile.write(fileData, fileLength, MPQ_COMPRESSION_ZLIB); mpqFile.finish(); params.item3.send(1); @@ -242,7 +242,7 @@ Future generateOTR( DateTime.now().millisecondsSinceEpoch ~/ 1000, data.length, 0, - MPQ_FILE_COMPRESS); + MPQ_FILE_COMPRESS,); mpqFile.write(data, data.length, MPQ_COMPRESSION_ZLIB); mpqFile.finish(); params.item3.send(1); @@ -250,11 +250,11 @@ Future generateOTR( } else if (entry.value is CustomTexturesEntry) { final processes = (entry.value as CustomTexturesEntry).pairs.map( (pair) => compute( - processTextureEntry, Tuple3(entry.key, pair, params.item4)), + processTextureEntry, Tuple3(entry.key, pair, params.item4),), ); final textures = await FutureExtensions.progressWait( - processes, () => params.item3.send(1)); + processes, () => params.item3.send(1),); for (final texture in textures) { if (texture.item2 == null) { @@ -267,9 +267,9 @@ Future generateOTR( DateTime.now().millisecondsSinceEpoch ~/ 1000, texture.item2!.length, 0, - MPQ_FILE_COMPRESS); + MPQ_FILE_COMPRESS,); mpqFile.write( - texture.item2!, texture.item2!.length, MPQ_COMPRESSION_ZLIB); + texture.item2!, texture.item2!.length, MPQ_COMPRESSION_ZLIB,); mpqFile.finish(); } } @@ -285,7 +285,7 @@ Future generateOTR( } Future> processTextureEntry( - Tuple3, bool> params) async { + Tuple3, bool> params,) async { final pair = params.item2; final textureName = pair.item1.path.split('/').last.split('.').first; final fileName = '${params.item1}/$textureName'; diff --git a/lib/features/create/create_replace_textures/create_replace_textures_viewmodel.dart b/lib/features/create/create_replace_textures/create_replace_textures_viewmodel.dart index 62fe358..0331917 100644 --- a/lib/features/create/create_replace_textures/create_replace_textures_viewmodel.dart +++ b/lib/features/create/create_replace_textures/create_replace_textures_viewmodel.dart @@ -72,7 +72,10 @@ class CreateReplaceTexturesViewModel extends ChangeNotifier { Future onSelectOTR() async { final result = await FilePicker.platform.pickFiles( - allowMultiple: true, type: FileType.custom, allowedExtensions: ['otr']); + allowMultiple: true, + type: FileType.custom, + allowedExtensions: ['otr'], + ); if (result != null && result.files.isNotEmpty) { // save paths filtering out nulls selectedOTRPaths = result.paths.whereType().toList(); @@ -130,7 +133,7 @@ class CreateReplaceTexturesViewModel extends ChangeNotifier { notifyListeners(); } - dumpFont(String outputPath, Function onProcessed) async { + Future dumpFont(String outputPath, Function onProcessed) async { final fontImage = Image(width: 16 * 4, height: 256, numChannels: 4); final tex = Texture.empty(); @@ -144,8 +147,12 @@ class CreateReplaceTexturesViewModel extends ChangeNotifier { await rootBundle.load(fontTLUT.replaceAll('%d', id.toString())); final pngImage = decodePng(data.buffer.asUint8List())!; tlut.fromRawImage(pngImage); - compositeImage(fontImage, decodePng(tex.toPNGBytes())!, - dstX: id * 16, dstY: 0); + compositeImage( + fontImage, + decodePng(await tex.toPNGBytes())!, + dstX: id * 16, + dstY: 0, + ); } final textureFile = File(path.join(outputPath, '$fontTextureName.png')); @@ -153,13 +160,20 @@ class CreateReplaceTexturesViewModel extends ChangeNotifier { await textureFile.create(recursive: true); await textureFile.writeAsBytes(pngBytes); final hash = sha256.convert(pngBytes).toString(); - onProcessed(TextureManifestEntry( - hash, tex.textureType, fontImage.width, fontImage.height)); + onProcessed( + TextureManifestEntry( + hash, + tex.textureType, + fontImage.width, + fontImage.height, + ), + ); } } Future?> processFolder( - String folderPath) async { + String folderPath, +) async { final processedFiles = HashMap(); // search for and load manifest.json @@ -194,10 +208,12 @@ Future?> processFolder( // if it has, add it to the processed files list log('Found file with changed hash: $texPathRelativeToFolder'); - final pathWithoutFilename = p.normalize(texPathRelativeToFolder - .split('/') - .sublist(0, texPathRelativeToFolder.split('/').length - 1) - .join('/')); + final pathWithoutFilename = p.normalize( + texPathRelativeToFolder + .split('/') + .sublist(0, texPathRelativeToFolder.split('/').length - 1) + .join('/'), + ); if (processedFiles.containsKey(pathWithoutFilename)) { processedFiles[pathWithoutFilename]! .add(Tuple2(texFile, manifestEntry)); @@ -216,7 +232,8 @@ Future?> processFolder( } Future?> processOTR( - Tuple2, String> params) async { + Tuple2, String> params, +) async { try { var fileFound = false; final processedFiles = HashMap(); @@ -290,8 +307,12 @@ Future?> processOTR( } } -Future processFile(String fileName, MPQArchive mpqArchive, - String outputPath, Function onProcessed) async { +Future processFile( + String fileName, + MPQArchive mpqArchive, + String outputPath, + Function onProcessed, +) async { try { final file = mpqArchive.openFileEx(fileName, 0); final fileSize = file.size(); @@ -313,14 +334,20 @@ Future processFile(String fileName, MPQArchive mpqArchive, final texture = Texture.empty(); texture.open(fileData); - final pngBytes = texture.toPNGBytes(); + final pngBytes = await texture.toPNGBytes(); final textureFile = File('$outputPath.png'); await textureFile.create(recursive: true); await textureFile.writeAsBytes(pngBytes); final textureBytes = await textureFile.readAsBytes(); hash = sha256.convert(textureBytes).toString(); - onProcessed(TextureManifestEntry( - hash, texture.textureType, texture.width, texture.height)); + onProcessed( + TextureManifestEntry( + hash, + texture.textureType, + texture.width, + texture.height, + ), + ); break; case ResourceType.sohBackground: final background = Background.empty(); @@ -332,8 +359,14 @@ Future processFile(String fileName, MPQArchive mpqArchive, await textureFile.create(recursive: true); await textureFile.writeAsBytes(background.texData); hash = sha256.convert(background.texData).toString(); - onProcessed(TextureManifestEntry( - hash, TextureType.JPEG32bpp, image.width, image.height)); + onProcessed( + TextureManifestEntry( + hash, + TextureType.JPEG32bpp, + image.width, + image.height, + ), + ); break; default: return false; diff --git a/lib/features/debug/debug_convert_textures/debug_convert_textures_screen.dart b/lib/features/debug/debug_convert_textures/debug_convert_textures_screen.dart index d023621..745abe7 100644 --- a/lib/features/debug/debug_convert_textures/debug_convert_textures_screen.dart +++ b/lib/features/debug/debug_convert_textures/debug_convert_textures_screen.dart @@ -15,11 +15,11 @@ class DebugGeneratorFontsScreen extends StatefulWidget { const DebugGeneratorFontsScreen({super.key}); @override - State createState() => _DebugGeneratorFontsScreenState(); + State createState() => + _DebugGeneratorFontsScreenState(); } class _DebugGeneratorFontsScreenState extends State { - TextureType selectedTextureType = TextureType.RGBA32bpp; Texture? textureData; File? textureFile; @@ -44,8 +44,13 @@ class _DebugGeneratorFontsScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - const Text('PNG to N64 Viewer', - style: TextStyle(color: Colors.white, fontFamily: 'GoogleSans', fontWeight: FontWeight.bold), + const Text( + 'PNG to N64 Viewer', + style: TextStyle( + color: Colors.white, + fontFamily: 'GoogleSans', + fontWeight: FontWeight.bold, + ), ), const SizedBox(height: 20), DecoratedBox( @@ -58,17 +63,26 @@ class _DebugGeneratorFontsScreenState extends State { icon: const Icon(Icons.arrow_drop_down_rounded), borderRadius: BorderRadius.circular(5), iconEnabledColor: Colors.white, - style: const TextStyle(color: Colors.white, fontFamily: 'GoogleSans', fontWeight: FontWeight.bold), + style: const TextStyle( + color: Colors.white, + fontFamily: 'GoogleSans', + fontWeight: FontWeight.bold, + ), dropdownColor: const Color(0xFF40aae8), underline: Container(), - items: TextureType.values.sublist(1).map((e) => DropdownMenuItem( - value: e, - child: Padding( - padding: const EdgeInsets.only(left: 17), - child: Text(e.name), - ), - ),).toList(), - onChanged: (_){ + items: TextureType.values + .sublist(1) + .map( + (e) => DropdownMenuItem( + value: e, + child: Padding( + padding: const EdgeInsets.only(left: 17), + child: Text(e.name), + ), + ), + ) + .toList(), + onChanged: (_) { setState(() { selectedTextureType = _ as TextureType; }); @@ -81,7 +95,10 @@ class _DebugGeneratorFontsScreenState extends State { constraints: const BoxConstraints(maxWidth: 250), child: FittedBox( fit: BoxFit.scaleDown, - child: Text(textureFile == null ? 'Select Texture File' : textureFile!.path.split(path.separator).last, + child: Text( + textureFile == null + ? 'Select Texture File' + : textureFile!.path.split(path.separator).last, maxLines: 1, ), ), @@ -100,62 +117,73 @@ class _DebugGeneratorFontsScreenState extends State { const SizedBox(height: 20), ElevatedButton( child: const Text('Convert Texture'), - onPressed: (){ + onPressed: () { if (textureFile != null) { - setState(() { + setState(() async { textureData = Texture.empty(); textureData?.textureType = selectedTextureType; - final image = decodePng(textureFile!.readAsBytesSync())!; + final image = + decodePng(await textureFile!.readAsBytes())!; textureData!.fromRawImage(image); - if(selectedTextureType.name.contains('Palette')){ + if (selectedTextureType.name.contains('Palette')) { textureData!.isPalette = true; } - textureBytes = textureData!.toPNGBytes(); - }); - } - }, - ), - if(textureData != null && textureData!.isPalette) - const SizedBox(height: 20), - if(textureData != null && textureData!.isPalette) - ElevatedButton( - child: const Text('Load TLUT'), - onPressed: () async { - final result = await FilePicker.platform.pickFiles( - type: FileType.image, - ); - if (result != null) { - setState(() { - final tlut = Texture.empty(); - tlut.textureType = TextureType.RGBA32bpp; - final image = decodePng(File(result.files.single.path!).readAsBytesSync())!; - tlut.fromRawImage(image); - textureData!.tlut = tlut; - textureBytes = textureData!.toPNGBytes(); - }); - } - }, - ), - if(textureData != null && textureData!.tlut != null) - const SizedBox(height: 20), - if(textureData != null && textureData!.tlut != null) - ElevatedButton( - child: const Text('Save As'), - onPressed: () async { - final result = await FilePicker.platform.saveFile( - type: FileType.image, allowedExtensions: ['png'], fileName: 'converted.png', - ); - if (result != null) { - setState(() { - final out = File(result); - out.writeAsBytesSync(textureBytes!); + textureBytes = await textureData!.toPNGBytes(); }); } }, ), + if (textureData != null && textureData!.isPalette) + const SizedBox(height: 20), + if (textureData != null && textureData!.isPalette) + ElevatedButton( + child: const Text('Load TLUT'), + onPressed: () async { + final result = await FilePicker.platform.pickFiles( + type: FileType.image, + ); + if (result != null) { + setState(() async { + final tlut = Texture.empty() + ..textureType = TextureType.RGBA32bpp; + final image = decodePng( + await File(result.files.single.path!) + .readAsBytes(), + )!; + tlut.fromRawImage(image); + textureData!.tlut = tlut; + textureBytes = await textureData!.toPNGBytes(); + }); + } + }, + ), + if (textureData != null && textureData!.tlut != null) + const SizedBox(height: 20), + if (textureData != null && textureData!.tlut != null) + ElevatedButton( + child: const Text('Save As'), + onPressed: () async { + final result = await FilePicker.platform.saveFile( + type: FileType.image, + allowedExtensions: ['png'], + fileName: 'converted.png', + ); + if (result != null) { + setState(() async { + final out = File(result); + await out.writeAsBytes(textureBytes!); + }); + } + }, + ), const SizedBox(height: 20), - const Text('OTR N64 Viewer', - style: TextStyle(color: Colors.white, fontFamily: 'GoogleSans', fontWeight: FontWeight.bold), + const Text( + 'OTR N64 Viewer', + style: TextStyle( + color: Colors.white, + fontFamily: 'GoogleSans', + fontWeight: FontWeight.bold, + ), ), const SizedBox(height: 20), ElevatedButton( @@ -163,15 +191,16 @@ class _DebugGeneratorFontsScreenState extends State { constraints: const BoxConstraints(maxWidth: 250), child: FittedBox( fit: BoxFit.scaleDown, - child: Text(textureFile == null ? 'Select Texture File' : textureFile!.path.split(path.separator).last, + child: Text( + textureFile == null + ? 'Select Texture File' + : textureFile!.path.split(path.separator).last, maxLines: 1, ), ), ), onPressed: () async { - final result = await FilePicker.platform.pickFiles( - - ); + final result = await FilePicker.platform.pickFiles(); if (result != null) { setState(() { textureFile = File(result.files.single.path!); @@ -182,22 +211,21 @@ class _DebugGeneratorFontsScreenState extends State { const SizedBox(height: 20), ElevatedButton( child: const Text('Load Texture'), - onPressed: (){ + onPressed: () async { if (textureFile != null) { - final bytes = textureFile!.readAsBytesSync(); + final bytes = await textureFile!.readAsBytes(); - setState(() { - final resource = Resource.empty(); - resource.rawLoad = true; - resource.open(bytes); + setState(() async { + final resource = Resource.empty() + ..rawLoad = true + ..open(bytes); - if(resource.resourceType == ResourceType.texture){ + if (resource.resourceType == ResourceType.texture) { textureData = Texture.empty(); textureData?.open(bytes); - textureBytes = textureData!.toPNGBytes(); + textureBytes = await textureData!.toPNGBytes(); } else { - final background = Background.empty(); - background.open(bytes); + final background = Background.empty()..open(bytes); textureData = Texture.empty(); textureBytes = background.texData; } @@ -211,15 +239,17 @@ class _DebugGeneratorFontsScreenState extends State { Expanded( child: Container( height: MediaQuery.of(context).size.height - 119, - padding: const EdgeInsets.only( right: 20), + padding: const EdgeInsets.only(right: 20), decoration: BoxDecoration( color: Colors.transparent, borderRadius: BorderRadius.circular(10), - image: textureData != null ? DecorationImage( - image: MemoryImage(textureBytes!), - filterQuality: FilterQuality.none, - fit: BoxFit.contain, - ) : null, + image: textureData != null + ? DecorationImage( + image: MemoryImage(textureBytes!), + filterQuality: FilterQuality.none, + fit: BoxFit.contain, + ) + : null, ), ), ), @@ -228,4 +258,4 @@ class _DebugGeneratorFontsScreenState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/debug/debug_font_generator/debug_font_generator_screen.dart b/lib/features/debug/debug_font_generator/debug_font_generator_screen.dart index e2ccf02..678133e 100644 --- a/lib/features/debug/debug_font_generator/debug_font_generator_screen.dart +++ b/lib/features/debug/debug_font_generator/debug_font_generator_screen.dart @@ -58,7 +58,7 @@ class _DebugGeneratorFontScreenState extends State { style: TextStyle( color: Colors.white, fontFamily: 'GoogleSans', - fontWeight: FontWeight.bold), + fontWeight: FontWeight.bold,), ), TextNumpad( title: 'Text Offset:', @@ -132,7 +132,7 @@ class _DebugGeneratorFontScreenState extends State { offset: textOffset, scale: textScale, glyphWidth: glyphWidth, - glyphHeight: glyphHeight), + glyphHeight: glyphHeight,), ) : null, ), @@ -242,7 +242,7 @@ class FontPainter extends CustomPainter { final ty = (id / 8).floorToDouble(); final to = Offset(tx * glyphWidth, ty * glyphHeight); final rect = Rect.fromLTWH( - to.dx, to.dy, glyphWidth.toDouble(), glyphHeight.toDouble()); + to.dx, to.dy, glyphWidth.toDouble(), glyphHeight.toDouble(),); final text = fontTable[ty.toInt()][tx.toInt()]; if (drawGrid) { canvas.drawRect(rect, paint); @@ -258,9 +258,9 @@ class FontPainter extends CustomPainter { ? convertFontSize(20) : convertFontSize(text.contains(regExp) ? glyphHeight - 5 - : glyphHeight.toDouble()) * + : glyphHeight.toDouble(),) * scale, - fontFamily: fontFamily), + fontFamily: fontFamily,), ), ); textPainter.layout(maxWidth: size.width); @@ -271,7 +271,7 @@ class FontPainter extends CustomPainter { (ty * glyphHeight + (glyphHeight / 2) - (textPainter.size.height / 2)) - - offset)); + offset,),); } } diff --git a/lib/ffi.dart b/lib/ffi.dart index fd1434a..bc72e38 100644 --- a/lib/ffi.dart +++ b/lib/ffi.dart @@ -2,14 +2,14 @@ // generated by flutter_rust_bridge_codegen. import 'dart:ffi'; +import 'dart:io' as io; -import 'bridge_generated.dart'; -import 'bridge_definitions.dart'; -export 'bridge_definitions.dart'; +import 'package:retro/bridge_definitions.dart'; +import 'package:retro/bridge_generated.dart'; +export 'bridge_definitions.dart'; // Re-export the bridge so it is only necessary to import this file. export 'bridge_generated.dart'; -import 'dart:io' as io; const _base = 'native'; @@ -19,4 +19,4 @@ final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so'; final Native api = NativeImpl(io.Platform.isIOS || io.Platform.isMacOS ? DynamicLibrary.executable() - : DynamicLibrary.open(_dylib)); + : DynamicLibrary.open(_dylib),); diff --git a/lib/otr/types/texture.dart b/lib/otr/types/texture.dart index 63b4d5a..8326383 100644 --- a/lib/otr/types/texture.dart +++ b/lib/otr/types/texture.dart @@ -2,6 +2,7 @@ import 'dart:typed_data'; import 'package:image/image.dart'; +import 'package:retro/ffi.dart'; import 'package:retro/otr/resource.dart'; import 'package:retro/otr/resource_type.dart'; import 'package:retro/otr/version.dart'; @@ -38,10 +39,13 @@ enum TextureType { } class Texture extends Resource { - Texture( - this.textureType, this.width, this.height, this.texDataSize, this.texData,) - : super(ResourceType.texture, 0, Version.deckard); + this.textureType, + this.width, + this.height, + this.texDataSize, + this.texData, + ) : super(ResourceType.texture, 0, Version.deckard); Texture.empty() : this(TextureType.Error, 0, 0, 0, Uint8List(0)); TextureType textureType; @@ -96,7 +100,15 @@ class Texture extends Resource { convertRawToN64(png); } - Uint8List toPNGBytes() { + Future toPNGBytes() async { + return api.convertNativeToPng( + bytes: texData, + format: textureType.value, + width: width, + height: height,); + } + + Uint8List toPNGBytesSync() { return convertN64ToPNG() ?? Uint8List(0); } diff --git a/lib/utils/tex_utils.dart b/lib/utils/tex_utils.dart index 31b510e..7715458 100644 --- a/lib/utils/tex_utils.dart +++ b/lib/utils/tex_utils.dart @@ -275,7 +275,7 @@ extension N64Graphics on Texture { } if (isPalette && tlut != null) { - final pal = decodePng(tlut!.toPNGBytes())!; + final pal = decodePng(tlut!.toPNGBytesSync())!; for (var y = 0; y < pal.height; y++) { for (var x = 0; x < pal.width; x++) { From d4e81022433ac14a0618dfbaa20edf4669319f7e Mon Sep 17 00:00:00 2001 From: David Chavez Date: Fri, 12 May 2023 01:05:39 +0200 Subject: [PATCH 6/7] Bump farbe --- native/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/Cargo.toml b/native/Cargo.toml index ac08900..84b1079 100644 --- a/native/Cargo.toml +++ b/native/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -farbe = "0.1.0" +farbe = "0.2.0" flutter_rust_bridge = "1" [lib] From 9839a81e1f729223912c53f5f60141efe3f9429e Mon Sep 17 00:00:00 2001 From: David Chavez Date: Fri, 12 May 2023 01:12:13 +0200 Subject: [PATCH 7/7] Remove old conversions --- lib/otr/types/texture.dart | 13 ++-- lib/utils/tex_utils.dart | 138 ------------------------------------- 2 files changed, 5 insertions(+), 146 deletions(-) diff --git a/lib/otr/types/texture.dart b/lib/otr/types/texture.dart index 8326383..1b1aca4 100644 --- a/lib/otr/types/texture.dart +++ b/lib/otr/types/texture.dart @@ -102,14 +102,11 @@ class Texture extends Resource { Future toPNGBytes() async { return api.convertNativeToPng( - bytes: texData, - format: textureType.value, - width: width, - height: height,); - } - - Uint8List toPNGBytesSync() { - return convertN64ToPNG() ?? Uint8List(0); + bytes: texData, + format: textureType.value, + width: width, + height: height, + ); } int getTMEMSize() { diff --git a/lib/utils/tex_utils.dart b/lib/utils/tex_utils.dart index 7715458..eea2e15 100644 --- a/lib/utils/tex_utils.dart +++ b/lib/utils/tex_utils.dart @@ -155,144 +155,6 @@ extension N64Graphics on Texture { } } - Uint8List? convertN64ToPNG() { - var image = Image( - width: width, - height: height, - numChannels: hasAlpha ? 4 : 3, - withPalette: isPalette, - ); - switch (textureType) { - case TextureType.RGBA32bpp: - image = Image.fromBytes( - width: width, - height: height, - bytes: texData.buffer, - numChannels: 4, - ); - break; - case TextureType.RGBA16bpp: - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - final pos = ((y * width) + x) * 2; - final data = texData[pos + 1] | (texData[pos] << 8); - final r = (data & 0xF800) >> 11; - final g = (data & 0x07C0) >> 6; - final b = (data & 0x003E) >> 1; - final a = data & 0x01; - image.setPixel(x, y, ColorInt8.rgba(r * 8, g * 8, b * 8, a * 255)); - } - } - break; - case TextureType.Palette4bpp: - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x += 2) { - for (var i = 0; i < 2; i++) { - final pos = ((y * width) + x) ~/ 2; - final paletteIndex = - i == 0 ? (texData[pos] & 0xF0) >> 4 : texData[pos] & 0x0F; - image.setPixelR(x + i, y, paletteIndex); - image.palette!.setRgba( - paletteIndex, - paletteIndex * 16, - paletteIndex * 16, - paletteIndex * 16, - 255, - ); - } - } - } - break; - case TextureType.Palette8bpp: - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - final pos = (y * width) + x; - final grayscale = texData[pos]; - image.setPixelR(x, y, grayscale); - image.palette! - .setRgba(grayscale, grayscale, grayscale, grayscale, 255); - } - } - break; - case TextureType.Grayscale4bpp: - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x += 2) { - for (var i = 0; i < 2; i++) { - final pos = ((y * width) + x) ~/ 2; - final grayscale = - i == 0 ? (texData[pos] & 0xF0) : (texData[pos] & 0x0F) << 4; - image.setGrayscalePixel(x + i, y, grayscale); - } - } - } - break; - case TextureType.Grayscale8bpp: - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - final pos = (y * width) + x; - image.setGrayscalePixel(x, y, texData[pos]); - } - } - break; - case TextureType.GrayscaleAlpha4bpp: - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x += 2) { - for (var i = 0; i < 2; i++) { - final pos = ((y * width) + x) ~/ 2; - final data = - i == 0 ? (texData[pos] & 0xF0) >> 4 : texData[pos] & 0x0F; - - final grayscale = ((data & 0x0E) >> 1) * 32; - final alpha = (data & 0x01) * 255; - - image.setGrayscalePixel(x + i, y, grayscale, alpha: alpha); - } - } - } - break; - case TextureType.GrayscaleAlpha8bpp: - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - final pos = ((y * width) + x) * 1; - final grayscale = texData[pos] & 0xF0; - final alpha = (texData[pos] & 0x0F) << 4; - image.setGrayscalePixel(x, y, grayscale, alpha: alpha); - } - } - break; - case TextureType.GrayscaleAlpha16bpp: - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - final pos = ((y * width) + x) * 2; - final grayscale = texData[pos]; - final alpha = texData[pos + 1]; - image.setGrayscalePixel(x, y, grayscale, alpha: alpha); - } - } - break; - default: - return null; - } - - if (isPalette && tlut != null) { - final pal = decodePng(tlut!.toPNGBytesSync())!; - - for (var y = 0; y < pal.height; y++) { - for (var x = 0; x < pal.width; x++) { - final index = y * pal.width + x; - if (index >= 16 * 16) { - continue; - } - - final pixel = pal.getPixel(x, y); - image.palette!.setRgba(index, pixel.r, pixel.g, pixel.b, pixel.a); - } - } - } - - return encodePng(image); - } - bool get hasAlpha => isPalette || textureType == TextureType.RGBA32bpp ||