~connorbell/ARSDFView

1cf3e26c3270a0dd1a3c20aae90b9db7978fbaf9 — Connor Bell 1 year, 6 months ago
First commit after migrating to framework from prototype app.
50 files changed, 3671 insertions(+), 0 deletions(-)

A .gitignore
A AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/project.pbxproj
A AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/project.xcworkspace/contents.xcworkspacedata
A AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
A AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/project.xcworkspace/xcuserdata/connorbell.xcuserdatad/UserInterfaceState.xcuserstate
A AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/xcuserdata/connorbell.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
A AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/xcuserdata/connorbell.xcuserdatad/xcschemes/xcschememanagement.plist
A AR-SDF-Renderer/AR-SDF-Renderer/AppDelegate.swift
A AR-SDF-Renderer/AR-SDF-Renderer/Assets.xcassets/AccentColor.colorset/Contents.json
A AR-SDF-Renderer/AR-SDF-Renderer/Assets.xcassets/AppIcon.appiconset/Contents.json
A AR-SDF-Renderer/AR-SDF-Renderer/Assets.xcassets/Contents.json
A AR-SDF-Renderer/AR-SDF-Renderer/Base.lproj/LaunchScreen.storyboard
A AR-SDF-Renderer/AR-SDF-Renderer/Base.lproj/Main.storyboard
A AR-SDF-Renderer/AR-SDF-Renderer/Info.plist
A AR-SDF-Renderer/AR-SDF-Renderer/SceneDelegate.swift
A AR-SDF-Renderer/AR-SDF-Renderer/ViewController.swift
A AR-SDF-Renderer/AR-SDF-RendererTests/AR_SDF_RendererTests.swift
A AR-SDF-Renderer/AR-SDF-RendererUITests/AR_SDF_RendererUITests.swift
A AR-SDF-Renderer/AR-SDF-RendererUITests/AR_SDF_RendererUITestsLaunchTests.swift
A AR-SDF/AR-SDF.xcodeproj/project.pbxproj
A AR-SDF/AR-SDF.xcodeproj/project.xcworkspace/contents.xcworkspacedata
A AR-SDF/AR-SDF.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
A AR-SDF/AR-SDF.xcodeproj/project.xcworkspace/xcuserdata/connorbell.xcuserdatad/UserInterfaceState.xcuserstate
A AR-SDF/AR-SDF.xcodeproj/xcuserdata/connorbell.xcuserdatad/xcschemes/xcschememanagement.plist
A AR-SDF/AR-SDF/ARManager.swift
A AR-SDF/AR-SDF/ARSDFView.swift
A AR-SDF/AR-SDF/AR_SDF.docc/AR_SDF.md
A AR-SDF/AR-SDF/AR_SDF.h
A AR-SDF/AR-SDF/ComputePass.swift
A AR-SDF/AR-SDF/Conemarcher.swift
A AR-SDF/AR-SDF/Extensions/CVPixelBuffer+MTLTexture.swift
A AR-SDF/AR-SDF/Extensions/Float4x4+Extensions.swift
A AR-SDF/AR-SDF/Extensions/MTLTexture+Extensions.swift
A AR-SDF/AR-SDF/Extensions/UIInterfaceOrientation+Extensions.swift
A AR-SDF/AR-SDF/MetalManager.swift
A AR-SDF/AR-SDF/MetalView.swift
A AR-SDF/AR-SDF/Models/ARData.swift
A AR-SDF/AR-SDF/Models/DistanceField.swift
A AR-SDF/AR-SDF/Models/TextureUniform.swift
A AR-SDF/AR-SDF/Models/Uniform.swift
A AR-SDF/AR-SDF/RendererDelegate.swift
A AR-SDF/AR-SDF/Shaders/Common.h
A AR-SDF/AR-SDF/Shaders/Conemarcher.metal
A AR-SDF/AR-SDF/Shaders/DistanceFields.h
A AR-SDF/AR-SDF/Shaders/DistanceFields.metal
A AR-SDF/AR-SDF/Shaders/OrientationTransforms.h
A AR-SDF/AR-SDF/Shaders/OrientationTransforms.metal
A AR-SDF/AR-SDF/Shaders/PostFxPass.metal
A AR-SDF/AR-SDF/Shaders/YCbCrToRGB.metal
A AR-SDF/AR-SDFTests/AR_SDFTests.swift
A  => .gitignore +1 -0
@@ 1,1 @@
.DS_Store

A  => AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/project.pbxproj +703 -0
@@ 1,703 @@
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 55;
	objects = {

/* Begin PBXBuildFile section */
		B9D8709327C0185500775F31 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8709227C0185500775F31 /* AppDelegate.swift */; };
		B9D8709527C0185500775F31 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8709427C0185500775F31 /* SceneDelegate.swift */; };
		B9D8709727C0185500775F31 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8709627C0185500775F31 /* ViewController.swift */; };
		B9D8709A27C0185500775F31 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9D8709827C0185500775F31 /* Main.storyboard */; };
		B9D8709C27C0185800775F31 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B9D8709B27C0185800775F31 /* Assets.xcassets */; };
		B9D8709F27C0185800775F31 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9D8709D27C0185800775F31 /* LaunchScreen.storyboard */; };
		B9D870AA27C0185800775F31 /* AR_SDF_RendererTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D870A927C0185800775F31 /* AR_SDF_RendererTests.swift */; };
		B9D870B427C0185800775F31 /* AR_SDF_RendererUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D870B327C0185800775F31 /* AR_SDF_RendererUITests.swift */; };
		B9D870B627C0185800775F31 /* AR_SDF_RendererUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D870B527C0185800775F31 /* AR_SDF_RendererUITestsLaunchTests.swift */; };
		B9D8715527C13AEF00775F31 /* AR_SDF.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9D8714D27C058CA00775F31 /* AR_SDF.framework */; platformFilter = ios; };
		B9D8715627C13AEF00775F31 /* AR_SDF.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B9D8714D27C058CA00775F31 /* AR_SDF.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
		B9D870A627C0185800775F31 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = B9D8708727C0185500775F31 /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = B9D8708E27C0185500775F31;
			remoteInfo = "AR-SDF-Renderer";
		};
		B9D870B027C0185800775F31 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = B9D8708727C0185500775F31 /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = B9D8708E27C0185500775F31;
			remoteInfo = "AR-SDF-Renderer";
		};
		B9D8714C27C058CA00775F31 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = B9D8714727C058CA00775F31 /* AR-SDF.xcodeproj */;
			proxyType = 2;
			remoteGlobalIDString = B9D8703327BFF97900775F31;
			remoteInfo = "AR-SDF";
		};
		B9D8714E27C058CA00775F31 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = B9D8714727C058CA00775F31 /* AR-SDF.xcodeproj */;
			proxyType = 2;
			remoteGlobalIDString = B9D8703D27BFF97A00775F31;
			remoteInfo = "AR-SDFTests";
		};
/* End PBXContainerItemProxy section */

/* Begin PBXCopyFilesBuildPhase section */
		B9D8715727C13AF000775F31 /* Embed Frameworks */ = {
			isa = PBXCopyFilesBuildPhase;
			buildActionMask = 2147483647;
			dstPath = "";
			dstSubfolderSpec = 10;
			files = (
				B9D8715627C13AEF00775F31 /* AR_SDF.framework in Embed Frameworks */,
			);
			name = "Embed Frameworks";
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
		B9D8708F27C0185500775F31 /* AR-SDF-Renderer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AR-SDF-Renderer.app"; sourceTree = BUILT_PRODUCTS_DIR; };
		B9D8709227C0185500775F31 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
		B9D8709427C0185500775F31 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
		B9D8709627C0185500775F31 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
		B9D8709927C0185500775F31 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
		B9D8709B27C0185800775F31 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
		B9D8709E27C0185800775F31 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
		B9D870A027C0185800775F31 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		B9D870A527C0185800775F31 /* AR-SDF-RendererTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AR-SDF-RendererTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
		B9D870A927C0185800775F31 /* AR_SDF_RendererTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AR_SDF_RendererTests.swift; sourceTree = "<group>"; };
		B9D870AF27C0185800775F31 /* AR-SDF-RendererUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AR-SDF-RendererUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
		B9D870B327C0185800775F31 /* AR_SDF_RendererUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AR_SDF_RendererUITests.swift; sourceTree = "<group>"; };
		B9D870B527C0185800775F31 /* AR_SDF_RendererUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AR_SDF_RendererUITestsLaunchTests.swift; sourceTree = "<group>"; };
		B9D8714727C058CA00775F31 /* AR-SDF.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "AR-SDF.xcodeproj"; path = "../AR-SDF/AR-SDF.xcodeproj"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		B9D8708C27C0185500775F31 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D8715527C13AEF00775F31 /* AR_SDF.framework in Frameworks */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D870A227C0185800775F31 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D870AC27C0185800775F31 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		B9D8708627C0185500775F31 = {
			isa = PBXGroup;
			children = (
				B9D8714727C058CA00775F31 /* AR-SDF.xcodeproj */,
				B9D8709127C0185500775F31 /* AR-SDF-Renderer */,
				B9D870A827C0185800775F31 /* AR-SDF-RendererTests */,
				B9D870B227C0185800775F31 /* AR-SDF-RendererUITests */,
				B9D8709027C0185500775F31 /* Products */,
				B9D8715427C13AEF00775F31 /* Frameworks */,
			);
			sourceTree = "<group>";
		};
		B9D8709027C0185500775F31 /* Products */ = {
			isa = PBXGroup;
			children = (
				B9D8708F27C0185500775F31 /* AR-SDF-Renderer.app */,
				B9D870A527C0185800775F31 /* AR-SDF-RendererTests.xctest */,
				B9D870AF27C0185800775F31 /* AR-SDF-RendererUITests.xctest */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		B9D8709127C0185500775F31 /* AR-SDF-Renderer */ = {
			isa = PBXGroup;
			children = (
				B9D8709227C0185500775F31 /* AppDelegate.swift */,
				B9D8709427C0185500775F31 /* SceneDelegate.swift */,
				B9D8709627C0185500775F31 /* ViewController.swift */,
				B9D8709827C0185500775F31 /* Main.storyboard */,
				B9D8709B27C0185800775F31 /* Assets.xcassets */,
				B9D8709D27C0185800775F31 /* LaunchScreen.storyboard */,
				B9D870A027C0185800775F31 /* Info.plist */,
			);
			path = "AR-SDF-Renderer";
			sourceTree = "<group>";
		};
		B9D870A827C0185800775F31 /* AR-SDF-RendererTests */ = {
			isa = PBXGroup;
			children = (
				B9D870A927C0185800775F31 /* AR_SDF_RendererTests.swift */,
			);
			path = "AR-SDF-RendererTests";
			sourceTree = "<group>";
		};
		B9D870B227C0185800775F31 /* AR-SDF-RendererUITests */ = {
			isa = PBXGroup;
			children = (
				B9D870B327C0185800775F31 /* AR_SDF_RendererUITests.swift */,
				B9D870B527C0185800775F31 /* AR_SDF_RendererUITestsLaunchTests.swift */,
			);
			path = "AR-SDF-RendererUITests";
			sourceTree = "<group>";
		};
		B9D8714827C058CA00775F31 /* Products */ = {
			isa = PBXGroup;
			children = (
				B9D8714D27C058CA00775F31 /* AR_SDF.framework */,
				B9D8714F27C058CA00775F31 /* AR-SDFTests.xctest */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		B9D8715427C13AEF00775F31 /* Frameworks */ = {
			isa = PBXGroup;
			children = (
			);
			name = Frameworks;
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
		B9D8708E27C0185500775F31 /* AR-SDF-Renderer */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = B9D870B927C0185800775F31 /* Build configuration list for PBXNativeTarget "AR-SDF-Renderer" */;
			buildPhases = (
				B9D8708B27C0185500775F31 /* Sources */,
				B9D8708C27C0185500775F31 /* Frameworks */,
				B9D8708D27C0185500775F31 /* Resources */,
				B9D8715727C13AF000775F31 /* Embed Frameworks */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = "AR-SDF-Renderer";
			productName = "AR-SDF-Renderer";
			productReference = B9D8708F27C0185500775F31 /* AR-SDF-Renderer.app */;
			productType = "com.apple.product-type.application";
		};
		B9D870A427C0185800775F31 /* AR-SDF-RendererTests */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = B9D870BC27C0185800775F31 /* Build configuration list for PBXNativeTarget "AR-SDF-RendererTests" */;
			buildPhases = (
				B9D870A127C0185800775F31 /* Sources */,
				B9D870A227C0185800775F31 /* Frameworks */,
				B9D870A327C0185800775F31 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
				B9D870A727C0185800775F31 /* PBXTargetDependency */,
			);
			name = "AR-SDF-RendererTests";
			productName = "AR-SDF-RendererTests";
			productReference = B9D870A527C0185800775F31 /* AR-SDF-RendererTests.xctest */;
			productType = "com.apple.product-type.bundle.unit-test";
		};
		B9D870AE27C0185800775F31 /* AR-SDF-RendererUITests */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = B9D870BF27C0185800775F31 /* Build configuration list for PBXNativeTarget "AR-SDF-RendererUITests" */;
			buildPhases = (
				B9D870AB27C0185800775F31 /* Sources */,
				B9D870AC27C0185800775F31 /* Frameworks */,
				B9D870AD27C0185800775F31 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
				B9D870B127C0185800775F31 /* PBXTargetDependency */,
			);
			name = "AR-SDF-RendererUITests";
			productName = "AR-SDF-RendererUITests";
			productReference = B9D870AF27C0185800775F31 /* AR-SDF-RendererUITests.xctest */;
			productType = "com.apple.product-type.bundle.ui-testing";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		B9D8708727C0185500775F31 /* Project object */ = {
			isa = PBXProject;
			attributes = {
				BuildIndependentTargetsInParallel = 1;
				LastSwiftUpdateCheck = 1310;
				LastUpgradeCheck = 1310;
				TargetAttributes = {
					B9D8708E27C0185500775F31 = {
						CreatedOnToolsVersion = 13.1;
					};
					B9D870A427C0185800775F31 = {
						CreatedOnToolsVersion = 13.1;
						TestTargetID = B9D8708E27C0185500775F31;
					};
					B9D870AE27C0185800775F31 = {
						CreatedOnToolsVersion = 13.1;
						TestTargetID = B9D8708E27C0185500775F31;
					};
				};
			};
			buildConfigurationList = B9D8708A27C0185500775F31 /* Build configuration list for PBXProject "AR-SDF-Renderer" */;
			compatibilityVersion = "Xcode 13.0";
			developmentRegion = en;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = B9D8708627C0185500775F31;
			productRefGroup = B9D8709027C0185500775F31 /* Products */;
			projectDirPath = "";
			projectReferences = (
				{
					ProductGroup = B9D8714827C058CA00775F31 /* Products */;
					ProjectRef = B9D8714727C058CA00775F31 /* AR-SDF.xcodeproj */;
				},
			);
			projectRoot = "";
			targets = (
				B9D8708E27C0185500775F31 /* AR-SDF-Renderer */,
				B9D870A427C0185800775F31 /* AR-SDF-RendererTests */,
				B9D870AE27C0185800775F31 /* AR-SDF-RendererUITests */,
			);
		};
/* End PBXProject section */

/* Begin PBXReferenceProxy section */
		B9D8714D27C058CA00775F31 /* AR_SDF.framework */ = {
			isa = PBXReferenceProxy;
			fileType = wrapper.framework;
			path = AR_SDF.framework;
			remoteRef = B9D8714C27C058CA00775F31 /* PBXContainerItemProxy */;
			sourceTree = BUILT_PRODUCTS_DIR;
		};
		B9D8714F27C058CA00775F31 /* AR-SDFTests.xctest */ = {
			isa = PBXReferenceProxy;
			fileType = wrapper.cfbundle;
			path = "AR-SDFTests.xctest";
			remoteRef = B9D8714E27C058CA00775F31 /* PBXContainerItemProxy */;
			sourceTree = BUILT_PRODUCTS_DIR;
		};
/* End PBXReferenceProxy section */

/* Begin PBXResourcesBuildPhase section */
		B9D8708D27C0185500775F31 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D8709F27C0185800775F31 /* LaunchScreen.storyboard in Resources */,
				B9D8709C27C0185800775F31 /* Assets.xcassets in Resources */,
				B9D8709A27C0185500775F31 /* Main.storyboard in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D870A327C0185800775F31 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D870AD27C0185800775F31 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		B9D8708B27C0185500775F31 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D8709727C0185500775F31 /* ViewController.swift in Sources */,
				B9D8709327C0185500775F31 /* AppDelegate.swift in Sources */,
				B9D8709527C0185500775F31 /* SceneDelegate.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D870A127C0185800775F31 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D870AA27C0185800775F31 /* AR_SDF_RendererTests.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D870AB27C0185800775F31 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D870B627C0185800775F31 /* AR_SDF_RendererUITestsLaunchTests.swift in Sources */,
				B9D870B427C0185800775F31 /* AR_SDF_RendererUITests.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
		B9D870A727C0185800775F31 /* PBXTargetDependency */ = {
			isa = PBXTargetDependency;
			target = B9D8708E27C0185500775F31 /* AR-SDF-Renderer */;
			targetProxy = B9D870A627C0185800775F31 /* PBXContainerItemProxy */;
		};
		B9D870B127C0185800775F31 /* PBXTargetDependency */ = {
			isa = PBXTargetDependency;
			target = B9D8708E27C0185500775F31 /* AR-SDF-Renderer */;
			targetProxy = B9D870B027C0185800775F31 /* PBXContainerItemProxy */;
		};
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
		B9D8709827C0185500775F31 /* Main.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				B9D8709927C0185500775F31 /* Base */,
			);
			name = Main.storyboard;
			sourceTree = "<group>";
		};
		B9D8709D27C0185800775F31 /* LaunchScreen.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				B9D8709E27C0185800775F31 /* Base */,
			);
			name = LaunchScreen.storyboard;
			sourceTree = "<group>";
		};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
		B9D870B727C0185800775F31 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = dwarf;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				GCC_DYNAMIC_NO_PIC = NO;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
				MTL_FAST_MATH = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = iphoneos;
				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
			};
			name = Debug;
		};
		B9D870B827C0185800775F31 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
				ENABLE_NS_ASSERTIONS = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
				MTL_ENABLE_DEBUG_INFO = NO;
				MTL_FAST_MATH = YES;
				SDKROOT = iphoneos;
				SWIFT_COMPILATION_MODE = wholemodule;
				SWIFT_OPTIMIZATION_LEVEL = "-O";
				VALIDATE_PRODUCT = YES;
			};
			name = Release;
		};
		B9D870BA27C0185800775F31 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				GENERATE_INFOPLIST_FILE = YES;
				INFOPLIST_FILE = "AR-SDF-Renderer/Info.plist";
				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
				INFOPLIST_KEY_UIMainStoryboardFile = Main;
				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDF-Renderer";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = YES;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Debug;
		};
		B9D870BB27C0185800775F31 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				GENERATE_INFOPLIST_FILE = YES;
				INFOPLIST_FILE = "AR-SDF-Renderer/Info.plist";
				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
				INFOPLIST_KEY_UIMainStoryboardFile = Main;
				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDF-Renderer";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = YES;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Release;
		};
		B9D870BD27C0185800775F31 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				BUNDLE_LOADER = "$(TEST_HOST)";
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				GENERATE_INFOPLIST_FILE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@loader_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDF-RendererTests";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = NO;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AR-SDF-Renderer.app/AR-SDF-Renderer";
			};
			name = Debug;
		};
		B9D870BE27C0185800775F31 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				BUNDLE_LOADER = "$(TEST_HOST)";
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				GENERATE_INFOPLIST_FILE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@loader_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDF-RendererTests";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = NO;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AR-SDF-Renderer.app/AR-SDF-Renderer";
			};
			name = Release;
		};
		B9D870C027C0185800775F31 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				GENERATE_INFOPLIST_FILE = YES;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@loader_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDF-RendererUITests";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = NO;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
				TEST_TARGET_NAME = "AR-SDF-Renderer";
			};
			name = Debug;
		};
		B9D870C127C0185800775F31 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				GENERATE_INFOPLIST_FILE = YES;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@loader_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDF-RendererUITests";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = NO;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
				TEST_TARGET_NAME = "AR-SDF-Renderer";
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		B9D8708A27C0185500775F31 /* Build configuration list for PBXProject "AR-SDF-Renderer" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				B9D870B727C0185800775F31 /* Debug */,
				B9D870B827C0185800775F31 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		B9D870B927C0185800775F31 /* Build configuration list for PBXNativeTarget "AR-SDF-Renderer" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				B9D870BA27C0185800775F31 /* Debug */,
				B9D870BB27C0185800775F31 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		B9D870BC27C0185800775F31 /* Build configuration list for PBXNativeTarget "AR-SDF-RendererTests" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				B9D870BD27C0185800775F31 /* Debug */,
				B9D870BE27C0185800775F31 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		B9D870BF27C0185800775F31 /* Build configuration list for PBXNativeTarget "AR-SDF-RendererUITests" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				B9D870C027C0185800775F31 /* Debug */,
				B9D870C127C0185800775F31 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = B9D8708727C0185500775F31 /* Project object */;
}

A  => AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
@@ 1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:">
   </FileRef>
</Workspace>

A  => AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
@@ 1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>IDEDidComputeMac32BitWarning</key>
	<true/>
</dict>
</plist>

A  => AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/project.xcworkspace/xcuserdata/connorbell.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
A  => AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/xcuserdata/connorbell.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +6 -0
@@ 1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
   uuid = "D030DA74-D6E5-487E-A2E4-F2C751FF240A"
   type = "1"
   version = "2.0">
</Bucket>

A  => AR-SDF-Renderer/AR-SDF-Renderer.xcodeproj/xcuserdata/connorbell.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
@@ 1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>SchemeUserState</key>
	<dict>
		<key>AR-SDF-Renderer.xcscheme_^#shared#^_</key>
		<dict>
			<key>orderHint</key>
			<integer>0</integer>
		</dict>
	</dict>
</dict>
</plist>

A  => AR-SDF-Renderer/AR-SDF-Renderer/AppDelegate.swift +36 -0
@@ 1,36 @@
//
//  AppDelegate.swift
//  AR-SDF-Renderer
//
//  Created by Connor Bell on 2022-02-18.
//

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {



    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }


}


A  => AR-SDF-Renderer/AR-SDF-Renderer/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
@@ 1,11 @@
{
  "colors" : [
    {
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A  => AR-SDF-Renderer/AR-SDF-Renderer/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
@@ 1,98 @@
{
  "images" : [
    {
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "20x20"
    },
    {
      "idiom" : "iphone",
      "scale" : "3x",
      "size" : "20x20"
    },
    {
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "29x29"
    },
    {
      "idiom" : "iphone",
      "scale" : "3x",
      "size" : "29x29"
    },
    {
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "40x40"
    },
    {
      "idiom" : "iphone",
      "scale" : "3x",
      "size" : "40x40"
    },
    {
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "60x60"
    },
    {
      "idiom" : "iphone",
      "scale" : "3x",
      "size" : "60x60"
    },
    {
      "idiom" : "ipad",
      "scale" : "1x",
      "size" : "20x20"
    },
    {
      "idiom" : "ipad",
      "scale" : "2x",
      "size" : "20x20"
    },
    {
      "idiom" : "ipad",
      "scale" : "1x",
      "size" : "29x29"
    },
    {
      "idiom" : "ipad",
      "scale" : "2x",
      "size" : "29x29"
    },
    {
      "idiom" : "ipad",
      "scale" : "1x",
      "size" : "40x40"
    },
    {
      "idiom" : "ipad",
      "scale" : "2x",
      "size" : "40x40"
    },
    {
      "idiom" : "ipad",
      "scale" : "1x",
      "size" : "76x76"
    },
    {
      "idiom" : "ipad",
      "scale" : "2x",
      "size" : "76x76"
    },
    {
      "idiom" : "ipad",
      "scale" : "2x",
      "size" : "83.5x83.5"
    },
    {
      "idiom" : "ios-marketing",
      "scale" : "1x",
      "size" : "1024x1024"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A  => AR-SDF-Renderer/AR-SDF-Renderer/Assets.xcassets/Contents.json +6 -0
@@ 1,6 @@
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A  => AR-SDF-Renderer/AR-SDF-Renderer/Base.lproj/LaunchScreen.storyboard +25 -0
@@ 1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="EHf-IW-A2E">
            <objects>
                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="53" y="375"/>
        </scene>
    </scenes>
</document>

A  => AR-SDF-Renderer/AR-SDF-Renderer/Base.lproj/Main.storyboard +24 -0
@@ 1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
        </scene>
    </scenes>
</document>

A  => AR-SDF-Renderer/AR-SDF-Renderer/Info.plist +27 -0
@@ 1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>UIApplicationSceneManifest</key>
	<dict>
		<key>UIApplicationSupportsMultipleScenes</key>
		<false/>
		<key>UISceneConfigurations</key>
		<dict>
			<key>UIWindowSceneSessionRoleApplication</key>
			<array>
				<dict>
					<key>UISceneConfigurationName</key>
					<string>Default Configuration</string>
					<key>UISceneDelegateClassName</key>
					<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
					<key>UISceneStoryboardFile</key>
					<string>Main</string>
				</dict>
			</array>
		</dict>
	</dict>
	<key>NSCameraUsageDescription</key>
	<string>This app requires camera for AR.</string>
</dict>
</plist>

A  => AR-SDF-Renderer/AR-SDF-Renderer/SceneDelegate.swift +52 -0
@@ 1,52 @@
//
//  SceneDelegate.swift
//  AR-SDF-Renderer
//
//  Created by Connor Bell on 2022-02-18.
//

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
        // This occurs shortly after the scene enters the background, or when its session is discarded.
        // Release any resources associated with this scene that can be re-created the next time the scene connects.
        // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    }


}


A  => AR-SDF-Renderer/AR-SDF-Renderer/ViewController.swift +37 -0
@@ 1,37 @@
//
//  ViewController.swift
//  AR-SDF-Renderer
//
//  Created by Connor Bell on 2022-02-18.
//

import UIKit
import AR_SDF
import simd

class ViewController: UIViewController {

    var arSDFView: ARSDFView?
    
    override func viewDidLoad() {        
        let cubeSizeUniform = Float3Uniform(name: "Cube Size",
                                            range: CGSize(width: 0.1, height: 5.0),
                                            value: simd_float3(0.5, 0.5, 0.5))
        
        let distanceField = DistanceField(kernelName: "tunnel",
                                          uniforms: [cubeSizeUniform])
        
        arSDFView = ARSDFView(frame: self.view.frame)
        
        self.view.addSubview(arSDFView!)
        arSDFView?.start(distanceFields: [distanceField])

        super.viewDidLoad()
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        arSDFView?.updateResolution(resolution: size)
    }
}


A  => AR-SDF-Renderer/AR-SDF-RendererTests/AR_SDF_RendererTests.swift +33 -0
@@ 1,33 @@
//
//  AR_SDF_RendererTests.swift
//  AR-SDF-RendererTests
//
//  Created by Connor Bell on 2022-02-18.
//

import XCTest
@testable import AR_SDF_Renderer

class AR_SDF_RendererTests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testPerformanceExample() throws {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }

}

A  => AR-SDF-Renderer/AR-SDF-RendererUITests/AR_SDF_RendererUITests.swift +42 -0
@@ 1,42 @@
//
//  AR_SDF_RendererUITests.swift
//  AR-SDF-RendererUITests
//
//  Created by Connor Bell on 2022-02-18.
//

import XCTest

class AR_SDF_RendererUITests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false

        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        // UI tests must launch the application that they test.
        let app = XCUIApplication()
        app.launch()

        // Use recording to get started writing UI tests.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testLaunchPerformance() throws {
        if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
            // This measures how long it takes to launch your application.
            measure(metrics: [XCTApplicationLaunchMetric()]) {
                XCUIApplication().launch()
            }
        }
    }
}

A  => AR-SDF-Renderer/AR-SDF-RendererUITests/AR_SDF_RendererUITestsLaunchTests.swift +32 -0
@@ 1,32 @@
//
//  AR_SDF_RendererUITestsLaunchTests.swift
//  AR-SDF-RendererUITests
//
//  Created by Connor Bell on 2022-02-18.
//

import XCTest

class AR_SDF_RendererUITestsLaunchTests: XCTestCase {

    override class var runsForEachTargetApplicationUIConfiguration: Bool {
        true
    }

    override func setUpWithError() throws {
        continueAfterFailure = false
    }

    func testLaunch() throws {
        let app = XCUIApplication()
        app.launch()

        // Insert steps here to perform after app launch but before taking a screenshot,
        // such as logging into a test account or navigating somewhere in the app

        let attachment = XCTAttachment(screenshot: app.screenshot())
        attachment.name = "Launch Screen"
        attachment.lifetime = .keepAlways
        add(attachment)
    }
}

A  => AR-SDF/AR-SDF.xcodeproj/project.pbxproj +597 -0
@@ 1,597 @@
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 55;
	objects = {

/* Begin PBXBuildFile section */
		B9D8703827BFF97900775F31 /* AR_SDF.docc in Sources */ = {isa = PBXBuildFile; fileRef = B9D8703727BFF97900775F31 /* AR_SDF.docc */; };
		B9D8703E27BFF97A00775F31 /* AR_SDF.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9D8703327BFF97900775F31 /* AR_SDF.framework */; };
		B9D8704327BFF97A00775F31 /* AR_SDFTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8704227BFF97A00775F31 /* AR_SDFTests.swift */; };
		B9D8704427BFF97A00775F31 /* AR_SDF.h in Headers */ = {isa = PBXBuildFile; fileRef = B9D8703627BFF97900775F31 /* AR_SDF.h */; settings = {ATTRIBUTES = (Public, ); }; };
		B9D8705427BFF9A300775F31 /* Conemarcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8704D27BFF9A300775F31 /* Conemarcher.swift */; };
		B9D8705527BFF9A300775F31 /* ComputePass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8704E27BFF9A300775F31 /* ComputePass.swift */; };
		B9D8705627BFF9A300775F31 /* RendererDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8704F27BFF9A300775F31 /* RendererDelegate.swift */; };
		B9D8705727BFF9A300775F31 /* ARSDFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8705027BFF9A300775F31 /* ARSDFView.swift */; };
		B9D8705827BFF9A300775F31 /* MetalManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8705127BFF9A300775F31 /* MetalManager.swift */; };
		B9D8705927BFF9A300775F31 /* ARManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8705227BFF9A300775F31 /* ARManager.swift */; };
		B9D8705A27BFF9A300775F31 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8705327BFF9A300775F31 /* MetalView.swift */; };
		B9D8706227BFFA4E00775F31 /* DistanceField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8705C27BFFA4E00775F31 /* DistanceField.swift */; };
		B9D8706327BFFA4E00775F31 /* Uniform.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8705D27BFFA4E00775F31 /* Uniform.swift */; };
		B9D8706627BFFA4E00775F31 /* TextureUniform.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8706027BFFA4E00775F31 /* TextureUniform.swift */; };
		B9D8706727BFFA4E00775F31 /* ARData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8706127BFFA4E00775F31 /* ARData.swift */; };
		B9D8706A27BFFC1400775F31 /* CVPixelBuffer+MTLTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8706927BFFC1400775F31 /* CVPixelBuffer+MTLTexture.swift */; };
		B9D8706C27BFFC1B00775F31 /* MTLTexture+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8706B27BFFC1B00775F31 /* MTLTexture+Extensions.swift */; };
		B9D8706E27BFFD5200775F31 /* UIInterfaceOrientation+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8706D27BFFD5200775F31 /* UIInterfaceOrientation+Extensions.swift */; };
		B9D8707027C001A000775F31 /* Float4x4+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D8706F27C001A000775F31 /* Float4x4+Extensions.swift */; };
		B9D8707527C0031600775F31 /* Conemarcher.metal in Sources */ = {isa = PBXBuildFile; fileRef = B9D8707427C0031600775F31 /* Conemarcher.metal */; };
		B9D8707727C0031E00775F31 /* YCbCrToRGB.metal in Sources */ = {isa = PBXBuildFile; fileRef = B9D8707627C0031E00775F31 /* YCbCrToRGB.metal */; };
		B9D8707927C0034100775F31 /* DistanceFields.h in Headers */ = {isa = PBXBuildFile; fileRef = B9D8707827C0034100775F31 /* DistanceFields.h */; };
		B9D8707B27C0039C00775F31 /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = B9D8707A27C0039C00775F31 /* Common.h */; };
		B9D8707D27C0043C00775F31 /* PostFxPass.metal in Sources */ = {isa = PBXBuildFile; fileRef = B9D8707C27C0043C00775F31 /* PostFxPass.metal */; };
		B9D8708227C0048600775F31 /* OrientationTransforms.h in Headers */ = {isa = PBXBuildFile; fileRef = B9D8708027C0048600775F31 /* OrientationTransforms.h */; };
		B9D8708527C0072900775F31 /* OrientationTransforms.metal in Sources */ = {isa = PBXBuildFile; fileRef = B9D8708427C0072900775F31 /* OrientationTransforms.metal */; };
		B9D8715227C138DE00775F31 /* DistanceFields.metal in Sources */ = {isa = PBXBuildFile; fileRef = B9D8715027C138DE00775F31 /* DistanceFields.metal */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
		B9D8703F27BFF97A00775F31 /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = B9D8702A27BFF97900775F31 /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = B9D8703227BFF97900775F31;
			remoteInfo = "AR-SDF";
		};
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
		B9D8703327BFF97900775F31 /* AR_SDF.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AR_SDF.framework; sourceTree = BUILT_PRODUCTS_DIR; };
		B9D8703627BFF97900775F31 /* AR_SDF.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AR_SDF.h; sourceTree = "<group>"; };
		B9D8703727BFF97900775F31 /* AR_SDF.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = AR_SDF.docc; sourceTree = "<group>"; };
		B9D8703D27BFF97A00775F31 /* AR-SDFTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AR-SDFTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
		B9D8704227BFF97A00775F31 /* AR_SDFTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AR_SDFTests.swift; sourceTree = "<group>"; };
		B9D8704D27BFF9A300775F31 /* Conemarcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Conemarcher.swift; sourceTree = "<group>"; };
		B9D8704E27BFF9A300775F31 /* ComputePass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComputePass.swift; sourceTree = "<group>"; };
		B9D8704F27BFF9A300775F31 /* RendererDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RendererDelegate.swift; sourceTree = "<group>"; };
		B9D8705027BFF9A300775F31 /* ARSDFView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ARSDFView.swift; sourceTree = "<group>"; };
		B9D8705127BFF9A300775F31 /* MetalManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetalManager.swift; sourceTree = "<group>"; };
		B9D8705227BFF9A300775F31 /* ARManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ARManager.swift; sourceTree = "<group>"; };
		B9D8705327BFF9A300775F31 /* MetalView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetalView.swift; sourceTree = "<group>"; };
		B9D8705C27BFFA4E00775F31 /* DistanceField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DistanceField.swift; sourceTree = "<group>"; };
		B9D8705D27BFFA4E00775F31 /* Uniform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Uniform.swift; sourceTree = "<group>"; };
		B9D8706027BFFA4E00775F31 /* TextureUniform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextureUniform.swift; sourceTree = "<group>"; };
		B9D8706127BFFA4E00775F31 /* ARData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ARData.swift; sourceTree = "<group>"; };
		B9D8706927BFFC1400775F31 /* CVPixelBuffer+MTLTexture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CVPixelBuffer+MTLTexture.swift"; sourceTree = "<group>"; };
		B9D8706B27BFFC1B00775F31 /* MTLTexture+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MTLTexture+Extensions.swift"; sourceTree = "<group>"; };
		B9D8706D27BFFD5200775F31 /* UIInterfaceOrientation+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIInterfaceOrientation+Extensions.swift"; sourceTree = "<group>"; };
		B9D8706F27C001A000775F31 /* Float4x4+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Float4x4+Extensions.swift"; sourceTree = "<group>"; };
		B9D8707427C0031600775F31 /* Conemarcher.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = Conemarcher.metal; sourceTree = "<group>"; };
		B9D8707627C0031E00775F31 /* YCbCrToRGB.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = YCbCrToRGB.metal; sourceTree = "<group>"; };
		B9D8707827C0034100775F31 /* DistanceFields.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DistanceFields.h; sourceTree = "<group>"; };
		B9D8707A27C0039C00775F31 /* Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = "<group>"; };
		B9D8707C27C0043C00775F31 /* PostFxPass.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = PostFxPass.metal; sourceTree = "<group>"; };
		B9D8708027C0048600775F31 /* OrientationTransforms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OrientationTransforms.h; sourceTree = "<group>"; };
		B9D8708427C0072900775F31 /* OrientationTransforms.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = OrientationTransforms.metal; sourceTree = "<group>"; };
		B9D8715027C138DE00775F31 /* DistanceFields.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = DistanceFields.metal; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		B9D8703027BFF97900775F31 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D8703A27BFF97A00775F31 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D8703E27BFF97A00775F31 /* AR_SDF.framework in Frameworks */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		B9D8702927BFF97900775F31 = {
			isa = PBXGroup;
			children = (
				B9D8703527BFF97900775F31 /* AR-SDF */,
				B9D8704127BFF97A00775F31 /* AR-SDFTests */,
				B9D8703427BFF97900775F31 /* Products */,
			);
			sourceTree = "<group>";
		};
		B9D8703427BFF97900775F31 /* Products */ = {
			isa = PBXGroup;
			children = (
				B9D8703327BFF97900775F31 /* AR_SDF.framework */,
				B9D8703D27BFF97A00775F31 /* AR-SDFTests.xctest */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		B9D8703527BFF97900775F31 /* AR-SDF */ = {
			isa = PBXGroup;
			children = (
				B9D8707127C002EE00775F31 /* Shaders */,
				B9D8706827BFFC0C00775F31 /* Extensions */,
				B9D8705B27BFFA4E00775F31 /* Models */,
				B9D8705227BFF9A300775F31 /* ARManager.swift */,
				B9D8705027BFF9A300775F31 /* ARSDFView.swift */,
				B9D8704E27BFF9A300775F31 /* ComputePass.swift */,
				B9D8704D27BFF9A300775F31 /* Conemarcher.swift */,
				B9D8705127BFF9A300775F31 /* MetalManager.swift */,
				B9D8705327BFF9A300775F31 /* MetalView.swift */,
				B9D8704F27BFF9A300775F31 /* RendererDelegate.swift */,
				B9D8703627BFF97900775F31 /* AR_SDF.h */,
				B9D8703727BFF97900775F31 /* AR_SDF.docc */,
			);
			path = "AR-SDF";
			sourceTree = "<group>";
		};
		B9D8704127BFF97A00775F31 /* AR-SDFTests */ = {
			isa = PBXGroup;
			children = (
				B9D8704227BFF97A00775F31 /* AR_SDFTests.swift */,
			);
			path = "AR-SDFTests";
			sourceTree = "<group>";
		};
		B9D8705B27BFFA4E00775F31 /* Models */ = {
			isa = PBXGroup;
			children = (
				B9D8705C27BFFA4E00775F31 /* DistanceField.swift */,
				B9D8705D27BFFA4E00775F31 /* Uniform.swift */,
				B9D8706027BFFA4E00775F31 /* TextureUniform.swift */,
				B9D8706127BFFA4E00775F31 /* ARData.swift */,
			);
			path = Models;
			sourceTree = "<group>";
		};
		B9D8706827BFFC0C00775F31 /* Extensions */ = {
			isa = PBXGroup;
			children = (
				B9D8706F27C001A000775F31 /* Float4x4+Extensions.swift */,
				B9D8706D27BFFD5200775F31 /* UIInterfaceOrientation+Extensions.swift */,
				B9D8706B27BFFC1B00775F31 /* MTLTexture+Extensions.swift */,
				B9D8706927BFFC1400775F31 /* CVPixelBuffer+MTLTexture.swift */,
			);
			path = Extensions;
			sourceTree = "<group>";
		};
		B9D8707127C002EE00775F31 /* Shaders */ = {
			isa = PBXGroup;
			children = (
				B9D8707427C0031600775F31 /* Conemarcher.metal */,
				B9D8707A27C0039C00775F31 /* Common.h */,
				B9D8707827C0034100775F31 /* DistanceFields.h */,
				B9D8715027C138DE00775F31 /* DistanceFields.metal */,
				B9D8708027C0048600775F31 /* OrientationTransforms.h */,
				B9D8708427C0072900775F31 /* OrientationTransforms.metal */,
				B9D8707C27C0043C00775F31 /* PostFxPass.metal */,
				B9D8707627C0031E00775F31 /* YCbCrToRGB.metal */,
			);
			path = Shaders;
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
		B9D8702E27BFF97900775F31 /* Headers */ = {
			isa = PBXHeadersBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D8708227C0048600775F31 /* OrientationTransforms.h in Headers */,
				B9D8707927C0034100775F31 /* DistanceFields.h in Headers */,
				B9D8704427BFF97A00775F31 /* AR_SDF.h in Headers */,
				B9D8707B27C0039C00775F31 /* Common.h in Headers */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXHeadersBuildPhase section */

/* Begin PBXNativeTarget section */
		B9D8703227BFF97900775F31 /* AR-SDF */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = B9D8704727BFF97A00775F31 /* Build configuration list for PBXNativeTarget "AR-SDF" */;
			buildPhases = (
				B9D8702E27BFF97900775F31 /* Headers */,
				B9D8702F27BFF97900775F31 /* Sources */,
				B9D8703027BFF97900775F31 /* Frameworks */,
				B9D8703127BFF97900775F31 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = "AR-SDF";
			productName = "AR-SDF";
			productReference = B9D8703327BFF97900775F31 /* AR_SDF.framework */;
			productType = "com.apple.product-type.framework";
		};
		B9D8703C27BFF97A00775F31 /* AR-SDFTests */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = B9D8704A27BFF97A00775F31 /* Build configuration list for PBXNativeTarget "AR-SDFTests" */;
			buildPhases = (
				B9D8703927BFF97A00775F31 /* Sources */,
				B9D8703A27BFF97A00775F31 /* Frameworks */,
				B9D8703B27BFF97A00775F31 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
				B9D8704027BFF97A00775F31 /* PBXTargetDependency */,
			);
			name = "AR-SDFTests";
			productName = "AR-SDFTests";
			productReference = B9D8703D27BFF97A00775F31 /* AR-SDFTests.xctest */;
			productType = "com.apple.product-type.bundle.unit-test";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		B9D8702A27BFF97900775F31 /* Project object */ = {
			isa = PBXProject;
			attributes = {
				BuildIndependentTargetsInParallel = 1;
				LastSwiftUpdateCheck = 1310;
				LastUpgradeCheck = 1310;
				TargetAttributes = {
					B9D8703227BFF97900775F31 = {
						CreatedOnToolsVersion = 13.1;
					};
					B9D8703C27BFF97A00775F31 = {
						CreatedOnToolsVersion = 13.1;
					};
				};
			};
			buildConfigurationList = B9D8702D27BFF97900775F31 /* Build configuration list for PBXProject "AR-SDF" */;
			compatibilityVersion = "Xcode 13.0";
			developmentRegion = en;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = B9D8702927BFF97900775F31;
			productRefGroup = B9D8703427BFF97900775F31 /* Products */;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				B9D8703227BFF97900775F31 /* AR-SDF */,
				B9D8703C27BFF97A00775F31 /* AR-SDFTests */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		B9D8703127BFF97900775F31 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D8703B27BFF97A00775F31 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		B9D8702F27BFF97900775F31 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D8707D27C0043C00775F31 /* PostFxPass.metal in Sources */,
				B9D8706627BFFA4E00775F31 /* TextureUniform.swift in Sources */,
				B9D8715227C138DE00775F31 /* DistanceFields.metal in Sources */,
				B9D8706327BFFA4E00775F31 /* Uniform.swift in Sources */,
				B9D8707727C0031E00775F31 /* YCbCrToRGB.metal in Sources */,
				B9D8706E27BFFD5200775F31 /* UIInterfaceOrientation+Extensions.swift in Sources */,
				B9D8705A27BFF9A300775F31 /* MetalView.swift in Sources */,
				B9D8703827BFF97900775F31 /* AR_SDF.docc in Sources */,
				B9D8707027C001A000775F31 /* Float4x4+Extensions.swift in Sources */,
				B9D8707527C0031600775F31 /* Conemarcher.metal in Sources */,
				B9D8705927BFF9A300775F31 /* ARManager.swift in Sources */,
				B9D8705427BFF9A300775F31 /* Conemarcher.swift in Sources */,
				B9D8705727BFF9A300775F31 /* ARSDFView.swift in Sources */,
				B9D8706A27BFFC1400775F31 /* CVPixelBuffer+MTLTexture.swift in Sources */,
				B9D8705827BFF9A300775F31 /* MetalManager.swift in Sources */,
				B9D8706227BFFA4E00775F31 /* DistanceField.swift in Sources */,
				B9D8705527BFF9A300775F31 /* ComputePass.swift in Sources */,
				B9D8706727BFFA4E00775F31 /* ARData.swift in Sources */,
				B9D8705627BFF9A300775F31 /* RendererDelegate.swift in Sources */,
				B9D8706C27BFFC1B00775F31 /* MTLTexture+Extensions.swift in Sources */,
				B9D8708527C0072900775F31 /* OrientationTransforms.metal in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		B9D8703927BFF97A00775F31 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				B9D8704327BFF97A00775F31 /* AR_SDFTests.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
		B9D8704027BFF97A00775F31 /* PBXTargetDependency */ = {
			isa = PBXTargetDependency;
			target = B9D8703227BFF97900775F31 /* AR-SDF */;
			targetProxy = B9D8703F27BFF97A00775F31 /* PBXContainerItemProxy */;
		};
/* End PBXTargetDependency section */

/* Begin XCBuildConfiguration section */
		B9D8704527BFF97A00775F31 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				COPY_PHASE_STRIP = NO;
				CURRENT_PROJECT_VERSION = 1;
				DEBUG_INFORMATION_FORMAT = dwarf;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				GCC_DYNAMIC_NO_PIC = NO;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
				MTL_FAST_MATH = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = iphoneos;
				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
				VERSIONING_SYSTEM = "apple-generic";
				VERSION_INFO_PREFIX = "";
			};
			name = Debug;
		};
		B9D8704627BFF97A00775F31 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				COPY_PHASE_STRIP = NO;
				CURRENT_PROJECT_VERSION = 1;
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
				ENABLE_NS_ASSERTIONS = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
				MTL_ENABLE_DEBUG_INFO = NO;
				MTL_FAST_MATH = YES;
				SDKROOT = iphoneos;
				SWIFT_COMPILATION_MODE = wholemodule;
				SWIFT_OPTIMIZATION_LEVEL = "-O";
				VALIDATE_PRODUCT = YES;
				VERSIONING_SYSTEM = "apple-generic";
				VERSION_INFO_PREFIX = "";
			};
			name = Release;
		};
		B9D8704827BFF97A00775F31 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEFINES_MODULE = YES;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				DYLIB_COMPATIBILITY_VERSION = 1;
				DYLIB_CURRENT_VERSION = 1;
				DYLIB_INSTALL_NAME_BASE = "@rpath";
				GENERATE_INFOPLIST_FILE = YES;
				INFOPLIST_KEY_NSHumanReadableCopyright = "";
				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@loader_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDF";
				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
				SKIP_INSTALL = YES;
				SUPPORTS_MACCATALYST = NO;
				SWIFT_EMIT_LOC_STRINGS = YES;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Debug;
		};
		B9D8704927BFF97A00775F31 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEFINES_MODULE = YES;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				DYLIB_COMPATIBILITY_VERSION = 1;
				DYLIB_CURRENT_VERSION = 1;
				DYLIB_INSTALL_NAME_BASE = "@rpath";
				GENERATE_INFOPLIST_FILE = YES;
				INFOPLIST_KEY_NSHumanReadableCopyright = "";
				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@loader_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDF";
				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
				SKIP_INSTALL = YES;
				SUPPORTS_MACCATALYST = NO;
				SWIFT_EMIT_LOC_STRINGS = YES;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Release;
		};
		B9D8704B27BFF97A00775F31 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				GENERATE_INFOPLIST_FILE = YES;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@loader_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDFTests";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = NO;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Debug;
		};
		B9D8704C27BFF97A00775F31 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = NQCRZ7VG59;
				GENERATE_INFOPLIST_FILE = YES;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@loader_path/Frameworks",
				);
				MARKETING_VERSION = 1.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.connorbell.AR-SDFTests";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = NO;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		B9D8702D27BFF97900775F31 /* Build configuration list for PBXProject "AR-SDF" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				B9D8704527BFF97A00775F31 /* Debug */,
				B9D8704627BFF97A00775F31 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		B9D8704727BFF97A00775F31 /* Build configuration list for PBXNativeTarget "AR-SDF" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				B9D8704827BFF97A00775F31 /* Debug */,
				B9D8704927BFF97A00775F31 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		B9D8704A27BFF97A00775F31 /* Build configuration list for PBXNativeTarget "AR-SDFTests" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				B9D8704B27BFF97A00775F31 /* Debug */,
				B9D8704C27BFF97A00775F31 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = B9D8702A27BFF97900775F31 /* Project object */;
}

A  => AR-SDF/AR-SDF.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
@@ 1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:">
   </FileRef>
</Workspace>

A  => AR-SDF/AR-SDF.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
@@ 1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>IDEDidComputeMac32BitWarning</key>
	<true/>
</dict>
</plist>

A  => AR-SDF/AR-SDF.xcodeproj/project.xcworkspace/xcuserdata/connorbell.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
A  => AR-SDF/AR-SDF.xcodeproj/xcuserdata/connorbell.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
@@ 1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>SchemeUserState</key>
	<dict>
		<key>AR-SDF.xcscheme_^#shared#^_</key>
		<dict>
			<key>orderHint</key>
			<integer>1</integer>
		</dict>
	</dict>
</dict>
</plist>

A  => AR-SDF/AR-SDF/ARManager.swift +135 -0
@@ 1,135 @@
//
//  ARManager.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-14.
//

import Foundation
import ARKit
import simd
import CoreVideo

protocol ARManagerDelegate {
    func ARManagerDidReadyFrame(arData: ARData)
}

public class ARManager: NSObject {

    var delegate: ARManagerDelegate?
    var rendererDelegate: RendererDelegate?

    public var resolution = CGSize() {
        didSet {
            allocTextures(size: resolution)
        }
    }

    private var anchor: ARAnchor?
    private let arSession: ARSession
    private var arData = ARData()
    private var yTexture: MTLTexture?
    private var cbCrTexture: MTLTexture?
    
    private var processingCenterPixels = true
    
    private var YCyCbPass: ComputePass
    private var lastRaycastTransform = simd_float4x4()
    
    init(resolution: CGSize) {
        arSession = ARSession()
        
        self.resolution = resolution
        YCyCbPass = ComputePass(kernelName: "convertYCbCrToRGBA",
                                linkedFunctionNames: [],
                                resolution: resolution)
        super.init()
        allocTextures(size: resolution)
        arSession.delegate = self
    }
    
    func startAR() {
        guard ARWorldTrackingConfiguration.supportsFrameSemantics([.sceneDepth, .smoothedSceneDepth]) else { return }
        
        let config = ARWorldTrackingConfiguration()
        config.isLightEstimationEnabled = true
        config.planeDetection = [.horizontal]
        config.frameSemantics = [.sceneDepth, .smoothedSceneDepth]
        arSession.run(config)
    }
    
    func allocTextures(size: CGSize) {
        arData.rgbTexture = MetalManager.shared.allocTexture(pixelFormat: .rgba32Float,
                                                             width: Int(size.width),
                                                             height: Int(size.height),
                                                             usage: [.shaderRead, .shaderWrite])
        YCyCbPass = ComputePass(kernelName: "convertYCbCrToRGBA",
                                linkedFunctionNames: [],
                                resolution: size)
    }
}

extension ARManager: ARSessionDelegate {

    public func session(_ session: ARSession, didUpdate frame: ARFrame) {
        
        // guard let sceneDepth = frame.sceneDepth else { return }
        guard let rendererDelegate = rendererDelegate else { return }
    
        if let smoothedSceneDepth = frame.smoothedSceneDepth {
            arData.depthSmoothTexture = MetalManager.shared.createTexture(from: smoothedSceneDepth.depthMap,
                                                                          format: .r32Float,
                                                                          planeIndex: 0)
        }
                
        createRGBTextureFromYCyCb(frame: frame, from: frame.capturedImage, dest: arData.rgbTexture)
        
        var orientation = rendererDelegate.rendererDidRequestOrientation()

        if orientation == .landscapeLeft {
            orientation = .landscapeRight
        } else if orientation == .landscapeRight {
            orientation = .landscapeLeft
        }
        
        arData.frame = frame
        arData.intrinsics = frame.camera.intrinsics
        arData.cameraResolution = frame.camera.imageResolution
        arData.projectionMatrix = frame.camera.projectionMatrix(for: orientation, viewportSize: self.resolution, zNear: 0.001, zFar: 1000.0)
        arData.camera = frame.camera.transform
        arData.viewMatrix = frame.camera.viewMatrix(for: orientation)
        arData.lightIntensity = Float(frame.lightEstimate!.ambientIntensity)
        arData.lightTemperature = Float(frame.lightEstimate!.ambientColorTemperature)
        
        delegate?.ARManagerDidReadyFrame(arData: arData)
    }
    
    func addAnchor() {
        let anchor = ARAnchor(transform: lastRaycastTransform)
        arSession.add(anchor: anchor)
        self.anchor = anchor
    }
}

// - Textures
extension ARManager {
    
    func createRGBTextureFromYCyCb(frame: ARFrame, from: CVPixelBuffer, dest: MTLTexture?) {
        yTexture = MetalManager.shared.createTexture(from: from, format: .r8Unorm, planeIndex: 0)
        cbCrTexture = MetalManager.shared.createTexture(from: from, format: .rg8Unorm, planeIndex: 1)
        let textureUniform = TextureUniform(texture: dest!, index: 2)
        
        YCyCbPass.dispatch(drawable: nil, outTexture: textureUniform) { encoder in
            encoder.setTexture(self.yTexture, index: 0)
            encoder.setTexture(self.cbCrTexture, index: 1)
            encoder.setTexture(self.arData.depthSmoothTexture, index: 3)
            if let delegate = self.rendererDelegate {
                var interfaceOrientation = delegate.rendererDidRequestOrientation().intValue
                encoder.setBytes(&interfaceOrientation, length: MemoryLayout<Int>.size, index: 0)
            }
            
        } completionBlock: { _ in
            
        }
    }
}

A  => AR-SDF/AR-SDF/ARSDFView.swift +102 -0
@@ 1,102 @@
//
//  ARSDFView.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2022-02-16.
//

import ARKit
import Foundation
import UIKit

public class ARSDFView: UIView {

    /// Access the last known AR Data
    public var lastARData: ARData?
    
    public var arManager: ARManager?
    public var conemarcher: Conemarcher?
    public var metalView: MetalView?
    
    /// Update this to render a distance field (class must have already called start() with the assigned distance field included.
    public var activeDistanceField: DistanceField?
    
    private var lastKnownOrientation: UIInterfaceOrientation = .portrait

    /// Available distance fields are stored as an array in order for the function table creation
    private var distanceFields: [DistanceField] = []
    
    private var startTime = Double(0.0)
    private var time = Double(0.0)
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    /// Begin rendering distance fields. The first one will be by default. Any distance fields intended to render should be passed as well in order to create the function table.
    public func start(distanceFields: [DistanceField]) {
        lastKnownOrientation = lastKnownOrientation.interfaceOrientationFromCurrentDevice
        
        self.startTime = CFAbsoluteTimeGetCurrent()
        self.distanceFields = distanceFields
        self.activeDistanceField = distanceFields.first
                
        self.metalView = MetalView(frame: self.frame, device: MetalManager.shared.metalDevice)
        
        self.addSubview(metalView!)

        conemarcher = Conemarcher(resolution: self.bounds.size,
                                  distanceFields: distanceFields)
        
        conemarcher?.rendererDelegate = self
        
        arManager = ARManager(resolution: self.bounds.size)
        metalView?.rendererDelegate = self
        arManager?.rendererDelegate = self
        arManager?.delegate = self
        
        arManager?.startAR()
    }
    
    public func updateResolution(resolution: CGSize) {
        conemarcher?.fullscreenResolution = resolution
        metalView?.resolution = resolution
        arManager?.resolution = resolution
    }
}

extension ARSDFView: ARManagerDelegate {
    func ARManagerDidReadyFrame(arData: ARData) {
        lastARData = arData
        lastKnownOrientation = lastKnownOrientation.interfaceOrientationFromCurrentDevice
    
        // Update Time
        self.time = CFAbsoluteTimeGetCurrent() - startTime
        
        // Perform conemarch render with current distance field
        guard let distanceField = activeDistanceField else { return }
        let distanceFieldIndex = distanceFields.firstIndex { $0 === distanceField }
        
        guard let conemarchRender = conemarcher?.step(data: arData,
                                                      field: distanceField,
                                                      functionIndex: distanceFieldIndex!) else { return }
        
        // Input result to metal view for post processing
        metalView?.blit(conemarchRender: conemarchRender)
    }
}

extension ARSDFView: RendererDelegate {
    func rendererDidRequestOrientation() -> UIInterfaceOrientation {
        return lastKnownOrientation
    }
    
    func rendererDidRequestTime() -> Double {
        return time
    }
}

A  => AR-SDF/AR-SDF/AR_SDF.docc/AR_SDF.md +13 -0
@@ 1,13 @@
# ``AR_SDF``

<!--@START_MENU_TOKEN@-->Summary<!--@END_MENU_TOKEN@-->

## Overview

<!--@START_MENU_TOKEN@-->Text<!--@END_MENU_TOKEN@-->

## Topics

### <!--@START_MENU_TOKEN@-->Group<!--@END_MENU_TOKEN@-->

- <!--@START_MENU_TOKEN@-->``Symbol``<!--@END_MENU_TOKEN@-->
\ No newline at end of file

A  => AR-SDF/AR-SDF/AR_SDF.h +18 -0
@@ 1,18 @@
//
//  AR_SDF.h
//  AR-SDF
//
//  Created by Connor Bell on 2022-02-18.
//

#import <Foundation/Foundation.h>

//! Project version number for AR_SDF.
FOUNDATION_EXPORT double AR_SDFVersionNumber;

//! Project version string for AR_SDF.
FOUNDATION_EXPORT const unsigned char AR_SDFVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <AR_SDF/PublicHeader.h>



A  => AR-SDF/AR-SDF/ComputePass.swift +141 -0
@@ 1,141 @@
//
//  ComputePass.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-20.
//

import CoreVideo
import Metal
import MetalKit

/// Compute pass encapsulates a Metal compute kernel
class ComputePass {
    
    /// Pipeline state for compute kernel
    let pipelineState: MTLComputePipelineState
    
    /// The metal function name to execute
    let kernelName: String
    
    /// Threadgroup information
    var threadsPerThreadGroup = MTLSize()
    var threadsPerGrid = MTLSize()
    
    /// Resolution of the expected render texture. Setting updates threadgroups
    var resolution: CGSize {
        didSet {
            updateThreadgroups()
        }
    }
    
    /// Function pointers and table to reference functions utilized by kernel
    var linkedPostFunctions = MTLLinkedFunctions()
    var visibleFunctionTable: MTLVisibleFunctionTable?
    var visibleFunctionTableIndex: Int
    
    /// Updated each pass to provide performance info
    var lastExecutionTime: CFTimeInterval = 0.0
    var executionCompletionBlock: (() -> Void)?
    
    init(kernelName: String, linkedFunctionNames: [String], resolution: CGSize, visibleFunctionTableIndex: Int = 0) {
        self.kernelName = kernelName
        self.resolution = resolution
        self.visibleFunctionTableIndex = visibleFunctionTableIndex
        
        // Create linked functions
        var functions: [MTLFunction] = []
        
        for functionName in linkedFunctionNames {
            if let postFunction = MetalManager.shared.createLinkedFunction(name: functionName, options: []) {
                functions.append(postFunction)
            }
        }
        linkedPostFunctions.functions = functions
        
        // Create pipeline state with linked functions
        self.pipelineState = MetalManager.shared.createComputePipelineState(name: kernelName, linkedFunctions: linkedPostFunctions)!

        // Build virtual function table from the pipeline's function handles
        let vTableDescriptor = MTLVisibleFunctionTableDescriptor()
        vTableDescriptor.functionCount = linkedPostFunctions.functions!.count
        
        let vTable = pipelineState.makeVisibleFunctionTable(descriptor: vTableDescriptor)
        var index = 0
        
        for postFxFunction in linkedPostFunctions.functions! {
            let functionHandle = pipelineState.functionHandle(function: postFxFunction)
            vTable?.setFunction(functionHandle, index: index)
            index+=1
        }
        
        self.visibleFunctionTable = vTable
        
        updateThreadgroups()
    }
    
    /// Schedules the task to GPU and output to either the drawable or texture.
    func dispatch(drawable: CAMetalDrawable?,
                  outTexture: TextureUniform?,
                  waitUntilCompleted: Bool = false,
                  updateUniformsBlock: ((MTLComputeCommandEncoder) -> Void)?,
                  completionBlock: ((MTLTexture?) -> Void)?) {
        
        guard let commandBuffer = MetalManager.shared.commandQueue.makeCommandBuffer(),
              let computeCommandEncoder = commandBuffer.makeComputeCommandEncoder() else { return }
        
        computeCommandEncoder.setComputePipelineState(pipelineState)
 
        if let outTexture = outTexture {
            computeCommandEncoder.setTextureUniform(uniform: outTexture)
        }
    
        computeCommandEncoder.setVisibleFunctionTable(visibleFunctionTable, bufferIndex: visibleFunctionTableIndex)

        if let uniformsBlock = updateUniformsBlock {
            uniformsBlock(computeCommandEncoder)
        }
        
        computeCommandEncoder.dispatchThreads(threadsPerGrid, threadsPerThreadgroup: threadsPerThreadGroup)
        computeCommandEncoder.endEncoding()
        
        // Add completion handler to update the execution time
        commandBuffer.addCompletedHandler { buffer in
            self.lastExecutionTime = buffer.gpuEndTime - buffer.gpuStartTime
            if let completionBlock = self.executionCompletionBlock {
                completionBlock()
            }
        }
        
        if let drawable = drawable {
            commandBuffer.present(drawable)
        }
        
        commandBuffer.commit()
        
        if waitUntilCompleted {
            commandBuffer.waitUntilCompleted()
        }
        
        if let completionBlock = completionBlock {
            if let drawable = drawable {
                completionBlock(drawable.texture)
            } else {
                completionBlock(outTexture?.texture)
            }
        }
    }
    
    func updateThreadgroups() {
        let w = pipelineState.threadExecutionWidth
        let h = pipelineState.maxTotalThreadsPerThreadgroup / w
        self.threadsPerThreadGroup = MTLSize(width: w, height: h, depth: 1)
        self.threadsPerGrid = MTLSize(width: Int(resolution.width), height: Int(resolution.height), depth: 1)
    }
}

extension MTLComputeCommandEncoder {
    func setTextureUniform(uniform: TextureUniform) {
        self.setTexture(uniform.texture, index: uniform.index)
    }
}

A  => AR-SDF/AR-SDF/Conemarcher.swift +232 -0
@@ 1,232 @@
//
//  Conemarcher.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-14.
//

import Foundation
import Metal
import simd
import CoreVideo

// This data struct gets passed to the conemarch kernel and needs to match the struct in Conemarcher.metal
struct ConemarchParameters {
    var maxDist = simd_float1(0.0)
    var minDist = simd_float1(0.0)
    var coneWidth = simd_float1(0.0)
    var inverseProjectionMatrix = simd_float4x4(0.0)
    var inverseViewMatrix = simd_float4x4(0.0)
    var viewMatrix = simd_float4x4(0.0)
    var projectionMatrix = simd_float4x4(0.0)
    var camera = simd_float4x4(0.0)
    var computeColor = simd_int1(0)
    var time = Float(CFAbsoluteTimeGetCurrent())
    var lightTemperature = simd_float1(0.0)
    var lightIntensity = simd_float1(0.0)
}

public class Conemarcher {
    
    /// Number of times resulting depth data is propigated to a higher resolution.
    let passes = 9

    /// Width of starting resolution
    var startWidth = 3

    /// Height of starting resolution
    var startHeight = 2
    
    /// Multiplier for the cone width
    let coneWidthScale = 2.0
    
    /// Max distance to cast rays before exiting traversal
    let maxDist = 50.0
    
    /// Min distance to surface for a ray
    let minDist = 0.001
    
    /// Step counts for each pass. If there's more passes than step counts, the step count is the last value.
    var stepCounts = [50, 40, 35, 30, 25, 20, 15, 10]
        
    var rendererDelegate: RendererDelegate?
        
    /// Callback which invokes each
    var executionTimeUpdated: ((CFTimeInterval) -> Void)?

    /// Conemarch parameter buffer pointer to update GPU memory
    private let bufferPointer: UnsafeMutablePointer<ConemarchParameters>

    /// Width of the cones for each pass
    private var coneWidths: [Float] = []
    
    /// Compute passes for each resolution
    private var computePasses: [ComputePass] = []
    
    /// Persistent parameter buffer
    private let conemarchParamsBuffer: MTLBuffer

    /// Parameter struct to be encoded into buffer
    private var conemarchParameters = ConemarchParameters()

    /// The names of the distance field functions the function table will be composed of
    public var linkedFunctionNames: [String] = []
    
    /// Render textures for the outputs of each pass
    private var textureUniforms: [TextureUniform] = []
    
    /// Updating resets starting texture size based on orientation
    var fullscreenResolution: CGSize {
        didSet {
            if fullscreenResolution.height > fullscreenResolution.width {
                startWidth = 3
                startHeight = 2
            } else {
                startWidth = 2
                startHeight = 3
            }
            allocTexturesAndPasses()
            computeConeWidths()
        }
    }
    
    init(resolution: CGSize, distanceFields: [DistanceField]) {
        for distanceField in distanceFields {
            linkedFunctionNames.append(distanceField.kernelName)
        }
        
        self.fullscreenResolution = resolution
        
        conemarchParameters.maxDist = Float(maxDist)
        conemarchParameters.minDist = Float(minDist)
        
        conemarchParamsBuffer = MetalManager.shared.metalDevice.makeBuffer(bytes: &self.conemarchParameters,
                                                                           length: MemoryLayout<ConemarchParameters>.stride,
                                                                           options:[])!

        bufferPointer = conemarchParamsBuffer.contents().bindMemory(to: ConemarchParameters.self, capacity: 1)
        
        allocTexturesAndPasses()
        computeConeWidths()
        registerExecutionTimeCallbacks()
    }
    
    /// Returns a texture with the rendered SDF composed with the AR Data
    func step(data: ARData, field: DistanceField, functionIndex: Int) -> MTLTexture? {
        
        guard let time = rendererDelegate?.rendererDidRequestTime() else { return nil }
        
        // Update buffer with relevant parameters
        bufferPointer.pointee.time = Float(time)
        bufferPointer.pointee.camera = data.camera
        bufferPointer.pointee.inverseProjectionMatrix = simd_inverse(data.projectionMatrix)
        bufferPointer.pointee.inverseViewMatrix = simd_inverse(data.viewMatrix)
        bufferPointer.pointee.computeColor = 0
        bufferPointer.pointee.lightTemperature = data.lightTemperature
        bufferPointer.pointee.lightIntensity = data.lightIntensity
        bufferPointer.pointee.viewMatrix = data.viewMatrix
        bufferPointer.pointee.projectionMatrix = data.projectionMatrix
        
        // Progressively render each pass with the last pass as input
        for i in 0...passes {
            
            bufferPointer.pointee.coneWidth = self.coneWidths[i]
            
            computePasses[i].dispatch(drawable: nil,
                                      outTexture: textureUniforms[i],
                                      waitUntilCompleted: true) { commandEncoder in

                commandEncoder.setTexture(data.rgbTexture, index: 2)

                var distFunctionIndex = functionIndex
                commandEncoder.setBytes(&distFunctionIndex, length: MemoryLayout<Int>.stride, index: 3)
                
                field.encodeUniforms(encoder: commandEncoder)

                // Set previous depth texture
                if i > 0 {
                    commandEncoder.setTexture(self.textureUniforms[i-1].texture, index: 0)
                }
                
                // Compute color if final pass
                if i == self.passes {
                    self.bufferPointer.pointee.computeColor = 1
                }
                
                commandEncoder.setBuffer(self.conemarchParamsBuffer, offset: 0, index: 0)
                
            } completionBlock: { _ in
                
            }
        }
        
        return textureUniforms[passes].texture
    }
    
    func registerExecutionTimeCallbacks() {
        var completedPasses = 0
        let executionCompletionBlock: () -> Void = {
            completedPasses += 1
            
            if completedPasses == self.passes {
                var totalExecutionTime = 0.0
                for pass in self.computePasses {
                    totalExecutionTime += pass.lastExecutionTime
                }
                if let completionBlock = self.executionTimeUpdated {
                    completionBlock(totalExecutionTime)
                }
            }
        }
        
        for pass in computePasses {
            pass.executionCompletionBlock = executionCompletionBlock
        }
    }
}

extension Conemarcher {
    func allocTexturesAndPasses() {
        
        var resolution = (startWidth, startHeight)
        textureUniforms = []
        computePasses = []
        
        for _ in 0...passes {
            let texture = MetalManager.shared.allocTexture(pixelFormat: .rgba32Float,
                                                           width: resolution.0,
                                                           height: resolution.1,
                                                           usage: [.shaderRead, .shaderWrite])
            let uniform = TextureUniform(texture: texture, index: 1)
            textureUniforms.append(uniform)
            
            let pass = ComputePass(kernelName: "conemarchKernel",
                                   linkedFunctionNames: linkedFunctionNames,
                                   resolution: CGSize(width: resolution.0, height: resolution.1),
                                   visibleFunctionTableIndex: 2)
            
            computePasses.append(pass)
            resolution.0 *= 2
            resolution.1 *= 2
        }
    }
    
    func computeConeWidths() {
        
        coneWidths = []
        
        for i in 0...passes {
            let texel = CGSize(width: CGFloat(1.0) / CGFloat(textureUniforms[i].texture.width),
                               height: CGFloat(1.0) / CGFloat(textureUniforms[i].texture.height))
            
            let x = simd_float3(simd_float1(texel.width), 0.0, 0.0)
            let y = simd_float3(0.0, simd_float1(texel.height), 0.0)
            let z = simd_float3(0.0, 0.0, -1.0)
            let basis = normalize(simd_float3(x + y + z))
            let theta = acos(simd_dot(simd_float3(0.0, 0.0, -1.0), basis));
            let cw = tan(theta);
            
            coneWidths.append(cw * Float(coneWidthScale))
        }
    }
}

A  => AR-SDF/AR-SDF/Extensions/CVPixelBuffer+MTLTexture.swift +23 -0
@@ 1,23 @@
//
//  CVPixelBuffer+MTLTexture.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-16.
//

import CoreVideo

extension CVPixelBuffer {

    func texture(withFormat pixelFormat: MTLPixelFormat, planeIndex: Int, addToCache cache: CVMetalTextureCache) -> MTLTexture? {
        
        let width = CVPixelBufferGetWidthOfPlane(self, planeIndex)
        let height = CVPixelBufferGetHeightOfPlane(self, planeIndex)
        
        var cvtexture: CVMetalTexture?
        CVMetalTextureCacheCreateTextureFromImage(nil, cache, self, nil, pixelFormat, width, height, planeIndex, &cvtexture)
        let texture = CVMetalTextureGetTexture(cvtexture!)
        
        return texture
    }
}

A  => AR-SDF/AR-SDF/Extensions/Float4x4+Extensions.swift +54 -0
@@ 1,54 @@
//
//  simd+ext.swift
//
//  Created by Kaz Yoshikawa on 11/6/15.
//
//  https://gist.github.com/codelynx/908fd30c93e40ea6408b

import Foundation
import simd
import GLKit

extension simd_float4x4 {

    static func makeScale(x: Float, _ y: Float, _ z: Float) -> simd_float4x4 {
        return unsafeBitCast(GLKMatrix4MakeScale(x, y, z), to: simd_float4x4.self)
    }

    static func makeRotate(radians: Float, _ x: Float, _ y: Float, _ z: Float) -> simd_float4x4 {
        return unsafeBitCast(GLKMatrix4MakeRotation(radians, x, y, z), to: simd_float4x4.self)
    }

    static func makeTranslation(x: Float, _ y: Float, _ z: Float) -> simd_float4x4 {
        return unsafeBitCast(GLKMatrix4MakeTranslation(x, y, z), to: simd_float4x4.self)
    }

    static func makePerspective(fovyRadians: Float, _ aspect: Float, _ nearZ: Float, _ farZ: Float) -> simd_float4x4 {
        return unsafeBitCast(GLKMatrix4MakePerspective(fovyRadians, aspect, nearZ, farZ), to: simd_float4x4.self)
    }

    static func makeFrustum(left: Float, _ right: Float, _ bottom: Float, _ top: Float, _ nearZ: Float, _ farZ: Float) -> simd_float4x4 {
        return unsafeBitCast(GLKMatrix4MakeFrustum(left, right, bottom, top, nearZ, farZ), to: simd_float4x4.self)
    }

    static func makeOrtho(left: Float, _ right: Float, _ bottom: Float, _ top: Float, _ nearZ: Float, _ farZ: Float) -> simd_float4x4 {
        return unsafeBitCast(GLKMatrix4MakeOrtho(left, right, bottom, top, nearZ, farZ), to: simd_float4x4.self)
    }

    static func makeLookAt(eyeX: Float, _ eyeY: Float, _ eyeZ: Float, _ centerX: Float, _ centerY: Float, _ centerZ: Float, _ upX: Float, _ upY: Float, _ upZ: Float) -> simd_float4x4 {
        return unsafeBitCast(GLKMatrix4MakeLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ), to: simd_float4x4.self)
    }


    func scale(x: Float, y: Float, z: Float) -> simd_float4x4 {
        return self * simd_float4x4.makeScale(x: x, y, z)
    }

    func rotate(radians: Float, _ x: Float, _ y: Float, _ z: Float) -> simd_float4x4 {
        return self * simd_float4x4.makeRotate(radians: radians, x, y, z)
    }

    func translate(x: Float, _ y: Float, _ z: Float) -> simd_float4x4 {
        return self * simd_float4x4.makeTranslation(x: x, y, z)
    }
}

A  => AR-SDF/AR-SDF/Extensions/MTLTexture+Extensions.swift +22 -0
@@ 1,22 @@
//
//  MTLTexture+Extensions.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-10.
//

import Metal

// from https://stackoverflow.com/questions/41577800/why-cant-i-read-those-mtltexture-pixels 
extension MTLTexture {
  func getPixels<T> (_ region: MTLRegion? = nil, mipmapLevel: Int = 0) -> UnsafeMutablePointer<T> {
    let fromRegion  = region ?? MTLRegionMake2D(0, 0, self.width, self.height)
    let width       = fromRegion.size.width
    let height      = fromRegion.size.height
    let bytesPerRow = MemoryLayout<T>.stride * width
    let data        = UnsafeMutablePointer<T>.allocate(capacity: bytesPerRow * height)

    self.getBytes(data, bytesPerRow: bytesPerRow, from: fromRegion, mipmapLevel: mipmapLevel)
    return data
  }
}

A  => AR-SDF/AR-SDF/Extensions/UIInterfaceOrientation+Extensions.swift +46 -0
@@ 1,46 @@
//
//  UIInterfaceOrientation+Extensions.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-25.
//

import UIKit

extension UIInterfaceOrientation {
    
    public var interfaceOrientationFromCurrentDevice: UIInterfaceOrientation {
        switch UIDevice.current.orientation {
        case .landscapeLeft:
            return UIInterfaceOrientation.landscapeLeft
        case .landscapeRight:
            return UIInterfaceOrientation.landscapeRight
        case .portrait:
            return UIInterfaceOrientation.portrait
        case .portraitUpsideDown:
            return UIInterfaceOrientation.portraitUpsideDown
        default:
            return self
        }
    }
    
    public var description: String {
        switch self {
        case .landscapeLeft: return "landscapeLeft"
        case .landscapeRight: return "landscapeRight"
        case .portrait: return "portrait"
        case .portraitUpsideDown: return "portraitUpsideDown"
        case .unknown: return "unknown"
        }
    }
    
    public var intValue: Int {
        switch self {
        case .landscapeLeft: return 0
        case .landscapeRight: return 2
        case .portrait: return 1
        case .portraitUpsideDown: return 3
        case .unknown: return 0
        }
    }
}

A  => AR-SDF/AR-SDF/MetalManager.swift +129 -0
@@ 1,129 @@
//
//  MetalProvider.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-15.
//

import Foundation
import Metal
import CoreVideo
import MetalKit
import AVFoundation

final class MetalManager {
    
    static let shared = MetalManager()
    
    var metalDevice: MTLDevice
    var commandQueue: MTLCommandQueue
    var functionLibrary: MTLLibrary
    
    var textureLoader: MTKTextureLoader?
    private var textureCache: CVMetalTextureCache?
    private var pipelineStateCache: [String: MTLComputePipelineState] = [:]
    
    init() {

        metalDevice = MTLCreateSystemDefaultDevice()!

        let frameworkBundle = Bundle(for: MetalManager.self)

        // Thanks Warren Moore!
        guard let defaultLibrary = try? metalDevice.makeDefaultLibrary(bundle: frameworkBundle) else {
            fatalError("Could not load default library from specified bundle")
        }
        
        commandQueue = metalDevice.makeCommandQueue()!
        
        functionLibrary = defaultLibrary
        textureLoader = MTKTextureLoader(device: metalDevice)
        
        createTextureCache()
    }
    
    /// Creates a pipeline state, caching the state by name.
    func createComputePipelineState(name: String, linkedFunctions: MTLLinkedFunctions?) -> MTLComputePipelineState? {
        
        if let cachedState = pipelineStateCache[name] {
            return cachedState
        }

        do {
            let descriptor = MTLFunctionDescriptor()
            descriptor.name = name
            
            let function = try functionLibrary.makeFunction(descriptor: descriptor)
         
            let computeDescriptor = MTLComputePipelineDescriptor()
            computeDescriptor.computeFunction = function
            if let linkedFunctions = linkedFunctions {
                computeDescriptor.linkedFunctions = linkedFunctions
            }
            do {
                let state = try metalDevice.makeComputePipelineState(descriptor: computeDescriptor, options: [], reflection: nil)
                pipelineStateCache[name] = state
                return state
            }
            catch {
                print(error)
                return nil
            }
            
        } catch {
            print(error)
            return nil
        }
    }
    
    func createLinkedFunction(name: String, options: MTLFunctionOptions) -> MTLFunction? {

        let descriptor = MTLFunctionDescriptor()
        descriptor.name = name
        descriptor.options = options
        
        do {
            return try functionLibrary.makeFunction(descriptor: descriptor)
        } catch {
            
        }
        return nil
    }
    
    func createTextureCache() {
        var textCache: CVMetalTextureCache?
        if CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, self.metalDevice, nil, &textCache) != kCVReturnSuccess {
            print("Unable to allocate texture cache")
        }
        else {
            guard let textureCache = textCache else { return }
            self.textureCache = textureCache
        }
    }
    
    func allocTexture(pixelFormat: MTLPixelFormat, width: Int, height: Int, usage: MTLTextureUsage) -> MTLTexture {
        let descriptor: MTLTextureDescriptor = MTLTextureDescriptor()
        descriptor.pixelFormat = pixelFormat
        descriptor.width = width
        descriptor.height = height
        descriptor.usage = usage
        let resTexture = metalDevice.makeTexture(descriptor: descriptor)
        return resTexture!
    }
    
    func createTexture(from: CVPixelBuffer, format: MTLPixelFormat, planeIndex: Int) -> MTLTexture {
        return from.texture(withFormat: format, planeIndex: planeIndex, addToCache: textureCache!)!
    }
    
    func createTexture(fileName: String) -> MTLTexture? {
        let imagePath = Bundle(for: MetalManager.self).path(forResource: fileName, ofType: "png")!
        let image = UIImage(contentsOfFile: imagePath)!
        
        do {
            return (try textureLoader?.newTexture(cgImage: image.cgImage!,
                                              options: [MTKTextureLoader.Option.SRGB : NSNumber(value: false)]))!
        } catch {
            return nil
        }
    }
}

A  => AR-SDF/AR-SDF/MetalView.swift +112 -0
@@ 1,112 @@
//
//  MetalView.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-14.
//

import Foundation
import Metal
import MetalKit
import MetalPerformanceShaders
import ARKit

public class MetalView: MTKView  {
    
    /// Used to obtain orientation and time
    var rendererDelegate: RendererDelegate?
    
    /// The input texture to be processed. Use "blit" function to render
    private var inputConemarchResult: MTLTexture?
    
    /// The compute pass to apply the post effect
    private var postFxPass: ComputePass?
    
    /// Used as render target between post-fx and lighting passes
    private var renderTexture: TextureUniform?
    
    var resolution: CGSize {
        didSet {
            allocTexturesAndPasses()
        }
    }
    
    public override init(frame frameRect: CGRect, device: MTLDevice?) {
        self.resolution = frameRect.size
        super.init(frame: frameRect, device: device)
        self.backgroundColor = .systemBlue
        
        self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        
        setup()
    }
    
    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public override func layoutSubviews() {
        super.layoutSubviews()
        self.drawableSize = CGSize(width: frame.size.width, height: frame.size.height)
    }

    func setup() {

        postFxPass = ComputePass(kernelName: "PostFxPass",
                                 linkedFunctionNames: [],
                                 resolution: resolution)
        
        let rt = MetalManager.shared.allocTexture(pixelFormat: .rgba32Float,
                                                  width: Int(resolution.width),
                                                  height: Int(resolution.height),
                                                  usage: [.shaderRead, .shaderWrite])

        renderTexture = TextureUniform(texture: rt, index: 4)
        
        self.framebufferOnly = false
    }
    
    public override func draw(_ rect: CGRect) {
        if rect.width > 0 && rect.height > 0 {
            self.render()
        }
    }

    private func render() {
        guard let drawable: CAMetalDrawable = self.currentDrawable,
              var time = rendererDelegate?.rendererDidRequestTime() else { return }
        
        let drawableTextureUniform = TextureUniform(texture: drawable.texture, index: 1)
        
        postFxPass?.dispatch(drawable: drawable,
                             outTexture: drawableTextureUniform,
                             updateUniformsBlock: { [self]
            
         computeCommandEncoder in
            
            computeCommandEncoder.setTexture(self.inputConemarchResult, index: 0)            
            computeCommandEncoder.setBytes(&time, length: MemoryLayout<Float>.size, index: 1)
            
        }, completionBlock: { texture in

        })
    }
    
    func blit(conemarchRender: MTLTexture?) {
        self.inputConemarchResult = conemarchRender
        setNeedsDisplay()
    }
    
    func allocTexturesAndPasses() {
        
        postFxPass?.resolution = resolution
        
        let rt = MetalManager.shared.allocTexture(pixelFormat: .rgba32Float,
                                                  width: Int(resolution.width),
                                                  height: Int(resolution.height),
                                                  usage: [.shaderRead, .shaderWrite])

        renderTexture = TextureUniform(texture: rt, index: 4)
    }
}


A  => AR-SDF/AR-SDF/Models/ARData.swift +40 -0
@@ 1,40 @@
//
//  ARData.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2022-02-17.
//

import CoreGraphics
import Metal
import simd
import ARKit

public class ARData {
    var depthTexture: MTLTexture?
    var depthSmoothTexture: MTLTexture?
    var rgbTexture: MTLTexture?
    var confidenceTexture: MTLTexture?
    var confidenceSmoothTexture: MTLTexture?
    var cameraIntrinsics = simd_float3x3()
    var cameraResolution = CGSize()
    var projectionMatrix = simd_float4x4()
    var viewMatrix = simd_float4x4()
    var intrinsics = simd_float3x3()
    var lightTemperature = simd_float1()
    var lightIntensity = simd_float1()
    var distanceToRaycast = simd_float1()
    var frame: ARFrame?
    
    var camera = simd_float4x4()
    var raycastPosition = simd_float3()
        
    public func camPos() -> simd_float3 {
        return simd_float3(camera.columns.3.x, camera.columns.3.y, camera.columns.3.z)
    }
    public func objectTarget() -> simd_float4x4 {
        let forward = simd_float3(camera.columns.2.x, camera.columns.2.y, camera.columns.2.z)
        let objectTransform = camera.translate(x: forward.x, forward.y, forward.z)
        return objectTransform
    }
}

A  => AR-SDF/AR-SDF/Models/DistanceField.swift +134 -0
@@ 1,134 @@
//
//  DistanceField.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-16.
//

import CoreVideo
import Foundation
import Metal
import simd

public struct DistanceFieldParameters {
    var param1 = simd_float4()
    var param2 = simd_float4()
    var param3 = simd_float4()
    var param4 = simd_float4()

    var transform = simd_float4x4(simd_float4(1.0, 0.0, 0.0, 0.0),
                                  simd_float4(0.0, 1.0, 0.0, 0.0),
                                  simd_float4(0.0, 0.0, 1.0, 0.0),
                                  simd_float4(0.0, 0.0, 0.0, 1.0))
    
    var scale = simd_float1(1.0)
    var steps = simd_int1(25)
    var fudge = simd_float1(1.0)
    
    public init() {
        
    }
}

public class DistanceField {
    
    /// Parameters to encode in the buffer
    public var uniforms: [Uniform] = []

    /// Number of raymarch steps for the final pass
    public var steps: Int {
        get {
            return Int(parameterBufferPointer.pointee.steps)
        }
        set(newValue) {
            parameterBufferPointer.pointee.steps = simd_int1(newValue)
        }
    }
    
    /// Transform for the distance field
    public var transform: simd_float4x4 {
        get {
            return parameterBufferPointer.pointee.transform
        }
        set(newValue) {
            parameterBufferPointer.pointee.transform = newValue
        }
    }
    
    /// Scale of the distance field
    public var scale: simd_float1 {
        get {
            return parameterBufferPointer.pointee.scale
        }
        set(newValue) {
            parameterBufferPointer.pointee.scale = newValue
        }
    }
    
    /// Name of the visible function
    public var kernelName = ""
    
    /// Reference to buffer for updating values
    private var parameterBufferPointer: UnsafeMutablePointer<DistanceFieldParameters>
    
    /// Parameters to encode in the buffer
    private var parameters = DistanceFieldParameters()
    
    /// The visible function of the distance field
    private var distanceFieldFunction: MTLFunction?
    
    /// Buffer to send to GPU
    private var parameterBuffer: MTLBuffer

    public init(kernelName: String, uniforms: [Uniform]) {
        
        if uniforms.count > 4 {
            fatalError("Distance Fields can have a maximum of 4 Float4 uniforms")
        }
            
        self.kernelName = kernelName
        self.uniforms = uniforms
        
        parameterBuffer = MetalManager.shared.metalDevice.makeBuffer(bytes: &self.parameters,
                                                             length: MemoryLayout<DistanceFieldParameters>.stride,
                                                             options: [])!
    
        parameterBufferPointer = parameterBuffer.contents().bindMemory(to: DistanceFieldParameters.self, capacity: 1)
        
        distanceFieldFunction = MetalManager.shared.createLinkedFunction(name: kernelName, options: [])
    }
    
    /// Update the uniforms pre-dispatch
    func encodeUniforms(encoder: MTLComputeCommandEncoder) {
        if uniforms.count > 0 {
            uniforms[0].assignToBufferValue(val: &parameterBufferPointer.pointee.param1)
        }
        if uniforms.count > 1 {
            uniforms[1].assignToBufferValue(val: &parameterBufferPointer.pointee.param2)
        }
        if uniforms.count > 2 {
            uniforms[2].assignToBufferValue(val: &parameterBufferPointer.pointee.param3)
        }
        if uniforms.count > 3 {
            uniforms[3].assignToBufferValue(val: &parameterBufferPointer.pointee
                                                .param4)
        }
      
        encoder.setBuffer(parameterBuffer, offset: 0, index: 1)
    }
    
    /// Translate the position of the distance field
    func translate(translation: simd_float3) {
        parameterBufferPointer.pointee.transform = parameterBufferPointer.pointee.transform.translate(x: translation.x, translation.y, translation.z)
    }
    
    /// Rotate the distance field around an axis
    func rotate(radians: Float, x: Float, y: Float, z: Float) {
        parameterBufferPointer.pointee.transform = parameterBufferPointer.pointee.transform.rotate(radians: radians, x, y, z)
    }
    
    /// Scale the distance field by some delta
    func scale(delta: simd_float1) {
        self.parameterBufferPointer.pointee.scale = simd_clamp(self.parameterBufferPointer.pointee.scale + delta, 0.25, 2.0)
    }
}

A  => AR-SDF/AR-SDF/Models/TextureUniform.swift +19 -0
@@ 1,19 @@
//
//  TextureUniform.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-20.
//

import Foundation
import Metal

class TextureUniform: Uniform {
    let texture: MTLTexture
    
    init(texture: MTLTexture, index: Int) {
        self.texture = texture
        super.init(index: index, name: "", range: .zero)
        self.index = index
    }
}

A  => AR-SDF/AR-SDF/Models/Uniform.swift +94 -0
@@ 1,94 @@
//
//  Uniform.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-09-15.
//

import simd
import Metal
import UIKit

public class Uniform {
    public var index: Int = 0
    public var name: String = ""
    public var range = CGSize()

    init(index: Int, name: String, range: CGSize) {
        self.index = index
        self.name = name
        self.range = range
    }
    
    func assignToBufferValue(val: inout simd_float4) {
        // :) fatalError("Must Override")
    }
    
    func numValues() -> Int {
        return 1
    }
}

public class FloatUniform: Uniform {
    public var currentValue: Float = 0.0

    public init(name: String, range: CGSize, value: Float) {
        super.init(index: 0, name: name, range: range)
        currentValue = value
    }

    override func assignToBufferValue(val: inout simd_float4) {
        val = simd_float4(currentValue, 0.0, 0.0, 0.0)
    }
}

public class Float2Uniform: Uniform {
    public var currentValue = simd_float2()

    public init(name: String, range: CGSize, value: simd_float2) {
        super.init(index: 0, name: name, range: range)
        currentValue = value
    }
    
    override func assignToBufferValue(val: inout simd_float4) {
        val = simd_float4(currentValue.x, currentValue.y, 0.0, 0.0)
    }
    
    override func numValues() -> Int {
        return 2
    }
}

public class Float3Uniform: Uniform {
    public var currentValue = simd_float3()

    public init(name: String, range: CGSize, value: simd_float3) {
        super.init(index: 0, name: name, range: range)
        currentValue = value
    }
    
    override func assignToBufferValue(val: inout simd_float4) {
        val = simd_float4(currentValue.x, currentValue.y, currentValue.z, 0.0)
    }
    
    override func numValues() -> Int {
        return 3
    }
}

public class Float4Uniform: Uniform {
    public var currentValue = simd_float4()

    public init(name: String, range: CGSize, value: simd_float4) {
        super.init(index: 0, name: name, range: range)
        currentValue = value
    }
    
    override func assignToBufferValue(val: inout simd_float4) {
        val = simd_float4(currentValue.x, currentValue.y, currentValue.z, currentValue.w)
    }
    
    override func numValues() -> Int {
        return 4
    }
}

A  => AR-SDF/AR-SDF/RendererDelegate.swift +13 -0
@@ 1,13 @@
//
//  RenderTargetDelegate.swift
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-25.
//

import UIKit

protocol RendererDelegate {
    func rendererDidRequestOrientation() -> UIInterfaceOrientation
    func rendererDidRequestTime() -> Double
}

A  => AR-SDF/AR-SDF/Shaders/Common.h +35 -0
@@ 1,35 @@
//
//  Common.h
//  conemarch-ar
//
//  Created by Connor Bell on 2021-11-14.
//

#ifndef Common_h
#define Common_h

struct RaymarchResult {
    float3 position;
    float distToSurface;
    float depth;
};

struct ScreenSpaceInfo {
    float3 rayDir;
    RaymarchResult raymarchResult;
};

// From https://www.shadertoy.com/view/4sc3D7
// Valid from 1000 to 40000 K (and additionally 0 for pure full white)
float3 colorTemperatureToRGB(const float temperature){
  // Values from: http://blenderartists.org/forum/showthread.php?270332-OSL-Goodness&p=2268693&viewfull=1#post2268693
  float3x3 m = (temperature <= 6500.0) ? float3x3(float3(0.0, -2902.1955373783176, -8257.7997278925690),
                                                  float3(0.0, 1669.5803561666639, 2575.2827530017594),
                                                  float3(1.0, 1.3302673723350029, 1.8993753891711275)) :
                                          float3x3(float3(1745.0425298314172, 1216.6168361476490, -8257.7997278925690),
                                                   float3(-2666.3474220535695, -2173.1012343082230, 2575.2827530017594),
                                                   float3(0.55995389139931482, 0.70381203140554553, 1.8993753891711275));
  return mix(clamp(float3(m[0] / (float3(clamp(temperature, 1000.0, 40000.0)) + m[1]) + m[2]), float3(0.0), float3(1.0)), float3(1.0), smoothstep(1000.0, 0.0, temperature));
}

#endif /* Common_h */

A  => AR-SDF/AR-SDF/Shaders/Conemarcher.metal +230 -0
@@ 1,230 @@
//
//  Conemarcher.metal
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-15.
//

#include <metal_stdlib>
#include "DistanceFields.h"
#include "Common.h"

using namespace metal;

struct ConemarchParameters {
    float maxDist;
    float minDist;
    float coneWidth;
    float4x4 inverseProjectionMatrix;
    float4x4 inverseViewMatrix;
    float4x4 viewMatrix;
    float4x4 projectionMatrix;
    float4x4 camera;
    int computeColor;
    float time;
    float lightTemperature;
    float lightIntensity;
};

float map(float3 pos,
          float time,
          DistanceFieldParams distParams,
          DistanceFieldFunction distanceFieldFunction) {
    
    float scale = distParams.scale;
    float3 transformedPos = (distParams.transform * float4(pos, 1.0) * scale).xyz;

    return distanceFieldFunction(transformedPos, time, distParams) / scale;
}

RaymarchResult conemarch(const float3 pos,
                         const float3 rayDir,
                         const float prevDist,
                         device ConemarchParameters &conemarchParams,
                         DistanceFieldParams distanceFieldParams,
                         DistanceFieldFunction distanceFieldFunction) {

    RaymarchResult ray;
    ray.position = pos;
    ray.depth = prevDist;
    
    for (int i = 0; i < distanceFieldParams.steps; i++) {
        
        float3 p = pos + rayDir * ray.depth;
        float res = map(p, conemarchParams.time, distanceFieldParams, distanceFieldFunction)*0.8;
        float cone = max(ray.depth * conemarchParams.coneWidth, conemarchParams.minDist);
        
        if (res < cone) {
            break;
        }
        
        float sum = ray.depth + res;
        
        if (sum > conemarchParams.maxDist) {
            break;
        }
        ray.distToSurface = res;
        ray.position = p;
        ray.depth = sum;
    }
    
    return ray;
}

RaymarchResult raymarch(const float3 pos,
                        const float3 rayDir,
                        const float prevDist,
                        const float maxDist,
                        device ConemarchParameters &conemarchParams,
                        DistanceFieldParams distFieldParams,
                        DistanceFieldFunction distanceFieldFunction) {

    RaymarchResult ray;
    ray.position = pos;
    ray.depth = prevDist;
    float stepLength = 0.0;
    
    for (int i = 0; i < distFieldParams.steps; i++) {
        
        ray.position = pos + rayDir * ray.depth;
        float newDist = map(ray.position, conemarchParams.time, distFieldParams, distanceFieldFunction) * distFieldParams.fudge;

        ray.distToSurface = newDist;

        if (newDist < conemarchParams.minDist) {
            break;
        }
        float sum = ray.depth + stepLength;
        
        if (sum > conemarchParams.maxDist) {
            break;
        }
        
        ray.depth = sum;
    }
    
    return ray;
}

float3 calcNormal(float3 pos, float time, DistanceFieldParams distParams, DistanceFieldFunction distanceFieldFunction) {
    const float3 eps = float3(0.001, 0., 0.);
    float3 nor = float3(map(pos+eps.xyy,
                            time, distParams,
                            distanceFieldFunction) - map(pos-eps.xyy, time, distParams, distanceFieldFunction),
                        map(pos+eps.yxy,
                            time, distParams,
                            distanceFieldFunction) - map(pos-eps.yxy, time, distParams, distanceFieldFunction),
                        map(pos+eps.yyx,
                            time, distParams,
                            distanceFieldFunction) - map(pos-eps.yyx, time, distParams, distanceFieldFunction));
    return normalize(nor);
}

float3 refractSample(float3 pos, float3 rayDir, float3 nor, float ior, float4x4 projMatrix, float4x4 viewMatrix, texture2d<float, access::sample> rgbTexture) {
    constexpr sampler s(coord::normalized, address::mirrored_repeat, filter::linear);
    float3 refractedDir = refract(rayDir, nor, ior);
    float3 refractedPos = pos + normalize(refractedDir);
    float4 clipPos = projMatrix * (viewMatrix * float4(refractedPos, 1.0));
    float2 screenSpaceUv = saturate((clipPos.xy / clipPos.w + 1.0) * 0.5);
    screenSpaceUv.y = 1.0 - screenSpaceUv.y;
    return rgbTexture.sample(s, screenSpaceUv).rgb;
}

float4 color(device ConemarchParameters &conemarchParams,
             device DistanceFieldParams &distanceFieldParams,
             DistanceFieldFunction distanceFieldFunction,
             float3 camPos,
             float3 rayDir,
             float2 uv,
             float4 worldColor,
             float lastDepth,
             texture2d<float, access::sample> rgbTexture) {
    
    // Only compute depth if not computing color
    if (!conemarchParams.computeColor) {
        return conemarch(camPos, rayDir, lastDepth, conemarchParams, distanceFieldParams, distanceFieldFunction).depth;
    }

    // Compute the depth
    RaymarchResult res = raymarch(camPos, rayDir, lastDepth, worldColor.a, conemarchParams, distanceFieldParams, distanceFieldFunction);

    float depth = res.depth;
    float4 color = float4(0.0, 0.0, 0.0, depth);
    
    // Only shade the surface if
    // 1. The resulting ray position isn't occluded by lidar depth data.
    if (depth < worldColor.a) {
        
        // Shade each color channel with 3 refracted samples
        float3 normal = calcNormal(res.position, conemarchParams.time, distanceFieldParams, distanceFieldFunction);
        
        color.rgb = refractSample(res.position, rayDir, normal, 0.98, conemarchParams.projectionMatrix, conemarchParams.viewMatrix, rgbTexture).rgb;
        color.rgb *= saturate(0.25+0.5*dot(normal, normalize(float3(0.05, 1.0, 0.1)-res.position)));
        color.rgb *= colorTemperatureToRGB(conemarchParams.lightTemperature);
        
    } else {
        color = worldColor;
    }
    
    return color;
}

kernel void conemarchKernel(texture2d<float, access::sample> previousTexture [[texture(0)]],
                            texture2d<float, access::write> outTexture [[texture(1)]],
                            texture2d<float, access::sample> rgbTexture [[texture(2)]],
                            device ConemarchParameters *conemarchParameters [[buffer(0)]],
                            device DistanceFieldParams *distanceFieldParameters [[buffer(1)]],
                            visible_function_table<DistanceFieldFunction> distanceFieldFunctions [[buffer(2)]],
                            device const int &distanceFieldIndex [[buffer(3)]],
                            uint2 gid [[ thread_position_in_grid ]]) {

    // Cone testing passes require nearest sampling.
    constexpr sampler linearSampler(coord::normalized, address::repeat, filter::linear);
    constexpr sampler nearestSampler(coord::normalized, address::repeat, filter::nearest);
    
    float2 textureSize = float2(outTexture.get_width(), outTexture.get_height());
    float2 uv = float2(gid) / textureSize;
    
    // Compute last depth if texture exists
    float lastDepth = conemarchParameters->minDist;

    if (!is_null_texture(previousTexture)) {
        if (conemarchParameters->computeColor) {
            lastDepth = previousTexture.sample(linearSampler, uv).a;
        } else {
            lastDepth = previousTexture.sample(nearestSampler, uv).a;
        }
    }

    // uv coordinate centered at 0,0
    float2 uv_c = uv * 2.0 - 1.0;
    uv_c.y = -uv_c.y;
    
    // Project a ray into the world space
    float4 rayEye = (conemarchParameters->inverseProjectionMatrix * float4(uv_c,1.0,1.0));
    float3 rdCam = rayEye.xyz / rayEye.w;
    float3 rayWorld = normalize((conemarchParameters->inverseViewMatrix * float4(rdCam,1.0)).xyz);
    
    // Reference the distance field function pointer from the function table.
    DistanceFieldFunction *distanceFieldFunction = distanceFieldFunctions[0];
    
    float3 camPos = float3(conemarchParameters->camera[3][0],
                           conemarchParameters->camera[3][1],
                           conemarchParameters->camera[3][2]);
    
    // Sample "real world" color and depth
    float4 worldColor = rgbTexture.sample(linearSampler, uv);
    worldColor.a = min(conemarchParameters->maxDist, worldColor.a);
    
    float4 result = color(*conemarchParameters,
                          *distanceFieldParameters,
                          distanceFieldFunction,
                          camPos,
                          rayWorld,
                          uv,
                          worldColor,
                          lastDepth,
                          rgbTexture);

    outTexture.write(result, gid);
}

A  => AR-SDF/AR-SDF/Shaders/DistanceFields.h +28 -0
@@ 1,28 @@
//
//  DistanceFields.h
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-15.
//

#ifndef DistanceFields_h
#define DistanceFields_h

using namespace metal;
struct DistanceFieldParams;
using DistanceFieldFunction = float(float3 p, float time, DistanceFieldParams params);

struct DistanceFieldParams {    
    float4 param1;
    float4 param2;
    float4 param3;
    float4 param4;

    float4x4 transform;
    
    float scale;
    int steps;
    float fudge;
};

#endif /* DistanceFields_h */

A  => AR-SDF/AR-SDF/Shaders/DistanceFields.metal +85 -0
@@ 1,85 @@
//
//  DistanceFields.metal
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-15.
//

#include <metal_stdlib>
#include "DistanceFields.h"

using namespace metal;

float2 mod(float2 x, float2 y) {
    return x - y * floor(x/y);
}

float3 mod(float3 x, float3 y) {
    return x - y * floor(x/y);
}

float sdBox( float3 p, float3 b )
{
    float3 q = abs(p) - b;
    return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
}

float sdSphere(float3 pos, float radius) {
    return length(pos) - radius;
}

float hash(float v) {
    return fract(sin(v) * 6209323.042);
}

[[visible]]
float sphere(float3 p, float time, DistanceFieldParams params) {
    float dist = length(p) - 0.5;
    return dist;
}

float length2(float2 p) {
    return sqrt( p.x*p.x + p.y*p.y );
}

float length8(float2 p) {
    p = p*p; p = p*p; p = p*p;
    return pow( p.x + p.y, 1.0/8.0 );
}

float sdTorus82(float3 p, float2 t) {
    float2 q = float2(length2(p.xz)-t.x,p.y);
    return length8(q)-t.y;
}

float opS( float d1, float d2 ) {
    return max(-d2,d1);
}

[[visible]]
float gasket(float3 p, float time, DistanceFieldParams params) {
    float s = dot(p, p)*0.75;

    float radius = params.param1.x;
    float4 pos = float4(p / s, 1.0);
    pos.xyz += float3(time * 0.25, 0., time * 0.25);

    pos.xyz = mod(pos.xyz, 2.)-1.;

    for (int i = 0; i < 9; i++) {
        pos.xyz = clamp(pos.xyz, -1., 1.) * 2. - pos.xyz;
        pos *= radius/dot(pos.xyz,pos.xyz);
    }
    return (0.25*abs(length(pos.xyz))/pos.w) * s;
}

[[visible]]
float tunnel(float3 pos, float time, DistanceFieldParams params) {
    float3 spaceSize = float3(0.25);
    //pos.xy = pR(pos.xy, pos.z*0.1);
    float3 p = mod(pos, spaceSize*2.0) - spaceSize;

    float dist = sdBox(p, spaceSize * 0.4);
    
    return dist;
}

A  => AR-SDF/AR-SDF/Shaders/OrientationTransforms.h +21 -0
@@ 1,21 @@
//
//  OrientationTransforms.h
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-25.
//

#ifndef OrientationTransforms_h
#define OrientationTransforms_h

using namespace metal;

typedef enum {
    landscapeLeft = 0,
    portrait,
    landscapeRight
} Orientation;

float2 transformedTo(Orientation target, float2 uv);

#endif /* OrientationTransforms_h */

A  => AR-SDF/AR-SDF/Shaders/OrientationTransforms.metal +20 -0
@@ 1,20 @@
//
//  OrientationTransforms.metal
//  conemarch-ar
//
//  Created by Connor Bell on 2021-10-25.
//

#include "OrientationTransforms.h"

#include <metal_stdlib>
using namespace metal;

float2 transformedTo(Orientation target, float2 uv) {
   if (target == portrait) {
       return -float2(uv.x, 1-uv.y).yx;
   } else if (target == landscapeRight) {
       return 1. - uv;
   }
   return uv;
}

A  => AR-SDF/AR-SDF/Shaders/PostFxPass.metal +57 -0
@@ 1,57 @@
//
//  Compositor.metal
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-18.
//

#include <metal_stdlib>
#include "OrientationTransforms.h"
#include "DistanceFields.h"

using namespace metal;

constexpr sampler colorSampler(coord::normalized,
                               address::clamp_to_border,
                               filter::linear);

float3 postFx_blackAndWhite(texture2d<float, access::sample> conemarchTexture,
                            float2 _uv,
                            float time) {
    float2 uv = (_uv- 0.5) * 2.0;
    uv *= 0.975 + pow(abs(float2(uv.y, uv.x)) / float2(5.0, 4.0),2.0);
    
    float2 ratio = float2(conemarchTexture.get_width() / conemarchTexture.get_height(), 1.0);
    float vignette = 1.-smoothstep(0.75, 2.5, length(uv * ratio) * length(uv * ratio));

    uv = uv / 2.0 + 0.5;
    float4 col = conemarchTexture.sample(colorSampler, uv);

    float3 output = mix(col.rgb, sqrt(dot(col.rgb*col.rgb, float3(.299,  .587, .114))), 0.5);
    float strength = 16.0;
    
    float x = (uv.x + 4.0 ) * (uv.y + 4.0 ) * (time * 10.0);
    float grain = (fmod((fmod(x, 13.0) + 1.0) * (fmod(x, 123.0) + 1.0), 0.01)-0.005) * strength;
    output.rgb *= 1.0 - grain;
    
    output.rgb *= .85 + sin(uv.y*1000.0)*0.15;
    output.rgb *= vignette;
    return output;
}

[[kernel]]
kernel void PostFxPass(texture2d<float, access::sample> conemarchTexture [[texture(0)]],
                       texture2d<float, access::write> outTexture [[texture(1)]],
                       device const float &time [[buffer(1)]],
                       uint2 gid [[ thread_position_in_grid ]]) {
    
    float2 outSize = float2(outTexture.get_width(), outTexture.get_height());
    float2 uv = float2(gid) / outSize;
    
    float4 col = conemarchTexture.sample(colorSampler, uv);
    //col.rgb = postFx_blackAndWhite(conemarchTexture, uv, time);

    col.a = 1.0;

    outTexture.write(col, gid);
}

A  => AR-SDF/AR-SDF/Shaders/YCbCrToRGB.metal +47 -0
@@ 1,47 @@
//
//  YCbCrToRGB.metal
//  conemarch-ar
//
//  Created by Connor Bell on 2021-07-16.
//  From Apple's pointCloudSample project 

#include <metal_stdlib>
#include "OrientationTransforms.h"

using namespace metal;
    
// Convert from YCbCr to rgb.
float4 ycbcrToRGBTransform(float4 y, float4 CbCr) {
    const float4x4 ycbcrToRGBTransform = float4x4(
      float4(+1.0000f, +1.0000f, +1.0000f, +0.0000f),
      float4(+0.0000f, -0.3441f, +1.7720f, +0.0000f),
      float4(+1.4020f, -0.7141f, +0.0000f, +0.0000f),
      float4(-0.7010f, +0.5291f, -0.8860f, +1.0000f)
    );

    float4 ycbcr = float4(y.r, CbCr.rg, 1.0);
    return ycbcrToRGBTransform * ycbcr;
}

// Convert the Y and CbCr textures into a single RGBA texture. Also rotates to resulting image.
kernel void convertYCbCrToRGBA(texture2d<float, access::sample> colorYtexture [[texture(0)]],
                               texture2d<float, access::sample> colorCbCrtexture [[texture(1)]],
                               texture2d<float, access::write> colorRGBTexture [[texture(2)]],
                               texture2d<float, access::sample> depthTexture [[texture(3)]],
                               device const Orientation &orientation [[buffer(0)]],
                               uint2 gid [[thread_position_in_grid]])
{
    constexpr sampler s(address::repeat, filter::linear);
    float2 uv = float2(gid) / float2(colorRGBTexture.get_width(), colorRGBTexture.get_height());
    uv = transformedTo(orientation, uv);
    
    // Sample this pixel's camera image color.
    float4 rgb = ycbcrToRGBTransform(
         colorYtexture.sample(s, uv),
         colorCbCrtexture.sample(s, uv)
    );
    
    rgb.a = depthTexture.sample(s, uv).r;
    
    colorRGBTexture.write(rgb, gid.xy);
}

A  => AR-SDF/AR-SDFTests/AR_SDFTests.swift +33 -0
@@ 1,33 @@
//
//  AR_SDFTests.swift
//  AR-SDFTests
//
//  Created by Connor Bell on 2022-02-18.
//

import XCTest
@testable import AR_SDF

class AR_SDFTests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testPerformanceExample() throws {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }

}