Skip to content

Commit

Permalink
Open source
Browse files Browse the repository at this point in the history
  • Loading branch information
tattn committed Oct 8, 2023
1 parent 4047102 commit ad27e6d
Show file tree
Hide file tree
Showing 15 changed files with 1,625 additions and 118 deletions.
75 changes: 38 additions & 37 deletions app/xcode/Sources/VCamBridge/UniBridge.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/// GENERATED BY ./scripts/generate_bridge
import SwiftUI
public final class UniBridge {
public init() {}
public static let shared = UniBridge()
private init() {}
public enum IntType: Int32 {
case lensFlare = 0
case facialExpression = 1
Expand All @@ -10,7 +11,7 @@ public final class UniBridge {
}
public let intMapper = ValueBinding<Int32, IntType>()
public var lensFlare: Binding<Int32> { intMapper.binding(.lensFlare) }
public lazy var facialExpression = intMapper.set(.facialExpression)
public private(set) lazy var facialExpression = intMapper.set(.facialExpression)
public var objectSelected: Binding<Int32> { intMapper.binding(.objectSelected) }
public var qualityLevel: Binding<Int32> { intMapper.binding(.qualityLevel) }

Expand Down Expand Up @@ -88,9 +89,9 @@ public final class UniBridge {
public var useCombineMesh: Binding<Bool> { boolMapper.binding(.useCombineMesh) }
public var useAddToMacOSMenuBar: Binding<Bool> { boolMapper.binding(.useAddToMacOSMenuBar) }
public var useVSync: Binding<Bool> { boolMapper.binding(.useVSync) }
public lazy var useHandTracking = boolMapper.set(.useHandTracking)
public lazy var useBlinker = boolMapper.set(.useBlinker)
public lazy var useFullTracking = boolMapper.set(.useFullTracking)
public private(set) lazy var useHandTracking = boolMapper.set(.useHandTracking)
public private(set) lazy var useBlinker = boolMapper.set(.useBlinker)
public private(set) lazy var useFullTracking = boolMapper.set(.useFullTracking)
public var lipSyncWebCam: Binding<Bool> { boolMapper.binding(.lipSyncWebCam) }
public var interactable: Bool { boolMapper.get(.interactable) }
public var hasPerfectSyncBlendShape: Bool { boolMapper.get(.hasPerfectSyncBlendShape) }
Expand All @@ -112,11 +113,11 @@ public final class UniBridge {
}
public let stringMapper = ValueBinding<String, StringType>()
public var message: Binding<String> { stringMapper.binding(.message) }
public lazy var loadVRM = stringMapper.set(.loadVRM)
public lazy var loadModel = stringMapper.set(.loadModel)
public private(set) lazy var loadVRM = stringMapper.set(.loadVRM)
public private(set) lazy var loadModel = stringMapper.set(.loadModel)
public var currentDisplayParameter: Binding<String> { stringMapper.binding(.currentDisplayParameter) }
public var allDisplayParameterPresets: String { stringMapper.get(.allDisplayParameterPresets) }
public lazy var showEmojiStamp = stringMapper.set(.showEmojiStamp)
public private(set) lazy var showEmojiStamp = stringMapper.set(.showEmojiStamp)
public var blendShapes: String { stringMapper.get(.blendShapes) }
public var currentBlendShape: Binding<String> { stringMapper.binding(.currentBlendShape) }

Expand All @@ -140,23 +141,23 @@ public final class UniBridge {
case quitApp = 16
}
public let triggerMapper = ValueBinding<Void, TriggerType>()
public lazy var openVRoidHub = triggerMapper.trigger(.openVRoidHub)
public lazy var resetCamera = triggerMapper.trigger(.resetCamera)
public lazy var motionJump = triggerMapper.trigger(.motionJump)
public lazy var motionWhat = triggerMapper.trigger(.motionWhat)
public lazy var motionHello = triggerMapper.trigger(.motionHello)
public lazy var motionYear = triggerMapper.trigger(.motionYear)
public lazy var motionWin = triggerMapper.trigger(.motionWin)
public lazy var applyDisplayParameter = triggerMapper.trigger(.applyDisplayParameter)
public lazy var saveDisplayParameter = triggerMapper.trigger(.saveDisplayParameter)
public lazy var addDisplayParameter = triggerMapper.trigger(.addDisplayParameter)
public lazy var deleteDisplayParameter = triggerMapper.trigger(.deleteDisplayParameter)
public lazy var deleteObject = triggerMapper.trigger(.deleteObject)
public lazy var resetAllObjects = triggerMapper.trigger(.resetAllObjects)
public lazy var editAvatar = triggerMapper.trigger(.editAvatar)
public lazy var pauseApp = triggerMapper.trigger(.pauseApp)
public lazy var resumeApp = triggerMapper.trigger(.resumeApp)
public lazy var quitApp = triggerMapper.trigger(.quitApp)
public private(set) lazy var openVRoidHub = triggerMapper.trigger(.openVRoidHub)
public private(set) lazy var resetCamera = triggerMapper.trigger(.resetCamera)
public private(set) lazy var motionJump = triggerMapper.trigger(.motionJump)
public private(set) lazy var motionWhat = triggerMapper.trigger(.motionWhat)
public private(set) lazy var motionHello = triggerMapper.trigger(.motionHello)
public private(set) lazy var motionYear = triggerMapper.trigger(.motionYear)
public private(set) lazy var motionWin = triggerMapper.trigger(.motionWin)
public private(set) lazy var applyDisplayParameter = triggerMapper.trigger(.applyDisplayParameter)
public private(set) lazy var saveDisplayParameter = triggerMapper.trigger(.saveDisplayParameter)
public private(set) lazy var addDisplayParameter = triggerMapper.trigger(.addDisplayParameter)
public private(set) lazy var deleteDisplayParameter = triggerMapper.trigger(.deleteDisplayParameter)
public private(set) lazy var deleteObject = triggerMapper.trigger(.deleteObject)
public private(set) lazy var resetAllObjects = triggerMapper.trigger(.resetAllObjects)
public private(set) lazy var editAvatar = triggerMapper.trigger(.editAvatar)
public private(set) lazy var pauseApp = triggerMapper.trigger(.pauseApp)
public private(set) lazy var resumeApp = triggerMapper.trigger(.resumeApp)
public private(set) lazy var quitApp = triggerMapper.trigger(.quitApp)

public enum StructType: Int32 {
case backgroundColor = 0
Expand Down Expand Up @@ -207,18 +208,18 @@ public final class UniBridge {
}
}
public let arrayMapper = ValueBinding<UnsafeMutableRawPointer, ArrayType>()
public lazy var headTransform = arrayMapper.set(.headTransform, type: [Float].self)
public lazy var hands = arrayMapper.set(.hands, type: [Float].self)
public lazy var fingers = arrayMapper.set(.fingers, type: [Float].self)
public lazy var receiveVCamBlendShape = arrayMapper.set(.receiveVCamBlendShape, type: [Float].self)
public lazy var receivePerfectSync = arrayMapper.set(.receivePerfectSync, type: [Float].self)
public lazy var addRenderTexture = arrayMapper.set(.addRenderTexture, type: [Int32].self)
public lazy var updateRenderTexture = arrayMapper.set(.updateRenderTexture, type: [Int32].self)
public lazy var updateObjectOrder = arrayMapper.set(.updateObjectOrder, type: [Int32].self)
public lazy var setObjectActive = arrayMapper.set(.setObjectActive, type: [Int32].self)
public lazy var setObjectLocked = arrayMapper.set(.setObjectLocked, type: [Int32].self)
public lazy var objectAvatarTransform = arrayMapper.set(.objectAvatarTransform, type: [Float].self)
public lazy var addWind = arrayMapper.set(.addWind, type: [Int32].self)
public private(set) lazy var headTransform = arrayMapper.set(.headTransform, type: [Float].self)
public private(set) lazy var hands = arrayMapper.set(.hands, type: [Float].self)
public private(set) lazy var fingers = arrayMapper.set(.fingers, type: [Float].self)
public private(set) lazy var receiveVCamBlendShape = arrayMapper.set(.receiveVCamBlendShape, type: [Float].self)
public private(set) lazy var receivePerfectSync = arrayMapper.set(.receivePerfectSync, type: [Float].self)
public private(set) lazy var addRenderTexture = arrayMapper.set(.addRenderTexture, type: [Int32].self)
public private(set) lazy var updateRenderTexture = arrayMapper.set(.updateRenderTexture, type: [Int32].self)
public private(set) lazy var updateObjectOrder = arrayMapper.set(.updateObjectOrder, type: [Int32].self)
public private(set) lazy var setObjectActive = arrayMapper.set(.setObjectActive, type: [Int32].self)
public private(set) lazy var setObjectLocked = arrayMapper.set(.setObjectLocked, type: [Int32].self)
public private(set) lazy var objectAvatarTransform = arrayMapper.set(.objectAvatarTransform, type: [Float].self)
public private(set) lazy var addWind = arrayMapper.set(.addWind, type: [Int32].self)
public var canvasSize: [Float] { arrayMapper.get(.canvasSize, size: 2) }
public var screenResolution: Binding<[Int32]> { arrayMapper.binding(.screenResolution, size: 2) }

Expand Down
64 changes: 64 additions & 0 deletions app/xcode/Sources/VCamUI/Extensions/UniBridge+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// UniBridge+.swift
//
//
// Created by Tatsuya Tanaka on 2022/05/23.
//

import Foundation
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 UniState<ScreenResolution>.CustomState {
public static var typedScreenResolution: Self {
let rawValue = UniState<[Int32]>(.screenResolution, name: "screenResolution", as: [Int32].self)
return .init {
let size = rawValue.wrappedValue
guard size.count == 2 else { return .init(width: 1920, height: 1280) } // an empty array after disposal
return ScreenResolution(width: Int(size[0]), height: Int(size[1]))
} set: {
let isLandscape = MainTexture.shared.isLandscape
rawValue.wrappedValue = [Int32($0.size.width), Int32($0.size.height)]
if isLandscape != MainTexture.shared.isLandscape {
SceneManager.shared.changeAspectRatio()
}
}
}
}

extension UniBridge {
public var canvasCGSize: CGSize {
let size = canvasSize
guard size.count == 2 else { return .init(width: 1920, height: 1280) } // an empty array after disposal
return .init(width: CGFloat(size[0]), height: CGFloat(size[1]))
}

public static var cachedBlendShapes: [String] = []
public var cachedBlendShapes: [String] {
Self.cachedBlendShapes
}
}
33 changes: 33 additions & 0 deletions app/xcode/Sources/VCamUI/Extensions/UniSet.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// UniSet.swift
//
//
// Created by Tatsuya Tanaka on 2023/03/01.
//

import SwiftUI
import VCamEntity
import VCamBridge

@propertyWrapper public struct UniSet<Value: Hashable>: 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<Value> {
.init(set: set)
}

public struct Action<T> {
let set: (T) -> Void

public func callAsFunction(_ value: T) {
set(value)
}
}
}
97 changes: 97 additions & 0 deletions app/xcode/Sources/VCamUI/RenderTextureManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//
// RenderTextureManager.swift
//
//
// Created by Tatsuya Tanaka on 2022/03/20.
//

import SwiftUI
import VCamBridge
import VCamLogger

public final class RenderTextureManager {
public static let shared = RenderTextureManager()

private var recorders: [Int32: any RenderTextureRenderer] = [:]
private let ciContext = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)

public func add(_ recorder: any RenderTextureRenderer) -> Int32 {
let id = Int32.random(in: 0..<Int32.max)
set(recorder, id: id)
return id
}

public func set(_ recorder: any RenderTextureRenderer, id: Int32) {
uniDebugLog("Set rendertexture: \(id)")
recorders[id] = recorder
}

public func drawer(id: Int32) -> (any RenderTextureRenderer)? {
recorders[id]
}

public func setRenderTexture(_ texture: any MTLTexture, id: Int32) {
uniDebugLog("setRenderTexture: \(id) in \(recorders.keys)")
guard let recorder = recorders[id] else {
uniDebugLog("setRenderTexture: no recorder \(id)")
return
}
Logger.log("\(texture.width)x\(texture.height), \(type(of: recorder))")

recorder.setRenderTexture { [self] image in
let width = image.extent.width
let height = image.extent.height
if recorder.updateTextureSizeIfNeeded(imageWidth: width, imageHeight: height) {
Logger.log("updateTextureSizeIfNeeded")
// iPhone's screen size initially becomes 0x0, so reconfigure when a texture is retrieved.
if let object = SceneObjectManager.shared.objects.find(byId: id), let texture = object.type.croppableTexture {
texture.crop = recorder.cropRect
texture.region = .init(origin: .zero, size: .invalid)
recorder.disableRenderTexture()
Task { @MainActor in
SceneObjectManager.shared.update(object)
}
return
}
}

let (camWidth, camHeight) = (Int(width * recorder.cropRect.width), Int(width * recorder.cropRect.height))
if texture.width == camWidth, texture.height == camHeight {
let croppedImage = recorder.cropped(of: image)
ciContext.render(croppedImage, to: texture, commandBuffer: nil, bounds: croppedImage.extent, colorSpace: .sRGB)
} else {
Logger.log("setRenderTexture change size: \(texture.width) == \(camWidth), \(texture.height) == \(camHeight), \(width)")
// Update the texture size
recorder.disableRenderTexture()
Task { @MainActor in
UniBridge.shared.updateRenderTexture([Int32(id), Int32(camWidth), Int32(camHeight)])
}
}
}
}

func remove(id: Int32) {
guard let recorder = recorders[id] else { return }
recorder.stopRendering()
recorders.removeValue(forKey: id)
}

func removeAll() {
let ids = [Int32](recorders.keys)
for id in ids {
remove(id: id)
}
}

public func pause() {
for recorder in recorders.values {
recorder.pauseRendering()
}
}

public func resume() {
for recorder in recorders.values {
recorder.resumeRendering()
}
}
}
Loading

0 comments on commit ad27e6d

Please sign in to comment.