@webspatial/platform-visionos 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/web-spatial/EventEmitter.swift +56 -0
- package/web-spatial/JSBCommand.swift +348 -0
- package/web-spatial/SpatialObject.swift +108 -0
- package/web-spatial/WebMsgCommand.swift +119 -0
- package/web-spatial/WebSpatialApp.swift +111 -0
- package/web-spatial/{libs/uiKitDelegate/Window.swift → Window.swift} +1 -0
- package/web-spatial/manager/Dynamic3DManager.swift +114 -0
- package/web-spatial/manager/JSBManager.swift +148 -0
- package/web-spatial/manager/WKWebViewManager.swift +39 -0
- package/web-spatial/{libs/webView/manifest.swift → manifest.swift} +16 -5
- package/web-spatial/model/SpatialApp.swift +190 -0
- package/web-spatial/model/SpatialScene.swift +1042 -0
- package/web-spatial/model/Spatialized2DElement.swift +128 -0
- package/web-spatial/model/SpatializedDynamic3DElement.swift +34 -0
- package/web-spatial/model/SpatializedElement.swift +95 -0
- package/web-spatial/model/SpatializedStatic3DElement.swift +19 -0
- package/web-spatial/model/dynamic3d/Geometry.swift +95 -0
- package/web-spatial/model/dynamic3d/SpatialComponent.swift +72 -0
- package/web-spatial/model/dynamic3d/SpatialEntity.swift +211 -0
- package/web-spatial/model/dynamic3d/SpatialMaterial.swift +39 -0
- package/web-spatial/model/dynamic3d/SpatialModelEntity.swift +39 -0
- package/web-spatial/model/dynamic3d/SpatialModelResource.swift +38 -0
- package/web-spatial/model/dynamic3d/SpatialTextureResource.swift +18 -0
- package/web-spatial/protocol/ScrollAbleSpatialElementContainer.swift +1 -0
- package/web-spatial/protocol/SpatialScrollAble.swift +8 -0
- package/web-spatial/protocol/SpatializedElementContainer.swift +8 -0
- package/web-spatial/protocol/WebMsgSender.swift +5 -0
- package/web-spatial/types/Vec2.swift +12 -0
- package/web-spatial/types/Vec3.swift +7 -0
- package/web-spatial/view/SceneHandlerUIView.swift +92 -0
- package/web-spatial/{views/ui/NavView.swift → view/SpatialNavView.swift} +149 -77
- package/web-spatial/view/SpatialSceneContentView.swift +218 -0
- package/web-spatial/view/SpatialSceneView.swift +53 -0
- package/web-spatial/view/Spatialized2DElementView.swift +96 -0
- package/web-spatial/view/SpatializedDynamic3DView.swift +104 -0
- package/web-spatial/view/SpatializedElementView.swift +178 -0
- package/web-spatial/view/SpatializedStatic3DView.swift +70 -0
- package/web-spatial/{views → view/view-modifier}/MaterialWithBorderCornerModifier.swift +28 -8
- package/web-spatial/webview/SpatialWebController.swift +300 -0
- package/web-spatial/webview/SpatialWebView.swift +34 -0
- package/web-spatial/webview/SpatialWebViewModel.swift +307 -0
- package/web-spatial.xcodeproj/project.pbxproj +126 -207
- package/web-spatial/libs/EventEmitter.swift +0 -25
- package/web-spatial/libs/SpatialComponent.swift +0 -24
- package/web-spatial/libs/SpatialEntity.swift +0 -172
- package/web-spatial/libs/SpatialInputComponent.swift +0 -19
- package/web-spatial/libs/SpatialMeshResource.swift +0 -12
- package/web-spatial/libs/SpatialModel3DComponent.swift +0 -51
- package/web-spatial/libs/SpatialModelComponent.swift +0 -25
- package/web-spatial/libs/SpatialObject.swift +0 -140
- package/web-spatial/libs/SpatialPhysicallyBasedMaterial.swift +0 -19
- package/web-spatial/libs/SpatialViewComponent.swift +0 -8
- package/web-spatial/libs/SpatialWindowComponent.swift +0 -454
- package/web-spatial/libs/SpatialWindowContainer.swift +0 -153
- package/web-spatial/libs/Utils/CommandManager.swift +0 -823
- package/web-spatial/libs/Utils/PerfClock.swift +0 -43
- package/web-spatial/libs/Utils/SceneManager.swift +0 -101
- package/web-spatial/libs/Utils/WindowContainerMgr.swift +0 -122
- package/web-spatial/libs/json/JsonParser.swift +0 -45
- package/web-spatial/libs/webView/UpdateSystem.swift +0 -26
- package/web-spatial/libs/webView/backend/NativeWebView.swift +0 -350
- package/web-spatial/views/ImmersiveView.swift +0 -17
- package/web-spatial/views/OpenDismissHandlerUI.swift +0 -45
- package/web-spatial/views/PlainWindowContainerView.swift +0 -132
- package/web-spatial/views/SpatialModel3DView.swift +0 -187
- package/web-spatial/views/SpatialViewUI.swift +0 -168
- package/web-spatial/views/SpatialWebViewUI.swift +0 -179
- package/web-spatial/views/VolumetricWindowContainerView.swift +0 -30
- package/web-spatial/web_spatialApp.swift +0 -141
- /package/web-spatial/{libs/Utils → Utils}/ColorExtension.swift +0 -0
- /package/web-spatial/{libs/Utils → Utils}/Logger.swift +0 -0
- /package/web-spatial/{views → view}/LoadingView.swift +0 -0
- /package/web-spatial/{views → view/view-modifier}/HideViewModifier.swift +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import RealityKit
|
|
3
|
+
import SwiftUI
|
|
4
|
+
|
|
5
|
+
@Observable
|
|
6
|
+
class Spatialized2DElement: SpatializedElement, ScrollAbleSpatialElementContainer {
|
|
7
|
+
var cornerRadius: CornerRadius = .init()
|
|
8
|
+
|
|
9
|
+
var backgroundMaterial = BackgroundMaterial.None
|
|
10
|
+
|
|
11
|
+
var scrollPageEnabled = false
|
|
12
|
+
|
|
13
|
+
var scrollEdgeInsetsMarginRight: CGFloat? {
|
|
14
|
+
get {
|
|
15
|
+
return spatialWebViewModel.getController().webview?.scrollView.contentInset.right
|
|
16
|
+
}
|
|
17
|
+
set(newValue) {
|
|
18
|
+
spatialWebViewModel.getController().webview?.scrollView.contentInset.right = newValue ?? 0
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
var _scrollOffset: Vec2 = .init(x: 0, y: 0)
|
|
23
|
+
var scrollOffset: Vec2 {
|
|
24
|
+
get {
|
|
25
|
+
return _scrollOffset
|
|
26
|
+
}
|
|
27
|
+
set(newValue) {
|
|
28
|
+
_scrollOffset = newValue
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func updateDeltaScrollOffset(_ delta: Vec2) {
|
|
33
|
+
spatialWebViewModel.setScrollOffset(_scrollOffset + delta)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func stopScrolling() {
|
|
37
|
+
spatialWebViewModel.stopScrolling()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private var spatialWebViewModel: SpatialWebViewModel
|
|
41
|
+
func getWebViewModel() -> SpatialWebViewModel {
|
|
42
|
+
return spatialWebViewModel
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override init() {
|
|
46
|
+
spatialWebViewModel = SpatialWebViewModel(url: nil)
|
|
47
|
+
|
|
48
|
+
super.init()
|
|
49
|
+
|
|
50
|
+
spatialWebViewModel.setBackgroundTransparent(true)
|
|
51
|
+
spatialWebViewModel.addScrollUpdateListener { _, point in
|
|
52
|
+
self._scrollOffset.x = point.x
|
|
53
|
+
self._scrollOffset.y = point.y
|
|
54
|
+
}
|
|
55
|
+
spatialWebViewModel.scrollEnabled = false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Spatialized2DElement can hold a collection of SpatializedElement children
|
|
59
|
+
private var children = [String: SpatializedElement]()
|
|
60
|
+
|
|
61
|
+
// Called by SpatializedElement.setParent
|
|
62
|
+
func addChild(_ spatializedElement: SpatializedElement) {
|
|
63
|
+
children[spatializedElement.id] = spatializedElement
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Called by SpatializedElement.setParent
|
|
67
|
+
func removeChild(_ spatializedElement: SpatializedElement) {
|
|
68
|
+
children.removeValue(forKey: spatializedElement.id)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func getChildren() -> [String: SpatializedElement] {
|
|
72
|
+
return children
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
func getChildrenOfType(_ type: SpatializedElementType) -> [String: SpatializedElement] {
|
|
76
|
+
let typedChildren = children.filter {
|
|
77
|
+
switch type {
|
|
78
|
+
case .Spatialized2DElement:
|
|
79
|
+
return $0.value is Spatialized2DElement
|
|
80
|
+
case .SpatializedStatic3DElement:
|
|
81
|
+
return $0.value is SpatializedStatic3DElement
|
|
82
|
+
case .SpatializedDynamic3DElement:
|
|
83
|
+
return $0.value is SpatializedDynamic3DElement
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return typedChildren
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func loadHtml(_ html: String) {
|
|
90
|
+
spatialWebViewModel.loadHTML(html)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
func load(_ url: String) {
|
|
94
|
+
spatialWebViewModel.load(url)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func getView() -> SpatialWebView {
|
|
98
|
+
return spatialWebViewModel.getView()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
override func onDestroy() {
|
|
102
|
+
let spatializedElements = children.map { $0.value }
|
|
103
|
+
for spatializedElement in spatializedElements {
|
|
104
|
+
spatializedElement.destroy()
|
|
105
|
+
}
|
|
106
|
+
spatialWebViewModel.destroy()
|
|
107
|
+
|
|
108
|
+
super.onDestroy()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
enum CodingKeys: String, CodingKey {
|
|
112
|
+
case cornerRadius, backgroundMaterial, children, type, scrollOffset, scrollPageEnabled, webviewIsOpaque
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
override func encode(to encoder: Encoder) throws {
|
|
116
|
+
try super.encode(to: encoder)
|
|
117
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
118
|
+
try container.encode(cornerRadius, forKey: .cornerRadius)
|
|
119
|
+
try container.encode(backgroundMaterial, forKey: .backgroundMaterial)
|
|
120
|
+
try container.encode(children, forKey: .children)
|
|
121
|
+
try container.encode(SpatializedElementType.Spatialized2DElement, forKey: .type)
|
|
122
|
+
try container.encode(scrollOffset, forKey: .scrollOffset)
|
|
123
|
+
try container.encode(scrollPageEnabled, forKey: .scrollPageEnabled)
|
|
124
|
+
|
|
125
|
+
// for debug only
|
|
126
|
+
try container.encode(spatialWebViewModel.getController().webview?.isOpaque, forKey: .webviewIsOpaque)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@Observable
|
|
4
|
+
class SpatializedDynamic3DElement: SpatializedElement {
|
|
5
|
+
private var rootEntity = SpatialEntity()
|
|
6
|
+
|
|
7
|
+
func getRoot() -> SpatialEntity {
|
|
8
|
+
return rootEntity
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
func addEntity(_ entity: SpatialEntity) {
|
|
12
|
+
rootEntity.addChild(entity)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
func removeEntity(_ entity: SpatialEntity) {
|
|
16
|
+
rootEntity.removeChild(entity)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
enum CodingKeys: String, CodingKey {
|
|
20
|
+
case type, root
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
override func encode(to encoder: Encoder) throws {
|
|
24
|
+
try super.encode(to: encoder)
|
|
25
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
26
|
+
try container.encode(SpatializedElementType.SpatializedDynamic3DElement, forKey: .type)
|
|
27
|
+
try container.encode(rootEntity, forKey: .root)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override func onDestroy() {
|
|
31
|
+
rootEntity.destroy()
|
|
32
|
+
super.onDestroy()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import RealityKit
|
|
3
|
+
import SwiftUI
|
|
4
|
+
|
|
5
|
+
enum SpatializedElementType: String, Codable {
|
|
6
|
+
case Spatialized2DElement
|
|
7
|
+
case SpatializedStatic3DElement
|
|
8
|
+
case SpatializedDynamic3DElement
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@Observable
|
|
12
|
+
class SpatializedElement: SpatialObject {
|
|
13
|
+
var clientX: Double = 0.0
|
|
14
|
+
var clientY: Double = 0.0
|
|
15
|
+
var width: Double = 0.0
|
|
16
|
+
var height: Double = 0.0
|
|
17
|
+
var depth: Double = 0.0
|
|
18
|
+
var backOffset: Double = 0.0
|
|
19
|
+
var transform: AffineTransform3D = .identity
|
|
20
|
+
var rotationAnchor: UnitPoint3D = .center
|
|
21
|
+
var opacity: Double = 1.0
|
|
22
|
+
var visible = true
|
|
23
|
+
var scrollWithParent = true
|
|
24
|
+
var zIndex: Double = 0
|
|
25
|
+
|
|
26
|
+
var enableDragStartGesture: Bool = false
|
|
27
|
+
var enableDragGesture: Bool = false
|
|
28
|
+
var enableDragEndGesture: Bool = false
|
|
29
|
+
var enableRotateStartGesture: Bool = false
|
|
30
|
+
var enableRotateGesture: Bool = false
|
|
31
|
+
var enableRotateEndGesture: Bool = false
|
|
32
|
+
var enableMagnifyStartGesture: Bool = false
|
|
33
|
+
var enableMagnifyGesture: Bool = false
|
|
34
|
+
var enableMagnifyEndGesture: Bool = false
|
|
35
|
+
var enableTapGesture: Bool = false
|
|
36
|
+
|
|
37
|
+
var enableGesture: Bool {
|
|
38
|
+
return enableDragStartGesture || enableDragGesture || enableDragEndGesture || enableRotateStartGesture || enableRotateGesture || enableRotateEndGesture || enableMagnifyStartGesture || enableMagnifyGesture || enableMagnifyEndGesture || enableTapGesture
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
enum CodingKeys: String, CodingKey {
|
|
42
|
+
case clientX, clientY, width, height, depth, backOffset, transform, rotationAnchor, opacity, visible, scrollWithParent, zIndex, parent, enableGesture, enableTapGesture, enableDragGesture, enableDragEndGesture, enableRotateStartGesture, enableRotateGesture, enableRotateEndGesture, enableMagnifyStartGesture, enableMagnifyGesture, enableMagnifyEndGesture
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override func encode(to encoder: Encoder) throws {
|
|
46
|
+
try super.encode(to: encoder)
|
|
47
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
48
|
+
try container.encode(clientX, forKey: .clientX)
|
|
49
|
+
try container.encode(clientY, forKey: .clientY)
|
|
50
|
+
try container.encode(width, forKey: .width)
|
|
51
|
+
try container.encode(height, forKey: .height)
|
|
52
|
+
try container.encode(depth, forKey: .depth)
|
|
53
|
+
try container.encode(backOffset, forKey: .backOffset)
|
|
54
|
+
try container.encode(transform, forKey: .transform)
|
|
55
|
+
try container.encode(rotationAnchor, forKey: .rotationAnchor)
|
|
56
|
+
try container.encode(opacity, forKey: .opacity)
|
|
57
|
+
try container.encode(visible, forKey: .visible)
|
|
58
|
+
try container.encode(scrollWithParent, forKey: .scrollWithParent)
|
|
59
|
+
try container.encode(zIndex, forKey: .zIndex)
|
|
60
|
+
try container.encode(parent?.id, forKey: .parent)
|
|
61
|
+
try container.encode(enableGesture, forKey: .enableGesture)
|
|
62
|
+
try container.encode(enableTapGesture, forKey: .enableTapGesture)
|
|
63
|
+
try container.encode(enableDragGesture, forKey: .enableDragGesture)
|
|
64
|
+
try container.encode(enableDragEndGesture, forKey: .enableDragEndGesture)
|
|
65
|
+
try container.encode(enableRotateStartGesture, forKey: .enableRotateStartGesture)
|
|
66
|
+
try container.encode(enableRotateGesture, forKey: .enableRotateGesture)
|
|
67
|
+
try container.encode(enableRotateEndGesture, forKey: .enableRotateEndGesture)
|
|
68
|
+
try container.encode(enableMagnifyStartGesture, forKey: .enableMagnifyStartGesture)
|
|
69
|
+
try container.encode(enableMagnifyGesture, forKey: .enableMagnifyGesture)
|
|
70
|
+
try container.encode(enableMagnifyEndGesture, forKey: .enableMagnifyEndGesture)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private(set) var parent: ScrollAbleSpatialElementContainer?
|
|
74
|
+
|
|
75
|
+
func setParent(_ parent: ScrollAbleSpatialElementContainer?) {
|
|
76
|
+
if self.parent?.id == parent?.id {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if let prevParent = self.parent {
|
|
81
|
+
prevParent.removeChild(self)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
parent?.addChild(self)
|
|
85
|
+
self.parent = parent
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func getParent() -> ScrollAbleSpatialElementContainer? {
|
|
89
|
+
return parent
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
override func onDestroy() {
|
|
93
|
+
setParent(nil)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
@Observable
|
|
5
|
+
class SpatializedStatic3DElement: SpatializedElement {
|
|
6
|
+
var modelURL: String = ""
|
|
7
|
+
var modelTransform: AffineTransform3D = AffineTransform3D.identity
|
|
8
|
+
|
|
9
|
+
enum CodingKeys: String, CodingKey {
|
|
10
|
+
case modelURL, type
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override func encode(to encoder: Encoder) throws {
|
|
14
|
+
try super.encode(to: encoder)
|
|
15
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
16
|
+
try container.encode(modelURL, forKey: .modelURL)
|
|
17
|
+
try container.encode(SpatializedElementType.SpatializedStatic3DElement, forKey: .type)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
@Observable
|
|
5
|
+
class Geometry: SpatialObject {
|
|
6
|
+
let type: GeometryType
|
|
7
|
+
|
|
8
|
+
var _resource: MeshResource?
|
|
9
|
+
var resource: MeshResource? {
|
|
10
|
+
_resource
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
init(_ _type: GeometryType) {
|
|
14
|
+
type = _type
|
|
15
|
+
super.init()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override func onDestroy() {
|
|
19
|
+
_resource = nil
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@Observable
|
|
24
|
+
class BoxGeometry: Geometry {
|
|
25
|
+
let width: Float
|
|
26
|
+
let height: Float
|
|
27
|
+
let depth: Float
|
|
28
|
+
let cornerRadius: Float
|
|
29
|
+
let splitFaces: Bool
|
|
30
|
+
init(width: Float, height: Float, depth: Float, cornerRadius: Float = 0, splitFaces: Bool = false) {
|
|
31
|
+
self.width = width
|
|
32
|
+
self.height = height
|
|
33
|
+
self.depth = depth
|
|
34
|
+
self.cornerRadius = cornerRadius
|
|
35
|
+
self.splitFaces = splitFaces
|
|
36
|
+
super.init(.BoxGeometry)
|
|
37
|
+
_resource = MeshResource.generateBox(width: width, height: height, depth: depth, cornerRadius: cornerRadius, splitFaces: splitFaces)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Observable
|
|
42
|
+
class PlaneGeometry: Geometry {
|
|
43
|
+
let width: Float
|
|
44
|
+
let height: Float
|
|
45
|
+
let cornerRadius: Float
|
|
46
|
+
init(width: Float, height: Float, cornerRadius: Float = 0) {
|
|
47
|
+
self.width = width
|
|
48
|
+
self.height = height
|
|
49
|
+
self.cornerRadius = cornerRadius
|
|
50
|
+
super.init(.PlaneGeometry)
|
|
51
|
+
_resource = MeshResource.generatePlane(width: width, height: height, cornerRadius: cornerRadius)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
enum GeometryType: String {
|
|
56
|
+
case BoxGeometry
|
|
57
|
+
case PlaneGeometry
|
|
58
|
+
case SphereGeometry
|
|
59
|
+
case ConeGeometry
|
|
60
|
+
case CylinderGeometry
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@Observable
|
|
64
|
+
class SphereGeometry: Geometry {
|
|
65
|
+
let radius: Float
|
|
66
|
+
init(radius: Float) {
|
|
67
|
+
self.radius = radius
|
|
68
|
+
super.init(.SphereGeometry)
|
|
69
|
+
_resource = MeshResource.generateSphere(radius: radius)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@Observable
|
|
74
|
+
class ConeGeometry: Geometry {
|
|
75
|
+
let radius: Float
|
|
76
|
+
let height: Float
|
|
77
|
+
init(radius: Float, height: Float) {
|
|
78
|
+
self.radius = radius
|
|
79
|
+
self.height = height
|
|
80
|
+
super.init(.ConeGeometry)
|
|
81
|
+
_resource = MeshResource.generateCone(height: height, radius: radius)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@Observable
|
|
86
|
+
class CylinderGeometry: Geometry {
|
|
87
|
+
let radius: Float
|
|
88
|
+
let height: Float
|
|
89
|
+
init(radius: Float, height: Float) {
|
|
90
|
+
self.radius = radius
|
|
91
|
+
self.height = height
|
|
92
|
+
super.init(.CylinderGeometry)
|
|
93
|
+
_resource = MeshResource.generateCylinder(height: height, radius: radius)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import RealityKit
|
|
3
|
+
|
|
4
|
+
@Observable
|
|
5
|
+
class SpatialComponent: SpatialObject {
|
|
6
|
+
let type: SpatialComponentType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
internal var _resource:Component? = nil
|
|
10
|
+
var resource:Component? {
|
|
11
|
+
_resource
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
internal var _entity:SpatialEntity? = nil
|
|
15
|
+
var entity:SpatialEntity? {
|
|
16
|
+
_entity
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
init(_ _type:SpatialComponentType){
|
|
20
|
+
type = _type
|
|
21
|
+
super.init()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
func addToEntity(entity:SpatialEntity){
|
|
25
|
+
if _entity != nil {
|
|
26
|
+
print("This component has already been added to another entity")
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
if let component = resource{
|
|
30
|
+
_entity = entity
|
|
31
|
+
entity.components.set(component)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func removeFromEntity(entity:SpatialEntity){
|
|
36
|
+
if let component = resource,
|
|
37
|
+
self.entity == entity{
|
|
38
|
+
entity.components.remove(Swift.type(of: component))
|
|
39
|
+
_entity = nil
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Observable
|
|
45
|
+
class SpatialModelComponent: SpatialComponent {
|
|
46
|
+
init(mesh:Geometry, mats:[SpatialMaterial]){
|
|
47
|
+
super.init(.ModelComponent)
|
|
48
|
+
var materials:[any RealityKit.Material] = []
|
|
49
|
+
mats.forEach{ item in
|
|
50
|
+
materials.append(item.resource!)
|
|
51
|
+
}
|
|
52
|
+
_resource = ModelComponent(mesh: mesh.resource!, materials: materials)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
override func addToEntity(entity:SpatialEntity){
|
|
56
|
+
super.addToEntity(entity: entity)
|
|
57
|
+
entity.generateCollisionShapes(recursive: true)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
override func removeFromEntity(entity:SpatialEntity){
|
|
61
|
+
super.removeFromEntity(entity: entity)
|
|
62
|
+
entity.generateCollisionShapes(recursive: true)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override internal func onDestroy() {
|
|
66
|
+
_resource = nil
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
enum SpatialComponentType:String {
|
|
71
|
+
case ModelComponent = "ModelComponent"
|
|
72
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import RealityKit
|
|
3
|
+
|
|
4
|
+
@Observable
|
|
5
|
+
class SpatialEntity: Entity, SpatialObjectProtocol {
|
|
6
|
+
let spatialId: String
|
|
7
|
+
|
|
8
|
+
private var _isDestroyed: Bool = false
|
|
9
|
+
var isDestroyed: Bool {
|
|
10
|
+
return _isDestroyed
|
|
11
|
+
}
|
|
12
|
+
internal var listeners: [String: [(_ object: Any, _ data: Any) -> Void]] = [:]
|
|
13
|
+
|
|
14
|
+
private var _enableTap: Bool = false
|
|
15
|
+
private var _enableRotate: Bool = false
|
|
16
|
+
private var _enableRotateStart: Bool = false
|
|
17
|
+
private var _enableRotateEnd: Bool = false
|
|
18
|
+
private var _enableDrag: Bool = false
|
|
19
|
+
private var _enableDragStart: Bool = false
|
|
20
|
+
private var _enableDragEnd: Bool = false
|
|
21
|
+
private var _enableMagnify: Bool = false
|
|
22
|
+
private var _enableMagnifyStart: Bool = false
|
|
23
|
+
private var _enableMagnifyEnd: Bool = false
|
|
24
|
+
|
|
25
|
+
internal var rotation: simd_quatd = simd_quatd()
|
|
26
|
+
internal var spatialChildren: [String:SpatialEntity] = [:]
|
|
27
|
+
internal var spatialComponents: [String: SpatialComponent] = [:]
|
|
28
|
+
|
|
29
|
+
var enableTap: Bool {
|
|
30
|
+
return _enableTap
|
|
31
|
+
}
|
|
32
|
+
var enableRotate: Bool {
|
|
33
|
+
return _enableRotate || _enableRotateStart
|
|
34
|
+
}
|
|
35
|
+
var enableDrag: Bool {
|
|
36
|
+
return _enableDrag || _enableDragStart
|
|
37
|
+
}
|
|
38
|
+
var enableMagnify: Bool {
|
|
39
|
+
return _enableMagnify || _enableMagnifyStart
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var enableRotateEnd: Bool {
|
|
43
|
+
return _enableRotateEnd
|
|
44
|
+
}
|
|
45
|
+
var enableDragEnd: Bool {
|
|
46
|
+
return _enableDragEnd
|
|
47
|
+
}
|
|
48
|
+
var enableMagnifyEnd: Bool {
|
|
49
|
+
return _enableMagnifyEnd
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var enableInteractive: Bool {
|
|
53
|
+
return enableTap || enableRotate || enableDrag || enableMagnify || enableRotateEnd || enableDragEnd || enableMagnifyEnd
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
required init() {
|
|
57
|
+
self.spatialId = UUID().uuidString
|
|
58
|
+
super.init()
|
|
59
|
+
SpatialObject.objects[spatialId] = self
|
|
60
|
+
SpatialObjectWeakRefManager.setWeakRef(spatialId, self)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
init(_ _name:String){
|
|
64
|
+
self.spatialId = UUID().uuidString
|
|
65
|
+
super.init()
|
|
66
|
+
self.name = _name
|
|
67
|
+
SpatialObject.objects[spatialId] = self
|
|
68
|
+
SpatialObjectWeakRefManager.setWeakRef(spatialId, self)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func addChild(entity:SpatialEntity){
|
|
72
|
+
spatialChildren[entity.spatialId] = entity
|
|
73
|
+
super.addChild(entity)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
func removeChild(id:String){
|
|
77
|
+
if let entity = spatialChildren[id]{
|
|
78
|
+
super.removeChild(entity)
|
|
79
|
+
spatialChildren.removeValue(forKey: id)
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
print("no child found")
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
func removeFromParent(){
|
|
87
|
+
if let parent = parent as? SpatialEntity{
|
|
88
|
+
parent.removeChild(self)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
func addComponent(_ comp: SpatialComponent) {
|
|
93
|
+
spatialComponents[comp.type.rawValue] = comp
|
|
94
|
+
comp.addToEntity(entity: self)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func removeComponent(_ comp: SpatialComponent) {
|
|
98
|
+
if spatialComponents[comp.type.rawValue] != nil {
|
|
99
|
+
comp.removeFromEntity(entity: self)
|
|
100
|
+
spatialComponents.removeValue(forKey: comp.type.rawValue)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
func updateTransform(_ matrix:[String:Float]){
|
|
105
|
+
transform.matrix = float4x4([matrix["0"]!, matrix["1"]!, matrix["2"]!, matrix["3"]!], [matrix["4"]!, matrix["5"]!, matrix["6"]!, matrix["7"]!], [matrix["8"]!, matrix["9"]!, matrix["10"]!, matrix["11"]!], [matrix["12"]!, matrix["13"]!, matrix["14"]!, matrix["15"]!])
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
func updateGesture(_ type:String, _ isEable:Bool){
|
|
109
|
+
switch WebSpatialGestureType(rawValue: type){
|
|
110
|
+
case .spatialtap:
|
|
111
|
+
_enableTap = isEable
|
|
112
|
+
case .spatialrotate:
|
|
113
|
+
_enableRotate = isEable
|
|
114
|
+
case .spatialrotatestart:
|
|
115
|
+
_enableRotateStart = isEable
|
|
116
|
+
case .spatialrotateend:
|
|
117
|
+
_enableRotateEnd = isEable
|
|
118
|
+
case .spatialdrag:
|
|
119
|
+
_enableDrag = isEable
|
|
120
|
+
case .spatialdragstart:
|
|
121
|
+
_enableDragStart = isEable
|
|
122
|
+
case .spatialdragend:
|
|
123
|
+
_enableDragEnd = isEable
|
|
124
|
+
case .spatialmagnify:
|
|
125
|
+
_enableMagnify = isEable
|
|
126
|
+
case .spatialmagnifystart:
|
|
127
|
+
_enableMagnifyStart = isEable
|
|
128
|
+
case .spatialmagnifyend:
|
|
129
|
+
_enableMagnifyEnd = isEable
|
|
130
|
+
default:
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if enableInteractive {
|
|
135
|
+
if !components.has(InputTargetComponent.self){
|
|
136
|
+
components.set(InputTargetComponent())
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
if components.has(InputTargetComponent.self){
|
|
141
|
+
components.remove(InputTargetComponent.self)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static func findNearestParent(entity: Entity) -> SpatialEntity?{
|
|
147
|
+
if let parent = entity.parent as? SpatialEntity{
|
|
148
|
+
return parent
|
|
149
|
+
}
|
|
150
|
+
else if entity.parent != nil {
|
|
151
|
+
return findNearestParent(entity: entity.parent!)
|
|
152
|
+
}
|
|
153
|
+
return nil
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
func setRotation(_ rotation: simd_quatd) {
|
|
157
|
+
self.rotation = rotation
|
|
158
|
+
self.transform.rotation = simd_quatf(ix: Float(rotation.imag.x), iy: Float(rotation.imag.y), iz: Float(rotation.imag.z), r: Float(rotation.real))
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Encodable
|
|
162
|
+
enum CodingKeys: String, CodingKey {
|
|
163
|
+
case id, name, isDestroyed, children, components
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
func encode(to encoder: any Encoder) throws {
|
|
167
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
168
|
+
try container.encode(spatialId, forKey: .id)
|
|
169
|
+
try container.encode(name, forKey: .name)
|
|
170
|
+
try container.encode(isDestroyed, forKey: .isDestroyed)
|
|
171
|
+
try container.encode(spatialChildren, forKey: .children)
|
|
172
|
+
try container.encode(spatialComponents, forKey: .components)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Equatable
|
|
176
|
+
static func == (lhs: SpatialEntity, rhs: SpatialEntity) -> Bool {
|
|
177
|
+
return lhs.spatialId == rhs.spatialId
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
func destroy() {
|
|
181
|
+
if _isDestroyed {
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
emit(event: SpatialObject.Events.BeforeDestroyed.rawValue, data: ["object": self])
|
|
185
|
+
onDestroy()
|
|
186
|
+
_isDestroyed = true
|
|
187
|
+
|
|
188
|
+
emit(event: SpatialObject.Events.Destroyed.rawValue, data: ["object": self])
|
|
189
|
+
listeners = [:]
|
|
190
|
+
SpatialObject.objects.removeValue(forKey: spatialId)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
internal func onDestroy() {
|
|
194
|
+
if(parent != nil){
|
|
195
|
+
removeFromParent()
|
|
196
|
+
}
|
|
197
|
+
components.removeAll()
|
|
198
|
+
spatialChildren.forEach { id, child in
|
|
199
|
+
child.destroy()
|
|
200
|
+
}
|
|
201
|
+
spatialChildren = [:]
|
|
202
|
+
spatialComponents.forEach { id, components in
|
|
203
|
+
components.destroy()
|
|
204
|
+
}
|
|
205
|
+
spatialComponents = [:]
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
deinit {
|
|
209
|
+
SpatialObjectWeakRefManager.removeWeakRef(spatialId)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import RealityKit
|
|
3
|
+
|
|
4
|
+
@Observable
|
|
5
|
+
class SpatialMaterial: SpatialObject {
|
|
6
|
+
let type: SpatialMaterialType
|
|
7
|
+
|
|
8
|
+
internal var _resource:RealityKit.Material? = nil
|
|
9
|
+
var resource:RealityKit.Material? {
|
|
10
|
+
_resource
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
init(_ _type:SpatialMaterialType){
|
|
14
|
+
type = _type
|
|
15
|
+
super.init()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override func onDestroy() {
|
|
19
|
+
_resource = nil
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@Observable
|
|
24
|
+
class SpatialUnlitMaterial: SpatialMaterial{
|
|
25
|
+
let color:UIColor
|
|
26
|
+
|
|
27
|
+
init(_ color:String, _ texture:TextureResource? = nil, _ transparent:Bool = true, _ opacity:Float = 1){
|
|
28
|
+
self.color = UIColor.init(Color(hex: color))
|
|
29
|
+
super.init(.UnlitMaterial)
|
|
30
|
+
var mat = UnlitMaterial()
|
|
31
|
+
mat.color = .init(tint:UIColor(Color.init(hex: color)), texture: texture != nil ? .init(texture!) : nil)
|
|
32
|
+
mat.blending = transparent ? .transparent(opacity: .init(scale: opacity)) : .opaque
|
|
33
|
+
_resource = mat
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
enum SpatialMaterialType: String{
|
|
38
|
+
case UnlitMaterial = "UnlitMaterial"
|
|
39
|
+
}
|