@webspatial/platform-visionos 1.2.1 → 1.3.0
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 +1 -1
- package/web-spatial/EventEmitter.swift +11 -11
- package/web-spatial/JSBCommand.swift +15 -3
- package/web-spatial/WebMsgCommand.swift +7 -3
- package/web-spatial/WebSpatialApp.swift +10 -10
- package/web-spatial/Window.swift +2 -2
- package/web-spatial/manager/AttachmentManager.swift +81 -0
- package/web-spatial/manager/JSBManager.swift +1 -2
- package/web-spatial/manifest.swift +1 -1
- package/web-spatial/model/SpatialApp.swift +59 -55
- package/web-spatial/model/SpatialScene.swift +97 -14
- package/web-spatial/model/Spatialized2DElement.swift +4 -5
- package/web-spatial/model/SpatializedStatic3DElement.swift +1 -1
- package/web-spatial/model/dynamic3d/SpatialComponent.swift +27 -27
- package/web-spatial/model/dynamic3d/SpatialEntity.swift +2 -2
- package/web-spatial/model/dynamic3d/SpatialMaterial.swift +15 -15
- package/web-spatial/model/dynamic3d/SpatialModelEntity.swift +10 -10
- package/web-spatial/model/dynamic3d/SpatialModelResource.swift +1 -1
- package/web-spatial/model/dynamic3d/SpatialTextureResource.swift +8 -8
- package/web-spatial/view/SpatialNavView.swift +52 -47
- package/web-spatial/view/SpatializedDynamic3DView.swift +68 -4
- package/web-spatial/view/SpatializedElementView.swift +28 -13
- package/web-spatial/view/SpatializedStatic3DView.swift +4 -6
- package/web-spatial/view/view-modifier/HideViewModifier.swift +2 -2
- package/web-spatial/webview/SpatialWebController.swift +27 -24
- package/web-spatial/webview/SpatialWebView.swift +5 -1
- package/web-spatial/webview/SpatialWebViewModel.swift +13 -7
- package/web-spatial.xcodeproj/project.pbxproj +13 -0
- package/web-spatialTests/NavigationCleanupTests.swift +33 -0
|
@@ -38,7 +38,9 @@ let defaultSceneConfig = SceneOptions(
|
|
|
38
38
|
class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSender {
|
|
39
39
|
var parent: (any ScrollAbleSpatialElementContainer)?
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
var attachmentManager = AttachmentManager()
|
|
42
|
+
|
|
43
|
+
/// Enum
|
|
42
44
|
enum WindowStyle: String, Codable, CaseIterable {
|
|
43
45
|
case window
|
|
44
46
|
case volume
|
|
@@ -66,15 +68,15 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
enum SceneStateKind: String {
|
|
69
|
-
|
|
71
|
+
/// default value
|
|
70
72
|
case idle
|
|
71
|
-
|
|
73
|
+
/// when SpatialScene is loading
|
|
72
74
|
case pending
|
|
73
|
-
|
|
75
|
+
/// when SpatialScen will visible after some time
|
|
74
76
|
case willVisible
|
|
75
|
-
|
|
77
|
+
/// when SpatialScen load Succesfully
|
|
76
78
|
case visible
|
|
77
|
-
|
|
79
|
+
/// when SpatialScen Failed to load
|
|
78
80
|
case fail
|
|
79
81
|
}
|
|
80
82
|
|
|
@@ -101,7 +103,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
101
103
|
moveToState(state, sceneOptions)
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
/// used to send message to spatial root webview
|
|
105
107
|
func sendWebMsg(_ id: String, _ msg: Encodable) {
|
|
106
108
|
spatialWebViewModel.sendWebEvent(id, msg)
|
|
107
109
|
}
|
|
@@ -299,6 +301,8 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
299
301
|
spatialWebViewModel.addJSBListener(ConvertFromEntityToScene.self, onConvertFromEntityToScene)
|
|
300
302
|
spatialWebViewModel.addJSBListener(ConvertFromSceneToEntity.self, onConvertFromSceneToEntity)
|
|
301
303
|
|
|
304
|
+
spatialWebViewModel.addJSBListener(UpdateAttachmentEntityCommand.self, onUpdateAttachmentEntity)
|
|
305
|
+
|
|
302
306
|
spatialWebViewModel.addOpenWindowListener(protocal: "webspatial", onOpenWindowHandler)
|
|
303
307
|
|
|
304
308
|
spatialWebViewModel
|
|
@@ -380,6 +384,8 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
380
384
|
let host = url.host ?? ""
|
|
381
385
|
if host == "createSpatialScene" {
|
|
382
386
|
return handleWindowOpenCustom(url)
|
|
387
|
+
} else if host == "createAttachment" {
|
|
388
|
+
return handleCreateAttachment(url)
|
|
383
389
|
} else {
|
|
384
390
|
let spatialized2DElement: Spatialized2DElement = createSpatializedElement(
|
|
385
391
|
.Spatialized2DElement
|
|
@@ -388,15 +394,66 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
388
394
|
}
|
|
389
395
|
}
|
|
390
396
|
|
|
397
|
+
private func handleCreateAttachment(_ url: URL) -> WebViewElementInfo? {
|
|
398
|
+
guard let components = URLComponents(string: url.absoluteString),
|
|
399
|
+
let queryItems = components.queryItems
|
|
400
|
+
else {
|
|
401
|
+
print("❌ fail to parse attachment URL")
|
|
402
|
+
return nil
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
guard let parentEntityId = queryItems.first(where: { $0.name == "parentEntityId" })?.value else {
|
|
406
|
+
print("❌ missing parentEntityId for attachment")
|
|
407
|
+
return nil
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Parse position (JSON array like [0,0.1,0])
|
|
411
|
+
var position = SIMD3<Float>(0, 0, 0)
|
|
412
|
+
if let positionStr = queryItems.first(where: { $0.name == "position" })?.value?.removingPercentEncoding,
|
|
413
|
+
let positionData = positionStr.data(using: .utf8),
|
|
414
|
+
let positionArray = try? JSONDecoder().decode([Float].self, from: positionData),
|
|
415
|
+
positionArray.count >= 3
|
|
416
|
+
{
|
|
417
|
+
position = SIMD3<Float>(positionArray[0], positionArray[1], positionArray[2])
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Parse size (JSON object like {"width":100,"height":100})
|
|
421
|
+
var size = CGSize(width: 100, height: 100)
|
|
422
|
+
if let sizeStr = queryItems.first(where: { $0.name == "size" })?.value?.removingPercentEncoding,
|
|
423
|
+
let sizeData = sizeStr.data(using: .utf8),
|
|
424
|
+
let sizeObj = try? JSONDecoder().decode(AttachmentSize.self, from: sizeData)
|
|
425
|
+
{
|
|
426
|
+
size = CGSize(width: sizeObj.width, height: sizeObj.height)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
let info = attachmentManager.create(
|
|
430
|
+
id: UUID().uuidString,
|
|
431
|
+
parentEntityId: parentEntityId,
|
|
432
|
+
position: position,
|
|
433
|
+
size: size
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
return WebViewElementInfo(id: info.id, element: info.webViewModel)
|
|
437
|
+
}
|
|
438
|
+
|
|
391
439
|
private func onPageStartLoad() {
|
|
392
440
|
// destroy all SpatialObject asset
|
|
393
441
|
let spatialObjectArray = spatialObjects.map { $0.value }
|
|
394
442
|
for spatialObject in spatialObjectArray {
|
|
395
443
|
spatialObject.destroy()
|
|
396
444
|
}
|
|
445
|
+
// destroy all attachments
|
|
446
|
+
attachmentManager.destroyAll()
|
|
397
447
|
backgroundMaterial = .None
|
|
398
448
|
}
|
|
399
449
|
|
|
450
|
+
/// Some SPA navigations (history back/forward) do not trigger a full WKNavigation
|
|
451
|
+
/// lifecycle. SpatialNavView calls this before navigation actions to ensure
|
|
452
|
+
/// previously-created spatial objects are cleaned up.
|
|
453
|
+
func resetForNavigation() {
|
|
454
|
+
onPageStartLoad()
|
|
455
|
+
}
|
|
456
|
+
|
|
400
457
|
private func onGetSpatialSceneState(
|
|
401
458
|
command: GetSpatialSceneStateCommand,
|
|
402
459
|
resolve: @escaping JSBManager.ResolveHandler<Encodable>
|
|
@@ -424,6 +481,12 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
424
481
|
}
|
|
425
482
|
|
|
426
483
|
private func onDestroySpatialObjectCommand(command: DestroyCommand, resolve: @escaping JSBManager.ResolveHandler<Encodable>) {
|
|
484
|
+
// Check if it's an attachment first
|
|
485
|
+
if attachmentManager.get(id: command.id) != nil {
|
|
486
|
+
attachmentManager.remove(id: command.id)
|
|
487
|
+
resolve(.success(nil))
|
|
488
|
+
return
|
|
489
|
+
}
|
|
427
490
|
if let spatialObject: SpatialObject = findSpatialObject(command.id) {
|
|
428
491
|
spatialObject.destroy()
|
|
429
492
|
resolve(.success(nil))
|
|
@@ -698,21 +761,21 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
698
761
|
* Begin Implement SpatializedElementContainer Protocol
|
|
699
762
|
*/
|
|
700
763
|
|
|
701
|
-
|
|
764
|
+
/// SpatialScene can hold a collection of SpatializedElement children
|
|
702
765
|
private var children = [String: SpatializedElement]()
|
|
703
766
|
|
|
704
|
-
|
|
767
|
+
/// Called by SpatializedElement.setParent
|
|
705
768
|
func addChild(_ spatializedElement: SpatializedElement) {
|
|
706
769
|
children[spatializedElement.id] = spatializedElement
|
|
707
770
|
}
|
|
708
771
|
|
|
709
|
-
|
|
772
|
+
/// Called by SpatializedElement.setParent
|
|
710
773
|
func removeChild(_ spatializedElement: SpatializedElement) {
|
|
711
774
|
children.removeValue(forKey: spatializedElement.id)
|
|
712
775
|
}
|
|
713
776
|
|
|
714
777
|
func getChildrenOfType(_ type: SpatializedElementType) -> [String: SpatializedElement] {
|
|
715
|
-
|
|
778
|
+
return children.filter {
|
|
716
779
|
switch type {
|
|
717
780
|
case .Spatialized2DElement:
|
|
718
781
|
return $0.value is Spatialized2DElement
|
|
@@ -722,7 +785,6 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
722
785
|
return $0.value is SpatializedDynamic3DElement
|
|
723
786
|
}
|
|
724
787
|
}
|
|
725
|
-
return typedChildren
|
|
726
788
|
}
|
|
727
789
|
|
|
728
790
|
func getChildren() -> [String: SpatializedElement] {
|
|
@@ -733,7 +795,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
733
795
|
* End Implement SpatializedElementContainer Protocol
|
|
734
796
|
*/
|
|
735
797
|
|
|
736
|
-
|
|
798
|
+
/**
|
|
737
799
|
* Begin Implement SpatialScrollAble Protocol
|
|
738
800
|
*/
|
|
739
801
|
let scrollPageEnabled: Bool = true
|
|
@@ -789,7 +851,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
789
851
|
* Begin SpatialObjects management
|
|
790
852
|
*/
|
|
791
853
|
|
|
792
|
-
|
|
854
|
+
/// Resources that will be destroyed when this webpage is destoryed or if it is navigated away from
|
|
793
855
|
private var spatialObjects = [String: any SpatialObjectProtocol]()
|
|
794
856
|
|
|
795
857
|
func createSpatializedElement<T: SpatializedElement>(_ type: SpatializedElementType) -> T {
|
|
@@ -1006,6 +1068,26 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
1006
1068
|
resolve(.success(ConvertReply(id: command.entityId, position: point)))
|
|
1007
1069
|
}
|
|
1008
1070
|
|
|
1071
|
+
private func onUpdateAttachmentEntity(command: UpdateAttachmentEntityCommand, resolve: @escaping JSBManager.ResolveHandler<Encodable>) {
|
|
1072
|
+
guard attachmentManager.get(id: command.id) != nil else {
|
|
1073
|
+
resolve(.failure(JsbError(code: .InvalidSpatialObject, message: "Attachment \(command.id) not found")))
|
|
1074
|
+
return
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
var newPosition: SIMD3<Float>? = nil
|
|
1078
|
+
if let posArray = command.position, posArray.count >= 3 {
|
|
1079
|
+
newPosition = SIMD3<Float>(posArray[0], posArray[1], posArray[2])
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
var newSize: CGSize? = nil
|
|
1083
|
+
if let sizeObj = command.size {
|
|
1084
|
+
newSize = CGSize(width: sizeObj.width, height: sizeObj.height)
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
attachmentManager.update(id: command.id, position: newPosition, size: newSize)
|
|
1088
|
+
resolve(.success(baseReplyData))
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1009
1091
|
private func addSpatialObject(_ object: any SpatialObjectProtocol) {
|
|
1010
1092
|
var spatialObject = object
|
|
1011
1093
|
spatialObjects[spatialObject.spatialId] = spatialObject
|
|
@@ -1042,6 +1124,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
|
|
|
1042
1124
|
for spatialObject in spatialObjectArray {
|
|
1043
1125
|
spatialObject.destroy()
|
|
1044
1126
|
}
|
|
1127
|
+
attachmentManager.destroyAll()
|
|
1045
1128
|
spatialWebViewModel.destroy()
|
|
1046
1129
|
}
|
|
1047
1130
|
|
|
@@ -57,15 +57,15 @@ class Spatialized2DElement: SpatializedElement, ScrollAbleSpatialElementContaine
|
|
|
57
57
|
defaultAlignment = .center
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
/// Spatialized2DElement can hold a collection of SpatializedElement children
|
|
61
61
|
private var children = [String: SpatializedElement]()
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
/// Called by SpatializedElement.setParent
|
|
64
64
|
func addChild(_ spatializedElement: SpatializedElement) {
|
|
65
65
|
children[spatializedElement.id] = spatializedElement
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
/// Called by SpatializedElement.setParent
|
|
69
69
|
func removeChild(_ spatializedElement: SpatializedElement) {
|
|
70
70
|
children.removeValue(forKey: spatializedElement.id)
|
|
71
71
|
}
|
|
@@ -75,7 +75,7 @@ class Spatialized2DElement: SpatializedElement, ScrollAbleSpatialElementContaine
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
func getChildrenOfType(_ type: SpatializedElementType) -> [String: SpatializedElement] {
|
|
78
|
-
|
|
78
|
+
return children.filter {
|
|
79
79
|
switch type {
|
|
80
80
|
case .Spatialized2DElement:
|
|
81
81
|
return $0.value is Spatialized2DElement
|
|
@@ -85,7 +85,6 @@ class Spatialized2DElement: SpatializedElement, ScrollAbleSpatialElementContaine
|
|
|
85
85
|
return $0.value is SpatializedDynamic3DElement
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
return typedChildren
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
func loadHtml(_ html: String) {
|
|
@@ -4,7 +4,7 @@ import SwiftUI
|
|
|
4
4
|
@Observable
|
|
5
5
|
class SpatializedStatic3DElement: SpatializedElement {
|
|
6
6
|
var modelURL: String = ""
|
|
7
|
-
var modelTransform: AffineTransform3D =
|
|
7
|
+
var modelTransform: AffineTransform3D = .identity
|
|
8
8
|
|
|
9
9
|
enum CodingKeys: String, CodingKey {
|
|
10
10
|
case modelURL, type
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import SwiftUI
|
|
2
1
|
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
3
|
|
|
4
4
|
@Observable
|
|
5
5
|
class SpatialComponent: SpatialObject {
|
|
6
6
|
let type: SpatialComponentType
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
var resource:Component? {
|
|
7
|
+
|
|
8
|
+
var _resource: Component?
|
|
9
|
+
var resource: Component? {
|
|
11
10
|
_resource
|
|
12
11
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
var entity:SpatialEntity? {
|
|
12
|
+
|
|
13
|
+
var _entity: SpatialEntity?
|
|
14
|
+
var entity: SpatialEntity? {
|
|
16
15
|
_entity
|
|
17
16
|
}
|
|
18
|
-
|
|
19
|
-
init(_ _type:SpatialComponentType){
|
|
17
|
+
|
|
18
|
+
init(_ _type: SpatialComponentType) {
|
|
20
19
|
type = _type
|
|
21
20
|
super.init()
|
|
22
21
|
}
|
|
23
|
-
|
|
24
|
-
func addToEntity(entity:SpatialEntity){
|
|
22
|
+
|
|
23
|
+
func addToEntity(entity: SpatialEntity) {
|
|
25
24
|
if _entity != nil {
|
|
26
25
|
print("This component has already been added to another entity")
|
|
27
26
|
return
|
|
28
27
|
}
|
|
29
|
-
if let component = resource{
|
|
28
|
+
if let component = resource {
|
|
30
29
|
_entity = entity
|
|
31
30
|
entity.components.set(component)
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
func removeFromEntity(entity:SpatialEntity){
|
|
33
|
+
|
|
34
|
+
func removeFromEntity(entity: SpatialEntity) {
|
|
36
35
|
if let component = resource,
|
|
37
|
-
self.entity == entity
|
|
36
|
+
self.entity == entity
|
|
37
|
+
{
|
|
38
38
|
entity.components.remove(Swift.type(of: component))
|
|
39
39
|
_entity = nil
|
|
40
40
|
}
|
|
@@ -43,30 +43,30 @@ class SpatialComponent: SpatialObject {
|
|
|
43
43
|
|
|
44
44
|
@Observable
|
|
45
45
|
class SpatialModelComponent: SpatialComponent {
|
|
46
|
-
init(mesh:Geometry, mats:[SpatialMaterial]){
|
|
46
|
+
init(mesh: Geometry, mats: [SpatialMaterial]) {
|
|
47
47
|
super.init(.ModelComponent)
|
|
48
|
-
var materials:[any RealityKit.Material] = []
|
|
49
|
-
|
|
48
|
+
var materials: [any RealityKit.Material] = []
|
|
49
|
+
for item in mats {
|
|
50
50
|
materials.append(item.resource!)
|
|
51
51
|
}
|
|
52
52
|
_resource = ModelComponent(mesh: mesh.resource!, materials: materials)
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
override func addToEntity(entity:SpatialEntity){
|
|
54
|
+
|
|
55
|
+
override func addToEntity(entity: SpatialEntity) {
|
|
56
56
|
super.addToEntity(entity: entity)
|
|
57
57
|
entity.generateCollisionShapes(recursive: true)
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
override func removeFromEntity(entity:SpatialEntity){
|
|
59
|
+
|
|
60
|
+
override func removeFromEntity(entity: SpatialEntity) {
|
|
61
61
|
super.removeFromEntity(entity: entity)
|
|
62
62
|
entity.generateCollisionShapes(recursive: true)
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
override
|
|
64
|
+
|
|
65
|
+
override func onDestroy() {
|
|
66
66
|
_resource = nil
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
enum SpatialComponentType:String {
|
|
71
|
-
case ModelComponent
|
|
70
|
+
enum SpatialComponentType: String {
|
|
71
|
+
case ModelComponent
|
|
72
72
|
}
|
|
@@ -159,7 +159,7 @@ class SpatialEntity: Entity, SpatialObjectProtocol {
|
|
|
159
159
|
transform.rotation = simd_quatf(ix: Float(rotation.imag.x), iy: Float(rotation.imag.y), iz: Float(rotation.imag.z), r: Float(rotation.real))
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
/// Encodable
|
|
163
163
|
enum CodingKeys: String, CodingKey {
|
|
164
164
|
case id, name, isDestroyed, children, components
|
|
165
165
|
}
|
|
@@ -173,7 +173,7 @@ class SpatialEntity: Entity, SpatialObjectProtocol {
|
|
|
173
173
|
try container.encode(spatialComponents, forKey: .components)
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
/// Equatable
|
|
177
177
|
static func == (lhs: SpatialEntity, rhs: SpatialEntity) -> Bool {
|
|
178
178
|
return lhs.spatialId == rhs.spatialId
|
|
179
179
|
}
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import SwiftUI
|
|
2
1
|
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
3
|
|
|
4
4
|
@Observable
|
|
5
5
|
class SpatialMaterial: SpatialObject {
|
|
6
6
|
let type: SpatialMaterialType
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var resource:RealityKit.Material? {
|
|
7
|
+
|
|
8
|
+
var _resource: RealityKit.Material?
|
|
9
|
+
var resource: RealityKit.Material? {
|
|
10
10
|
_resource
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
init(_ _type:SpatialMaterialType){
|
|
12
|
+
|
|
13
|
+
init(_ _type: SpatialMaterialType) {
|
|
14
14
|
type = _type
|
|
15
15
|
super.init()
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
override func onDestroy() {
|
|
19
19
|
_resource = nil
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
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
|
|
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(Color(hex: color))
|
|
29
29
|
super.init(.UnlitMaterial)
|
|
30
30
|
var mat = UnlitMaterial()
|
|
31
|
-
mat.color = .init(tint:UIColor(Color
|
|
31
|
+
mat.color = .init(tint: UIColor(Color(hex: color)), texture: texture != nil ? .init(texture!) : nil)
|
|
32
32
|
mat.blending = transparent ? .transparent(opacity: .init(scale: opacity)) : .opaque
|
|
33
33
|
_resource = mat
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
enum SpatialMaterialType: String{
|
|
38
|
-
case UnlitMaterial
|
|
37
|
+
enum SpatialMaterialType: String {
|
|
38
|
+
case UnlitMaterial
|
|
39
39
|
}
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import SwiftUI
|
|
2
1
|
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
3
|
|
|
4
4
|
@Observable
|
|
5
|
-
class SpatialModelEntity: SpatialEntity{
|
|
6
|
-
private var modelEntity:Entity?
|
|
7
|
-
required init(_ modelResource:SpatialModelResource, _ _name:String = ""){
|
|
5
|
+
class SpatialModelEntity: SpatialEntity {
|
|
6
|
+
private var modelEntity: Entity?
|
|
7
|
+
required init(_ modelResource: SpatialModelResource, _ _name: String = "") {
|
|
8
8
|
super.init(_name)
|
|
9
9
|
modelEntity = modelResource.resource
|
|
10
10
|
addChild(modelEntity!)
|
|
11
11
|
generateCollisionShapes(recursive: true)
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
required init() {
|
|
15
15
|
super.init()
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
override
|
|
17
|
+
|
|
18
|
+
override func onDestroy() {
|
|
19
19
|
super.onDestroy()
|
|
20
|
-
if let modelEntity =
|
|
20
|
+
if let modelEntity = modelEntity {
|
|
21
21
|
removeChild(modelEntity)
|
|
22
22
|
}
|
|
23
23
|
modelEntity = nil
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
enum CodingKeys: String, CodingKey {
|
|
27
27
|
case id, name, isDestroyed, children, components, model
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
override func encode(to encoder: any Encoder) throws {
|
|
31
31
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
32
32
|
try container.encode(spatialId, forKey: .id)
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import SwiftUI
|
|
2
1
|
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
3
|
|
|
4
4
|
@Observable
|
|
5
|
-
class SpatialTextureResource:SpatialObject {
|
|
6
|
-
|
|
7
|
-
var resource:TextureResource? {
|
|
5
|
+
class SpatialTextureResource: SpatialObject {
|
|
6
|
+
var _resource: TextureResource?
|
|
7
|
+
var resource: TextureResource? {
|
|
8
8
|
_resource
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
override init(_ url:String){
|
|
10
|
+
|
|
11
|
+
override init(_ url: String) {
|
|
12
12
|
super.init()
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
override
|
|
14
|
+
|
|
15
|
+
override func onDestroy() {
|
|
16
16
|
_resource = nil
|
|
17
17
|
}
|
|
18
18
|
}
|