diff --git a/app/xcode/Sources/VCamEntity/Notification+.swift b/app/xcode/Sources/VCamEntity/Notification+.swift index b06a2db..aa6b20f 100644 --- a/app/xcode/Sources/VCamEntity/Notification+.swift +++ b/app/xcode/Sources/VCamEntity/Notification+.swift @@ -8,7 +8,6 @@ import Foundation public extension Notification.Name { - static let reloadUI = Notification.Name("vcam.reloadUI") static let showEmojiPicker = Notification.Name("vcam.showEmojiPicker") static let deviceWasChanged = Notification.Name("vcam.deviceWasChanged") static let unfocusObject = Notification.Name("vcam.unfocusObject") diff --git a/app/xcode/Sources/VCamUI/Extensions/UniBridge+.swift b/app/xcode/Sources/VCamUI/Extensions/UniBridge+.swift index f1b28d7..d708c39 100644 --- a/app/xcode/Sources/VCamUI/Extensions/UniBridge+.swift +++ b/app/xcode/Sources/VCamUI/Extensions/UniBridge+.swift @@ -10,29 +10,6 @@ import VCamEntity import SwiftUI import VCamBridge -extension UniState { - public init(_ state: CustomState) { - get = state.get - set = state.set - name = state.name - reloadThrottle = state.reloadThrottle - } - - public struct CustomState { - public init(get: @escaping () -> Value, set: @escaping (Value) -> Void, name: String = "", reloadThrottle: Bool = false) { - self.get = get - self.set = set - self.name = name - self.reloadThrottle = reloadThrottle - } - - public var get: () -> Value - public var set: (Value) -> Void - public var name = "" - public var reloadThrottle = false - } -} - extension UniBridge { public var canvasCGSize: CGSize { let size = canvasSize diff --git a/app/xcode/Sources/VCamUI/Extensions/UniSet.swift b/app/xcode/Sources/VCamUI/Extensions/UniSet.swift deleted file mode 100644 index 26c7eec..0000000 --- a/app/xcode/Sources/VCamUI/Extensions/UniSet.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// UniSet.swift -// -// -// Created by Tatsuya Tanaka on 2023/03/01. -// - -import SwiftUI -import VCamEntity -import VCamBridge - -@propertyWrapper public struct UniSet: DynamicProperty { - public init(_ type: UniBridge.BoolType, name: String) where Value == Bool { - let mapper = UniBridge.shared.boolMapper - self.set = mapper.set(type) - self.name = name - } - - private let set: (Value) -> Void - private var name = "" - - public var wrappedValue: Action { - .init(set: set) - } - - public struct Action { - let set: (T) -> Void - - public func callAsFunction(_ value: T) { - set(value) - } - } -} diff --git a/app/xcode/Sources/VCamUI/MacWindowManager.swift b/app/xcode/Sources/VCamUI/MacWindowManager.swift index b348106..9e277cf 100644 --- a/app/xcode/Sources/VCamUI/MacWindowManager.swift +++ b/app/xcode/Sources/VCamUI/MacWindowManager.swift @@ -47,6 +47,8 @@ public final class MacWindowManager { private var openWindows: [String: NSWindow] = [:] + public var openCredits: () -> Void = {} + public func open(_ windowView: T) { let id = self.id(T.self) if let window = openWindows[id] { diff --git a/app/xcode/Sources/VCamUI/Shortcut/Action/VCamMessageAction.swift b/app/xcode/Sources/VCamUI/Shortcut/Action/VCamMessageAction.swift index 4c9a167..c769ca4 100644 --- a/app/xcode/Sources/VCamUI/Shortcut/Action/VCamMessageAction.swift +++ b/app/xcode/Sources/VCamUI/Shortcut/Action/VCamMessageAction.swift @@ -8,6 +8,7 @@ import AppKit import VCamEntity import VCamLocalization +import VCamBridge import struct SwiftUI.Image public struct VCamMessageAction: VCamAction { @@ -19,10 +20,8 @@ public struct VCamMessageAction: VCamAction { public var name: String { L10n.message.text } public var icon: Image { Image(systemName: "text.bubble") } - @UniState(.message, name: "message") private var message - @MainActor public func callAsFunction(context: VCamActionContext) async throws { - message = configuration.message + UniBridge.shared.message.wrappedValue = configuration.message } } diff --git a/app/xcode/Sources/VCamUI/UniState.swift b/app/xcode/Sources/VCamUI/UniState.swift deleted file mode 100644 index 743f8d8..0000000 --- a/app/xcode/Sources/VCamUI/UniState.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// UniState.swift -// -// -// Created by Tatsuya Tanaka on 2023/04/02. -// - -import SwiftUI -import VCamEntity -import VCamBridge - -@propertyWrapper @dynamicMemberLookup public struct UniState: DynamicProperty { - let get: () -> Value - let set: (Value) -> Void - var name = "" - var reloadThrottle = false - - @UniReload private var reload: Void - - public var wrappedValue: Value { - get { - get() - } - nonmutating set { - set(newValue) - InternalUniState.reload(name, reloadThrottle) - } - } - - public var projectedValue: Binding { - .init(get: { wrappedValue }, set: { wrappedValue = $0 }) - } - - public subscript(dynamicMember keyPath: ReferenceWritableKeyPath) -> Binding { - get { - .init(get: { wrappedValue[keyPath: keyPath] }, set: { wrappedValue[keyPath: keyPath] = $0 }) - } - set { - wrappedValue[keyPath: keyPath] = newValue.wrappedValue - } - } -} - -public extension UniState { - init(binding: Binding) { - self.init(get: { binding.wrappedValue }, set: { binding.wrappedValue = $0 }) - } - - init(_ type: UniBridge.BoolType, name: String, reloadThrottle: Bool = false) where Value == Bool { - let mapper = UniBridge.shared.boolMapper - self.init(get: { mapper.get(type) }, set: mapper.set(type), name: name, reloadThrottle: reloadThrottle) - } - - init(_ type: UniBridge.FloatType, name: String, reloadThrottle: Bool = false) where Value == CGFloat { - let mapper = UniBridge.shared.floatMapper - self.init(get: { mapper.get(type) }, set: mapper.set(type), name: name, reloadThrottle: reloadThrottle) - } - - init(_ type: UniBridge.IntType, name: String, reloadThrottle: Bool = false) where Value == Int32 { - let mapper = UniBridge.shared.intMapper - self.init(get: { mapper.get(type) }, set: mapper.set(type), name: name, reloadThrottle: reloadThrottle) - } - - init(_ type: UniBridge.StringType, name: String, reloadThrottle: Bool = false) where Value == String { - let mapper = UniBridge.shared.stringMapper - self.init(get: { mapper.get(type) }, set: mapper.set(type), name: name, reloadThrottle: reloadThrottle) - } - - init(_ type: UniBridge.ArrayType, name: String, as: Array.Type, reloadThrottle: Bool = false) where Value == Array { - let mapper = UniBridge.shared.arrayMapper - self.init(get: { mapper.binding(type, size: type.arraySize).wrappedValue }, set: mapper.set(type), name: name, reloadThrottle: reloadThrottle) - } - - init(_ type: UniBridge.StructType, name: String, as: Value.Type = Value.self, reloadThrottle: Bool = false) where Value: ValueBindingStructType { - let mapper = UniBridge.shared.structMapper - self.init(get: { mapper.binding(type).wrappedValue }, set: { mapper.binding(type).wrappedValue = $0 }, name: name, reloadThrottle: reloadThrottle) - } -} - -public enum InternalUniState { - public static var reload: (String, Bool) -> Void = { _, _ in } -} diff --git a/app/xcode/Sources/VCamUI/UnityCallback.swift b/app/xcode/Sources/VCamUI/UnityCallback.swift new file mode 100644 index 0000000..cb2894b --- /dev/null +++ b/app/xcode/Sources/VCamUI/UnityCallback.swift @@ -0,0 +1,112 @@ +// +// UnityCallback.swift +// +// +// Created by Tatsuya Tanaka on 2023/01/21. +// + +import Foundation +import VCamData +import VCamBridge +import VCamCamera +import VCamTracking +import VCamLogger + +@_cdecl("uniOnVCamSystemStart") +public func uniOnVCamSystemStart() { + Logger.log("uniOnVCamSystemStart") + WindowManager.shared.system.isUniVCamSystemEnabled = true + WindowManager.shared.system.startSystem() + UniReload.Reloader.shared.objectWillChange.send() +} + +@_cdecl("uniOnVCamSystemDestroy") +public func uniOnVCamSystemDestroy() { + Logger.log("uniOnVCamSystemDestroy") + WindowManager.shared.system.isUniVCamSystemEnabled = false + UniReload.Reloader.shared.objectWillChange.send() +} + +@_cdecl("uniOnApplyCaptureSystem") +public func uniOnApplyCaptureSystem() { + UniBridge.shared.useFullTracking(UserDefaults.standard.value(for: .integrationMocopi)) + Tracking.shared.updateLipSyncIfNeeded() + + UniBridge.cachedBlendShapes = UniBridge.shared.blendShapes.components(separatedBy: ",") +} + +@_cdecl("uniUseAutoConvertVRM1") +public func uniUseAutoConvertVRM1() -> Bool { + UserDefaults.standard.value(for: .useAutoConvertVRM1) +} + +@_cdecl("uniDisposeWindow") +public func uniDisposeWindow() { + Logger.log("") + WindowManager.shared.dispose() +} + +@_cdecl("uniHideWindow") +public func uniHideWindow() { + Logger.log("") + WindowManager.shared.hide() +} + +@_cdecl("uniReloadUI") +public func uniReloadUI() { + guard WindowManager.shared.isConfigured, + WindowManager.shared.system.isUniVCamSystemEnabled else { return } + UniReload.Reloader.shared.objectWillChange.send() +} + +@_cdecl("uniUpdateRenderFrame") +public func uniUpdateRenderFrame() { + guard WindowManager.shared.isConfigured else { return } + VirtualCameraManager.shared.sendImageToVirtualCamera( + with: MainTexture.shared.texture, + useHMirror: UserDefaults.cached.useHMirror + ) + + VideoRecorder.shared.renderFrame(MainTexture.shared.texture) +} + +@_cdecl("uniRegisterString") +public func uniRegisterString(_ get: @escaping @convention(c) (Int32) -> UnsafePointer, _ set: @escaping @convention(c) (Int32, UnsafePointer) -> Void) { + UniBridge.shared.stringMapper.getValue = { String(cString: get($0.rawValue)) } + UniBridge.shared.stringMapper.setValue = { set($0.rawValue, strdup($1)) } +} + +@_cdecl("uniRegisterInt") +public func uniRegisterInt(_ get: @escaping @convention(c) (Int32) -> Int32, _ set: @escaping @convention(c) (Int32, Int32) -> Void) { + UniBridge.shared.intMapper.getValue = { get($0.rawValue) } + UniBridge.shared.intMapper.setValue = { set($0.rawValue, $1) } +} + +@_cdecl("uniRegisterFloat") +public func uniRegisterFloat(_ get: @escaping @convention(c) (Int32) -> Float, _ set: @escaping @convention(c) (Int32, Float) -> Void) { + UniBridge.shared.floatMapper.getValue = { CGFloat(get($0.rawValue)) } + UniBridge.shared.floatMapper.setValue = { set($0.rawValue, Float($1)) } +} + +@_cdecl("uniRegisterBool") +public func uniRegisterBool(_ get: @escaping @convention(c) (Int32) -> Bool, _ set: @escaping @convention(c) (Int32, Bool) -> Void) { + UniBridge.shared.boolMapper.getValue = { get($0.rawValue) } + UniBridge.shared.boolMapper.setValue = { set($0.rawValue, $1) } +} + +@_cdecl("uniRegisterTrigger") +public func uniRegisterTrigger(_ trigger: @escaping @convention(c) (Int32) -> Void) { + UniBridge.shared.triggerMapper.getValue = { trigger($0.rawValue) } +} + +@_cdecl("uniRegisterStruct") +public func uniRegisterStruct(_ get: @escaping @convention(c) (Int32) -> UnsafeMutableRawPointer, _ set: @escaping @convention(c) (Int32, UnsafeMutableRawPointer) -> Void) { + UniBridge.shared.structMapper.getValue = { get($0.rawValue) } + UniBridge.shared.structMapper.setValue = { set($0.rawValue, $1) } +} + +@_cdecl("uniRegisterArray") +public func uniRegisterArray(_ get: @escaping @convention(c) (Int32) -> UnsafeMutableRawPointer, _ set: @escaping @convention(c) (Int32, UnsafeMutableRawPointer) -> Void) { + UniBridge.shared.arrayMapper.getValue = { get($0.rawValue) } + UniBridge.shared.arrayMapper.setValue = { set($0.rawValue, $1) } +} diff --git a/app/xcode/Sources/VCamUI/VCamMainView.swift b/app/xcode/Sources/VCamUI/VCamMainView.swift index 64230b8..425ed9d 100644 --- a/app/xcode/Sources/VCamUI/VCamMainView.swift +++ b/app/xcode/Sources/VCamUI/VCamMainView.swift @@ -9,11 +9,12 @@ import SwiftUI import VCamEntity import VCamCamera import VCamTracking +import VCamBridge public struct VCamMainView: View { public init() {} - @UniState(.message, name: "message") private var message + @ExternalStateBinding(.message) private var message @State private var isCameraExtensionDisallow = false