renaming to Thermion

This commit is contained in:
Nick Fisher
2024-06-15 15:05:34 +08:00
parent 1a5f573bc0
commit fe62a70e29
719 changed files with 7291 additions and 3946 deletions

View File

@@ -0,0 +1,115 @@
import FlutterMacOS
import GLKit
public class SwiftThermionFlutterPlugin: NSObject, FlutterPlugin {
var registrar : FlutterPluginRegistrar
var registry: FlutterTextureRegistry
var texture: ThermionFlutterTexture?
var createdAt = Date()
var resources:[UInt32:NSData] = [:]
static var messenger : FlutterBinaryMessenger? = nil;
var loadResource : @convention(c) (UnsafePointer<Int8>?, UnsafeMutableRawPointer?) -> ResourceBuffer = { uri, resourcesPtr in
let instance:SwiftThermionFlutterPlugin = Unmanaged<SwiftThermionFlutterPlugin>.fromOpaque(resourcesPtr!).takeUnretainedValue()
var uriString = String(cString:uri!)
var path:String? = nil
print("Received request to load \(uriString)")
if(uriString.hasPrefix("file://")) {
path = String(uriString.dropFirst(7))
} else {
if(uriString.hasPrefix("asset://")) {
uriString = String(uriString.dropFirst(8))
}
let bundle = Bundle.init(identifier: "io.flutter.flutter.app")!
path = bundle.path(forResource:uriString, ofType: nil, inDirectory: "flutter_assets")
}
if(path != nil) {
do {
let data = try Data(contentsOf: URL(fileURLWithPath:path!))
let nsData = data as NSData
let resId = UInt32(instance.resources.count)
instance.resources[resId] = nsData
let length = nsData.length
print("Resolved asset to file of length \(Int32(length)) at path \(path!)")
return ResourceBuffer(data:nsData.bytes, size:Int32(UInt32(nsData.length)), id:Int32(UInt32(resId)))
} catch {
print("ERROR LOADING RESOURCE")
}
}
return ResourceBuffer()
}
var freeResource : @convention(c) (ResourceBuffer,UnsafeMutableRawPointer?) -> () = { rbuf, resourcesPtr in
let instance:SwiftThermionFlutterPlugin = Unmanaged<SwiftThermionFlutterPlugin>.fromOpaque(resourcesPtr!).takeUnretainedValue()
instance.resources.removeValue(forKey:UInt32(rbuf.id))
}
var markTextureFrameAvailable : @convention(c) (UnsafeMutableRawPointer?) -> () = { instancePtr in
let instance:SwiftThermionFlutterPlugin = Unmanaged<SwiftThermionFlutterPlugin>.fromOpaque(instancePtr!).takeUnretainedValue()
if(instance.texture != nil) {
instance.registry.textureFrameAvailable(instance.texture!.flutterTextureId)
}
}
public static func register(with registrar: FlutterPluginRegistrar) {
let _messenger = registrar.messenger;
messenger = _messenger;
let channel = FlutterMethodChannel(name: "app.polyvox.filament/event", binaryMessenger: _messenger)
let instance = SwiftThermionFlutterPlugin(textureRegistry: registrar.textures, registrar:registrar)
registrar.addMethodCallDelegate(instance, channel: channel)
}
init(textureRegistry: FlutterTextureRegistry, registrar:FlutterPluginRegistrar) {
self.registry = textureRegistry;
self.registrar = registrar
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let methodName = call.method;
switch methodName {
case "getResourceLoaderWrapper":
var resourceLoaderWrapper = make_resource_loader(loadResource, freeResource, Unmanaged.passUnretained(self).toOpaque())
result(unsafeBitCast(resourceLoaderWrapper, to:Int64.self))
case "getRenderCallback":
let renderCallback = markTextureFrameAvailable
let resultArray:[Any] = [
unsafeBitCast(renderCallback, to:Int64.self), unsafeBitCast(Unmanaged.passUnretained(self), to:UInt64.self)]
result(resultArray)
case "getDriverPlatform":
result(nil)
case "getSharedContext":
result(nil)
case "createTexture":
let args = call.arguments as! [Any]
let width = args[0] as! Int64
let height = args[1] as! Int64
self.texture = ThermionFlutterTexture(registry: registry, width: width, height: height)
if(self.texture?.metalTextureAddress == -1) {
result(nil)
} else {
result([self.texture!.flutterTextureId as Any, self.texture?.metalTextureAddress, nil])
}
case "destroyTexture":
self.texture?.destroy()
self.texture = nil
result(true)
default:
result(FlutterMethodNotImplemented)
}
}
}

View File

@@ -0,0 +1,102 @@
import Foundation
import GLKit
@objc public class ThermionDartTexture : NSObject {
public var pixelBuffer: CVPixelBuffer?
var pixelBufferAttrs = [
kCVPixelBufferPixelFormatTypeKey: NSNumber(value: kCVPixelFormatType_32ABGR ),
kCVPixelBufferIOSurfacePropertiesKey: [:] as CFDictionary
] as [CFString : Any] as CFDictionary
@objc public var cvMetalTextureCache:CVMetalTextureCache?
@objc public var cvMetalTexture:CVMetalTexture?
@objc public var metalTexture:MTLTexture?
@objc public var metalDevice:MTLDevice?
@objc public var metalTextureAddress:Int = -1
@objc override public init() {
}
@objc public init(width:Int64, height:Int64) {
self.metalDevice = MTLCreateSystemDefaultDevice()!
// create pixel buffer
if(CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height),
kCVPixelFormatType_32BGRA, pixelBufferAttrs, &pixelBuffer) != kCVReturnSuccess) {
print("Error allocating pixel buffer")
metalTextureAddress = -1;
return
}
var cvret = CVMetalTextureCacheCreate(
kCFAllocatorDefault,
nil,
metalDevice!,
nil,
&cvMetalTextureCache);
if(cvret != 0) {
print("Error creating Metal texture cache")
metalTextureAddress = -1
return
}
cvret = CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault,
cvMetalTextureCache!,
pixelBuffer!, nil,
MTLPixelFormat.bgra8Unorm,
Int(width), Int(height),
0,
&cvMetalTexture)
if(cvret != 0) {
print("Error creating texture from image")
metalTextureAddress = -1
return
}
metalTexture = CVMetalTextureGetTexture(cvMetalTexture!)
let metalTexturePtr = Unmanaged.passUnretained(metalTexture!).toOpaque()
metalTextureAddress = Int(bitPattern:metalTexturePtr)
print("Created metal texture @ \(metalTextureAddress)")
// CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
// let bufferWidth = Int(CVPixelBufferGetWidth(pixelBuffer!))
// let bufferHeight = Int(CVPixelBufferGetHeight(pixelBuffer!))
// let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer!)
// guard let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer!) else {
// return
// }
// for row in 0..<bufferHeight {
// var pixel = baseAddress + row * bytesPerRow
// for col in 0..<bufferWidth {
// let blue = pixel
// blue.storeBytes(of: 255, as: UInt8.self)
// let red = pixel + 1
// red.storeBytes(of: 0, as: UInt8.self)
// let green = pixel + 2
// green.storeBytes(of: 0, as: UInt8.self)
// let alpha = pixel + 3
// alpha.storeBytes(of: 255, as: UInt8.self)
// pixel += 4;
// }
// }
// CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
}
@objc public func destroyTexture() {
metalTexture = nil
}
}

View File

@@ -0,0 +1,30 @@
import Foundation
import GLKit
import FlutterMacOS
public class ThermionFlutterTexture : ThermionDartTexture, FlutterTexture {
var flutterTextureId: Int64 = -1
var registry: FlutterTextureRegistry
init(registry:FlutterTextureRegistry, width:Int64, height:Int64) {
self.registry = registry
super.init(width:width, height:height)
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() {
self.registry.unregisterTexture(self.flutterTextureId)
self.destroyTexture()
}
}

View File

@@ -0,0 +1,91 @@
#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 thermion_flutter {
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 SwiftThermionFlutterPlugin_Bridging_Header_h
#define SwiftThermionFlutterPlugin_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

View File

@@ -0,0 +1,28 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint thermion_flutter.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'thermion_flutter'
s.version = '0.0.1'
s.summary = 'A new Flutter plugin project.'
s.description = <<-DESC
A new Flutter plugin project.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/*', 'include/ResourceBuffer.hpp','include/SwiftThermionFlutterPlugin-Bridging-Header.h'
s.public_header_files = 'include/SwiftThermionFlutterPlugin-Bridging-Header.h', 'include/ResourceBuffer.hpp'
s.dependency 'FlutterMacOS'
s.platform = :osx, '13'
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'OTHER_CFLAGS' => '"-fvisibility=default" "$(inherited)"',
}
s.swift_version = '5.0'
end