diff --git a/README.md b/README.md index ff29f89..4d0d1f0 100644 --- a/README.md +++ b/README.md @@ -67,4 +67,4 @@ This plugin will be updated as the API stabilizes. ## Credits -This plugin is based on the source for Mozilla's WebXR Viewer ([webxr-ios@c91decb](https://github.com/mozilla-mobile/webxr-ios/tree/c91decbecd11b0691f974fb5edc80a06b62cec11)) \ No newline at end of file +This plugin is based on the source for Mozilla's WebXR Viewer ([webxr-ios@d631bfb](https://github.com/mozilla-mobile/webxr-ios/tree/d631bfb0a65573c26efe34f53e012427b75da847)) \ No newline at end of file diff --git a/XRViewer/ARKController/ARKController+ARSessionDelegate.swift b/XRViewer/ARKController/ARKController+ARSessionDelegate.swift index c25fd8f..b139ef0 100644 --- a/XRViewer/ARKController/ARKController+ARSessionDelegate.swift +++ b/XRViewer/ARKController/ARKController+ARSessionDelegate.swift @@ -1,3 +1,5 @@ +import ARKit + extension ARKController: ARSessionDelegate { // Tony: Per SO, a bug that's been around for 3+ years necessitates these @objc calls @@ -56,7 +58,8 @@ extension ARKController: ARSessionDelegate { } if usingMetal, - let controller = controller as? ARKMetalController + let controller = controller as? ARKMetalController, + addedAnchor is ARPlaneAnchor { let node = Node() controller.planes[addedAnchor.identifier] = node @@ -110,6 +113,7 @@ extension ARKController: ARSessionDelegate { if usingMetal, let controller = controller as? ARKMetalController, + updatedAnchor is ARPlaneAnchor, let node = controller.planes[updatedAnchor.identifier] { node.transform = Transform(from: updatedAnchor.transform) @@ -126,6 +130,7 @@ extension ARKController: ARSessionDelegate { if usingMetal, let controller = controller as? ARKMetalController, + removedAnchor is ARPlaneAnchor, let node = controller.planes[removedAnchor.identifier] { node.removeFromParentNode() diff --git a/XRViewer/ARKController/ARKController+ARSessionObserver.swift b/XRViewer/ARKController/ARKController+ARSessionObserver.swift index 7e1faf4..e2a2fa5 100644 --- a/XRViewer/ARKController/ARKController+ARSessionObserver.swift +++ b/XRViewer/ARKController/ARKController+ARSessionObserver.swift @@ -1,3 +1,5 @@ +import ARKit + extension ARKController: ARSessionObserver { @objc(session:cameraDidChangeTrackingState:) diff --git a/XRViewer/ARKController/ARKController+Anchors.swift b/XRViewer/ARKController/ARKController+Anchors.swift index e642d98..d200761 100644 --- a/XRViewer/ARKController/ARKController+Anchors.swift +++ b/XRViewer/ARKController/ARKController+Anchors.swift @@ -1,4 +1,6 @@ -@objc extension ARKController { +import ARKit + +extension ARKController { // MARK: - Anchor Dictionaries @@ -272,11 +274,11 @@ for anchorIDToDelete in anchorIDsToDelete as? [String] ?? [] { var anchorToDelete: ARAnchor? = getAnchorFromUserAnchorID(anchorIDToDelete) if let anchorToDelete = anchorToDelete { - session?.remove(anchor: anchorToDelete) + session.remove(anchor: anchorToDelete) } else { anchorToDelete = getAnchorFromARKitAnchorID(anchorIDToDelete) if let anchorToDelete = anchorToDelete { - session?.remove(anchor: anchorToDelete) + session.remove(anchor: anchorToDelete) } } } @@ -287,7 +289,7 @@ key "distantAnchorsDistanceKey" */ func removeDistantAnchors() { - guard let currentFrame = session?.currentFrame else { return } + guard let currentFrame = session.currentFrame else { return } let cameraTransform = currentFrame.camera.transform let distanceThreshold: Float = UserDefaults.standard.float(forKey: Constant.distantAnchorsDistanceKey()) @@ -316,13 +318,13 @@ (center2 + extent2) < -distanceThreshold { print("\n\n*********\n\nRemoving distant plane \(anchor.identifier.uuidString)\n\n*********") - session?.remove(anchor: anchor) + session.remove(anchor: anchor) } } else { let distance = simd_distance(anchor.transform.columns.3, cameraTransform.columns.3) if distance >= distanceThreshold { print("\n\n*********\n\nRemoving distant anchor \(anchor.identifier.uuidString)\n\n*********") - session?.remove(anchor: anchor) + session.remove(anchor: anchor) } } } @@ -331,21 +333,21 @@ func removeAllAnchors() { clearImageDetectionDictionaries() - guard let currentFrame = session?.currentFrame else { return } + guard let currentFrame = session.currentFrame else { return } for anchor in currentFrame.anchors { - session?.remove(anchor: anchor) + session.remove(anchor: anchor) } } func removeAllAnchorsExceptPlanes() { clearImageDetectionDictionaries() - guard let currentFrame = session?.currentFrame else { return } + guard let currentFrame = session.currentFrame else { return } for anchor in currentFrame.anchors { if !(anchor is ARPlaneAnchor) { - session?.remove(anchor: anchor) + session.remove(anchor: anchor) } } } @@ -354,7 +356,7 @@ func getAnchorFromARKitAnchorID(_ arkitAnchorID: String) -> ARAnchor? { var anchor: ARAnchor? = nil - guard let currentFrame: ARFrame = session?.currentFrame else { return nil } + guard let currentFrame: ARFrame = session.currentFrame else { return nil } for currentAnchor in currentFrame.anchors { if currentAnchor.identifier.uuidString == arkitAnchorID { anchor = currentAnchor @@ -370,7 +372,7 @@ guard let userID = userID as? String else { return } guard let arkitID = arkitID as? String else { return } if userID == userAnchorID { - guard let currentFrame = self.session?.currentFrame else { return } + guard let currentFrame = self.session.currentFrame else { return } let anchors = currentFrame.anchors for currentAnchor in anchors { if currentAnchor.identifier.uuidString == arkitID { @@ -463,7 +465,7 @@ var matrix = matrix_float4x4() matrix = transform.matrix() let anchor = ARAnchor(name: userGeneratedAnchorID ?? "", transform: matrix) - session?.add(anchor: anchor) + session.add(anchor: anchor) arkitGeneratedAnchorIDUserAnchorIDMap[anchor.identifier.uuidString] = userGeneratedAnchorID ?? "" return true diff --git a/XRViewer/ARKController/ARKController+AppState.swift b/XRViewer/ARKController/ARKController+AppState.swift index dce3005..0bfb6a9 100644 --- a/XRViewer/ARKController/ARKController+AppState.swift +++ b/XRViewer/ARKController/ARKController+AppState.swift @@ -12,7 +12,7 @@ extension ARKController { */ func startSession(with state: AppState) { updateARConfiguration(with: state) - session?.run(configuration, options: [.resetTracking, .removeExistingAnchors]) + session.run(configuration, options: [.resetTracking, .removeExistingAnchors]) arSessionState = .arkSessionRunning // if we are removing anchors, clear the user map @@ -43,13 +43,13 @@ extension ARKController { */ func runSession(with state: AppState) { updateARConfiguration(with: state) - session?.run(configuration, options: []) + session.run(configuration, options: []) arSessionState = .arkSessionRunning } func runSessionRemovingAnchors(with state: AppState) { updateARConfiguration(with: state) - session?.run(configuration, options: .removeExistingAnchors) + session.run(configuration, options: .removeExistingAnchors) // If we are removing anchors, clear the user map arkitGeneratedAnchorIDUserAnchorIDMap = NSMutableDictionary() arSessionState = .arkSessionRunning @@ -57,7 +57,7 @@ extension ARKController { func runSessionResettingTrackingAndRemovingAnchors(with state: AppState) { updateARConfiguration(with: state) - session?.run(configuration, options: [.resetTracking, .removeExistingAnchors]) + session.run(configuration, options: [.resetTracking, .removeExistingAnchors]) // If we are removing anchors, clear the user map arkitGeneratedAnchorIDUserAnchorIDMap = NSMutableDictionary() arSessionState = .arkSessionRunning @@ -90,7 +90,7 @@ extension ARKController { } else { appDelegate().logger.error("resume session on a face-tracking camera") } - session?.run(configuration, options: []) + session.run(configuration, options: []) arSessionState = .arkSessionRunning setupDeviceCamera() setShowMode(state.showMode) @@ -123,7 +123,7 @@ extension ARKController { } else { appDelegate().logger.error("resume session on a face-tracking camera") } - session?.run(configuration, options: []) + session.run(configuration, options: []) arSessionState = .arkSessionRunning } @@ -131,7 +131,7 @@ extension ARKController { Pauses the AR session and sets the arSessionState to paused */ func pauseSession() { - session?.pause() + session.pause() arSessionState = .arkSessionPaused } @@ -187,11 +187,11 @@ extension ARKController { // MARK: - Helpers func currentFrameTimeInMilliseconds() -> TimeInterval { - return TimeInterval((session?.currentFrame?.timestamp ?? 0.0) * 1000) + return TimeInterval((session.currentFrame?.timestamp ?? 0.0) * 1000) } func trackingStateNormal() -> Bool { - guard let ts = session?.currentFrame?.camera.trackingState.presentationString else { + guard let ts = session.currentFrame?.camera.trackingState.presentationString else { print("Unable to check if camera trackingState presentationString is normal") return false } @@ -199,7 +199,7 @@ extension ARKController { } func trackingStateRelocalizing() -> Bool { - guard let ts = session?.currentFrame?.camera.trackingState.presentationString else { + guard let ts = session.currentFrame?.camera.trackingState.presentationString else { print("Unable to check if camera trackingState presentationString is relocalizing") return false } diff --git a/XRViewer/ARKController/ARKController+Camera.swift b/XRViewer/ARKController/ARKController+Camera.swift index 73428e2..ba99335 100644 --- a/XRViewer/ARKController/ARKController+Camera.swift +++ b/XRViewer/ARKController/ARKController+Camera.swift @@ -1,4 +1,6 @@ -@objc extension ARKController { +import ARKit + +extension ARKController { // MARK: - Camera Device @@ -47,9 +49,9 @@ in the previous ARWorldTrackingConfiguration session, and run the session. */ func switchCameraButtonTapped(_ state: AppState) { // numberOfTrackedImages: Int) { - guard let currentFrame = session?.currentFrame else { return } + guard let currentFrame = session.currentFrame else { return } for anchor in currentFrame.anchors { - session?.remove(anchor: anchor) + session.remove(anchor: anchor) } if !(configuration is ARFaceTrackingConfiguration) { diff --git a/XRViewer/ARKController/ARKController+Frame.swift b/XRViewer/ARKController/ARKController+Frame.swift index d70e01f..00dd026 100644 --- a/XRViewer/ARKController/ARKController+Frame.swift +++ b/XRViewer/ARKController/ARKController+Frame.swift @@ -1,8 +1,9 @@ import Accelerate +import ARKit extension ARKController { - @objc func updateARKData(with frame: ARFrame) { + func updateARKData(with frame: ARFrame) { synced(self) { diff --git a/XRViewer/ARKController/ARKController+Images.swift b/XRViewer/ARKController/ARKController+Images.swift index a668d6d..399de3f 100644 --- a/XRViewer/ARKController/ARKController+Images.swift +++ b/XRViewer/ARKController/ARKController+Images.swift @@ -1,4 +1,5 @@ import Accelerate +import ARKit extension ARKController { @@ -117,7 +118,7 @@ extension ARKController { } detectionImageActivationPromises[referenceImage.name ?? ""] = completion - session?.run(configuration, options: []) + session.run(configuration, options: []) } else { if detectionImageActivationPromises[referenceImage.name ?? ""] != nil { // Trying to reactivate an active image that hasn't been found yet, return an error on the first promise, keep the second @@ -128,7 +129,7 @@ extension ARKController { } else { // Activating an already activated and found image, remove the anchor from the scene // so it can be detected again - guard let anchors = session?.currentFrame?.anchors else { return } + guard let anchors = session.currentFrame?.anchors else { return } for anchor in anchors { if let imageAnchor = anchor as? ARImageAnchor, imageAnchor.referenceImage.name == imageName @@ -138,13 +139,13 @@ extension ARKController { if let currentDetectionImages = currentDetectionImages as? Set { worldTrackingConfiguration?.detectionImages = currentDetectionImages } - session?.run(configuration, options: []) + session.run(configuration, options: []) // When the anchor is removed and didRemoveAnchor callback gets called, look in this map // and see if there is a promise for the recently removed image anchor. If so, call // activateDetectionImage again with the image name of the removed anchor, and the completion set here detectionImageActivationAfterRemovalPromises[referenceImage.name ?? ""] = completion - session?.remove(anchor: anchor) + session.remove(anchor: anchor) return } } @@ -190,7 +191,7 @@ extension ARKController { if let currentDetectionImages = currentDetectionImages as? Set { worldTrackingConfiguration?.detectionImages = currentDetectionImages } - session?.run(configuration, options: []) + session.run(configuration, options: []) completion(true, nil) } else { completion(false, "The image attempting to be deactivated doesn't exist") @@ -230,7 +231,7 @@ extension ARKController { if let currentDetectionImages = currentDetectionImages as? Set { worldTrackingConfiguration?.detectionImages = currentDetectionImages } - session?.run(configuration, options: []) + session.run(configuration, options: []) } } referenceImageMap[imageName] = nil @@ -440,7 +441,7 @@ extension ARKController { func setNumberOfTrackedImages(_ numberOfTrackedImages: Int) { if let trackingConfiguration = configuration as? ARWorldTrackingConfiguration { trackingConfiguration.maximumNumberOfTrackedImages = numberOfTrackedImages - session?.run(trackingConfiguration, options: []) + session.run(trackingConfiguration, options: []) } else { print("Error: Cannot set tracked images on an ARFaceTrackingConfiguration session.") } diff --git a/XRViewer/ARKController/ARKController+WorldMap.swift b/XRViewer/ARKController/ARKController+WorldMap.swift index 71f1481..68e5b99 100644 --- a/XRViewer/ARKController/ARKController+WorldMap.swift +++ b/XRViewer/ARKController/ARKController+WorldMap.swift @@ -1,6 +1,7 @@ import Compression +import ARKit -@objc extension ARKController { +extension ARKController { // MARK: - Saving @@ -20,7 +21,7 @@ import Compression return } - session?.getCurrentWorldMap(completionHandler: { worldMap, error in + session.getCurrentWorldMap(completionHandler: { worldMap, error in if let worldMap = worldMap { appDelegate().logger.error("saving WorldMap to local storage") self._save(worldMap) @@ -56,7 +57,7 @@ import Compression return } - session?.getCurrentWorldMap(completionHandler: { worldMap, error in + session.getCurrentWorldMap(completionHandler: { worldMap, error in if worldMap != nil { appDelegate().logger.error("saving WorldMap as we transition to background") self.backgroundWorldMap = worldMap @@ -154,7 +155,7 @@ import Compression return } - session?.getCurrentWorldMap(completionHandler: { worldMap, error in + session.getCurrentWorldMap(completionHandler: { worldMap, error in if let worldMap = worldMap { if let completion = completion { var mapData = [AnyHashable: Any]() @@ -262,14 +263,14 @@ import Compression worldTrackingConfiguration?.initialWorldMap = map printWorldMapInfo(map) - session?.run(configuration, options: [.resetTracking, .removeExistingAnchors]) + session.run(configuration, options: [.resetTracking, .removeExistingAnchors]) // if we are removing anchors, clear the user map arkitGeneratedAnchorIDUserAnchorIDMap = NSMutableDictionary.init() print("Restarted, loading map.") for anchor in map.anchors { - session?.add(anchor: anchor) + session.add(anchor: anchor) arkitGeneratedAnchorIDUserAnchorIDMap[anchor.identifier.uuidString] = anchor.name ?? "" print("WorldMap loaded anchor: \(anchor.name ?? "nameless anchor")") } @@ -385,7 +386,7 @@ import Compression } func worldMappingAvailable() -> Bool { - guard let ws = session?.currentFrame?.worldMappingStatus else { return false } + guard let ws = session.currentFrame?.worldMappingStatus else { return false } return ws != .notAvailable } diff --git a/XRViewer/ARKController/ARKController.swift b/XRViewer/ARKController/ARKController.swift index 650efcb..2891af6 100644 --- a/XRViewer/ARKController/ARKController.swift +++ b/XRViewer/ARKController/ARKController.swift @@ -2,6 +2,7 @@ import AVFoundation import os import Accelerate import Compression +import ARKit // The ARSessionConfiguration object passed to the run(_:options:) method is not supported by the current device. let UNSUPPORTED_CONFIGURATION_ARKIT_ERROR_CODE = 100 @@ -31,6 +32,59 @@ enum ARKitSessionState : Int { case arkSessionRunning } +/** + Enum representing the WebXR authorization status + + - WebXRAuthorizationStateNotDetermined: The user didn't say anything about the world sensing + - WebXRAuthorizationStateDenied: The user denied sending world sensing data + - WebXRAuthorizationStateMinimal: The user allowed minimal sending world sensing data, which + displays video from the camera without giving the page access to the video + - WebXRAuthorizationStateLite: The user allowed Lite Mode world sensing data, which only shares + one plane from the real world with the site and enables face-based experiences + - WebXRAuthorizationStateWorldSensing: The user allowed sending world sensing data + - WebXRAuthorizationStateVideoCameraAccess: The user allowed access to the video camera and sending world sensing data + + */ +enum WebXRAuthorizationState { + case notDetermined + case denied + case minimal + case lite + case worldSensing + case videoCameraAccess +} + +/** + Show options. This option set is built from the AR Request dictionary received on initAR + + - None: Shows nothing + - Browser: Shows in browser mode + - ARWarnings: Shows warnings reported by ARKit + - ARFocus: Shows a focus node + - ARObject: Shows AR objects + - Debug: Not used + - ARPlanes: Shows AR planes + - ARPoints: Shows AR feature points + - ARStatistics: Shows AR Statistics + - BuildNumber: Shows the app build number + - Full: Shows everything + */ +struct ShowOptions: OptionSet { + let rawValue: Int + + static let none = ShowOptions(rawValue: 0) + static let browser = ShowOptions(rawValue: 1 << 0) + static let arWarnings = ShowOptions(rawValue: 1 << 1) + static let arFocus = ShowOptions(rawValue: 1 << 2) + static let arObject = ShowOptions(rawValue: 1 << 3) + static let debug = ShowOptions(rawValue: 1 << 4) + static let arPlanes = ShowOptions(rawValue: 1 << 5) + static let arPoints = ShowOptions(rawValue: 1 << 6) + static let arStatistics = ShowOptions(rawValue: 1 << 7) + static let buildNumber = ShowOptions(rawValue: 1 << 8) + static let full = ShowOptions(rawValue: Int.max) +} + enum ARKType : Int { case arkMetal case arkSceneKit @@ -43,6 +97,7 @@ typealias SessionInterruptionEnded = () -> Void typealias DidFailSession = (Error?) -> Void typealias DidUpdateWindowSize = () -> Void typealias DetectionImageCreatedCompletionType = (Bool, String?) -> Void +typealias HotAction = (Bool) -> Void class ARKController: NSObject { @@ -79,7 +134,7 @@ class ARKController: NSObject { // A flag representing whether Metal (true) is being used for ARKController or SceneKit (false) var usingMetal = false - var session: ARSession? + var session: ARSession = ARSession() var request: [AnyHashable : Any] = [:] var configuration: ARConfiguration var backgroundWorldMap: ARWorldMap? @@ -113,7 +168,7 @@ class ARKController: NSObject { /// completion block for getWorldMap request var getWorldMapPromise: GetWorldMapCompletionBlock? var device: AVCaptureDevice? - var controller: ARKControllerProtocol + var controller: ARKControllerProtocol! /// The CV image being sent to JS is downscaled using the metho /// downscaleByFactorOf2UntilLargestSideIsLessThan512AvoidingFractionalSides /// This call has a side effect on computerVisionImageScaleFactor, that's later used @@ -146,7 +201,7 @@ class ARKController: NSObject { /// Dictionary that maps a user-generated anchor ID with the one generated by ARKit var arkitGeneratedAnchorIDUserAnchorIDMap = NSMutableDictionary.init() var arkData: [AnyHashable : Any] = [:] - var lock: os_unfair_lock + var lock = os_unfair_lock() var computerVisionData: [AnyHashable : Any] = [:] var showOptions: ShowOptions = .init() @@ -161,7 +216,7 @@ class ARKController: NSObject { appDelegate().logger.debug("WebXR auth changed to video camera access/world sensing") // make sure all the anchors are in the objects[] array, and mark them as added - if let anchors = session?.currentFrame?.anchors { + if let anchors = session.currentFrame?.anchors { for addedAnchor in anchors { if objects[anchorID(for: addedAnchor)] == nil { let addedAnchorDictionary = createDictionary(for: addedAnchor) @@ -180,7 +235,7 @@ class ARKController: NSObject { case .lite, .minimal, .denied: appDelegate().logger.debug("WebXR auth changed to lite/minimal/denied") - if let anchors = session?.currentFrame?.anchors { + if let anchors = session.currentFrame?.anchors { for addedAnchor in anchors { if objects[anchorID(for: addedAnchor)] == nil { // If the anchor was not being sent but is in the approved list, start sending it @@ -209,21 +264,21 @@ class ARKController: NSObject { } init(type: ARKType, rootView: UIView) { - let worldTrackingConfiguration = ARWorldTrackingConfiguration() worldTrackingConfiguration.planeDetection = [.horizontal, .vertical] worldTrackingConfiguration.worldAlignment = .gravityAndHeading configuration = worldTrackingConfiguration - session = ARSession() + webXRAuthorizationStatus = .notDetermined + + super.init() + session.delegate = self arSessionState = .arkSessionUnknown - if type == .arkMetal - { - controller = ARKMetalController(sesion: session!, size: rootView.bounds.size) + if type == .arkMetal { + controller = ARKMetalController(sesion: session, size: rootView.bounds.size) } else { - controller = ARKSceneKitController(sesion: session!, size: rootView.bounds.size) + controller = ARKSceneKitController(sesion: session, size: rootView.bounds.size) } - lock = os_unfair_lock() objects = NSMutableDictionary.init() computerVisionData = [:] arkData = [:] @@ -237,10 +292,10 @@ class ARKController: NSObject { let renderView = controller.getRenderView() rootView.addSubview(renderView) renderView.translatesAutoresizingMaskIntoConstraints = false - renderView.topAnchor.constraint(equalTo: rootView.topAnchor) - renderView.leftAnchor.constraint(equalTo: rootView.leftAnchor) - renderView.rightAnchor.constraint(equalTo: rootView.rightAnchor) - renderView.bottomAnchor.constraint(equalTo: rootView.bottomAnchor) + renderView.topAnchor.constraint(equalTo: rootView.topAnchor).isActive = true + renderView.leftAnchor.constraint(equalTo: rootView.leftAnchor).isActive = true + renderView.rightAnchor.constraint(equalTo: rootView.rightAnchor).isActive = true + renderView.bottomAnchor.constraint(equalTo: rootView.bottomAnchor).isActive = true controller.setHitTestFocus(renderView.center) @@ -253,7 +308,6 @@ class ARKController: NSObject { computerVisionImageScaleFactor = 4.0 lumaBufferSize = CGSize(width: 0.0, height: 0.0) - webXRAuthorizationStatus = .notDetermined detectionImageActivationPromises = NSMutableDictionary.init() referenceImageMap = NSMutableDictionary.init() detectionImageCreationRequests = NSMutableArray.init() @@ -274,9 +328,6 @@ class ARKController: NSObject { appDelegate().logger.debug("Couldn't create map save directory") } worldSaveURL = newDir.appendingPathComponent("webxrviewer") - - super.init() - session?.delegate = self } deinit { diff --git a/XRViewer/ARKController/ARKControllerProtocol.swift b/XRViewer/ARKController/ARKControllerProtocol.swift index fab6057..839f0dc 100644 --- a/XRViewer/ARKController/ARKControllerProtocol.swift +++ b/XRViewer/ARKController/ARKControllerProtocol.swift @@ -1,4 +1,6 @@ -@objc protocol ARKControllerProtocol: NSObjectProtocol { +import ARKit + +protocol ARKControllerProtocol: NSObjectProtocol { init(sesion session: ARSession, size: CGSize) func update(_ session: ARSession) func clean() diff --git a/XRViewer/ARKController/ARKHelper.h b/XRViewer/ARKController/ARKHelper.h deleted file mode 100644 index 7743fac..0000000 --- a/XRViewer/ARKController/ARKHelper.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef ARKHelper_h -#define ARKHelper_h - -#import -#import -#import -#import - -/** - Enum representing the WebXR authorization status - - - WebXRAuthorizationStateNotDetermined: The user didn't say anything about the world sensing - - WebXRAuthorizationStateDenied: The user denied sending world sensing data - - WebXRAuthorizationStateMinimal: The user allowed minimal sending world sensing data, which - displays video from the camera without giving the page access to the video - - WebXRAuthorizationStateLite: The user allowed Lite Mode world sensing data, which only shares - one plane from the real world with the site and enables face-based experiences - - WebXRAuthorizationStateWorldSensing: The user allowed sending world sensing data - - WebXRAuthorizationStateVideoCameraAccess: The user allowed access to the video camera and sending world sensing data - - */ -typedef NS_ENUM(NSUInteger, WebXRAuthorizationState) -{ - WebXRAuthorizationStateNotDetermined, - WebXRAuthorizationStateDenied, - WebXRAuthorizationStateMinimal, - WebXRAuthorizationStateLite, - WebXRAuthorizationStateWorldSensing, - WebXRAuthorizationStateVideoCameraAccess -}; - -/** - Show options. This option set is built from the AR Request dictionary received on initAR - - - None: Shows nothing - - Browser: Shows in browser mode - - ARWarnings: Shows warnings reported by ARKit - - ARFocus: Shows a focus node - - ARObject: Shows AR objects - - Debug: Not used - - ARPlanes: Shows AR planes - - ARPoints: Shows AR feature points - - ARStatistics: Shows AR Statistics - - BuildNumber: Shows the app build number - - Full: Shows everything - */ -typedef NS_OPTIONS(NSUInteger, ShowOptions) -{ - None = 0, - Browser = (1 << 0), - ARWarnings = (1 << 1), - ARFocus = (1 << 2), - ARObject = (1 << 3), - Debug = (1 << 4), - ARPlanes = (1 << 5), - ARPoints = (1 << 6), - ARStatistics = (1 << 7), - BuildNumber = (1 << 8), - Full = NSUIntegerMax -}; - -static inline NSDictionary * dictFromVector3(vector_float3 vector) -{ - return @{@"x" : @(vector.x), @"y" : @(vector.y), @"z" : @(vector.z)}; -} - -#endif /* ARKHelper_h */ diff --git a/XRViewer/ARKController/HitTestResult.swift b/XRViewer/ARKController/HitTestResult.swift index cf5ac8a..21d91b5 100644 --- a/XRViewer/ARKController/HitTestResult.swift +++ b/XRViewer/ARKController/HitTestResult.swift @@ -1,4 +1,4 @@ -import Foundation +import ARKit class HitTestResult: NSObject { var position: SCNVector3? diff --git a/XRViewer/ARKController/SceneKit/ARKSceneKitController.swift b/XRViewer/ARKController/SceneKit/ARKSceneKitController.swift index 54e6e5a..cee87c7 100644 --- a/XRViewer/ARKController/SceneKit/ARKSceneKitController.swift +++ b/XRViewer/ARKController/SceneKit/ARKSceneKitController.swift @@ -32,6 +32,9 @@ class ARKSceneKitController: NSObject, ARKControllerProtocol, ARSCNViewDelegate } } } + var readyToRenderFrame: Bool = true + var initializingRender: Bool = true + var renderer: Renderer! = nil deinit { renderView.delegate = nil @@ -91,8 +94,8 @@ class ARKSceneKitController: NSObject, ARKControllerProtocol, ARSCNViewDelegate guard let showMode = showMode else { return } guard let showOptions = showOptions else { return } if showMode == ShowMode.urlDebug || showMode == ShowMode.debug { - renderView.showsStatistics = (showOptions.rawValue & ShowOptions.ARStatistics.rawValue) != 0 - renderView.debugOptions = (showOptions.rawValue & ShowOptions.ARPoints.rawValue) != 0 ? .showFeaturePoints : [] + renderView.showsStatistics = (showOptions.rawValue & ShowOptions.arStatistics.rawValue) != 0 + renderView.debugOptions = (showOptions.rawValue & ShowOptions.arPoints.rawValue) != 0 ? .showFeaturePoints : [] } else { renderView.showsStatistics = false renderView.debugOptions = [] @@ -106,7 +109,7 @@ class ARKSceneKitController: NSObject, ARKControllerProtocol, ARSCNViewDelegate case .normal: focus?.show(false) default: - focus?.show((showOptions.rawValue & ShowOptions.ARFocus.rawValue) != 0) + focus?.show((showOptions.rawValue & ShowOptions.arFocus.rawValue) != 0) } } @@ -151,7 +154,7 @@ class ARKSceneKitController: NSObject, ARKControllerProtocol, ARSCNViewDelegate func hitTest() { guard let showOptions = showOptions else { return } // hit testing only for Focus node! - if (showOptions.rawValue & ShowOptions.ARFocus.rawValue) != 0 { + if (showOptions.rawValue & ShowOptions.arFocus.rawValue) != 0 { if let aFocus = renderView.hitTest(point: hitTestFocusPoint, withResult: { result in self.currentHitTest = result @@ -178,7 +181,7 @@ class ARKSceneKitController: NSObject, ARKControllerProtocol, ARSCNViewDelegate func updateFocus() { guard let showOptions = showOptions else { return } if currentHitTest != nil { - focus?.show((showOptions.rawValue & ShowOptions.ARFocus.rawValue) != 0) + focus?.show((showOptions.rawValue & ShowOptions.arFocus.rawValue) != 0) } else { focus?.show(false) } @@ -209,14 +212,14 @@ class ARKSceneKitController: NSObject, ARKControllerProtocol, ARSCNViewDelegate guard let showOptions = showOptions else { return } for (_, plane) in planes { plane.geometry?.firstMaterial?.diffuse.contents = focusedPlane == plane ? UIImage(named: "Models.scnassets/plane_grid2.png") : UIImage(named: "Models.scnassets/plane_grid1.png") - plane.show(((showMode == ShowMode.urlDebug) && (showOptions.rawValue & ShowOptions.ARPlanes.rawValue) != 0) || ((showMode == ShowMode.debug) && (showOptions.rawValue & ShowOptions.ARPlanes.rawValue) != 0) || previewingSinglePlane) + plane.show(((showMode == ShowMode.urlDebug) && (showOptions.rawValue & ShowOptions.arPlanes.rawValue) != 0) || ((showMode == ShowMode.debug) && (showOptions.rawValue & ShowOptions.arPlanes.rawValue) != 0) || previewingSinglePlane) } } func updateAnchors() { guard let showOptions = showOptions else { return } for anchor in anchorsNodes { - anchor.show((showOptions.rawValue & ShowOptions.ARObject.rawValue) != 0) + anchor.show((showOptions.rawValue & ShowOptions.arObject.rawValue) != 0) } } @@ -298,8 +301,4 @@ class ARKSceneKitController: NSObject, ARKControllerProtocol, ARSCNViewDelegate func setShowOptions(_ options: ShowOptions) { showOptions = options } - - var readyToRenderFrame: Bool = true - var initializingRender: Bool = true - var renderer: Renderer! = nil } diff --git a/XRViewer/ARKController/SceneKit/FocusNode.swift b/XRViewer/ARKController/SceneKit/FocusNode.swift index 76b620e..67fbe00 100644 --- a/XRViewer/ARKController/SceneKit/FocusNode.swift +++ b/XRViewer/ARKController/SceneKit/FocusNode.swift @@ -1,4 +1,5 @@ import SceneKit +import ARKit class FocusNode: SCNNode { diff --git a/XRViewer/ARKController/SceneKit/Models.scnassets/plane_grid1.png b/XRViewer/ARKController/SceneKit/Models.scnassets/plane_grid1.png old mode 100644 new mode 100755 diff --git a/XRViewer/AppStateController/AppState.swift b/XRViewer/AppStateController/AppState.swift index fb8aebc..2213ad8 100644 --- a/XRViewer/AppStateController/AppState.swift +++ b/XRViewer/AppStateController/AppState.swift @@ -18,7 +18,7 @@ import Foundation var numberOfTrackedImages: Int = 0 @objc var userGrantedSendingComputerVisionData = false @objc var askedComputerVisionData = false - @objc var userGrantedSendingWorldStateData: WebXRAuthorizationState = .notDetermined + var userGrantedSendingWorldStateData: WebXRAuthorizationState = .notDetermined @objc var askedWorldStateData = false class func defaultState() -> AppState { diff --git a/XRViewer/Resources/XRViewer-Bridging-Header.h b/XRViewer/Resources/XRViewer-Bridging-Header.h index 084db4f..75e5336 100644 --- a/XRViewer/Resources/XRViewer-Bridging-Header.h +++ b/XRViewer/Resources/XRViewer-Bridging-Header.h @@ -2,7 +2,4 @@ // Use this file to import your target's public headers that you would like to expose to Swift. // -#import "ARKHelper.h" #import "ShaderTypes.h" - -typedef void (^HotAction)(BOOL); // long diff --git a/XRViewer/Utilities/Constants.swift b/XRViewer/Utilities/Constants.swift index 1b2db82..a40234d 100644 --- a/XRViewer/Utilities/Constants.swift +++ b/XRViewer/Utilities/Constants.swift @@ -4,6 +4,7 @@ // Copyright © 2018 Mozilla. All rights reserved. import Foundation +import ARKit /// The NSUserDefaults key for the boolean that tells us whether /// the AnalyticsManager should be used diff --git a/XRViewer/Utilities/Utils.swift b/XRViewer/Utilities/Utils.swift index fee0221..4d73caf 100644 --- a/XRViewer/Utilities/Utils.swift +++ b/XRViewer/Utilities/Utils.swift @@ -126,6 +126,14 @@ func appDelegate() -> AppDelegate { return UIApplication.shared.delegate as! AppDelegate } +func dictFromVector3(_ vector: vector_float3) -> NSDictionary { + return [ + "x": vector.x, + "y": vector.y, + "z": vector.z + ] +} + class ClosureSleeve { let closure: ()->() diff --git a/XRViewer/WebController.swift b/XRViewer/WebController.swift index e8c949b..43d7eca 100644 --- a/XRViewer/WebController.swift +++ b/XRViewer/WebController.swift @@ -191,7 +191,7 @@ class WebController: NSObject, WKUIDelegate, WKNavigationDelegate, WKScriptMessa }) } - @objc func userGrantedWebXRAuthorizationState(_ access: WebXRAuthorizationState) { + func userGrantedWebXRAuthorizationState(_ access: WebXRAuthorizationState) { // This may change, in one of two ways: // - should probably switch this to one method that updates all aspects of the state we want // the page to know @@ -529,7 +529,7 @@ class WebController: NSObject, WKUIDelegate, WKNavigationDelegate, WKScriptMessa webView?.isOpaque = false webView?.backgroundColor = UIColor.clear webView?.isUserInteractionEnabled = true - webView?.scrollView.bounces = false + // webView?.scrollView.bounces = false webView?.scrollView.bouncesZoom = false } diff --git a/XRViewer/WebXRPlugin.swift b/XRViewer/WebXRPlugin.swift index 83faa94..822fe74 100644 --- a/XRViewer/WebXRPlugin.swift +++ b/XRViewer/WebXRPlugin.swift @@ -1,6 +1,7 @@ import Foundation import AVFoundation import WebKit +import ARKit @objc(WebXRPlugin) class WebXRPlugin : CDVPlugin { @@ -43,6 +44,7 @@ class WebXRPlugin : CDVPlugin { setupTargetControllers() } + // 9/3/19: Commenting to monitor default failure response and frequency // override func didReceiveMemoryWarning() { // super.didReceiveMemoryWarning() // appDelegate().logger.error("didReceiveMemoryWarning") @@ -447,7 +449,7 @@ class WebXRPlugin : CDVPlugin { if arkController?.usingMetal ?? false { arkController?.controller.renderer.rendererShouldUpdateFrame = { block in - if let frame = blockSelf?.arkController?.session?.currentFrame { + if let frame = blockSelf?.arkController?.session.currentFrame { blockSelf?.arkController?.controller.readyToRenderFrame = false blockSelf?.savedRender = block blockSelf?.arkController?.updateARKData(with: frame) @@ -729,45 +731,45 @@ class WebXRPlugin : CDVPlugin { private func showOptionsFormDict(dict: [AnyHashable : Any]?) -> ShowOptions { if dict == nil { - return .Browser + return .browser } var options: ShowOptions = .init(rawValue: 0) if (dict?[WEB_AR_UI_BROWSER_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .Browser] + options = [options, .browser] } if (dict?[WEB_AR_UI_POINTS_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .ARPoints] + options = [options, .arPoints] } if (dict?[WEB_AR_UI_DEBUG_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .Debug] + options = [options, .debug] } if (dict?[WEB_AR_UI_STATISTICS_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .ARStatistics] + options = [options, .arStatistics] } if (dict?[WEB_AR_UI_FOCUS_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .ARFocus] + options = [options, .arFocus] } if (dict?[WEB_AR_UI_BUILD_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .BuildNumber] + options = [options, .buildNumber] } if (dict?[WEB_AR_UI_PLANE_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .ARPlanes] + options = [options, .arPlanes] } if (dict?[WEB_AR_UI_WARNINGS_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .ARWarnings] + options = [options, .arWarnings] } if (dict?[WEB_AR_UI_ANCHORS_OPTION] as? NSNumber)?.boolValue ?? false { - options = [options, .ARObject] + options = [options, .arObject] } return options @@ -1054,7 +1056,7 @@ class WebXRPlugin : CDVPlugin { if let arController = arkController?.controller as? ARKMetalController { guard let chosenPlane = arController.focusedPlane else { return } if let anchorIdentifier = arController.planes.someKey(forValue: chosenPlane) { - let allFrameAnchors = arkController?.session?.currentFrame?.anchors + let allFrameAnchors = arkController?.session.currentFrame?.anchors let anchor = allFrameAnchors?.filter { $0.identifier == anchorIdentifier }.first if let anchor = anchor { let addedAnchorDictionary = arkController?.createDictionary(for: anchor) @@ -1065,7 +1067,7 @@ class WebXRPlugin : CDVPlugin { } else if let arController = arkController?.controller as? ARKSceneKitController { guard let chosenPlane = arController.focusedPlane else { return } if let anchorIdentifier = arController.planes.someKey(forValue: chosenPlane) { - let allFrameAnchors = arkController?.session?.currentFrame?.anchors + let allFrameAnchors = arkController?.session.currentFrame?.anchors let anchor = allFrameAnchors?.filter { $0.identifier == anchorIdentifier }.first if let anchor = anchor { let addedAnchorDictionary = arkController?.createDictionary(for: anchor) diff --git a/package.json b/package.json index 037c94a..d4624cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cordova-plugin-webxr", - "version": "1.17.3", + "version": "1.17.4", "description": "WebXR Plugin", "cordova": { "id": "cordova-plugin-webxr", diff --git a/plugin.xml b/plugin.xml index b7712ba..3595efd 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,4 +1,4 @@ - + WebXR WebXR Plugin Thomas Zachariah @@ -22,7 +22,6 @@ $CAMERA_USAGE_DESCRIPTION -