From f595fefa71d54f9bbc8da1f0c54dd3e0acd2aa39 Mon Sep 17 00:00:00 2001 From: Max Cobb Date: Sun, 22 Nov 2020 12:16:12 +0000 Subject: [PATCH 1/7] added initial ruitext version, minimal documentation --- .../ViewController+RealityControls.swift | 3 + Sources/RealityUI/HasClick.swift | 5 - Sources/RealityUI/RUIStepper.swift | 5 - Sources/RealityUI/RUISwitch.swift | 9 +- Sources/RealityUI/RUIText.swift | 175 ++++++++++++++++++ Sources/RealityUI/RealityUI.swift | 7 +- 6 files changed, 185 insertions(+), 19 deletions(-) create mode 100644 Sources/RealityUI/RUIText.swift diff --git a/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift b/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift index 86691d2..0340f3e 100644 --- a/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift +++ b/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift @@ -129,5 +129,8 @@ extension ViewController { } }) self.arView.scene.addAnchor(controlsAnchor) + let textAbove = RUIText(with: "RealityUI") + textAbove.look(at: [0, 1.5, 0], from: [0, 1.5, -1], relativeTo: nil) + controlsAnchor.addChild(textAbove) } } diff --git a/Sources/RealityUI/HasClick.swift b/Sources/RealityUI/HasClick.swift index 6ab4ddc..bb40891 100644 --- a/Sources/RealityUI/HasClick.swift +++ b/Sources/RealityUI/HasClick.swift @@ -7,11 +7,6 @@ // import RealityKit -#if os(iOS) -import UIKit -#elseif os(macOS) -import AppKit -#endif public protocol HasClick: HasRUI, HasCollision { var tapAction: ((HasClick, SIMD3?) -> Void)? {get set} diff --git a/Sources/RealityUI/RUIStepper.swift b/Sources/RealityUI/RUIStepper.swift index 391af1a..47ef235 100644 --- a/Sources/RealityUI/RUIStepper.swift +++ b/Sources/RealityUI/RUIStepper.swift @@ -8,11 +8,6 @@ import RealityKit import Combine -#if os(iOS) -import UIKit -#elseif os(macOS) -import AppKit -#endif /// A new RealityUI Stepper to be added to your RealityKit scene. public class RUIStepper: Entity, HasRUI, HasStepper { diff --git a/Sources/RealityUI/RUISwitch.swift b/Sources/RealityUI/RUISwitch.swift index a2bf6a1..ff64546 100644 --- a/Sources/RealityUI/RUISwitch.swift +++ b/Sources/RealityUI/RUISwitch.swift @@ -7,11 +7,6 @@ // import RealityKit -#if os(iOS) -import UIKit -#elseif os(macOS) -import AppKit -#endif /// A RealityUI Switch to be added to a RealityKit scene. public class RUISwitch: Entity, HasSwitch, HasClick { @@ -48,7 +43,7 @@ public class RUISwitch: Entity, HasSwitch, HasClick { } } -public protocol HasSwitch: HasClick { +public protocol HasSwitch: HasRUI { var switchChanged: ((HasSwitch) -> Void)? { get set } } @@ -190,7 +185,7 @@ public extension HasSwitch { let thumb = self.addModel(part: .thumb) thumb.model = ModelComponent(mesh: .generateSphere(radius: (1 - padding) / 2), materials: []) thumb.position = togglePos - self.collision = CollisionComponent( + (self as? HasCollision)?.collision = CollisionComponent( shapes: [ShapeResource.generateCapsule(height: 2, radius: 0.5) .offsetBy(rotation: simd_quatf(angle: .pi/2, axis: [0, 0, 1])) ] diff --git a/Sources/RealityUI/RUIText.swift b/Sources/RealityUI/RUIText.swift new file mode 100644 index 0000000..e06190d --- /dev/null +++ b/Sources/RealityUI/RUIText.swift @@ -0,0 +1,175 @@ +// +// RUIText.swift +// +// +// Created by Max Cobb on 21/11/2020. +// + +import CoreGraphics +import RealityKit + +/// A RealityUI Text object to be added to a RealityKit scene. +open class RUIText: Entity, HasText, HasClick { + public var tapAction: ((HasClick, SIMD3?) -> Void)? { + didSet { + self.updateCollision() + } + } + + convenience init( + with text: String, width: CGFloat = 0, height: CGFloat = 0, + font: MeshResource.Font = RUIText.mediumFont, extrusion: Float = 0.1, + color: Material.Color = .green + ) { + let textComponent = TextComponent( + text: text, font: font, + width: width, height: height, + color: color, extrusion: extrusion + ) + self.init(textComponent: textComponent) + } + + /// Creates a RealityUI Text entity. + /// - Parameters: + /// - textComponent: Details about the text object, including text, font, extrusion and others. + /// - RUI: Details about the RealityUI Entity. + /// - tapAction: callback function to receive updates touchUpInside the RealityUI Text. + required public init( + textComponent: TextComponent? = nil, RUI: RUIComponent = RUIComponent(), + tapAction: ((HasClick, SIMD3?) -> Void)? = nil + ) { + self.tapAction = tapAction + super.init() + self.RUI = RUI + self.textComponent = textComponent ?? TextComponent() + self.makeModels() + } + + func makeModels() { + self.addModel(part: .textEntity) + .look(at: [0, 0, 1], from: .zero, upVector: [0, 1, 0], relativeTo: self) + self.setText(self.text) + } + + required public init() { + fatalError("init() has not been implemented") + } +} + +public struct TextComponent: Component { + var text: String? = nil + var font: MeshResource.Font = .systemFont(ofSize: 0.1) + var width: CGFloat = 0 + var height: CGFloat = 0 + #if os(iOS) + var color: Material.Color = .label + #elseif os(macOS) + var color: Material.Color = .labelColor + #endif + var extrusion: Float = 1 + + enum UIPart: String { + case textEntity + } +} + +public protocol HasText: HasRUI {} +public extension HasText { + var textComponent: TextComponent { + get { self.components[TextComponent.self] ?? TextComponent() } + set { self.components[TextComponent.self] = newValue } + } + var text: String? { + get { self.textComponent.text } + set { + self.setText(newValue) + } + } + + var textModel: ModelComponent? { + get { self.getModel(part: .textEntity)?.model } + set { self.addModel(part: .textEntity).model = newValue } + } + + var font: MeshResource.Font { + self.textComponent.font + } + var color: Material.Color { + self.textComponent.color + } + + private func getModel(part: TextComponent.UIPart) -> ModelEntity? { + return (self as HasRUI).getModel(part: part.rawValue) + } + + internal func addModel(part: TextComponent.UIPart) -> ModelEntity { + self.addModel(part: part.rawValue) + } + + + func updateMaterials() { + self.getModel(part: .textEntity)?.model?.materials = [self.getMaterial(with: self.textComponent.color)] + } + func setText(_ text: String?) { + guard let text = text else { + self.getModel(part: .textEntity)?.model = nil + return + } + let textMesh = MeshResource.generateText( + text, + extrusionDepth: self.textComponent.extrusion, + font: self.font, + containerFrame: .init( + origin: .zero, + size: CGSize(width: self.textComponent.width, height: self.textComponent.height)), + alignment: .center, + lineBreakMode: .byWordWrapping + ) + + self.textModel = ModelComponent(mesh: textMesh, materials: [SimpleMaterial(color: self.textComponent.color, isMetallic: false)]) + self.getModel(part: .textEntity)?.model = self.textModel + guard let textModel = self.textModel else { + return + } + let textSize = textModel.mesh.bounds.extents + let textOffset = -textModel.mesh.bounds.center + self.getModel(part: .textEntity)?.position = [ + -textOffset.x, + textOffset.y, + -textSize.z / 2 + ] + self.updateCollision() + } + func updateCollision() { + guard let selfCol = (self as? HasClick) else { + return + } + if selfCol.tapAction == nil { + selfCol.collision = nil + return + } + let visbounds = self.visualBounds(relativeTo: nil) + selfCol.collision = CollisionComponent( + shapes: [ShapeResource.generateBox(size: visbounds.extents) + .offsetBy(translation: visbounds.center)] + ) + } +} + +extension RUIText { + /// Used as default larger text to be displayed in the scene + static var largeFont = MeshResource.Font( + descriptor: .init( + name: "Helvetica", + size: 1), + size: MeshResource.Font.systemFontSize / 20 + ) ?? MeshResource.Font.systemFont(ofSize: MeshResource.Font.systemFontSize / 20) + + /// Used as default medium text to be displayed in the scene + static var mediumFont = MeshResource.Font( + descriptor: .init( + name: "Helvetica", + size: 1), + size: MeshResource.Font.systemFontSize / 28 + ) ?? MeshResource.Font.systemFont(ofSize: MeshResource.Font.systemFontSize / 28) +} diff --git a/Sources/RealityUI/RealityUI.swift b/Sources/RealityUI/RealityUI.swift index 25d0404..a8c733e 100644 --- a/Sources/RealityUI/RealityUI.swift +++ b/Sources/RealityUI/RealityUI.swift @@ -7,11 +7,13 @@ // import RealityKit +import Foundation #if os(iOS) -import UIKit +import UIKit.UIGestureRecognizer #elseif os(macOS) import AppKit #endif + import Combine @objc public class RealityUI: NSObject { @@ -66,7 +68,8 @@ import Combine SwitchComponent.self, StepperComponent.self, SliderComponent.self, - PivotComponent.self + PivotComponent.self, + TextComponent.self ] internal static var shared = RealityUI() From 33b31532352a82dba31c9e6ca1282ee354852723 Mon Sep 17 00:00:00 2001 From: Max Cobb Date: Sun, 22 Nov 2020 12:19:17 +0000 Subject: [PATCH 2/7] set RUIText initialiser to public --- Sources/RealityUI/RUIText.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/RealityUI/RUIText.swift b/Sources/RealityUI/RUIText.swift index e06190d..859201e 100644 --- a/Sources/RealityUI/RUIText.swift +++ b/Sources/RealityUI/RUIText.swift @@ -16,7 +16,7 @@ open class RUIText: Entity, HasText, HasClick { } } - convenience init( + public convenience init( with text: String, width: CGFloat = 0, height: CGFloat = 0, font: MeshResource.Font = RUIText.mediumFont, extrusion: Float = 0.1, color: Material.Color = .green @@ -158,7 +158,7 @@ public extension HasText { extension RUIText { /// Used as default larger text to be displayed in the scene - static var largeFont = MeshResource.Font( + static public var largeFont = MeshResource.Font( descriptor: .init( name: "Helvetica", size: 1), @@ -166,7 +166,7 @@ extension RUIText { ) ?? MeshResource.Font.systemFont(ofSize: MeshResource.Font.systemFontSize / 20) /// Used as default medium text to be displayed in the scene - static var mediumFont = MeshResource.Font( + static public var mediumFont = MeshResource.Font( descriptor: .init( name: "Helvetica", size: 1), From 309bfc4a1557137832c99419e7bd66e23be7d8f1 Mon Sep 17 00:00:00 2001 From: Max Cobb Date: Mon, 14 Dec 2020 09:54:05 +0000 Subject: [PATCH 3/7] added maximum distance for pivot, flipped all RUI elements to facing -z, means that .look(at:) works correctly. updated example project to reflect these changes --- .../project.pbxproj | 67 ++++++++++++++----- .../ViewController+NonRealityUI.swift | 2 +- .../ViewController+RealityControls.swift | 35 +++++----- .../RealityUI+Examples/ViewController.swift | 2 +- Sources/RealityUI/HasPivotTouch.swift | 16 +++-- Sources/RealityUI/RUIButton.swift | 4 +- .../RUILongTouchGestureRecognizer.swift | 17 +++++ Sources/RealityUI/RUISlider.swift | 10 +-- Sources/RealityUI/RUIStepper.swift | 36 +++++----- Sources/RealityUI/RUISwitch.swift | 2 +- 10 files changed, 125 insertions(+), 66 deletions(-) diff --git a/RealityUI+Examples/RealityUI+Examples.xcodeproj/project.pbxproj b/RealityUI+Examples/RealityUI+Examples.xcodeproj/project.pbxproj index fc86f5c..bcb45fa 100644 --- a/RealityUI+Examples/RealityUI+Examples.xcodeproj/project.pbxproj +++ b/RealityUI+Examples/RealityUI+Examples.xcodeproj/project.pbxproj @@ -13,9 +13,18 @@ F3414195246FF540006B1ECA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F3414194246FF540006B1ECA /* Assets.xcassets */; }; F3414198246FF540006B1ECA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F3414196246FF540006B1ECA /* LaunchScreen.storyboard */; }; F34141B12471A595006B1ECA /* ShowTime in Frameworks */ = {isa = PBXBuildFile; productRef = F34141B02471A595006B1ECA /* ShowTime */; }; - F37D9C9E2482E88200AF5A5F /* RealityUI in Frameworks */ = {isa = PBXBuildFile; productRef = F37D9C9D2482E88200AF5A5F /* RealityUI */; }; F38598C2247AE28F007BBC88 /* Entity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F38598C1247AE28F007BBC88 /* Entity+Extensions.swift */; }; F3DB9D81247D8BF8006D6CE5 /* ViewController+NonRealityUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DB9D80247D8BF8006D6CE5 /* ViewController+NonRealityUI.swift */; }; + F3F68530256BB91D0090A6C0 /* RUIText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F68526256BB91D0090A6C0 /* RUIText.swift */; }; + F3F68531256BB91D0090A6C0 /* RealityUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F68527256BB91D0090A6C0 /* RealityUI.swift */; }; + F3F68532256BB91D0090A6C0 /* RUILongTouchGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F68528256BB91D0090A6C0 /* RUILongTouchGestureRecognizer.swift */; }; + F3F68533256BB91D0090A6C0 /* RUIStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F68529256BB91D0090A6C0 /* RUIStepper.swift */; }; + F3F68534256BB91D0090A6C0 /* RUISwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F6852A256BB91D0090A6C0 /* RUISwitch.swift */; }; + F3F68535256BB91D0090A6C0 /* HasPivotTouch.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F6852B256BB91D0090A6C0 /* HasPivotTouch.swift */; }; + F3F68536256BB91D0090A6C0 /* RUIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F6852C256BB91D0090A6C0 /* RUIButton.swift */; }; + F3F68537256BB91D0090A6C0 /* HasRUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F6852D256BB91D0090A6C0 /* HasRUI.swift */; }; + F3F68538256BB91D0090A6C0 /* HasClick.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F6852E256BB91D0090A6C0 /* HasClick.swift */; }; + F3F68539256BB91D0090A6C0 /* RUISlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F6852F256BB91D0090A6C0 /* RUISlider.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -28,6 +37,16 @@ F3414199246FF540006B1ECA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F38598C1247AE28F007BBC88 /* Entity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Entity+Extensions.swift"; sourceTree = ""; }; F3DB9D80247D8BF8006D6CE5 /* ViewController+NonRealityUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewController+NonRealityUI.swift"; sourceTree = ""; }; + F3F68526256BB91D0090A6C0 /* RUIText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RUIText.swift; path = ../../../Sources/RealityUI/RUIText.swift; sourceTree = ""; }; + F3F68527256BB91D0090A6C0 /* RealityUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RealityUI.swift; path = ../../../Sources/RealityUI/RealityUI.swift; sourceTree = ""; }; + F3F68528256BB91D0090A6C0 /* RUILongTouchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RUILongTouchGestureRecognizer.swift; path = ../../../Sources/RealityUI/RUILongTouchGestureRecognizer.swift; sourceTree = ""; }; + F3F68529256BB91D0090A6C0 /* RUIStepper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RUIStepper.swift; path = ../../../Sources/RealityUI/RUIStepper.swift; sourceTree = ""; }; + F3F6852A256BB91D0090A6C0 /* RUISwitch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RUISwitch.swift; path = ../../../Sources/RealityUI/RUISwitch.swift; sourceTree = ""; }; + F3F6852B256BB91D0090A6C0 /* HasPivotTouch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HasPivotTouch.swift; path = ../../../Sources/RealityUI/HasPivotTouch.swift; sourceTree = ""; }; + F3F6852C256BB91D0090A6C0 /* RUIButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RUIButton.swift; path = ../../../Sources/RealityUI/RUIButton.swift; sourceTree = ""; }; + F3F6852D256BB91D0090A6C0 /* HasRUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HasRUI.swift; path = ../../../Sources/RealityUI/HasRUI.swift; sourceTree = ""; }; + F3F6852E256BB91D0090A6C0 /* HasClick.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HasClick.swift; path = ../../../Sources/RealityUI/HasClick.swift; sourceTree = ""; }; + F3F6852F256BB91D0090A6C0 /* RUISlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RUISlider.swift; path = ../../../Sources/RealityUI/RUISlider.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -36,7 +55,6 @@ buildActionMask = 2147483647; files = ( F34141B12471A595006B1ECA /* ShowTime in Frameworks */, - F37D9C9E2482E88200AF5A5F /* RealityUI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -67,6 +85,7 @@ F301D8A7247A62ED004AE1FA /* ViewController+RealityControls.swift */, F3DB9D80247D8BF8006D6CE5 /* ViewController+NonRealityUI.swift */, F38598C1247AE28F007BBC88 /* Entity+Extensions.swift */, + F3F68525256BB8FB0090A6C0 /* RealityUI */, F3414194246FF540006B1ECA /* Assets.xcassets */, F3414196246FF540006B1ECA /* LaunchScreen.storyboard */, F3414199246FF540006B1ECA /* Info.plist */, @@ -74,6 +93,23 @@ path = "RealityUI+Examples"; sourceTree = ""; }; + F3F68525256BB8FB0090A6C0 /* RealityUI */ = { + isa = PBXGroup; + children = ( + F3F6852E256BB91D0090A6C0 /* HasClick.swift */, + F3F6852B256BB91D0090A6C0 /* HasPivotTouch.swift */, + F3F6852D256BB91D0090A6C0 /* HasRUI.swift */, + F3F68527256BB91D0090A6C0 /* RealityUI.swift */, + F3F6852C256BB91D0090A6C0 /* RUIButton.swift */, + F3F68528256BB91D0090A6C0 /* RUILongTouchGestureRecognizer.swift */, + F3F6852F256BB91D0090A6C0 /* RUISlider.swift */, + F3F68529256BB91D0090A6C0 /* RUIStepper.swift */, + F3F6852A256BB91D0090A6C0 /* RUISwitch.swift */, + F3F68526256BB91D0090A6C0 /* RUIText.swift */, + ); + path = RealityUI; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -93,7 +129,6 @@ name = "RealityUI+Examples"; packageProductDependencies = ( F34141B02471A595006B1ECA /* ShowTime */, - F37D9C9D2482E88200AF5A5F /* RealityUI */, ); productName = "RealityUI+Examples"; productReference = F341418D246FF53E006B1ECA /* RealityUI+Examples.app */; @@ -125,7 +160,6 @@ mainGroup = F3414184246FF53E006B1ECA; packageReferences = ( F34141AF2471A595006B1ECA /* XCRemoteSwiftPackageReference "ShowTime" */, - F37D9C9C2482E88200AF5A5F /* XCRemoteSwiftPackageReference "/" */, ); productRefGroup = F341418E246FF53E006B1ECA /* Products */; projectDirPath = ""; @@ -174,11 +208,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F3F68534256BB91D0090A6C0 /* RUISwitch.swift in Sources */, + F3F68532256BB91D0090A6C0 /* RUILongTouchGestureRecognizer.swift in Sources */, + F3F68533256BB91D0090A6C0 /* RUIStepper.swift in Sources */, + F3F68538256BB91D0090A6C0 /* HasClick.swift in Sources */, + F3F68539256BB91D0090A6C0 /* RUISlider.swift in Sources */, F38598C2247AE28F007BBC88 /* Entity+Extensions.swift in Sources */, F3414193246FF53E006B1ECA /* ViewController.swift in Sources */, + F3F68531256BB91D0090A6C0 /* RealityUI.swift in Sources */, + F3F68536256BB91D0090A6C0 /* RUIButton.swift in Sources */, + F3F68537256BB91D0090A6C0 /* HasRUI.swift in Sources */, + F3F68535256BB91D0090A6C0 /* HasPivotTouch.swift in Sources */, F3DB9D81247D8BF8006D6CE5 /* ViewController+NonRealityUI.swift in Sources */, F301D8A8247A62ED004AE1FA /* ViewController+RealityControls.swift in Sources */, F3414191246FF53E006B1ECA /* AppDelegate.swift in Sources */, + F3F68530256BB91D0090A6C0 /* RUIText.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -321,6 +365,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = ""; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -338,6 +383,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = ""; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -376,14 +422,6 @@ minimumVersion = 2.5.2; }; }; - F37D9C9C2482E88200AF5A5F /* XCRemoteSwiftPackageReference "/" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "file://../"; - requirement = { - branch = main; - kind = branch; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -392,11 +430,6 @@ package = F34141AF2471A595006B1ECA /* XCRemoteSwiftPackageReference "ShowTime" */; productName = ShowTime; }; - F37D9C9D2482E88200AF5A5F /* RealityUI */ = { - isa = XCSwiftPackageProductDependency; - package = F37D9C9C2482E88200AF5A5F /* XCRemoteSwiftPackageReference "/" */; - productName = RealityUI; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = F3414185246FF53E006B1ECA /* Project object */; diff --git a/RealityUI+Examples/RealityUI+Examples/ViewController+NonRealityUI.swift b/RealityUI+Examples/RealityUI+Examples/ViewController+NonRealityUI.swift index 437cb3f..4b76eed 100644 --- a/RealityUI+Examples/RealityUI+Examples/ViewController+NonRealityUI.swift +++ b/RealityUI+Examples/RealityUI+Examples/ViewController+NonRealityUI.swift @@ -8,7 +8,7 @@ import RealityKit -import RealityUI +//import RealityUI class ContainerCube: Entity, HasPhysicsBody, HasModel { private static var boxPositions: [SIMD3] = [ diff --git a/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift b/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift index 0340f3e..2fa6a93 100644 --- a/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift +++ b/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift @@ -10,7 +10,7 @@ import RealityKit import Foundation import Combine -import RealityUI +//import RealityUI class ControlsParent: Entity, HasAnchoring, HasCollision, HasModel, HasPivotTouch { func updateMaterials() {} @@ -22,6 +22,7 @@ class ControlsParent: Entity, HasAnchoring, HasCollision, HasModel, HasPivotTouc self.anchoring = AnchoringComponent(.plane( .horizontal, classification: .any, minimumBounds: [0.5, 0.5] )) + self.maxPivotDistance = 0.75 self.addControls() /// Uncomment this to try out HasPivotTouch, but it's still in an experimental stage. if let rotateImg = try? TextureResource.load(named: "rotato") { @@ -46,7 +47,7 @@ class ControlsParent: Entity, HasAnchoring, HasCollision, HasModel, HasPivotTouc ) button.transform = Transform( scale: .init(repeating: 0.2), - rotation: simd_quatf(angle: -.pi / 2, axis: [1, 0, 0]), + rotation: simd_quatf(angle: .pi / 2, axis: [1, 0, 0]), translation: .zero ) self.addChild(button) @@ -59,37 +60,37 @@ class ControlsParent: Entity, HasAnchoring, HasCollision, HasModel, HasPivotTouc } }) toggle.transform = Transform( - scale: .init(repeating: 0.15), rotation: .init(), translation: [0, 0.25, -0.25] + scale: .init(repeating: 0.15), rotation: .init(angle: .pi, axis: [0, 1, 0]), translation: [0, 0.25, -0.25] ) self.addChild(toggle) let slider = RUISlider(slider: SliderComponent(startingValue: 0.5, steps: 0)) { (slider, _) in - for child in self.tumblingCubes { - child.scale = .init(repeating: slider.value + 0.5) - } + self.tumblingCubes.forEach { $0.scale = .init(repeating: slider.value + 0.5)} } - slider.transform = Transform(scale: .init(repeating: 0.1), rotation: .init(), translation: [0, 1.15, -0.25]) + slider.transform = Transform( + scale: .init(repeating: 0.1), + rotation: .init(angle: .pi, axis: [0, 1, 0]), + translation: [0, 1.15, -0.25] + ) self.addChild(slider) let minusPlusStepper = RUIStepper(upTrigger: { _ in if self.tumblingCubes.count <= 8 { self.spawnShape(with: SIMD3(repeating: slider.value + 0.5)) } - }, downTrigger: { _ in - self.removeCube() - }) + }, downTrigger: { _ in self.removeCube() }) minusPlusStepper.transform = Transform( - scale: .init(repeating: 0.15), rotation: .init(), translation: [-0.5, 0.25, -0.25] + scale: .init(repeating: 0.15), rotation: .init(angle: .pi, axis: [0, 1, 0]), translation: [-0.5, 0.25, -0.25] ) self.addChild(minusPlusStepper) - let shapeStepper = RUIStepper(style: .arrowLeftRight, upTrigger: { stepper in - self.shiftShape(1, on: stepper) - }, downTrigger: { stepper in - self.shiftShape(-1, on: stepper) - }) + let shapeStepper = RUIStepper( + style: .arrowLeftRight, + upTrigger: { stepper in self.shiftShape(1, on: stepper) }, + downTrigger: { stepper in self.shiftShape(-1, on: stepper) } + ) shapeStepper.transform = Transform( - scale: .init(repeating: 0.15), rotation: .init(), translation: [0.5, 0.25, -0.25] + scale: .init(repeating: 0.15), rotation: .init(angle: .pi, axis: [0, 1, 0]), translation: [0.5, 0.25, -0.25] ) self.addChild(shapeStepper) self.shiftShape(0, on: shapeStepper) diff --git a/RealityUI+Examples/RealityUI+Examples/ViewController.swift b/RealityUI+Examples/RealityUI+Examples/ViewController.swift index 9048895..8052196 100644 --- a/RealityUI+Examples/RealityUI+Examples/ViewController.swift +++ b/RealityUI+Examples/RealityUI+Examples/ViewController.swift @@ -10,7 +10,7 @@ import UIKit import RealityKit import ARKit -import RealityUI +//import RealityUI class ViewController: UIViewController { diff --git a/Sources/RealityUI/HasPivotTouch.swift b/Sources/RealityUI/HasPivotTouch.swift index b57621a..97093a1 100644 --- a/Sources/RealityUI/HasPivotTouch.swift +++ b/Sources/RealityUI/HasPivotTouch.swift @@ -44,12 +44,14 @@ public struct PivotComponent: Component { internal var lastTouchAngle: Float? internal var lastGlobalPosition: SIMD3 = .zero public var pivotAxis: SIMD3 - public init(pivot: SIMD3 = [0, 1, 0]) { - self.pivotAxis = pivot + public var maxPivotDistance: Float? + public init(pivotAxis: SIMD3 = [0, 1, 0], maxPivotDistance: Float? = nil) { + self.pivotAxis = pivotAxis + self.maxPivotDistance = maxPivotDistance } } -internal extension HasPivotTouch { +public extension HasPivotTouch { var pivotRotation: simd_quatf { simd_quaternion(self.pivotAxis, [0, 1, 0]) } @@ -61,7 +63,13 @@ internal extension HasPivotTouch { get { self.pivotTouch.pivotAxis } set { self.pivotTouch.pivotAxis = newValue } } - var lastGlobalPosition: SIMD3 { + + /// Maximum distance away from the center of the object where the pivot touch is active + var maxPivotDistance: Float? { + get { self.pivotTouch.maxPivotDistance } + set { self.pivotTouch.maxPivotDistance = newValue } + } + internal var lastGlobalPosition: SIMD3 { get { self.pivotTouch.lastGlobalPosition } set { self.pivotTouch.lastGlobalPosition = newValue } } diff --git a/Sources/RealityUI/RUIButton.swift b/Sources/RealityUI/RUIButton.swift index f7ddf00..818c5d2 100644 --- a/Sources/RealityUI/RUIButton.swift +++ b/Sources/RealityUI/RUIButton.swift @@ -192,13 +192,13 @@ internal extension HasButton { var buttonOutPos: SIMD3 { return [ 0, 0, - (self.button.size.z + self.innerBoxSize.z * (2 * extrude - 1)) / 2 + -(self.button.size.z + self.innerBoxSize.z * (2 * extrude - 1)) / 2 ] } var buttonInPos: SIMD3 { return [ 0, 0, - (self.button.size.z + self.innerBoxSize.z * (2 * compress - 1)) / 2 + -(self.button.size.z + self.innerBoxSize.z * (2 * compress - 1)) / 2 ] } diff --git a/Sources/RealityUI/RUILongTouchGestureRecognizer.swift b/Sources/RealityUI/RUILongTouchGestureRecognizer.swift index f688bb6..d15838b 100644 --- a/Sources/RealityUI/RUILongTouchGestureRecognizer.swift +++ b/Sources/RealityUI/RUILongTouchGestureRecognizer.swift @@ -65,6 +65,7 @@ public protocol HasTouchUpInside: HasARTouch {} var touchLocation: CGPoint? var viewSubscriber: Cancellable? var collisionPlane: float4x4? + public init(target: Any?, action: Selector?, view: ARView) { self.arView = view super.init(target: target, action: action) @@ -98,6 +99,12 @@ public protocol HasTouchUpInside: HasARTouch {} if let planeCollisionPoint = self.arView.unproject( touchInView, ontoPlane: collisionPlane ) { + if let thisPivot = hitEntity as? HasPivotTouch, let maxDist = thisPivot.maxPivotDistance { + let convPoint = hitEntity.convert(position: planeCollisionPoint, from: nil) + if convPoint.magnitude > maxDist { + return + } + } worldTouch = planeCollisionPoint } else { return @@ -254,3 +261,13 @@ extension RUILongTouchGestureRecognizer { } } #endif + +fileprivate extension SIMD where Self.Scalar : FloatingPoint { + var magnitude: Self.Scalar { + var sqSum: Self.Scalar = 0 + for indice in self.indices { + sqSum += self[indice] * self[indice] + } + return sqrt(sqSum) + } +} diff --git a/Sources/RealityUI/RUISlider.swift b/Sources/RealityUI/RUISlider.swift index 9c6dc5e..bc6d5d1 100644 --- a/Sources/RealityUI/RUISlider.swift +++ b/Sources/RealityUI/RUISlider.swift @@ -61,12 +61,12 @@ public class RUISlider: Entity, HasSlider, HasModel { public func arTouchStarted(_ worldCoordinate: SIMD3, hasCollided: Bool = true) { let localPos = self.convert(position: worldCoordinate, from: nil) - self.panGestureOffset = self.value - (localPos.x / self.sliderLength + 1 / 2) + self.panGestureOffset = self.value - (0.5 - localPos.x / self.sliderLength) self.sliderUpdated?(self, .started) } public func arTouchUpdated(_ worldCoordinate: SIMD3, hasCollided: Bool = true) { let localPos = self.convert(position: worldCoordinate, from: nil) - var newPercent = (localPos.x / self.sliderLength + 1 / 2) + self.panGestureOffset + var newPercent = (0.5 - localPos.x / self.sliderLength) + self.panGestureOffset self.clampSlideValue(&newPercent) if self.value == newPercent { return @@ -205,11 +205,11 @@ public extension HasSlider { private func getSliderPosition(for part: SliderComponent.UIPart) -> SIMD3 { switch part { case .fill: - return [(self.value / 2 - 0.5) * self.sliderLength, 0, 0] + return [(0.5 - self.value / 2) * self.sliderLength, 0, 0] case .thumb: - return [(-0.5 + self.value) * self.sliderLength, 0, 0] + return [(0.5 - self.value) * self.sliderLength, 0, 0] case .empty: - return [(self.value / 2) * self.sliderLength, 0, 0] + return [-self.value / 2 * self.sliderLength, 0, 0] } } diff --git a/Sources/RealityUI/RUIStepper.swift b/Sources/RealityUI/RUIStepper.swift index 47ef235..18b0c09 100644 --- a/Sources/RealityUI/RUIStepper.swift +++ b/Sources/RealityUI/RUIStepper.swift @@ -184,9 +184,9 @@ internal extension HasStepper { fileprivate func makeModels() { let rightModel = self.addModel(part: .right) - rightModel.position.x = 0.5 + rightModel.position.x = -0.5 let leftModel = self.addModel(part: .left) - leftModel.position.x = -0.5 + leftModel.position.x = 0.5 switch self.style { case .minusPlus: rightModel.model = ModelComponent( @@ -219,44 +219,44 @@ internal extension HasStepper { private func addArrowModels(_ leftModel: ModelEntity, _ rightModel: ModelEntity) { // Setup parameters let turnAngle: Float = .pi / 6 - let sinAng: Float = sin(turnAngle) - let partLen: Float = (0.7 / 2) / cos(turnAngle) + let partLen: Float = (0.7 / 2) let partThickness = partLen * 0.2 - let yDist = 0.2 - (sinAng * partThickness) + let hCorner = hypot(partLen / 2, partThickness / 2) + let ang2 = atan2(partThickness / 2, partLen / 2) + let yDist = hCorner * cos(turnAngle + ang2) if self.style == .arrowDownUp { leftModel.orientation = simd_quatf(angle: .pi / 2, axis: [0, 0, -1]) rightModel.orientation = simd_quatf(angle: .pi / 2, axis: [0, 0, -1]) } - let rightSubModel1 = ModelEntity(mesh: .generateBox( + let leftSubModel1 = ModelEntity(mesh: .generateBox( size: [partThickness, partLen, partThickness], cornerRadius: partThickness * 0.25 ), materials: [] ) - rightSubModel1.transform = Transform( + leftSubModel1.transform = Transform( scale: .one, rotation: .init(angle: turnAngle, axis: [0, 0, 1]), translation: [0, yDist, 0] ) - let rightSubModel2 = ModelEntity() - rightSubModel2.model = rightSubModel1.model + let leftSubModel2 = ModelEntity() + leftSubModel2.model = leftSubModel1.model - rightSubModel2.transform = Transform( + leftSubModel2.transform = Transform( scale: .one, rotation: .init(angle: -turnAngle, axis: [0, 0, 1]), translation: [0, -yDist, 0] ) - let leftSubModel1 = rightSubModel2.clone(recursive: true) - leftSubModel1.position.y = yDist - let leftSubModel2 = rightSubModel1.clone(recursive: true) - leftSubModel2.position.y = -yDist + let rightSubModel1 = leftSubModel2.clone(recursive: true) + rightSubModel1.position.y = yDist + let rightSubModel2 = leftSubModel1.clone(recursive: true) + rightSubModel2.position.y = -yDist - rightModel.addChild(rightSubModel1) - rightModel.addChild(rightSubModel2) leftModel.addChild(leftSubModel1) leftModel.addChild(leftSubModel2) - + rightModel.addChild(rightSubModel1) + rightModel.addChild(rightSubModel2) } func stepperTap(clicker: HasClick, worldTapPos: SIMD3?) { @@ -268,7 +268,7 @@ internal extension HasStepper { } let localPos = stepperObj.convert(position: tapPos, from: nil) - if localPos.x < 0 { + if localPos.x > 0 { if let downModel = stepperObj.getModel(part: .left) { stepperObj.springAnimate(entity: downModel) } diff --git a/Sources/RealityUI/RUISwitch.swift b/Sources/RealityUI/RUISwitch.swift index ff64546..357f9f3 100644 --- a/Sources/RealityUI/RUISwitch.swift +++ b/Sources/RealityUI/RUISwitch.swift @@ -152,7 +152,7 @@ public extension HasSwitch { var onColor: Material.Color { self.switchness.onColor } var offColor: Material.Color { self.switchness.offColor } private var togglePos: SIMD3 { - [(isOn ? 1 : -1) * (self.switchness.length - 1)/2, 0, 0] + [(isOn ? -1 : 1) * (self.switchness.length - 1)/2, 0, 0] } private var thumbColor: Material.Color { self.switchness.thumbColor From 61ea12416a064627e4a94beca22a883dee2efccd Mon Sep 17 00:00:00 2001 From: Max Cobb Date: Tue, 15 Dec 2020 16:06:30 +0000 Subject: [PATCH 4/7] updated README and adjusted centering of RUIText entity --- README.md | 2 +- Sources/RealityUI/RUIText.swift | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 128dc52..561a174 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ RUISlider uses `.pan`, but I would just recommend using `.all` to avoid issues, For the sake of all these examples, the _Simple_ heading will create an Entity with no custom properties or callbacks, and for _Functional_, imagine there is a `ModelEntity` in the scene which we can reference from the variable `adjustmentCuboid`. -By default all RealityUI Entities are quite large. This is used to standardize the sizes so that you always know what to expect. For example, all UI thumbs are spheres with a diameter of 1 meter, which is 1 unit in RealityKit, ± any padding adjustments. All RealityUI Entities face `[0, 0, 1]` by default, in the same way as a ModelEntity with a [plane mesh](https://developer.apple.com/documentation/realitykit/meshresource/3244419-generateplane). +By default all RealityUI Entities are quite large. This is used to standardize the sizes so that you always know what to expect. For example, all UI thumbs are spheres with a diameter of 1 meter, which is 1 unit in RealityKit, ± any padding adjustments. All RealityUI Entities face `[0, 0, -1]` by default. To have them point at the user camera, or `.zero`, you can use the [`.look(at:,from:,relativeTo:)`](https://developer.apple.com/documentation/realitykit/entity/3244094-look) method like so: `.look(at: .zero, from: [0, 0, 1])`. Or if you want it to turn around straight away if you've positioned it at `[0, 0, -1]`, set the orientation to `simd_quatf(angle: .pi, axis: [0, 1, 0])`. Using the [.look()](https://developer.apple.com/documentation/realitykit/entity/3244094-look) method works here by setting the `at:` value to the direction the button should be used from. ## RUISwitch Creation diff --git a/Sources/RealityUI/RUIText.swift b/Sources/RealityUI/RUIText.swift index 859201e..b6a111f 100644 --- a/Sources/RealityUI/RUIText.swift +++ b/Sources/RealityUI/RUIText.swift @@ -57,16 +57,16 @@ open class RUIText: Entity, HasText, HasClick { } public struct TextComponent: Component { - var text: String? = nil - var font: MeshResource.Font = .systemFont(ofSize: 0.1) - var width: CGFloat = 0 - var height: CGFloat = 0 + public var text: String? = nil + public var font: MeshResource.Font = .systemFont(ofSize: 0.1) + public var width: CGFloat = 0 + public var height: CGFloat = 0 #if os(iOS) - var color: Material.Color = .label + public var color: Material.Color = .label #elseif os(macOS) - var color: Material.Color = .labelColor + public var color: Material.Color = .labelColor #endif - var extrusion: Float = 1 + public var extrusion: Float = 1 enum UIPart: String { case textEntity @@ -131,12 +131,12 @@ public extension HasText { guard let textModel = self.textModel else { return } - let textSize = textModel.mesh.bounds.extents +// let textSize = textModel.mesh.bounds.extents let textOffset = -textModel.mesh.bounds.center self.getModel(part: .textEntity)?.position = [ -textOffset.x, textOffset.y, - -textSize.z / 2 + 0 // textSize.z / 2 ] self.updateCollision() } From c2519f5e969ceb72a10890582950e8aba47b192d Mon Sep 17 00:00:00 2001 From: Max Cobb Date: Wed, 16 Dec 2020 18:10:25 +0000 Subject: [PATCH 5/7] let user set orientation for all new realityui models with RealityUI.ruiOrientation, removed old macos long touch not working prompt --- README.md | 2 -- Sources/RealityUI/HasRUI.swift | 5 +++++ Sources/RealityUI/RUIButton.swift | 3 ++- .../RUILongTouchGestureRecognizer.swift | 2 +- Sources/RealityUI/RUISlider.swift | 1 + Sources/RealityUI/RUIStepper.swift | 1 + Sources/RealityUI/RUISwitch.swift | 3 ++- Sources/RealityUI/RUIText.swift | 22 +++++++++++++++++-- Sources/RealityUI/RealityUI.swift | 4 +--- 9 files changed, 33 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 561a174..cac0f5d 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,6 @@ The User Interface controls in this repository so far are made to be familiar to - Swift 5.2 - Xcode 11 -RUISlider gestures are not working with macOS currently. - ## Content - [Installation](#installation) diff --git a/Sources/RealityUI/HasRUI.swift b/Sources/RealityUI/HasRUI.swift index cb50fe9..dbf8326 100644 --- a/Sources/RealityUI/HasRUI.swift +++ b/Sources/RealityUI/HasRUI.swift @@ -93,6 +93,11 @@ internal extension HasRUI { func getModel(part: String) -> ModelEntity? { self.findEntity(named: part) as? ModelEntity } + func ruiOrientation() { + if let startOrient = RealityUI.startingOrientation { + self.orientation = startOrient + } + } func addModel(part: String) -> ModelEntity { if let modelPart = self.getModel(part: part) { return modelPart diff --git a/Sources/RealityUI/RUIButton.swift b/Sources/RealityUI/RUIButton.swift index 818c5d2..f6bd078 100644 --- a/Sources/RealityUI/RUIButton.swift +++ b/Sources/RealityUI/RUIButton.swift @@ -11,7 +11,7 @@ import RealityKit /// A RealityUI Button to be added to a RealityKit scene. public class RUIButton: Entity, HasButton, HasModel, HasPhysics { - public var collisionPlane: float4x4? = nil + public var collisionPlane: float4x4? public var touchUpCompleted: ((HasButton) -> Void)? @@ -28,6 +28,7 @@ public class RUIButton: Entity, HasButton, HasModel, HasPhysics { super.init() self.RUI = RUI ?? RUIComponent() self.button = button ?? ButtonComponent() + self.ruiOrientation() self.makeModels() } diff --git a/Sources/RealityUI/RUILongTouchGestureRecognizer.swift b/Sources/RealityUI/RUILongTouchGestureRecognizer.swift index d15838b..aebc7d1 100644 --- a/Sources/RealityUI/RUILongTouchGestureRecognizer.swift +++ b/Sources/RealityUI/RUILongTouchGestureRecognizer.swift @@ -262,7 +262,7 @@ extension RUILongTouchGestureRecognizer { } #endif -fileprivate extension SIMD where Self.Scalar : FloatingPoint { +fileprivate extension SIMD where Self.Scalar: FloatingPoint { var magnitude: Self.Scalar { var sqSum: Self.Scalar = 0 for indice in self.indices { diff --git a/Sources/RealityUI/RUISlider.swift b/Sources/RealityUI/RUISlider.swift index bc6d5d1..8667111 100644 --- a/Sources/RealityUI/RUISlider.swift +++ b/Sources/RealityUI/RUISlider.swift @@ -31,6 +31,7 @@ public class RUISlider: Entity, HasSlider, HasModel { super.init() self.RUI = RUI ?? RUIComponent() self.slider = slider ?? SliderComponent() + self.ruiOrientation() self.makeModels() self.setPercent(to: self.slider.value) self.updateCollision() diff --git a/Sources/RealityUI/RUIStepper.swift b/Sources/RealityUI/RUIStepper.swift index 18b0c09..e65c6df 100644 --- a/Sources/RealityUI/RUIStepper.swift +++ b/Sources/RealityUI/RUIStepper.swift @@ -36,6 +36,7 @@ public class RUIStepper: Entity, HasRUI, HasStepper { super.init() self.RUI = RUI ?? RUIComponent() self.stepper = stepper ?? StepperComponent() + self.ruiOrientation() self.makeModels() self.upTrigger = upTrigger self.downTrigger = downTrigger diff --git a/Sources/RealityUI/RUISwitch.swift b/Sources/RealityUI/RUISwitch.swift index 357f9f3..dcd0c58 100644 --- a/Sources/RealityUI/RUISwitch.swift +++ b/Sources/RealityUI/RUISwitch.swift @@ -34,7 +34,8 @@ public class RUISwitch: Entity, HasSwitch, HasClick { super.init() self.RUI = RUI ?? RUIComponent() self.switchness = switchness ?? SwitchComponent() - makeModels() + self.ruiOrientation() + self.makeModels() self.switchChanged = changedCallback } diff --git a/Sources/RealityUI/RUIText.swift b/Sources/RealityUI/RUIText.swift index b6a111f..b61c3d7 100644 --- a/Sources/RealityUI/RUIText.swift +++ b/Sources/RealityUI/RUIText.swift @@ -42,6 +42,7 @@ open class RUIText: Entity, HasText, HasClick { super.init() self.RUI = RUI self.textComponent = textComponent ?? TextComponent() + self.ruiOrientation() self.makeModels() } @@ -57,7 +58,7 @@ open class RUIText: Entity, HasText, HasClick { } public struct TextComponent: Component { - public var text: String? = nil + public var text: String? public var font: MeshResource.Font = .systemFont(ofSize: 0.1) public var width: CGFloat = 0 public var height: CGFloat = 0 @@ -106,7 +107,6 @@ public extension HasText { self.addModel(part: part.rawValue) } - func updateMaterials() { self.getModel(part: .textEntity)?.model?.materials = [self.getMaterial(with: self.textComponent.color)] } @@ -157,6 +157,23 @@ public extension HasText { } extension RUIText { + #if os(iOS) + /// Used as default larger text to be displayed in the scene + static public var largeFont = MeshResource.Font( + descriptor: .init( + name: "Helvetica", + size: 1), + size: MeshResource.Font.systemFontSize / 20 + ) + + /// Used as default medium text to be displayed in the scene + static public var mediumFont = MeshResource.Font( + descriptor: .init( + name: "Helvetica", + size: 1), + size: MeshResource.Font.systemFontSize / 28 + ) + #elseif os(macOS) /// Used as default larger text to be displayed in the scene static public var largeFont = MeshResource.Font( descriptor: .init( @@ -172,4 +189,5 @@ extension RUIText { size: 1), size: MeshResource.Font.systemFontSize / 28 ) ?? MeshResource.Font.systemFont(ofSize: MeshResource.Font.systemFontSize / 28) + #endif } diff --git a/Sources/RealityUI/RealityUI.swift b/Sources/RealityUI/RealityUI.swift index a8c733e..0a831cd 100644 --- a/Sources/RealityUI/RealityUI.swift +++ b/Sources/RealityUI/RealityUI.swift @@ -23,6 +23,7 @@ import Combine public static func registerComponents() { RealityUI.shared.logActivated() } + public static var startingOrientation: simd_quatf? public static var longGestureMask: CollisionGroup = .all public static var tapGestureMask: CollisionGroup = .all private func logActivated() { @@ -105,9 +106,6 @@ import Combine self.installedGestures[arView]?.append(addUITapGesture) } private func addLongTouch(to arView: ARView) { - #if os(macOS) - RealityUI.RUIPrint("RealityUI: long touch gesture not fully working on macOS") - #endif let longTouchGesture = RUILongTouchGestureRecognizer( target: self, action: #selector(self.arTouchReco), view: arView From 8d45fc0887b879369773045de7f4919b2229470b Mon Sep 17 00:00:00 2001 From: Max Cobb Date: Wed, 16 Dec 2020 18:18:59 +0000 Subject: [PATCH 6/7] Text now applying material correctly, meaning it will respond to light only if told to --- Sources/RealityUI/RUIStepper.swift | 3 +-- Sources/RealityUI/RUIText.swift | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Sources/RealityUI/RUIStepper.swift b/Sources/RealityUI/RUIStepper.swift index e65c6df..659841d 100644 --- a/Sources/RealityUI/RUIStepper.swift +++ b/Sources/RealityUI/RUIStepper.swift @@ -11,8 +11,7 @@ import Combine /// A new RealityUI Stepper to be added to your RealityKit scene. public class RUIStepper: Entity, HasRUI, HasStepper { - public var tapAction: ((HasClick, SIMD3?) -> Void)? = { - clicker, worldPos in + public var tapAction: ((HasClick, SIMD3?) -> Void)? = { clicker, worldPos in (clicker as? HasStepper)?.stepperTap(clicker: clicker, worldTapPos: worldPos) } diff --git a/Sources/RealityUI/RUIText.swift b/Sources/RealityUI/RUIText.swift index b61c3d7..0085232 100644 --- a/Sources/RealityUI/RUIText.swift +++ b/Sources/RealityUI/RUIText.swift @@ -107,9 +107,19 @@ public extension HasText { self.addModel(part: part.rawValue) } + internal func getMaterials( + for part: TextComponent.UIPart + ) -> [Material] { + switch part { + case .textEntity: + return [self.getMaterial(with: self.textComponent.color)] + } + } + func updateMaterials() { - self.getModel(part: .textEntity)?.model?.materials = [self.getMaterial(with: self.textComponent.color)] + self.getModel(part: .textEntity)?.model?.materials = self.getMaterials(for: .textEntity) } + func setText(_ text: String?) { guard let text = text else { self.getModel(part: .textEntity)?.model = nil @@ -126,7 +136,10 @@ public extension HasText { lineBreakMode: .byWordWrapping ) - self.textModel = ModelComponent(mesh: textMesh, materials: [SimpleMaterial(color: self.textComponent.color, isMetallic: false)]) + self.textModel = ModelComponent( + mesh: textMesh, + materials: [SimpleMaterial(color: self.textComponent.color, isMetallic: false)] + ) self.getModel(part: .textEntity)?.model = self.textModel guard let textModel = self.textModel else { return From bcda04b0e676bec6b0f577b085ac84290f6010e8 Mon Sep 17 00:00:00 2001 From: Max Cobb Date: Thu, 17 Dec 2020 21:27:10 +0000 Subject: [PATCH 7/7] update indentation fixes --- .../ViewController+RealityControls.swift | 32 +++++++++---------- Sources/RealityUI/HasPivotTouch.swift | 2 +- .../RUILongTouchGestureRecognizer.swift | 20 ++++++------ Sources/RealityUI/RUIStepper.swift | 5 +-- Sources/RealityUI/RUIText.swift | 9 +++--- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift b/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift index 2fa6a93..be4a585 100644 --- a/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift +++ b/RealityUI+Examples/RealityUI+Examples/ViewController+RealityControls.swift @@ -60,7 +60,7 @@ class ControlsParent: Entity, HasAnchoring, HasCollision, HasModel, HasPivotTouc } }) toggle.transform = Transform( - scale: .init(repeating: 0.15), rotation: .init(angle: .pi, axis: [0, 1, 0]), translation: [0, 0.25, -0.25] + scale: .init(repeating: 0.15), rotation: .init(angle: .pi, axis: [0, 1, 0]), translation: [0, 0.25, -0.25] ) self.addChild(toggle) @@ -68,9 +68,9 @@ class ControlsParent: Entity, HasAnchoring, HasCollision, HasModel, HasPivotTouc self.tumblingCubes.forEach { $0.scale = .init(repeating: slider.value + 0.5)} } slider.transform = Transform( - scale: .init(repeating: 0.1), - rotation: .init(angle: .pi, axis: [0, 1, 0]), - translation: [0, 1.15, -0.25] + scale: .init(repeating: 0.1), + rotation: .init(angle: .pi, axis: [0, 1, 0]), + translation: [0, 1.15, -0.25] ) self.addChild(slider) @@ -114,21 +114,19 @@ extension ViewController { var anchorFoundCallback: Cancellable? anchorFoundCallback = self.arView.scene.subscribe( to: SceneEvents.AnchoredStateChanged.self, on: controlsAnchor, { anchorEvent in - if anchorEvent.isAnchored { - controlsAnchor.entityAnchored() - if ViewController.letRotate { - let visBounds = controlsAnchor.visualBounds(relativeTo: controlsAnchor) - print(visBounds.center) - controlsAnchor.collision = CollisionComponent(shapes: [ - ShapeResource.generateBox(size: visBounds.extents * 1.1).offsetBy(translation: visBounds.center) - ]) - self.arView.installGestures(.rotation, for: controlsAnchor) - } - DispatchQueue.main.async { - anchorFoundCallback?.cancel() + if anchorEvent.isAnchored { + controlsAnchor.entityAnchored() + if ViewController.letRotate { + let visBounds = controlsAnchor.visualBounds(relativeTo: controlsAnchor) + controlsAnchor.collision = CollisionComponent(shapes: [ + ShapeResource.generateBox(size: visBounds.extents * 1.1).offsetBy(translation: visBounds.center) + ]) + self.arView.installGestures(.rotation, for: controlsAnchor) + } + DispatchQueue.main.async { anchorFoundCallback?.cancel() } } } - }) + ) self.arView.scene.addAnchor(controlsAnchor) let textAbove = RUIText(with: "RealityUI") textAbove.look(at: [0, 1.5, 0], from: [0, 1.5, -1], relativeTo: nil) diff --git a/Sources/RealityUI/HasPivotTouch.swift b/Sources/RealityUI/HasPivotTouch.swift index 97093a1..efd66d6 100644 --- a/Sources/RealityUI/HasPivotTouch.swift +++ b/Sources/RealityUI/HasPivotTouch.swift @@ -45,7 +45,7 @@ public struct PivotComponent: Component { internal var lastGlobalPosition: SIMD3 = .zero public var pivotAxis: SIMD3 public var maxPivotDistance: Float? - public init(pivotAxis: SIMD3 = [0, 1, 0], maxPivotDistance: Float? = nil) { + public init(pivotAxis: SIMD3 = [0, 1, 0], maxPivotDistance: Float? = nil) { self.pivotAxis = pivotAxis self.maxPivotDistance = maxPivotDistance } diff --git a/Sources/RealityUI/RUILongTouchGestureRecognizer.swift b/Sources/RealityUI/RUILongTouchGestureRecognizer.swift index aebc7d1..f59c326 100644 --- a/Sources/RealityUI/RUILongTouchGestureRecognizer.swift +++ b/Sources/RealityUI/RUILongTouchGestureRecognizer.swift @@ -100,10 +100,10 @@ public protocol HasTouchUpInside: HasARTouch {} touchInView, ontoPlane: collisionPlane ) { if let thisPivot = hitEntity as? HasPivotTouch, let maxDist = thisPivot.maxPivotDistance { - let convPoint = hitEntity.convert(position: planeCollisionPoint, from: nil) - if convPoint.magnitude > maxDist { - return - } + let convPoint = hitEntity.convert(position: planeCollisionPoint, from: nil) + if convPoint.magnitude > maxDist { + return + } } worldTouch = planeCollisionPoint } else { @@ -263,11 +263,11 @@ extension RUILongTouchGestureRecognizer { #endif fileprivate extension SIMD where Self.Scalar: FloatingPoint { - var magnitude: Self.Scalar { - var sqSum: Self.Scalar = 0 - for indice in self.indices { - sqSum += self[indice] * self[indice] - } - return sqrt(sqSum) + var magnitude: Self.Scalar { + var sqSum: Self.Scalar = 0 + for indice in self.indices { + sqSum += self[indice] * self[indice] } + return sqrt(sqSum) + } } diff --git a/Sources/RealityUI/RUIStepper.swift b/Sources/RealityUI/RUIStepper.swift index 659841d..1174420 100644 --- a/Sources/RealityUI/RUIStepper.swift +++ b/Sources/RealityUI/RUIStepper.swift @@ -12,7 +12,7 @@ import Combine /// A new RealityUI Stepper to be added to your RealityKit scene. public class RUIStepper: Entity, HasRUI, HasStepper { public var tapAction: ((HasClick, SIMD3?) -> Void)? = { clicker, worldPos in - (clicker as? HasStepper)?.stepperTap(clicker: clicker, worldTapPos: worldPos) + (clicker as? HasStepper)?.stepperTap(clicker: clicker, worldTapPos: worldPos) } // Consider changing to 1 function @@ -230,7 +230,8 @@ internal extension HasStepper { rightModel.orientation = simd_quatf(angle: .pi / 2, axis: [0, 0, -1]) } - let leftSubModel1 = ModelEntity(mesh: .generateBox( + let leftSubModel1 = ModelEntity( + mesh: .generateBox( size: [partThickness, partLen, partThickness], cornerRadius: partThickness * 0.25 ), materials: [] diff --git a/Sources/RealityUI/RUIText.swift b/Sources/RealityUI/RUIText.swift index 0085232..b7b8f9e 100644 --- a/Sources/RealityUI/RUIText.swift +++ b/Sources/RealityUI/RUIText.swift @@ -112,7 +112,7 @@ public extension HasText { ) -> [Material] { switch part { case .textEntity: - return [self.getMaterial(with: self.textComponent.color)] + return [self.getMaterial(with: self.textComponent.color)] } } @@ -137,8 +137,8 @@ public extension HasText { ) self.textModel = ModelComponent( - mesh: textMesh, - materials: [SimpleMaterial(color: self.textComponent.color, isMetallic: false)] + mesh: textMesh, + materials: [SimpleMaterial(color: self.textComponent.color, isMetallic: false)] ) self.getModel(part: .textEntity)?.model = self.textModel guard let textModel = self.textModel else { @@ -164,7 +164,8 @@ public extension HasText { let visbounds = self.visualBounds(relativeTo: nil) selfCol.collision = CollisionComponent( shapes: [ShapeResource.generateBox(size: visbounds.extents) - .offsetBy(translation: visbounds.center)] + .offsetBy(translation: visbounds.center) + ] ) } }