This commit is contained in:
Nick Fisher
2024-04-30 14:14:54 +08:00
parent 8f9e309c34
commit 14b0b674c5
28 changed files with 423 additions and 1787 deletions

View File

@@ -25,6 +25,29 @@ void main(List<String> args) async {
"${config.packageRoot.toFilePath()}/native/include/material/image.c", "${config.packageRoot.toFilePath()}/native/include/material/image.c",
]); ]);
var frameworks = [];
if (platform == "ios") {
frameworks.addAll([
'Foundation',
'CoreGraphics',
'QuartzCore',
'GLKit',
"Metal",
'CoreVideo',
'OpenGLES'
]);
} else if (platform == "macos") {
frameworks.addAll([
'Foundation',
'CoreVideo',
'Cocoa',
"Metal",
]);
}
frameworks = frameworks.expand((f) => ["-framework", f]).toList();
final cbuilder = CBuilder.library( final cbuilder = CBuilder.library(
name: packageName, name: packageName,
language: Language.cpp, language: Language.cpp,
@@ -32,16 +55,10 @@ void main(List<String> args) async {
sources: sources, sources: sources,
includes: ['native/include', 'native/include/filament'], includes: ['native/include', 'native/include/filament'],
flags: [ flags: [
'-mmacosx-version-min=13.0', if (platform == "macos") '-mmacosx-version-min=13.0',
if (platform == "ios") '-mios-version-min=13.0',
...frameworks,
'-std=c++17', '-std=c++17',
'-framework',
'Foundation',
'-framework',
'CoreVideo',
'-framework',
'Cocoa',
'-framework',
'Metal',
"-lfilament", "-lfilament",
"-lbackend", "-lbackend",
"-lfilameshio", "-lfilameshio",
@@ -68,8 +85,8 @@ void main(List<String> args) async {
"-luberarchive", "-luberarchive",
"-lzstd", "-lzstd",
"-lstdc++", "-lstdc++",
"-lbluegl", if (platform == "macos") "-lbluegl",
"-lbluevk", if (platform == "macos") "-lbluevk",
"-lbasis_transcoder", "-lbasis_transcoder",
"-L$libDir", "-L$libDir",
"-force_load", "-force_load",

View File

@@ -48,8 +48,6 @@ class FilamentViewer extends AbstractFilamentViewer {
var _sharedContext = nullptr.cast<Void>(); var _sharedContext = nullptr.cast<Void>();
late final Pointer<Void> _surface;
/// ///
/// This controller uses platform channels to bridge Dart with the C/C++ code for the Filament API. /// This controller uses platform channels to bridge Dart with the C/C++ code for the Filament API.
/// Setting up the context/texture (since this is platform-specific) and the render ticker are platform-specific; all other methods are passed through by the platform channel to the methods specified in FlutterFilamentApi.h. /// Setting up the context/texture (since this is platform-specific) and the render ticker are platform-specific; all other methods are passed through by the platform channel to the methods specified in FlutterFilamentApi.h.
@@ -57,14 +55,12 @@ class FilamentViewer extends AbstractFilamentViewer {
FilamentViewer( FilamentViewer(
{RenderCallback? renderCallback, {RenderCallback? renderCallback,
Pointer<Void>? renderCallbackOwner, Pointer<Void>? renderCallbackOwner,
Pointer<Void>? surface,
required this.resourceLoader, required this.resourceLoader,
Pointer<Void>? driver, Pointer<Void>? driver,
Pointer<Void>? sharedContext, Pointer<Void>? sharedContext,
this.uberArchivePath}) { this.uberArchivePath}) {
this._renderCallbackOwner = renderCallbackOwner ?? nullptr; this._renderCallbackOwner = renderCallbackOwner ?? nullptr;
this._renderCallback = renderCallback ?? nullptr; this._renderCallback = renderCallback ?? nullptr;
this._surface = surface ?? nullptr;
this._driver = driver ?? nullptr; this._driver = driver ?? nullptr;
this._sharedContext = sharedContext ?? nullptr; this._sharedContext = sharedContext ?? nullptr;
@@ -87,11 +83,11 @@ class FilamentViewer extends AbstractFilamentViewer {
}); });
} }
Future createSwapChain(double width, double height) async { Future createSwapChain(double width, double height,
{Pointer<Void>? surface}) async {
await _withVoidCallback((callback) { await _withVoidCallback((callback) {
print("VIEWER IS $_viewer"); create_swap_chain_ffi(_viewer!, surface ?? nullptr, width.toInt(),
create_swap_chain_ffi( height.toInt(), callback);
_viewer!, _surface, width.toInt(), height.toInt(), callback);
}); });
} }

View File

@@ -0,0 +1,46 @@
#ifndef RESOURCE_BUFFER_H
#define RESOURCE_BUFFER_H
#include <stdint.h>
#include <stdlib.h>
//
// A ResourceBuffer is a unified interface for working with
// binary assets across various platforms.
// This is simply:
// 1) a pointer to some data
// 2) the length of the data
// 3) an ID that can be passed back to the native platform to release the underlying asset when needed.
//
struct ResourceBuffer
{
const void *const data;
const int32_t size;
const int32_t id;
#if defined(__cplusplus)
ResourceBuffer(void *const data, int32_t size, int32_t id) : data(data), size(size), id(id) {}
#endif
};
typedef struct ResourceBuffer ResourceBuffer;
typedef void (*LoadFilamentResourceIntoOutPointer)(const char *uri, ResourceBuffer *out);
typedef ResourceBuffer (*LoadFilamentResource)(const char *uri);
typedef ResourceBuffer (*LoadFilamentResourceFromOwner)(const char *const, void *const owner);
typedef void (*FreeFilamentResource)(ResourceBuffer);
typedef void (*FreeFilamentResourceFromOwner)(ResourceBuffer, void *const owner);
struct ResourceLoaderWrapper
{
LoadFilamentResource loadResource;
FreeFilamentResource freeResource;
LoadFilamentResourceFromOwner loadFromOwner;
FreeFilamentResourceFromOwner freeFromOwner;
void *owner;
LoadFilamentResourceIntoOutPointer loadToOut;
};
typedef struct ResourceLoaderWrapper ResourceLoaderWrapper;
ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner);
#endif

View File

@@ -1,45 +1,7 @@
#ifndef RESOURCE_BUFFER_H #ifndef RESOURCE_BUFFER_HPP
#define RESOURCE_BUFFER_H #define RESOURCE_BUFFER_HPP
#include <stdint.h> #include "ResourceBuffer.h"
#include <stdlib.h>
//
// A ResourceBuffer is a unified interface for working with
// binary assets across various platforms.
// This is simply:
// 1) a pointer to some data
// 2) the length of the data
// 3) an ID that can be passed back to the native platform to release the underlying asset when needed.
//
struct ResourceBuffer
{
const void *const data;
const int32_t size;
const int32_t id;
#if defined(__cplusplus)
ResourceBuffer(void *const data, int32_t size, int32_t id) : data(data), size(size), id(id) {}
#endif
};
typedef struct ResourceBuffer ResourceBuffer;
typedef void (*LoadFilamentResourceIntoOutPointer)(const char *uri, ResourceBuffer *out);
typedef ResourceBuffer (*LoadFilamentResource)(const char *uri);
typedef ResourceBuffer (*LoadFilamentResourceFromOwner)(const char *const, void *const owner);
typedef void (*FreeFilamentResource)(ResourceBuffer);
typedef void (*FreeFilamentResourceFromOwner)(ResourceBuffer, void *const owner);
struct ResourceLoaderWrapper
{
LoadFilamentResource loadResource;
FreeFilamentResource freeResource;
LoadFilamentResourceFromOwner loadFromOwner;
FreeFilamentResourceFromOwner freeFromOwner;
void *owner;
LoadFilamentResourceIntoOutPointer loadToOut;
};
typedef struct ResourceLoaderWrapper ResourceLoaderWrapper;
#if defined(__cplusplus) #if defined(__cplusplus)

View File

@@ -1,4 +1,2 @@
.vscode .vscode
macos/src .DS_Store
macos/include
.DS_Store

View File

@@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>11.0</string> <string>12.0</string>
</dict> </dict>
</plist> </plist>

View File

@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
platform :ios, '12.1' platform :ios, '13.1'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@@ -7,7 +7,7 @@ PODS:
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- permission_handler_apple (9.1.1): - permission_handler_apple (9.3.0):
- Flutter - Flutter
DEPENDENCIES: DEPENDENCIES:
@@ -30,12 +30,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/permission_handler_apple/ios" :path: ".symlinks/plugins/permission_handler_apple/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_filament: 9d744e795935e0fc5308e46a0c5947cb91714848 flutter_filament: 931482c60f0020743ef1a87350e0620079c22b61
integration_test: 13825b8a9334a850581300559b8839134b124670 integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PODFILE CHECKSUM: 7adbc9d59f05e1b01f554ea99b6c79e97f2214a2 PODFILE CHECKSUM: a4605dec2dc7bf1ddcfc6f5f4cb7515785c9865e
COCOAPODS: 1.12.1 COCOAPODS: 1.15.2

View File

@@ -139,6 +139,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
F9FAB8A67CF505858CCDA424 /* [CP] Embed Pods Frameworks */, F9FAB8A67CF505858CCDA424 /* [CP] Embed Pods Frameworks */,
55F3237D47F23FE63525E002 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -155,7 +156,7 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1430; LastUpgradeCheck = 1510;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
@@ -235,6 +236,23 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
55F3237D47F23FE63525E002 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@@ -365,6 +383,7 @@
DEVELOPMENT_TEAM = TM2B4SJXNJ; DEVELOPMENT_TEAM = TM2B4SJXNJ;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@@ -504,6 +523,7 @@
DEVELOPMENT_TEAM = TM2B4SJXNJ; DEVELOPMENT_TEAM = TM2B4SJXNJ;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@@ -533,6 +553,7 @@
DEVELOPMENT_TEAM = TM2B4SJXNJ; DEVELOPMENT_TEAM = TM2B4SJXNJ;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1430" LastUpgradeVersion = "1510"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@@ -1,7 +1,7 @@
import UIKit import UIKit
import Flutter import Flutter
@UIApplicationMain @main
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,

View File

@@ -1,4 +0,0 @@
#import <Flutter/Flutter.h>
@interface FlutterFilamentPlugin : NSObject<FlutterPlugin>
@end

View File

@@ -1,18 +0,0 @@
#import "FlutterFilamentPlugin.h"
#if __has_include(<flutter_filament/flutter_filament-Swift.h>)
#import <flutter_filament/flutter_filament-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import "flutter_filament-Swift.h"
#endif
#include "FlutterFilamentApi.h"
@implementation FlutterFilamentPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftFlutterFilamentPlugin registerWithRegistrar:registrar];
ios_dummy();
}
@end

View File

@@ -0,0 +1,48 @@
import Foundation
import GLKit
import Flutter
public class FlutterFilamentTexture : NSObject, FlutterTexture {
public var pixelBuffer: CVPixelBuffer?
var pixelBufferAttrs = [
kCVPixelBufferPixelFormatTypeKey: NSNumber(value: kCVPixelFormatType_32BGRA),
kCVPixelBufferOpenGLCompatibilityKey: kCFBooleanTrue,
kCVPixelBufferOpenGLESCompatibilityKey: kCFBooleanTrue,
kCVPixelBufferIOSurfacePropertiesKey: [:]
] as CFDictionary
var flutterTextureId: Int64 = -1
var registry: FlutterTextureRegistry?
init(width:Int64, height:Int64, registry:FlutterTextureRegistry) {
self.registry = registry
super.init()
if(CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height),
kCVPixelFormatType_32BGRA, pixelBufferAttrs, &pixelBuffer) != kCVReturnSuccess) {
print("Error allocating pixel buffer")
} else {
self.flutterTextureId = registry.register(self)
}
}
public func copyPixelBuffer() -> Unmanaged<CVPixelBuffer>? {
return Unmanaged.passRetained(pixelBuffer!);
}
public func onTextureUnregistered(_ texture:FlutterTexture) {
print("Texture unregistered")
}
public func destroy() {
if(self.flutterTextureId != -1) {
self.registry!.unregisterTexture(self.flutterTextureId)
}
self.pixelBuffer = nil
}
}

View File

@@ -0,0 +1,10 @@
#include "ResourceBuffer.h"
ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner)
{
ResourceLoaderWrapper *rlw = (ResourceLoaderWrapper *)malloc(sizeof(ResourceLoaderWrapper));
rlw->loadFromOwner = loadFn;
rlw->freeFromOwner = freeFn;
rlw->owner = owner;
return rlw;
}

View File

@@ -2,23 +2,14 @@ import Flutter
import UIKit import UIKit
import GLKit import GLKit
public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture { public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin {
var registrar : FlutterPluginRegistrar var registrar : FlutterPluginRegistrar
var flutterTextureId: Int64?
var registry: FlutterTextureRegistry var registry: FlutterTextureRegistry
var texture: FlutterFilamentTexture?
var pixelBuffer: CVPixelBuffer?;
var createdAt = Date() var createdAt = Date()
var pixelBufferAttrs = [
kCVPixelBufferPixelFormatTypeKey: NSNumber(value: kCVPixelFormatType_32BGRA),
kCVPixelBufferOpenGLCompatibilityKey: kCFBooleanTrue,
kCVPixelBufferOpenGLESCompatibilityKey: kCFBooleanTrue,
kCVPixelBufferIOSurfacePropertiesKey: [:]
] as CFDictionary
var resources:NSMutableDictionary = [:] var resources:NSMutableDictionary = [:]
static var messenger : FlutterBinaryMessenger? = nil; static var messenger : FlutterBinaryMessenger? = nil;
@@ -127,19 +118,11 @@ public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture
var markTextureFrameAvailable : @convention(c) (UnsafeMutableRawPointer?) -> () = { instancePtr in var markTextureFrameAvailable : @convention(c) (UnsafeMutableRawPointer?) -> () = { instancePtr in
let instance:SwiftFlutterFilamentPlugin = Unmanaged<SwiftFlutterFilamentPlugin>.fromOpaque(instancePtr!).takeUnretainedValue() let instance:SwiftFlutterFilamentPlugin = Unmanaged<SwiftFlutterFilamentPlugin>.fromOpaque(instancePtr!).takeUnretainedValue()
instance.registry.textureFrameAvailable(instance.flutterTextureId!) if(instance.texture != nil) {
} instance.registry.textureFrameAvailable(instance.texture!.flutterTextureId)
public func copyPixelBuffer() -> Unmanaged<CVPixelBuffer>? {
if(pixelBuffer == nil) {
return nil;
} }
return Unmanaged.passRetained(pixelBuffer!);
}
public func onTextureUnregistered(_ texture:FlutterTexture) {
print("Texture unregistered")
} }
public static func register(with registrar: FlutterPluginRegistrar) { public static func register(with registrar: FlutterPluginRegistrar) {
let _messenger = registrar.messenger(); let _messenger = registrar.messenger();
@@ -153,15 +136,6 @@ public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture
self.registry = textureRegistry; self.registry = textureRegistry;
self.registrar = registrar self.registrar = registrar
} }
private func createPixelBuffer(width:Int, height:Int) {
if(CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height),
kCVPixelFormatType_32BGRA, pixelBufferAttrs, &pixelBuffer) != kCVReturnSuccess) {
print("Error allocating pixel buffer")
}
self.flutterTextureId = self.registry.register(self)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let methodName = call.method; let methodName = call.method;
@@ -173,20 +147,25 @@ public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture
let renderCallback = markTextureFrameAvailable let renderCallback = markTextureFrameAvailable
result([ result([
unsafeBitCast(renderCallback, to:Int64.self), unsafeBitCast(Unmanaged.passUnretained(self), to:UInt64.self)]) unsafeBitCast(renderCallback, to:Int64.self), unsafeBitCast(Unmanaged.passUnretained(self), to:UInt64.self)])
case "getDriverPlatfrom": case "getDriverPlatform":
result(nil)
case "getSharedContext":
result(nil) result(nil)
case "createTexture": case "createTexture":
let args = call.arguments as! Array<Int32> let args = call.arguments as! [Any]
createPixelBuffer(width:Int(args[0]), height:Int(args[1])) let width = args[0] as! Int64
let pixelBufferPtr = unsafeBitCast(pixelBuffer!, to:UnsafeRawPointer.self) let height = args[1] as! Int64
self.texture = FlutterFilamentTexture(width: width, height: height, registry: registry)
let pixelBufferPtr = unsafeBitCast(self.texture!.pixelBuffer, to:UnsafeRawPointer.self)
let pixelBufferAddress = Int(bitPattern:pixelBufferPtr); let pixelBufferAddress = Int(bitPattern:pixelBufferPtr);
result([self.flutterTextureId, pixelBufferAddress, nil, nil])
result([self.texture!.flutterTextureId as Any, nil, pixelBufferAddress])
case "destroyTexture": case "destroyTexture":
if(self.flutterTextureId != nil) { let texture = self.texture
self.registry.unregisterTexture(self.flutterTextureId!) self.texture = nil
} texture?.destroy()
self.flutterTextureId = nil
self.pixelBuffer = nil
result(true) result(true)
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)

View File

@@ -13,33 +13,21 @@ A new flutter plugin project.
s.license = { :file => '../LICENSE' } s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' } s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' } s.source = { :path => '.' }
s.source_files = 'Classes/*', 'src/*', "src/camutils/*", 'src/ios/*', 'include/filament/*', 'include/*', 'include/material/*.c' s.source_files = 'Classes/*', 'include/SwiftFlutterFilamentPlugin-Bridging-Header.h', 'include/ResourceBuffer.h'
s.public_header_files = 'include/SwiftFlutterFilamentPlugin-Bridging-Header.h', 'include/FlutterFilamentApi.h', 'include/FlutterFilamentFFIApi.h', 'include/ResourceBuffer.hpp', 'include/Log.hpp' s.public_header_files = 'include/SwiftFlutterFilamentPlugin-Bridging-Header.h', 'include/ResourceBuffer.h'
s.dependency 'Flutter' s.dependency 'Flutter'
s.platform = :ios, '13.0' s.platform = :ios, '13.0'
s.static_framework = true s.static_framework = true
s.vendored_libraries = "lib/*.a"
s.user_target_xcconfig = { s.user_target_xcconfig = {
'DEFINES_MODULE' => 'YES', 'DEFINES_MODULE' => 'YES',
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17", "CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
'OTHER_CFLAGS' => '"-fvisibility=default" "$(inherited)"', 'OTHER_CFLAGS' => '"-fvisibility=default" "$(inherited)"',
'USER_HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/include" "${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/include/filament" "${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/src" "${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/src/image" "${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/src/shaders" "$(inherited)"',
'ALWAYS_SEARCH_USER_PATHS' => 'YES',
"OTHER_LDFLAGS" => '-lfilament -lbackend -lfilameshio -lviewer -lfilamat -lgeometry -lutils -lfilabridge -lgltfio_core -lfilament-iblprefilter -limage -limageio -ltinyexr -lgltfio_core -lfilaflat -ldracodec -libl -lktxreader -lpng -lpng16 -lz -lstb -luberzlib -lsmol-v -luberarchive -lzstd -lstdc++',
'LIBRARY_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/lib" "$(inherited)"',
} }
s.pod_target_xcconfig = { s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES', 'DEFINES_MODULE' => 'YES',
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
'OTHER_CXXFLAGS' => '"--std=c++17" "-fmodules" "-fcxx-modules" "-fvisibility=default" "$(inherited)"',
'OTHER_CFLAGS' => '"-fvisibility=default" "$(inherited)"',
'USER_HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/include" "${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/include/filament" "${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/src" "${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/src/image" "${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/src/shaders" "$(inherited)"',
'ALWAYS_SEARCH_USER_PATHS' => 'YES',
"OTHER_LDFLAGS" => '-lfilament -lbackend -lfilameshio -lviewer -lfilamat -lgeometry -lutils -lfilabridge -lgltfio_core -lfilament-iblprefilter -limage -limageio -ltinyexr -lgltfio_core -lfilaflat -ldracodec -libl -lktxreader -lpng -lpng16 -lz -lstb -luberzlib -lsmol-v -luberarchive -lzstd -lstdc++',
'LIBRARY_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/flutter_filament/ios/lib" "$(inherited)"',
} }
s.swift_version = '5.0' s.swift_version = '5.0'

View File

@@ -0,0 +1 @@
../../../dart_filament/native/include/ResourceBuffer.h

View File

@@ -0,0 +1 @@
../../../dart_filament/native/include/ResourceBuffer.h

View File

@@ -0,0 +1,6 @@
#ifndef SwiftFlutterFilamentPlugin_Bridging_Header_h
#define SwiftFlutterFilamentPlugin_Bridging_Header_h
#include "ResourceBuffer.h"
#endif

View File

@@ -10,14 +10,12 @@ import 'package:flutter_filament/filament/flutter_filament_texture.dart';
/// A subclass of [FilamentViewer] that uses Flutter platform channels /// A subclass of [FilamentViewer] that uses Flutter platform channels
/// to create rendering contexts, callbacks and surfaces (either backing texture(s). /// to create rendering contexts, callbacks and surfaces (either backing texture(s).
/// ///
///
class FlutterFilamentPlugin extends FilamentViewer { class FlutterFilamentPlugin extends FilamentViewer {
final MethodChannel _channel; final MethodChannel _channel;
FlutterFilamentPlugin._(this._channel, FlutterFilamentPlugin._(this._channel,
{super.renderCallback, {super.renderCallback,
super.renderCallbackOwner, super.renderCallbackOwner,
super.surface,
required super.resourceLoader, required super.resourceLoader,
super.driver, super.driver,
super.sharedContext, super.sharedContext,
@@ -50,14 +48,9 @@ class FlutterFilamentPlugin extends FilamentViewer {
? nullptr ? nullptr
: Pointer<Void>.fromAddress(sharedContext); : Pointer<Void>.fromAddress(sharedContext);
var window = await channel.invokeMethod("getWindow");
var windowPtr =
window == null ? nullptr : Pointer<Void>.fromAddress(window);
return FlutterFilamentPlugin._(channel, return FlutterFilamentPlugin._(channel,
renderCallback: renderCallback, renderCallback: renderCallback,
renderCallbackOwner: renderCallbackOwner, renderCallbackOwner: renderCallbackOwner,
surface: windowPtr,
resourceLoader: resourceLoader, resourceLoader: resourceLoader,
driver: driverPtr, driver: driverPtr,
sharedContext: sharedContextPtr, sharedContext: sharedContextPtr,
@@ -69,14 +62,22 @@ class FlutterFilamentPlugin extends FilamentViewer {
var result = await _channel var result = await _channel
.invokeMethod("createTexture", [width, height, offsetLeft, offsetLeft]); .invokeMethod("createTexture", [width, height, offsetLeft, offsetLeft]);
if (result == null) { if (result == null) {
return null; throw Exception("Failed to create texture");
} }
viewportDimensions = (width.toDouble(), height.toDouble()); viewportDimensions = (width.toDouble(), height.toDouble());
var texture = FlutterFilamentTexture(result[0], result[1], width, height); var texture =
await createSwapChain(width.toDouble(), height.toDouble()); FlutterFilamentTexture(result[0], result[1], width, height, result[2]);
var renderTarget = await createRenderTarget( await createSwapChain(width.toDouble(), height.toDouble(),
width.toDouble(), height.toDouble(), texture.hardwareTextureId); surface: texture.surface);
if (texture.hardwareTextureId != null) {
var renderTarget = await createRenderTarget(
width.toDouble(), height.toDouble(), texture.hardwareTextureId!);
}
await updateViewportAndCameraProjection(
width.toDouble(), height.toDouble());
this.render();
return texture; return texture;
} }
@@ -85,19 +86,35 @@ class FlutterFilamentPlugin extends FilamentViewer {
} }
@override @override
Future resizeTexture(FlutterFilamentTexture texture, int width, int height, Future<FlutterFilamentTexture?> resizeTexture(FlutterFilamentTexture texture,
int offsetLeft, int offsetRight) async { int width, int height, int offsetLeft, int offsetRight) async {
if ((width - viewportDimensions.$1).abs() < 0.001 ||
(height - viewportDimensions.$2).abs() < 0.001) {
return texture;
}
bool wasRendering = rendering;
await setRendering(false);
await destroySwapChain(); await destroySwapChain();
await destroyTexture(texture); await destroyTexture(texture);
await createSwapChain(width.toDouble(), height.toDouble());
var newTexture = var newTexture =
await createTexture(width, height, offsetLeft, offsetRight); await createTexture(width, height, offsetLeft, offsetRight);
await createRenderTarget( if (newTexture == null) {
width.toDouble(), height.toDouble(), newTexture!.hardwareTextureId); throw Exception("Failed to create texture");
}
await createSwapChain(width.toDouble(), height.toDouble(),
surface: newTexture.surface!);
if (newTexture!.hardwareTextureId != null) {
await createRenderTarget(
width.toDouble(), height.toDouble(), newTexture!.hardwareTextureId!);
}
await updateViewportAndCameraProjection( await updateViewportAndCameraProjection(
width.toDouble(), height.toDouble()); width.toDouble(), height.toDouble());
viewportDimensions = (width.toDouble(), height.toDouble()); viewportDimensions = (width.toDouble(), height.toDouble());
if (wasRendering) {
await setRendering(true);
}
return newTexture; return newTexture;
// await _channel.invokeMethod("resizeTexture", // await _channel.invokeMethod("resizeTexture",
// [texture.flutterTextureId, width, height, offsetLeft, offsetRight]); // [texture.flutterTextureId, width, height, offsetLeft, offsetRight]);

View File

@@ -1,9 +1,16 @@
import 'dart:ffi';
class FlutterFilamentTexture { class FlutterFilamentTexture {
final int width; final int width;
final int height; final int height;
final int flutterTextureId; final int flutterTextureId;
final int hardwareTextureId; final int? hardwareTextureId;
Pointer<Void>? surface;
FlutterFilamentTexture( FlutterFilamentTexture(this.flutterTextureId, this.hardwareTextureId,
this.flutterTextureId, this.hardwareTextureId, this.width, this.height); this.width, this.height, int? surfaceAddress) {
if (surfaceAddress != null) {
surface = Pointer<Void>.fromAddress(surfaceAddress!);
}
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,15 @@
import Foundation import Foundation
import Foundation
import GLKit import GLKit
@objc public class DartFilamentTexture : NSObject { @objc public class DartFilamentTexture : NSObject {
var pixelBuffer: CVPixelBuffer? public var pixelBuffer: CVPixelBuffer?
var pixelBufferAttrs = [ var pixelBufferAttrs = [
kCVPixelBufferPixelFormatTypeKey: NSNumber(value: kCVPixelFormatType_32ABGR ), kCVPixelBufferPixelFormatTypeKey: NSNumber(value: kCVPixelFormatType_32ABGR ),
// kCVPixelBufferOpenGLCompatibilityKey: kCFBooleanTrue!, kCVPixelBufferOpenGLCompatibilityKey: kCFBooleanFalse!,
kCVPixelBufferIOSurfacePropertiesKey: [:] as CFDictionary // kCVPixelBufferIOSurfacePropertiesKey: [Any:Any] as CFDictionary
] as CFDictionary ] as [CFString : Any] as CFDictionary
@objc public var cvMetalTextureCache:CVMetalTextureCache? @objc public var cvMetalTextureCache:CVMetalTextureCache?
@objc public var cvMetalTexture:CVMetalTexture? @objc public var cvMetalTexture:CVMetalTexture?
@@ -19,7 +18,7 @@ import GLKit
@objc public var metalTextureAddress:Int = -1 @objc public var metalTextureAddress:Int = -1
@objc override public init() { @objc override public init() {
print("VAnilla init")
} }
@objc public init(width:Int64, height:Int64) { @objc public init(width:Int64, height:Int64) {

View File

@@ -0,0 +1,33 @@
import Foundation
import GLKit
import FlutterMacOS
public class FlutterFilamentTexture : NSObject, FlutterTexture {
var texture:DartFilamentTexture
var flutterTextureId: Int64 = -1
var registry: FlutterTextureRegistry
init(registry:FlutterTextureRegistry, texture:DartFilamentTexture) {
self.texture = texture
self.registry = registry
super.init()
self.flutterTextureId = registry.register(self)
}
public func copyPixelBuffer() -> Unmanaged<CVPixelBuffer>? {
return Unmanaged.passRetained(texture.pixelBuffer!);
}
public func onTextureUnregistered(_ texture:FlutterTexture) {
print("Texture unregistered")
}
public func destroy() {
self.registry.unregisterTexture(self.flutterTextureId)
self.texture.destroyTexture()
}
}

View File

@@ -1,36 +1,6 @@
import FlutterMacOS import FlutterMacOS
import GLKit import GLKit
public class FlutterFilamentTexture : NSObject, FlutterTexture {
var texture:DartFilamentTexture
var flutterTextureId: Int64 = -1
var registry: FlutterTextureRegistry
init(registry:FlutterTextureRegistry, texture:DartFilamentTexture) {
self.texture = texture
self.registry = registry
super.init()
self.flutterTextureId = registry.register(self)
}
public func copyPixelBuffer() -> Unmanaged<CVPixelBuffer>? {
return Unmanaged.passRetained(texture.pixelBuffer!);
}
public func onTextureUnregistered(_ texture:FlutterTexture) {
print("Texture unregistered")
}
public func destroy() {
self.registry.unregisterTexture(self.flutterTextureId)
self.texture.destroyTexture()
}
}
public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin { public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin {
var registrar : FlutterPluginRegistrar var registrar : FlutterPluginRegistrar
@@ -121,8 +91,6 @@ public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin {
result(nil) result(nil)
case "getSharedContext": case "getSharedContext":
result(nil) result(nil)
case "getWindow":
result(nil)
case "createTexture": case "createTexture":
let args = call.arguments as! [Any] let args = call.arguments as! [Any]
let width = args[0] as! Int64 let width = args[0] as! Int64
@@ -131,7 +99,7 @@ public class SwiftFlutterFilamentPlugin: NSObject, FlutterPlugin {
let texture = DartFilamentTexture(width: width, height: height) let texture = DartFilamentTexture(width: width, height: height)
self.texture = FlutterFilamentTexture(registry: registry, texture: texture) self.texture = FlutterFilamentTexture(registry: registry, texture: texture)
result([self.texture!.flutterTextureId as Any, texture.metalTextureAddress]) result([self.texture!.flutterTextureId as Any, texture.metalTextureAddress, nil])
case "destroyTexture": case "destroyTexture":
self.texture?.destroy() self.texture?.destroy()
self.texture = nil self.texture = nil

View File

@@ -0,0 +1,117 @@
#ifndef RESOURCE_BUFFER_H
#define RESOURCE_BUFFER_H
#include <stdint.h>
#include <stdlib.h>
//
// A ResourceBuffer is a unified interface for working with
// binary assets across various platforms.
// This is simply:
// 1) a pointer to some data
// 2) the length of the data
// 3) an ID that can be passed back to the native platform to release the underlying asset when needed.
//
struct ResourceBuffer
{
const void *const data;
const int32_t size;
const int32_t id;
};
typedef struct ResourceBuffer ResourceBuffer;
typedef ResourceBuffer (*LoadFilamentResource)(const char *uri);
typedef ResourceBuffer (*LoadFilamentResourceFromOwner)(const char *const, void *const owner);
typedef void (*FreeFilamentResource)(ResourceBuffer);
typedef void (*FreeFilamentResourceFromOwner)(ResourceBuffer, void *const owner);
struct ResourceLoaderWrapper
{
LoadFilamentResource loadResource;
FreeFilamentResource freeResource;
LoadFilamentResourceFromOwner loadFromOwner;
FreeFilamentResourceFromOwner freeFromOwner;
void *owner;
};
typedef struct ResourceLoaderWrapper ResourceLoaderWrapper;
#if defined(__cplusplus)
namespace flutter_filament {
// struct ResourceBufferImpl : public ResourceBuffer
// {
// ResourceBufferImpl(const void *const mData, const int32_t mSize, const int32_t mId)
// {
// data = mData;
// size = mSize;
// id = mId;
// };
// ResourceBufferImpl(const ResourceBufferImpl &rb)
// {
// (void *)data = rb.data;
// size = rb.size;
// id = rb.id;
// };
// ResourceBufferImpl(const ResourceBufferImpl &&rb) noexcept
// {
// data = rb.data;
// size = rb.size;
// id = rb.id;
// };
// ResourceBufferImpl &operator=(const ResourceBufferImpl &other) = delete;
// };
struct ResourceLoaderWrapperImpl : public ResourceLoaderWrapper
{
ResourceLoaderWrapperImpl(LoadFilamentResource loader, FreeFilamentResource freeResource)
{
loadFromOwner = nullptr;
freeFromOwner = nullptr;
loadResource = loader;
freeResource = freeResource;
owner = nullptr;
}
ResourceLoaderWrapperImpl(LoadFilamentResourceFromOwner loader, FreeFilamentResourceFromOwner freeResource, void * owner)
{
loadResource = nullptr;
freeResource = nullptr;
loadFromOwner = loader;
freeFromOwner = freeResource;
owner = owner;
}
ResourceBuffer load(const char *uri) const
{
if (loadFromOwner)
{
auto rb = loadFromOwner(uri, owner);
return rb;
}
auto rb = loadResource(uri);
return rb;
}
void free(ResourceBuffer rb) const
{
if (freeFromOwner)
{
freeFromOwner(rb, owner);
}
else
{
freeResource(rb);
}
}
};
}
#endif
#endif

View File

@@ -0,0 +1,17 @@
#ifndef SwiftFlutterFilamentPlugin_Bridging_Header_h
#define SwiftFlutterFilamentPlugin_Bridging_Header_h
#include <stdint.h>
#include "ResourceBuffer.hpp"
ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner)
{
ResourceLoaderWrapper *rlw = (ResourceLoaderWrapper *)malloc(sizeof(ResourceLoaderWrapper));
rlw->loadFromOwner = loadFn;
rlw->freeFromOwner = freeFn;
rlw->owner = owner;
return rlw;
}
#endif