Skip to content

Commit

Permalink
All code changes and content added for visionOS video #2
Browse files Browse the repository at this point in the history
  • Loading branch information
dilmerv committed Oct 9, 2023
1 parent 130be99 commit 8e00521
Show file tree
Hide file tree
Showing 42 changed files with 740 additions and 311 deletions.
48 changes: 46 additions & 2 deletions Inspiration4.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
0F4A00AF2AB6362C004AE0DE /* FullRocketRealityArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F4A00AE2AB6362C004AE0DE /* FullRocketRealityArea.swift */; };
0F4A00B32AB646D5004AE0DE /* MissionArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F4A00B22AB646D5004AE0DE /* MissionArea.swift */; };
0F4A00B42AB770AF004AE0DE /* Inspiration4.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 0F4A00B12AB646C2004AE0DE /* Inspiration4.mp4 */; };
0FD3612D2AD34C90004746F1 /* EquipmentCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FD3612C2AD34C90004746F1 /* EquipmentCard.swift */; };
0FD3612F2AD38B38004746F1 /* CapsuleDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FD3612E2AD38B38004746F1 /* CapsuleDetails.swift */; };
0FD361322AD38ECE004746F1 /* Sunlight.skybox in Resources */ = {isa = PBXBuildFile; fileRef = 0FD361312AD38ECE004746F1 /* Sunlight.skybox */; };
0FD361352AD38EF5004746F1 /* Entity+Sunlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FD361342AD38EF5004746F1 /* Entity+Sunlight.swift */; };
0FD361382AD394B8004746F1 /* OrbitSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FD361372AD394B8004746F1 /* OrbitSystem.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -42,6 +47,11 @@
0F4A00AE2AB6362C004AE0DE /* FullRocketRealityArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullRocketRealityArea.swift; sourceTree = "<group>"; };
0F4A00B12AB646C2004AE0DE /* Inspiration4.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = Inspiration4.mp4; sourceTree = "<group>"; };
0F4A00B22AB646D5004AE0DE /* MissionArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissionArea.swift; sourceTree = "<group>"; };
0FD3612C2AD34C90004746F1 /* EquipmentCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EquipmentCard.swift; sourceTree = "<group>"; };
0FD3612E2AD38B38004746F1 /* CapsuleDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapsuleDetails.swift; sourceTree = "<group>"; };
0FD361312AD38ECE004746F1 /* Sunlight.skybox */ = {isa = PBXFileReference; lastKnownFileType = file.skybox; path = Sunlight.skybox; sourceTree = "<group>"; };
0FD361342AD38EF5004746F1 /* Entity+Sunlight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Entity+Sunlight.swift"; sourceTree = "<group>"; };
0FD361372AD394B8004746F1 /* OrbitSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrbitSystem.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -81,7 +91,9 @@
0F4A00AB2AB635E8004AE0DE /* RealityViews */,
0F4A00B02AB646B3004AE0DE /* Videos */,
0F4A00872AB3B505004AE0DE /* Inspiration4App.swift */,
0F4A008F2AB3B506004AE0DE /* Assets.xcassets */,
0FD361362AD3949E004746F1 /* Systems */,
0FD361332AD38ED4004746F1 /* Extensions */,
0FD361302AD38EBB004746F1 /* Resources */,
0F4A00942AB3B506004AE0DE /* Info.plist */,
0F4A00912AB3B506004AE0DE /* Preview Content */,
);
Expand All @@ -108,10 +120,12 @@
isa = PBXGroup;
children = (
0F4A009B2AB4FD47004AE0DE /* Areas.swift */,
0F4A00A52AB61968004AE0DE /* NavigationToAreas.swift */,
0F4A00A72AB621D5004AE0DE /* CrewArea.swift */,
0F4A00A92AB628FD004AE0DE /* EquipmentArea.swift */,
0FD3612C2AD34C90004746F1 /* EquipmentCard.swift */,
0F4A00B22AB646D5004AE0DE /* MissionArea.swift */,
0F4A00A52AB61968004AE0DE /* NavigationToAreas.swift */,
0FD3612E2AD38B38004746F1 /* CapsuleDetails.swift */,
);
path = Areas;
sourceTree = "<group>";
Expand Down Expand Up @@ -143,6 +157,31 @@
path = Videos;
sourceTree = "<group>";
};
0FD361302AD38EBB004746F1 /* Resources */ = {
isa = PBXGroup;
children = (
0FD361312AD38ECE004746F1 /* Sunlight.skybox */,
0F4A008F2AB3B506004AE0DE /* Assets.xcassets */,
);
path = Resources;
sourceTree = "<group>";
};
0FD361332AD38ED4004746F1 /* Extensions */ = {
isa = PBXGroup;
children = (
0FD361342AD38EF5004746F1 /* Entity+Sunlight.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
0FD361362AD3949E004746F1 /* Systems */ = {
isa = PBXGroup;
children = (
0FD361372AD394B8004746F1 /* OrbitSystem.swift */,
);
path = Systems;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -207,6 +246,7 @@
0F4A00B42AB770AF004AE0DE /* Inspiration4.mp4 in Resources */,
0F4A00902AB3B506004AE0DE /* Assets.xcassets in Resources */,
0F4A00932AB3B506004AE0DE /* Preview Assets.xcassets in Resources */,
0FD361322AD38ECE004746F1 /* Sunlight.skybox in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -217,15 +257,19 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0FD361352AD38EF5004746F1 /* Entity+Sunlight.swift in Sources */,
0FD3612F2AD38B38004746F1 /* CapsuleDetails.swift in Sources */,
0F4A00A42AB61590004AE0DE /* ViewModel.swift in Sources */,
0F4A00B32AB646D5004AE0DE /* MissionArea.swift in Sources */,
0F4A009C2AB4FD47004AE0DE /* Areas.swift in Sources */,
0F4A00A02AB61372004AE0DE /* Area.swift in Sources */,
0FD3612D2AD34C90004746F1 /* EquipmentCard.swift in Sources */,
0F4A00A82AB621D5004AE0DE /* CrewArea.swift in Sources */,
0F4A00A62AB61968004AE0DE /* NavigationToAreas.swift in Sources */,
0F4A00AD2AB6361B004AE0DE /* CapsuleRealityArea.swift in Sources */,
0F4A00AF2AB6362C004AE0DE /* FullRocketRealityArea.swift in Sources */,
0F4A00A22AB61544004AE0DE /* Crew.swift in Sources */,
0FD361382AD394B8004746F1 /* OrbitSystem.swift in Sources */,
0F4A00882AB3B505004AE0DE /* Inspiration4App.swift in Sources */,
0F4A00AA2AB628FD004AE0DE /* EquipmentArea.swift in Sources */,
);
Expand Down
12 changes: 12 additions & 0 deletions Inspiration4/Areas/Areas.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,24 @@
import SwiftUI

struct Areas: View {
@Environment(ViewModel.self) private var model
@Environment(\.scenePhase) private var scenePhase
@Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace

var body: some View {
ZStack {
NavigationStack {
NavigationToAreas()
}
}

.onChange(of: scenePhase) { _, newScenePhase in
if (model.isShowingFullRocket || model.isShowingMixedRocket) && newScenePhase == .background {
Task {
await dismissImmersiveSpace();
}
}
}
}
}

Expand Down
74 changes: 74 additions & 0 deletions Inspiration4/Areas/CapsuleDetails.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// CapsuleDetails.swift
// Inspiration4
//
// Created by Dilmer Valecillos on 10/8/23.
//

import SwiftUI

struct CapsuleDetails: View {
@State private var orbitOn = false
@State private var lightOn = true
@State private var isShowing = false

let turnOnLight: () -> Void
let turnOffLight: () -> Void
let turnOnOrbit: () -> Void
let turnOffOrbit: () -> Void

var body: some View {
VStack {
Button {
isShowing.toggle()
} label: {
Label("Rocket Options", systemImage: "gear")
}
.controlSize(.mini)
.font(.system(size: 10))
}
if isShowing {
VStack {
Text("The Dragon spacecraft is capable of carrying up to 7 passengers to and from Earth orbit, and beyond. It is the only spacecraft currently flying that is capable of returning significant amounts of cargo to Earth, and is the first private spacecraft to take humans to the space station.")
.font(.system(size: 8))

HStack(alignment:.top) {
VStack(alignment:.leading) {
Toggle(isOn: $lightOn){
Text("Light \(!lightOn ? "Off" : "On")")
.font(.system(size: 8, weight:. bold))
.onChange(of: lightOn, {
if lightOn {
turnOnLight()
}
else
{
turnOffLight()
}
})
}
}

VStack(alignment:.leading) {
Toggle(isOn: $orbitOn){
Text("Orbit \(!orbitOn ? "Off" : "On")")
.font(.system(size: 8, weight:. bold))
.onChange(of: orbitOn, {
if orbitOn {
turnOnOrbit()
}
else
{
turnOffOrbit()
}
})
}
}
}
}
.padding(EdgeInsets(top: 5, leading: 25, bottom: 0, trailing: 25))
.frame(width: 300, height: 120)
.glassBackgroundEffect()
}
}
}
52 changes: 14 additions & 38 deletions Inspiration4/Areas/EquipmentArea.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,23 @@ struct EquipmentArea: View {
@Bindable var model = model

HStack {
VStack {
Image("equipment-capsule")
.resizable()
.frame(width: 300, height: 300)
.padding(20)
Toggle(model.isShowingRocketCapsule ? "Hide Rocket Capsule (Volumetric)" : "Show Rocket Capsule (Volumetric)", isOn: $model.isShowingRocketCapsule)
.onChange(of: model.isShowingRocketCapsule) { _, isShowing in
if isShowing {
openWindow(id: "CapsuleRealityArea")
}
else
{
dismissWindow(id: "CapsuleRealityArea")
}
}
.toggleStyle(.button)
.padding(25)
EquipmentCard(isShowing: $model.isShowingRocketCapsule, toggleTitle: "Rocket Capsule (Volumetric)", imageName: "equipment-capsule") {
openWindow(id: model.capsuleRealityAreaId)
} dismissCard: {
dismissWindow(id: model.capsuleRealityAreaId)
}
.glassBackgroundEffect()

VStack {
Image("equipment-fullrocket")
.resizable()
.frame(width: 300, height: 300)
.padding(20)
Toggle(model.isShowingFullRocket ? "Hide Full Rocket (Full Immersed)" : "Show Show Full Rocket (Full Immersed)", isOn: $model.isShowingFullRocket)
.onChange(of: model.isShowingFullRocket) { _, isShowing in
Task {
if isShowing {
await openImmersiveSpace(id: "FullRocketRealityArea")
}
else
{
await dismissImmersiveSpace()
}
}
}
.toggleStyle(.button)
.padding(25)
EquipmentCard(isShowing: $model.isShowingFullRocket, toggleTitle: "Rocket (Full Immersive Space)", imageName: "equipment-fullrocket") {
await openImmersiveSpace(id: model.fullRocketRealityArea)
} dismissCard: {
await dismissImmersiveSpace()
}

EquipmentCard(isShowing: $model.isShowingMixedRocket, toggleTitle: "Rocket (Mixed Immersive Space)", imageName: "equipment-mixedrocket") {
await openImmersiveSpace(id: model.mixedRocketRealityArea)
} dismissCard: {
await dismissImmersiveSpace()
}
.glassBackgroundEffect()
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions Inspiration4/Areas/EquipmentCard.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// EquipmentCard.swift
// Inspiration4
//
// Created by Dilmer Valecillos on 10/8/23.
//

import SwiftUI

struct EquipmentCard: View {
@Binding var isShowing: Bool
let toggleTitle: String
let imageName: String
let openCard: () async -> Void
let dismissCard: () async -> Void

var body: some View {
VStack {
Image(imageName)
.resizable()
.frame(width: 300, height: 300)
.padding(20)

Toggle(isShowing ? "Hide \(toggleTitle)" : "Show \(toggleTitle)", isOn: $isShowing)
.onChange(of: isShowing, initial: false) { isShowing, initial in
Task {
if !isShowing {
await openCard()
} else {
await dismissCard()
}
}
}
.toggleStyle(.button)
.padding(25)
}
.glassBackgroundEffect()
}
}
21 changes: 21 additions & 0 deletions Inspiration4/Extensions/Entity+Sunlight.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Credits to Apple for providing this example!
import RealityKit

extension Entity {
func setSunlight(intensity: Float?) {
if let intensity {
Task {
guard let resource = try? await EnvironmentResource(named: "Sunlight") else { return }
var iblComponent = ImageBasedLightComponent(
source: .single(resource),
intensityExponent: intensity)

components.set(iblComponent)
components.set(ImageBasedLightReceiverComponent(imageBasedLight: self))
}
} else {
components.remove(ImageBasedLightComponent.self)
components.remove(ImageBasedLightReceiverComponent.self)
}
}
}
19 changes: 16 additions & 3 deletions Inspiration4/Inspiration4App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,28 @@ struct Inspiration4App: App {
//.defaultSize(CGSize(width: 200, height: 150))
//.defaultSize(width: 0.6, height: 0.3, depth: 0.6, in: .meters)

WindowGroup(id: "CapsuleRealityArea"){
WindowGroup(id: model.capsuleRealityAreaId){
CapsuleRealityArea()
.environment(model)
}
.windowStyle(.volumetric)
.defaultSize(width: 0.6, height: 0.6, depth: 0.6, in: .meters)
.defaultSize(width: 0.65, height: 0.3, depth: 0.3, in: .meters)

ImmersiveSpace(id: "FullRocketRealityArea"){
ImmersiveSpace(id: model.fullRocketRealityArea){
FullRocketRealityArea()
.environment(model)
}
.immersionStyle(selection: .constant(.full), in: .full)

ImmersiveSpace(id: model.mixedRocketRealityArea){
FullRocketRealityArea()
.environment(model)
}
.immersionStyle(selection: .constant(.mixed), in: .mixed)
}

init(){
OrbitComponent.registerComponent()
OrbitSystem.registerSystem()
}
}
5 changes: 5 additions & 0 deletions Inspiration4/Models/ViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ class ViewModel
var navigationPath : [Area] = []
var isShowingRocketCapsule : Bool = false
var isShowingFullRocket : Bool = false
var isShowingMixedRocket : Bool = false

var capsuleRealityAreaId: String = "CapsuleRealityArea"
var fullRocketRealityArea: String = "FullRocketRealityArea"
var mixedRocketRealityArea: String = "MixedRocketRealityArea"
}
Loading

0 comments on commit 8e00521

Please sign in to comment.