Skip to content

Commit c0605f1

Browse files
committed
Open source
1 parent 4047102 commit c0605f1

16 files changed

+1681
-118
lines changed

app/xcode/Sources/VCamBridge/UniBridge.swift

+38-37
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/// GENERATED BY ./scripts/generate_bridge
22
import SwiftUI
33
public final class UniBridge {
4-
public init() {}
4+
public static let shared = UniBridge()
5+
private init() {}
56
public enum IntType: Int32 {
67
case lensFlare = 0
78
case facialExpression = 1
@@ -10,7 +11,7 @@ public final class UniBridge {
1011
}
1112
public let intMapper = ValueBinding<Int32, IntType>()
1213
public var lensFlare: Binding<Int32> { intMapper.binding(.lensFlare) }
13-
public lazy var facialExpression = intMapper.set(.facialExpression)
14+
public private(set) lazy var facialExpression = intMapper.set(.facialExpression)
1415
public var objectSelected: Binding<Int32> { intMapper.binding(.objectSelected) }
1516
public var qualityLevel: Binding<Int32> { intMapper.binding(.qualityLevel) }
1617

@@ -88,9 +89,9 @@ public final class UniBridge {
8889
public var useCombineMesh: Binding<Bool> { boolMapper.binding(.useCombineMesh) }
8990
public var useAddToMacOSMenuBar: Binding<Bool> { boolMapper.binding(.useAddToMacOSMenuBar) }
9091
public var useVSync: Binding<Bool> { boolMapper.binding(.useVSync) }
91-
public lazy var useHandTracking = boolMapper.set(.useHandTracking)
92-
public lazy var useBlinker = boolMapper.set(.useBlinker)
93-
public lazy var useFullTracking = boolMapper.set(.useFullTracking)
92+
public private(set) lazy var useHandTracking = boolMapper.set(.useHandTracking)
93+
public private(set) lazy var useBlinker = boolMapper.set(.useBlinker)
94+
public private(set) lazy var useFullTracking = boolMapper.set(.useFullTracking)
9495
public var lipSyncWebCam: Binding<Bool> { boolMapper.binding(.lipSyncWebCam) }
9596
public var interactable: Bool { boolMapper.get(.interactable) }
9697
public var hasPerfectSyncBlendShape: Bool { boolMapper.get(.hasPerfectSyncBlendShape) }
@@ -112,11 +113,11 @@ public final class UniBridge {
112113
}
113114
public let stringMapper = ValueBinding<String, StringType>()
114115
public var message: Binding<String> { stringMapper.binding(.message) }
115-
public lazy var loadVRM = stringMapper.set(.loadVRM)
116-
public lazy var loadModel = stringMapper.set(.loadModel)
116+
public private(set) lazy var loadVRM = stringMapper.set(.loadVRM)
117+
public private(set) lazy var loadModel = stringMapper.set(.loadModel)
117118
public var currentDisplayParameter: Binding<String> { stringMapper.binding(.currentDisplayParameter) }
118119
public var allDisplayParameterPresets: String { stringMapper.get(.allDisplayParameterPresets) }
119-
public lazy var showEmojiStamp = stringMapper.set(.showEmojiStamp)
120+
public private(set) lazy var showEmojiStamp = stringMapper.set(.showEmojiStamp)
120121
public var blendShapes: String { stringMapper.get(.blendShapes) }
121122
public var currentBlendShape: Binding<String> { stringMapper.binding(.currentBlendShape) }
122123

@@ -140,23 +141,23 @@ public final class UniBridge {
140141
case quitApp = 16
141142
}
142143
public let triggerMapper = ValueBinding<Void, TriggerType>()
143-
public lazy var openVRoidHub = triggerMapper.trigger(.openVRoidHub)
144-
public lazy var resetCamera = triggerMapper.trigger(.resetCamera)
145-
public lazy var motionJump = triggerMapper.trigger(.motionJump)
146-
public lazy var motionWhat = triggerMapper.trigger(.motionWhat)
147-
public lazy var motionHello = triggerMapper.trigger(.motionHello)
148-
public lazy var motionYear = triggerMapper.trigger(.motionYear)
149-
public lazy var motionWin = triggerMapper.trigger(.motionWin)
150-
public lazy var applyDisplayParameter = triggerMapper.trigger(.applyDisplayParameter)
151-
public lazy var saveDisplayParameter = triggerMapper.trigger(.saveDisplayParameter)
152-
public lazy var addDisplayParameter = triggerMapper.trigger(.addDisplayParameter)
153-
public lazy var deleteDisplayParameter = triggerMapper.trigger(.deleteDisplayParameter)
154-
public lazy var deleteObject = triggerMapper.trigger(.deleteObject)
155-
public lazy var resetAllObjects = triggerMapper.trigger(.resetAllObjects)
156-
public lazy var editAvatar = triggerMapper.trigger(.editAvatar)
157-
public lazy var pauseApp = triggerMapper.trigger(.pauseApp)
158-
public lazy var resumeApp = triggerMapper.trigger(.resumeApp)
159-
public lazy var quitApp = triggerMapper.trigger(.quitApp)
144+
public private(set) lazy var openVRoidHub = triggerMapper.trigger(.openVRoidHub)
145+
public private(set) lazy var resetCamera = triggerMapper.trigger(.resetCamera)
146+
public private(set) lazy var motionJump = triggerMapper.trigger(.motionJump)
147+
public private(set) lazy var motionWhat = triggerMapper.trigger(.motionWhat)
148+
public private(set) lazy var motionHello = triggerMapper.trigger(.motionHello)
149+
public private(set) lazy var motionYear = triggerMapper.trigger(.motionYear)
150+
public private(set) lazy var motionWin = triggerMapper.trigger(.motionWin)
151+
public private(set) lazy var applyDisplayParameter = triggerMapper.trigger(.applyDisplayParameter)
152+
public private(set) lazy var saveDisplayParameter = triggerMapper.trigger(.saveDisplayParameter)
153+
public private(set) lazy var addDisplayParameter = triggerMapper.trigger(.addDisplayParameter)
154+
public private(set) lazy var deleteDisplayParameter = triggerMapper.trigger(.deleteDisplayParameter)
155+
public private(set) lazy var deleteObject = triggerMapper.trigger(.deleteObject)
156+
public private(set) lazy var resetAllObjects = triggerMapper.trigger(.resetAllObjects)
157+
public private(set) lazy var editAvatar = triggerMapper.trigger(.editAvatar)
158+
public private(set) lazy var pauseApp = triggerMapper.trigger(.pauseApp)
159+
public private(set) lazy var resumeApp = triggerMapper.trigger(.resumeApp)
160+
public private(set) lazy var quitApp = triggerMapper.trigger(.quitApp)
160161

161162
public enum StructType: Int32 {
162163
case backgroundColor = 0
@@ -207,18 +208,18 @@ public final class UniBridge {
207208
}
208209
}
209210
public let arrayMapper = ValueBinding<UnsafeMutableRawPointer, ArrayType>()
210-
public lazy var headTransform = arrayMapper.set(.headTransform, type: [Float].self)
211-
public lazy var hands = arrayMapper.set(.hands, type: [Float].self)
212-
public lazy var fingers = arrayMapper.set(.fingers, type: [Float].self)
213-
public lazy var receiveVCamBlendShape = arrayMapper.set(.receiveVCamBlendShape, type: [Float].self)
214-
public lazy var receivePerfectSync = arrayMapper.set(.receivePerfectSync, type: [Float].self)
215-
public lazy var addRenderTexture = arrayMapper.set(.addRenderTexture, type: [Int32].self)
216-
public lazy var updateRenderTexture = arrayMapper.set(.updateRenderTexture, type: [Int32].self)
217-
public lazy var updateObjectOrder = arrayMapper.set(.updateObjectOrder, type: [Int32].self)
218-
public lazy var setObjectActive = arrayMapper.set(.setObjectActive, type: [Int32].self)
219-
public lazy var setObjectLocked = arrayMapper.set(.setObjectLocked, type: [Int32].self)
220-
public lazy var objectAvatarTransform = arrayMapper.set(.objectAvatarTransform, type: [Float].self)
221-
public lazy var addWind = arrayMapper.set(.addWind, type: [Int32].self)
211+
public private(set) lazy var headTransform = arrayMapper.set(.headTransform, type: [Float].self)
212+
public private(set) lazy var hands = arrayMapper.set(.hands, type: [Float].self)
213+
public private(set) lazy var fingers = arrayMapper.set(.fingers, type: [Float].self)
214+
public private(set) lazy var receiveVCamBlendShape = arrayMapper.set(.receiveVCamBlendShape, type: [Float].self)
215+
public private(set) lazy var receivePerfectSync = arrayMapper.set(.receivePerfectSync, type: [Float].self)
216+
public private(set) lazy var addRenderTexture = arrayMapper.set(.addRenderTexture, type: [Int32].self)
217+
public private(set) lazy var updateRenderTexture = arrayMapper.set(.updateRenderTexture, type: [Int32].self)
218+
public private(set) lazy var updateObjectOrder = arrayMapper.set(.updateObjectOrder, type: [Int32].self)
219+
public private(set) lazy var setObjectActive = arrayMapper.set(.setObjectActive, type: [Int32].self)
220+
public private(set) lazy var setObjectLocked = arrayMapper.set(.setObjectLocked, type: [Int32].self)
221+
public private(set) lazy var objectAvatarTransform = arrayMapper.set(.objectAvatarTransform, type: [Float].self)
222+
public private(set) lazy var addWind = arrayMapper.set(.addWind, type: [Int32].self)
222223
public var canvasSize: [Float] { arrayMapper.get(.canvasSize, size: 2) }
223224
public var screenResolution: Binding<[Int32]> { arrayMapper.binding(.screenResolution, size: 2) }
224225

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// CustomModal.swift
3+
//
4+
//
5+
// Created by Tatsuya Tanaka on 2022/03/20.
6+
//
7+
8+
import AppKit
9+
import SwiftUI
10+
11+
public func showSheet<Content: View>(title: String, view: (@escaping () -> Void) -> Content) {
12+
var panel: NSPanel?
13+
panel = NSPanel(contentViewController: NSHostingController(rootView: view({
14+
panel?.close()
15+
panel = nil
16+
})))
17+
panel!.title = title
18+
panel!.isReleasedWhenClosed = true
19+
20+
if let window = NSApp.vcamWindow {
21+
window.beginSheet(panel!)
22+
}
23+
}
24+
25+
// Deprecated: Migrate to MacWindowManager
26+
public enum VCamWindow {
27+
public static func showWindow<Content: View>(title: String, view: (@escaping () -> Void) -> Content, close: (() -> Void)? = nil) {
28+
var panel: NSPanel!
29+
var closeObserver: (any NSObjectProtocol)?
30+
31+
let windowClosed = {
32+
panel = nil
33+
close?()
34+
35+
if let observer = closeObserver {
36+
NotificationCenter.default.removeObserver(observer)
37+
closeObserver = nil
38+
}
39+
}
40+
41+
closeObserver = NotificationCenter.default.addObserver(forName: NSWindow.willCloseNotification, object: nil, queue: .main) { notification in
42+
guard notification.object as? NSPanel === panel else {
43+
return
44+
}
45+
windowClosed()
46+
}
47+
48+
panel = NSPanel(contentViewController: NSHostingController(rootView: view({
49+
panel.close()
50+
windowClosed()
51+
})))
52+
panel.title = title
53+
panel.styleMask.remove([.fullScreen, .miniaturizable, .resizable])
54+
panel.makeKeyAndOrderFront(nil)
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//
2+
// UniBridge+.swift
3+
//
4+
//
5+
// Created by Tatsuya Tanaka on 2022/05/23.
6+
//
7+
8+
import Foundation
9+
import VCamEntity
10+
import SwiftUI
11+
import VCamBridge
12+
13+
extension UniState {
14+
public init(_ state: CustomState) {
15+
get = state.get
16+
set = state.set
17+
name = state.name
18+
reloadThrottle = state.reloadThrottle
19+
}
20+
21+
public struct CustomState {
22+
public init(get: @escaping () -> Value, set: @escaping (Value) -> Void, name: String = "", reloadThrottle: Bool = false) {
23+
self.get = get
24+
self.set = set
25+
self.name = name
26+
self.reloadThrottle = reloadThrottle
27+
}
28+
29+
public var get: () -> Value
30+
public var set: (Value) -> Void
31+
public var name = ""
32+
public var reloadThrottle = false
33+
}
34+
}
35+
36+
extension UniState<ScreenResolution>.CustomState {
37+
public static var typedScreenResolution: Self {
38+
let rawValue = UniState<[Int32]>(.screenResolution, name: "screenResolution", as: [Int32].self)
39+
return .init {
40+
let size = rawValue.wrappedValue
41+
guard size.count == 2 else { return .init(width: 1920, height: 1280) } // an empty array after disposal
42+
return ScreenResolution(width: Int(size[0]), height: Int(size[1]))
43+
} set: {
44+
let isLandscape = MainTexture.shared.isLandscape
45+
rawValue.wrappedValue = [Int32($0.size.width), Int32($0.size.height)]
46+
if isLandscape != MainTexture.shared.isLandscape {
47+
SceneManager.shared.changeAspectRatio()
48+
}
49+
}
50+
}
51+
}
52+
53+
extension UniBridge {
54+
public var canvasCGSize: CGSize {
55+
let size = canvasSize
56+
guard size.count == 2 else { return .init(width: 1920, height: 1280) } // an empty array after disposal
57+
return .init(width: CGFloat(size[0]), height: CGFloat(size[1]))
58+
}
59+
60+
public static var cachedBlendShapes: [String] = []
61+
public var cachedBlendShapes: [String] {
62+
Self.cachedBlendShapes
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// UniSet.swift
3+
//
4+
//
5+
// Created by Tatsuya Tanaka on 2023/03/01.
6+
//
7+
8+
import SwiftUI
9+
import VCamEntity
10+
import VCamBridge
11+
12+
@propertyWrapper public struct UniSet<Value: Hashable>: DynamicProperty {
13+
public init(_ type: UniBridge.BoolType, name: String) where Value == Bool {
14+
let mapper = UniBridge.shared.boolMapper
15+
self.set = mapper.set(type)
16+
self.name = name
17+
}
18+
19+
private let set: (Value) -> Void
20+
private var name = ""
21+
22+
public var wrappedValue: Action<Value> {
23+
.init(set: set)
24+
}
25+
26+
public struct Action<T> {
27+
let set: (T) -> Void
28+
29+
public func callAsFunction(_ value: T) {
30+
set(value)
31+
}
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//
2+
// RenderTextureManager.swift
3+
//
4+
//
5+
// Created by Tatsuya Tanaka on 2022/03/20.
6+
//
7+
8+
import SwiftUI
9+
import VCamBridge
10+
import VCamLogger
11+
12+
public final class RenderTextureManager {
13+
public static let shared = RenderTextureManager()
14+
15+
private var recorders: [Int32: any RenderTextureRenderer] = [:]
16+
private let ciContext = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)
17+
18+
public func add(_ recorder: any RenderTextureRenderer) -> Int32 {
19+
let id = Int32.random(in: 0..<Int32.max)
20+
set(recorder, id: id)
21+
return id
22+
}
23+
24+
public func set(_ recorder: any RenderTextureRenderer, id: Int32) {
25+
uniDebugLog("Set rendertexture: \(id)")
26+
recorders[id] = recorder
27+
}
28+
29+
public func drawer(id: Int32) -> (any RenderTextureRenderer)? {
30+
recorders[id]
31+
}
32+
33+
public func setRenderTexture(_ texture: any MTLTexture, id: Int32) {
34+
uniDebugLog("setRenderTexture: \(id) in \(recorders.keys)")
35+
guard let recorder = recorders[id] else {
36+
uniDebugLog("setRenderTexture: no recorder \(id)")
37+
return
38+
}
39+
Logger.log("\(texture.width)x\(texture.height), \(type(of: recorder))")
40+
41+
recorder.setRenderTexture { [self] image in
42+
let width = image.extent.width
43+
let height = image.extent.height
44+
if recorder.updateTextureSizeIfNeeded(imageWidth: width, imageHeight: height) {
45+
Logger.log("updateTextureSizeIfNeeded")
46+
// iPhone's screen size initially becomes 0x0, so reconfigure when a texture is retrieved.
47+
if let object = SceneObjectManager.shared.objects.find(byId: id), let texture = object.type.croppableTexture {
48+
texture.crop = recorder.cropRect
49+
texture.region = .init(origin: .zero, size: .invalid)
50+
recorder.disableRenderTexture()
51+
Task { @MainActor in
52+
SceneObjectManager.shared.update(object)
53+
}
54+
return
55+
}
56+
}
57+
58+
let (camWidth, camHeight) = (Int(width * recorder.cropRect.width), Int(width * recorder.cropRect.height))
59+
if texture.width == camWidth, texture.height == camHeight {
60+
let croppedImage = recorder.cropped(of: image)
61+
ciContext.render(croppedImage, to: texture, commandBuffer: nil, bounds: croppedImage.extent, colorSpace: .sRGB)
62+
} else {
63+
Logger.log("setRenderTexture change size: \(texture.width) == \(camWidth), \(texture.height) == \(camHeight), \(width)")
64+
// Update the texture size
65+
recorder.disableRenderTexture()
66+
Task { @MainActor in
67+
UniBridge.shared.updateRenderTexture([Int32(id), Int32(camWidth), Int32(camHeight)])
68+
}
69+
}
70+
}
71+
}
72+
73+
func remove(id: Int32) {
74+
guard let recorder = recorders[id] else { return }
75+
recorder.stopRendering()
76+
recorders.removeValue(forKey: id)
77+
}
78+
79+
func removeAll() {
80+
let ids = [Int32](recorders.keys)
81+
for id in ids {
82+
remove(id: id)
83+
}
84+
}
85+
86+
public func pause() {
87+
for recorder in recorders.values {
88+
recorder.pauseRendering()
89+
}
90+
}
91+
92+
public func resume() {
93+
for recorder in recorders.values {
94+
recorder.resumeRendering()
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)